]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/linux/files/mipv6-1.1-v2.4.25.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.25.patch
1 diff -uprN linux-2.4.25.old/Documentation/Configure.help linux-2.4.25/Documentation/Configure.help
2 --- linux-2.4.25.old/Documentation/Configure.help       2004-06-26 11:22:00.000000000 +0100
3 +++ linux-2.4.25/Documentation/Configure.help   2004-06-26 11:29:29.000000000 +0100
4 @@ -6204,6 +6204,57 @@ CONFIG_IPV6
5  
6    It is safe to say N here for now.
7  
8 +IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)
9 +CONFIG_IPV6_TUNNEL
10 +  Experimental IP6-IP6 tunneling.  You must select this, if you want
11 +  to use CONFIG_IPV6_MOBILITY.  More information in MIPL Mobile IPv6
12 +  instructions.
13 +
14 +  If you don't want IP6-IP6 tunnels and Mobile IPv6, say N.
15 +
16 +IPv6: Mobility Support (EXPERIMENTAL)
17 +CONFIG_IPV6_MOBILITY
18 +  This is experimental support for the upcoming specification of
19 +  Mobile IPv6. Mobile IPv6 allows nodes to seamlessly move between
20 +  networks without changing their IP addresses, thus allowing them to
21 +  maintain upper layer connections (e.g. TCP).  Selecting this option
22 +  allows your computer to act as a Correspondent Node (CN).  A MIPv6
23 +  Mobile Node will be able to communicate with the CN and use route
24 +  optimization.
25 +
26 +  For more information and configuration details, see
27 +  http://www.mipl.mediapoli.com/.
28 +
29 +  If unsure, say N.
30 +
31 +MIPv6: Mobile Node Support
32 +CONFIG_IPV6_MOBILITY_MN
33 +  If you want your computer to be a MIPv6 Mobile Node (MN), select
34 +  this option.  You must configure MN using the userspace tools
35 +  available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
36 +
37 +  If your computer is stationary, or you are unsure if you need this,
38 +  say N.  Note that you will need a properly configured MIPv6 Home
39 +  Agent to use any Mobile Nodes.
40 +
41 +MIPv6: Home Agent Support
42 +CONFIG_IPV6_MOBILITY_HA
43 +  If you want your router to serve as a MIPv6 Home Agent (HA), select
44 +  this option.  You must configure HA using the userspace tools
45 +  available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
46 +
47 +  If your computer is not a router, or you are unsure if you need
48 +  this, say N.
49 +
50 +MIPv6: Debug messages
51 +CONFIG_IPV6_MOBILITY_DEBUG
52 +  MIPL Mobile IPv6 can produce a lot of debugging messages. There are
53 +  eight debug levels (0 through 7) and the level is controlled via
54 +  /proc/sys/net/ipv6/mobility/debuglevel. Since MIPL is still
55 +  experimental, you might want to say Y here.
56 +
57 +  Be sure to say Y and record debug messages when submitting a bug
58 +  report.
59  The SCTP Protocol (EXPERIMENTAL)
60  CONFIG_IP_SCTP
61    Stream Control Transmission Protocol
62 diff -uprN linux-2.4.25.old/Documentation/DocBook/Makefile linux-2.4.25/Documentation/DocBook/Makefile
63 --- linux-2.4.25.old/Documentation/DocBook/Makefile     2002-11-28 23:53:08.000000000 +0000
64 +++ linux-2.4.25/Documentation/DocBook/Makefile 2004-06-26 11:29:29.000000000 +0100
65 @@ -2,7 +2,7 @@ BOOKS   := wanbook.sgml z8530book.sgml mca
66            kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
67            kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
68            deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
69 -          journal-api.sgml
70 +          journal-api.sgml mip6-func.sgml
71  
72  PS     :=      $(patsubst %.sgml, %.ps, $(BOOKS))
73  PDF    :=      $(patsubst %.sgml, %.pdf, $(BOOKS))
74 @@ -86,6 +86,9 @@ videobook.sgml: videobook.tmpl $(TOPDIR)
75  procfs-guide.sgml:  procfs-guide.tmpl procfs_example.sgml
76         $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
77  
78 +mip6-func.sgml: mip6-func.tmpl
79 +       $(TOPDIR)/scripts/docgen <$< >$@
80 +
81  APISOURCES :=  $(TOPDIR)/drivers/media/video/videodev.c \
82                 $(TOPDIR)/arch/i386/kernel/irq.c \
83                 $(TOPDIR)/arch/i386/kernel/mca.c \
84 diff -uprN linux-2.4.25.old/Documentation/DocBook/mip6-func.tmpl linux-2.4.25/Documentation/DocBook/mip6-func.tmpl
85 --- linux-2.4.25.old/Documentation/DocBook/mip6-func.tmpl       1970-01-01 01:00:00.000000000 +0100
86 +++ linux-2.4.25/Documentation/DocBook/mip6-func.tmpl   2004-06-26 11:29:29.000000000 +0100
87 @@ -0,0 +1,756 @@
88 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
89 +<book id="LinuxMobileIPv6">
90 + <bookinfo>
91 +  <title>MIPL Mobile IPv6 Function Reference Guide</title>
92 +
93 +  <authorgroup>
94 +    <author>
95 +      <othername>MIPL Mobile IPv6 for Linux Team</othername>
96 +      <affiliation>
97 +       <orgname>Helsinki University of Technology</orgname>
98 +       <orgdiv>Telecommunications Software and Multimedia Lab</orgdiv>
99 +       <address>
100 +        <pob>PO BOX 9201</pob>
101 +       <postcode>FIN-02015 HUT</postcode>
102 +       <country>Finland</country>
103 +        <email>mipl@list.mipl.mediapoli.com</email>
104 +       </address>
105 +      </affiliation>
106 +     </author>
107 +  </authorgroup>
108 +
109 +  <copyright>
110 +   <year>2000-2001</year>
111 +   <holder>Helsinki University of Technology</holder>
112 +  </copyright>
113
114 +  <legalnotice>
115 +   <para>
116 +     Copyright (c) 2001, 2002 MIPL Mobile IPv6 for Linux Team.
117 +   </para>
118 +   <para>
119 +     Permission is granted to copy, distribute and/or modify this
120 +     document under the terms of the GNU Free Documentation License,
121 +     Version 1.1 published by the Free Software Foundation; with the
122 +     Invariant Sections being "Introduction", with the Front-Cover
123 +     Texts being "MIPL Mobile IPv6 Function Reference Guide", "MIPL
124 +     Mobile IPv6 for Linux Team" and "Helsinki University of
125 +     Technology".  A copy of the license is included in <xref
126 +     linkend="gfdl">.
127 +   </para>
128 +      
129 +  </legalnotice>
130 + </bookinfo>
131 +
132 +<toc></toc>
133 +
134 +  <preface id="intro">
135 +     <title>Introduction</title>
136 +
137 +     <para>
138 +       MIPL Mobile IPv6 for Linux is an implementation of Mobility
139 +       Support in IPv6 IETF mobile-ip working groups Internet-Draft
140 +       (draft-ietf-mobileip-ipv6).  This implementation has been
141 +       developed in the Telecommunications Software and Multimedia
142 +       Laboratory at Helsinki University of Technology.
143 +     </para>
144 +
145 +     <para>
146 +       MIPL is fully open source, licensed under the GNU General
147 +       Public License.  Latest source for MIPL can be downloaded from
148 +       the MIPL website at:
149 +     </para>
150 +     <programlisting>
151 +       http://www.mipl.mediapoli.com/.
152 +     </programlisting>
153 +     <para>
154 +       Developers and users interested in MIPL can subscribe to the
155 +       MIPL mailing list by sending e-mail to
156 +       <email>majordomo@list.mipl.mediapoli.com</email> with
157 +     </para>
158 +     <programlisting>
159 +       subscribe mipl
160 +     </programlisting>
161 +     <para>
162 +       in the body of the message.
163 +     </para>
164 +
165 +     <para>
166 +       This document is a reference guide to MIPL functions.  Intended
167 +       audience is developers wishing to contribute to the project.
168 +       Hopefully this document will make it easier and quicker to
169 +       understand and adopt the inner workings of MIPL Mobile IPv6.
170 +     </para>
171 +
172 +     <para>
173 +       MIPL Mobile IPv6 for Linux Team members (past and present):
174 +
175 +       <itemizedlist>
176 +        <listitem>
177 +       <address>
178 +       Sami Kivisaari <email>Sami.Kivisaari@hut.fi</email>
179 +       </address>
180 +        </listitem>
181 +        <listitem>
182 +       <address>
183 +       Niklas Kampe <email>Niklas.Kampe@hut.fi</email>
184 +       </address>
185 +        </listitem>
186 +        <listitem>
187 +       <address>
188 +       Juha Mynttinen <email>Juha.Mynttinen@hut.fi</email>
189 +       </address>
190 +        </listitem>
191 +        <listitem>
192 +       <address>
193 +       Toni Nykanen <email>Toni.Nykanen@iki.fi</email>
194 +       </address>
195 +        </listitem>
196 +        <listitem>
197 +       <address>
198 +       Henrik Petander <email>Henrik.Petander@hut.fi</email>
199 +       </address>
200 +        </listitem>
201 +        <listitem>
202 +       <address>
203 +       Antti Tuominen <email>ajtuomin@tml.hut.fi</email>
204 +       </address>
205 +        </listitem>
206 +       </itemizedlist>
207 +
208 +       <itemizedlist>
209 +        <listitem>
210 +       <address>
211 +       Marko Myllynen
212 +       </address>
213 +        </listitem>
214 +        <listitem>
215 +       <address>
216 +       Ville Nuorvala <email>vnuorval@tcs.hut.fi</email>
217 +       </address>
218 +        </listitem>
219 +        <listitem>
220 +       <address>
221 +       Jaakko Laine <email>Jaakko.Laine@hut.fi</email>
222 +       </address>
223 +        </listitem>
224 +       </itemizedlist>
225 +     </para>
226 +
227 +  </preface>
228 +
229 +  <chapter id="common">
230 +     <title>Common functions for all entities</title>
231 +
232 +     <sect1><title>Low-level functions</title>
233 +     <para>
234 +       These functions implement memory allocation used by others.
235 +       Hashlist functions implement a linked list with hash lookup,
236 +       which is used with Binding Update List, Binding Cache, Home
237 +       Agents List etc.
238 +     </para>
239 +!Inet/ipv6/mobile_ip6/mempool.h
240 +!Inet/ipv6/mobile_ip6/hashlist.h
241 +     </sect1>
242 +
243 +     <sect1><title>Debug functions</title>
244 +     <para>
245 +       Debug and utility functions.  These functions are available if
246 +       <constant>CONFIG_IPV6_MOBILITY_DEBUG</constant> is set.
247 +       Otherwise macros expand to no operation.
248 +     </para>
249 +!Inet/ipv6/mobile_ip6/debug.h
250 +!Inet/ipv6/mobile_ip6/mipv6.c
251 +     </sect1>
252 +
253 +     <sect1><title>Extension Header functions</title>
254 +     <para>
255 +       These functions create and handle extension headers that are
256 +       specific to MIPv6.
257 +     </para>
258 +!Inet/ipv6/mobile_ip6/exthdrs.c
259 +     </sect1>
260 +
261 +     <sect1><title>Mobility Header functions</title>
262 +     <para>
263 +       MIPv6 specifies a new protocol called Mobility Header.
264 +       Mobility Header has several message types.  Messages may also
265 +       carry Mobility Options.  These functions are used to create and
266 +       handle Mobility Headers and Mobility Options.
267 +     </para>
268 +!Inet/ipv6/mobile_ip6/sendopts.c
269 +!Inet/ipv6/mobile_ip6/mh_recv.c
270 +!Inet/ipv6/mobile_ip6/auth_subopt.c
271 +     </sect1>
272 +
273 +     <sect1><title>Binding Cache</title>
274 +     <para>
275 +       All Mobile IPv6 entities have a binding cache.  These functions
276 +       provide easy manipulation of the binding cache.
277 +     </para>
278 +!Inet/ipv6/mobile_ip6/bcache.c
279 +     </sect1>
280 +
281 +     <sect1><title>Security</title>
282 +
283 +     <para>
284 +       These functions are common authentication functions and
285 +       implement Draft 13 style IPSec AH support for Binding Updates.
286 +     </para>
287 +!Inet/ipv6/mobile_ip6/ah_algo.c
288 +!Inet/ipv6/mobile_ip6/sadb.c
289 +!Inet/ipv6/mobile_ip6/ah.c
290 +     </sect1>
291 +
292 +     <sect1><title>Utility functions</title>
293 +
294 +     <para>
295 +       These functions are general utility functions commonly used by
296 +       all entities.
297 +     </para>
298 +!Inet/ipv6/mobile_ip6/util.c
299 +     </sect1>
300 +
301 +  </chapter>
302 +
303 +  <chapter id="mn">
304 +     <title>Mobile Node functions</title>
305 +     <sect1><title>General functions</title>
306 +     <para>
307 +     </para>
308 +!Inet/ipv6/mobile_ip6/mn.c
309 +     </sect1>
310 +
311 +     <sect1><title>Binding Update List</title>
312 +     <para>
313 +       Mobile Node keeps track of sent binding updates in Binding
314 +       Update List.
315 +     </para>
316 +!Inet/ipv6/mobile_ip6/bul.c
317 +     </sect1>
318 +
319 +     <sect1><title>Movement detection</title>
320 +
321 +     <para>
322 +       These functions are used by the mobile node for movement
323 +       detection.
324 +     </para>
325 +!Inet/ipv6/mobile_ip6/mdetect.c
326 +     </sect1>
327 +  </chapter>
328 +
329 +  <chapter id="ha">
330 +     <title>Home Agent functions</title>
331 +     <sect1><title>General functions</title>
332 +     <para>
333 +     </para>
334 +!Inet/ipv6/mobile_ip6/ha.c
335 +     </sect1>
336 +
337 +     <sect1><title>Duplicate Address Detection functions</title>
338 +     <para>
339 +       Home Agent does Duplicate Address Detection for Mobile Nodes'
340 +       addresses.  These functions implement MIPv6 specific DAD
341 +       functionality.
342 +     </para>
343 +!Inet/ipv6/mobile_ip6/dad.c
344 +     </sect1>
345 +
346 +  </chapter>
347 +  <appendix id="gfdl">
348 +     <title>GNU Free Documentation License</title>
349 +
350 +     <para>
351 +       Version 1.1, March 2000
352 +     </para>
353 +
354 +     <programlisting>
355 +       Copyright (C) 2000  Free Software Foundation, Inc.
356 +       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
357 +       Everyone is permitted to copy and distribute verbatim copies
358 +       of this license document, but changing it is not allowed.
359 +     </programlisting>
360 +
361 +     <sect1><title>0. PREAMBLE</title>
362 +
363 +     <para>
364 +       The purpose of this License is to make a manual, textbook, or
365 +       other written document "free" in the sense of freedom: to
366 +       assure everyone the effective freedom to copy and redistribute
367 +       it, with or without modifying it, either commercially or
368 +       noncommercially. Secondarily, this License preserves for the
369 +       author and publisher a way to get credit for their work, while
370 +       not being considered responsible for modifications made by
371 +       others.
372 +     </para>
373 +
374 +     <para>
375 +       This License is a kind of "copyleft", which means that
376 +       derivative works of the document must themselves be free in the
377 +       same sense. It complements the GNU General Public License,
378 +       which is a copyleft license designed for free software.
379 +     </para>
380 +
381 +     <para>
382 +       We have designed this License in order to use it for manuals
383 +       for free software, because free software needs free
384 +       documentation: a free program should come with manuals
385 +       providing the same freedoms that the software does. But this
386 +       License is not limited to software manuals; it can be used for
387 +       any textual work, regardless of subject matter or whether it is
388 +       published as a printed book. We recommend this License
389 +       principally for works whose purpose is instruction or
390 +       reference.
391 +     </para>
392 +
393 +     </sect1>
394 +     <sect1><title>1. APPLICABILITY AND DEFINITIONS</title>
395 +
396 +     <para>
397 +       This License applies to any manual or other work that contains
398 +       a notice placed by the copyright holder saying it can be
399 +       distributed under the terms of this License. The "Document",
400 +       below, refers to any such manual or work. Any member of the
401 +       public is a licensee, and is addressed as "you".
402 +     </para>
403 +
404 +     <para>
405 +       A "Modified Version" of the Document means any work containing
406 +       the Document or a portion of it, either copied verbatim, or
407 +       with modifications and/or translated into another language.
408 +     </para>
409 +
410 +     <para>
411 +       A "Secondary Section" is a named appendix or a front-matter
412 +       section of the Document that deals exclusively with the
413 +       relationship of the publishers or authors of the Document to
414 +       the Document's overall subject (or to related matters) and
415 +       contains nothing that could fall directly within that overall
416 +       subject. (For example, if the Document is in part a textbook of
417 +       mathematics, a Secondary Section may not explain any
418 +       mathematics.) The relationship could be a matter of historical
419 +       connection with the subject or with related matters, or of
420 +       legal, commercial, philosophical, ethical or political position
421 +       regarding them.
422 +     </para>
423 +
424 +     <para>
425 +       The "Invariant Sections" are certain Secondary Sections whose
426 +       titles are designated, as being those of Invariant Sections, in
427 +       the notice that says that the Document is released under this
428 +       License.
429 +     </para>
430 +
431 +     <para>
432 +       The "Cover Texts" are certain short passages of text that are
433 +       listed, as Front-Cover Texts or Back-Cover Texts, in the notice
434 +       that says that the Document is released under this License.
435 +     </para>
436 +
437 +     <para>
438 +       A "Transparent" copy of the Document means a machine-readable
439 +       copy, represented in a format whose specification is available
440 +       to the general public, whose contents can be viewed and edited
441 +       directly and straightforwardly with generic text editors or
442 +       (for images composed of pixels) generic paint programs or (for
443 +       drawings) some widely available drawing editor, and that is
444 +       suitable for input to text formatters or for automatic
445 +       translation to a variety of formats suitable for input to text
446 +       formatters. A copy made in an otherwise Transparent file format
447 +       whose markup has been designed to thwart or discourage
448 +       subsequent modification by readers is not Transparent. A copy
449 +       that is not "Transparent" is called "Opaque".
450 +     </para>
451 +
452 +     <para>
453 +       Examples of suitable formats for Transparent copies include
454 +       plain ASCII without markup, Texinfo input format, LaTeX input
455 +       format, SGML or XML using a publicly available DTD, and
456 +       standard-conforming simple HTML designed for human
457 +       modification. Opaque formats include PostScript, PDF,
458 +       proprietary formats that can be read and edited only by
459 +       proprietary word processors, SGML or XML for which the DTD
460 +       and/or processing tools are not generally available, and the
461 +       machine-generated HTML produced by some word processors for
462 +       output purposes only.
463 +     </para>
464 +
465 +     <para>
466 +       The "Title Page" means, for a printed book, the title page
467 +       itself, plus such following pages as are needed to hold,
468 +       legibly, the material this License requires to appear in the
469 +       title page. For works in formats which do not have any title
470 +       page as such, "Title Page" means the text near the most
471 +       prominent appearance of the work's title, preceding the
472 +       beginning of the body of the text.
473 +     </para>
474 +
475 +     </sect1>
476 +     <sect1><title>2. VERBATIM COPYING</title>
477 +
478 +     <para>
479 +       You may copy and distribute the Document in any medium, either
480 +       commercially or noncommercially, provided that this License,
481 +       the copyright notices, and the license notice saying this
482 +       License applies to the Document are reproduced in all copies,
483 +       and that you add no other conditions whatsoever to those of
484 +       this License. You may not use technical measures to obstruct or
485 +       control the reading or further copying of the copies you make
486 +       or distribute. However, you may accept compensation in exchange
487 +       for copies. If you distribute a large enough number of copies
488 +       you must also follow the conditions in section 3.
489 +     </para>
490 +
491 +     <para>
492 +       You may also lend copies, under the same conditions stated
493 +       above, and you may publicly display copies.
494 +     </para>
495 +
496 +     </sect1>
497 +     <sect1><title>3. COPYING IN QUANTITY</title>
498 +
499 +     <para>
500 +       If you publish printed copies of the Document numbering more
501 +       than 100, and the Document's license notice requires Cover
502 +       Texts, you must enclose the copies in covers that carry,
503 +       clearly and legibly, all these Cover Texts: Front-Cover Texts
504 +       on the front cover, and Back-Cover Texts on the back
505 +       cover. Both covers must also clearly and legibly identify you
506 +       as the publisher of these copies. The front cover must present
507 +       the full title with all words of the title equally prominent
508 +       and visible. You may add other material on the covers in
509 +       addition. Copying with changes limited to the covers, as long
510 +       as they preserve the title of the Document and satisfy these
511 +       conditions, can be treated as verbatim copying in other
512 +       respects.
513 +     </para>
514 +
515 +     <para>
516 +       If the required texts for either cover are too voluminous to
517 +       fit legibly, you should put the first ones listed (as many as
518 +       fit reasonably) on the actual cover, and continue the rest onto
519 +       adjacent pages.
520 +     </para>
521 +
522 +     <para>
523 +       If you publish or distribute Opaque copies of the Document
524 +       numbering more than 100, you must either include a
525 +       machine-readable Transparent copy along with each Opaque copy,
526 +       or state in or with each Opaque copy a publicly-accessible
527 +       computer-network location containing a complete Transparent
528 +       copy of the Document, free of added material, which the general
529 +       network-using public has access to download anonymously at no
530 +       charge using public-standard network protocols. If you use the
531 +       latter option, you must take reasonably prudent steps, when you
532 +       begin distribution of Opaque copies in quantity, to ensure that
533 +       this Transparent copy will remain thus accessible at the stated
534 +       location until at least one year after the last time you
535 +       distribute an Opaque copy (directly or through your agents or
536 +       retailers) of that edition to the public.
537 +     </para>
538 +
539 +     <para>
540 +       It is requested, but not required, that you contact the authors
541 +       of the Document well before redistributing any large number of
542 +       copies, to give them a chance to provide you with an updated
543 +       version of the Document.
544 +     </para>
545 +
546 +     </sect1>
547 +     <sect1><title>4. MODIFICATIONS</title>
548 +
549 +     <para>
550 +       You may copy and distribute a Modified Version of the Document
551 +       under the conditions of sections 2 and 3 above, provided that
552 +       you release the Modified Version under precisely this License,
553 +       with the Modified Version filling the role of the Document,
554 +       thus licensing distribution and modification of the Modified
555 +       Version to whoever possesses a copy of it. In addition, you
556 +       must do these things in the Modified Version:
557 +     </para>
558 +
559 +     <para>
560 +      <itemizedlist spacing=compact>
561 +       <listitem>
562 +        <para>
563 +        A. Use in the Title Page (and on the covers, if any) a title
564 +        distinct from that of the Document, and from those of previous
565 +        versions (which should, if there were any, be listed in the
566 +        History section of the Document). You may use the same title
567 +        as a previous version if the original publisher of that
568 +        version gives permission.
569 +       </para>
570 +       </listitem>
571 +       <listitem>
572 +        <para>
573 +       B. List on the Title Page, as authors, one or more persons
574 +       or entities responsible for authorship of the modifications in
575 +       the Modified Version, together with at least five of the
576 +       principal authors of the Document (all of its principal
577 +       authors, if it has less than five).
578 +       </para>
579 +       </listitem>
580 +       <listitem>
581 +        <para>
582 +       C. State on the Title page the name of the publisher of the
583 +       Modified Version, as the publisher.
584 +       </para>
585 +       </listitem>
586 +       <listitem>
587 +        <para>
588 +       D. Preserve all the copyright notices of the Document.
589 +       </para>
590 +       </listitem>
591 +       <listitem>
592 +        <para>
593 +       E. Add an appropriate copyright notice for your
594 +       modifications adjacent to the other copyright notices.
595 +       </para>
596 +       </listitem>
597 +       <listitem>
598 +        <para>
599 +       F. Include, immediately after the copyright notices, a
600 +       license notice giving the public permission to use the
601 +       Modified Version under the terms of this License, in the form
602 +       shown in the Addendum below.
603 +       </para>
604 +       </listitem>
605 +       <listitem>
606 +        <para>
607 +       G. Preserve in that license notice the full lists of
608 +       Invariant Sections and required Cover Texts given in the
609 +       Document's license notice.
610 +       </para>
611 +       </listitem>
612 +       <listitem>
613 +        <para>
614 +       H. Include an unaltered copy of this License.
615 +       </para>
616 +       </listitem>
617 +       <listitem>
618 +        <para>
619 +       I. Preserve the section entitled "History", and its title,
620 +       and add to it an item stating at least the title, year, new
621 +       authors, and publisher of the Modified Version as given on the
622 +       Title Page. If there is no section entitled "History" in the
623 +       Document, create one stating the title, year, authors, and
624 +       publisher of the Document as given on its Title Page, then add
625 +       an item describing the Modified Version as stated in the
626 +       previous sentence.
627 +       </para>
628 +       </listitem>
629 +       <listitem>
630 +        <para>
631 +        J. Preserve the network location, if any, given in the
632 +        Document for public access to a Transparent copy of the
633 +        Document, and likewise the network locations given in the
634 +        Document for previous versions it was based on. These may be
635 +        placed in the "History" section. You may omit a network
636 +        location for a work that was published at least four years
637 +        before the Document itself, or if the original publisher of
638 +        the version it refers to gives permission.
639 +       </para>
640 +       </listitem>
641 +       <listitem>
642 +        <para>
643 +        K. In any section entitled "Acknowledgements" or
644 +        "Dedications", preserve the section's title, and preserve in
645 +        the section all the substance and tone of each of the
646 +        contributor acknowledgements and/or dedications given therein.
647 +       </para>
648 +       </listitem>
649 +       <listitem>
650 +        <para>
651 +       L. Preserve all the Invariant Sections of the Document,
652 +       unaltered in their text and in their titles. Section numbers
653 +       or the equivalent are not considered part of the section
654 +       titles.
655 +       </para>
656 +       </listitem>
657 +       <listitem>
658 +        <para>
659 +       M. Delete any section entitled "Endorsements". Such a
660 +       section may not be included in the Modified Version.
661 +       </para>
662 +       </listitem>
663 +       <listitem>
664 +        <para>
665 +       N. Do not retitle any existing section as "Endorsements" or
666 +       to conflict in title with any Invariant Section.
667 +       </para>
668 +       </listitem>
669 +      </itemizedlist>
670 +     </para>
671 +
672 +     <para>
673 +       If the Modified Version includes new front-matter sections or
674 +       appendices that qualify as Secondary Sections and contain no
675 +       material copied from the Document, you may at your option
676 +       designate some or all of these sections as invariant. To do
677 +       this, add their titles to the list of Invariant Sections in the
678 +       Modified Version's license notice. These titles must be
679 +       distinct from any other section titles.
680 +     </para>
681 +
682 +     <para>
683 +       You may add a section entitled "Endorsements", provided it
684 +       contains nothing but endorsements of your Modified Version by
685 +       various parties--for example, statements of peer review or that
686 +       the text has been approved by an organization as the
687 +       authoritative definition of a standard.
688 +     </para>
689 +
690 +     <para>
691 +       You may add a passage of up to five words as a Front-Cover
692 +       Text, and a passage of up to 25 words as a Back-Cover Text, to
693 +       the end of the list of Cover Texts in the Modified
694 +       Version. Only one passage of Front-Cover Text and one of
695 +       Back-Cover Text may be added by (or through arrangements made
696 +       by) any one entity. If the Document already includes a cover
697 +       text for the same cover, previously added by you or by
698 +       arrangement made by the same entity you are acting on behalf
699 +       of, you may not add another; but you may replace the old one,
700 +       on explicit permission from the previous publisher that added
701 +       the old one.
702 +     </para>
703 +
704 +     <para>
705 +       The author(s) and publisher(s) of the Document do not by this
706 +       License give permission to use their names for publicity for or
707 +       to assert or imply endorsement of any Modified Version.
708 +     </para>
709 +
710 +     </sect1>
711 +     <sect1><title>5. COMBINING DOCUMENTS</title>
712 +
713 +     <para>
714 +       You may combine the Document with other documents released
715 +       under this License, under the terms defined in section 4 above
716 +       for modified versions, provided that you include in the
717 +       combination all of the Invariant Sections of all of the
718 +       original documents, unmodified, and list them all as Invariant
719 +       Sections of your combined work in its license notice.
720 +     </para>
721 +
722 +     <para>
723 +       The combined work need only contain one copy of this License,
724 +       and multiple identical Invariant Sections may be replaced with
725 +       a single copy. If there are multiple Invariant Sections with
726 +       the same name but different contents, make the title of each
727 +       such section unique by adding at the end of it, in parentheses,
728 +       the name of the original author or publisher of that section if
729 +       known, or else a unique number. Make the same adjustment to the
730 +       section titles in the list of Invariant Sections in the license
731 +       notice of the combined work.
732 +     </para>
733 +
734 +     <para>
735 +       In the combination, you must combine any sections entitled
736 +       "History" in the various original documents, forming one
737 +       section entitled "History"; likewise combine any sections
738 +       entitled "Acknowledgements", and any sections entitled
739 +       "Dedications". You must delete all sections entitled
740 +       "Endorsements."
741 +     </para>
742 +
743 +     </sect1>
744 +     <sect1><title>6. COLLECTIONS OF DOCUMENTS</title>
745 +
746 +     <para>
747 +       You may make a collection consisting of the Document and other
748 +       documents released under this License, and replace the
749 +       individual copies of this License in the various documents with
750 +       a single copy that is included in the collection, provided that
751 +       you follow the rules of this License for verbatim copying of
752 +       each of the documents in all other respects.
753 +     </para>
754 +
755 +     <para>
756 +       You may extract a single document from such a collection, and
757 +       distribute it individually under this License, provided you
758 +       insert a copy of this License into the extracted document, and
759 +       follow this License in all other respects regarding verbatim
760 +       copying of that document.
761 +     </para>
762 +
763 +     </sect1>
764 +     <sect1><title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
765 +
766 +     <para>
767 +       A compilation of the Document or its derivatives with other
768 +       separate and independent documents or works, in or on a volume
769 +       of a storage or distribution medium, does not as a whole count
770 +       as a Modified Version of the Document, provided no compilation
771 +       copyright is claimed for the compilation. Such a compilation is
772 +       called an "aggregate", and this License does not apply to the
773 +       other self-contained works thus compiled with the Document, on
774 +       account of their being thus compiled, if they are not
775 +       themselves derivative works of the Document.
776 +     </para>
777 +
778 +     <para>
779 +       If the Cover Text requirement of section 3 is applicable to
780 +       these copies of the Document, then if the Document is less than
781 +       one quarter of the entire aggregate, the Document's Cover Texts
782 +       may be placed on covers that surround only the Document within
783 +       the aggregate. Otherwise they must appear on covers around the
784 +       whole aggregate.
785 +     </para>
786 +
787 +     </sect1>
788 +     <sect1><title>8. TRANSLATION</title>
789 +
790 +     <para>
791 +       Translation is considered a kind of modification, so you may
792 +       distribute translations of the Document under the terms of
793 +       section 4. Replacing Invariant Sections with translations
794 +       requires special permission from their copyright holders, but
795 +       you may include translations of some or all Invariant Sections
796 +       in addition to the original versions of these Invariant
797 +       Sections. You may include a translation of this License
798 +       provided that you also include the original English version of
799 +       this License. In case of a disagreement between the translation
800 +       and the original English version of this License, the original
801 +       English version will prevail.
802 +     </para>
803 +
804 +     </sect1>
805 +     <sect1><title>9. TERMINATION</title>
806 +
807 +     <para>
808 +       You may not copy, modify, sublicense, or distribute the
809 +       Document except as expressly provided for under this
810 +       License. Any other attempt to copy, modify, sublicense or
811 +       distribute the Document is void, and will automatically
812 +       terminate your rights under this License. However, parties who
813 +       have received copies, or rights, from you under this License
814 +       will not have their licenses terminated so long as such parties
815 +       remain in full compliance.
816 +     </para>
817 +
818 +     </sect1>
819 +     <sect1><title>10. FUTURE REVISIONS OF THIS LICENSE</title>
820 +
821 +     <para>
822 +       The Free Software Foundation may publish new, revised versions
823 +       of the GNU Free Documentation License from time to time. Such
824 +       new versions will be similar in spirit to the present version,
825 +       but may differ in detail to address new problems or
826 +       concerns. See http://www.gnu.org/copyleft/.
827 +     </para>
828 +
829 +     <para>
830 +       Each version of the License is given a distinguishing version
831 +       number. If the Document specifies that a particular numbered
832 +       version of this License "or any later version" applies to it,
833 +       you have the option of following the terms and conditions
834 +       either of that specified version or of any later version that
835 +       has been published (not as a draft) by the Free Software
836 +       Foundation. If the Document does not specify a version number
837 +       of this License, you may choose any version ever published (not
838 +       as a draft) by the Free Software Foundation.
839 +     </para>
840 +
841 +     </sect1>
842 +  </appendix>
843 +</book>
844 diff -uprN linux-2.4.25.old/include/linux/icmpv6.h linux-2.4.25/include/linux/icmpv6.h
845 --- linux-2.4.25.old/include/linux/icmpv6.h     2003-08-25 12:44:44.000000000 +0100
846 +++ linux-2.4.25/include/linux/icmpv6.h 2004-06-26 11:29:29.000000000 +0100
847 @@ -40,14 +40,16 @@ struct icmp6hdr {
848                  struct icmpv6_nd_ra {
849                         __u8            hop_limit;
850  #if defined(__LITTLE_ENDIAN_BITFIELD)
851 -                       __u8            reserved:6,
852 +                       __u8            reserved:5,
853 +                                       home_agent:1,
854                                         other:1,
855                                         managed:1;
856  
857  #elif defined(__BIG_ENDIAN_BITFIELD)
858                         __u8            managed:1,
859                                         other:1,
860 -                                       reserved:6;
861 +                                       home_agent:1,
862 +                                       reserved:5;
863  #else
864  #error "Please fix <asm/byteorder.h>"
865  #endif
866 @@ -70,6 +72,7 @@ struct icmp6hdr {
867  #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
868  #define icmp6_addrconf_other   icmp6_dataun.u_nd_ra.other
869  #define icmp6_rt_lifetime      icmp6_dataun.u_nd_ra.rt_lifetime
870 +#define icmp6_home_agent       icmp6_dataun.u_nd_ra.home_agent
871  };
872  
873  
874 diff -uprN linux-2.4.25.old/include/linux/if_arp.h linux-2.4.25/include/linux/if_arp.h
875 --- linux-2.4.25.old/include/linux/if_arp.h     2002-02-25 19:38:13.000000000 +0000
876 +++ linux-2.4.25/include/linux/if_arp.h 2004-06-26 11:29:29.000000000 +0100
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 diff -uprN linux-2.4.25.old/include/linux/in6.h linux-2.4.25/include/linux/in6.h
887 --- linux-2.4.25.old/include/linux/in6.h        2003-06-13 15:51:38.000000000 +0100
888 +++ linux-2.4.25/include/linux/in6.h    2004-06-26 11:29:29.000000000 +0100
889 @@ -142,6 +142,11 @@ struct in6_flowlabel_req
890  #define IPV6_TLV_JUMBO         194
891  
892  /*
893 + *     Mobile IPv6 TLV options.
894 + */
895 +#define MIPV6_TLV_HOMEADDR     201
896 +
897 +/*
898   *     IPV6 socket options
899   */
900  
901 diff -uprN linux-2.4.25.old/include/linux/ipv6.h linux-2.4.25/include/linux/ipv6.h
902 --- linux-2.4.25.old/include/linux/ipv6.h       2003-11-28 18:26:21.000000000 +0000
903 +++ linux-2.4.25/include/linux/ipv6.h   2004-06-26 11:29:29.000000000 +0100
904 @@ -29,6 +29,7 @@ struct in6_ifreq {
905  
906  #define IPV6_SRCRT_STRICT      0x01    /* this hop must be a neighbor  */
907  #define IPV6_SRCRT_TYPE_0      0       /* IPv6 type 0 Routing Header   */
908 +#define IPV6_SRCRT_TYPE_2      2       /*      type 2 for Mobile IPv6  */
909  
910  /*
911   *     routing header
912 @@ -71,6 +72,19 @@ struct rt0_hdr {
913         struct in6_addr         addr[0];
914  
915  #define rt0_type               rt_hdr.type
916 +
917 +};
918 +
919 +/*
920 + *     routing header type 2
921 + */
922 +
923 +struct rt2_hdr {
924 +       struct ipv6_rt_hdr      rt_hdr;
925 +       __u32                   reserved;
926 +       struct in6_addr         addr;
927 +
928 +#define rt2_type               rt_hdr.type;
929  };
930  
931  /*
932 @@ -156,12 +170,16 @@ enum {
933  struct inet6_skb_parm
934  {
935         int                     iif;
936 +       __u8                    mipv6_flags;
937         __u16                   ra;
938         __u16                   hop;
939         __u16                   auth;
940         __u16                   dst0;
941         __u16                   srcrt;
942 +       __u16                   srcrt2;
943 +       __u16                   hao;
944         __u16                   dst1;
945 +       struct in6_addr         hoa;
946  };
947  
948  #endif
949 diff -uprN linux-2.4.25.old/include/linux/ipv6_route.h linux-2.4.25/include/linux/ipv6_route.h
950 --- linux-2.4.25.old/include/linux/ipv6_route.h 2003-11-28 18:26:21.000000000 +0000
951 +++ linux-2.4.25/include/linux/ipv6_route.h     2004-06-26 11:29:29.000000000 +0100
952 @@ -33,6 +33,7 @@ enum
953  #define RTF_CACHE      0x01000000      /* cache entry                  */
954  #define RTF_FLOW       0x02000000      /* flow significant route       */
955  #define RTF_POLICY     0x04000000      /* policy route                 */
956 +#define RTF_MOBILENODE  0x10000000      /* for routing to Mobile Node   */
957  
958  #define RTF_LOCAL      0x80000000
959  
960 diff -uprN linux-2.4.25.old/include/linux/ipv6_tunnel.h linux-2.4.25/include/linux/ipv6_tunnel.h
961 --- linux-2.4.25.old/include/linux/ipv6_tunnel.h        1970-01-01 01:00:00.000000000 +0100
962 +++ linux-2.4.25/include/linux/ipv6_tunnel.h    2004-06-26 11:29:29.000000000 +0100
963 @@ -0,0 +1,34 @@
964 +/*
965 + * $Id$
966 + */
967 +
968 +#ifndef _IPV6_TUNNEL_H
969 +#define _IPV6_TUNNEL_H
970 +
971 +#define IPV6_TLV_TNL_ENCAP_LIMIT 4
972 +#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
973 +
974 +/* don't add encapsulation limit if one isn't present in inner packet */
975 +#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
976 +/* copy the traffic class field from the inner packet */
977 +#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
978 +/* copy the flowlabel from the inner packet */
979 +#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
980 +/* created and maintained from within the kernel */
981 +#define IP6_TNL_F_KERNEL_DEV 0x8
982 +/* being used for Mobile IPv6 */
983 +#define IP6_TNL_F_MIP6_DEV 0x10
984 +
985 +struct ip6_tnl_parm {
986 +       char name[IFNAMSIZ];    /* name of tunnel device */
987 +       int link;               /* ifindex of underlying L2 interface */
988 +       __u8 proto;             /* tunnel protocol */
989 +       __u8 encap_limit;       /* encapsulation limit for tunnel */
990 +       __u8 hop_limit;         /* hop limit for tunnel */
991 +       __u32 flowinfo;         /* traffic class and flowlabel for tunnel */
992 +       __u32 flags;            /* tunnel flags */
993 +       struct in6_addr laddr;  /* local tunnel end-point address */
994 +       struct in6_addr raddr;  /* remote tunnel end-point address */
995 +};
996 +
997 +#endif
998 diff -uprN linux-2.4.25.old/include/linux/rtnetlink.h linux-2.4.25/include/linux/rtnetlink.h
999 --- linux-2.4.25.old/include/linux/rtnetlink.h  2004-02-18 13:36:32.000000000 +0000
1000 +++ linux-2.4.25/include/linux/rtnetlink.h      2004-06-26 11:29:29.000000000 +0100
1001 @@ -309,15 +309,17 @@ enum
1002         IFA_LABEL,
1003         IFA_BROADCAST,
1004         IFA_ANYCAST,
1005 -       IFA_CACHEINFO
1006 +       IFA_CACHEINFO,
1007 +       IFA_HOMEAGENT
1008  };
1009  
1010 -#define IFA_MAX IFA_CACHEINFO
1011 +#define IFA_MAX IFA_HOMEAGENT
1012  
1013  /* ifa_flags */
1014  
1015  #define IFA_F_SECONDARY                0x01
1016  
1017 +#define IFA_F_HOMEADDR         0x10
1018  #define IFA_F_DEPRECATED       0x20
1019  #define IFA_F_TENTATIVE                0x40
1020  #define IFA_F_PERMANENT                0x80
1021 diff -uprN linux-2.4.25.old/include/linux/skbuff.h linux-2.4.25/include/linux/skbuff.h
1022 --- linux-2.4.25.old/include/linux/skbuff.h     2003-08-25 12:44:44.000000000 +0100
1023 +++ linux-2.4.25/include/linux/skbuff.h 2004-06-26 11:29:29.000000000 +0100
1024 @@ -177,7 +177,7 @@ struct sk_buff {
1025          * want to keep them across layers you have to do a skb_clone()
1026          * first. This is owned by whoever has the skb queued ATM.
1027          */ 
1028 -       char            cb[48];  
1029 +       char            cb[64];  
1030  
1031         unsigned int    len;                    /* Length of actual data                        */
1032         unsigned int    data_len;
1033 diff -uprN linux-2.4.25.old/include/linux/sysctl.h linux-2.4.25/include/linux/sysctl.h
1034 --- linux-2.4.25.old/include/linux/sysctl.h     2004-02-18 13:36:32.000000000 +0000
1035 +++ linux-2.4.25/include/linux/sysctl.h 2004-06-26 11:29:29.000000000 +0100
1036 @@ -387,7 +387,24 @@ enum {
1037         NET_IPV6_NEIGH=17,
1038         NET_IPV6_ROUTE=18,
1039         NET_IPV6_ICMP=19,
1040 -       NET_IPV6_BINDV6ONLY=20
1041 +       NET_IPV6_BINDV6ONLY=20,
1042 +       NET_IPV6_MOBILITY=26
1043 +};
1044 +
1045 +/* /proc/sys/net/ipv6/mobility */
1046 +enum {
1047 +       NET_IPV6_MOBILITY_DEBUG=1,
1048 +       NET_IPV6_MOBILITY_TUNNEL_SITELOCAL=2,
1049 +       NET_IPV6_MOBILITY_ROUTER_SOLICITATION_MAX_SENDTIME=3,
1050 +       NET_IPV6_MOBILITY_ROUTER_REACH=4,
1051 +       NET_IPV6_MOBILITY_MDETECT_MECHANISM=5,
1052 +       NET_IPV6_MOBILITY_RETROUT=6,
1053 +       NET_IPV6_MOBILITY_MAX_TNLS=7,
1054 +       NET_IPV6_MOBILITY_MIN_TNLS=8,
1055 +       NET_IPV6_MOBILITY_BINDING_REFRESH=9,
1056 +       NET_IPV6_MOBILITY_BU_F_LLADDR=10,
1057 +       NET_IPV6_MOBILITY_BU_F_KEYMGM=11,
1058 +       NET_IPV6_MOBILITY_BU_F_CN_ACK=12
1059  };
1060  
1061  enum {
1062 diff -uprN linux-2.4.25.old/include/net/addrconf.h linux-2.4.25/include/net/addrconf.h
1063 --- linux-2.4.25.old/include/net/addrconf.h     2003-08-25 12:44:44.000000000 +0100
1064 +++ linux-2.4.25/include/net/addrconf.h 2004-06-26 11:29:29.000000000 +0100
1065 @@ -16,9 +16,11 @@ struct prefix_info {
1066  #if defined(__BIG_ENDIAN_BITFIELD)
1067         __u8                    onlink : 1,
1068                                 autoconf : 1,
1069 -                               reserved : 6;
1070 +                               router_address : 1,
1071 +                               reserved : 5;
1072  #elif defined(__LITTLE_ENDIAN_BITFIELD)
1073 -       __u8                    reserved : 6,
1074 +       __u8                    reserved : 5,
1075 +                               router_address : 1,
1076                                 autoconf : 1,
1077                                 onlink : 1;
1078  #else
1079 @@ -55,6 +57,7 @@ extern int                    ipv6_chk_addr(struct in6_ad
1080                                               struct net_device *dev);
1081  extern struct inet6_ifaddr *   ipv6_get_ifaddr(struct in6_addr *addr,
1082                                                 struct net_device *dev);
1083 +extern void                    ipv6_del_addr(struct inet6_ifaddr *ifp);
1084  extern int                     ipv6_get_saddr(struct dst_entry *dst, 
1085                                                struct in6_addr *daddr,
1086                                                struct in6_addr *saddr);
1087 @@ -85,7 +88,9 @@ extern void ipv6_mc_up(struct inet6_dev 
1088  extern void ipv6_mc_down(struct inet6_dev *idev);
1089  extern void ipv6_mc_init_dev(struct inet6_dev *idev);
1090  extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
1091 +extern void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1092  extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
1093 +extern void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1094  
1095  extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
1096                 struct in6_addr *src_addr);
1097 @@ -116,6 +121,9 @@ extern int                  ipv6_chk_acast_addr(struct 
1098  extern int register_inet6addr_notifier(struct notifier_block *nb);
1099  extern int unregister_inet6addr_notifier(struct notifier_block *nb);
1100  
1101 +extern int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
1102 +extern int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev);
1103 +
1104  static inline struct inet6_dev *
1105  __in6_dev_get(struct net_device *dev)
1106  {
1107 diff -uprN linux-2.4.25.old/include/net/ip6_route.h linux-2.4.25/include/net/ip6_route.h
1108 --- linux-2.4.25.old/include/net/ip6_route.h    2003-06-13 15:51:39.000000000 +0100
1109 +++ linux-2.4.25/include/net/ip6_route.h        2004-06-26 11:29:29.000000000 +0100
1110 @@ -2,6 +2,7 @@
1111  #define _NET_IP6_ROUTE_H
1112  
1113  #define IP6_RT_PRIO_FW         16
1114 +#define IP6_RT_PRIO_MIPV6              64
1115  #define IP6_RT_PRIO_USER       1024
1116  #define IP6_RT_PRIO_ADDRCONF   256
1117  #define IP6_RT_PRIO_KERN       512
1118 @@ -40,6 +41,9 @@ extern int                    ipv6_route_ioctl(unsigned i
1119  
1120  extern int                     ip6_route_add(struct in6_rtmsg *rtmsg,
1121                                               struct nlmsghdr *);
1122 +
1123 +extern int                     ip6_route_del(struct in6_rtmsg *rtmsg,
1124 +                                             struct nlmsghdr *);
1125  extern int                     ip6_del_rt(struct rt6_info *,
1126                                            struct nlmsghdr *);
1127  
1128 @@ -99,7 +103,8 @@ extern rwlock_t rt6_lock;
1129   */
1130  
1131  static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
1132 -                                    struct in6_addr *daddr)
1133 +                                struct in6_addr *daddr, 
1134 +                                struct in6_addr *saddr)
1135  {
1136         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
1137         struct rt6_info *rt = (struct rt6_info *) dst;
1138 @@ -107,6 +112,9 @@ static inline void ip6_dst_store(struct 
1139         write_lock(&sk->dst_lock);
1140         __sk_dst_set(sk, dst);
1141         np->daddr_cache = daddr;
1142 +#ifdef CONFIG_IPV6_SUBTREES
1143 +       np->saddr_cache = saddr;
1144 +#endif
1145         np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
1146         write_unlock(&sk->dst_lock);
1147  }
1148 diff -uprN linux-2.4.25.old/include/net/ipv6.h linux-2.4.25/include/net/ipv6.h
1149 --- linux-2.4.25.old/include/net/ipv6.h 2003-11-28 18:26:21.000000000 +0000
1150 +++ linux-2.4.25/include/net/ipv6.h     2004-06-26 11:29:29.000000000 +0100
1151 @@ -37,6 +37,7 @@
1152  #define NEXTHDR_ICMP           58      /* ICMP for IPv6. */
1153  #define NEXTHDR_NONE           59      /* No next header */
1154  #define NEXTHDR_DEST           60      /* Destination options header. */
1155 +#define NEXTHDR_MH             135     /* Mobility header, RFC 3775 */
1156  
1157  #define NEXTHDR_MAX            255
1158  
1159 @@ -145,9 +146,12 @@ struct ipv6_txoptions
1160         __u16                   opt_flen;       /* after fragment hdr */
1161         __u16                   opt_nflen;      /* before fragment hdr */
1162  
1163 +       __u8                    mipv6_flags;    /* flags set by MIPv6 */
1164 +
1165         struct ipv6_opt_hdr     *hopopt;
1166         struct ipv6_opt_hdr     *dst0opt;
1167 -       struct ipv6_rt_hdr      *srcrt; /* Routing Header */
1168 +       struct ipv6_rt_hdr      *srcrt; /* Routing Header Type 0 */
1169 +       struct ipv6_rt_hdr      *srcrt2; /* Routing Header Type 2 */
1170         struct ipv6_opt_hdr     *auth;
1171         struct ipv6_opt_hdr     *dst1opt;
1172  
1173 @@ -256,6 +260,38 @@ static inline int ipv6_addr_any(const st
1174                  a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
1175  }
1176  
1177 +static inline void ipv6_addr_prefix(struct in6_addr *pfx,
1178 +                                   const struct in6_addr *addr, int plen)
1179 +{
1180 +       /* caller must guarantee 0 <= plen <= 128 */
1181 +       int o = plen >> 3,
1182 +           b = plen & 0x7;
1183 +
1184 +       memcpy(pfx->s6_addr, addr, o);
1185 +       if (b != 0) {
1186 +               pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
1187 +               o++;
1188 +       }
1189 +       if (o < 16)
1190 +               memset(pfx->s6_addr + o, 0, 16 - o);
1191 +}
1192 +
1193 +static inline int ipv6_prefix_cmp(const struct in6_addr *p1,
1194 +                                 const struct in6_addr *p2, int plen)
1195 +{
1196 +       int b = plen&0x7;
1197 +       int o = plen>>3;
1198 +       int res = 0;
1199 +
1200 +       if (o > 0) 
1201 +               res = memcmp(&p1->s6_addr[0], &p2->s6_addr[0], o);
1202 +       if (res == 0 && b > 0) {
1203 +               __u8 m = (0xff00 >> b) & 0xff;
1204 +               res = (p1->s6_addr[o] & m) - (p2->s6_addr[o] & m);  
1205 +       }
1206 +       return res;
1207 +}
1208 +
1209  /*
1210   *     Prototypes exported by ipv6
1211   */
1212 diff -uprN linux-2.4.25.old/include/net/ipv6_tunnel.h linux-2.4.25/include/net/ipv6_tunnel.h
1213 --- linux-2.4.25.old/include/net/ipv6_tunnel.h  1970-01-01 01:00:00.000000000 +0100
1214 +++ linux-2.4.25/include/net/ipv6_tunnel.h      2004-06-26 11:29:29.000000000 +0100
1215 @@ -0,0 +1,92 @@
1216 +/*
1217 + * $Id$
1218 + */
1219 +
1220 +#ifndef _NET_IPV6_TUNNEL_H
1221 +#define _NET_IPV6_TUNNEL_H
1222 +
1223 +#include <linux/ipv6.h>
1224 +#include <linux/netdevice.h>
1225 +#include <linux/ipv6_tunnel.h>
1226 +#include <linux/skbuff.h>
1227 +#include <asm/atomic.h>
1228 +
1229 +/* capable of sending packets */
1230 +#define IP6_TNL_F_CAP_XMIT 0x10000
1231 +/* capable of receiving packets */
1232 +#define IP6_TNL_F_CAP_RCV 0x20000
1233 +
1234 +#define IP6_TNL_MAX 128
1235 +
1236 +/* IPv6 tunnel */
1237 +
1238 +struct ip6_tnl {
1239 +       struct ip6_tnl *next;   /* next tunnel in list */
1240 +       struct net_device *dev; /* virtual device associated with tunnel */
1241 +       struct net_device_stats stat;   /* statistics for tunnel device */
1242 +       int recursion;          /* depth of hard_start_xmit recursion */
1243 +       struct ip6_tnl_parm parms;      /* tunnel configuration paramters */
1244 +       struct flowi fl;        /* flowi template for xmit */
1245 +       atomic_t refcnt;        /* nr of identical tunnels used by kernel */
1246 +       struct socket *sock;
1247 +};
1248 +
1249 +#define IP6_TNL_PRE_ENCAP 0
1250 +#define IP6_TNL_PRE_DECAP 1
1251 +#define IP6_TNL_MAXHOOKS 2
1252 +
1253 +#define IP6_TNL_DROP 0
1254 +#define IP6_TNL_ACCEPT 1
1255 +
1256 +typedef int ip6_tnl_hookfn(struct ip6_tnl *t, struct sk_buff *skb);
1257 +
1258 +struct ip6_tnl_hook_ops {
1259 +       struct list_head list;
1260 +       unsigned int hooknum;
1261 +       int priority;
1262 +       ip6_tnl_hookfn *hook;
1263 +};
1264 +
1265 +enum ip6_tnl_hook_priorities {
1266 +       IP6_TNL_PRI_FIRST = INT_MIN,
1267 +       IP6_TNL_PRI_LAST = INT_MAX
1268 +};
1269 +
1270 +/* Tunnel encapsulation limit destination sub-option */
1271 +
1272 +struct ipv6_tlv_tnl_enc_lim {
1273 +       __u8 type;              /* type-code for option         */
1274 +       __u8 length;            /* option length                */
1275 +       __u8 encap_limit;       /* tunnel encapsulation limit   */
1276 +} __attribute__ ((packed));
1277 +
1278 +#ifdef __KERNEL__
1279 +extern int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt);
1280 +
1281 +extern struct ip6_tnl *ip6ip6_tnl_lookup(struct in6_addr *remote,
1282 +                                        struct in6_addr *local);
1283 +
1284 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p);
1285 +
1286 +extern int ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p);
1287 +
1288 +extern int ip6ip6_kernel_tnl_del(struct ip6_tnl *t);
1289 +
1290 +extern unsigned int ip6ip6_tnl_inc_max_kdev_count(unsigned int n);
1291 +
1292 +extern unsigned int ip6ip6_tnl_dec_max_kdev_count(unsigned int n);
1293 +
1294 +extern unsigned int ip6ip6_tnl_inc_min_kdev_count(unsigned int n);
1295 +
1296 +extern unsigned int ip6ip6_tnl_dec_min_kdev_count(unsigned int n);
1297 +
1298 +extern void ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg);
1299 +
1300 +extern void ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg);
1301 +
1302 +#ifdef CONFIG_IPV6_TUNNEL
1303 +extern int __init ip6_tunnel_init(void);
1304 +extern void ip6_tunnel_cleanup(void);
1305 +#endif
1306 +#endif
1307 +#endif
1308 diff -uprN linux-2.4.25.old/include/net/mipglue.h linux-2.4.25/include/net/mipglue.h
1309 --- linux-2.4.25.old/include/net/mipglue.h      1970-01-01 01:00:00.000000000 +0100
1310 +++ linux-2.4.25/include/net/mipglue.h  2004-06-26 11:29:29.000000000 +0100
1311 @@ -0,0 +1,266 @@
1312 +/*
1313 + *     Glue for Mobility support integration to IPv6
1314 + *
1315 + *     Authors:
1316 + *     Antti Tuominen          <ajtuomin@cc.hut.fi>    
1317 + *
1318 + *     $Id$
1319 + *
1320 + *     This program is free software; you can redistribute it and/or
1321 + *      modify it under the terms of the GNU General Public License
1322 + *      as published by the Free Software Foundation; either version
1323 + *      2 of the License, or (at your option) any later version.
1324 + *
1325 + */
1326 +
1327 +#ifndef _NET_MIPGLUE_H
1328 +#define _NET_MIPGLUE_H
1329 +
1330 +#ifndef USE_IPV6_MOBILITY
1331 +#if defined(CONFIG_IPV6_MOBILITY) || defined(CONFIG_IPV6_MOBILITY_MODULE)
1332 +#define USE_IPV6_MOBILITY
1333 +#endif
1334 +#endif
1335 +
1336 +/* symbols to indicate whether destination options received should take
1337 + * effect or not (see exthdrs.c, procrcv.c)
1338 + */
1339 +#define MIPV6_DSTOPTS_ACCEPT 1
1340 +#define MIPV6_DSTOPTS_DISCARD 0
1341 +
1342 +#define MIPV6_IGN_RTR 0
1343 +#define MIPV6_ADD_RTR 1
1344 +#define MIPV6_CHG_RTR 2
1345 +
1346 +/* MIPV6: Approximate maximum for mobile IPv6 options and headers */
1347 +#define MIPV6_HEADERS 48
1348 +
1349 +#ifdef __KERNEL__
1350 +#include <net/mipv6.h>
1351 +#include <linux/slab.h>
1352 +#include <net/ipv6.h>
1353 +
1354 +struct sk_buff;
1355 +struct ndisc_options;
1356 +struct sock;
1357 +struct ipv6_txoptions;
1358 +struct flowi;
1359 +struct dst_entry;
1360 +struct in6_addr;
1361 +struct inet6_ifaddr;
1362 +
1363 +#ifdef USE_IPV6_MOBILITY
1364 +
1365 +/* calls a procedure from mipv6-module */
1366 +#define MIPV6_CALLPROC(X) if(mipv6_functions.X) mipv6_functions.X
1367 +
1368 +/* calls a function from mipv6-module, default-value if function not defined
1369 + */
1370 +#define MIPV6_CALLFUNC(X,Y) (!mipv6_functions.X)?(Y):mipv6_functions.X
1371 +
1372 +/* sets a handler-function to process a call */
1373 +#define MIPV6_SETCALL(X,Y) if(mipv6_functions.X) printk("mipv6: Warning, function assigned twice!\n"); \
1374 +                           mipv6_functions.X = Y
1375 +#define MIPV6_RESETCALL(X) mipv6_functions.X = NULL
1376 +
1377 +/* pointers to mipv6 callable functions */
1378 +struct mipv6_callable_functions {
1379 +       void (*mipv6_initialize_dstopt_rcv) (struct sk_buff *skb);
1380 +       int (*mipv6_finalize_dstopt_rcv) (int process);
1381 +       int (*mipv6_handle_homeaddr) (struct sk_buff *skb, int optoff);
1382 +       int (*mipv6_ra_rcv) (struct sk_buff *skb,
1383 +                            struct ndisc_options *ndopts);
1384 +       void (*mipv6_icmp_rcv) (struct sk_buff *skb);
1385 +       struct ipv6_txoptions * (*mipv6_modify_txoptions) (
1386 +               struct sock *sk,
1387 +               struct sk_buff *skb, 
1388 +               struct ipv6_txoptions *opt,
1389 +               struct flowi *fl,
1390 +               struct dst_entry **dst);
1391 +       void (*mipv6_set_home) (int ifindex, struct in6_addr *homeaddr,
1392 +                               int plen, struct in6_addr *homeagent, 
1393 +                               int plen2);
1394 +       void (*mipv6_get_home_address) (struct in6_addr *home_addr);
1395 +       void (*mipv6_get_care_of_address)(struct in6_addr *homeaddr, 
1396 +                                         struct in6_addr *coa);
1397 +       int (*mipv6_is_home_addr)(struct in6_addr *addr);
1398 +       void (*mipv6_change_router)(void);
1399 +       void (*mipv6_check_dad)(struct in6_addr *home_addr);      
1400 +       void (*mipv6_icmp_swap_addrs)(struct sk_buff *skb);
1401 +       int (*mipv6_forward)(struct sk_buff *skb);
1402 +       int (*mipv6_mn_ha_probe)(struct inet6_ifaddr *ifp, u8 *lladdr);
1403 +};
1404 +
1405 +extern struct mipv6_callable_functions mipv6_functions;
1406 +
1407 +extern void mipv6_invalidate_calls(void);
1408 +
1409 +extern int mipv6_handle_dstopt(struct sk_buff *skb, int optoff);
1410 +
1411 +static inline int
1412 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1413 +{
1414 +       return MIPV6_CALLFUNC(mipv6_mn_ha_probe, 0)(ifp, lladdr);
1415 +}
1416 +
1417 +/* Must only be called for HA, no checks here */
1418 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1419 +{
1420 +       return MIPV6_CALLFUNC(mipv6_forward, 0)(skb);
1421 +}
1422 +
1423 +/* 
1424 + * Avoid adding new default routers if the old one is still in use 
1425 + */
1426 +
1427 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1428 +                                    struct ndisc_options *ndopts)
1429 +{
1430 +       return MIPV6_CALLFUNC(mipv6_ra_rcv, MIPV6_ADD_RTR)(skb, ndopts);
1431 +}
1432 +
1433 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1434 +{
1435 +       return MIPV6_CALLFUNC(mipv6_is_home_addr, 0)(addr);
1436 +}
1437 +
1438 +static inline void ndisc_mipv6_change_router(int change_rtr)
1439 +{
1440 +       if (change_rtr == MIPV6_CHG_RTR)
1441 +               MIPV6_CALLPROC(mipv6_change_router)();
1442 +}
1443 +
1444 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target)
1445 +{
1446 +       MIPV6_CALLPROC(mipv6_check_dad)(target);
1447 +}
1448 +
1449 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb)
1450 +{
1451 +       MIPV6_CALLPROC(mipv6_icmp_swap_addrs)(skb);
1452 +}
1453 +
1454 +static inline void mipv6_icmp_rcv(struct sk_buff *skb)
1455 +{
1456 +       MIPV6_CALLPROC(mipv6_icmp_rcv)(skb);
1457 +}
1458 +
1459 +static inline int tcp_v6_get_mipv6_header_len(void)
1460 +{
1461 +       return MIPV6_HEADERS;
1462 +}
1463 +
1464 +static inline struct in6_addr *
1465 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1466 +{
1467 +       return daddr;
1468 +}
1469 +
1470 +static inline void 
1471 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1472 +                          struct in6_addr *homeagent, int plen2)
1473 +{
1474 +       MIPV6_CALLPROC(mipv6_set_home)(ifindex, homeaddr, plen, homeagent, plen2);
1475 +}
1476 +
1477 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr)
1478 +{
1479 +       MIPV6_CALLPROC(mipv6_get_home_address)(saddr);
1480 +}
1481 +
1482 +static inline struct ipv6_txoptions *
1483 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb, 
1484 +                       struct ipv6_txoptions *opt, struct flowi *fl,
1485 +                       struct dst_entry **dst)
1486 +{
1487 +       return MIPV6_CALLFUNC(mipv6_modify_txoptions, opt)(sk, skb, opt, fl, dst); 
1488 +
1489 +}
1490 +
1491 +static inline void
1492 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb)
1493 +{
1494 +       struct inet6_skb_parm *opt;
1495 +       if (txopt) {
1496 +               opt = (struct inet6_skb_parm *)skb->cb;
1497 +               opt->mipv6_flags = txopt->mipv6_flags;
1498 +       }
1499 +}
1500 +
1501 +static inline void 
1502 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt,
1503 +                        struct ipv6_txoptions *orig_opt) 
1504 +{
1505 +       if (opt && opt != orig_opt)
1506 +               kfree(opt);
1507 +}
1508 +
1509 +#else /* USE_IPV6_MOBILITY */
1510 +
1511 +#define mipv6_handle_dstopt ip6_tlvopt_unknown
1512 +
1513 +static inline int
1514 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1515 +{
1516 +       return 0;
1517 +}
1518 +
1519 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1520 +{
1521 +       return 0;
1522 +}
1523 +
1524 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1525 +                                    struct ndisc_options *ndopts)
1526 +{
1527 +       return MIPV6_ADD_RTR;
1528 +}
1529 +
1530 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1531 +{
1532 +       return 0;
1533 +}
1534 +
1535 +static inline void ndisc_mipv6_change_router(int change_rtr) {}
1536 +
1537 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target) {}
1538 +
1539 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb) {}
1540 +
1541 +static inline void mipv6_icmp_rcv(struct sk_buff *skb) {}
1542 +
1543 +static inline int tcp_v6_get_mipv6_header_len(void)
1544 +{
1545 +       return 0;
1546 +}
1547 +
1548 +static inline struct in6_addr *
1549 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1550 +{
1551 +       return hdaddr;
1552 +}
1553 +
1554 +static inline void 
1555 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1556 +                          struct in6_addr *homeagent, int plen2) {}
1557 +
1558 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr) {}
1559 +
1560 +static inline struct ipv6_txoptions *
1561 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb,
1562 +                       struct ipv6_txoptions *opt, struct flowi *fl,
1563 +                       struct dst_entry **dst)
1564 +{
1565 +       return opt;
1566 +}
1567 +
1568 +static inline void
1569 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb) {}
1570 +
1571 +static inline void 
1572 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt, 
1573 +                        struct ipv6_txoptions *orig_opt) {}
1574 +
1575 +#endif /* USE_IPV6_MOBILITY */
1576 +#endif /* __KERNEL__ */
1577 +#endif /* _NET_MIPGLUE_H */
1578 diff -uprN linux-2.4.25.old/include/net/mipv6.h linux-2.4.25/include/net/mipv6.h
1579 --- linux-2.4.25.old/include/net/mipv6.h        1970-01-01 01:00:00.000000000 +0100
1580 +++ linux-2.4.25/include/net/mipv6.h    2004-06-26 11:29:29.000000000 +0100
1581 @@ -0,0 +1,258 @@
1582 +/*
1583 + *     Mobile IPv6 header-file
1584 + *
1585 + *     Authors:
1586 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
1587 + *
1588 + *     $Id$
1589 + *
1590 + *     This program is free software; you can redistribute it and/or
1591 + *      modify it under the terms of the GNU General Public License
1592 + *      as published by the Free Software Foundation; either version
1593 + *      2 of the License, or (at your option) any later version.
1594 + *
1595 + */
1596 +
1597 +#ifndef _NET_MIPV6_H
1598 +#define _NET_MIPV6_H
1599 +
1600 +#include <linux/types.h>
1601 +#include <asm/byteorder.h>
1602 +#include <linux/in6.h>
1603 +
1604 +/*
1605 + *
1606 + * Mobile IPv6 Protocol constants
1607 + *
1608 + */
1609 +#define DHAAD_RETRIES                  4       /* transmissions        */
1610 +#define INITIAL_BINDACK_TIMEOUT                1       /* seconds              */
1611 +#define INITIAL_DHAAD_TIMEOUT          3       /* seconds              */
1612 +#define INITIAL_SOLICIT_TIMER          3       /* seconds              */
1613 +#define MAX_BINDACK_TIMEOUT            32      /* seconds              */
1614 +#define MAX_NONCE_LIFE                 240     /* seconds              */
1615 +#define MAX_TOKEN_LIFE                 210     /* seconds              */
1616 +#define MAX_RR_BINDING_LIFE            420     /* seconds              */
1617 +#define MAX_UPDATE_RATE                        3       /* 1/s (min delay=1s)   */
1618 +#define PREFIX_ADV_RETRIES             3       /* transmissions        */
1619 +#define PREFIX_ADV_TIMEOUT             3       /* seconds              */
1620 +
1621 +#define MAX_FAST_UPDATES               5       /* transmissions        */
1622 +#define MAX_PFX_ADV_DELAY              1000    /* seconds              */
1623 +#define SLOW_UPDATE_RATE               10      /* 1/10s (max delay=10s)*/
1624 +#define INITIAL_BINDACK_DAD_TIMEOUT    2       /* seconds              */
1625 +
1626 +/*
1627 + *
1628 + * Mobile IPv6 (RFC 3775) Protocol configuration variable defaults
1629 + *
1630 + */
1631 +#define DefHomeRtrAdvInterval          1000    /* seconds              */
1632 +#define DefMaxMobPfxAdvInterval                86400   /* seconds              */
1633 +#define DefMinDelayBetweenRAs          3       /* seconds (min 0.03)   */
1634 +#define DefMinMobPfxAdvInterval                600     /* seconds              */
1635 +#define DefInitialBindackTimeoutFirstReg       1.5 /* seconds          */
1636 +
1637 +/* This is not actually specified in the draft, but is needed to avoid
1638 + * prefix solicitation storm when valid lifetime of a prefix is smaller
1639 + * than MAX_PFX_ADV_DELAY
1640 + */
1641 +#define MIN_PFX_SOL_DELAY              5       /* seconds              */
1642 +
1643 +/* Mobile IPv6 ICMP types                */
1644 +/*
1645 + * Official numbers from RFC 3775
1646 + */
1647 +#define MIPV6_DHAAD_REQUEST            144
1648 +#define MIPV6_DHAAD_REPLY              145
1649 +#define MIPV6_PREFIX_SOLICIT           146
1650 +#define MIPV6_PREFIX_ADV               147
1651 +
1652 +/* Binding update flag codes              */
1653 +#define MIPV6_BU_F_ACK                 0x80
1654 +#define MIPV6_BU_F_HOME                        0x40
1655 +#define MIPV6_BU_F_LLADDR              0x20
1656 +#define MIPV6_BU_F_KEYMGM              0x10
1657 +
1658 +/* Binding ackknowledgment flag codes */
1659 +#define MIPV6_BA_F_KEYMGM              0x80
1660 +
1661 +/* Binding error status */
1662 +#define MIPV6_BE_HAO_WO_BINDING                1
1663 +#define MIPV6_BE_UNKNOWN_MH_TYPE       2
1664 +
1665 +/* Mobility Header */
1666 +struct mipv6_mh
1667 +{
1668 +       __u8    payload;                /* Payload Protocol             */
1669 +       __u8    length;                 /* MH Length                    */
1670 +       __u8    type;                   /* MH Type                      */
1671 +       __u8    reserved;               /* Reserved                     */
1672 +       __u16   checksum;               /* Checksum                     */
1673 +       __u8    data[0];                /* Message specific data        */
1674 +} __attribute__ ((packed));
1675 +
1676 +/* Mobility Header type */
1677 +#define IPPROTO_MOBILITY                135 /* RFC 3775*/                
1678 +/* Mobility Header Message Types */
1679 +
1680 +#define MIPV6_MH_BRR                   0
1681 +#define MIPV6_MH_HOTI                  1
1682 +#define MIPV6_MH_COTI                  2
1683 +#define MIPV6_MH_HOT                   3
1684 +#define MIPV6_MH_COT                   4
1685 +#define MIPV6_MH_BU                    5
1686 +#define MIPV6_MH_BA                    6
1687 +#define MIPV6_MH_BE                    7
1688 +
1689 +/*
1690 + * Status codes for Binding Acknowledgements
1691 + */
1692 +#define SUCCESS                                0
1693 +#define REASON_UNSPECIFIED             128
1694 +#define ADMINISTRATIVELY_PROHIBITED    129
1695 +#define INSUFFICIENT_RESOURCES         130
1696 +#define HOME_REGISTRATION_NOT_SUPPORTED        131
1697 +#define NOT_HOME_SUBNET                        132
1698 +#define NOT_HA_FOR_MN                  133
1699 +#define DUPLICATE_ADDR_DETECT_FAIL     134
1700 +#define SEQUENCE_NUMBER_OUT_OF_WINDOW  135
1701 +#define EXPIRED_HOME_NONCE_INDEX       136
1702 +#define EXPIRED_CAREOF_NONCE_INDEX     137
1703 +#define EXPIRED_NONCES                 138
1704 +#define REG_TYPE_CHANGE_FORBIDDEN       139
1705 +/*
1706 + * Values for mipv6_flags in struct inet6_skb_parm
1707 + */
1708 +
1709 +#define MIPV6_RCV_TUNNEL               0x1
1710 +#define MIPV6_SND_HAO                  0x2
1711 +#define MIPV6_SND_BU                    0x4
1712 +
1713 +/*
1714 + * Mobility Header Message structures
1715 + */
1716 +
1717 +struct mipv6_mh_brr
1718 +{
1719 +       __u16           reserved;
1720 +       /* Mobility options */
1721 +} __attribute__ ((packed));
1722 +
1723 +struct mipv6_mh_bu
1724 +{
1725 +       __u16           sequence;       /* sequence number of BU        */
1726 +       __u8            flags;          /* flags                        */
1727 +       __u8            reserved;       /* reserved bits                */
1728 +       __u16           lifetime;       /* lifetime of BU               */
1729 +       /* Mobility options */
1730 +} __attribute__ ((packed));
1731 +
1732 +struct mipv6_mh_ba
1733 +{
1734 +       __u8            status;         /* statuscode                   */
1735 +       __u8            reserved;       /* reserved bits                */
1736 +       __u16           sequence;       /* sequence number of BA        */
1737 +       __u16           lifetime;       /* lifetime in CN's bcache      */
1738 +       /* Mobility options */
1739 +} __attribute__ ((packed));
1740 +
1741 +struct mipv6_mh_be
1742 +{
1743 +       __u8            status;
1744 +       __u8            reserved;
1745 +       struct in6_addr home_addr;
1746 +       /* Mobility options */
1747 +} __attribute__ ((packed));
1748 +
1749 +struct mipv6_mh_addr_ti
1750 +{
1751 +       __u16           reserved;       /* Reserved                     */
1752 +       u_int8_t        init_cookie[8]; /* HoT/CoT Init Cookie          */
1753 +       /* Mobility options */
1754 +} __attribute__ ((packed));
1755 +
1756 +struct mipv6_mh_addr_test
1757 +{
1758 +       __u16           nonce_index;    /* Home/Care-of Nonce Index     */
1759 +       u_int8_t        init_cookie[8]; /* HoT/CoT Init Cookie          */
1760 +       u_int8_t        kgen_token[8];  /* Home/Care-of key generation token */
1761 +       /* Mobility options */
1762 +} __attribute__ ((packed));
1763 +
1764 +/*
1765 + * Mobility Options for various MH types.
1766 + */
1767 +#define MIPV6_OPT_PAD1                 0x00
1768 +#define MIPV6_OPT_PADN                 0x01
1769 +#define MIPV6_OPT_BIND_REFRESH_ADVICE  0x02
1770 +#define MIPV6_OPT_ALTERNATE_COA                0x03
1771 +#define MIPV6_OPT_NONCE_INDICES                0x04
1772 +#define MIPV6_OPT_AUTH_DATA            0x05
1773 +
1774 +#define MIPV6_SEQ_GT(x,y) \
1775 +        ((short int)(((__u16)(x)) - ((__u16)(y))) > 0)
1776 +
1777 +/*
1778 + * Mobility Option structures
1779 + */
1780 +
1781 +struct mipv6_mo
1782 +{
1783 +       __u8            type;
1784 +       __u8            length;
1785 +       __u8            value[0];       /* type specific data */
1786 +} __attribute__ ((packed));
1787 +
1788 +struct mipv6_mo_pad1
1789 +{
1790 +       __u8            type;
1791 +} __attribute__ ((packed));
1792 +
1793 +struct mipv6_mo_padn
1794 +{
1795 +       __u8            type;
1796 +       __u8            length;
1797 +       __u8            data[0];
1798 +} __attribute__ ((packed));
1799 +
1800 +struct mipv6_mo_alt_coa
1801 +{
1802 +       __u8            type;
1803 +       __u8            length;
1804 +       struct in6_addr addr;           /* alternate care-of-address    */
1805 +} __attribute__ ((packed));
1806 +
1807 +struct mipv6_mo_nonce_indices
1808 +{
1809 +       __u8            type;
1810 +       __u8            length;
1811 +       __u16           home_nonce_i;   /* Home Nonce Index             */
1812 +       __u16           careof_nonce_i; /* Careof Nonce Index           */
1813 +} __attribute__ ((packed)); 
1814 +
1815 +struct mipv6_mo_bauth_data
1816 +{
1817 +       __u8            type;
1818 +       __u8            length;
1819 +       __u8            data[0];
1820 +} __attribute__ ((packed)); 
1821 +
1822 +struct mipv6_mo_br_advice
1823 +{
1824 +       __u8            type;
1825 +       __u8            length;
1826 +       __u16           refresh_interval; /* Refresh Interval           */
1827 +} __attribute__ ((packed));
1828 +
1829 +/*
1830 + * Home Address Destination Option structure
1831 + */
1832 +struct mipv6_dstopt_homeaddr
1833 +{
1834 +       __u8            type;           /* type-code for option         */
1835 +       __u8            length;         /* option length                */
1836 +       struct in6_addr addr;           /* home address                 */
1837 +} __attribute__ ((packed));
1838 +
1839 +#endif /* _NET_MIPV6_H */
1840 diff -uprN linux-2.4.25.old/include/net/ndisc.h linux-2.4.25/include/net/ndisc.h
1841 --- linux-2.4.25.old/include/net/ndisc.h        2002-11-28 23:53:15.000000000 +0000
1842 +++ linux-2.4.25/include/net/ndisc.h    2004-06-26 11:29:29.000000000 +0100
1843 @@ -21,6 +21,10 @@
1844  #define ND_OPT_REDIRECT_HDR            4
1845  #define ND_OPT_MTU                     5
1846  
1847 +/* Mobile IPv6 specific ndisc options */ 
1848 +#define ND_OPT_RTR_ADV_INTERVAL                7 
1849 +#define ND_OPT_HOME_AGENT_INFO         8  
1850 +
1851  #define MAX_RTR_SOLICITATION_DELAY     HZ
1852  
1853  #define ND_REACHABLE_TIME              (30*HZ)
1854 @@ -57,7 +61,7 @@ struct nd_opt_hdr {
1855  } __attribute__((__packed__));
1856  
1857  struct ndisc_options {
1858 -       struct nd_opt_hdr *nd_opt_array[7];
1859 +       struct nd_opt_hdr *nd_opt_array[10];
1860         struct nd_opt_hdr *nd_opt_piend;
1861  };
1862  
1863 @@ -67,6 +71,8 @@ struct ndisc_options {
1864  #define nd_opts_pi_end         nd_opt_piend
1865  #define nd_opts_rh             nd_opt_array[ND_OPT_REDIRECT_HDR]
1866  #define nd_opts_mtu            nd_opt_array[ND_OPT_MTU]
1867 +#define nd_opts_rai            nd_opt_array[ND_OPT_RTR_ADV_INTERVAL]
1868 +#define nd_opts_hai            nd_opt_array[ND_OPT_HOME_AGENT_INFO]
1869  
1870  extern struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end);
1871  extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts);
1872 @@ -83,6 +89,15 @@ extern void                  ndisc_send_ns(struct net_d
1873                                               struct in6_addr *daddr,
1874                                               struct in6_addr *saddr);
1875  
1876 +extern void                    ndisc_send_na(struct net_device *dev,
1877 +                                             struct neighbour *neigh,
1878 +                                             struct in6_addr *daddr,
1879 +                                             struct in6_addr *solicited_addr,
1880 +                                             int router,
1881 +                                             int solicited,
1882 +                                             int override,
1883 +                                             int inc_opt);
1884 +
1885  extern void                    ndisc_send_rs(struct net_device *dev,
1886                                               struct in6_addr *saddr,
1887                                               struct in6_addr *daddr);
1888 diff -uprN linux-2.4.25.old/include/net/sock.h linux-2.4.25/include/net/sock.h
1889 --- linux-2.4.25.old/include/net/sock.h 2004-02-18 13:36:32.000000000 +0000
1890 +++ linux-2.4.25/include/net/sock.h     2004-06-26 11:29:30.000000000 +0100
1891 @@ -149,7 +149,9 @@ struct ipv6_pinfo {
1892         struct in6_addr         rcv_saddr;
1893         struct in6_addr         daddr;
1894         struct in6_addr         *daddr_cache;
1895 -
1896 +#if defined(CONFIG_IPV6_SUBTREES)
1897 +       struct in6_addr         *saddr_cache;
1898 +#endif
1899         __u32                   flow_label;
1900         __u32                   frag_size;
1901         int                     hop_limit;
1902 diff -uprN linux-2.4.25.old/net/Makefile linux-2.4.25/net/Makefile
1903 --- linux-2.4.25.old/net/Makefile       2004-06-26 11:22:00.000000000 +0100
1904 +++ linux-2.4.25/net/Makefile   2004-06-26 11:29:30.000000000 +0100
1905 @@ -7,7 +7,7 @@
1906  
1907  O_TARGET :=    network.o
1908  
1909 -mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp
1910 +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp ipv6
1911  export-objs := netsyms.o
1912  
1913  subdir-y :=    core ethernet
1914 @@ -25,6 +25,7 @@ subdir-$(CONFIG_IP_SCTP)      += sctp
1915  ifneq ($(CONFIG_IPV6),n)
1916  ifneq ($(CONFIG_IPV6),)
1917  subdir-$(CONFIG_NETFILTER)     += ipv6/netfilter
1918 +subdir-$(CONFIG_IPV6_MOBILITY) += ipv6/mobile_ip6
1919  endif
1920  endif
1921  
1922 diff -uprN linux-2.4.25.old/net/core/neighbour.c linux-2.4.25/net/core/neighbour.c
1923 --- linux-2.4.25.old/net/core/neighbour.c       2004-02-18 13:36:32.000000000 +0000
1924 +++ linux-2.4.25/net/core/neighbour.c   2004-06-26 11:29:30.000000000 +0100
1925 @@ -386,7 +386,7 @@ struct pneigh_entry * pneigh_lookup(stru
1926         if (!creat)
1927                 return NULL;
1928  
1929 -       n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
1930 +       n = kmalloc(sizeof(*n) + key_len, GFP_ATOMIC);
1931         if (n == NULL)
1932                 return NULL;
1933  
1934 diff -uprN linux-2.4.25.old/net/ipv6/Config.in linux-2.4.25/net/ipv6/Config.in
1935 --- linux-2.4.25.old/net/ipv6/Config.in 2001-12-21 17:42:05.000000000 +0000
1936 +++ linux-2.4.25/net/ipv6/Config.in     2004-06-26 11:29:30.000000000 +0100
1937 @@ -1,10 +1,16 @@
1938  #
1939  # IPv6 configuration
1940  # 
1941 -
1942 +bool '    IPv6: routing by source address (EXPERIMENTAL)' CONFIG_IPV6_SUBTREES
1943  #bool '    IPv6: flow policy support' CONFIG_RT6_POLICY
1944  #bool '    IPv6: firewall support' CONFIG_IPV6_FIREWALL
1945  
1946 +if [ "$CONFIG_IPV6" != "n" ]; then
1947 +       dep_tristate '    IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)' CONFIG_IPV6_TUNNEL $CONFIG_IPV6
1948 +fi
1949 +
1950 +source net/ipv6/mobile_ip6/Config.in
1951 +
1952  if [ "$CONFIG_NETFILTER" != "n" ]; then
1953     source net/ipv6/netfilter/Config.in
1954  fi
1955 diff -uprN linux-2.4.25.old/net/ipv6/Makefile linux-2.4.25/net/ipv6/Makefile
1956 --- linux-2.4.25.old/net/ipv6/Makefile  2003-11-28 18:26:21.000000000 +0000
1957 +++ linux-2.4.25/net/ipv6/Makefile      2004-06-26 11:29:30.000000000 +0100
1958 @@ -6,18 +6,28 @@
1959  # unless it's something special (ie not a .c file).
1960  #
1961  
1962 +export-objs := ipv6_syms.o ipv6_tunnel.o
1963  
1964 -O_TARGET := ipv6.o
1965 +#list-multi    := ipv6.o ipv6_tunnel.o
1966  
1967 -obj-y :=       af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
1968 -               route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
1969 -               protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1970 -               exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1971 -               ip6_flowlabel.o ipv6_syms.o
1972 +ipv6-objs      := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
1973 +                  sit.o route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \
1974 +                  raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1975 +                  exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1976 +                  ip6_flowlabel.o ipv6_syms.o
1977 +
1978 +ifneq ($(CONFIG_IPV6_MOBILITY),n)
1979 +ifneq ($(CONFIG_IPV6_MOBILITY),)
1980 +ipv6-objs += mipglue.o
1981 +endif
1982 +endif
1983  
1984 -export-objs := ipv6_syms.o
1985 +obj-$(CONFIG_IPV6)  += ipv6.o
1986 +obj-$(CONFIG_IPV6_TUNNEL)  += ipv6_tunnel.o
1987 +
1988 +ipv6.o: $(ipv6-objs)
1989 +       $(LD) -r -o $@ $(ipv6-objs)
1990  
1991 -obj-m  := $(O_TARGET)
1992  
1993  #obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
1994  
1995 diff -uprN linux-2.4.25.old/net/ipv6/addrconf.c linux-2.4.25/net/ipv6/addrconf.c
1996 --- linux-2.4.25.old/net/ipv6/addrconf.c        2003-11-28 18:26:21.000000000 +0000
1997 +++ linux-2.4.25/net/ipv6/addrconf.c    2004-06-26 11:29:30.000000000 +0100
1998 @@ -68,6 +68,8 @@
1999  
2000  #include <asm/uaccess.h>
2001  
2002 +#include <net/mipglue.h>
2003 +
2004  #define IPV6_MAX_ADDRESSES 16
2005  
2006  /* Set to 3 to get tracing... */
2007 @@ -103,9 +105,9 @@ static spinlock_t addrconf_verify_lock =
2008  
2009  static int addrconf_ifdown(struct net_device *dev, int how);
2010  
2011 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
2012 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
2013  static void addrconf_dad_timer(unsigned long data);
2014 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
2015 +void addrconf_dad_completed(struct inet6_ifaddr *ifp);
2016  static void addrconf_rs_timer(unsigned long data);
2017  static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
2018  
2019 @@ -330,38 +332,6 @@ static struct inet6_dev * ipv6_find_idev
2020         return idev;
2021  }
2022  
2023 -void ipv6_addr_prefix(struct in6_addr *prefix,
2024 -       struct in6_addr *addr, int prefix_len)
2025 -{
2026 -       unsigned long mask;
2027 -       int ncopy, nbits;
2028 -
2029 -       memset(prefix, 0, sizeof(*prefix));
2030 -
2031 -       if (prefix_len <= 0)
2032 -               return;
2033 -       if (prefix_len > 128)
2034 -               prefix_len = 128;
2035 -
2036 -       ncopy = prefix_len / 32;
2037 -       switch (ncopy) {
2038 -       case 4: prefix->s6_addr32[3] = addr->s6_addr32[3];
2039 -       case 3: prefix->s6_addr32[2] = addr->s6_addr32[2];
2040 -       case 2: prefix->s6_addr32[1] = addr->s6_addr32[1];
2041 -       case 1: prefix->s6_addr32[0] = addr->s6_addr32[0];
2042 -       case 0: break;
2043 -       }
2044 -       nbits = prefix_len % 32;
2045 -       if (nbits == 0)
2046 -               return;
2047 -
2048 -       mask = ~((1 << (32 - nbits)) - 1);
2049 -       mask = htonl(mask);
2050 -
2051 -       prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask;
2052 -}
2053 -
2054 -
2055  static void dev_forward_change(struct inet6_dev *idev)
2056  {
2057         struct net_device *dev;
2058 @@ -513,7 +483,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
2059  
2060  /* This function wants to get referenced ifp and releases it before return */
2061  
2062 -static void ipv6_del_addr(struct inet6_ifaddr *ifp)
2063 +void ipv6_del_addr(struct inet6_ifaddr *ifp)
2064  {
2065         struct inet6_ifaddr *ifa, **ifap;
2066         struct inet6_dev *idev = ifp->idev;
2067 @@ -662,6 +632,12 @@ out:
2068         if (match)
2069                 in6_ifa_put(match);
2070  
2071 +       /* The home address is always used as source address in
2072 +        * MIPL mobile IPv6
2073 +        */
2074 +       if (scope != IFA_HOST && scope != IFA_LINK)
2075 +               addrconf_get_mipv6_home_address(saddr);
2076 +
2077         return err;
2078  }
2079  
2080 @@ -815,7 +791,7 @@ void addrconf_leave_solict(struct net_de
2081  }
2082  
2083  
2084 -static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2085 +int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2086  {
2087         switch (dev->type) {
2088         case ARPHRD_ETHER:
2089 @@ -840,7 +816,7 @@ static int ipv6_generate_eui64(u8 *eui, 
2090         return -1;
2091  }
2092  
2093 -static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2094 +int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2095  {
2096         int err = -1;
2097         struct inet6_ifaddr *ifp;
2098 @@ -1407,6 +1383,24 @@ static void addrconf_sit_config(struct n
2099                 sit_route_add(dev);
2100  }
2101  
2102 +/**
2103 + * addrconf_ipv6_tunnel_config - configure IPv6 tunnel device
2104 + * @dev: tunnel device
2105 + **/
2106 +
2107 +static void addrconf_ipv6_tunnel_config(struct net_device *dev)
2108 +{
2109 +       struct inet6_dev *idev;
2110 +
2111 +       ASSERT_RTNL();
2112 +
2113 +       /* Assign inet6_dev structure to tunnel device */
2114 +       if ((idev = ipv6_find_idev(dev)) == NULL) {
2115 +               printk(KERN_DEBUG "init ipv6 tunnel: add_dev failed\n");
2116 +               return;
2117 +       }
2118 +}
2119 +
2120  
2121  int addrconf_notify(struct notifier_block *this, unsigned long event, 
2122                     void * data)
2123 @@ -1421,6 +1415,10 @@ int addrconf_notify(struct notifier_bloc
2124                         addrconf_sit_config(dev);
2125                         break;
2126  
2127 +               case ARPHRD_TUNNEL6:
2128 +                       addrconf_ipv6_tunnel_config(dev);
2129 +                       break;
2130 +
2131                 case ARPHRD_LOOPBACK:
2132                         init_loopback(dev);
2133                         break;
2134 @@ -1602,7 +1600,7 @@ out:
2135  /*
2136   *     Duplicate Address Detection
2137   */
2138 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2139 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2140  {
2141         struct net_device *dev;
2142         unsigned long rand_num;
2143 @@ -1667,7 +1665,7 @@ static void addrconf_dad_timer(unsigned 
2144         in6_ifa_put(ifp);
2145  }
2146  
2147 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2148 +void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2149  {
2150         struct net_device *     dev = ifp->idev->dev;
2151  
2152 @@ -1676,7 +1674,7 @@ static void addrconf_dad_completed(struc
2153          */
2154  
2155         ipv6_ifa_notify(RTM_NEWADDR, ifp);
2156 -
2157 +       notifier_call_chain(&inet6addr_chain,NETDEV_UP,ifp);
2158         /* If added prefix is link local and forwarding is off,
2159            start sending router solicitations.
2160          */
2161 @@ -1877,8 +1875,20 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
2162         if (rta[IFA_LOCAL-1]) {
2163                 if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
2164                         return -EINVAL;
2165 +               if (ifm->ifa_flags & IFA_F_HOMEADDR && !rta[IFA_HOMEAGENT-1])
2166 +                       return -EINVAL;
2167                 pfx = RTA_DATA(rta[IFA_LOCAL-1]);
2168         }
2169 +       if (rta[IFA_HOMEAGENT-1]) {
2170 +               struct in6_addr *ha;
2171 +               if (pfx == NULL || !(ifm->ifa_flags & IFA_F_HOMEADDR))
2172 +                       return -EINVAL;
2173 +               if (RTA_PAYLOAD(rta[IFA_HOMEAGENT-1]) < sizeof(*ha))
2174 +                       return -EINVAL;
2175 +               ha = RTA_DATA(rta[IFA_HOMEAGENT-1]);
2176 +               addrconf_set_mipv6_mn_home(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
2177 +                                          ha, ifm->ifa_prefixlen);
2178 +       }
2179         if (pfx == NULL)
2180                 return -EINVAL;
2181  
2182 diff -uprN linux-2.4.25.old/net/ipv6/af_inet6.c linux-2.4.25/net/ipv6/af_inet6.c
2183 --- linux-2.4.25.old/net/ipv6/af_inet6.c        2003-11-28 18:26:21.000000000 +0000
2184 +++ linux-2.4.25/net/ipv6/af_inet6.c    2004-06-26 11:29:30.000000000 +0100
2185 @@ -58,6 +58,9 @@
2186  #include <net/transp_v6.h>
2187  #include <net/ip6_route.h>
2188  #include <net/addrconf.h>
2189 +#ifdef CONFIG_IPV6_TUNNEL
2190 +#include <net/ipv6_tunnel.h>
2191 +#endif
2192  
2193  #include <asm/uaccess.h>
2194  #include <asm/system.h>
2195 @@ -646,6 +649,11 @@ static int __init inet6_init(void)
2196         err = ndisc_init(&inet6_family_ops);
2197         if (err)
2198                 goto ndisc_fail;
2199 +#ifdef CONFIG_IPV6_TUNNEL
2200 +       err = ip6_tunnel_init();
2201 +       if (err)
2202 +               goto ip6_tunnel_fail;
2203 +#endif
2204         err = igmp6_init(&inet6_family_ops);
2205         if (err)
2206                 goto igmp_fail;
2207 @@ -698,6 +706,10 @@ proc_raw6_fail:
2208  #endif
2209  igmp_fail:
2210         ndisc_cleanup();
2211 +#ifdef CONFIG_IPV6_TUNNEL
2212 +       ip6_tunnel_cleanup();
2213 +ip6_tunnel_fail:
2214 +#endif
2215  ndisc_fail:
2216         icmpv6_cleanup();
2217  icmp_fail:
2218 @@ -730,6 +742,9 @@ static void inet6_exit(void)
2219         ip6_route_cleanup();
2220         ipv6_packet_cleanup();
2221         igmp6_cleanup();
2222 +#ifdef CONFIG_IPV6_TUNNEL
2223 +       ip6_tunnel_cleanup();
2224 +#endif
2225         ndisc_cleanup();
2226         icmpv6_cleanup();
2227  #ifdef CONFIG_SYSCTL
2228 diff -uprN linux-2.4.25.old/net/ipv6/exthdrs.c linux-2.4.25/net/ipv6/exthdrs.c
2229 --- linux-2.4.25.old/net/ipv6/exthdrs.c 2003-08-25 12:44:44.000000000 +0100
2230 +++ linux-2.4.25/net/ipv6/exthdrs.c     2004-06-26 11:29:30.000000000 +0100
2231 @@ -41,6 +41,9 @@
2232  #include <net/ip6_route.h>
2233  #include <net/addrconf.h>
2234  
2235 +#include <net/mipglue.h>
2236 +#include <net/mipv6.h>
2237 +
2238  #include <asm/uaccess.h>
2239  
2240  /*
2241 @@ -160,7 +163,8 @@ bad:
2242   *****************************/
2243  
2244  struct tlvtype_proc tlvprocdestopt_lst[] = {
2245 -       /* No destination options are defined now */
2246 +       /* Mobility Support destination options */
2247 +       {MIPV6_TLV_HOMEADDR,    mipv6_handle_dstopt},
2248         {-1,                    NULL}
2249  };
2250  
2251 @@ -210,6 +214,7 @@ static int ipv6_routing_header(struct sk
2252  
2253         struct ipv6_rt_hdr *hdr;
2254         struct rt0_hdr *rthdr;
2255 +       struct rt2_hdr *rt2hdr;
2256  
2257         if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
2258             !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
2259 @@ -225,17 +230,25 @@ static int ipv6_routing_header(struct sk
2260                 kfree_skb(skb);
2261                 return -1;
2262         }
2263 -
2264 +       /* Silently discard invalid packets containing RTH type 2 */ 
2265 +       if (hdr->type == IPV6_SRCRT_TYPE_2 && 
2266 +           (hdr->hdrlen != 2 || hdr->segments_left != 1)) {
2267 +               kfree_skb(skb);
2268 +               return -1;
2269 +       }
2270  looped_back:
2271         if (hdr->segments_left == 0) {
2272 -               opt->srcrt = skb->h.raw - skb->nh.raw;
2273 +               if (hdr->type == IPV6_SRCRT_TYPE_0)
2274 +                       opt->srcrt = skb->h.raw - skb->nh.raw;
2275 +               else if (hdr->type == IPV6_SRCRT_TYPE_2)
2276 +                       opt->srcrt2 = skb->h.raw - skb->nh.raw;
2277                 skb->h.raw += (hdr->hdrlen + 1) << 3;
2278                 opt->dst0 = opt->dst1;
2279                 opt->dst1 = 0;
2280                 return (&hdr->nexthdr) - skb->nh.raw;
2281         }
2282  
2283 -       if (hdr->type != IPV6_SRCRT_TYPE_0) {
2284 +       if (hdr->type != IPV6_SRCRT_TYPE_0 && hdr->type != IPV6_SRCRT_TYPE_2) {
2285                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
2286                 return -1;
2287         }
2288 @@ -275,9 +288,20 @@ looped_back:
2289  
2290         i = n - --hdr->segments_left;
2291  
2292 -       rthdr = (struct rt0_hdr *) hdr;
2293 -       addr = rthdr->addr;
2294 -       addr += i - 1;
2295 +       if (hdr->type == IPV6_SRCRT_TYPE_0) {
2296 +               rthdr = (struct rt0_hdr *) hdr;
2297 +               addr = rthdr->addr;
2298 +               addr += i - 1;
2299 +       } else {
2300 +               /* check that address is this node's home address */
2301 +               rt2hdr = (struct rt2_hdr *) hdr;
2302 +               addr = &rt2hdr->addr;
2303 +               if (!ipv6_chk_addr(addr, NULL) || 
2304 +                   !ipv6_chk_mip_home_addr(addr)) {
2305 +                       kfree_skb(skb);
2306 +                       return -1;
2307 +               }
2308 +       }
2309  
2310         addr_type = ipv6_addr_type(addr);
2311  
2312 @@ -330,6 +354,10 @@ looped_back:
2313     temporary (or permanent) backdoor.
2314     If listening socket set IPV6_RTHDR to 2, then we invert header.
2315                                                     --ANK (980729)
2316 +
2317 +   By the Mobile IPv6 specification Type 2 routing header MUST NOT be
2318 +   inverted.
2319 +                                                   --AJT (20020917)
2320   */
2321  
2322  struct ipv6_txoptions *
2323 @@ -352,6 +380,18 @@ ipv6_invert_rthdr(struct sock *sk, struc
2324         struct ipv6_txoptions *opt;
2325         int hdrlen = ipv6_optlen(hdr);
2326  
2327 +       if (hdr->type == IPV6_SRCRT_TYPE_2) {
2328 +               opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
2329 +               if (opt == NULL)
2330 +                       return NULL;
2331 +               memset(opt, 0, sizeof(*opt));
2332 +               opt->tot_len = sizeof(*opt) + hdrlen;
2333 +               opt->srcrt = (void*)(opt+1);
2334 +               opt->opt_nflen = hdrlen;
2335 +               memcpy(opt->srcrt, hdr, sizeof(struct rt2_hdr));
2336 +               return opt;
2337 +       }
2338 +
2339         if (hdr->segments_left ||
2340             hdr->type != IPV6_SRCRT_TYPE_0 ||
2341             hdr->hdrlen & 0x01)
2342 @@ -622,8 +662,18 @@ u8 *ipv6_build_nfrag_opts(struct sk_buff
2343         if (opt) {
2344                 if (opt->dst0opt)
2345                         prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
2346 -               if (opt->srcrt)
2347 -                       prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2348 +               if (opt->srcrt) {
2349 +                       if (opt->srcrt2) {
2350 +                               struct in6_addr *rt2_hop = &((struct rt2_hdr *)opt->srcrt2)->addr;
2351 +                               prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, rt2_hop);
2352 +                       } else
2353 +                               prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2354 +               }
2355 +               if (opt->srcrt2) {
2356 +                       struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2357 +                       ipv6_addr_copy(&parm->hoa, daddr);
2358 +                       prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt2, daddr);
2359 +               }
2360         }
2361         return prev_hdr;
2362  }
2363 @@ -684,6 +734,11 @@ void ipv6_push_nfrag_opts(struct sk_buff
2364                           u8 *proto,
2365                           struct in6_addr **daddr)
2366  {
2367 +       if (opt->srcrt2) {
2368 +               struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2369 +               ipv6_addr_copy(&parm->hoa, *daddr);
2370 +               ipv6_push_rthdr(skb, proto, opt->srcrt2, daddr);
2371 +       }
2372         if (opt->srcrt)
2373                 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
2374         if (opt->dst0opt)
2375 @@ -719,6 +774,8 @@ ipv6_dup_options(struct sock *sk, struct
2376                         *((char**)&opt2->auth) += dif;
2377                 if (opt2->srcrt)
2378                         *((char**)&opt2->srcrt) += dif;
2379 +               if (opt2->srcrt2)
2380 +                       *((char**)&opt2->srcrt2) += dif;
2381         }
2382         return opt2;
2383  }
2384 diff -uprN linux-2.4.25.old/net/ipv6/icmp.c linux-2.4.25/net/ipv6/icmp.c
2385 --- linux-2.4.25.old/net/ipv6/icmp.c    2003-11-28 18:26:21.000000000 +0000
2386 +++ linux-2.4.25/net/ipv6/icmp.c        2004-06-26 11:29:30.000000000 +0100
2387 @@ -61,6 +61,8 @@
2388  #include <net/addrconf.h>
2389  #include <net/icmp.h>
2390  
2391 +#include <net/mipglue.h>
2392 +
2393  #include <asm/uaccess.h>
2394  #include <asm/system.h>
2395  
2396 @@ -364,6 +366,8 @@ void icmpv6_send(struct sk_buff *skb, in
2397  
2398         msg.len = len;
2399  
2400 +       icmpv6_swap_mipv6_addrs(skb);
2401 +
2402         ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
2403                        MSG_DONTWAIT);
2404         if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
2405 @@ -562,13 +566,13 @@ int icmpv6_rcv(struct sk_buff *skb)
2406                 rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
2407                                    ntohl(hdr->icmp6_mtu));
2408  
2409 -               /*
2410 -                *      Drop through to notify
2411 -                */
2412 +               icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2413 +               break;
2414  
2415         case ICMPV6_DEST_UNREACH:
2416 -       case ICMPV6_TIME_EXCEED:
2417         case ICMPV6_PARAMPROB:
2418 +               mipv6_icmp_rcv(skb);
2419 +       case ICMPV6_TIME_EXCEED:
2420                 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2421                 break;
2422  
2423 @@ -597,6 +601,13 @@ int icmpv6_rcv(struct sk_buff *skb)
2424         case ICMPV6_MGM_REDUCTION:
2425                 break;
2426  
2427 +       case MIPV6_DHAAD_REQUEST:
2428 +       case MIPV6_DHAAD_REPLY:
2429 +       case MIPV6_PREFIX_SOLICIT:
2430 +       case MIPV6_PREFIX_ADV:
2431 +               mipv6_icmp_rcv(skb);
2432 +               break;
2433 +
2434         default:
2435                 if (net_ratelimit())
2436                         printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
2437 diff -uprN linux-2.4.25.old/net/ipv6/ip6_fib.c linux-2.4.25/net/ipv6/ip6_fib.c
2438 --- linux-2.4.25.old/net/ipv6/ip6_fib.c 2003-08-25 12:44:44.000000000 +0100
2439 +++ linux-2.4.25/net/ipv6/ip6_fib.c     2004-06-26 11:29:30.000000000 +0100
2440 @@ -18,6 +18,7 @@
2441   *     Yuji SEKIYA @USAGI:     Support default route on router node;
2442   *                             remove ip6_null_entry from the top of
2443   *                             routing table.
2444 + *     Ville Nuorvala:         Fixes to source address based routing
2445   */
2446  #include <linux/config.h>
2447  #include <linux/errno.h>
2448 @@ -40,7 +41,6 @@
2449  #include <net/ip6_route.h>
2450  
2451  #define RT6_DEBUG 2
2452 -#undef CONFIG_IPV6_SUBTREES
2453  
2454  #if RT6_DEBUG >= 3
2455  #define RT6_TRACE(x...) printk(KERN_DEBUG x)
2456 @@ -500,6 +500,8 @@ static __inline__ void fib6_start_gc(str
2457                 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
2458  }
2459  
2460 +static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
2461 +
2462  /*
2463   *     Add routing information to the routing tree.
2464   *     <destination addr>/<source addr>
2465 @@ -508,17 +510,19 @@ static __inline__ void fib6_start_gc(str
2466  
2467  int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
2468  {
2469 -       struct fib6_node *fn;
2470 +       struct fib6_node *fn = root;
2471         int err = -ENOMEM;
2472  
2473 -       fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2474 -                       rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2475 +#ifdef CONFIG_IPV6_SUBTREES
2476 +       struct fib6_node *pn = NULL;
2477  
2478 +       fn = fib6_add_1(root, &rt->rt6i_src.addr, sizeof(struct in6_addr),
2479 +                       rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt);
2480 +       
2481         if (fn == NULL)
2482                 goto out;
2483  
2484 -#ifdef CONFIG_IPV6_SUBTREES
2485 -       if (rt->rt6i_src.plen) {
2486 +       if (rt->rt6i_dst.plen) {
2487                 struct fib6_node *sn;
2488  
2489                 if (fn->subtree == NULL) {
2490 @@ -546,9 +550,9 @@ int fib6_add(struct fib6_node *root, str
2491  
2492                         /* Now add the first leaf node to new subtree */
2493  
2494 -                       sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
2495 -                                       sizeof(struct in6_addr), rt->rt6i_src.plen,
2496 -                                       (u8*) &rt->rt6i_src - (u8*) rt);
2497 +                       sn = fib6_add_1(sfn, &rt->rt6i_dst.addr,
2498 +                                       sizeof(struct in6_addr), rt->rt6i_dst.plen,
2499 +                                       (u8*) &rt->rt6i_dst - (u8*) rt);
2500  
2501                         if (sn == NULL) {
2502                                 /* If it is failed, discard just allocated
2503 @@ -562,21 +566,30 @@ int fib6_add(struct fib6_node *root, str
2504                         /* Now link new subtree to main tree */
2505                         sfn->parent = fn;
2506                         fn->subtree = sfn;
2507 -                       if (fn->leaf == NULL) {
2508 -                               fn->leaf = rt;
2509 -                               atomic_inc(&rt->rt6i_ref);
2510 -                       }
2511                 } else {
2512 -                       sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
2513 -                                       sizeof(struct in6_addr), rt->rt6i_src.plen,
2514 -                                       (u8*) &rt->rt6i_src - (u8*) rt);
2515 +                       sn = fib6_add_1(fn->subtree, &rt->rt6i_dst.addr,
2516 +                                       sizeof(struct in6_addr), rt->rt6i_dst.plen,
2517 +                                       (u8*) &rt->rt6i_dst - (u8*) rt);
2518  
2519                         if (sn == NULL)
2520                                 goto st_failure;
2521                 }
2522  
2523 +               /* fib6_add_1 might have cleared the old leaf pointer */
2524 +               if (fn->leaf == NULL) {
2525 +                       fn->leaf = rt;
2526 +                       atomic_inc(&rt->rt6i_ref);
2527 +               }
2528 +
2529 +               pn = fn;
2530                 fn = sn;
2531         }
2532 +#else 
2533 +       fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2534 +                       rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2535 +
2536 +       if (fn == NULL)
2537 +               goto out;
2538  #endif
2539  
2540         err = fib6_add_rt2node(fn, rt, nlh);
2541 @@ -588,8 +601,30 @@ int fib6_add(struct fib6_node *root, str
2542         }
2543  
2544  out:
2545 -       if (err)
2546 +       if (err) {
2547 +#ifdef CONFIG_IPV6_SUBTREES
2548 +
2549 +               /* If fib6_add_1 has cleared the old leaf pointer in the 
2550 +                  super-tree leaf node, we have to find a new one for it. 
2551 +                  
2552 +                  This situation will never arise in the sub-tree since 
2553 +                  the node will at least have the route that caused 
2554 +                  fib6_add_rt2node to fail.
2555 +               */
2556 +
2557 +               if (pn && !(pn->fn_flags & RTN_RTINFO)) {
2558 +                       pn->leaf = fib6_find_prefix(pn);
2559 +#if RT6_DEBUG >= 2
2560 +                       if (!pn->leaf) {
2561 +                               BUG_TRAP(pn->leaf);
2562 +                               pn->leaf = &ip6_null_entry;
2563 +                       }
2564 +#endif
2565 +                       atomic_inc(&pn->leaf->rt6i_ref);
2566 +               }
2567 +#endif
2568                 dst_free(&rt->u.dst);
2569 +       }
2570         return err;
2571  
2572  #ifdef CONFIG_IPV6_SUBTREES
2573 @@ -597,8 +632,8 @@ out:
2574            is orphan. If it is, shoot it.
2575          */
2576  st_failure:
2577 -       if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
2578 -               fib_repair_tree(fn);
2579 +       if (fn && !(fn->fn_flags & (RTN_RTINFO | RTN_ROOT)))
2580 +               fib6_repair_tree(fn);
2581         dst_free(&rt->u.dst);
2582         return err;
2583  #endif
2584 @@ -641,22 +676,28 @@ static struct fib6_node * fib6_lookup_1(
2585                 break;
2586         }
2587  
2588 -       while ((fn->fn_flags & RTN_ROOT) == 0) {
2589 +       for (;;) {
2590  #ifdef CONFIG_IPV6_SUBTREES
2591                 if (fn->subtree) {
2592 -                       struct fib6_node *st;
2593 -                       struct lookup_args *narg;
2594 -
2595 -                       narg = args + 1;
2596 -
2597 -                       if (narg->addr) {
2598 -                               st = fib6_lookup_1(fn->subtree, narg);
2599 +                       struct rt6key *key;
2600  
2601 -                               if (st && !(st->fn_flags & RTN_ROOT))
2602 -                                       return st;
2603 +                       key = (struct rt6key *) ((u8 *) fn->leaf +
2604 +                                                args->offset);
2605 +                       
2606 +                       if (addr_match(&key->addr, args->addr, key->plen)) {
2607 +                               struct fib6_node *st;
2608 +                               struct lookup_args *narg = args + 1;
2609 +                               if (!ipv6_addr_any(narg->addr)) {
2610 +                                       st = fib6_lookup_1(fn->subtree, narg);
2611 +                                       
2612 +                                       if (st && !(st->fn_flags & RTN_ROOT))
2613 +                                               return st;
2614 +                               } 
2615                         }
2616                 }
2617  #endif
2618 +               if (fn->fn_flags & RTN_ROOT)
2619 +                       break;
2620  
2621                 if (fn->fn_flags & RTN_RTINFO) {
2622                         struct rt6key *key;
2623 @@ -680,13 +721,22 @@ struct fib6_node * fib6_lookup(struct fi
2624         struct lookup_args args[2];
2625         struct rt6_info *rt = NULL;
2626         struct fib6_node *fn;
2627 +#ifdef CONFIG_IPV6_SUBTREES
2628 +       struct in6_addr saddr_buf;
2629 +#endif
2630  
2631 +#ifdef CONFIG_IPV6_SUBTREES
2632 +       if (saddr == NULL) {
2633 +               memset(&saddr_buf, 0, sizeof(struct in6_addr));
2634 +               saddr = &saddr_buf;
2635 +       }
2636 +       args[0].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2637 +       args[0].addr = saddr;
2638 +       args[1].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2639 +       args[1].addr = daddr;
2640 +#else 
2641         args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2642         args[0].addr = daddr;
2643 -
2644 -#ifdef CONFIG_IPV6_SUBTREES
2645 -       args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2646 -       args[1].addr = saddr;
2647  #endif
2648  
2649         fn = fib6_lookup_1(root, args);
2650 @@ -739,19 +789,25 @@ struct fib6_node * fib6_locate(struct fi
2651  {
2652         struct rt6_info *rt = NULL;
2653         struct fib6_node *fn;
2654 -
2655 -       fn = fib6_locate_1(root, daddr, dst_len,
2656 -                          (u8*) &rt->rt6i_dst - (u8*) rt);
2657 -
2658  #ifdef CONFIG_IPV6_SUBTREES
2659 -       if (src_len) {
2660 -               BUG_TRAP(saddr!=NULL);
2661 -               if (fn == NULL)
2662 -                       fn = fn->subtree;
2663 +       struct in6_addr saddr_buf;
2664 +
2665 +       if (saddr == NULL) {
2666 +               memset(&saddr_buf, 0, sizeof(struct in6_addr));
2667 +               saddr = &saddr_buf;
2668 +       }
2669 +       fn = fib6_locate_1(root, saddr, src_len, 
2670 +                          (u8*) &rt->rt6i_src - (u8*) rt);
2671 +       if (dst_len) {
2672                 if (fn)
2673 -                       fn = fib6_locate_1(fn, saddr, src_len,
2674 -                                          (u8*) &rt->rt6i_src - (u8*) rt);
2675 +                       fn = fib6_locate_1(fn->subtree, daddr, dst_len,
2676 +                                          (u8*) &rt->rt6i_dst - (u8*) rt);
2677 +               else 
2678 +                       return NULL;
2679         }
2680 +#else
2681 +       fn = fib6_locate_1(root, daddr, dst_len,
2682 +                          (u8*) &rt->rt6i_dst - (u8*) rt);
2683  #endif
2684  
2685         if (fn && fn->fn_flags&RTN_RTINFO)
2686 @@ -939,7 +995,7 @@ static void fib6_del_route(struct fib6_n
2687                         }
2688                         fn = fn->parent;
2689                 }
2690 -               /* No more references are possiible at this point. */
2691 +               /* No more references are possible at this point. */
2692                 if (atomic_read(&rt->rt6i_ref) != 1) BUG();
2693         }
2694  
2695 diff -uprN linux-2.4.25.old/net/ipv6/ip6_input.c linux-2.4.25/net/ipv6/ip6_input.c
2696 --- linux-2.4.25.old/net/ipv6/ip6_input.c       2003-08-25 12:44:44.000000000 +0100
2697 +++ linux-2.4.25/net/ipv6/ip6_input.c   2004-06-26 11:29:30.000000000 +0100
2698 @@ -40,13 +40,42 @@
2699  #include <net/ip6_route.h>
2700  #include <net/addrconf.h>
2701  
2702 +static inline int ip6_proxy_chk(struct sk_buff *skb)
2703 +{
2704 +       struct ipv6hdr *hdr = skb->nh.ipv6h;
2705  
2706 -
2707 +       if (ipv6_addr_type(&hdr->daddr)&IPV6_ADDR_UNICAST &&
2708 +           pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2709 +               u8 nexthdr = hdr->nexthdr;
2710 +               int offset;
2711 +               struct icmp6hdr msg;
2712 +
2713 +               if (ipv6_ext_hdr(nexthdr)) {
2714 +                       offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, 
2715 +                                                 skb->len - sizeof(*hdr));
2716 +                       if (offset < 0)
2717 +                               return 0;
2718 +               } else
2719 +                       offset = sizeof(*hdr);
2720 +
2721 +               /* capture unicast NUD probes on behalf of the proxied node */
2722 +
2723 +               if (nexthdr == IPPROTO_ICMPV6 &&
2724 +                   !skb_copy_bits(skb, offset, &msg, sizeof(msg)) &&
2725 +                   msg.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
2726 +                       return 1;
2727 +               }
2728 +       }
2729 +       return 0;
2730 +}
2731
2732  static inline int ip6_rcv_finish( struct sk_buff *skb) 
2733  {
2734 -       if (skb->dst == NULL)
2735 -               ip6_route_input(skb);
2736 -
2737 +       if (skb->dst == NULL) {
2738 +               if (ip6_proxy_chk(skb)) 
2739 +                       return ip6_input(skb);
2740 +               ip6_route_input(skb);
2741 +       }
2742         return skb->dst->input(skb);
2743  }
2744  
2745 diff -uprN linux-2.4.25.old/net/ipv6/ip6_output.c linux-2.4.25/net/ipv6/ip6_output.c
2746 --- linux-2.4.25.old/net/ipv6/ip6_output.c      2003-08-25 12:44:44.000000000 +0100
2747 +++ linux-2.4.25/net/ipv6/ip6_output.c  2004-06-26 11:29:30.000000000 +0100
2748 @@ -50,6 +50,8 @@
2749  #include <net/rawv6.h>
2750  #include <net/icmp.h>
2751  
2752 +#include <net/mipglue.h>
2753 +
2754  static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
2755  {
2756         static u32 ipv6_fragmentation_id = 1;
2757 @@ -194,7 +196,14 @@ int ip6_xmit(struct sock *sk, struct sk_
2758         u8  proto = fl->proto;
2759         int seg_len = skb->len;
2760         int hlimit;
2761 +       int retval;
2762 +       struct ipv6_txoptions *orig_opt = opt;
2763 +
2764 +       opt = ip6_add_mipv6_txoptions(sk, skb, orig_opt, fl, &dst);
2765  
2766 +       if(orig_opt && !opt)
2767 +               return -ENOMEM;
2768 +               
2769         if (opt) {
2770                 int head_room;
2771  
2772 @@ -209,8 +218,11 @@ int ip6_xmit(struct sock *sk, struct sk_
2773                         struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
2774                         kfree_skb(skb);
2775                         skb = skb2;
2776 -                       if (skb == NULL)
2777 +                       if (skb == NULL) {
2778 +                               ip6_free_mipv6_txoptions(opt, orig_opt);
2779 +
2780                                 return -ENOBUFS;
2781 +                       }
2782                         if (sk)
2783                                 skb_set_owner_w(skb, sk);
2784                 }
2785 @@ -242,7 +254,10 @@ int ip6_xmit(struct sock *sk, struct sk_
2786  
2787         if (skb->len <= dst->pmtu) {
2788                 IP6_INC_STATS(Ip6OutRequests);
2789 -               return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2790 +               ip6_mark_mipv6_packet(opt, skb);
2791 +               retval = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2792 +               ip6_free_mipv6_txoptions(opt, orig_opt);
2793 +               return retval; 
2794         }
2795  
2796         if (net_ratelimit())
2797 @@ -250,6 +265,9 @@ int ip6_xmit(struct sock *sk, struct sk_
2798         skb->dev = dst->dev;
2799         icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
2800         kfree_skb(skb);
2801 +
2802 +       ip6_free_mipv6_txoptions(opt, orig_opt);
2803 +
2804         return -EMSGSIZE;
2805  }
2806  
2807 @@ -473,6 +491,7 @@ static int ip6_frag_xmit(struct sock *sk
2808  
2809                         IP6_INC_STATS(Ip6FragCreates);
2810                         IP6_INC_STATS(Ip6OutRequests);
2811 +                       ip6_mark_mipv6_packet(opt, skb);
2812                         err = NF_HOOK(PF_INET6,NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2813                         if (err) {
2814                                 kfree_skb(last_skb);
2815 @@ -499,6 +518,7 @@ static int ip6_frag_xmit(struct sock *sk
2816         IP6_INC_STATS(Ip6FragCreates);
2817         IP6_INC_STATS(Ip6FragOKs);
2818         IP6_INC_STATS(Ip6OutRequests);
2819 +       ip6_mark_mipv6_packet(opt, last_skb);
2820         return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute);
2821  }
2822  
2823 @@ -509,26 +529,43 @@ int ip6_build_xmit(struct sock *sk, inet
2824         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
2825         struct in6_addr *final_dst = NULL;
2826         struct dst_entry *dst;
2827 +       struct rt6_info *rt;
2828         int err = 0;
2829         unsigned int pktlength, jumbolen, mtu;
2830         struct in6_addr saddr;
2831 +       struct ipv6_txoptions *orig_opt = opt; 
2832 +#ifdef CONFIG_IPV6_SUBTREES
2833 +       struct dst_entry *org_dst;
2834 +#endif
2835 +
2836 +       opt = ip6_add_mipv6_txoptions(sk, NULL, orig_opt, fl, NULL);
2837 +
2838 +       if(orig_opt && !opt)
2839 +               return -ENOMEM;
2840  
2841         if (opt && opt->srcrt) {
2842                 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
2843                 final_dst = fl->fl6_dst;
2844                 fl->fl6_dst = rt0->addr;
2845 -       }
2846 +       } else if (opt && opt->srcrt2) {
2847 +                struct rt2_hdr *rt2 = (struct rt2_hdr *) opt->srcrt2;
2848 +                final_dst = fl->fl6_dst;
2849 +                fl->fl6_dst = &rt2->addr;
2850 +        }
2851  
2852         if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
2853                 fl->oif = np->mcast_oif;
2854  
2855         dst = __sk_dst_check(sk, np->dst_cookie);
2856 +#ifdef CONFIG_IPV6_SUBTREES
2857 +       org_dst = dst;
2858 +#endif
2859         if (dst) {
2860 -               struct rt6_info *rt = (struct rt6_info*)dst;
2861 +               rt = (struct rt6_info*)dst;
2862  
2863                         /* Yes, checking route validity in not connected
2864                            case is not very simple. Take into account,
2865 -                          that we do not support routing by source, TOS,
2866 +                          that we do not support routing by TOS,
2867                            and MSG_DONTROUTE            --ANK (980726)
2868  
2869                            1. If route was host route, check that
2870 @@ -548,6 +585,13 @@ int ip6_build_xmit(struct sock *sk, inet
2871                       ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
2872                      && (np->daddr_cache == NULL ||
2873                          ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
2874 +#ifdef CONFIG_IPV6_SUBTREES
2875 +                   || (fl->fl6_src != NULL
2876 +                       && (rt->rt6i_src.plen != 128 ||
2877 +                           ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr))
2878 +                       && (np->saddr_cache == NULL ||
2879 +                           ipv6_addr_cmp(fl->fl6_src, np->saddr_cache)))
2880 +#endif
2881                     || (fl->oif && fl->oif != dst->dev->ifindex)) {
2882                         dst = NULL;
2883                 } else
2884 @@ -560,21 +604,42 @@ int ip6_build_xmit(struct sock *sk, inet
2885         if (dst->error) {
2886                 IP6_INC_STATS(Ip6OutNoRoutes);
2887                 dst_release(dst);
2888 +               ip6_free_mipv6_txoptions(opt, orig_opt);
2889                 return -ENETUNREACH;
2890         }
2891  
2892         if (fl->fl6_src == NULL) {
2893                 err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
2894 -
2895                 if (err) {
2896  #if IP6_DEBUG >= 2
2897                         printk(KERN_DEBUG "ip6_build_xmit: "
2898                                "no available source address\n");
2899  #endif
2900 +
2901 +#ifdef CONFIG_IPV6_SUBTREES
2902 +                       if (dst != org_dst) {
2903 +                               dst_release(dst);
2904 +                               dst = org_dst;
2905 +                       }
2906 +#endif         
2907                         goto out;
2908                 }
2909                 fl->fl6_src = &saddr;
2910         }
2911 +#ifdef CONFIG_IPV6_SUBTREES
2912 +       rt = (struct rt6_info*)dst;
2913 +       if (dst != org_dst || rt->rt6i_src.plen != 128 ||
2914 +           ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr)) {
2915 +               dst_release(dst);
2916 +               dst = ip6_route_output(sk, fl);
2917 +               if (dst->error) {
2918 +                       IP6_INC_STATS(Ip6OutNoRoutes);
2919 +                       dst_release(dst);
2920 +                       ip6_free_mipv6_txoptions(opt, orig_opt);
2921 +                       return -ENETUNREACH;
2922 +               }
2923 +       }
2924 +#endif
2925         pktlength = length;
2926  
2927         if (hlimit < 0) {
2928 @@ -667,6 +732,7 @@ int ip6_build_xmit(struct sock *sk, inet
2929  
2930                 if (!err) {
2931                         IP6_INC_STATS(Ip6OutRequests);
2932 +                       ip6_mark_mipv6_packet(opt, skb);
2933                         err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2934                 } else {
2935                         err = -EFAULT;
2936 @@ -688,9 +754,14 @@ int ip6_build_xmit(struct sock *sk, inet
2937          *      cleanup
2938          */
2939  out:
2940 -       ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
2941 +       ip6_dst_store(sk, dst, 
2942 +                     fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL,
2943 +                     fl->nl_u.ip6_u.saddr == &np->saddr ? &np->saddr : NULL);
2944         if (err > 0)
2945                 err = np->recverr ? net_xmit_errno(err) : 0;
2946 +
2947 +       ip6_free_mipv6_txoptions(opt, orig_opt);
2948 +
2949         return err;
2950  }
2951  
2952 @@ -769,6 +840,15 @@ int ip6_forward(struct sk_buff *skb)
2953                 return -ETIMEDOUT;
2954         }
2955  
2956 +       /* The proxying router can't forward traffic sent to a link-local
2957 +          address, so signal the sender and discard the packet. This
2958 +          behavior is required by the MIPv6 specification. */
2959 +
2960 +       if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL && 
2961 +           skb->dev && pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2962 +               dst_link_failure(skb);
2963 +               goto drop;
2964 +       }
2965         /* IPv6 specs say nothing about it, but it is clear that we cannot
2966            send redirects to source routed frames.
2967          */
2968 diff -uprN linux-2.4.25.old/net/ipv6/ipv6_syms.c linux-2.4.25/net/ipv6/ipv6_syms.c
2969 --- linux-2.4.25.old/net/ipv6/ipv6_syms.c       2003-11-28 18:26:21.000000000 +0000
2970 +++ linux-2.4.25/net/ipv6/ipv6_syms.c   2004-06-26 11:29:30.000000000 +0100
2971 @@ -6,6 +6,8 @@
2972  #include <net/ipv6.h>
2973  #include <net/addrconf.h>
2974  #include <net/ip6_route.h>
2975 +#include <net/ndisc.h>
2976 +#include <net/mipglue.h>
2977  
2978  EXPORT_SYMBOL(ipv6_addr_type);
2979  EXPORT_SYMBOL(icmpv6_send);
2980 @@ -33,3 +35,48 @@ EXPORT_SYMBOL(inet6_ioctl);
2981  EXPORT_SYMBOL(ipv6_get_saddr);
2982  EXPORT_SYMBOL(ipv6_chk_addr);
2983  EXPORT_SYMBOL(in6_dev_finish_destroy);
2984 +
2985 +#if defined(CONFIG_IPV6_TUNNEL_MODULE) || defined(CONFIG_IPV6_MOBILITY_MODULE)
2986 +EXPORT_SYMBOL(ip6_build_xmit);
2987 +EXPORT_SYMBOL(rt6_lookup);
2988 +EXPORT_SYMBOL(ipv6_ext_hdr);
2989 +#endif
2990 +#ifdef CONFIG_IPV6_MOBILITY_MODULE
2991 +EXPORT_SYMBOL(mipv6_functions);
2992 +EXPORT_SYMBOL(mipv6_invalidate_calls);
2993 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
2994 +EXPORT_SYMBOL(ip6_route_add);
2995 +EXPORT_SYMBOL(ip6_route_del);
2996 +EXPORT_SYMBOL(ipv6_get_lladdr);
2997 +EXPORT_SYMBOL(ipv6_get_ifaddr);
2998 +EXPORT_SYMBOL(nd_tbl);
2999 +EXPORT_SYMBOL(ndisc_send_ns);
3000 +EXPORT_SYMBOL(ndisc_send_na);
3001 +EXPORT_SYMBOL(ndisc_next_option);
3002 +EXPORT_SYMBOL(inet6_ifa_finish_destroy);
3003 +#endif
3004 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
3005 +EXPORT_SYMBOL(ipv6_dev_ac_dec);
3006 +EXPORT_SYMBOL(ipv6_dev_ac_inc);
3007 +EXPORT_SYMBOL(ipv6_dev_mc_dec);
3008 +EXPORT_SYMBOL(ipv6_dev_mc_inc);
3009 +EXPORT_SYMBOL(ip6_forward);
3010 +EXPORT_SYMBOL(ip6_input);
3011 +EXPORT_SYMBOL(ipv6_chk_acast_addr);
3012 +#endif
3013 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
3014 +#endif
3015 +EXPORT_SYMBOL(addrconf_add_ifaddr);
3016 +EXPORT_SYMBOL(addrconf_del_ifaddr);
3017 +EXPORT_SYMBOL(addrconf_dad_start);
3018 +EXPORT_SYMBOL(ip6_del_rt);
3019 +EXPORT_SYMBOL(ip6_routing_table);
3020 +EXPORT_SYMBOL(rt6_get_dflt_router);
3021 +EXPORT_SYMBOL(rt6_purge_dflt_routers);
3022 +EXPORT_SYMBOL(rt6_lock);
3023 +EXPORT_SYMBOL(ndisc_send_rs);
3024 +EXPORT_SYMBOL(fib6_clean_tree);
3025 +EXPORT_SYMBOL(ipv6_del_addr);
3026 +EXPORT_SYMBOL(ipv6_generate_eui64);
3027 +EXPORT_SYMBOL(ipv6_inherit_eui64);
3028 +#endif
3029 diff -uprN linux-2.4.25.old/net/ipv6/ipv6_tunnel.c linux-2.4.25/net/ipv6/ipv6_tunnel.c
3030 --- linux-2.4.25.old/net/ipv6/ipv6_tunnel.c     1970-01-01 01:00:00.000000000 +0100
3031 +++ linux-2.4.25/net/ipv6/ipv6_tunnel.c 2004-06-26 11:29:30.000000000 +0100
3032 @@ -0,0 +1,1604 @@
3033 +/*
3034 + *     IPv6 over IPv6 tunnel device
3035 + *     Linux INET6 implementation
3036 + *
3037 + *     Authors:
3038 + *     Ville Nuorvala          <vnuorval@tcs.hut.fi>   
3039 + *
3040 + *     $Id$
3041 + *
3042 + *      Based on:
3043 + *      linux/net/ipv6/sit.c
3044 + *
3045 + *      RFC 2473
3046 + *
3047 + *     This program is free software; you can redistribute it and/or
3048 + *      modify it under the terms of the GNU General Public License
3049 + *      as published by the Free Software Foundation; either version
3050 + *      2 of the License, or (at your option) any later version.
3051 + *
3052 + */
3053 +
3054 +#include <linux/config.h>
3055 +#include <linux/module.h>
3056 +#include <linux/errno.h>
3057 +#include <linux/types.h>
3058 +#include <linux/socket.h>
3059 +#include <linux/sockios.h>
3060 +#include <linux/if.h>
3061 +#include <linux/in.h>
3062 +#include <linux/ip.h>
3063 +#include <linux/if_tunnel.h>
3064 +#include <linux/net.h>
3065 +#include <linux/in6.h>
3066 +#include <linux/netdevice.h>
3067 +#include <linux/if_arp.h>
3068 +#include <linux/icmpv6.h>
3069 +#include <linux/init.h>
3070 +#include <linux/route.h>
3071 +#include <linux/rtnetlink.h>
3072 +#include <linux/tqueue.h>
3073 +
3074 +#include <asm/uaccess.h>
3075 +#include <asm/atomic.h>
3076 +
3077 +#include <net/sock.h>
3078 +#include <net/ipv6.h>
3079 +#include <net/protocol.h>
3080 +#include <net/ip6_route.h>
3081 +#include <net/addrconf.h>
3082 +#include <net/ipv6_tunnel.h>
3083 +
3084 +MODULE_AUTHOR("Ville Nuorvala");
3085 +MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
3086 +MODULE_LICENSE("GPL");
3087 +
3088 +#define IPV6_TLV_TEL_DST_SIZE 8
3089 +
3090 +#ifdef IP6_TNL_DEBUG
3091 +#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
3092 +#else
3093 +#define IP6_TNL_TRACE(x...) do {;} while(0)
3094 +#endif
3095 +
3096 +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
3097 +
3098 +#define HASH_SIZE  32
3099 +
3100 +#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
3101 +                    (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
3102 +                    (HASH_SIZE - 1))
3103 +
3104 +static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
3105 +static int ip6ip6_tnl_dev_init(struct net_device *dev);
3106 +
3107 +/* the IPv6 IPv6 tunnel fallback device */
3108 +static struct net_device ip6ip6_fb_tnl_dev = {
3109 +       name: "ip6tnl0",
3110 +       init: ip6ip6_fb_tnl_dev_init
3111 +};
3112 +
3113 +/* the IPv6 IPv6 fallback tunnel */
3114 +static struct ip6_tnl ip6ip6_fb_tnl = {
3115 +       dev: &ip6ip6_fb_tnl_dev,
3116 +       parms:{name: "ip6tnl0", proto: IPPROTO_IPV6}
3117 +};
3118 +
3119 +/* lists for storing tunnels in use */
3120 +static struct ip6_tnl *tnls_r_l[HASH_SIZE];
3121 +static struct ip6_tnl *tnls_wc[1];
3122 +static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
3123 +
3124 +/* list for unused cached kernel tunnels */
3125 +static struct ip6_tnl *tnls_kernel[1];
3126 +/* maximum number of cached kernel tunnels */
3127 +static unsigned int max_kdev_count = 0;
3128 +/* minimum number of cached kernel tunnels */
3129 +static unsigned int min_kdev_count = 0;
3130 +/* current number of cached kernel tunnels */
3131 +static unsigned int kdev_count = 0;
3132 +
3133 +/* lists for tunnel hook functions */
3134 +static struct list_head hooks[IP6_TNL_MAXHOOKS];
3135 +
3136 +/* locks for the different lists */
3137 +static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
3138 +static rwlock_t ip6ip6_kernel_lock = RW_LOCK_UNLOCKED;
3139 +static rwlock_t ip6ip6_hook_lock = RW_LOCK_UNLOCKED;
3140 +
3141 +/* flag indicating if the module is being removed */
3142 +static int shutdown = 0;
3143 +
3144 +/**
3145 + * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
3146 + *   @remote: the address of the tunnel exit-point 
3147 + *   @local: the address of the tunnel entry-point 
3148 + *
3149 + * Return:  
3150 + *   tunnel matching given end-points if found,
3151 + *   else fallback tunnel if its device is up, 
3152 + *   else %NULL
3153 + **/
3154 +
3155 +struct ip6_tnl *
3156 +ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
3157 +{
3158 +       unsigned h0 = HASH(remote);
3159 +       unsigned h1 = HASH(local);
3160 +       struct ip6_tnl *t;
3161 +
3162 +       for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
3163 +               if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3164 +                   !ipv6_addr_cmp(remote, &t->parms.raddr) &&
3165 +                   (t->dev->flags & IFF_UP))
3166 +                       return t;
3167 +       }
3168 +       if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
3169 +               return t;
3170 +
3171 +       return NULL;
3172 +}
3173 +
3174 +/**
3175 + * ip6ip6_bucket - get head of list matching given tunnel parameters
3176 + *   @p: parameters containing tunnel end-points 
3177 + *
3178 + * Description:
3179 + *   ip6ip6_bucket() returns the head of the list matching the 
3180 + *   &struct in6_addr entries laddr and raddr in @p.
3181 + *
3182 + * Return: head of IPv6 tunnel list 
3183 + **/
3184 +
3185 +static struct ip6_tnl **
3186 +ip6ip6_bucket(struct ip6_tnl_parm *p)
3187 +{
3188 +       struct in6_addr *remote = &p->raddr;
3189 +       struct in6_addr *local = &p->laddr;
3190 +       unsigned h = 0;
3191 +       int prio = 0;
3192 +
3193 +       if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
3194 +               prio = 1;
3195 +               h = HASH(remote) ^ HASH(local);
3196 +       }
3197 +       return &tnls[prio][h];
3198 +}
3199 +
3200 +/**
3201 + * ip6ip6_kernel_tnl_link - add new kernel tunnel to cache
3202 + *   @t: kernel tunnel
3203 + *
3204 + * Note:
3205 + *   %IP6_TNL_F_KERNEL_DEV is assumed to be raised in t->parms.flags. 
3206 + *   See the comments on ip6ip6_kernel_tnl_add() for more information.
3207 + **/
3208 +
3209 +static inline void
3210 +ip6ip6_kernel_tnl_link(struct ip6_tnl *t)
3211 +{
3212 +       write_lock_bh(&ip6ip6_kernel_lock);
3213 +       t->next = tnls_kernel[0];
3214 +       tnls_kernel[0] = t;
3215 +       kdev_count++;
3216 +       write_unlock_bh(&ip6ip6_kernel_lock);
3217 +}
3218 +
3219 +/**
3220 + * ip6ip6_kernel_tnl_unlink - remove first kernel tunnel from cache
3221 + *
3222 + * Return: first free kernel tunnel
3223 + *
3224 + * Note:
3225 + *   See the comments on ip6ip6_kernel_tnl_add() for more information.
3226 + **/
3227 +
3228 +static inline struct ip6_tnl *
3229 +ip6ip6_kernel_tnl_unlink(void)
3230 +{
3231 +       struct ip6_tnl *t;
3232 +
3233 +       write_lock_bh(&ip6ip6_kernel_lock);
3234 +       if ((t = tnls_kernel[0]) != NULL) {
3235 +               tnls_kernel[0] = t->next;
3236 +               kdev_count--;
3237 +       }
3238 +       write_unlock_bh(&ip6ip6_kernel_lock);
3239 +       return t;
3240 +}
3241 +
3242 +/**
3243 + * ip6ip6_tnl_link - add tunnel to hash table
3244 + *   @t: tunnel to be added
3245 + **/
3246 +
3247 +static void
3248 +ip6ip6_tnl_link(struct ip6_tnl *t)
3249 +{
3250 +       struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
3251 +
3252 +       write_lock_bh(&ip6ip6_lock);
3253 +       t->next = *tp;
3254 +       *tp = t;
3255 +       write_unlock_bh(&ip6ip6_lock);
3256 +}
3257 +
3258 +/**
3259 + * ip6ip6_tnl_unlink - remove tunnel from hash table
3260 + *   @t: tunnel to be removed
3261 + **/
3262 +
3263 +static void
3264 +ip6ip6_tnl_unlink(struct ip6_tnl *t)
3265 +{
3266 +       struct ip6_tnl **tp;
3267 +       
3268 +       write_lock_bh(&ip6ip6_lock);
3269 +       for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
3270 +               if (t == *tp) {
3271 +                       *tp = t->next;
3272 +                       break;
3273 +               }
3274 +       }
3275 +       write_unlock_bh(&ip6ip6_lock);
3276 +}
3277 +
3278 +/**
3279 + * ip6ip6_tnl_create() - create a new tunnel
3280 + *   @p: tunnel parameters
3281 + *   @pt: pointer to new tunnel
3282 + *
3283 + * Description:
3284 + *   Create tunnel matching given parameters. New kernel managed devices are 
3285 + *   not put in the normal hash structure, but are instead cached for later
3286 + *   use.
3287 + * 
3288 + * Return: 
3289 + *   0 on success
3290 + **/
3291 +
3292 +
3293 +static int __ip6ip6_tnl_create(struct ip6_tnl_parm *p,
3294 +                              struct ip6_tnl **pt,
3295 +                              int kernel_list)
3296 +{
3297 +       struct net_device *dev;
3298 +       int err = -ENOBUFS;
3299 +       struct ip6_tnl *t;
3300 +
3301 +       MOD_INC_USE_COUNT;
3302 +       dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
3303 +       if (!dev) {
3304 +               MOD_DEC_USE_COUNT;
3305 +               return err;
3306 +       }
3307 +       memset(dev, 0, sizeof (*dev) + sizeof (*t));
3308 +       dev->priv = (void *) (dev + 1);
3309 +       t = (struct ip6_tnl *) dev->priv;
3310 +       t->dev = dev;
3311 +       dev->init = ip6ip6_tnl_dev_init;
3312 +       dev->features |= NETIF_F_DYNALLOC;
3313 +       if (kernel_list) {
3314 +               memcpy(t->parms.name, p->name, IFNAMSIZ - 1);
3315 +               t->parms.proto = IPPROTO_IPV6;
3316 +               t->parms.flags = IP6_TNL_F_KERNEL_DEV;
3317 +       } else {
3318 +               memcpy(&t->parms, p, sizeof (*p));
3319 +       }
3320 +       t->parms.name[IFNAMSIZ - 1] = '\0';
3321 +       strcpy(dev->name, t->parms.name);
3322 +       if (!dev->name[0]) {
3323 +               int i;
3324 +               for (i = 0; i < IP6_TNL_MAX; i++) {
3325 +                       sprintf(dev->name, "ip6tnl%d", i);
3326 +                       if (__dev_get_by_name(dev->name) == NULL)
3327 +                               break;
3328 +               }
3329 +
3330 +               if (i == IP6_TNL_MAX) {
3331 +                       goto failed;
3332 +               }
3333 +               memcpy(t->parms.name, dev->name, IFNAMSIZ);
3334 +       }
3335 +       if ((err = register_netdevice(dev)) < 0) {
3336 +               goto failed;
3337 +       }
3338 +       dev_hold(dev);
3339 +       if (kernel_list) {
3340 +               ip6ip6_kernel_tnl_link(t);
3341 +       } else {
3342 +               ip6ip6_tnl_link(t);
3343 +       }
3344 +       *pt = t;
3345 +       return 0;
3346 +failed:
3347 +       kfree(dev);
3348 +       MOD_DEC_USE_COUNT;
3349 +       return err;
3350 +}
3351 +
3352 +
3353 +int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
3354 +{
3355 +       return __ip6ip6_tnl_create(p, pt, 0);
3356 +}
3357 +
3358 +
3359 +static void manage_kernel_tnls(void *foo);
3360 +
3361 +static struct tq_struct manager_task = {
3362 +       routine:manage_kernel_tnls,
3363 +       data:NULL
3364 +};
3365 +
3366 +/**
3367 + * manage_kernel_tnls() - create and destroy kernel tunnels
3368 + *
3369 + * Description:
3370 + *   manage_kernel_tnls() creates new kernel devices if there
3371 + *   are less than $min_kdev_count of them and deletes old ones if
3372 + *   there are less than $max_kdev_count of them in the cache
3373 + *
3374 + * Note:
3375 + *   Schedules itself to be run later in process context if called from 
3376 + *   interrupt. Therefore only works synchronously when called from process 
3377 + *   context.
3378 + **/
3379 +
3380 +static void
3381 +manage_kernel_tnls(void *foo)
3382 +{
3383 +       struct ip6_tnl *t = NULL;
3384 +       struct ip6_tnl_parm parm;
3385 +
3386 +       /* We can't do this processing in interrupt 
3387 +          context so schedule it for later */
3388 +       if (in_interrupt()) {
3389 +               read_lock(&ip6ip6_kernel_lock);
3390 +               if (!shutdown &&
3391 +                   (kdev_count < min_kdev_count ||
3392 +                    kdev_count > max_kdev_count)) {
3393 +                       schedule_task(&manager_task);
3394 +               }
3395 +               read_unlock(&ip6ip6_kernel_lock);
3396 +               return;
3397 +       }
3398 +
3399 +       rtnl_lock();
3400 +       read_lock_bh(&ip6ip6_kernel_lock);
3401 +       memset(&parm, 0, sizeof (parm));
3402 +       parm.flags = IP6_TNL_F_KERNEL_DEV;
3403 +       /* Create tunnels until there are at least min_kdev_count */
3404 +       while (kdev_count < min_kdev_count) {
3405 +               read_unlock_bh(&ip6ip6_kernel_lock);
3406 +               if (!__ip6ip6_tnl_create(&parm, &t, 1)) {
3407 +                       dev_open(t->dev);
3408 +               } else {
3409 +                       goto err;
3410 +               }
3411 +               read_lock_bh(&ip6ip6_kernel_lock);
3412 +       }
3413 +
3414 +       /* Destroy tunnels until there are at most max_kdev_count */
3415 +       while (kdev_count > max_kdev_count) {
3416 +               read_unlock_bh(&ip6ip6_kernel_lock);
3417 +               if ((t = ip6ip6_kernel_tnl_unlink()) != NULL) {
3418 +                       unregister_netdevice(t->dev);
3419 +               } else {
3420 +                       goto err;
3421 +               }
3422 +               read_lock_bh(&ip6ip6_kernel_lock);
3423 +       }
3424 +       read_unlock_bh(&ip6ip6_kernel_lock);
3425 +err:
3426 +       rtnl_unlock();
3427 +}
3428 +
3429 +/**
3430 + * ip6ip6_tnl_inc_max_kdev_count() - increase max kernel dev cache size
3431 + *   @n: size increase
3432 + * Description:
3433 + *   Increase the upper limit for the number of kernel devices allowed in the 
3434 + *   cache at any on time.
3435 + **/
3436 +
3437 +unsigned int
3438 +ip6ip6_tnl_inc_max_kdev_count(unsigned int n)
3439 +{
3440 +       write_lock_bh(&ip6ip6_kernel_lock);
3441 +       max_kdev_count += n;
3442 +       write_unlock_bh(&ip6ip6_kernel_lock);
3443 +       manage_kernel_tnls(NULL);
3444 +       return max_kdev_count;
3445 +}
3446 +
3447 +/**
3448 + * ip6ip6_tnl_dec_max_kdev_count() -  decrease max kernel dev cache size
3449 + *   @n: size decrement
3450 + * Description:
3451 + *   Decrease the upper limit for the number of kernel devices allowed in the 
3452 + *   cache at any on time.
3453 + **/
3454 +
3455 +unsigned int
3456 +ip6ip6_tnl_dec_max_kdev_count(unsigned int n)
3457 +{
3458 +       write_lock_bh(&ip6ip6_kernel_lock);
3459 +       max_kdev_count -= min(max_kdev_count, n);
3460 +       if (max_kdev_count < min_kdev_count)
3461 +               min_kdev_count = max_kdev_count;
3462 +       write_unlock_bh(&ip6ip6_kernel_lock);
3463 +       manage_kernel_tnls(NULL);
3464 +       return max_kdev_count;
3465 +}
3466 +
3467 +/**
3468 + * ip6ip6_tnl_inc_min_kdev_count() - increase min kernel dev cache size
3469 + *   @n: size increase
3470 + * Description:
3471 + *   Increase the lower limit for the number of kernel devices allowed in the 
3472 + *   cache at any on time.
3473 + **/
3474 +
3475 +unsigned int
3476 +ip6ip6_tnl_inc_min_kdev_count(unsigned int n)
3477 +{
3478 +       write_lock_bh(&ip6ip6_kernel_lock);
3479 +       min_kdev_count += n;
3480 +       if (min_kdev_count > max_kdev_count)
3481 +               max_kdev_count = min_kdev_count;
3482 +       write_unlock_bh(&ip6ip6_kernel_lock);
3483 +       manage_kernel_tnls(NULL);
3484 +       return min_kdev_count;
3485 +}
3486 +
3487 +/**
3488 + * ip6ip6_tnl_dec_min_kdev_count() -  decrease min kernel dev cache size
3489 + *   @n: size decrement
3490 + * Description:
3491 + *   Decrease the lower limit for the number of kernel devices allowed in the 
3492 + *   cache at any on time.
3493 + **/
3494 +
3495 +unsigned int
3496 +ip6ip6_tnl_dec_min_kdev_count(unsigned int n)
3497 +{
3498 +       write_lock_bh(&ip6ip6_kernel_lock);
3499 +       min_kdev_count -= min(min_kdev_count, n);
3500 +       write_unlock_bh(&ip6ip6_kernel_lock);
3501 +       manage_kernel_tnls(NULL);
3502 +       return min_kdev_count;
3503 +}
3504 +
3505 +/**
3506 + * ip6ip6_tnl_locate - find or create tunnel matching given parameters
3507 + *   @p: tunnel parameters 
3508 + *   @create: != 0 if allowed to create new tunnel if no match found
3509 + *
3510 + * Description:
3511 + *   ip6ip6_tnl_locate() first tries to locate an existing tunnel
3512 + *   based on @parms. If this is unsuccessful, but @create is set a new
3513 + *   tunnel device is created and registered for use.
3514 + *
3515 + * Return:
3516 + *   0 if tunnel located or created,
3517 + *   -EINVAL if parameters incorrect,
3518 + *   -ENODEV if no matching tunnel available
3519 + **/
3520 +
3521 +int ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
3522 +{
3523 +       struct in6_addr *remote = &p->raddr;
3524 +       struct in6_addr *local = &p->laddr;
3525 +       struct ip6_tnl *t;
3526 +
3527 +       if (p->proto != IPPROTO_IPV6)
3528 +               return -EINVAL;
3529 +
3530 +       for (t = *ip6ip6_bucket(p); t; t = t->next) {
3531 +               if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3532 +                   !ipv6_addr_cmp(remote, &t->parms.raddr)) {
3533 +                       *pt = t;
3534 +                       return (create ? -EEXIST : 0);
3535 +               }
3536 +       }
3537 +       return ip6ip6_tnl_create(p, pt);
3538 +}
3539 +
3540 +/**
3541 + * ip6ip6_tnl_dev_destructor - tunnel device destructor
3542 + *   @dev: the device to be destroyed
3543 + **/
3544 +
3545 +static void
3546 +ip6ip6_tnl_dev_destructor(struct net_device *dev)
3547 +{
3548 +       if (dev != &ip6ip6_fb_tnl_dev) {
3549 +               MOD_DEC_USE_COUNT;
3550 +       }
3551 +}
3552 +
3553 +/**
3554 + * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
3555 + *   @dev: the device to be destroyed
3556 + *   
3557 + * Description:
3558 + *   ip6ip6_tnl_dev_uninit() removes tunnel from its list
3559 + **/
3560 +
3561 +static void
3562 +ip6ip6_tnl_dev_uninit(struct net_device *dev)
3563 +{
3564 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3565 +
3566 +       if (dev == &ip6ip6_fb_tnl_dev) {
3567 +               write_lock_bh(&ip6ip6_lock);
3568 +               tnls_wc[0] = NULL;
3569 +               write_unlock_bh(&ip6ip6_lock);
3570 +       } else {
3571 +               ip6ip6_tnl_unlink(t);
3572 +       }
3573 +       sock_release(t->sock);
3574 +       dev_put(dev);
3575 +}
3576 +
3577 +/**
3578 + * parse_tvl_tnl_enc_lim - handle encapsulation limit option
3579 + *   @skb: received socket buffer
3580 + *
3581 + * Return: 
3582 + *   0 if none was found, 
3583 + *   else index to encapsulation limit
3584 + **/
3585 +
3586 +static __u16
3587 +parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
3588 +{
3589 +       struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
3590 +       __u8 nexthdr = ipv6h->nexthdr;
3591 +       __u16 off = sizeof (*ipv6h);
3592 +
3593 +       while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
3594 +               __u16 optlen = 0;
3595 +               struct ipv6_opt_hdr *hdr;
3596 +               if (raw + off + sizeof (*hdr) > skb->data &&
3597 +                   !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
3598 +                       break;
3599 +
3600 +               hdr = (struct ipv6_opt_hdr *) (raw + off);
3601 +               if (nexthdr == NEXTHDR_FRAGMENT) {
3602 +                       struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
3603 +                       if (frag_hdr->frag_off)
3604 +                               break;
3605 +                       optlen = 8;
3606 +               } else if (nexthdr == NEXTHDR_AUTH) {
3607 +                       optlen = (hdr->hdrlen + 2) << 2;
3608 +               } else {
3609 +                       optlen = ipv6_optlen(hdr);
3610 +               }
3611 +               if (nexthdr == NEXTHDR_DEST) {
3612 +                       __u16 i = off + 2;
3613 +                       while (1) {
3614 +                               struct ipv6_tlv_tnl_enc_lim *tel;
3615 +
3616 +                               /* No more room for encapsulation limit */
3617 +                               if (i + sizeof (*tel) > off + optlen)
3618 +                                       break;
3619 +
3620 +                               tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
3621 +                               /* return index of option if found and valid */
3622 +                               if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
3623 +                                   tel->length == 1)
3624 +                                       return i;
3625 +                               /* else jump to next option */
3626 +                               if (tel->type)
3627 +                                       i += tel->length + 2;
3628 +                               else
3629 +                                       i++;
3630 +                       }
3631 +               }
3632 +               nexthdr = hdr->nexthdr;
3633 +               off += optlen;
3634 +       }
3635 +       return 0;
3636 +}
3637 +
3638 +/**
3639 + * ip6ip6_err - tunnel error handler
3640 + *
3641 + * Description:
3642 + *   ip6ip6_err() should handle errors in the tunnel according
3643 + *   to the specifications in RFC 2473.
3644 + **/
3645 +
3646 +void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
3647 +                  int type, int code, int offset, __u32 info)
3648 +{
3649 +       struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
3650 +       struct ip6_tnl *t;
3651 +       int rel_msg = 0;
3652 +       int rel_type = ICMPV6_DEST_UNREACH;
3653 +       int rel_code = ICMPV6_ADDR_UNREACH;
3654 +       __u32 rel_info = 0;
3655 +       __u16 len;
3656 +
3657 +       /* If the packet doesn't contain the original IPv6 header we are 
3658 +          in trouble since we might need the source address for furter 
3659 +          processing of the error. */
3660 +
3661 +       read_lock(&ip6ip6_lock);
3662 +       if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
3663 +               goto out;
3664 +
3665 +       switch (type) {
3666 +               __u32 teli;
3667 +               struct ipv6_tlv_tnl_enc_lim *tel;
3668 +               __u32 mtu;
3669 +       case ICMPV6_DEST_UNREACH:
3670 +               if (net_ratelimit())
3671 +                       printk(KERN_WARNING
3672 +                              "%s: Path to destination invalid "
3673 +                              "or inactive!\n", t->parms.name);
3674 +               rel_msg = 1;
3675 +               break;
3676 +       case ICMPV6_TIME_EXCEED:
3677 +               if (code == ICMPV6_EXC_HOPLIMIT) {
3678 +                       if (net_ratelimit())
3679 +                               printk(KERN_WARNING
3680 +                                      "%s: Too small hop limit or "
3681 +                                      "routing loop in tunnel!\n", 
3682 +                                      t->parms.name);
3683 +                       rel_msg = 1;
3684 +               }
3685 +               break;
3686 +       case ICMPV6_PARAMPROB:
3687 +               /* ignore if parameter problem not caused by a tunnel
3688 +                  encapsulation limit sub-option */
3689 +               if (code != ICMPV6_HDR_FIELD) {
3690 +                       break;
3691 +               }
3692 +               teli = parse_tlv_tnl_enc_lim(skb, skb->data);
3693 +
3694 +               if (teli && teli == ntohl(info) - 2) {
3695 +                       tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
3696 +                       if (tel->encap_limit == 0) {
3697 +                               if (net_ratelimit())
3698 +                                       printk(KERN_WARNING
3699 +                                              "%s: Too small encapsulation "
3700 +                                              "limit or routing loop in "
3701 +                                              "tunnel!\n", t->parms.name);
3702 +                               rel_msg = 1;
3703 +                       }
3704 +               }
3705 +               break;
3706 +       case ICMPV6_PKT_TOOBIG:
3707 +               mtu = ntohl(info) - offset;
3708 +               if (mtu < IPV6_MIN_MTU)
3709 +                       mtu = IPV6_MIN_MTU;
3710 +               t->dev->mtu = mtu;
3711 +
3712 +               if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
3713 +                       rel_type = ICMPV6_PKT_TOOBIG;
3714 +                       rel_code = 0;
3715 +                       rel_info = mtu;
3716 +                       rel_msg = 1;
3717 +               }
3718 +               break;
3719 +       }
3720 +       if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
3721 +               struct rt6_info *rt;
3722 +               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
3723 +               if (!skb2)
3724 +                       goto out;
3725 +
3726 +               dst_release(skb2->dst);
3727 +               skb2->dst = NULL;
3728 +               skb_pull(skb2, offset);
3729 +               skb2->nh.raw = skb2->data;
3730 +
3731 +               /* Try to guess incoming interface */
3732 +               rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
3733 +
3734 +               if (rt && rt->rt6i_dev)
3735 +                       skb2->dev = rt->rt6i_dev;
3736 +
3737 +               icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
3738 +
3739 +               if (rt)
3740 +                       dst_release(&rt->u.dst);
3741 +
3742 +               kfree_skb(skb2);
3743 +       }
3744 +out:
3745 +       read_unlock(&ip6ip6_lock);
3746 +}
3747 +
3748 +/**
3749 + * call_hooks - call ipv6 tunnel hooks
3750 + *   @hooknum: hook number, either %IP6_TNL_PRE_ENCAP, or 
3751 + *   %IP6_TNL_PRE_DECAP
3752 + *   @t: the current tunnel
3753 + *   @skb: the tunneled packet
3754 + *
3755 + * Description:
3756 + *   Pass packet to all the hook functions until %IP6_TNL_DROP
3757 + *
3758 + * Return:
3759 + *   %IP6_TNL_ACCEPT or %IP6_TNL_DROP
3760 + **/
3761 +
3762 +static inline int
3763 +call_hooks(unsigned int hooknum, struct ip6_tnl *t, struct sk_buff *skb)
3764 +{
3765 +       struct ip6_tnl_hook_ops *h;
3766 +       int accept = IP6_TNL_ACCEPT;
3767 +
3768 +       if (hooknum < IP6_TNL_MAXHOOKS) {
3769 +               struct list_head *i;
3770 +               read_lock(&ip6ip6_hook_lock);
3771 +               for (i = hooks[hooknum].next; i != &hooks[hooknum]; i = i->next) {
3772 +                       h = (struct ip6_tnl_hook_ops *) i;
3773 +
3774 +                       if (h->hook) {
3775 +                               accept = h->hook(t, skb);
3776 +
3777 +                               if (accept != IP6_TNL_ACCEPT)
3778 +                                       break;
3779 +                       }
3780 +               }
3781 +               read_unlock(&ip6ip6_hook_lock);
3782 +       }
3783 +       return accept;
3784 +}
3785 +
3786 +/**
3787 + * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
3788 + *   @skb: received socket buffer
3789 + *
3790 + * Return: 0
3791 + **/
3792 +
3793 +int ip6ip6_rcv(struct sk_buff *skb)
3794 +{
3795 +       struct ipv6hdr *ipv6h;
3796 +       struct ip6_tnl *t;
3797 +
3798 +       if (!pskb_may_pull(skb, sizeof (*ipv6h)))
3799 +               goto discard;
3800 +
3801 +       ipv6h = skb->nh.ipv6h;
3802 +
3803 +       read_lock(&ip6ip6_lock);
3804 +
3805 +       if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
3806 +               if (!(t->parms.flags & IP6_TNL_F_CAP_RCV) ||
3807 +                   call_hooks(IP6_TNL_PRE_DECAP, t, skb) != IP6_TNL_ACCEPT) {
3808 +                       t->stat.rx_dropped++;
3809 +                       read_unlock(&ip6ip6_lock);
3810 +                       goto discard;
3811 +               }
3812 +               skb->mac.raw = skb->nh.raw;
3813 +               skb->nh.raw = skb->data;
3814 +               skb->protocol = htons(ETH_P_IPV6);
3815 +               skb->pkt_type = PACKET_HOST;
3816 +               memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
3817 +               skb->dev = t->dev;
3818 +               dst_release(skb->dst);
3819 +               skb->dst = NULL;
3820 +               t->stat.rx_packets++;
3821 +               t->stat.rx_bytes += skb->len;
3822 +               netif_rx(skb);
3823 +               read_unlock(&ip6ip6_lock);
3824 +               return 0;
3825 +       }
3826 +       read_unlock(&ip6ip6_lock);
3827 +       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
3828 +discard:
3829 +       kfree_skb(skb);
3830 +       return 0;
3831 +}
3832 +
3833 +static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
3834 +{
3835 +       struct ipv6_tlv_tnl_enc_lim *tel;
3836 +       struct ipv6_txoptions *opt;
3837 +       __u8 *raw;
3838 +
3839 +       int opt_len = sizeof(*opt) + IPV6_TLV_TEL_DST_SIZE;
3840 +
3841 +       if (!(opt = kmalloc(opt_len, GFP_ATOMIC))) {
3842 +               return NULL;
3843 +       }
3844 +       memset(opt, 0, opt_len);
3845 +       opt->tot_len = opt_len;
3846 +       opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
3847 +       opt->opt_nflen = 8;
3848 +
3849 +       tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
3850 +       tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
3851 +       tel->length = 1;
3852 +       tel->encap_limit = encap_limit;
3853 +
3854 +       raw = (__u8 *) opt->dst0opt;
3855 +       raw[5] = IPV6_TLV_PADN;
3856 +       raw[6] = 1;
3857 +
3858 +       return opt;
3859 +}
3860 +
3861 +static int
3862 +ip6ip6_getfrag(const void *data, struct in6_addr *addr,
3863 +                 char *buff, unsigned int offset, unsigned int len)
3864 +{
3865 +       memcpy(buff, data + offset, len);
3866 +       return 0;
3867 +}
3868 +
3869 +/**
3870 + * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
3871 + *   @t: the outgoing tunnel device
3872 + *   @hdr: IPv6 header from the incoming packet 
3873 + *
3874 + * Description:
3875 + *   Avoid trivial tunneling loop by checking that tunnel exit-point 
3876 + *   doesn't match source of incoming packet.
3877 + *
3878 + * Return: 
3879 + *   1 if conflict,
3880 + *   0 else
3881 + **/
3882 +
3883 +static inline int
3884 +ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
3885 +{
3886 +       return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
3887 +}
3888 +
3889 +/**
3890 + * ip6ip6_tnl_xmit - encapsulate packet and send 
3891 + *   @skb: the outgoing socket buffer
3892 + *   @dev: the outgoing tunnel device 
3893 + *
3894 + * Description:
3895 + *   Build new header and do some sanity checks on the packet before sending
3896 + *   it to ip6_build_xmit().
3897 + *
3898 + * Return: 
3899 + *   0
3900 + **/
3901 +
3902 +int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
3903 +{
3904 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3905 +       struct net_device_stats *stats = &t->stat;
3906 +       struct ipv6hdr *ipv6h = skb->nh.ipv6h;
3907 +       struct ipv6_txoptions *opt = NULL;
3908 +       int encap_limit = -1;
3909 +       __u16 offset;
3910 +       struct flowi fl;
3911 +       int err = 0;
3912 +       struct dst_entry *dst;
3913 +       struct sock *sk = t->sock->sk;
3914 +       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
3915 +       int mtu;
3916 +
3917 +       if (t->recursion++) {
3918 +               stats->collisions++;
3919 +               goto tx_err;
3920 +       }
3921 +       if (skb->protocol != htons(ETH_P_IPV6) ||
3922 +           !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
3923 +           ip6ip6_tnl_addr_conflict(t, ipv6h)) {
3924 +               goto tx_err;
3925 +       }
3926 +       if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
3927 +               struct ipv6_tlv_tnl_enc_lim *tel;
3928 +               tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
3929 +               if (tel->encap_limit == 0) {
3930 +                       icmpv6_send(skb, ICMPV6_PARAMPROB,
3931 +                                   ICMPV6_HDR_FIELD, offset + 2, skb->dev);
3932 +                       goto tx_err;
3933 +               }
3934 +               encap_limit = tel->encap_limit - 1;
3935 +       } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
3936 +               encap_limit = t->parms.encap_limit;
3937 +       }
3938 +       if (call_hooks(IP6_TNL_PRE_ENCAP, t, skb) != IP6_TNL_ACCEPT)
3939 +               goto discard;
3940 +       memcpy(&fl, &t->fl, sizeof (fl));
3941 +
3942 +       if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
3943 +               fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
3944 +       if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
3945 +               fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
3946 +
3947 +       if (encap_limit >= 0 && (opt = create_tel(encap_limit)) == NULL)
3948 +               goto tx_err;
3949 +
3950 +       dst = __sk_dst_check(sk, np->dst_cookie);
3951 +
3952 +       if (dst) {
3953 +               if (np->daddr_cache == NULL ||
3954 +                   ipv6_addr_cmp(fl.fl6_dst, np->daddr_cache) ||
3955 +#ifdef CONFIG_IPV6_SUBTREES
3956 +                   np->saddr_cache == NULL ||
3957 +                   ipv6_addr_cmp(fl.fl6_src, np->saddr_cache) ||
3958 +#endif
3959 +                   (fl.oif && fl.oif != dst->dev->ifindex)) {
3960 +                       dst = NULL;
3961 +               } else {
3962 +                       dst_hold(dst);
3963 +               }
3964 +       }
3965 +       if (dst == NULL) {
3966 +               dst = ip6_route_output(sk, &fl);
3967 +               if (dst->error) {
3968 +                       stats->tx_carrier_errors++;
3969 +                       dst_link_failure(skb);
3970 +                       goto tx_err_dst_release;
3971 +               }
3972 +               /* local routing loop */
3973 +               if (dst->dev == dev) {
3974 +                       stats->collisions++;
3975 +                       if (net_ratelimit())
3976 +                               printk(KERN_WARNING 
3977 +                                      "%s: Local routing loop detected!\n",
3978 +                                      t->parms.name);
3979 +                       goto tx_err_dst_release;
3980 +               }
3981 +       }
3982 +       mtu = dst->pmtu - sizeof (*ipv6h);
3983 +       if (opt) {
3984 +               mtu -= (opt->opt_nflen + opt->opt_flen);
3985 +       }
3986 +       if (mtu < IPV6_MIN_MTU)
3987 +               mtu = IPV6_MIN_MTU;
3988 +       if (skb->dst && mtu < skb->dst->pmtu) {
3989 +               struct rt6_info *rt = (struct rt6_info *) skb->dst;
3990 +               rt->rt6i_flags |= RTF_MODIFIED;
3991 +               rt->u.dst.pmtu = mtu;
3992 +       }
3993 +       if (skb->len > mtu) {
3994 +               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
3995 +               goto tx_err_dst_release;
3996 +       }
3997 +       ip6_dst_store(sk, dst, &np->daddr, &np->saddr);
3998 +       err = ip6_build_xmit(sk, ip6ip6_getfrag, (void *) skb->nh.raw,
3999 +                            &fl, skb->len, opt, t->parms.hop_limit,
4000 +                            MSG_DONTWAIT);
4001 +
4002 +       if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {
4003 +               stats->tx_bytes += skb->len;
4004 +               stats->tx_packets++;
4005 +       } else {
4006 +               stats->tx_errors++;
4007 +               stats->tx_aborted_errors++;
4008 +       }
4009 +       if (opt)
4010 +               kfree(opt);
4011 +       kfree_skb(skb);
4012 +       t->recursion--;
4013 +       return 0;
4014 +tx_err_dst_release:
4015 +       dst_release(dst);
4016 +       if (opt)
4017 +               kfree(opt);
4018 +tx_err:
4019 +       stats->tx_errors++;
4020 +discard:
4021 +       stats->tx_dropped++;
4022 +       kfree_skb(skb);
4023 +       t->recursion--;
4024 +       return 0;
4025 +}
4026 +
4027 +static void ip6_tnl_set_cap(struct ip6_tnl *t)
4028 +{
4029 +       struct ip6_tnl_parm *p = &t->parms;
4030 +       struct in6_addr *laddr = &p->laddr;
4031 +       struct in6_addr *raddr = &p->raddr;
4032 +       int ltype = ipv6_addr_type(laddr);
4033 +       int rtype = ipv6_addr_type(raddr);
4034 +
4035 +       p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
4036 +
4037 +       if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
4038 +           ((ltype|rtype) &
4039 +            (IPV6_ADDR_UNICAST|
4040 +             IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
4041 +             IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
4042 +               struct net_device *ldev = NULL;
4043 +               int l_ok = 1;
4044 +               int r_ok = 1;
4045 +
4046 +               if (p->link)
4047 +                       ldev = dev_get_by_index(p->link);
4048 +
4049 +               if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
4050 +                       l_ok = 0;
4051 +
4052 +               if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
4053 +                       r_ok = 0;
4054 +
4055 +               if (l_ok && r_ok) {
4056 +                       if (ltype&IPV6_ADDR_UNICAST)
4057 +                               p->flags |= IP6_TNL_F_CAP_XMIT;
4058 +                       if (rtype&IPV6_ADDR_UNICAST)
4059 +                               p->flags |= IP6_TNL_F_CAP_RCV;
4060 +               }
4061 +               if (ldev)
4062 +                       dev_put(ldev);
4063 +       }
4064 +}
4065 +
4066 +static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
4067 +{
4068 +       struct net_device *dev = t->dev;
4069 +       struct ip6_tnl_parm *p = &t->parms;
4070 +       struct flowi *fl = &t->fl;
4071 +
4072 +       /* Set up flowi template */
4073 +       fl->fl6_src = &p->laddr;
4074 +       fl->fl6_dst = &p->raddr;
4075 +       fl->oif = p->link;
4076 +       fl->fl6_flowlabel = 0;
4077 +
4078 +       if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
4079 +               fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
4080 +       if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
4081 +               fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
4082 +
4083 +       ip6_tnl_set_cap(t);
4084 +
4085 +       if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
4086 +               dev->flags |= IFF_POINTOPOINT;
4087 +       else
4088 +               dev->flags &= ~IFF_POINTOPOINT;
4089 +
4090 +       if (p->flags & IP6_TNL_F_CAP_XMIT) {
4091 +               struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
4092 +                                                p->link, 0);
4093 +               
4094 +               if (rt == NULL)
4095 +                       return;
4096 +               
4097 +               if (rt->rt6i_dev) {
4098 +                       dev->iflink = rt->rt6i_dev->ifindex;
4099 +
4100 +                       dev->hard_header_len = rt->rt6i_dev->hard_header_len +
4101 +                               sizeof (struct ipv6hdr);
4102 +
4103 +                       dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr);
4104 +
4105 +                       if (dev->mtu < IPV6_MIN_MTU)
4106 +                               dev->mtu = IPV6_MIN_MTU;
4107 +               }
4108 +               dst_release(&rt->u.dst);
4109 +       }
4110 +}
4111 +
4112 +/**
4113 + * __ip6ip6_tnl_change - update the tunnel parameters
4114 + *   @t: tunnel to be changed
4115 + *   @p: tunnel configuration parameters
4116 + *
4117 + * Description:
4118 + *   __ip6ip6_tnl_change() updates the tunnel parameters
4119 + **/
4120 +
4121 +static void
4122 +__ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4123 +{
4124 +       ipv6_addr_copy(&t->parms.laddr, &p->laddr);
4125 +       ipv6_addr_copy(&t->parms.raddr, &p->raddr);
4126 +       t->parms.flags = p->flags;
4127 +       t->parms.hop_limit = p->hop_limit;
4128 +       t->parms.encap_limit = p->encap_limit;
4129 +       t->parms.flowinfo = p->flowinfo;
4130 +       ip6ip6_tnl_link_config(t);
4131 +}
4132 +
4133 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4134 +{
4135 +       ip6ip6_tnl_unlink(t);
4136 +       __ip6ip6_tnl_change(t, p);
4137 +       ip6ip6_tnl_link(t);
4138 +}
4139 +
4140 +/**
4141 + * ip6ip6_kernel_tnl_add - configure and add kernel tunnel to hash 
4142 + *   @p: kernel tunnel configuration parameters
4143 + *
4144 + * Description:
4145 + *   ip6ip6_kernel_tnl_add() fetches an unused kernel tunnel configures
4146 + *   it according to @p and places it among the active tunnels.
4147 + * 
4148 + * Return:
4149 + *   number of references to tunnel on success,
4150 + *   %-EEXIST if there is already a device matching description
4151 + *   %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4152 + *   %-ENODEV if there are no unused kernel tunnels available 
4153 + * 
4154 + * Note:
4155 + *   The code for creating, opening, closing and destroying network devices
4156 + *   must be called from process context, while the Mobile IP code, which 
4157 + *   needs the tunnel devices, unfortunately runs in interrupt context. 
4158 + *   
4159 + *   The devices must be created and opened in advance, then placed in a 
4160 + *   list where the kernel can fetch and ready them for use at a later time.
4161 + *
4162 + **/
4163 +
4164 +int
4165 +ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p)
4166 +{
4167 +       struct ip6_tnl *t;
4168 +
4169 +       if (!(p->flags & IP6_TNL_F_KERNEL_DEV))
4170 +               return -EINVAL;
4171 +       if ((t = ip6ip6_tnl_lookup(&p->raddr, &p->laddr)) != NULL &&
4172 +           t != &ip6ip6_fb_tnl) {
4173 +               /* Handle duplicate tunnels by incrementing 
4174 +                  reference count */
4175 +               atomic_inc(&t->refcnt);
4176 +               goto out;
4177 +       }
4178 +       if ((t = ip6ip6_kernel_tnl_unlink()) == NULL)
4179 +               return -ENODEV;
4180 +       __ip6ip6_tnl_change(t, p);
4181 +
4182 +       atomic_inc(&t->refcnt);
4183 +
4184 +       ip6ip6_tnl_link(t);
4185 +
4186 +       manage_kernel_tnls(NULL);
4187 +out:
4188 +       return atomic_read(&t->refcnt);
4189 +}
4190 +
4191 +/**
4192 + * ip6ip6_kernel_tnl_del - delete no longer needed kernel tunnel 
4193 + *   @t: kernel tunnel to be removed from hash
4194 + *
4195 + * Description:
4196 + *   ip6ip6_kernel_tnl_del() removes and deconfigures the tunnel @t
4197 + *   and places it among the unused kernel devices.
4198 + * 
4199 + * Return:
4200 + *   number of references on success,
4201 + *   %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4202 + * 
4203 + * Note:
4204 + *   See the comments on ip6ip6_kernel_tnl_add() for more information.
4205 + **/
4206 +
4207 +int
4208 +ip6ip6_kernel_tnl_del(struct ip6_tnl *t)
4209 +{
4210 +       if (!t)
4211 +               return -ENODEV;
4212 +
4213 +       if (!(t->parms.flags & IP6_TNL_F_KERNEL_DEV))
4214 +               return -EINVAL;
4215 +
4216 +       if (atomic_dec_and_test(&t->refcnt)) {
4217 +               struct ip6_tnl_parm p;
4218 +               ip6ip6_tnl_unlink(t);
4219 +               memset(&p, 0, sizeof (p));
4220 +               p.flags = IP6_TNL_F_KERNEL_DEV;
4221 +
4222 +               __ip6ip6_tnl_change(t, &p);
4223 +
4224 +               ip6ip6_kernel_tnl_link(t);
4225 +
4226 +               manage_kernel_tnls(NULL);
4227 +       }
4228 +       return atomic_read(&t->refcnt);
4229 +}
4230 +
4231 +/**
4232 + * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace 
4233 + *   @dev: virtual device associated with tunnel
4234 + *   @ifr: parameters passed from userspace
4235 + *   @cmd: command to be performed
4236 + *
4237 + * Description:
4238 + *   ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels 
4239 + *   from userspace. 
4240 + *
4241 + *   The possible commands are the following:
4242 + *     %SIOCGETTUNNEL: get tunnel parameters for device
4243 + *     %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
4244 + *     %SIOCCHGTUNNEL: change tunnel parameters to those given
4245 + *     %SIOCDELTUNNEL: delete tunnel
4246 + *
4247 + *   The fallback device "ip6tnl0", created during module 
4248 + *   initialization, can be used for creating other tunnel devices.
4249 + *
4250 + * Return:
4251 + *   0 on success,
4252 + *   %-EFAULT if unable to copy data to or from userspace,
4253 + *   %-EPERM if current process hasn't %CAP_NET_ADMIN set or attempting
4254 + *   to configure kernel devices from userspace, 
4255 + *   %-EINVAL if passed tunnel parameters are invalid,
4256 + *   %-EEXIST if changing a tunnel's parameters would cause a conflict
4257 + *   %-ENODEV if attempting to change or delete a nonexisting device
4258 + *
4259 + * Note:
4260 + *   See the comments on ip6ip6_kernel_tnl_add() for more information 
4261 + *   about kernel tunnels.
4262 + * **/
4263 +
4264 +static int
4265 +ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4266 +{
4267 +       int err = 0;
4268 +       int create;
4269 +       struct ip6_tnl_parm p;
4270 +       struct ip6_tnl *t = NULL;
4271 +
4272 +       MOD_INC_USE_COUNT;
4273 +
4274 +       switch (cmd) {
4275 +       case SIOCGETTUNNEL:
4276 +               if (dev == &ip6ip6_fb_tnl_dev) {
4277 +                       if (copy_from_user(&p,
4278 +                                          ifr->ifr_ifru.ifru_data,
4279 +                                          sizeof (p))) {
4280 +                               err = -EFAULT;
4281 +                               break;
4282 +                       }
4283 +                       if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
4284 +                               t = (struct ip6_tnl *) dev->priv;
4285 +                       else if (err)
4286 +                               break;
4287 +               } else
4288 +                       t = (struct ip6_tnl *) dev->priv;
4289 +
4290 +               memcpy(&p, &t->parms, sizeof (p));
4291 +               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
4292 +                       err = -EFAULT;
4293 +               }
4294 +               break;
4295 +       case SIOCADDTUNNEL:
4296 +       case SIOCCHGTUNNEL:
4297 +               err = -EPERM;
4298 +               create = (cmd == SIOCADDTUNNEL);
4299 +               if (!capable(CAP_NET_ADMIN))
4300 +                       break;
4301 +               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
4302 +                       err = -EFAULT;
4303 +                       break;
4304 +               }
4305 +               if (p.flags & IP6_TNL_F_KERNEL_DEV) {
4306 +                       break;
4307 +               }
4308 +               if (!create && dev != &ip6ip6_fb_tnl_dev) {
4309 +                       t = (struct ip6_tnl *) dev->priv;
4310 +               }
4311 +               if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
4312 +                       break;
4313 +               }
4314 +               if (cmd == SIOCCHGTUNNEL) {
4315 +                       if (t->dev != dev) {
4316 +                               err = -EEXIST;
4317 +                               break;
4318 +                       }
4319 +                       if (t->parms.flags & IP6_TNL_F_KERNEL_DEV) {
4320 +                               err = -EPERM;
4321 +                               break;
4322 +                       }
4323 +                       ip6ip6_tnl_change(t, &p);
4324 +                       netdev_state_change(dev);
4325 +               }
4326 +               if (copy_to_user(ifr->ifr_ifru.ifru_data,
4327 +                                &t->parms, sizeof (p))) {
4328 +                       err = -EFAULT;
4329 +               } else {
4330 +                       err = 0;
4331 +               }
4332 +               break;
4333 +       case SIOCDELTUNNEL:
4334 +               err = -EPERM;
4335 +               if (!capable(CAP_NET_ADMIN))
4336 +                       break;
4337 +
4338 +               if (dev == &ip6ip6_fb_tnl_dev) {
4339 +                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
4340 +                                          sizeof (p))) {
4341 +                               err = -EFAULT;
4342 +                               break;
4343 +                       }
4344 +                       err = ip6ip6_tnl_locate(&p, &t, 0);
4345 +                       if (err)
4346 +                               break;
4347 +                       if (t == &ip6ip6_fb_tnl) {
4348 +                               err = -EPERM;
4349 +                               break;
4350 +                       }
4351 +               } else {
4352 +                       t = (struct ip6_tnl *) dev->priv;
4353 +               }
4354 +               if (t->parms.flags & IP6_TNL_F_KERNEL_DEV)
4355 +                       err = -EPERM;
4356 +               else
4357 +                       err = unregister_netdevice(t->dev);
4358 +               break;
4359 +       default:
4360 +               err = -EINVAL;
4361 +       }
4362 +       MOD_DEC_USE_COUNT;
4363 +       return err;
4364 +}
4365 +
4366 +/**
4367 + * ip6ip6_tnl_get_stats - return the stats for tunnel device 
4368 + *   @dev: virtual device associated with tunnel
4369 + *
4370 + * Return: stats for device
4371 + **/
4372 +
4373 +static struct net_device_stats *
4374 +ip6ip6_tnl_get_stats(struct net_device *dev)
4375 +{
4376 +       return &(((struct ip6_tnl *) dev->priv)->stat);
4377 +}
4378 +
4379 +/**
4380 + * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
4381 + *   @dev: virtual device associated with tunnel
4382 + *   @new_mtu: the new mtu
4383 + *
4384 + * Return:
4385 + *   0 on success,
4386 + *   %-EINVAL if mtu too small
4387 + **/
4388 +
4389 +static int
4390 +ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
4391 +{
4392 +       if (new_mtu < IPV6_MIN_MTU) {
4393 +               return -EINVAL;
4394 +       }
4395 +       dev->mtu = new_mtu;
4396 +       return 0;
4397 +}
4398 +
4399 +/**
4400 + * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
4401 + *   @dev: virtual device associated with tunnel
4402 + *
4403 + * Description:
4404 + *   Set function pointers and initialize the &struct flowi template used
4405 + *   by the tunnel.
4406 + **/
4407 +
4408 +static int
4409 +ip6ip6_tnl_dev_init_gen(struct net_device *dev)
4410 +{
4411 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4412 +       struct flowi *fl = &t->fl;
4413 +       int err;
4414 +       struct sock *sk;
4415 +
4416 +       if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6, &t->sock))) {
4417 +               printk(KERN_ERR
4418 +                      "Failed to create IPv6 tunnel socket (err %d).\n", err);
4419 +               return err;
4420 +       }
4421 +       t->sock->inode->i_uid = 0;
4422 +       t->sock->inode->i_gid = 0;
4423 +
4424 +       sk = t->sock->sk;
4425 +       sk->allocation = GFP_ATOMIC;
4426 +       sk->net_pinfo.af_inet6.hop_limit = 254;
4427 +       sk->net_pinfo.af_inet6.mc_loop = 0;
4428 +       sk->prot->unhash(sk);
4429 +
4430 +       memset(fl, 0, sizeof (*fl));
4431 +       fl->proto = IPPROTO_IPV6;
4432 +
4433 +       dev->destructor = ip6ip6_tnl_dev_destructor;
4434 +       dev->uninit = ip6ip6_tnl_dev_uninit;
4435 +       dev->hard_start_xmit = ip6ip6_tnl_xmit;
4436 +       dev->get_stats = ip6ip6_tnl_get_stats;
4437 +       dev->do_ioctl = ip6ip6_tnl_ioctl;
4438 +       dev->change_mtu = ip6ip6_tnl_change_mtu;
4439 +
4440 +       dev->type = ARPHRD_TUNNEL6;
4441 +       dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
4442 +       dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
4443 +       dev->flags |= IFF_NOARP;
4444 +       dev->iflink = 0;
4445 +       /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be 
4446 +          copied to dev->dev_addr and dev->broadcast, like the ipv4
4447 +          addresses were in ipip.c, ip_gre.c and sit.c. */
4448 +       dev->addr_len = 0;
4449 +       return 0;
4450 +}
4451 +
4452 +/**
4453 + * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
4454 + *   @dev: virtual device associated with tunnel
4455 + **/
4456 +
4457 +static int
4458 +ip6ip6_tnl_dev_init(struct net_device *dev)
4459 +{
4460 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4461 +       ip6ip6_tnl_dev_init_gen(dev);
4462 +       ip6ip6_tnl_link_config(t);
4463 +       return 0;
4464 +}
4465 +
4466 +#ifdef MODULE
4467 +
4468 +/**
4469 + * ip6ip6_fb_tnl_open - function called when fallback device opened
4470 + *   @dev: fallback device
4471 + *
4472 + * Return: 0 
4473 + **/
4474 +
4475 +static int
4476 +ip6ip6_fb_tnl_open(struct net_device *dev)
4477 +{
4478 +       MOD_INC_USE_COUNT;
4479 +       return 0;
4480 +}
4481 +
4482 +/**
4483 + * ip6ip6_fb_tnl_close - function called when fallback device closed
4484 + *   @dev: fallback device
4485 + *
4486 + * Return: 0 
4487 + **/
4488 +
4489 +static int
4490 +ip6ip6_fb_tnl_close(struct net_device *dev)
4491 +{
4492 +       MOD_DEC_USE_COUNT;
4493 +       return 0;
4494 +}
4495 +#endif
4496 +
4497 +/**
4498 + * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
4499 + *   @dev: fallback device
4500 + *
4501 + * Return: 0
4502 + **/
4503 +
4504 +int __init
4505 +ip6ip6_fb_tnl_dev_init(struct net_device *dev)
4506 +{
4507 +       ip6ip6_tnl_dev_init_gen(dev);
4508 +#ifdef MODULE
4509 +       dev->open = ip6ip6_fb_tnl_open;
4510 +       dev->stop = ip6ip6_fb_tnl_close;
4511 +#endif
4512 +       dev_hold(dev);
4513 +       tnls_wc[0] = &ip6ip6_fb_tnl;
4514 +       return 0;
4515 +}
4516 +
4517 +/**
4518 + * ip6ip6_tnl_register_hook - add hook for processing of tunneled packets
4519 + *   @reg: hook function and its parameters
4520 + * 
4521 + * Description:
4522 + *   Add a netfilter like hook function for special handling of tunneled 
4523 + *   packets. The hook functions are called before encapsulation 
4524 + *   (%IP6_TNL_PRE_ENCAP) and before decapsulation 
4525 + *   (%IP6_TNL_PRE_DECAP). The possible return values by the hook 
4526 + *   functions are %IP6_TNL_DROP, %IP6_TNL_ACCEPT and 
4527 + *   %IP6_TNL_STOLEN (in case the hook function took care of the packet
4528 + *   and it doesn't have to be processed any further).
4529 + **/
4530 +
4531 +void
4532 +ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg)
4533 +{
4534 +       if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4535 +               struct list_head *i;
4536 +
4537 +               write_lock_bh(&ip6ip6_hook_lock);
4538 +               for (i = hooks[reg->hooknum].next;
4539 +                    i != &hooks[reg->hooknum]; i = i->next) {
4540 +                       if (reg->priority <
4541 +                           ((struct ip6_tnl_hook_ops *) i)->priority) {
4542 +                               break;
4543 +                       }
4544 +               }
4545 +               list_add(&reg->list, i->prev);
4546 +               write_unlock_bh(&ip6ip6_hook_lock);
4547 +       }
4548 +}
4549 +
4550 +/**
4551 + * ip6ip6_tnl_unregister_hook - remove tunnel hook
4552 + *   @reg: hook function and its parameters
4553 + **/
4554 +
4555 +void
4556 +ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg)
4557 +{
4558 +       if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4559 +               write_lock_bh(&ip6ip6_hook_lock);
4560 +               list_del(&reg->list);
4561 +               write_unlock_bh(&ip6ip6_hook_lock);
4562 +       }
4563 +}
4564 +
4565 +
4566 +/* the IPv6 over IPv6 protocol structure */
4567 +static struct inet6_protocol ip6ip6_protocol = {
4568 +       ip6ip6_rcv,             /* IPv6 handler         */
4569 +       ip6ip6_err,             /* IPv6 error control   */
4570 +       NULL,                   /* next                 */
4571 +       IPPROTO_IPV6,           /* protocol ID          */
4572 +       0,                      /* copy                 */
4573 +       NULL,                   /* data                 */
4574 +       "IPv6 over IPv6"        /* name                 */
4575 +};
4576 +
4577 +/**
4578 + * ip6_tunnel_init - register protocol and reserve needed resources
4579 + *
4580 + * Return: 0 on success
4581 + **/
4582 +
4583 +int __init ip6_tunnel_init(void)
4584 +{
4585 +       int i, err;
4586 +
4587 +       ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
4588 +
4589 +       for (i = 0; i < IP6_TNL_MAXHOOKS; i++) {
4590 +               INIT_LIST_HEAD(&hooks[i]);
4591 +       }
4592 +       if ((err = register_netdev(&ip6ip6_fb_tnl_dev)))
4593 +               return err;
4594 +
4595 +       inet6_add_protocol(&ip6ip6_protocol);
4596 +       return 0;
4597 +}
4598 +
4599 +/**
4600 + * ip6_tunnel_cleanup - free resources and unregister protocol
4601 + **/
4602 +
4603 +void ip6_tunnel_cleanup(void)
4604 +{
4605 +       write_lock_bh(&ip6ip6_kernel_lock);
4606 +       shutdown = 1;
4607 +       write_unlock_bh(&ip6ip6_kernel_lock);
4608 +       flush_scheduled_tasks();
4609 +       manage_kernel_tnls(NULL);
4610 +       inet6_del_protocol(&ip6ip6_protocol);
4611 +       unregister_netdev(&ip6ip6_fb_tnl_dev);
4612 +}
4613 +
4614 +#ifdef MODULE
4615 +module_init(ip6_tunnel_init);
4616 +module_exit(ip6_tunnel_cleanup);
4617 +#endif
4618 +
4619 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
4620 +EXPORT_SYMBOL(ip6ip6_tnl_register_hook);
4621 +EXPORT_SYMBOL(ip6ip6_tnl_unregister_hook);
4622 +#endif
4623 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
4624 +EXPORT_SYMBOL(ip6ip6_tnl_dec_max_kdev_count);
4625 +EXPORT_SYMBOL(ip6ip6_tnl_inc_max_kdev_count);
4626 +EXPORT_SYMBOL(ip6ip6_tnl_dec_min_kdev_count);
4627 +EXPORT_SYMBOL(ip6ip6_tnl_inc_min_kdev_count);
4628 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_add);
4629 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_del);
4630 +EXPORT_SYMBOL(ip6ip6_tnl_lookup);
4631 +#endif
4632 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
4633 +EXPORT_SYMBOL(ip6ip6_tnl_create);
4634 +EXPORT_SYMBOL(ip6ip6_tnl_change);
4635 +#endif
4636 +
4637 diff -uprN linux-2.4.25.old/net/ipv6/mipglue.c linux-2.4.25/net/ipv6/mipglue.c
4638 --- linux-2.4.25.old/net/ipv6/mipglue.c 1970-01-01 01:00:00.000000000 +0100
4639 +++ linux-2.4.25/net/ipv6/mipglue.c     2004-06-26 11:29:30.000000000 +0100
4640 @@ -0,0 +1,63 @@
4641 +/*
4642 + *     Glue for Mobility support integration to IPv6
4643 + *
4644 + *     Authors:
4645 + *     Antti Tuominen          <ajtuomin@cc.hut.fi>    
4646 + *
4647 + *     $Id$
4648 + *
4649 + *     This program is free software; you can redistribute it and/or
4650 + *      modify it under the terms of the GNU General Public License
4651 + *      as published by the Free Software Foundation; either version
4652 + *      2 of the License, or (at your option) any later version.
4653 + *
4654 + */
4655 +
4656 +#include <linux/sched.h>
4657 +
4658 +#include <net/ipv6.h>
4659 +#include <net/addrconf.h>
4660 +#include <net/neighbour.h>
4661 +#include <net/mipglue.h>
4662 +
4663 +extern int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff);
4664 +
4665 +/*  Initialize all zero  */
4666 +struct mipv6_callable_functions mipv6_functions = { NULL };
4667 +
4668 +/* Sets mipv6_functions struct to zero to invalidate all successive
4669 + * calls to mipv6 functions. Used on module unload. */
4670 +
4671 +void mipv6_invalidate_calls(void)
4672 +{
4673 +       memset(&mipv6_functions, 0, sizeof(mipv6_functions));
4674 +}
4675 +
4676 +
4677 +/* Selects correct handler for tlv encoded destination option. Called
4678 + * by ip6_parse_tlv. Checks if mipv6 calls are valid before calling. */
4679 +
4680 +int mipv6_handle_dstopt(struct sk_buff *skb, int optoff)
4681 +{
4682 +       int ret;
4683 +
4684 +        switch (skb->nh.raw[optoff]) {
4685 +       case MIPV6_TLV_HOMEADDR: 
4686 +               ret = MIPV6_CALLFUNC(mipv6_handle_homeaddr, 0)(skb, optoff);
4687 +               break;
4688 +       default:
4689 +               /* Should never happen */
4690 +               printk(KERN_ERR __FILE__ ": Invalid destination option code (%d)\n",
4691 +                      skb->nh.raw[optoff]);
4692 +               ret = 1;
4693 +               break;
4694 +       }
4695 +
4696 +       /* If mipv6 handlers are not valid, pass the packet to
4697 +         * ip6_tlvopt_unknown() for correct handling. */
4698 +       if (!ret)
4699 +               return ip6_tlvopt_unknown(skb, optoff);
4700 +
4701 +       return ret;
4702 +}
4703 +
4704 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/Config.in linux-2.4.25/net/ipv6/mobile_ip6/Config.in
4705 --- linux-2.4.25.old/net/ipv6/mobile_ip6/Config.in      1970-01-01 01:00:00.000000000 +0100
4706 +++ linux-2.4.25/net/ipv6/mobile_ip6/Config.in  2004-06-26 11:29:30.000000000 +0100
4707 @@ -0,0 +1,12 @@
4708 +#
4709 +# Mobile IPv6 Configuration
4710 +#
4711 +dep_tristate '    IPv6: Mobility Support (Correspondent Node)' CONFIG_IPV6_MOBILITY $CONFIG_IPV6
4712 +if [ "$CONFIG_IPV6_IPV6_TUNNEL" != "n" ]; then
4713 +   dep_tristate '      MIPv6: Mobile Node Support' CONFIG_IPV6_MOBILITY_MN $CONFIG_IPV6_MOBILITY
4714 +
4715 +   dep_tristate '      MIPv6: Home Agent Support' CONFIG_IPV6_MOBILITY_HA $CONFIG_IPV6_MOBILITY
4716 +fi
4717 +if [ "$CONFIG_IPV6_MOBILITY" != "n" ]; then
4718 +   bool '      MIPv6: Debug messages' CONFIG_IPV6_MOBILITY_DEBUG
4719 +fi
4720 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/Makefile linux-2.4.25/net/ipv6/mobile_ip6/Makefile
4721 --- linux-2.4.25.old/net/ipv6/mobile_ip6/Makefile       1970-01-01 01:00:00.000000000 +0100
4722 +++ linux-2.4.25/net/ipv6/mobile_ip6/Makefile   2004-06-26 11:29:30.000000000 +0100
4723 @@ -0,0 +1,35 @@
4724 +#
4725 +# Makefile for the MIPL Mobile IPv6 for Linux.
4726 +#
4727 +# Note! Dependencies are done automagically by 'make dep', which also
4728 +# removes any old dependencies. DON'T put your own dependencies here
4729 +# unless it's something special (ie not a .c file).
4730 +#
4731 +
4732 +
4733 +O_TARGET := mip6_base.o
4734 +
4735 +list-multi := mip6_ha.o mip6_mn.o
4736 +
4737 +obj-y := hashlist.o bcache.o mobhdr_common.o stats.o exthdrs.o \
4738 +       rr_crypto.o hmac.o auth_opt.o mipv6_icmp.o module_cn.o
4739 +
4740 +obj-m := $(O_TARGET)
4741 +
4742 +mip6_ha-objs := halist.o mipv6_icmp_ha.o tunnel_ha.o \
4743 +               ndisc_ha.o ha.o module_ha.o
4744 +
4745 +mip6_mn-objs := mipv6_icmp_mn.o ioctl_mn.o tunnel_mn.o \
4746 +               mdetect.o bul.o multiaccess_ctl.o mobhdr_mn.o mn.o \
4747 +               module_mn.o 
4748 +
4749 +obj-$(CONFIG_IPV6_MOBILITY_HA) += mip6_ha.o
4750 +obj-$(CONFIG_IPV6_MOBILITY_MN) += mip6_mn.o
4751 +
4752 +include $(TOPDIR)/Rules.make
4753 +
4754 +mip6_ha.o: $(mip6_ha-objs)
4755 +       $(LD) -r -o $@ $(mip6_ha-objs)
4756 +
4757 +mip6_mn.o: $(mip6_mn-objs)
4758 +       $(LD) -r -o $@ $(mip6_mn-objs)
4759 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/README linux-2.4.25/net/ipv6/mobile_ip6/README
4760 --- linux-2.4.25.old/net/ipv6/mobile_ip6/README 1970-01-01 01:00:00.000000000 +0100
4761 +++ linux-2.4.25/net/ipv6/mobile_ip6/README     2004-06-26 11:29:30.000000000 +0100
4762 @@ -0,0 +1,15 @@
4763 +MIPL Mobile IPv6 for Linux
4764 +
4765 +More information at http://www.mipl.mediapoli.com/.
4766 +
4767 +To join MIPL Mobile IPv6 for Linux mailing lists go to:
4768 +
4769 +       http://www.mipl.mediapoli.com/cgi-bin/mailman/listinfo
4770 +
4771 +Or send mail with subject "subscribe" for the general list to:
4772 +
4773 +       mipl-request@list.mipl.mediapoli.com
4774 +
4775 +or for the developer list to:
4776 +
4777 +       mipl-devel-request@list.mail.mediapoli.com
4778 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/auth_opt.c linux-2.4.25/net/ipv6/mobile_ip6/auth_opt.c
4779 --- linux-2.4.25.old/net/ipv6/mobile_ip6/auth_opt.c     1970-01-01 01:00:00.000000000 +0100
4780 +++ linux-2.4.25/net/ipv6/mobile_ip6/auth_opt.c 2004-06-26 11:29:30.000000000 +0100
4781 @@ -0,0 +1,121 @@
4782 +/*
4783 + *     MIPv6 Binding Authentication Data Option functions
4784 + *     
4785 + *      Authors: 
4786 + *      Henrik Petander         <lpetande@tml.hut.fi>
4787 + * 
4788 + *      $Id$
4789 + *
4790 + *      This program is free software; you can redistribute it and/or
4791 + *      modify it under the terms of the GNU General Public License
4792 + *      as published by the Free Software Foundation; either version
4793 + *      2 of the License, or (at your option) any later version.
4794 + */
4795 +
4796 +#include <linux/autoconf.h>
4797 +#include <linux/icmpv6.h>
4798 +#include <net/mipv6.h>
4799 +
4800 +#include "debug.h"
4801 +#include "hmac.h"
4802 +#include "mobhdr.h"
4803 +
4804 +#define DBG_KEY 5
4805 +
4806 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa, 
4807 +                    __u8 *mh, __u8 *aud_data, __u8 *k_bu)
4808 +{
4809 +       /* First look up the peer from sadb based on his address */ 
4810 +       struct ah_processing ahp;
4811 +
4812 +       /* Don't add any other options or this system is screwed */
4813 +
4814 +       __u8 buf[MAX_HASH_LENGTH];  
4815 +       
4816 +       
4817 +       if (!k_bu) {
4818 +               DEBUG(DBG_ERROR, "k_bu missing, aborting");
4819 +               return -1;
4820 +       }
4821 +       DEBUG(DBG_KEY, "Key for building authenticator:");
4822 +       debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4823 +
4824 +       if (ah_hmac_sha1_init(&ahp, k_bu,  HMAC_SHA1_KEY_SIZE) < 0) {
4825 +               DEBUG(DBG_ERROR, "Failed to initialize hmac sha1");
4826 +                return -1; 
4827 +        } 
4828 +
4829 +       DEBUG(DBG_KEY, "coa: ");
4830 +       debug_print_buffer(DBG_KEY, coa, 16);
4831 +       DEBUG(DBG_KEY, "cn_addr: ");
4832 +       debug_print_buffer(DBG_KEY, cn_addr, 16);
4833 +       DEBUG(DBG_KEY, "MH contents: ");
4834 +       debug_print_buffer(DBG_KEY, mh, aud_data - mh);
4835 +
4836 +       /* First the common part */
4837 +       ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4838 +       ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4839 +       ah_hmac_sha1_loop(&ahp, mh, aud_data - mh);
4840 +       ah_hmac_sha1_result(&ahp, buf);
4841 +
4842 +       memcpy(aud_data, buf,  MIPV6_RR_MAC_LENGTH);
4843 +
4844 +       return 0;
4845 +}
4846 +
4847 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa,
4848 +                    __u8 *opt, __u8 optlen, 
4849 +                    struct mipv6_mo_bauth_data *aud, __u8 *k_bu)
4850 +{
4851 +       int ret = -1;
4852 +       struct ah_processing ahp;
4853 +       __u8 htarget[MAX_HASH_LENGTH];
4854 +
4855 +       /* Look up peer by home address */ 
4856 +       if (!k_bu) {
4857 +               DEBUG(DBG_ERROR, "k_bu missing, aborting"); 
4858 +               return -1;
4859 +       }
4860 +
4861 +       DEBUG(DBG_KEY, "Key for checking authenticator:");
4862 +       debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4863 +
4864 +       if (!aud || !coa) {
4865 +               DEBUG(DBG_INFO, "%s is NULL", aud ? "coa" : "aud");
4866 +               goto out;
4867 +       }
4868 +
4869 +       if (aud->length != MIPV6_RR_MAC_LENGTH) {
4870 +               DEBUG(DBG_ERROR,
4871 +                        ": Incorrect authentication option length %d", aud->length); 
4872 +               goto out; 
4873 +       }
4874 +       
4875 +       if (ah_hmac_sha1_init(&ahp, k_bu, HMAC_SHA1_KEY_SIZE) < 0) { 
4876 +                DEBUG(DBG_ERROR,
4877 +                        "internal error in initialization of authentication algorithm");
4878 +               goto out;
4879 +        } 
4880 +       DEBUG(DBG_KEY, "coa: ");
4881 +       debug_print_buffer(DBG_KEY, coa, 16);
4882 +       DEBUG(DBG_KEY, "cn_addr: ");
4883 +       debug_print_buffer(DBG_KEY, cn_addr, 16);
4884 +       DEBUG(DBG_KEY, "MH contents: ");
4885 +       debug_print_buffer(DBG_KEY, opt, (u8*) aud->data - opt);
4886 +
4887 +       ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4888 +       ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4889 +
4890 +       /* 
4891 +        * Process MH + options till the start of the authenticator in
4892 +        * Auth. data option
4893 +        */
4894 +       ah_hmac_sha1_loop(&ahp, opt,  (u8 *)aud->data - opt);
4895 +       ah_hmac_sha1_result(&ahp, htarget);
4896 +       if (memcmp(htarget, aud->data, MIPV6_RR_MAC_LENGTH) == 0)
4897 +               ret = 0;
4898 +
4899 +       DEBUG(DBG_ERROR, "returning %d", ret);
4900 +out:   
4901 +       return ret;
4902 +}
4903 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.c linux-2.4.25/net/ipv6/mobile_ip6/bcache.c
4904 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.c       1970-01-01 01:00:00.000000000 +0100
4905 +++ linux-2.4.25/net/ipv6/mobile_ip6/bcache.c   2004-06-26 11:29:30.000000000 +0100
4906 @@ -0,0 +1,746 @@
4907 +/*
4908 + *      Binding Cache
4909 + *
4910 + *      Authors:
4911 + *      Juha Mynttinen            <jmynttin@cc.hut.fi>
4912 + *
4913 + *      $Id$
4914 + *
4915 + *      This program is free software; you can redistribute it and/or
4916 + *      modify it under the terms of the GNU General Public License
4917 + *      as published by the Free Software Foundation; either version
4918 + *      2 of the License, or (at your option) any later version.
4919 + */
4920 +
4921 +/*
4922 + *     Changes:
4923 + *
4924 + *     Nanno Langstraat        :       Timer code cleaned up, active socket
4925 + *                                     test rewritten
4926 + */
4927 +
4928 +#include <linux/autoconf.h>
4929 +#include <linux/sched.h>
4930 +#include <linux/timer.h>
4931 +#include <linux/in6.h>
4932 +#include <linux/init.h>
4933 +#include <linux/spinlock.h>
4934 +#include <linux/proc_fs.h>
4935 +#include <linux/ipv6_route.h>
4936 +#include <net/ipv6.h>
4937 +#include <net/addrconf.h>
4938 +#include <net/tcp.h>
4939 +#include <net/udp.h>
4940 +#include <net/ip6_route.h>
4941 +#include <net/mipv6.h>
4942 +
4943 +#include "bcache.h"
4944 +#include "hashlist.h"
4945 +#include "debug.h"
4946 +#include "mobhdr.h"
4947 +#include "tunnel.h"
4948 +#include "config.h"
4949 +
4950 +#define TIMERDELAY HZ/10
4951 +
4952 +struct mipv6_bcache {
4953 +       struct hashlist *entries;
4954 +       __u32 size;
4955 +       struct timer_list callback_timer;
4956 +};
4957 +
4958 +struct in6_addr_pair {
4959 +       struct in6_addr *a1;
4960 +       struct in6_addr *a2;
4961 +};
4962 +
4963 +static rwlock_t bcache_lock = RW_LOCK_UNLOCKED;
4964 +
4965 +static struct mipv6_bcache bcache;
4966 +
4967 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
4968 +                           int length);
4969 +
4970 +#define MIPV6_BCACHE_HASHSIZE  32
4971 +
4972 +/* Moment of transmission of a BR, in seconds before bcache entry expiry */
4973 +#define BCACHE_BR_SEND_LEAD  3
4974 +
4975 +#define MIPV6_MAX_BRR 3 /* Send 3 BRRs before deleting BC entry */
4976 +#define MIPV6_BRR_RATE HZ /* Send BRRs once per second */
4977 +
4978 +/* 
4979 + * Internal functions.
4980 + */
4981 +
4982 +struct cache_entry_iterator_args {
4983 +       struct mipv6_bce **entry;
4984 +};
4985 +
4986 +static int find_first_cache_entry_iterator(void *data, void *args,
4987 +                                          unsigned long *lifetime)
4988 +{
4989 +       struct mipv6_bce *entry =
4990 +           (struct mipv6_bce *) data;
4991 +       struct cache_entry_iterator_args *state =
4992 +           (struct cache_entry_iterator_args *) args;
4993 +
4994 +       ASSERT(entry != NULL);
4995 +
4996 +       if (entry->type == CACHE_ENTRY) {
4997 +               *(state->entry) = entry;
4998 +               return ITERATOR_STOP;   /* stop iteration */
4999 +       } else {
5000 +               return ITERATOR_CONT;   /* continue iteration */
5001 +       }
5002 +}
5003 +
5004 +
5005 +/* 
5006 + * Get memory for a new bcache entry.  If bcache is full, a cache
5007 + * entry may be deleted to get space for a home registration, but not
5008 + * vice versa.
5009 + */
5010 +static struct mipv6_bce *mipv6_bce_alloc(__u8 type)
5011 +{
5012 +       struct mipv6_bce *entry;
5013 +       struct cache_entry_iterator_args args;
5014 +
5015 +       DEBUG_FUNC();
5016 +
5017 +       entry = (struct mipv6_bce *)
5018 +               hashlist_alloc(bcache.entries, SLAB_ATOMIC);
5019 +
5020 +       /* Cache replacement policy: always replace the CACHE_ENTRY
5021 +           closest to expiration.  Type HOME_REGISTRATION entry may
5022 +           never be deleted before expiration. */
5023 +       if (entry == NULL) {
5024 +               /* cache full, try to delete a CACHE_ENTRY */
5025 +               args.entry = &entry;
5026 +               hashlist_iterate(bcache.entries, &args,
5027 +                                find_first_cache_entry_iterator);
5028 +               if (entry == NULL)
5029 +                       return NULL;
5030 +               hashlist_delete(bcache.entries,
5031 +                               (struct hashlist_entry *)entry);
5032 +               entry = (struct mipv6_bce *)
5033 +                       hashlist_alloc(bcache.entries, SLAB_ATOMIC);
5034 +       }
5035 +       return entry;
5036 +}
5037 +
5038 +/*
5039 + * Frees entry's memory allocated with mipv6_bce_alloc
5040 + */
5041 +static void mipv6_bce_free(struct mipv6_bce *entry)
5042 +{
5043 +       hashlist_free(bcache.entries, (void *) entry);
5044 +}
5045 +
5046 +/*
5047 + * Removes all expired entries 
5048 + */
5049 +static void expire(void)
5050 +{
5051 +       struct mipv6_bce *entry;
5052 +       struct br_addrs {
5053 +               struct in6_addr daddr;
5054 +               struct in6_addr saddr;
5055 +               struct br_addrs *next;
5056 +       };
5057 +       struct br_addrs *br_info = NULL;
5058 +
5059 +       DEBUG_FUNC();
5060 +
5061 +       write_lock(&bcache_lock);
5062 +
5063 +       while ((entry = (struct mipv6_bce *)
5064 +               hashlist_get_first(bcache.entries)) != NULL) {
5065 +               struct rt6_info *rt;
5066 +               if (time_after_eq(jiffies, entry->callback_time)) {
5067 +
5068 +                       DEBUG(DBG_INFO, "an entry expired");
5069 +
5070 +                       if (entry->type & HOME_REGISTRATION) {
5071 +                               mip6_fn.proxy_del(&entry->home_addr, entry);
5072 +                       }
5073 +                       hashlist_delete(bcache.entries, (void *)entry);
5074 +                       mipv6_bce_free(entry);
5075 +                       entry = NULL;
5076 +               } else if (entry->br_callback_time != 0 &&
5077 +                          time_after_eq(jiffies, entry->br_callback_time) &&
5078 +                          entry->br_count < MIPV6_MAX_BRR &&
5079 +                          (rt = rt6_lookup(&entry->home_addr, &entry->our_addr, 0, 0)) != NULL){
5080 +                       /* Do we have a destination cache entry for the home address */
5081 +                       if (rt->rt6i_flags & RTF_CACHE) {
5082 +                               struct br_addrs *tmp;
5083 +                               tmp = br_info;
5084 +                               DEBUG(DBG_INFO,
5085 +                                     "bcache entry recently used. Sending BR.");
5086 +                               /* queue for sending */
5087 +                               br_info = kmalloc(sizeof(struct br_addrs),
5088 +                                                 GFP_ATOMIC);
5089 +                               if (br_info) {
5090 +                                       ipv6_addr_copy(&br_info->saddr,
5091 +                                                      &entry->our_addr);
5092 +                                       ipv6_addr_copy(&br_info->daddr,
5093 +                                                      &entry->home_addr);
5094 +                                       br_info->next = tmp;
5095 +                                       entry->last_br = jiffies;
5096 +                                       entry->br_callback_time = jiffies + MIPV6_BRR_RATE;
5097 +                                       entry->br_count++;
5098 +                               } else {
5099 +                                       br_info = tmp;
5100 +                                       DEBUG(DBG_ERROR, "Out of memory");
5101 +                               }
5102 +                               
5103 +                       } else
5104 +                               entry->br_callback_time = 0;    
5105 +                       dst_release(&rt->u.dst);
5106 +               } else {
5107 +                       entry->br_callback_time = 0;
5108 +                       break;
5109 +               }
5110 +       }
5111 +       write_unlock(&bcache_lock);
5112 +
5113 +       while (br_info) {
5114 +               struct br_addrs *tmp = br_info->next;
5115 +               if (mipv6_send_brr(&br_info->saddr, &br_info->daddr, NULL) < 0)
5116 +                       DEBUG(DBG_WARNING,
5117 +                             "BR send for %x:%x:%x:%x:%x:%x:%x:%x failed",
5118 +                             NIPV6ADDR(&br_info->daddr));
5119 +               kfree(br_info);
5120 +               br_info = tmp;
5121 +       }
5122 +}
5123 +
5124 +static void set_timer(void)
5125 +{
5126 +       struct mipv6_bce *entry;
5127 +       unsigned long callback_time;
5128 +
5129 +       DEBUG_FUNC();
5130 +
5131 +       entry = (struct mipv6_bce *)
5132 +               hashlist_get_first(bcache.entries);
5133 +       if (entry != NULL) {
5134 +               if (entry->br_callback_time > 0 && 
5135 +                   time_after(entry->br_callback_time, jiffies))
5136 +                       callback_time = entry->br_callback_time;
5137 +               else if (time_after(entry->callback_time, jiffies))
5138 +                       callback_time = entry->callback_time;
5139 +               else {
5140 +                       DEBUG(DBG_WARNING, 
5141 +                             "bcache timer attempted to schedule"
5142 +                             " for a historical jiffies count!");
5143 +                       callback_time = jiffies + TIMERDELAY;
5144 +               }
5145 +               
5146 +               DEBUG(DBG_INFO, "setting timer to now");
5147 +               mod_timer(&bcache.callback_timer, callback_time);
5148 +       } else {
5149 +               del_timer(&bcache.callback_timer);
5150 +               DEBUG(DBG_INFO, "BC empty, not setting a new timer");
5151 +       }
5152 +}
5153 +
5154 +/* 
5155 + * The function that is scheduled to do the callback functions. May be
5156 + * modified e.g to allow Binding Requests, now only calls expire() and
5157 + * schedules a new timer.
5158 + */
5159 +static void timer_handler(unsigned long dummy)
5160 +{
5161 +       expire();
5162 +       write_lock(&bcache_lock);
5163 +       set_timer();
5164 +       write_unlock(&bcache_lock);
5165 +}
5166 +
5167 +/*
5168 + * Interface functions visible to other modules
5169 + */
5170 +
5171 +/**
5172 + * mipv6_bcache_add - add Binding Cache entry
5173 + * @ifindex: interface index
5174 + * @our_addr: own address
5175 + * @home_addr_org: MN's home address
5176 + * @coa: MN's care-of address
5177 + * @lifetime: lifetime for this binding
5178 + * @prefix: prefix length
5179 + * @seq: sequence number
5180 + * @flags: flags received in BU
5181 + * @type: type of entry
5182 + *
5183 + * Adds an entry for this @home_addr_org in the Binding Cache.  If entry
5184 + * already exists, old entry is updated.  @type may be %CACHE_ENTRY or
5185 + * %HOME_REGISTRATION.
5186 + **/
5187 +int mipv6_bcache_add(int ifindex,
5188 +                    struct in6_addr *our_addr,
5189 +                    struct in6_addr *home_addr,
5190 +                    struct in6_addr *coa,
5191 +                    __u32 lifetime, __u16 seq, __u8 flags, __u8 type)
5192 +{
5193 +       struct mipv6_bce *entry;
5194 +       int update = 0;
5195 +       int create_tunnel = 0;
5196 +       unsigned long now = jiffies;
5197 +       struct in6_addr_pair hashkey;
5198 +       int ret = -1;
5199 +
5200 +       DEBUG_FUNC();
5201 +
5202 +       hashkey.a1 = home_addr;
5203 +       hashkey.a2 = our_addr;
5204 +
5205 +       write_lock(&bcache_lock);
5206 +
5207 +       if (type == HOME_REGISTRATION && !(mip6node_cnf.capabilities&CAP_HA))
5208 +               return 0;
5209 +
5210 +       if (unlikely(bcache.entries == NULL)) {
5211 +               ret = -ENOMEM;
5212 +               goto err;
5213 +       }
5214 +
5215 +       if ((entry = (struct mipv6_bce *)
5216 +            hashlist_get(bcache.entries, &hashkey)) != NULL) {
5217 +               /* if an entry for this home_addr exists (with smaller
5218 +                * seq than the new seq), update it by removing it
5219 +                * first
5220 +                */
5221 +               if (!MIPV6_SEQ_GT(seq, entry->seq)) {
5222 +                       DEBUG(DBG_INFO, "smaller seq than existing, not updating");
5223 +                       goto out;
5224 +               }
5225 +               DEBUG(DBG_INFO, "updating an existing entry");
5226 +               update = 1;
5227 +
5228 +               /* H-flag is already checked in BU handler. */
5229 +               /* XXX: Should we care about the other flags?*/
5230 +               if (flags != entry->flags) {
5231 +                       DEBUG(DBG_INFO, "entry/BU flag mismatch");
5232 +               }
5233 +
5234 +               if (type == HOME_REGISTRATION) {
5235 +                       create_tunnel = (ipv6_addr_cmp(&entry->coa, coa) ||
5236 +                                        entry->ifindex != ifindex);
5237 +               }
5238 +       } else {
5239 +               /* no entry for this home_addr, try to create a new entry */
5240 +               DEBUG(DBG_INFO, "creating a new entry");
5241 +               update = 0;
5242 +
5243 +               entry = mipv6_bce_alloc(type);
5244 +               if (entry == NULL) {
5245 +                       DEBUG(DBG_INFO, "cache full, entry not added");
5246 +                       goto err;
5247 +               }
5248 +
5249 +               create_tunnel = (type == HOME_REGISTRATION);
5250 +       }
5251 +
5252 +       if (create_tunnel) {
5253 +               if (update)
5254 +                       mip6_fn.proxy_del(&entry->home_addr, entry);
5255 +               if (mip6_fn.proxy_create(flags, ifindex, coa, our_addr, home_addr) < 0) {
5256 +                       goto err_proxy;
5257 +               }
5258 +       }
5259 +
5260 +       ipv6_addr_copy(&(entry->our_addr), our_addr);
5261 +       ipv6_addr_copy(&(entry->home_addr), home_addr);
5262 +       ipv6_addr_copy(&(entry->coa), coa);
5263 +       entry->ifindex = ifindex;
5264 +       entry->seq = seq;
5265 +       entry->type = type;
5266 +       entry->flags = flags;
5267 +       
5268 +       entry->last_br = 0;
5269 +       entry->destunr_count = 0;
5270 +       entry->callback_time = now + lifetime * HZ;
5271 +       if (entry->type & HOME_REGISTRATION)
5272 +               entry->br_callback_time = 0;
5273 +       else
5274 +               entry->br_callback_time = now +
5275 +                       (lifetime - BCACHE_BR_SEND_LEAD) * HZ;
5276 +       
5277 +       if (update) {
5278 +               DEBUG(DBG_INFO, "updating entry : %x", entry);
5279 +               hashlist_reposition(bcache.entries, (void *)entry, 
5280 +                                   entry->callback_time);
5281 +       } else {
5282 +               DEBUG(DBG_INFO, "adding entry: %x", entry);
5283 +               if ((hashlist_add(bcache.entries,
5284 +                                 &hashkey,
5285 +                                 entry->callback_time, entry)) < 0) {
5286 +                       
5287 +                       DEBUG(DBG_ERROR, "Hash add failed");
5288 +                       goto err_hashlist;
5289 +               }
5290 +       }
5291 +       
5292 +       set_timer();
5293 +       
5294 +out:
5295 +       write_unlock(&bcache_lock);
5296 +       return 0;
5297 +
5298 +err_hashlist:
5299 +       if (create_tunnel) {
5300 +               mip6_fn.proxy_del(home_addr, entry);
5301 +       }
5302 +err_proxy:
5303 +       if (update) {
5304 +               hashlist_delete(bcache.entries, (void *)entry);
5305 +       }
5306 +       mipv6_bce_free(entry);
5307 +err:
5308 +       write_unlock(&bcache_lock);
5309 +       return ret;
5310 +}
5311 +
5312 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5313 +                         struct in6_addr *our_addr, 
5314 +                         int destunr_count)
5315 +{
5316 +       struct mipv6_bce *entry;
5317 +       struct in6_addr_pair hashkey;
5318 +
5319 +       int ret = -ENOENT;
5320 +
5321 +       DEBUG_FUNC();
5322 +
5323 +       hashkey.a1 = home_addr;
5324 +       hashkey.a2 = our_addr;
5325 +
5326 +       write_lock(&bcache_lock);
5327 +       if (unlikely(bcache.entries == NULL)) {
5328 +               ret = -ENOMEM;
5329 +               goto err;
5330 +       }
5331 +
5332 +       if ((entry = (struct mipv6_bce *)
5333 +            hashlist_get(bcache.entries, &hashkey)) != NULL) {
5334 +               entry->last_destunr = jiffies;
5335 +               entry->destunr_count = destunr_count;
5336 +               ret = 0;
5337 +       }
5338 +err:
5339 +       write_unlock(&bcache_lock);
5340 +       return ret;
5341 +}
5342 +
5343 +
5344 +/**
5345 + * mipv6_bcache_delete - delete Binding Cache entry
5346 + * @home_addr: MN's home address
5347 + * @our_addr: our address
5348 + * @type: type of entry
5349 + *
5350 + * Deletes an entry associated with @home_addr from Binding Cache.
5351 + * Valid values for @type are %CACHE_ENTRY, %HOME_REGISTRATION and
5352 + * %ANY_ENTRY.  %ANY_ENTRY deletes any type of entry.
5353 + **/
5354 +int mipv6_bcache_delete(struct in6_addr *home_addr,
5355 +                       struct in6_addr *our_addr, __u8 type)
5356 +{
5357 +       struct mipv6_bce *entry;
5358 +       struct in6_addr_pair hashkey;
5359 +       int err = 0;
5360 +
5361 +       DEBUG_FUNC();
5362 +
5363 +       if (home_addr == NULL || our_addr == NULL) {
5364 +               DEBUG(DBG_INFO, "error in arguments");
5365 +               return -EINVAL;
5366 +       }
5367 +
5368 +       hashkey.a1 = home_addr;
5369 +       hashkey.a2 = our_addr;
5370 +
5371 +       write_lock(&bcache_lock);
5372 +
5373 +       if (unlikely(bcache.entries == NULL) ||
5374 +           (entry = (struct mipv6_bce *)
5375 +            hashlist_get(bcache.entries, &hashkey)) == NULL ||
5376 +           !(entry->type & type)) {
5377 +               DEBUG(DBG_INFO, "No matching entry found");
5378 +               err = -ENOENT;
5379 +               goto out;
5380 +       }
5381 +
5382 +       hashlist_delete(bcache.entries, (void *) entry);
5383 +       mipv6_bce_free(entry);
5384 +
5385 +       set_timer();
5386 +out:
5387 +       write_unlock(&bcache_lock);
5388 +       return err;
5389 +}
5390 +
5391 +/**
5392 + * mipv6_bcache_exists - check if entry exists
5393 + * @home_addr: home address to check
5394 + * @our_addr: our address
5395 + *
5396 + * Determines if a binding exists for @home_addr.  Returns type of the
5397 + * entry or negative if entry does not exist.
5398 + **/
5399 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5400 +                       struct in6_addr *our_addr)
5401 +{
5402 +       struct mipv6_bce *entry;
5403 +       struct in6_addr_pair hashkey;
5404 +       int type = -ENOENT;
5405 +
5406 +       DEBUG_FUNC();
5407 +
5408 +       if (home_addr == NULL || our_addr == NULL)
5409 +               return -EINVAL;
5410 +
5411 +       hashkey.a1 = home_addr;
5412 +       hashkey.a2 = our_addr;
5413 +
5414 +       read_lock(&bcache_lock);
5415 +       if (likely(bcache.entries != NULL) &&
5416 +           (entry = (struct mipv6_bce *)
5417 +            hashlist_get(bcache.entries, &hashkey)) != NULL) {
5418 +               type = entry->type;
5419 +       }
5420 +       read_unlock(&bcache_lock);
5421 +
5422 +       return type;
5423 +}
5424 +
5425 +/**
5426 + * mipv6_bcache_get - get entry from Binding Cache
5427 + * @home_addr: home address to search
5428 + * @our_addr: our address
5429 + * @entry: pointer to buffer
5430 + *
5431 + * Gets a copy of Binding Cache entry for @home_addr. If entry 
5432 + * exists entry is copied to @entry and zero is returned.  
5433 + * Otherwise returns negative.
5434 + **/
5435 +int mipv6_bcache_get(struct in6_addr *home_addr,
5436 +                    struct in6_addr *our_addr,
5437 +                    struct mipv6_bce *entry)
5438 +{
5439 +       struct mipv6_bce *entry2;
5440 +       struct in6_addr_pair hashkey;
5441 +       int ret = -ENOENT;
5442 +
5443 +       DEBUG_FUNC();
5444 +
5445 +       if (home_addr == NULL || our_addr == NULL || entry == NULL)
5446 +               return -EINVAL;
5447 +
5448 +       hashkey.a1 = home_addr;
5449 +       hashkey.a2 = our_addr;
5450 +
5451 +       read_lock_bh(&bcache_lock);
5452 +
5453 +       entry2 = (struct mipv6_bce *)
5454 +               hashlist_get(bcache.entries, &hashkey);
5455 +       if (entry2 != NULL) {
5456 +               memcpy(entry, entry2, sizeof(struct mipv6_bce));
5457 +               ret = 0;
5458 +       }
5459 +       read_unlock_bh(&bcache_lock);
5460 +       return ret;
5461 +}
5462 +
5463 +int mipv6_bcache_iterate(hashlist_iterator_t func, void *args)
5464 +{
5465 +       int ret;
5466 +
5467 +       read_lock_bh(&bcache_lock);
5468 +       ret = hashlist_iterate(bcache.entries, args, func);
5469 +       read_unlock_bh(&bcache_lock);
5470 +
5471 +       return ret;
5472 +}
5473 +
5474 +/*
5475 + * Proc-filesystem functions
5476 + */
5477 +
5478 +#define BC_INFO_LEN 80
5479 +
5480 +struct procinfo_iterator_args {
5481 +       char *buffer;
5482 +       int offset;
5483 +       int length;
5484 +       int skip;
5485 +       int len;
5486 +};
5487 +
5488 +static int procinfo_iterator(void *data, void *args, unsigned long *pref)
5489 +{
5490 +       struct procinfo_iterator_args *arg =
5491 +           (struct procinfo_iterator_args *) args;
5492 +       struct mipv6_bce *entry =
5493 +           (struct mipv6_bce *) data;
5494 +
5495 +       ASSERT(entry != NULL);
5496 +
5497 +       if (arg->skip < arg->offset / BC_INFO_LEN) {
5498 +               arg->skip++;
5499 +               return ITERATOR_CONT;
5500 +       }
5501 +
5502 +       if (arg->len >= arg->length)
5503 +               return ITERATOR_CONT;
5504 +
5505 +       /* HoA CoA CallbackInSecs Type */
5506 +       arg->len += sprintf(arg->buffer + arg->len,
5507 +                           "%08x%08x%08x%08x %08x%08x%08x%08x %010lu %02d\n",
5508 +                           ntohl(entry->home_addr.s6_addr32[0]),
5509 +                           ntohl(entry->home_addr.s6_addr32[1]),
5510 +                           ntohl(entry->home_addr.s6_addr32[2]),
5511 +                           ntohl(entry->home_addr.s6_addr32[3]),
5512 +                           ntohl(entry->coa.s6_addr32[0]),
5513 +                           ntohl(entry->coa.s6_addr32[1]),
5514 +                           ntohl(entry->coa.s6_addr32[2]),
5515 +                           ntohl(entry->coa.s6_addr32[3]),
5516 +                           ((entry->callback_time) - jiffies) / HZ,
5517 +                           (int) entry->type);
5518 +
5519 +       return ITERATOR_CONT;
5520 +}
5521 +
5522 + /*
5523 +  * Callback function for proc filesystem.
5524 +  */
5525 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
5526 +                           int length)
5527 +{
5528 +       struct procinfo_iterator_args args;
5529 +
5530 +       DEBUG_FUNC();
5531 +
5532 +       args.buffer = buffer;
5533 +       args.offset = offset;
5534 +       args.length = length;
5535 +       args.skip = 0;
5536 +       args.len = 0;
5537 +
5538 +       read_lock_bh(&bcache_lock);
5539 +       hashlist_iterate(bcache.entries, &args, procinfo_iterator);
5540 +       read_unlock_bh(&bcache_lock);
5541 +
5542 +       *start = buffer;
5543 +       if (offset)
5544 +               *start += offset % BC_INFO_LEN;
5545 +
5546 +       args.len -= offset % BC_INFO_LEN;
5547 +
5548 +       if (args.len > length)
5549 +               args.len = length;
5550 +       if (args.len < 0)
5551 +               args.len = 0;
5552 +
5553 +       return args.len;
5554 +}
5555 +
5556 +static int bcache_compare(void *data, void *hashkey)
5557 +{
5558 +       struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5559 +       struct mipv6_bce *e = (struct mipv6_bce *) data;
5560 +
5561 +       if (ipv6_addr_cmp(&e->home_addr, p->a1) == 0
5562 +           && ipv6_addr_cmp(&e->our_addr, p->a2) == 0)
5563 +               return 0;
5564 +       else
5565 +               return -1;
5566 +}
5567 +
5568 +static __u32 bcache_hash(void *hashkey)
5569 +{
5570 +       struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5571 +
5572 +       return p->a1->s6_addr32[0] ^ p->a1->s6_addr32[1] ^
5573 +               p->a2->s6_addr32[2] ^ p->a2->s6_addr32[3];
5574 +}
5575 +
5576 +/* 
5577 + * Initialization and shutdown functions
5578 + */
5579 +
5580 +int __init mipv6_bcache_init(__u32 size)
5581 +{
5582 +       if (size < 1) {
5583 +               DEBUG(DBG_ERROR, "Binding cache size must be at least 1");
5584 +               return -EINVAL;
5585 +       }
5586 +       bcache.entries = hashlist_create(MIPV6_BCACHE_HASHSIZE, size,
5587 +                                        sizeof(struct mipv6_bce),
5588 +                                        "mip6_bcache", NULL, NULL,
5589 +                                        bcache_compare, bcache_hash);
5590 +
5591 +       if (bcache.entries == NULL) {
5592 +               DEBUG(DBG_ERROR, "Failed to initialize hashlist");
5593 +               return -ENOMEM;
5594 +       }
5595 +
5596 +       init_timer(&bcache.callback_timer);
5597 +       bcache.callback_timer.data = 0;
5598 +       bcache.callback_timer.function = timer_handler;
5599 +       bcache.size = size;
5600 +
5601 +       proc_net_create("mip6_bcache", 0, bcache_proc_info);
5602 +
5603 +       DEBUG(DBG_INFO, "Binding cache initialized");
5604 +       return 0;
5605 +}
5606 +
5607 +static int 
5608 +bce_cleanup_iterator(void *rawentry, void *args, unsigned long *sortkey)
5609 +{
5610 +       int type = (int) args;
5611 +       struct mipv6_bce *entry = (struct mipv6_bce *) rawentry;
5612 +       if (entry->type == type) {
5613 +               if (entry->type & HOME_REGISTRATION) {
5614 +                       if (unlikely(mip6_fn.proxy_del == NULL))
5615 +                               DEBUG(DBG_ERROR, "proxy_del unitialized");
5616 +                       else
5617 +                               mip6_fn.proxy_del(&entry->home_addr, entry);
5618 +               }
5619 +               return ITERATOR_DELETE_ENTRY;
5620 +       }
5621 +       return ITERATOR_CONT;
5622 +
5623 +}
5624 +
5625 +void mipv6_bcache_cleanup(int type)
5626 +{
5627 +       write_lock_bh(&bcache_lock);
5628 +       hashlist_iterate(bcache.entries,(void *) type, bce_cleanup_iterator);
5629 +       write_unlock_bh(&bcache_lock);
5630 +}
5631 +
5632 +int __exit mipv6_bcache_exit(void)
5633 +{
5634 +       struct hashlist *entries;
5635 +
5636 +       DEBUG_FUNC();
5637 +
5638 +       proc_net_remove("mip6_bcache");
5639 +
5640 +       write_lock_bh(&bcache_lock);
5641 +       DEBUG(DBG_INFO, "Stopping the bcache timer");
5642 +       del_timer(&bcache.callback_timer);
5643 +       hashlist_iterate(bcache.entries,(void *)CACHE_ENTRY, 
5644 +                        bce_cleanup_iterator);
5645 +
5646 +       entries = bcache.entries;
5647 +       bcache.entries = NULL;
5648 +       write_unlock_bh(&bcache_lock);
5649 +
5650 +       hashlist_destroy(entries);
5651 +       return 0;
5652 +}
5653 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.h linux-2.4.25/net/ipv6/mobile_ip6/bcache.h
5654 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.h       1970-01-01 01:00:00.000000000 +0100
5655 +++ linux-2.4.25/net/ipv6/mobile_ip6/bcache.h   2004-06-26 11:29:30.000000000 +0100
5656 @@ -0,0 +1,72 @@
5657 +/*
5658 + *      MIPL Mobile IPv6 Binding Cache header file
5659 + *
5660 + *      $Id$
5661 + *
5662 + *      This program is free software; you can redistribute it and/or
5663 + *      modify it under the terms of the GNU General Public License
5664 + *      as published by the Free Software Foundation; either version
5665 + *      2 of the License, or (at your option) any later version.
5666 + */
5667 +
5668 +#ifndef _BCACHE_H
5669 +#define _BCACHE_H
5670 +
5671 +#include <linux/in6.h>
5672 +#include <linux/timer.h>
5673 +#include "hashlist.h"
5674 +
5675 +#define CACHE_ENTRY 1 /* this and HOME_REGISTRATION are the entry types */
5676 +#define HOME_REGISTRATION 2
5677 +#define ANY_ENTRY 3
5678 +
5679 +#define MIPV6_MAX_DESTUNREACH 5 /* Delete CN BCEs after 5 destination unreachables */
5680 +#define MIPV6_DEST_UNR_IVAL  10 /* What is the max interval of destination  
5681 +                                  unreacahable error messages for them to be persistent*/
5682 +
5683 +struct mipv6_bce {
5684 +       struct hashlist_entry e;
5685 +       int ifindex;                            /* Interface identifier */
5686 +       struct in6_addr our_addr;               /* our address (as seen by the MN) */
5687 +       struct in6_addr home_addr;              /* MN home address */
5688 +       struct in6_addr coa;                    /* MN care-of address */
5689 +       unsigned long callback_time;            /* time of expiration     (in jiffies) */
5690 +       unsigned long br_callback_time;         /* time for sending a BR  (in jiffies) */
5691 +       int (*callback_function)(struct mipv6_bce *entry);
5692 +       __u8 type;                              /* home registration */
5693 +       __u8 router;                            /* mn is router */
5694 +       __u8 flags;                             /* flags received in BU */
5695 +       __u16 seq;                              /* sequence number */
5696 +       unsigned long last_br;                  /* time when last BR sent */
5697 +       unsigned long last_destunr;             /* time when last ICMP destination unreachable received */
5698 +       int br_count;                           /* How many BRRs have sent */
5699 +       int destunr_count;                      /* Number of destination unreachables received */   
5700 +};
5701 +
5702 +int mipv6_bcache_add(int ifindex, struct in6_addr *our_addr, 
5703 +                    struct in6_addr *home_addr, struct in6_addr *coa,
5704 +                    __u32 lifetime, __u16 seq, __u8 flags, __u8 type);
5705 +
5706 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5707 +                         struct in6_addr *our_addr, 
5708 +                         int destunr_count);
5709 +
5710 +int mipv6_bcache_delete(struct in6_addr *home_addr, struct in6_addr *our_addr,
5711 +                       __u8 type);
5712 +
5713 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5714 +                       struct in6_addr *our_addr);
5715 +
5716 +int mipv6_bcache_get(struct in6_addr *home_addr,
5717 +                    struct in6_addr *our_addr,
5718 +                    struct mipv6_bce *entry);
5719 +
5720 +int mipv6_bcache_iterate(int (*func)(void *, void *, unsigned long *), void *args);
5721 +
5722 +void mipv6_bcache_cleanup(int type);
5723 +
5724 +int mipv6_bcache_init(__u32 size);
5725 +
5726 +int mipv6_bcache_exit(void);
5727 +
5728 +#endif /* _BCACHE_H */
5729 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bul.c linux-2.4.25/net/ipv6/mobile_ip6/bul.c
5730 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bul.c  1970-01-01 01:00:00.000000000 +0100
5731 +++ linux-2.4.25/net/ipv6/mobile_ip6/bul.c      2004-06-26 11:29:30.000000000 +0100
5732 @@ -0,0 +1,634 @@
5733 +/*
5734 + *      Binding update list
5735 + *
5736 + *      Authors:
5737 + *      Juha Mynttinen            <jmynttin@cc.hut.fi>
5738 + *
5739 + *      $Id$
5740 + *
5741 + *      This program is free software; you can redistribute it and/or
5742 + *      modify it under the terms of the GNU General Public License
5743 + *      as published by the Free Software Foundation; either version
5744 + *      2 of the License, or (at your option) any later version.
5745 + */
5746 +
5747 +/*
5748 + *     Changes:
5749 + *
5750 + *     Nanno Langstraat        :       Timer code cleaned up
5751 + */
5752 +
5753 +#include <linux/autoconf.h>
5754 +#include <linux/sched.h>
5755 +#include <linux/timer.h>
5756 +#include <linux/in6.h>
5757 +#include <linux/init.h>
5758 +#include <linux/spinlock.h>
5759 +#include <net/ipv6.h>
5760 +#include <net/mipv6.h>
5761 +#include <linux/proc_fs.h>
5762 +
5763 +#include "bul.h"
5764 +#include "debug.h"
5765 +#include "hashlist.h"
5766 +#include "tunnel_mn.h"
5767 +#include "mobhdr.h"
5768 +
5769 +#define MIPV6_BUL_HASHSIZE 32
5770 +
5771 +rwlock_t bul_lock = RW_LOCK_UNLOCKED;
5772 +
5773 +struct mipv6_bul {
5774 +       struct hashlist *entries;
5775 +       struct timer_list callback_timer;
5776 +};
5777 +
5778 +static struct mipv6_bul bul;
5779 +
5780 +struct in6_addr_pair {
5781 +       struct in6_addr *a1;
5782 +       struct in6_addr *a2;
5783 +};
5784 +
5785 +/**********************************************************************
5786 + *
5787 + * Private functions
5788 + *
5789 + **********************************************************************/
5790 +
5791 +static int bul_compare(void *data, void *hashkey)
5792 +{
5793 +       struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5794 +       struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5795 +
5796 +       if (ipv6_addr_cmp(&e->cn_addr, p->a1) == 0
5797 +           && ipv6_addr_cmp(&e->home_addr, p->a2) == 0)
5798 +               return 0;
5799 +       else
5800 +               return -1;
5801 +}
5802 +
5803 +struct test_keys {
5804 +       struct in6_addr *addr;
5805 +       u8 *cookie;
5806 +};
5807 +
5808 +static int bul_compare_cookie(void *data, void *keys)
5809 +{
5810 +       struct test_keys *p = (struct test_keys *)keys;
5811 +       struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5812 +
5813 +       if (ipv6_addr_cmp(&e->cn_addr, p->addr) == 0 && e->rr
5814 +           && memcmp(&e->rr->cot_cookie, p->cookie, 8) == 0)
5815 +               return 0;
5816 +       else
5817 +               return -1;
5818 +}
5819 +
5820 +static u32 bul_hash(void *hashkey)
5821 +{
5822 +       struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5823 +       
5824 +       return p->a1->s6_addr32[0] ^
5825 +               p->a1->s6_addr32[1] ^
5826 +               p->a1->s6_addr32[2] ^
5827 +               p->a1->s6_addr32[3];
5828 +}
5829 +
5830 +static int bul_proc_info(char *buffer, char **start, off_t offset,
5831 +                           int length);
5832 +
5833 +static struct mipv6_bul_entry *mipv6_bul_get_entry(void)
5834 +{
5835 +       DEBUG_FUNC();
5836 +       return ((struct mipv6_bul_entry *) 
5837 +               hashlist_alloc(bul.entries, SLAB_ATOMIC));
5838 +}
5839 +
5840 +static void mipv6_bul_entry_free(struct mipv6_bul_entry *entry)
5841 +{
5842 +       DEBUG_FUNC();           
5843 +
5844 +       if (entry->rr) {
5845 +               if (entry->rr->kbu)
5846 +                       kfree(entry->rr->kbu);
5847 +               kfree(entry->rr);
5848 +       }
5849 +       if (entry->ops)
5850 +               kfree(entry->ops);
5851 +       hashlist_free(bul.entries, (void *)entry);
5852 +}
5853 +
5854 +static __inline__ int del_bul_entry_tnl(struct mipv6_bul_entry *entry) 
5855 +{
5856 +       if (entry->flags & MIPV6_BU_F_HOME) {
5857 +               return mipv6_mv_tnl_to_ha(&entry->cn_addr, 
5858 +                                          &entry->coa,
5859 +                                          &entry->home_addr);
5860 +       }
5861 +       return 0;
5862 +}
5863 +
5864 +static void timer_update(void)
5865 +{
5866 +       struct mipv6_bul_entry *entry;
5867 +
5868 +       DEBUG_FUNC();
5869 +
5870 +       entry = hashlist_get_first(bul.entries);
5871 +
5872 +       while (entry && time_after_eq(jiffies, entry->callback_time)) {
5873 +               if (time_after_eq(jiffies, entry->expire) ||
5874 +                   entry->callback(entry) != 0) {
5875 +                       /*
5876 +                        * Either the entry has expired, or the callback
5877 +                        * indicated that it should be deleted.
5878 +                        */
5879 +                       hashlist_delete(bul.entries, (void *)entry);
5880 +                       
5881 +                       del_bul_entry_tnl(entry);
5882 +                       mipv6_bul_entry_free(entry);
5883 +                       DEBUG(DBG_INFO, "Entry deleted (was expired) from "
5884 +                             "binding update list");
5885 +               } else {
5886 +                       /* move entry to its right place in the hashlist */
5887 +                       DEBUG(DBG_INFO, "Rescheduling");
5888 +                       hashlist_reposition(bul.entries, (void *)entry,
5889 +                                           entry->callback_time);
5890 +               }
5891 +               entry = (struct mipv6_bul_entry *)
5892 +                       hashlist_get_first(bul.entries);
5893 +       }
5894 +
5895 +       if (entry == NULL) {
5896 +               DEBUG(DBG_INFO, "bul empty, not setting a new timer");
5897 +               del_timer(&bul.callback_timer);
5898 +       } else {
5899 +               mod_timer(&bul.callback_timer, entry->callback_time);
5900 +       }
5901 +}
5902 +
5903 +static void timer_handler(unsigned long dummy)
5904 +{
5905 +       DEBUG_FUNC();
5906 +
5907 +       write_lock(&bul_lock);
5908 +       timer_update();
5909 +       write_unlock(&bul_lock);
5910 +}
5911 +
5912 +/**********************************************************************
5913 + *
5914 + * Public interface functions
5915 + *
5916 + **********************************************************************/
5917 +
5918 +/**
5919 + * mipv6_bul_iterate - apply interator function to all entries
5920 + * @func: function to apply
5921 + * @args: extra arguments for iterator
5922 + *
5923 + * Applies @func for each entry in Binding Update List.  Extra
5924 + * arguments given in @args are also passed to the iterator function.
5925 + * Caller must hold @bul_lock.
5926 + **/
5927 +int mipv6_bul_iterate(hashlist_iterator_t func, void *args)
5928 +{
5929 +       DEBUG_FUNC();
5930 +
5931 +       return hashlist_iterate(bul.entries, args, func);
5932 +}
5933 +
5934 +/**
5935 + * mipv6_bul_exists - check if Binding Update List entry exists
5936 + * @cn: address to check
5937 + *
5938 + * Checks if Binding Update List has an entry for @cn.  Returns true
5939 + * if entry exists, false otherwise. Caller may not hold @bul_lock.
5940 + **/
5941 +int mipv6_bul_exists(struct in6_addr *cn, struct in6_addr *haddr)
5942 +{
5943 +       int exists;
5944 +       struct in6_addr_pair hashkey;
5945 +
5946 +       DEBUG_FUNC();
5947 +
5948 +       hashkey.a1 = cn;
5949 +       hashkey.a2 = haddr;
5950 +       
5951 +       read_lock_bh(&bul_lock);
5952 +
5953 +       if (unlikely(bul.entries == NULL))
5954 +               exists = 0;
5955 +       else
5956 +               exists = (hashlist_get(bul.entries, &hashkey) != NULL);
5957 +
5958 +       read_unlock_bh(&bul_lock);
5959 +       return exists;
5960 +}
5961 +
5962 +/**
5963 + * mipv6_bul_get - get Binding Update List entry
5964 + * @cn_addr: CN address to search
5965 + * @home_addr: home address to search
5966 + *
5967 + * Returns Binding Update List entry for @cn_addr if it exists.
5968 + * Otherwise returns %NULL.  Caller must hold @bul_lock.
5969 + **/
5970 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cn_addr, 
5971 +                                     struct in6_addr *home_addr)
5972 +{
5973 +       struct mipv6_bul_entry *entry;
5974 +       struct in6_addr_pair hashkey;
5975 +       
5976 +       DEBUG_FUNC();
5977 +
5978 +       if (unlikely(bul.entries == NULL)) {
5979 +               return NULL;
5980 +       }
5981 +       hashkey.a1 = cn_addr;
5982 +       hashkey.a2 = home_addr;
5983 +
5984 +       entry = (struct mipv6_bul_entry *) 
5985 +               hashlist_get(bul.entries, &hashkey);
5986 +               
5987 +       return entry;
5988 +}
5989 +
5990 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(
5991 +       struct in6_addr *cn_addr, u8 *cookie)
5992 +{
5993 +       struct test_keys key;
5994 +
5995 +       DEBUG_FUNC();
5996 +
5997 +       if (unlikely(bul.entries == NULL))
5998 +               return NULL;
5999 +       key.addr = cn_addr;
6000 +       key.cookie = cookie;
6001 +
6002 +       return (struct mipv6_bul_entry *) 
6003 +               hashlist_get_ex(bul.entries, &key,
6004 +                               bul_compare_cookie);
6005 +}
6006 +
6007 +/**
6008 + * mipv6_bul_reschedule - reschedule Binding Update List entry
6009 + * @entry: entry to reschedule
6010 + *
6011 + * Reschedules a Binding Update List entry.  Must be called after
6012 + * modifying entry lifetime.  Caller must hold @bul_lock (write).
6013 + **/
6014 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry)
6015 +{
6016 +       DEBUG_FUNC();
6017 +
6018 +       hashlist_reposition(bul.entries,
6019 +                           (void *)entry,
6020 +                           entry->callback_time);
6021 +       timer_update();
6022 +}
6023 +
6024 +/**
6025 + * mipv6_bul_add - add binding update to Binding Update List
6026 + * @cn_addr: IPv6 address where BU was sent
6027 + * @home_addr: Home address for this binding
6028 + * @coa: Care-of address for this binding
6029 + * @lifetime: expiration time of the binding in seconds
6030 + * @seq: sequence number of the BU
6031 + * @flags: %MIPV6_BU_F_* flags
6032 + * @callback: callback function called on expiration
6033 + * @callback_time: expiration time for callback
6034 + * @state: binding send state
6035 + * @delay: retransmission delay
6036 + * @maxdelay: retransmission maximum delay
6037 + * @ops: Mobility header options for BU
6038 + * @rr: Return routability information
6039 + *
6040 + * Adds a binding update sent to @cn_addr for @home_addr to the
6041 + * Binding Update List.  If entry already exists, it is updated.
6042 + * Entry is set to expire in @lifetime seconds.  Entry has a callback
6043 + * function @callback that is called at @callback_time.  Entry @state
6044 + * controls resending of this binding update and it can be set to
6045 + * %ACK_OK, %RESEND_EXP or %ACK_ERROR.  Returns a pointer to the newly
6046 + * created or updated entry.  Caller must hold @bul_lock (write).
6047 + **/
6048 +struct mipv6_bul_entry *mipv6_bul_add(
6049 +       struct in6_addr *cn_addr, struct in6_addr *home_addr,
6050 +       struct in6_addr *coa, 
6051 +       __u32 lifetime, __u16 seq, __u8 flags,
6052 +       int (*callback)(struct mipv6_bul_entry *entry),
6053 +       __u32 callback_time, 
6054 +       __u8 state, __u32 delay, __u32 maxdelay,
6055 +       struct mipv6_mh_opt *ops, 
6056 +       struct mipv6_rr_info *rr)
6057 +{
6058 +       struct mipv6_bul_entry *entry;
6059 +       int update = 0;
6060 +       struct in6_addr_pair hashkey;
6061 +
6062 +       DEBUG_FUNC();
6063 +
6064 +       if (unlikely(bul.entries == NULL))
6065 +               return NULL;
6066 +
6067 +       if (cn_addr == NULL || home_addr == NULL || coa == NULL || 
6068 +           lifetime < 0 || callback == NULL || callback_time < 0 || 
6069 +           (state != ACK_OK && state != RESEND_EXP && state != ACK_ERROR) ||
6070 +           delay < 0 || maxdelay < 0) {
6071 +               DEBUG(DBG_ERROR, "invalid arguments");
6072 +               return NULL;
6073 +       }
6074 +       DEBUG(DBG_INFO, "cn_addr: %x:%x:%x:%x:%x:%x:%x:%x, "
6075 +             "home_addr: %x:%x:%x:%x:%x:%x:%x:%x"
6076 +             "coaddr: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(cn_addr), 
6077 +              NIPV6ADDR(home_addr), NIPV6ADDR(coa));
6078 +       hashkey.a1 = cn_addr;
6079 +       hashkey.a2 = home_addr;
6080 +       
6081 +       /* 
6082 +        * decide whether to add a new entry or update existing, also
6083 +        * check if there's room for a new entry when adding a new
6084 +        * entry (latter is handled by mipv6_bul_get_entry() 
6085 +        */
6086 +       if ((entry = (struct mipv6_bul_entry *)
6087 +            hashlist_get(bul.entries, &hashkey)) != NULL) {
6088 +               /* if an entry for this cn_addr exists (with smaller
6089 +                * seq than the new entry's seq), update it */
6090 +               
6091 +               if (MIPV6_SEQ_GT(seq, entry->seq)) {
6092 +                       DEBUG(DBG_INFO, "updating an existing entry");
6093 +                       update = 1;
6094 +               } else {
6095 +                       DEBUG(DBG_INFO, "smaller seq than existing, not updating");
6096 +                       return NULL;
6097 +               }
6098 +       } else {
6099 +               entry = mipv6_bul_get_entry();
6100 +               if (entry == NULL) {
6101 +                       DEBUG(DBG_WARNING, "binding update list full, can't add!!!");
6102 +                       return NULL;
6103 +               }
6104 +               memset(entry, 0, sizeof(*entry));
6105 +               /* First BU send happens here, save count in the entry */
6106 +               entry->consecutive_sends = 1;
6107 +       }
6108 +
6109 +       if (!update) {
6110 +               ipv6_addr_copy(&(entry->cn_addr), cn_addr);
6111 +               ipv6_addr_copy(&(entry->home_addr), home_addr);
6112 +               entry->ops = ops;
6113 +       }
6114 +       /* Add Return Routability info to bul entry */
6115 +       if (rr) {
6116 +               if(entry->rr)
6117 +                       kfree(entry->rr); 
6118 +               entry->rr = rr;
6119 +       }
6120 +
6121 +       ipv6_addr_copy(&(entry->coa), coa);
6122 +       entry->lifetime = lifetime;
6123 +       if (lifetime)
6124 +               entry->expire = jiffies + lifetime * HZ;
6125 +       else if (flags & MIPV6_BU_F_ACK)
6126 +               entry->expire = jiffies + HOME_RESEND_EXPIRE * HZ;
6127 +       entry->seq = seq;
6128 +       entry->flags = flags;
6129 +       entry->lastsend = jiffies; /* current time = last use of the entry */
6130 +       entry->state = state;
6131 +       entry->delay = delay;
6132 +       entry->maxdelay = maxdelay;
6133 +       entry->callback_time = jiffies + callback_time * HZ;
6134 +       entry->callback = callback;
6135 +
6136 +       if (flags & MIPV6_BU_F_HOME && 
6137 +           mipv6_mv_tnl_to_ha(cn_addr, coa, home_addr)) {
6138 +               DEBUG(DBG_ERROR, "reconfiguration of the tunnel failed");
6139 +       }
6140 +       if (update) {
6141 +               DEBUG(DBG_INFO, "updating entry: %x", entry);
6142 +               hashlist_reposition(bul.entries, (void *)entry,
6143 +                                   entry->callback_time);
6144 +       } else {
6145 +               DEBUG(DBG_INFO, "adding entry: %x", entry);
6146 +
6147 +               hashkey.a1 = &entry->cn_addr;
6148 +               hashkey.a2 = &entry->home_addr;
6149 +
6150 +               if ((hashlist_add(bul.entries, &hashkey,
6151 +                                 entry->callback_time,
6152 +                                 entry)) < 0) {
6153 +                       DEBUG(DBG_ERROR, "Hash add failed");
6154 +                       mipv6_bul_entry_free(entry);                    
6155 +                       return NULL;
6156 +               }
6157 +       }
6158 +       timer_update(); 
6159 +
6160 +       return entry;
6161 +}
6162 +
6163 +/**
6164 + * mipv6_bul_delete - delete Binding Update List entry
6165 + * @cn_addr: address for entry to delete
6166 + *
6167 + * Deletes the entry for @cn_addr from the Binding Update List.
6168 + * Returns zero if entry was deleted succesfully, otherwise returns
6169 + * negative.  Caller may not hold @bul_lock.
6170 + **/
6171 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr)
6172 +{
6173 +       struct mipv6_bul_entry *entry;
6174 +       struct in6_addr_pair hashkey;
6175 +
6176 +       DEBUG_FUNC();
6177 +
6178 +       hashkey.a1 = cn_addr;
6179 +       hashkey.a2 = home_addr;
6180 +
6181 +       write_lock(&bul_lock);
6182 +
6183 +       if (unlikely(bul.entries == NULL) ||  
6184 +           (entry = (struct mipv6_bul_entry *)
6185 +            hashlist_get(bul.entries, &hashkey)) == NULL) {
6186 +               write_unlock(&bul_lock);
6187 +               DEBUG(DBG_INFO, "No such entry");
6188 +               return -ENOENT;
6189 +       }
6190 +
6191 +       hashlist_delete(bul.entries, (void *)entry);
6192 +
6193 +       del_bul_entry_tnl(entry);
6194 +
6195 +       mipv6_bul_entry_free(entry);
6196 +       timer_update();
6197 +       write_unlock(&bul_lock);
6198 +
6199 +       DEBUG(DBG_INFO, "Binding update list entry deleted");
6200 +
6201 +       return 0;
6202 +}
6203 +
6204 +/**********************************************************************
6205 + *
6206 + * Proc interface functions
6207 + *
6208 + **********************************************************************/
6209 +
6210 +#define BUL_INFO_LEN 152
6211 +
6212 +struct procinfo_iterator_args {
6213 +       char *buffer;
6214 +       int offset;
6215 +       int length;
6216 +       int skip;
6217 +       int len;
6218 +};
6219 +
6220 +static int procinfo_iterator(void *data, void *args,
6221 +                            unsigned long *sortkey)
6222 +{
6223 +       struct procinfo_iterator_args *arg =
6224 +               (struct procinfo_iterator_args *)args;
6225 +       struct mipv6_bul_entry *entry =
6226 +               (struct mipv6_bul_entry *)data;
6227 +       unsigned long callback_seconds;
6228 +
6229 +       DEBUG_FUNC();
6230 +
6231 +       if (entry == NULL) return ITERATOR_ERR;
6232 +
6233 +       if (time_after(jiffies, entry->callback_time))
6234 +               callback_seconds = 0;
6235 +       else
6236 +               callback_seconds = (entry->callback_time - jiffies) / HZ;
6237 +
6238 +       if (arg->skip < arg->offset / BUL_INFO_LEN) {
6239 +               arg->skip++;
6240 +               return ITERATOR_CONT;
6241 +       }
6242 +
6243 +       if (arg->len >= arg->length)
6244 +               return ITERATOR_CONT;
6245 +
6246 +       /* CN HoA CoA ExpInSecs SeqNum State Delay MaxDelay CallbackInSecs */
6247 +       arg->len += sprintf(arg->buffer + arg->len,
6248 +                           "%08x%08x%08x%08x %08x%08x%08x%08x %08x%08x%08x%08x\n"
6249 +                           "%010lu %05d %02d %010d %010d %010lu\n",
6250 +                           ntohl(entry->cn_addr.s6_addr32[0]),
6251 +                           ntohl(entry->cn_addr.s6_addr32[1]),
6252 +                           ntohl(entry->cn_addr.s6_addr32[2]),
6253 +                           ntohl(entry->cn_addr.s6_addr32[3]),
6254 +                           ntohl(entry->home_addr.s6_addr32[0]),
6255 +                           ntohl(entry->home_addr.s6_addr32[1]),
6256 +                           ntohl(entry->home_addr.s6_addr32[2]),
6257 +                           ntohl(entry->home_addr.s6_addr32[3]),
6258 +                           ntohl(entry->coa.s6_addr32[0]),
6259 +                           ntohl(entry->coa.s6_addr32[1]),
6260 +                           ntohl(entry->coa.s6_addr32[2]),
6261 +                           ntohl(entry->coa.s6_addr32[3]),
6262 +                           (entry->expire - jiffies) / HZ,
6263 +                           entry->seq, entry->state, entry->delay, 
6264 +                           entry->maxdelay, callback_seconds);
6265 +
6266 +       return ITERATOR_CONT;
6267 +}
6268 +
6269 +
6270 +/*
6271 + * Callback function for proc filesystem.
6272 + */
6273 +static int bul_proc_info(char *buffer, char **start, off_t offset,
6274 +                            int length)
6275 +{
6276 +       struct procinfo_iterator_args args;
6277 +
6278 +       DEBUG_FUNC();
6279 +
6280 +       args.buffer = buffer;
6281 +       args.offset = offset;
6282 +       args.length = length;
6283 +       args.skip = 0;
6284 +       args.len = 0;
6285 +
6286 +       read_lock_bh(&bul_lock);
6287 +       hashlist_iterate(bul.entries, &args, procinfo_iterator);
6288 +       read_unlock_bh(&bul_lock);
6289 +
6290 +       *start = buffer;
6291 +       if (offset)
6292 +               *start += offset % BUL_INFO_LEN;
6293 +
6294 +       args.len -= offset % BUL_INFO_LEN;
6295 +
6296 +       if (args.len > length)
6297 +               args.len = length;
6298 +       if (args.len < 0)
6299 +               args.len = 0;
6300 +       
6301 +       return args.len;
6302 +}
6303 +
6304 +/**********************************************************************
6305 + *
6306 + * Code module init/fini functions
6307 + *
6308 + **********************************************************************/
6309 +
6310 +int __init mipv6_bul_init(__u32 size)
6311 +{
6312 +       DEBUG_FUNC();
6313 +
6314 +       if (size < 1) {
6315 +               DEBUG(DBG_CRITICAL, 
6316 +                     "Binding update list size must be at least 1");
6317 +               return -EINVAL;
6318 +       }
6319 +       bul.entries = hashlist_create(MIPV6_BUL_HASHSIZE, size, 
6320 +                                      sizeof(struct mipv6_bul_entry),
6321 +                                      "mip6_bul", NULL, NULL,
6322 +                                      bul_compare, bul_hash);
6323 +
6324 +       if (bul.entries == NULL) {
6325 +               DEBUG(DBG_CRITICAL, "Couldn't allocate memory for "
6326 +                     "hashlist when creating a binding update list");
6327 +               return -ENOMEM;
6328 +       }
6329 +       init_timer(&bul.callback_timer);
6330 +       bul.callback_timer.data = 0;
6331 +       bul.callback_timer.function = timer_handler;
6332 +       proc_net_create("mip6_bul", 0, bul_proc_info);
6333 +       DEBUG(DBG_INFO, "Binding update list initialized");
6334 +       return 0;
6335 +}
6336 +
6337 +void __exit mipv6_bul_exit()
6338 +{
6339 +       struct mipv6_bul_entry *entry;
6340 +       struct hashlist *entries;
6341 +
6342 +       DEBUG_FUNC();
6343 +
6344 +       proc_net_remove("mip6_bul");
6345 +
6346 +       write_lock_bh(&bul_lock);
6347 +
6348 +       DEBUG(DBG_INFO, "Stopping the bul timer");
6349 +       del_timer(&bul.callback_timer);
6350 +
6351 +       while ((entry = (struct mipv6_bul_entry *) 
6352 +               hashlist_get_first(bul.entries)) != NULL) {
6353 +               hashlist_delete(bul.entries, (void *)entry);
6354 +               
6355 +               del_bul_entry_tnl(entry);
6356 +               
6357 +               mipv6_bul_entry_free(entry);
6358 +       }
6359 +       entries = bul.entries;
6360 +       bul.entries = NULL;
6361 +       write_unlock_bh(&bul_lock); 
6362 +
6363 +       hashlist_destroy(entries);
6364 +
6365 +       DEBUG(DBG_INFO, "binding update list destroyed");
6366 +}
6367 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bul.h linux-2.4.25/net/ipv6/mobile_ip6/bul.h
6368 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bul.h  1970-01-01 01:00:00.000000000 +0100
6369 +++ linux-2.4.25/net/ipv6/mobile_ip6/bul.h      2004-06-26 11:29:30.000000000 +0100
6370 @@ -0,0 +1,91 @@
6371 +/*
6372 + *      MIPL Mobile IPv6 Binding Update List header file
6373 + *
6374 + *      $Id$
6375 + *
6376 + *      This program is free software; you can redistribute it and/or
6377 + *      modify it under the terms of the GNU General Public License
6378 + *      as published by the Free Software Foundation; either version
6379 + *      2 of the License, or (at your option) any later version.
6380 + */
6381 +
6382 +#ifndef _BUL_H
6383 +#define _BUL_H
6384 +
6385 +#include "hashlist.h"
6386 +
6387 +#define ACK_OK          0x01
6388 +#define RESEND_EXP      0x02
6389 +#define ACK_ERROR       0x04
6390 +
6391 +#define HOME_RESEND_EXPIRE 3600
6392 +#define MIPV6_COOKIE_LEN 8
6393 +struct mipv6_rr_info {
6394 +       /* RR information */
6395 +       u16 rr_state;                /* State of the RR */
6396 +       u16 rr_flags;                /* Flags for the RR */
6397 +       u8 hot_cookie[MIPV6_COOKIE_LEN];    /* HoT Cookie */
6398 +       u8 cot_cookie[MIPV6_COOKIE_LEN];    /* CoT Cookie */
6399 +       u8 home_cookie[MIPV6_COOKIE_LEN];   /* Home Cookie */
6400 +       u8 careof_cookie[MIPV6_COOKIE_LEN]; /* Careof Cookie */
6401 +       u32 lastsend_hoti;            /* When HoTI was last sent (jiffies) */
6402 +       u32 lastsend_coti;            /* When CoTI was last sent (jiffies) */
6403 +       u32 home_time;                /* when Care-of cookie was received */
6404 +       u32 careof_time;              /* when Home cookie was received */
6405 +       int home_nonce_index;         /* Home cookie nonce index */
6406 +       int careof_nonce_index;       /* Care-of cookie nonce index */
6407 +       u8 *kbu;                      /* Binding authentication key */
6408 +};
6409 +struct mipv6_bul_entry {
6410 +       struct hashlist_entry e;
6411 +       struct in6_addr cn_addr;        /* CN to which BU was sent */
6412 +       struct in6_addr home_addr;      /* home address of this binding */
6413 +       struct in6_addr coa;            /* care-of address of the sent BU */
6414 +
6415 +       unsigned long expire;           /* entry's expiration time (jiffies) */ 
6416 +       __u32 lifetime;                 /* lifetime sent in this BU */
6417 +       __u32 lastsend;                 /* last time when BU sent (jiffies) */
6418 +       __u32 consecutive_sends;        /* Number of consecutive BU's sent */
6419 +       __u16 seq;                      /* sequence number of the latest BU */
6420 +       __u8 flags;                     /* BU send flags */
6421 +       __u8 state;                     /* resend state */
6422 +       __u32 initdelay;                /* initial ack wait */
6423 +       __u32 delay;                    /* current ack wait */
6424 +       __u32 maxdelay;                 /* maximum ack wait */
6425 +
6426 +       struct mipv6_rr_info *rr;
6427 +       struct mipv6_mh_opt *ops;       /* saved option values */
6428 +
6429 +       unsigned long callback_time;
6430 +       int (*callback)(struct mipv6_bul_entry *entry);
6431 +};
6432 +
6433 +extern rwlock_t bul_lock;
6434 +
6435 +int mipv6_bul_init(__u32 size);
6436 +
6437 +void mipv6_bul_exit(void);
6438 +
6439 +struct mipv6_bul_entry *mipv6_bul_add(
6440 +       struct in6_addr *cn_addr, struct in6_addr *home_addr,
6441 +       struct in6_addr *coa, __u32 lifetime, __u16 seq, __u8 flags,
6442 +       int (*callback)(struct mipv6_bul_entry *entry), __u32 callback_time,
6443 +       __u8 state, __u32 delay, __u32 maxdelay, struct mipv6_mh_opt *ops,
6444 +       struct mipv6_rr_info *rr);
6445 +
6446 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr);
6447 +
6448 +int mipv6_bul_exists(struct in6_addr *cnaddr, struct in6_addr *home_addr);
6449 +
6450 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cnaddr,
6451 +                                     struct in6_addr *home_addr);
6452 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(struct in6_addr *cn_addr,
6453 +                                                u8 *cookie);
6454 +
6455 +int bul_entry_expired(struct mipv6_bul_entry *bulentry);
6456 +
6457 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry);
6458 +
6459 +int mipv6_bul_iterate(int (*func)(void *, void *, unsigned long *), void *args);
6460 +
6461 +#endif /* BUL_H */
6462 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/config.h linux-2.4.25/net/ipv6/mobile_ip6/config.h
6463 --- linux-2.4.25.old/net/ipv6/mobile_ip6/config.h       1970-01-01 01:00:00.000000000 +0100
6464 +++ linux-2.4.25/net/ipv6/mobile_ip6/config.h   2004-06-26 11:29:30.000000000 +0100
6465 @@ -0,0 +1,72 @@
6466 +/*
6467 + * Configuration parameters
6468 + *
6469 + * $Id$
6470 + */
6471 +
6472 +#define MIPV6VERSION "D24"
6473 +#define MIPLVERSION "v1.0"
6474 +
6475 +#define CAP_CN 0x01
6476 +#define CAP_HA 0x02
6477 +#define CAP_MN 0x04
6478 +
6479 +struct mip6_conf {
6480 +       int capabilities;
6481 +       int debug_level;
6482 +       int accept_ret_rout;
6483 +       int max_rtr_reachable_time;
6484 +       int eager_cell_switching;
6485 +       int max_num_tunnels;
6486 +       int min_num_tunnels;
6487 +       int binding_refresh_advice;
6488 +       int bu_lladdr;
6489 +       int bu_keymgm;
6490 +       int bu_cn_ack;
6491 +};
6492 +
6493 +extern struct mip6_conf mip6node_cnf;
6494 +
6495 +struct mipv6_bce;
6496 +
6497 +struct mip6_func {
6498 +       void (*bce_home_add) (int ifindex, struct in6_addr *daddr, 
6499 +                             struct in6_addr *haddr, struct in6_addr *coa,
6500 +                             struct in6_addr *rep_coa, __u32 lifetime, 
6501 +                             __u16 sequence, __u8 flags, __u8 *k_bu);
6502 +       void (*bce_cache_add) (int ifindex, struct in6_addr *daddr,
6503 +                              struct in6_addr *haddr, struct in6_addr *coa,
6504 +                              struct in6_addr *rep_coa, __u32 lifetime,
6505 +                              __u16 sequence, __u8 flags, __u8 *k_bu);
6506 +       void (*bce_home_del) (struct in6_addr *daddr, struct in6_addr *haddr, 
6507 +                             struct in6_addr *coa, struct in6_addr *rep_coa,
6508 +                             __u16 sequence, __u8 flags,
6509 +                             __u8 *k_bu);
6510 +       void (*bce_cache_del) (struct in6_addr *daddr, struct in6_addr *haddr, 
6511 +                              struct in6_addr *coa, struct in6_addr *rep_coa,
6512 +                              __u16 sequence, __u8 flags,
6513 +                              __u8 *k_bu);
6514 +       
6515 +       int (*bce_tnl_rt_add) (struct in6_addr *coa, 
6516 +                              struct in6_addr *ha_addr, 
6517 +                              struct in6_addr *home_addr);
6518 +
6519 +       void (*bce_tnl_rt_del) (struct in6_addr *coa, 
6520 +                               struct in6_addr *ha_addr, 
6521 +                               struct in6_addr *home_addr);
6522 +
6523 +       void (*proxy_del) (struct in6_addr *home_addr, struct mipv6_bce *entry);
6524 +       int (*proxy_create) (int flags, int ifindex, struct in6_addr *coa,
6525 +                            struct in6_addr *our_addr, struct in6_addr *home_addr);
6526 +
6527 +       int (*icmpv6_dhaad_rep_rcv) (struct sk_buff *skb);
6528 +       int (*icmpv6_dhaad_req_rcv) (struct sk_buff *skb);
6529 +       int (*icmpv6_pfxadv_rcv) (struct sk_buff *skb);
6530 +       int (*icmpv6_pfxsol_rcv) (struct sk_buff *skb);
6531 +       int (*icmpv6_paramprob_rcv) (struct sk_buff *skb);
6532 +
6533 +       int (*mn_use_hao) (struct in6_addr *daddr, struct in6_addr *saddr);
6534 +       void (*mn_check_tunneled_packet) (struct sk_buff *skb);
6535 +};
6536 +
6537 +extern struct mip6_func mip6_fn;
6538 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/debug.h linux-2.4.25/net/ipv6/mobile_ip6/debug.h
6539 --- linux-2.4.25.old/net/ipv6/mobile_ip6/debug.h        1970-01-01 01:00:00.000000000 +0100
6540 +++ linux-2.4.25/net/ipv6/mobile_ip6/debug.h    2004-06-26 11:29:30.000000000 +0100
6541 @@ -0,0 +1,112 @@
6542 +/*
6543 + *      MIPL Mobile IPv6 Debugging macros and functions
6544 + *
6545 + *      $Id$
6546 + *
6547 + *      This program is free software; you can redistribute it and/or
6548 + *      modify it under the terms of the GNU General Public License
6549 + *      as published by the Free Software Foundation; either version
6550 + *      2 of the License, or (at your option) any later version.
6551 + */
6552 +
6553 +#ifndef _DEBUG_H
6554 +#define _DEBUG_H
6555 +
6556 +#include <linux/autoconf.h>
6557 +
6558 +/* priorities for different debug conditions */
6559 +
6560 +#define DBG_CRITICAL   0 /* unrecoverable error                     */
6561 +#define DBG_ERROR      1 /* error (recoverable)                     */
6562 +#define DBG_WARNING    2 /* unusual situation but not a real error  */
6563 +#define DBG_INFO       3 /* generally useful information            */
6564 +#define DBG_EXTRA      4 /* extra information                       */
6565 +#define DBG_FUNC_ENTRY 6 /* use to indicate function entry and exit */
6566 +#define DBG_DATADUMP   7 /* packet dumps, etc. lots of flood        */
6567 +
6568 +/**
6569 + * NIPV6ADDR - macro for IPv6 addresses
6570 + * @addr: Network byte order IPv6 address
6571 + *
6572 + * Macro for printing IPv6 addresses.  Used in conjunction with
6573 + * printk() or derivatives (such as DEBUG macro).
6574 + **/
6575 +#define NIPV6ADDR(addr) \
6576 +        ntohs(((u16 *)addr)[0]), \
6577 +        ntohs(((u16 *)addr)[1]), \
6578 +        ntohs(((u16 *)addr)[2]), \
6579 +        ntohs(((u16 *)addr)[3]), \
6580 +        ntohs(((u16 *)addr)[4]), \
6581 +        ntohs(((u16 *)addr)[5]), \
6582 +        ntohs(((u16 *)addr)[6]), \
6583 +        ntohs(((u16 *)addr)[7])
6584 +
6585 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
6586 +extern int mipv6_debug;
6587 +
6588 +/**
6589 + * debug_print - print debug message
6590 + * @debug_level: message priority
6591 + * @fname: calling function's name
6592 + * @fmt: printf-style formatting string
6593 + *
6594 + * Prints a debug message to system log if @debug_level is less or
6595 + * equal to @mipv6_debug.  Should always be called using DEBUG()
6596 + * macro, not directly.
6597 + **/
6598 +static void debug_print(int debug_level, const char *fname, const char* fmt, ...)
6599 +{
6600 +       char s[1024];
6601 +       va_list args;
6602
6603 +       if (mipv6_debug < debug_level)
6604 +               return;
6605
6606 +       va_start(args, fmt);
6607 +       vsprintf(s, fmt, args);
6608 +       printk("mip6[%s]: %s\n", fname, s);
6609 +       va_end(args);
6610 +}
6611 +
6612 +/**
6613 + * debug_print_buffer - print arbitrary buffer to system log
6614 + * @debug_level: message priority
6615 + * @data: pointer to buffer
6616 + * @len: number of bytes to print
6617 + *
6618 + * Prints @len bytes from buffer @data to system log.  @debug_level
6619 + * tells on which debug level message gets printed.  For
6620 + * debug_print_buffer() priority %DBG_DATADUMP should be used.
6621 + **/
6622 +#define debug_print_buffer(debug_level,data,len) { \
6623 +       if (mipv6_debug >= debug_level) { \
6624 +       int i; \
6625 +       for (i=0; i<len; i++) { \
6626 +               if (i%16 == 0) printk("\n%04x: ", i); \
6627 +               printk("%02x ", ((unsigned char *)data)[i]); \
6628 +       } \
6629 +       printk("\n\n"); \
6630 +       } \
6631 +}
6632 +
6633 +#define DEBUG(x,y,z...) debug_print(x,__FUNCTION__,y,##z)
6634 +#define DEBUG_FUNC() \
6635 +DEBUG(DBG_FUNC_ENTRY, "%s(%d)/%s: ", __FILE__,__LINE__,__FUNCTION__)
6636 +
6637 +#else
6638 +#define DEBUG(x,y,z...)
6639 +#define DEBUG_FUNC()
6640 +#define debug_print_buffer(x,y,z)
6641 +#endif
6642 +
6643 +#undef ASSERT
6644 +#define ASSERT(expression) { \
6645 +        if (!(expression)) { \
6646 +                (void)printk(KERN_ERR \
6647 +                 "Assertion \"%s\" failed: file \"%s\", function \"%s\", line %d\n", \
6648 +                 #expression, __FILE__, __FUNCTION__, __LINE__); \
6649 +               BUG(); \
6650 +        } \
6651 +}
6652 +
6653 +#endif /* _DEBUG_H */
6654 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.c linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.c
6655 --- linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.c      1970-01-01 01:00:00.000000000 +0100
6656 +++ linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.c  2004-06-26 11:29:30.000000000 +0100
6657 @@ -0,0 +1,394 @@
6658 +/*
6659 + *     Extension Header handling and adding code
6660 + *
6661 + *     Authors:
6662 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>    
6663 + *
6664 + *     $Id$
6665 + *
6666 + *     This program is free software; you can redistribute it and/or
6667 + *      modify it under the terms of the GNU General Public License
6668 + *      as published by the Free Software Foundation; either version
6669 + *      2 of the License, or (at your option) any later version.
6670 + */
6671 +
6672 +#include <linux/types.h>
6673 +#include <linux/slab.h>
6674 +
6675 +#include <net/ipv6.h>
6676 +#include <net/ip6_route.h>
6677 +#include <net/addrconf.h>
6678 +#include <net/mipv6.h>
6679 +
6680 +#include "debug.h"
6681 +#include "stats.h"
6682 +#include "mobhdr.h"
6683 +#include "bcache.h"
6684 +#include "config.h"
6685 +
6686 +/**
6687 + * mipv6_append_home_addr - Add Home Address Option
6688 + * @opt: buffer for Home Address Option
6689 + * @offset: offset from beginning of @opt
6690 + * @addr: address for HAO
6691 + *
6692 + * Adds a Home Address Option to a packet.  Option is stored in
6693 + * @offset from beginning of @opt.  The option is created but the
6694 + * original source address in IPv6 header is left intact.  The source
6695 + * address will be changed from home address to CoA after the checksum
6696 + * has been calculated in getfrag.  Padding is done automatically, and
6697 + * @opt must have allocated space for both actual option and pad.
6698 + * Returns offset from @opt to end of options.
6699 + **/
6700 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr)
6701 +{
6702 +       int pad;
6703 +       struct mipv6_dstopt_homeaddr *ho;
6704 +
6705 +       DEBUG(DBG_DATADUMP, "HAO: %x:%x:%x:%x:%x:%x:%x:%x",
6706 +             NIPV6ADDR(addr));
6707 +
6708 +       pad = (6 - offset) & 7;
6709 +       mipv6_add_pad(opt + offset, pad);
6710 +
6711 +       ho = (struct mipv6_dstopt_homeaddr *)(opt + offset + pad);
6712 +       ho->type = MIPV6_TLV_HOMEADDR;
6713 +       ho->length = sizeof(*ho) - 2;
6714 +       ipv6_addr_copy(&ho->addr, addr); 
6715 +
6716 +       return offset + pad + sizeof(*ho);
6717 +}
6718 +static inline int check_hao_validity(struct mipv6_dstopt_homeaddr *haopt, 
6719 +                                    u8 *dst1, 
6720 +                                    struct in6_addr *saddr, 
6721 +                                    struct in6_addr *daddr)
6722 +{
6723 +       int addr_type = ipv6_addr_type(&haopt->addr);
6724 +       struct mipv6_bce bc_entry;
6725 +       
6726 +       if (addr_type & IPV6_ADDR_LINKLOCAL || 
6727 +           !(addr_type & IPV6_ADDR_UNICAST)) {
6728 +               DEBUG(DBG_INFO, "HAO with link local or non-unicast HoA, "
6729 +                     "not sending BE to "
6730 +                     "home address " 
6731 +                     "%x:%x:%x:%x:%x:%x:%x:%x ",
6732 +                     "care-of  address %x:%x:%x:%x:%x:%x:%x:%x",
6733 +                     NIPV6ADDR(&haopt->addr),
6734 +                     NIPV6ADDR(saddr));
6735 +               return -EINVAL;
6736 +       } else if (dst1[0] != IPPROTO_MOBILITY && 
6737 +           (mipv6_bcache_get(&haopt->addr, 
6738 +                             daddr, &bc_entry) != 0 ||
6739 +            ipv6_addr_cmp(saddr, &bc_entry.coa))) {
6740 +               DEBUG(DBG_INFO, "HAO without binding or incorrect CoA, "
6741 +                     "sending BE code 1: "
6742 +                     "home address %x:%x:%x:%x:%x:%x:%x:%x",
6743 +                     "to care-of address %x:%x:%x:%x:%x:%x:%x:%x",
6744 +                     NIPV6ADDR(&haopt->addr),
6745 +                     NIPV6ADDR(saddr));
6746 +               return -ENOENT;
6747 +       }
6748 +       return 0;
6749 +}
6750 +/**
6751 + * mipv6_handle_homeaddr - Home Address Destination Option handler
6752 + * @skb: packet buffer
6753 + * @optoff: offset to where option begins
6754 + *
6755 + * Handles Home Address Option in IPv6 Destination Option header.
6756 + * Packet and offset to option are passed.  If HAO is used without
6757 + * binding, sends a Binding Error code 1.  When sending BE, notify bit
6758 + * is cleared to prevent IPv6 error handling from sending ICMP
6759 + * Parameter Problem.  Returns 1 on success, otherwise zero.
6760 + **/
6761 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff)
6762 +{
6763 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
6764 +       struct in6_addr coaddr;
6765 +       struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
6766 +       struct mipv6_dstopt_homeaddr *haopt =
6767 +           (struct mipv6_dstopt_homeaddr *) &skb->nh.raw[optoff];
6768 +       u8 *dst1;
6769 +       int err;
6770 +
6771 +       DEBUG_FUNC();
6772 +       
6773 +       if (haopt->length != sizeof(*haopt) - 2) {
6774 +               DEBUG(DBG_WARNING, "HAO has invalid length");
6775 +               MIPV6_INC_STATS(n_ha_drop.invalid);
6776 +               return 0;
6777 +       }
6778 +       dst1 = (u8 *)skb->h.raw;
6779 +       err = check_hao_validity(haopt, dst1, saddr, &skb->nh.ipv6h->daddr);
6780 +
6781 +       if (err) {
6782 +               haopt->type &= ~(0x80); /* clear notify bit */
6783 +               if (err == -ENOENT)
6784 +                       mipv6_send_be(&skb->nh.ipv6h->daddr, saddr,
6785 +                                     &haopt->addr, MIPV6_BE_HAO_WO_BINDING);
6786 +               MIPV6_INC_STATS(n_ha_drop.misc);
6787 +               return 0;
6788 +       }
6789 +       ipv6_addr_copy(&coaddr, saddr);
6790 +       ipv6_addr_copy(saddr, &haopt->addr);
6791 +       ipv6_addr_copy(&haopt->addr, &coaddr);
6792 +       opt->hao = optoff;
6793 +       if (mip6_fn.mn_check_tunneled_packet != NULL)
6794 +               mip6_fn.mn_check_tunneled_packet(skb);
6795 +
6796 +       MIPV6_INC_STATS(n_ha_rcvd);
6797 +       return 1;
6798 +}
6799 +
6800 +/**
6801 + * mipv6_icmp_swap_addrs - Switch HAO and src and RT2 and dest for ICMP errors
6802 + * @skb: packet buffer
6803 + *
6804 + * Reset the source address and the Home Address option in skb before
6805 + * appending it to an ICMP error message, so original packet appears
6806 + * in the error message rather than mangled.
6807 + **/
6808 +void mipv6_icmp_swap_addrs(struct sk_buff *skb)
6809 +{
6810 +       struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
6811 +       struct in6_addr tmp;
6812 +       struct in6_addr *hoa;
6813 +       DEBUG_FUNC();
6814 +       if (opt->srcrt2) {
6815 +               struct rt2_hdr *rt2;
6816 +               rt2 = (struct rt2_hdr *)(skb->nh.raw + opt->srcrt2);
6817 +               hoa = &rt2->addr;
6818 +
6819 +               ipv6_addr_copy(&tmp, hoa);
6820 +               ipv6_addr_copy(hoa, &skb->nh.ipv6h->daddr);
6821 +               ipv6_addr_copy(&skb->nh.ipv6h->daddr, &tmp);
6822 +               rt2->rt_hdr.segments_left++;
6823 +               skb->nh.ipv6h->hop_limit++;
6824 +       }
6825 +       if (opt->hao) {
6826 +               struct mipv6_dstopt_homeaddr *hao;
6827 +               hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
6828 +               hoa = &hao->addr;
6829 +
6830 +               ipv6_addr_copy(&tmp, hoa);
6831 +               ipv6_addr_copy(hoa, &skb->nh.ipv6h->saddr);
6832 +               ipv6_addr_copy(&skb->nh.ipv6h->saddr, &tmp);
6833 +       }
6834 +}
6835 +
6836 +/**
6837 + * mipv6_append_rt2hdr - Add Type 2 Routing Header
6838 + * @rt: buffer for new routing header
6839 + * @addr: intermediate hop address
6840 + *
6841 + * Adds a Routing Header Type 2 in a packet.  Stores newly created
6842 + * routing header in buffer @rt.  Type 2 RT only carries one address,
6843 + * so there is no need to process old routing header.  @rt must have
6844 + * allocated space for 24 bytes.
6845 + **/
6846 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *rt, struct in6_addr *addr)
6847 +{
6848 +       struct rt2_hdr *rt2 = (struct rt2_hdr *)rt;
6849 +
6850 +        DEBUG(DBG_DATADUMP, "RT2: %x:%x:%x:%x:%x:%x:%x:%x",
6851 +             NIPV6ADDR(addr));
6852 +
6853 +       if (ipv6_addr_type(addr) == IPV6_ADDR_MULTICAST) {
6854 +               DEBUG(DBG_ERROR, "destination address not unicast");
6855 +               return;
6856 +       }
6857 +
6858 +       memset(rt2, 0, sizeof(*rt2));
6859 +       rt2->rt_hdr.type = 2;
6860 +       rt2->rt_hdr.hdrlen = 2;
6861 +       rt2->rt_hdr.segments_left = 1;
6862 +       ipv6_addr_copy(&rt2->addr, addr);
6863 +}
6864 +
6865 +/**
6866 + * mipv6_append_dst1opts - Add Destination Option (1) Headers
6867 + * @dst1opt: buffer for new destination options
6868 + * @saddr: address for Home Address Option
6869 + * @old_dst1opt: old destination options
6870 + * @len: length of options
6871 + *
6872 + * Adds Destination Option (1) Header to a packet.  New options are
6873 + * stored in @dst1opt.  If old destination options exist, they are
6874 + * copied from @old_dst1opt.  Only Home Address Option is destination
6875 + * option.  @dstopt must have allocated space for @len bytes.  @len
6876 + * includes Destination Option Header (2 bytes), Home Address Option
6877 + * (18 bytes) and possible HAO pad (8n+6).
6878 + **/
6879 +/*
6880 + * ISSUE: Home Address Destination Option should really be added to a
6881 + * new destination option header specified in Mobile IPv6 spec which
6882 + * should be placed after routing header(s), but before fragmentation
6883 + * header.  Putting HAO in DO1 works for now, but support for the new
6884 + * placement should be added to the IPv6 stack.
6885 + */
6886 +void 
6887 +mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
6888 +                     struct ipv6_opt_hdr *old_dst1opt, int len)
6889 +{
6890 +       int offset;
6891 +
6892 +       if (old_dst1opt) {
6893 +               memcpy(dst1opt, old_dst1opt, ipv6_optlen(old_dst1opt));
6894 +               offset = ipv6_optlen(old_dst1opt);
6895 +       } else {
6896 +               offset = sizeof (*dst1opt);
6897 +       }
6898 +       dst1opt->hdrlen = (len >> 3) - 1;
6899 +       mipv6_append_home_addr((__u8 *) dst1opt, offset, saddr);
6900 +}
6901 +
6902 +/**
6903 + * mipv6_modify_txoptions - Modify outgoing packets
6904 + * @sk: socket
6905 + * @skb: packet buffer for outgoing packet
6906 + * @old_opt: transmit options
6907 + * @fl: packet flow structure
6908 + * @dst: pointer to destination cache entry
6909 + *
6910 + * Adds Home Address Option (for MN packets, when not at home) and
6911 + * Routing Header Type 2 (for CN packets when sending to an MN) to
6912 + * data packets.  Old extension headers are copied from @old_opt (if
6913 + * any).  Extension headers are _explicitly_ added for packets with
6914 + * Mobility Header.  Returns the new header structure, or old if no
6915 + * changes.
6916 + **/
6917 +struct ipv6_txoptions *
6918 +mipv6_modify_txoptions(struct sock *sk, struct sk_buff *skb, 
6919 +                      struct ipv6_txoptions *old_opt, struct flowi *fl, 
6920 +                      struct dst_entry **dst)
6921 +{      
6922 +       struct ipv6_opt_hdr *old_hopopt = NULL;
6923 +       struct ipv6_opt_hdr *old_dst1opt = NULL;
6924 +       struct ipv6_rt_hdr *old_srcrt = NULL;
6925 +
6926 +       int srcrtlen = 0, dst1len = 0;
6927 +       int tot_len, use_hao = 0;
6928 +       struct ipv6_txoptions *opt;
6929 +       struct mipv6_bce bc_entry;
6930 +       struct in6_addr tmpaddr, *saddr, *daddr, coaddr;
6931 +       __u8 *opt_ptr;
6932 +
6933 +       DEBUG_FUNC();
6934 +
6935 +       if (fl->proto == IPPROTO_MOBILITY) return old_opt;
6936 +       /*
6937 +        * we have to be prepared to the fact that saddr might not be present,
6938 +        * if that is the case, we acquire saddr just as kernel does.
6939 +        */
6940 +       saddr = fl ? fl->fl6_src : NULL;
6941 +       daddr = fl ? fl->fl6_dst : NULL;
6942 +
6943 +       if (daddr == NULL)
6944 +               return old_opt;
6945 +       if (saddr == NULL) {
6946 +               int err = ipv6_get_saddr(NULL, daddr, &tmpaddr);
6947 +               if (err)
6948 +                       return old_opt;
6949 +               else
6950 +                       saddr = &tmpaddr;
6951 +       }
6952 +
6953 +       DEBUG(DBG_DATADUMP,
6954 +             "dest. address of packet: %x:%x:%x:%x:%x:%x:%x:%x",
6955 +             NIPV6ADDR(daddr));
6956 +       DEBUG(DBG_DATADUMP, " and src. address: %x:%x:%x:%x:%x:%x:%x:%x", 
6957 +             NIPV6ADDR(saddr));
6958 +
6959 +       if (old_opt) {
6960 +               old_hopopt = old_opt->hopopt;
6961 +               old_dst1opt = old_opt->dst1opt;
6962 +               old_srcrt = old_opt->srcrt;
6963 +       } 
6964 +
6965 +       if (mip6_fn.mn_use_hao != NULL)
6966 +               use_hao = mip6_fn.mn_use_hao(daddr, saddr);
6967 +
6968 +       if (use_hao) {
6969 +               if (old_dst1opt)
6970 +                       dst1len = ipv6_optlen(old_dst1opt);
6971 +               dst1len += sizeof(struct mipv6_dstopt_homeaddr) +
6972 +                       ((6 - dst1len) & 7); /* padding */
6973 +       }
6974 +
6975 +       if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0)
6976 +               srcrtlen = sizeof(struct rt2_hdr);
6977 +
6978 +       if ((tot_len = srcrtlen + dst1len) == 0) { 
6979 +               return old_opt;
6980 +       }
6981 +
6982 +       tot_len += sizeof(*opt);
6983 +
6984 +       if (!(opt = kmalloc(tot_len, GFP_ATOMIC))) {
6985 +               return NULL;
6986 +       }
6987 +       memset(opt, 0, tot_len);
6988 +       opt->tot_len = tot_len;
6989 +       opt_ptr = (__u8 *) (opt + 1);
6990 +       
6991 +       if (old_srcrt) {
6992 +               opt->srcrt = old_srcrt;
6993 +               opt->opt_nflen += ipv6_optlen(old_srcrt);
6994 +       }
6995 +
6996 +       if (srcrtlen) {
6997 +               DEBUG(DBG_DATADUMP, "Binding exists. Adding routing header");
6998 +
6999 +               opt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
7000 +               opt->opt_nflen += srcrtlen;
7001 +               opt_ptr += srcrtlen;
7002 +               
7003 +               /*
7004 +                * Append care-of-address to routing header (original
7005 +                * destination address is home address, the first
7006 +                * source route segment gets put to the destination
7007 +                * address and the home address gets to the last
7008 +                * segment of source route (just as it should)) 
7009 +                */
7010 +
7011 +               ipv6_addr_copy(&coaddr, &bc_entry.coa);
7012 +
7013 +               mipv6_append_rt2hdr(opt->srcrt2, &coaddr);
7014 +
7015 +               /*
7016 +                * reroute output (we have to do this in case of TCP
7017 +                 * segment) unless a routing header of type 0 is also added
7018 +                */
7019 +               if (dst && !opt->srcrt) {
7020 +                       struct in6_addr *tmp = fl->fl6_dst;
7021 +                       fl->fl6_dst = &coaddr;
7022 +
7023 +                       dst_release(*dst);
7024 +                       *dst = ip6_route_output(sk, fl);
7025 +                       if (skb)
7026 +                               skb->dst = *dst;
7027 +                       fl->fl6_dst = tmp;
7028 +
7029 +                       DEBUG(DBG_DATADUMP, "Rerouted outgoing packet");
7030 +               }
7031 +       }
7032 +
7033 +       /* Only home address option is inserted to first dst opt header */
7034 +       if (dst1len) {
7035 +               opt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
7036 +               opt->opt_flen += dst1len;
7037 +               opt_ptr += dst1len;
7038 +               mipv6_append_dst1opts(opt->dst1opt, saddr, 
7039 +                                     old_dst1opt, dst1len);
7040 +               opt->mipv6_flags = MIPV6_SND_HAO;
7041 +       } else if (old_dst1opt) {
7042 +               opt->dst1opt = old_dst1opt;
7043 +               opt->opt_flen += ipv6_optlen(old_dst1opt);
7044 +       }
7045 +       if (old_hopopt) {
7046 +               opt->hopopt = old_hopopt;
7047 +               opt->opt_nflen += ipv6_optlen(old_hopopt);
7048 +       }       
7049 +       
7050 +       return opt;
7051 +}
7052 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.h linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.h
7053 --- linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.h      1970-01-01 01:00:00.000000000 +0100
7054 +++ linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.h  2004-06-26 11:29:30.000000000 +0100
7055 @@ -0,0 +1,47 @@
7056 +/*
7057 + *     MIPL Mobile IPv6 Extension Headers header file
7058 + *
7059 + *     $Id$
7060 + *
7061 + *     This program is free software; you can redistribute it and/or
7062 + *      modify it under the terms of the GNU General Public License
7063 + *      as published by the Free Software Foundation; either version
7064 + *      2 of the License, or (at your option) any later version.
7065 + */
7066 +
7067 +#ifndef _MIPV6_EXTHDRS_H
7068 +#define _MIPV6_EXTHDRS_H
7069 +
7070 +struct in6_addr;
7071 +struct sk_buff;
7072 +struct ipv6_rt_hdr;
7073 +struct ipv6_opt_hdr;
7074 +struct ipv6_txoptions;
7075 +struct flowi;
7076 +struct dst_entry;
7077 +/*
7078 + * Home Address Destination Option function prototypes
7079 + */
7080 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr);
7081 +
7082 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff);
7083 +
7084 +void mipv6_icmp_swap_addrs(struct sk_buff *skb);
7085 +
7086 +/*
7087 + * Creates a routing header of type 2.
7088 + */
7089 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *srcrt, struct in6_addr *addr);
7090 +
7091 +/* Function to add the first destination option header, which may
7092 + * include a home address option.  
7093 + */
7094 +void mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
7095 +                          struct ipv6_opt_hdr *old_dst1opt, int len);
7096 +
7097 +struct ipv6_txoptions *mipv6_modify_txoptions(
7098 +       struct sock *sk, struct sk_buff *skb,
7099 +       struct ipv6_txoptions *old_opt, struct flowi *fl,
7100 +       struct dst_entry **dst);
7101 +
7102 +#endif /* _MIPV6_EXTHDRS_H */
7103 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ha.c linux-2.4.25/net/ipv6/mobile_ip6/ha.c
7104 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ha.c   1970-01-01 01:00:00.000000000 +0100
7105 +++ linux-2.4.25/net/ipv6/mobile_ip6/ha.c       2004-06-26 11:29:30.000000000 +0100
7106 @@ -0,0 +1,553 @@
7107 +/*
7108 + *      Home-agent functionality
7109 + *
7110 + *      Authors:
7111 + *      Sami Kivisaari           <skivisaa@cc.hut.fi>
7112 + *      Henrik Petander          <lpetande@cc.hut.fi>
7113 + *
7114 + *      $Id$
7115 + *
7116 + *      This program is free software; you can redistribute it and/or
7117 + *      modify it under the terms of the GNU General Public License
7118 + *      as published by the Free Software Foundation; either version
7119 + *      2 of the License, or (at your option) any later version.
7120 + *   
7121 + *      Changes: Venkata Jagana,
7122 + *               Krishna Kumar     : Statistics fix
7123 + *               Masahide Nakamura : Use of mipv6_forward  
7124 + *     
7125 + */
7126 +
7127 +#include <linux/autoconf.h>
7128 +#include <linux/net.h>
7129 +#include <linux/skbuff.h>
7130 +#include <linux/if_ether.h>
7131 +#include <linux/netdevice.h>
7132 +#include <linux/in6.h>
7133 +#include <linux/init.h>
7134 +#include <linux/netfilter.h>
7135 +#include <linux/netfilter_ipv6.h>
7136 +#ifdef CONFIG_SYSCTL
7137 +#include <linux/sysctl.h>
7138 +#endif
7139 +
7140 +#include <net/neighbour.h>
7141 +#include <net/ipv6.h>
7142 +#include <net/ip6_fib.h>
7143 +#include <net/ip6_route.h>
7144 +#include <net/ndisc.h>
7145 +#include <net/addrconf.h>
7146 +#include <net/neighbour.h>
7147 +
7148 +#include "tunnel_ha.h"
7149 +#include "bcache.h"
7150 +#include "stats.h"
7151 +#include "debug.h"
7152 +#include "util.h"
7153 +#include "ha.h"
7154 +#include "config.h"
7155 +#include "mobhdr.h"
7156 +
7157 +static int mipv6_ha_tunnel_sitelocal = 0;
7158 +
7159 +#ifdef CONFIG_SYSCTL
7160 +
7161 +static struct ctl_table_header *mipv6_ha_sysctl_header;
7162 +
7163 +static struct mipv6_ha_sysctl_table
7164 +{
7165 +       struct ctl_table_header *sysctl_header;
7166 +       ctl_table mipv6_vars[3];
7167 +       ctl_table mipv6_mobility_table[2];
7168 +       ctl_table mipv6_proto_table[2];
7169 +       ctl_table mipv6_root_table[2];
7170 +} mipv6_ha_sysctl = {
7171 +       NULL,
7172 +
7173 +        {{NET_IPV6_MOBILITY_TUNNEL_SITELOCAL, "tunnel_sitelocal",
7174 +         &mipv6_ha_tunnel_sitelocal, sizeof(int), 0644, NULL, 
7175 +         &proc_dointvec},
7176 +        {0}},
7177 +
7178 +       {{NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, 
7179 +         mipv6_ha_sysctl.mipv6_vars}, {0}},
7180 +       {{NET_IPV6, "ipv6", NULL, 0, 0555, 
7181 +         mipv6_ha_sysctl.mipv6_mobility_table}, {0}},
7182 +       {{CTL_NET, "net", NULL, 0, 0555, 
7183 +         mipv6_ha_sysctl.mipv6_proto_table}, {0}}
7184 +};
7185 +
7186 +#endif /* CONFIG_SYSCTL */
7187 +
7188 +
7189 +/*  this is defined in kernel IPv6 module (sockglue.c)  */
7190 +extern struct packet_type ipv6_packet_type;
7191 +
7192 +/* mipv6_forward: Intercept NS packets destined to home address of MN */
7193 +int mipv6_forward(struct sk_buff *skb)
7194 +{
7195 +       struct ipv6hdr *ipv6h;
7196 +       struct in6_addr *daddr, *saddr;
7197 +       __u8 nexthdr;
7198 +       int nhoff;
7199 +       
7200 +       if (skb == NULL) return  0;
7201 +       
7202 +       ipv6h = skb->nh.ipv6h;
7203 +       daddr = &ipv6h->daddr;
7204 +       saddr = &ipv6h->saddr;
7205 +
7206 +       nexthdr = ipv6h->nexthdr;
7207 +       nhoff = sizeof(*ipv6h);
7208 +   
7209 +       if (ipv6_ext_hdr(nexthdr))
7210 +               nhoff = ipv6_skip_exthdr(skb, nhoff, &nexthdr,
7211 +                                        skb->len - sizeof(*ipv6h));
7212 +       
7213 +       /* Do not to forward Neighbor Solicitation to Home Address of MN */
7214 +       if (nexthdr == IPPROTO_ICMPV6) {
7215 +               struct icmp6hdr *icmp6h;
7216 +               int dest_type;
7217 +               
7218 +               if (nhoff < 0 || !pskb_may_pull(skb, nhoff + 
7219 +                                               sizeof(struct icmp6hdr))) {
7220 +                       kfree_skb(skb);
7221 +                       return 0;
7222 +                   }
7223 +               
7224 +               dest_type = ipv6_addr_type(daddr);
7225 +               icmp6h = (struct icmp6hdr *)&skb->nh.raw[nhoff];
7226 +               
7227 +               /* Intercepts NS to HoA of MN */
7228 +
7229 +               if ((icmp6h->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) ||
7230 +                   ((dest_type & IPV6_ADDR_MULTICAST) &&
7231 +                    (icmp6h->icmp6_type == NDISC_ROUTER_ADVERTISEMENT))) {
7232 +                       ip6_input(skb);
7233 +               } else {
7234 +                       ip6_forward(skb);
7235 +               }
7236 +       } else {
7237 +               ip6_forward(skb);
7238 +       }
7239 +       return 0;
7240 +}
7241 +
7242 +
7243 +/**
7244 + * mipv6_proxy_nd_rem - stop acting as a proxy for @home_address
7245 + * @home_addr: address to remove
7246 + * @ha_addr: home agent's address on home link
7247 + * @linklocal: link-local compatibility bit
7248 + *
7249 + * When Home Agent acts as a proxy for an address it must leave the
7250 + * solicited node multicast group for that address and stop responding 
7251 + * to neighbour solicitations.  
7252 + **/
7253 +static int mipv6_proxy_nd_rem(struct in6_addr *home_addr,
7254 +                             int ifindex, int linklocal)
7255 +{
7256 +        /* When MN returns home HA leaves the solicited mcast groups
7257 +         * for MNs home addresses 
7258 +        */
7259 +       int err;
7260 +       struct net_device *dev;
7261 +       
7262 +       DEBUG_FUNC();
7263 +       
7264 +        if ((dev = dev_get_by_index(ifindex)) == NULL) {
7265 +               DEBUG(DBG_ERROR, "couldn't get dev");
7266 +               return -ENODEV;
7267 +       }
7268 +#if 1  /* TEST */
7269 +       /* Remove link-local entry */
7270 +       if (linklocal) {
7271 +               struct in6_addr ll_addr;
7272 +               mipv6_generate_ll_addr(&ll_addr, home_addr);
7273 +               if ((err = pneigh_delete(&nd_tbl, &ll_addr, dev)) < 0) {
7274 +                       DEBUG(DBG_INFO,
7275 +                             "peigh_delete failed for "
7276 +                             "%x:%x:%x:%x:%x:%x:%x:%x",
7277 +                             NIPV6ADDR(&ll_addr));     
7278 +               }
7279 +       }
7280 +#endif
7281 +       /* Remove global (or site-local) entry */
7282 +       if ((err = pneigh_delete(&nd_tbl, home_addr, dev)) < 0) {
7283 +               DEBUG(DBG_INFO,
7284 +                     "peigh_delete failed for " 
7285 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
7286 +                     NIPV6ADDR(home_addr));
7287 +       }
7288 +       dev_put(dev);
7289 +       return err;
7290 +}
7291 +
7292 +/**
7293 + * mipv6_proxy_nd - join multicast group for this address
7294 + * @home_addr: address to defend
7295 + * @ha_addr: home agent's address on home link
7296 + * @linklocal: link-local compatibility bit
7297 + *
7298 + * While Mobile Node is away from home, Home Agent acts as a proxy for
7299 + * @home_address. HA responds to neighbour solicitations for  @home_address 
7300 + * thus getting all packets destined to home address of MN. 
7301 + **/
7302 +static int mipv6_proxy_nd(struct in6_addr *home_addr, 
7303 +                         int ifindex, int linklocal)
7304 +{  
7305 +       /* The HA sends a proxy ndisc_na message to all hosts on MN's
7306 +        * home subnet by sending a neighbor advertisement with the
7307 +        * home address or all addresses of the mobile node if the
7308 +        * prefix is not 0. The addresses are formed by combining the
7309 +        * suffix or the host part of the address with each subnet
7310 +        * prefix that exists in the home subnet 
7311 +        */
7312 +       
7313 +        /* Since no previous entry for MN exists a proxy_nd advertisement
7314 +        * is sent to all nodes link local multicast address
7315 +        */     
7316 +       int err = -1;
7317 +
7318 +       struct net_device *dev;
7319 +       struct in6_addr na_saddr;
7320 +       struct in6_addr ll_addr;
7321 +       struct pneigh_entry *ll_pneigh;
7322 +       struct in6_addr mcdest;
7323 +       int send_ll_na = 0;
7324 +       int inc_opt = 1;
7325 +       int solicited = 0;
7326 +       int override = 1;
7327 +       
7328 +       DEBUG_FUNC();
7329 +       
7330 +       if ((dev = dev_get_by_index(ifindex)) == NULL) {
7331 +               DEBUG(DBG_ERROR, "couldn't get dev");
7332 +               return -ENODEV;
7333 +       }
7334 +       
7335 +       if (!pneigh_lookup(&nd_tbl, home_addr, dev, 1)) {
7336 +               DEBUG(DBG_INFO,
7337 +                     "peigh_lookup failed for "
7338 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
7339 +                     NIPV6ADDR(home_addr));
7340 +               goto free_dev;
7341 +       }
7342 +#if 1 /* TEST */
7343 +       if (linklocal) {
7344 +               mipv6_generate_ll_addr(&ll_addr, home_addr);
7345 +               
7346 +               if ((ll_pneigh = pneigh_lookup(&nd_tbl, &ll_addr, 
7347 +                                              dev, 1)) == NULL) {
7348 +                       DEBUG(DBG_INFO,
7349 +                             "peigh_lookup failed for "
7350 +                             "%x:%x:%x:%x:%x:%x:%x:%x",
7351 +                             NIPV6ADDR(&ll_addr));
7352 +                       pneigh_delete(&nd_tbl, home_addr, dev);
7353 +                       goto free_dev;
7354 +               } else {
7355 +                       send_ll_na = 1;
7356 +               }
7357 +       } else {
7358 +               ll_pneigh = NULL;
7359 +       }
7360 +#endif 
7361 +       /* Proxy neighbor advertisement of MN's home address 
7362 +        * to all nodes solicited multicast address 
7363 +        */
7364 +       if (!ipv6_get_lladdr(dev, &na_saddr)) { 
7365 +               ipv6_addr_all_nodes(&mcdest); 
7366 +               ndisc_send_na(dev, NULL, &mcdest, home_addr, 0, 
7367 +                             solicited, override, inc_opt);
7368 +#if 1 /* TEST */
7369 +               if (send_ll_na) {
7370 +                       ndisc_send_na(dev, NULL, &mcdest, &ll_addr, 
7371 +                                     0, solicited, override, inc_opt);
7372 +               }
7373 +#endif
7374 +               err = 0;
7375 +       } else {
7376 +               DEBUG(DBG_ERROR, "failed to get link local address for sending proxy NA");
7377 +       }
7378 +free_dev:
7379 +       dev_put(dev);
7380 +       return err;
7381 +       
7382 +}
7383 +
7384 +struct inet6_ifaddr *is_on_link_ipv6_address(struct in6_addr *mn_haddr,
7385 +                                            struct in6_addr *ha_addr)
7386 +{
7387 +       struct inet6_ifaddr *ifp;
7388 +       struct inet6_dev *in6_dev;
7389 +       struct inet6_ifaddr *oifp = NULL;
7390 +
7391 +       if ((ifp = ipv6_get_ifaddr(ha_addr, 0)) == NULL)
7392 +               return NULL;
7393 +
7394 +       if ((in6_dev = ifp->idev) != NULL) {
7395 +               in6_dev_hold(in6_dev);
7396 +               oifp = in6_dev->addr_list;
7397 +               while (oifp != NULL) {
7398 +                       spin_lock(&oifp->lock);
7399 +                       if (mipv6_prefix_compare(&oifp->addr, mn_haddr,
7400 +                                                oifp->prefix_len) &&
7401 +                           !(oifp->flags & IFA_F_TENTATIVE)) {
7402 +                               spin_unlock(&oifp->lock);
7403 +                               DEBUG(DBG_INFO, "Home Addr Opt: on-link");
7404 +                               in6_ifa_hold(oifp);
7405 +                               break;
7406 +                       }
7407 +                       spin_unlock(&oifp->lock);
7408 +                       oifp = oifp->if_next;
7409 +               }
7410 +               in6_dev_put(in6_dev);
7411 +       }
7412 +       in6_ifa_put(ifp);
7413 +/*      DEBUG(DBG_WARNING, "Home Addr Opt NOT on-link"); */
7414 +       return oifp;
7415 +
7416 +}
7417 +
7418 +/*
7419 + * Lifetime checks. ifp->valid_lft >= ifp->prefered_lft always (see addrconf.c)
7420 + * Returned value is in seconds.
7421 + */
7422 +
7423 +static __u32 get_min_lifetime(struct inet6_ifaddr *ifp, __u32 lifetime)
7424 +{
7425 +       __u32 rem_lifetime = 0;
7426 +       unsigned long now = jiffies;
7427 +
7428 +       if (ifp->valid_lft == 0) {
7429 +               rem_lifetime = lifetime;
7430 +       } else {
7431 +               __u32 valid_lft_left =
7432 +                   ifp->valid_lft - ((now - ifp->tstamp) / HZ);
7433 +               rem_lifetime =
7434 +                   min_t(unsigned long, valid_lft_left, lifetime);
7435 +       }
7436 +
7437 +       return rem_lifetime;
7438 +}
7439 +
7440 +#define MAX_LIFETIME 1000
7441 +
7442 +/**
7443 + * mipv6_lifetime_check - check maximum lifetime is not exceeded
7444 + * @lifetime: lifetime to check
7445 + *
7446 + * Checks @lifetime does not exceed %MAX_LIFETIME.  Returns @lifetime
7447 + * if not exceeded, otherwise returns %MAX_LIFETIME.
7448 + **/
7449 +static int mipv6_lifetime_check(int lifetime)
7450 +{
7451 +       return (lifetime > MAX_LIFETIME) ? MAX_LIFETIME : lifetime;
7452 +}
7453 +
7454 +/* Generic routine handling finish of BU processing */
7455 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex, __u8 ba_status,
7456 +                    struct in6_addr *daddr, struct in6_addr *haddr,
7457 +                    struct in6_addr *coa, struct in6_addr *rep_coa,
7458 +                    __u32 ba_lifetime, __u16 sequence, __u8 flags, __u8 *k_bu)
7459 +{
7460 +       int err;
7461 +
7462 +       if (ba_status >= REASON_UNSPECIFIED) {
7463 +               /* DAD failed */
7464 +               goto out;
7465 +       }
7466 +       
7467 +       ba_lifetime = get_min_lifetime(ifp, ba_lifetime);
7468 +       ba_lifetime = mipv6_lifetime_check(ba_lifetime);
7469 +
7470 +       if ((err = mipv6_bcache_add(ifindex, daddr, haddr, coa, 
7471 +                                   ba_lifetime, sequence, flags,
7472 +                                   HOME_REGISTRATION)) != 0 ) {
7473 +               DEBUG(DBG_WARNING, "home reg failed.");
7474 +
7475 +               if (err == -ENOMEDIUM)
7476 +                       return;
7477 +
7478 +               ba_status = INSUFFICIENT_RESOURCES;
7479 +       } else {
7480 +               DEBUG(DBG_INFO, "home reg succeeded.");
7481 +       }
7482 +
7483 +       DEBUG(DBG_DATADUMP, "home_addr: %x:%x:%x:%x:%x:%x:%x:%x",
7484 +             NIPV6ADDR(haddr));
7485 +       DEBUG(DBG_DATADUMP, "coa: %x:%x:%x:%x:%x:%x:%x:%x",
7486 +             NIPV6ADDR(coa));
7487 +       DEBUG(DBG_DATADUMP, "lifet:%d, seq:%d", ba_lifetime, sequence);
7488 +out:
7489 +       mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
7490 +                     ba_lifetime, k_bu);
7491 +}
7492 +
7493 +static int ha_proxy_create(int flags, int ifindex, struct in6_addr *coa,
7494 +                          struct in6_addr *our_addr, struct in6_addr *home_addr)
7495 +{
7496 +       int ret;
7497 +
7498 +       if ((ret = mipv6_add_tnl_to_mn(coa, our_addr, home_addr)) <= 0) {
7499 +               if (ret != -ENOMEDIUM) {
7500 +                       DEBUG(DBG_ERROR, "unable to configure tunnel to MN!");
7501 +               }
7502 +               return -1;
7503 +       }
7504 +       if (mipv6_proxy_nd(home_addr, ifindex, 
7505 +                          flags & MIPV6_BU_F_LLADDR) != 0) {
7506 +               DEBUG(DBG_ERROR, "mipv6_proxy_nd failed!");
7507 +               mipv6_del_tnl_to_mn(coa, our_addr, home_addr);
7508 +               return -2;
7509 +       }
7510 +       return 0;
7511 +}
7512 +
7513 +static void ha_proxy_del(struct in6_addr *home_addr, struct mipv6_bce *entry)
7514 +{
7515 +       if (mipv6_proxy_nd_rem(&entry->home_addr, entry->ifindex,
7516 +                              entry->flags & MIPV6_BU_F_LLADDR) == 0) {
7517 +               DEBUG(DBG_INFO, "proxy_nd succ");
7518 +       } else {
7519 +               DEBUG(DBG_INFO, "proxy_nd fail");
7520 +       }
7521 +       mipv6_del_tnl_to_mn(&entry->coa, &entry->our_addr, home_addr);
7522 +}
7523 +
7524 +static void bc_home_add(int ifindex, 
7525 +                       struct in6_addr *daddr, struct in6_addr *haddr, 
7526 +                       struct in6_addr *coa, struct in6_addr *rep_coa,
7527 +                       __u32 lifetime, __u16 sequence, __u8 flags, 
7528 +                       __u8 *k_bu)
7529 +{
7530 +       struct inet6_ifaddr *ifp = NULL;
7531 +       __u8 ba_status = SUCCESS;
7532 +
7533 +       DEBUG_FUNC();
7534 +
7535 +       ifp = is_on_link_ipv6_address(haddr, daddr);
7536 +
7537 +       if (ifp == NULL) {
7538 +               ba_status = NOT_HOME_SUBNET;
7539 +       } else if (((ipv6_addr_type(haddr) & IPV6_ADDR_SITELOCAL) ||
7540 +                   (ipv6_addr_type(coa) & IPV6_ADDR_SITELOCAL))
7541 +                  && !mipv6_ha_tunnel_sitelocal) {
7542 +               /* Site-local home or care-of addresses are not 
7543 +                  accepted by default */
7544 +               ba_status = ADMINISTRATIVELY_PROHIBITED;
7545 +       } else {
7546 +               int ret;
7547 +
7548 +               ifindex = ifp->idev->dev->ifindex;
7549 +
7550 +               if ((ret = mipv6_dad_start(ifp, ifindex, daddr, 
7551 +                                          haddr, coa, rep_coa, lifetime,
7552 +                                          sequence, flags)) < 0) {
7553 +                       /* An error occurred */
7554 +                       ba_status = -ret;
7555 +               } else if (ret) {
7556 +                       /* DAD is needed to be performed. */
7557 +                       in6_ifa_put(ifp);
7558 +                       return;
7559 +               }
7560 +       }
7561 +
7562 +       mipv6_bu_finish(ifp, ifindex, ba_status, daddr, haddr, coa, 
7563 +                       rep_coa, lifetime, sequence, flags, k_bu);
7564 +       if (ifp)
7565 +               in6_ifa_put(ifp);
7566 +}
7567 +
7568 +static void bc_home_delete(struct in6_addr *daddr, struct in6_addr *haddr, 
7569 +                          struct in6_addr *coa, struct in6_addr *rep_coa, 
7570 +                          __u16 sequence, __u8 flags, __u8 *k_bu)
7571 +{
7572 +       __u8 status = SUCCESS;
7573 +       struct mipv6_bce bce;
7574 +
7575 +       /* Primary Care-of Address Deregistration */
7576 +       if (mipv6_bcache_get(haddr, daddr, &bce) < 0) {
7577 +               DEBUG(DBG_INFO, "entry is not in cache");
7578 +               status = NOT_HA_FOR_MN;
7579 +       } else {
7580 +               ha_proxy_del(&bce.home_addr, &bce);
7581 +               mipv6_bcache_delete(haddr, daddr, HOME_REGISTRATION);
7582 +       }
7583 +       mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence, 0, k_bu);
7584 +}
7585 +
7586 +extern int mipv6_ra_rcv_ptr(struct sk_buff *skb, struct icmp6hdr *msg);
7587 +
7588 +
7589 +static int
7590 +mipv6_ha_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7591 +{
7592 +       DEBUG_FUNC();
7593 +       if (is_mip6_tnl(t))
7594 +               MIPV6_INC_STATS(n_encapsulations);
7595 +       return IP6_TNL_ACCEPT;
7596 +}
7597 +
7598 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_xmit_stats_ops = {
7599 +       {NULL, NULL},
7600 +       IP6_TNL_PRE_ENCAP,
7601 +       IP6_TNL_PRI_LAST,
7602 +       mipv6_ha_tnl_xmit_stats_hook
7603 +};
7604 +
7605 +static int
7606 +mipv6_ha_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7607 +{
7608 +       DEBUG_FUNC();
7609 +       if (is_mip6_tnl(t))
7610 +               MIPV6_INC_STATS(n_decapsulations);
7611 +       return IP6_TNL_ACCEPT;
7612 +}
7613 +
7614 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_rcv_stats_ops = {
7615 +       {NULL, NULL},
7616 +       IP6_TNL_PRE_DECAP,
7617 +       IP6_TNL_PRI_LAST,
7618 +       mipv6_ha_tnl_rcv_stats_hook
7619 +};
7620 +
7621 +static struct mip6_func old;
7622 +
7623 +int __init mipv6_ha_init(void)
7624 +{
7625 +       DEBUG_FUNC();
7626 +       
7627 +#ifdef CONFIG_SYSCTL
7628 +       if (!(mipv6_ha_sysctl_header = 
7629 +             register_sysctl_table(mipv6_ha_sysctl.mipv6_root_table, 0)))
7630 +               printk(KERN_ERR "Failed to register sysctl handlers!");
7631 +#endif
7632 +       memcpy(&old, &mip6_fn, sizeof(struct mip6_func));
7633 +       mip6_fn.bce_home_add = bc_home_add;
7634 +       mip6_fn.bce_home_del = bc_home_delete;
7635 +       mip6_fn.proxy_del = ha_proxy_del;
7636 +       mip6_fn.proxy_create = ha_proxy_create;
7637 +       /*  register packet interception hooks  */
7638 +       ip6ip6_tnl_register_hook(&mipv6_ha_tnl_xmit_stats_ops);
7639 +       ip6ip6_tnl_register_hook(&mipv6_ha_tnl_rcv_stats_ops);
7640 +       return 0;
7641 +}
7642 +
7643 +void __exit mipv6_ha_exit(void)
7644 +{
7645 +       DEBUG_FUNC();
7646 +
7647 +#ifdef CONFIG_SYSCTL
7648 +       unregister_sysctl_table(mipv6_ha_sysctl_header);
7649 +#endif
7650 +
7651 +       /*  remove packet interception hooks  */
7652 +       ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_rcv_stats_ops);
7653 +       ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_xmit_stats_ops);
7654 +
7655 +       mip6_fn.bce_home_add = old.bce_home_add;
7656 +       mip6_fn.bce_home_del = old.bce_home_del;
7657 +       mip6_fn.proxy_del = old.proxy_del;
7658 +       mip6_fn.proxy_create = old.proxy_create;
7659 +}
7660 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ha.h linux-2.4.25/net/ipv6/mobile_ip6/ha.h
7661 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ha.h   1970-01-01 01:00:00.000000000 +0100
7662 +++ linux-2.4.25/net/ipv6/mobile_ip6/ha.h       2004-06-26 11:29:30.000000000 +0100
7663 @@ -0,0 +1,39 @@
7664 +/*
7665 + *      MIPL Mobile IPv6 Home Agent header file
7666 + *
7667 + *      $Id$
7668 + *
7669 + *      This program is free software; you can redistribute it and/or
7670 + *      modify it under the terms of the GNU General Public License
7671 + *      as published by the Free Software Foundation; either version
7672 + *      2 of the License, or (at your option) any later version.
7673 + */
7674 +
7675 +#ifndef _HA_H
7676 +#define _HA_H
7677 +
7678 +int mipv6_ha_init(void);
7679 +void mipv6_ha_exit(void);
7680 +
7681 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
7682 +                   struct in6_addr *daddr, struct in6_addr *haddr,
7683 +                   struct in6_addr *coa, struct in6_addr *rep_coa,
7684 +                   __u32 ba_lifetime, __u16 sequence, __u8 flags);
7685 +
7686 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex, 
7687 +                    __u8 ba_status, struct in6_addr *daddr,
7688 +                    struct in6_addr *haddr, struct in6_addr *coa, 
7689 +                    struct in6_addr *rep_coa, __u32 ba_lifetime,
7690 +                    __u16 sequence, __u8 flags, __u8 *k_bu);
7691 +
7692 +
7693 +static __inline__ void mipv6_generate_ll_addr(struct in6_addr *ll_addr,
7694 +                                             struct in6_addr *addr)
7695 +{
7696 +       ll_addr->s6_addr32[0] = htonl(0xfe800000);
7697 +       ll_addr->s6_addr32[1] = 0;
7698 +       ll_addr->s6_addr32[2] = addr->s6_addr32[2];
7699 +       ll_addr->s6_addr32[3] = addr->s6_addr32[3];
7700 +}
7701 +
7702 +#endif
7703 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/halist.c linux-2.4.25/net/ipv6/mobile_ip6/halist.c
7704 --- linux-2.4.25.old/net/ipv6/mobile_ip6/halist.c       1970-01-01 01:00:00.000000000 +0100
7705 +++ linux-2.4.25/net/ipv6/mobile_ip6/halist.c   2004-06-26 11:29:30.000000000 +0100
7706 @@ -0,0 +1,507 @@
7707 +/*
7708 + *      Home Agents List
7709 + *
7710 + *      Authors:
7711 + *      Antti Tuominen          <ajtuomin@tml.hut.fi>
7712 + *
7713 + *      $Id$
7714 + *
7715 + *      This program is free software; you can redistribute it and/or
7716 + *      modify it under the terms of the GNU General Public License
7717 + *      as published by the Free Software Foundation; either version
7718 + *      2 of the License, or (at your option) any later version.
7719 + *
7720 + */
7721 +
7722 +#define PREF_BASE 0xffff /* MAX value for u16 field in RA */
7723 +
7724 +#include <linux/autoconf.h>
7725 +#include <linux/sched.h>
7726 +#include <linux/timer.h>
7727 +#include <linux/proc_fs.h>
7728 +#include <linux/init.h>
7729 +#include <net/ipv6.h>
7730 +#include <net/addrconf.h>
7731 +
7732 +#include "hashlist.h"
7733 +#include "util.h"
7734 +#include "debug.h"
7735 +
7736 +struct mipv6_halist {
7737 +       struct hashlist *entries;
7738 +       struct timer_list expire_timer;
7739 +};
7740 +
7741 +static rwlock_t home_agents_lock = RW_LOCK_UNLOCKED;
7742 +
7743 +static struct mipv6_halist home_agents;
7744 +
7745 +struct mipv6_halist_entry {
7746 +       struct hashlist_entry e;
7747 +       int ifindex;                     /* Link identifier             */
7748 +       struct in6_addr link_local_addr; /* HA's link-local address     */
7749 +       struct in6_addr global_addr;     /* HA's Global address         */
7750 +       int plen;
7751 +       long preference;                 /* The preference for this HA  */
7752 +       unsigned long expire;            /* expiration time (jiffies)   */
7753 +};
7754 +
7755 +static inline void mipv6_ha_ac_add(struct in6_addr *ll_addr, int ifindex,
7756 +                                  struct in6_addr *glob_addr, int plen)
7757 +{
7758 +       struct net_device *dev;
7759 +
7760 +       if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7761 +               struct in6_addr addr;
7762 +               mipv6_ha_anycast(&addr, glob_addr, plen);
7763 +               ipv6_dev_ac_inc(dev, &addr);
7764 +       }
7765 +}
7766 +
7767 +static inline void mipv6_ha_ac_del(struct in6_addr *ll_addr, int ifindex,
7768 +                                  struct in6_addr *glob_addr, int plen)
7769 +{
7770 +       struct net_device *dev;
7771 +
7772 +       if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7773 +               struct in6_addr addr;
7774 +               mipv6_ha_anycast(&addr, glob_addr, plen);
7775 +               ipv6_dev_ac_dec(dev, &addr);
7776 +       }
7777 +}
7778 +
7779 +struct preflist_iterator_args {
7780 +       int count;
7781 +       int requested;
7782 +       int ifindex;
7783 +       struct in6_addr *list;
7784 +};
7785 +
7786 +static int preflist_iterator(void *data, void *args,
7787 +                            unsigned long *pref)
7788 +{
7789 +       struct preflist_iterator_args *state =
7790 +               (struct preflist_iterator_args *)args;
7791 +       struct mipv6_halist_entry *entry =
7792 +               (struct mipv6_halist_entry *)data;
7793 +       struct in6_addr *newaddr =
7794 +               (struct in6_addr *)state->list + state->count;
7795 +
7796 +       if (state->count >= state->requested)
7797 +               return ITERATOR_STOP;
7798 +
7799 +       if (time_after(jiffies, entry->expire)) {
7800 +               if (!ipv6_addr_any(&entry->link_local_addr)) {
7801 +                       mipv6_ha_ac_del(&entry->link_local_addr, 
7802 +                                       entry->ifindex, 
7803 +                                       &entry->global_addr, entry->plen);
7804 +               }
7805 +               DEBUG(DBG_INFO, "preflist_iterator: Deleting entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7806 +               return ITERATOR_DELETE_ENTRY;
7807 +       }
7808 +       if (state->ifindex != entry->ifindex)
7809 +               return ITERATOR_CONT;
7810 +
7811 +       ipv6_addr_copy(newaddr, &entry->global_addr);
7812 +       DEBUG(DBG_INFO, "preflist_iterator: adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7813 +       state->count++;
7814 +
7815 +       return ITERATOR_CONT;
7816 +}
7817 +
7818 +static int gc_iterator(void *data, void *args,
7819 +                      unsigned long *pref)
7820 +{
7821 +       struct mipv6_halist_entry *entry =
7822 +               (struct mipv6_halist_entry *)data;
7823 +
7824 +       int *type = (int *)args;
7825 +
7826 +       if (*type == 1 || time_after(jiffies, entry->expire)) {
7827 +               if (!ipv6_addr_any(&entry->link_local_addr)) {
7828 +                       mipv6_ha_ac_del(&entry->link_local_addr, 
7829 +                                       entry->ifindex, 
7830 +                                       &entry->global_addr, entry->plen);
7831 +               }
7832 +               return ITERATOR_DELETE_ENTRY;
7833 +       }
7834 +
7835 +       return ITERATOR_CONT;
7836 +}
7837 +
7838 +static int mipv6_halist_gc(int type)
7839 +{
7840 +       DEBUG_FUNC();
7841 +       hashlist_iterate(home_agents.entries, &type, gc_iterator);
7842 +       return 0;
7843 +}
7844 +
7845 +static void mipv6_halist_expire(unsigned long dummy)
7846 +{
7847 +       DEBUG_FUNC();
7848 +
7849 +       write_lock(&home_agents_lock);
7850 +       mipv6_halist_gc(0);
7851 +       write_unlock(&home_agents_lock);
7852 +}
7853 +
7854 +
7855 +static struct mipv6_halist_entry *mipv6_halist_new_entry(void)
7856 +{
7857 +       struct mipv6_halist_entry *entry;
7858 +
7859 +       DEBUG_FUNC();
7860 +
7861 +       entry = hashlist_alloc(home_agents.entries, SLAB_ATOMIC);
7862 +
7863 +       return entry;
7864 +}
7865 +
7866 +
7867 +
7868 +/**
7869 + * mipv6_halist_add - Add new home agent to the Home Agents List
7870 + * @ifindex: interface identifier
7871 + * @glob_addr: home agent's global address
7872 + * @ll_addr: home agent's link-local address
7873 + * @pref: relative preference for this home agent
7874 + * @lifetime: lifetime for the entry
7875 + *
7876 + * Adds new home agent to the Home Agents List.  The list is interface
7877 + * specific and @ifindex tells through which interface the home agent
7878 + * was heard.  Returns zero on success and negative on failure.
7879 + **/
7880 +
7881 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
7882 +                    struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime)
7883 +{
7884 +       int update = 0, ret = 0;
7885 +       unsigned int mpref;
7886 +       struct mipv6_halist_entry *entry = NULL;
7887 +
7888 +       DEBUG_FUNC();
7889 +
7890 +       write_lock(&home_agents_lock);
7891 +
7892 +       if (glob_addr == NULL || lifetime <= 0) {
7893 +               DEBUG(DBG_WARNING, "invalid arguments");
7894 +               ret = -EINVAL;
7895 +               goto out;
7896 +       }
7897 +       mpref = PREF_BASE - pref;
7898 +       if ((entry = (struct mipv6_halist_entry *)
7899 +            hashlist_get(home_agents.entries, glob_addr)) != NULL) {
7900 +               if (entry->ifindex == ifindex) {
7901 +                       DEBUG(DBG_DATADUMP, "updating old entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7902 +                       update = 1;
7903 +               } else {
7904 +                       DEBUG(DBG_INFO, "halist_add : adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7905 +                       update = 0;
7906 +               }
7907 +       }
7908 +       if (update) {
7909 +               entry->expire = jiffies + lifetime * HZ;
7910 +               if (entry->preference != mpref) {
7911 +                       entry->preference = mpref;
7912 +                       ret = hashlist_reposition(home_agents.entries, 
7913 +                                                 (void *)entry, mpref);
7914 +               }
7915 +       } else {
7916 +               entry = mipv6_halist_new_entry();
7917 +               if (entry == NULL) {
7918 +                       DEBUG(DBG_INFO, "list full");
7919 +                       ret = -ENOMEM;
7920 +                       goto out;
7921 +               }
7922 +               entry->ifindex = ifindex;
7923 +               if (ll_addr) {
7924 +                       ipv6_addr_copy(&entry->link_local_addr, ll_addr);
7925 +                       mipv6_ha_ac_add(ll_addr, ifindex, glob_addr, plen);
7926 +               } else
7927 +                       ipv6_addr_set(&entry->link_local_addr, 0, 0, 0, 0);
7928 +
7929 +               ipv6_addr_copy(&entry->global_addr, glob_addr);
7930 +               entry->plen = plen;
7931 +               entry->preference = mpref;
7932 +               entry->expire = jiffies + lifetime * HZ;
7933 +               ret = hashlist_add(home_agents.entries, glob_addr, mpref, 
7934 +                                  entry);
7935 +       }
7936 +out:
7937 +       write_unlock(&home_agents_lock);
7938 +       return ret;
7939 +}
7940 +
7941 +/**
7942 + * mipv6_halist_delete - delete home agent from Home Agents List
7943 + * @glob_addr: home agent's global address
7944 + *
7945 + * Deletes entry for home agent @glob_addr from the Home Agent List.
7946 + **/
7947 +int mipv6_halist_delete(struct in6_addr *glob_addr)
7948 +{
7949 +       struct hashlist_entry *e;
7950 +       struct mipv6_halist_entry *entry;
7951 +       DEBUG_FUNC();
7952 +
7953 +       if (glob_addr == NULL) {
7954 +               DEBUG(DBG_WARNING, "invalid glob addr");
7955 +               return -EINVAL;
7956 +       }
7957 +       write_lock(&home_agents_lock);
7958 +       if ((e = hashlist_get(home_agents.entries, glob_addr)) == NULL) {
7959 +               write_unlock(&home_agents_lock);
7960 +               return -ENOENT;
7961 +       }
7962 +       hashlist_delete(home_agents.entries, e);
7963 +       entry = (struct mipv6_halist_entry *)e;
7964 +       if (!ipv6_addr_any(&entry->link_local_addr)) {
7965 +               mipv6_ha_ac_del(&entry->link_local_addr, entry->ifindex, 
7966 +                               &entry->global_addr, entry->plen);
7967 +       }
7968 +       hashlist_free(home_agents.entries, e);
7969 +       write_unlock(&home_agents_lock);
7970 +       return 0;
7971 +}
7972 +
7973 +/**
7974 + * mipv6_ha_get_pref_list - Get list of preferred home agents
7975 + * @ifindex: interface identifier
7976 + * @addrs: pointer to a buffer to store the list
7977 + * @max: maximum number of home agents to return
7978 + *
7979 + * Creates a list of @max preferred (or all known if less than @max)
7980 + * home agents.  Home Agents List is interface specific so you must
7981 + * supply @ifindex.  Stores list in addrs and returns number of home
7982 + * agents stored.  On failure, returns a negative value.
7983 + **/
7984 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max)
7985 +{
7986 +       struct preflist_iterator_args args;
7987 +
7988 +       DEBUG_FUNC();
7989 +       if (max <= 0) {
7990 +               *addrs = NULL;
7991 +               return 0;
7992 +       }
7993 +
7994 +       args.count = 0;
7995 +       args.requested = max;
7996 +       args.ifindex = ifindex;
7997 +       args.list = kmalloc(max * sizeof(struct in6_addr), GFP_ATOMIC);
7998 +
7999 +       if (args.list == NULL) return -ENOMEM;
8000 +
8001 +       read_lock(&home_agents_lock);
8002 +       hashlist_iterate(home_agents.entries, &args, preflist_iterator);
8003 +       read_unlock(&home_agents_lock);
8004 +
8005 +       if (args.count >= 0) {
8006 +               *addrs = args.list;
8007 +       } else {
8008 +               kfree(args.list);
8009 +               *addrs = NULL;
8010 +       }
8011 +
8012 +       return args.count;
8013 +}
8014 +
8015 +struct getaddr_iterator_args {
8016 +       struct net_device *dev;
8017 +       struct in6_addr *addr;
8018 +};
8019 +
8020 +static int getaddr_iterator(void *data, void *args,
8021 +            unsigned long *pref)
8022 +{
8023 +       struct mipv6_halist_entry *entry =
8024 +               (struct mipv6_halist_entry *)data;
8025 +       struct getaddr_iterator_args *state =
8026 +               (struct getaddr_iterator_args *)args;
8027 +
8028 +       if (entry->ifindex != state->dev->ifindex)
8029 +               return ITERATOR_CONT;
8030 +
8031 +       if (ipv6_chk_addr(&entry->global_addr, state->dev)) {
8032 +               ipv6_addr_copy(state->addr, &entry->global_addr);
8033 +               return ITERATOR_STOP;
8034 +       }
8035 +       return ITERATOR_CONT;
8036 +}
8037 +
8038 +/*
8039 + * Get Home Agent Address for given interface.  If node is not serving
8040 + * as a HA for this interface returns negative error value.
8041 + */
8042 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr)
8043 +{
8044 +       struct getaddr_iterator_args args;
8045 +       struct net_device *dev;
8046 +
8047 +       if (ifindex <= 0)
8048 +               return -EINVAL;
8049 +
8050 +       if ((dev = dev_get_by_index(ifindex)) == NULL)
8051 +               return -ENODEV;
8052 +
8053 +       memset(addr, 0, sizeof(struct in6_addr));
8054 +       args.dev = dev;
8055 +       args.addr = addr;
8056 +       read_lock(&home_agents_lock);
8057 +       hashlist_iterate(home_agents.entries, &args, getaddr_iterator);
8058 +       read_unlock(&home_agents_lock);
8059 +       dev_put(dev);
8060 +
8061 +       if (ipv6_addr_any(addr))
8062 +               return -ENOENT;
8063 +       
8064 +       return 0;
8065 +}
8066 +
8067 +#define HALIST_INFO_LEN 81
8068 +
8069 +struct procinfo_iterator_args {
8070 +       char *buffer;
8071 +       int offset;
8072 +       int length;
8073 +       int skip;
8074 +       int len;
8075 +};
8076 +
8077 +static int procinfo_iterator(void *data, void *args,
8078 +                            unsigned long *pref)
8079 +{
8080 +       struct procinfo_iterator_args *arg =
8081 +               (struct procinfo_iterator_args *)args;
8082 +       struct mipv6_halist_entry *entry =
8083 +               (struct mipv6_halist_entry *)data;
8084 +       unsigned long int expire;
8085 +
8086 +       DEBUG_FUNC();
8087 +
8088 +       if (entry == NULL) return ITERATOR_ERR;
8089 +
8090 +       if (time_after(jiffies, entry->expire)) {
8091 +               if (!ipv6_addr_any(&entry->link_local_addr)) {
8092 +                       mipv6_ha_ac_del(&entry->link_local_addr, 
8093 +                                       entry->ifindex, 
8094 +                                       &entry->global_addr, entry->plen);
8095 +               }
8096 +               return ITERATOR_DELETE_ENTRY;
8097 +       }
8098 +       if (arg->skip < arg->offset / HALIST_INFO_LEN) {
8099 +               arg->skip++;
8100 +               return ITERATOR_CONT;
8101 +       }
8102 +
8103 +       if (arg->len >= arg->length)
8104 +               return ITERATOR_CONT;
8105 +
8106 +       expire = (entry->expire - jiffies) / HZ;
8107 +
8108 +       arg->len += sprintf(arg->buffer + arg->len, 
8109 +                           "%02d %08x%08x%08x%08x %08x%08x%08x%08x %05ld %05ld\n",
8110 +                           entry->ifindex,
8111 +                           ntohl(entry->global_addr.s6_addr32[0]),
8112 +                           ntohl(entry->global_addr.s6_addr32[1]),
8113 +                           ntohl(entry->global_addr.s6_addr32[2]),
8114 +                           ntohl(entry->global_addr.s6_addr32[3]),
8115 +                           ntohl(entry->link_local_addr.s6_addr32[0]),
8116 +                           ntohl(entry->link_local_addr.s6_addr32[1]),
8117 +                           ntohl(entry->link_local_addr.s6_addr32[2]),
8118 +                           ntohl(entry->link_local_addr.s6_addr32[3]),
8119 +                           -(entry->preference - PREF_BASE), expire);
8120 +
8121 +       return ITERATOR_CONT;
8122 +}
8123 +
8124 +static int halist_proc_info(char *buffer, char **start, off_t offset,
8125 +                            int length)
8126 +{
8127 +       struct procinfo_iterator_args args;
8128 +
8129 +       DEBUG_FUNC();
8130 +
8131 +       args.buffer = buffer;
8132 +       args.offset = offset;
8133 +       args.length = length;
8134 +       args.skip = 0;
8135 +       args.len = 0;
8136 +
8137 +       read_lock_bh(&home_agents_lock);
8138 +       hashlist_iterate(home_agents.entries, &args, procinfo_iterator);
8139 +       read_unlock_bh(&home_agents_lock);
8140 +
8141 +       *start = buffer;
8142 +       if (offset)
8143 +               *start += offset % HALIST_INFO_LEN;
8144 +
8145 +       args.len -= offset % HALIST_INFO_LEN;
8146 +
8147 +       if (args.len > length)
8148 +               args.len = length;
8149 +       if (args.len < 0)
8150 +               args.len = 0;
8151 +       
8152 +       return args.len;
8153 +}
8154 +
8155 +static int halist_compare(void *data, void *hashkey)
8156 +{
8157 +       struct mipv6_halist_entry *e = (struct mipv6_halist_entry *)data;
8158 +       struct in6_addr *key = (struct in6_addr *)hashkey;
8159 +
8160 +       return ipv6_addr_cmp(&e->global_addr, key);
8161 +}
8162 +
8163 +static __u32 halist_hash(void *hashkey)
8164 +{
8165 +       struct in6_addr *key = (struct in6_addr *)hashkey;
8166 +       __u32 hash;
8167 +
8168 +       hash = key->s6_addr32[0] ^
8169 +                key->s6_addr32[1] ^
8170 +                key->s6_addr32[2] ^
8171 +                key->s6_addr32[3];
8172 +
8173 +       return hash;
8174 +}
8175 +
8176 +int __init mipv6_halist_init(__u32 size)
8177 +{
8178 +       DEBUG_FUNC();
8179 +
8180 +       if (size <= 0) {
8181 +               DEBUG(DBG_ERROR, "size must be at least 1");
8182 +               return -EINVAL;
8183 +       }
8184 +       init_timer(&home_agents.expire_timer);
8185 +       home_agents.expire_timer.data = 0;
8186 +       home_agents.expire_timer.function = mipv6_halist_expire;
8187 +       home_agents_lock = RW_LOCK_UNLOCKED;
8188 +
8189 +       home_agents.entries = hashlist_create(16, size, sizeof(struct mipv6_halist_entry),
8190 +                                              "mip6_halist", NULL, NULL,
8191 +                                              halist_compare, halist_hash);
8192 +
8193 +       if (home_agents.entries == NULL) {
8194 +               DEBUG(DBG_ERROR, "Failed to initialize hashlist");
8195 +               return -ENOMEM;
8196 +       }
8197 +
8198 +       proc_net_create("mip6_home_agents", 0, halist_proc_info);
8199 +       DEBUG(DBG_INFO, "Home Agents List initialized");
8200 +       return 0;
8201 +}
8202 +
8203 +void __exit mipv6_halist_exit(void)
8204 +{
8205 +       DEBUG_FUNC();
8206 +       proc_net_remove("mip6_home_agents");
8207 +       write_lock_bh(&home_agents_lock);
8208 +       DEBUG(DBG_INFO, "Stopping the halist timer");
8209 +       del_timer(&home_agents.expire_timer);
8210 +       mipv6_halist_gc(1);
8211 +       write_unlock_bh(&home_agents_lock);
8212 +       hashlist_destroy(home_agents.entries);
8213 +}
8214 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/halist.h linux-2.4.25/net/ipv6/mobile_ip6/halist.h
8215 --- linux-2.4.25.old/net/ipv6/mobile_ip6/halist.h       1970-01-01 01:00:00.000000000 +0100
8216 +++ linux-2.4.25/net/ipv6/mobile_ip6/halist.h   2004-06-26 11:29:30.000000000 +0100
8217 @@ -0,0 +1,28 @@
8218 +/*
8219 + *      MIPL Mobile IPv6 Home Agents List header file      
8220 + *
8221 + *      $Id$
8222 + *
8223 + *      This program is free software; you can redistribute it and/or
8224 + *      modify it under the terms of the GNU General Public License
8225 + *      as published by the Free Software Foundation; either version
8226 + *      2 of the License, or (at your option) any later version.
8227 + */
8228 +
8229 +#ifndef _HALIST_H
8230 +#define _HALIST_H
8231 +
8232 +int mipv6_halist_init(__u32 size);
8233 +
8234 +void mipv6_halist_exit(void);
8235 +
8236 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
8237 +                    struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime);
8238 +
8239 +int mipv6_halist_delete(struct in6_addr *glob_addr);
8240 +
8241 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max);
8242 +
8243 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr);
8244 +
8245 +#endif /* _HALIST_H */
8246 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.c linux-2.4.25/net/ipv6/mobile_ip6/hashlist.c
8247 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.c     1970-01-01 01:00:00.000000000 +0100
8248 +++ linux-2.4.25/net/ipv6/mobile_ip6/hashlist.c 2004-06-26 11:29:31.000000000 +0100
8249 @@ -0,0 +1,351 @@
8250 +/*
8251 + *     Generic hashtable with chaining.  Supports secodary sort order
8252 + *     with doubly linked-list.
8253 + *
8254 + *     Authors:
8255 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
8256 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
8257 + *
8258 + *     $Id: s.hashlist.c 1.21 02/10/07 19:31:52+03:00 antti@traci.mipl.mediapoli.com $
8259 + *
8260 + *     This program is free software; you can redistribute it and/or
8261 + *     modify it under the terms of the GNU General Public License as
8262 + *     published by the Free Software Foundation; either version 2 of
8263 + *     the License, or (at your option) any later version.
8264 + */
8265 +
8266 +#include <linux/slab.h>
8267 +#include "hashlist.h"
8268 +#include "debug.h"
8269 +
8270 +struct hashlist {
8271 +       int count;              /* entry count  */
8272 +       int maxcount;           /* max entries  */
8273 +       __u32 bucketnum;        /* hash buckets */
8274 +
8275 +       kmem_cache_t *kmem;
8276 +
8277 +       struct list_head *hashtable;
8278 +       struct list_head sortedlist;
8279 +
8280 +       int (*compare)(void *data, void *hashkey);
8281 +       __u32 (*hash_function)(void *hashkey);
8282 +};
8283 +
8284 +/**
8285 + * hashlist_create - Create new hashlist
8286 + * @bucketnum: number of hash buckets
8287 + * @maxentries: maximum number of entries (0 = no limit)
8288 + * @size: entry size in bytes
8289 + * @name: name for kmem_cache_t
8290 + * @ctor: kmem_cache_t constructor
8291 + * @dtor: kmem_cache_t destructor
8292 + * @compare: compare function for key
8293 + * @hash_function: hash function
8294 + *
8295 + * Creates a hashlist structure with @max_entries entries of @size
8296 + * bytes.  User must supply @hash_function and @compare function for
8297 + * the hashlist.  User can also supply @ctor and @dtor for kmem_cache.
8298 + **/
8299 +struct hashlist *hashlist_create(int bucketnum, int max_entries, size_t size,
8300 +                                char *name,
8301 +                                void (*ctor)(void *, kmem_cache_t *, unsigned long),
8302 +                                void (*dtor)(void *, kmem_cache_t *, unsigned long),
8303 +                                int (*compare)(void *data, void *hashkey),
8304 +                                __u32 (*hash_function)(void *hashkey))
8305 +{
8306 +       int i;
8307 +       struct hashlist *hl;
8308 +
8309 +       if (!compare || !hash_function)
8310 +               goto hlfailed;
8311 +
8312 +       hl = kmalloc(sizeof(struct hashlist), GFP_ATOMIC);
8313 +       if (!hl) goto hlfailed;
8314 +
8315 +       hl->kmem = kmem_cache_create(name, size, 0, 0, ctor, dtor);
8316 +       if (!hl->kmem) goto poolfailed;
8317 +
8318 +       hl->hashtable = kmalloc(
8319 +               sizeof(struct list_head) * bucketnum, GFP_ATOMIC);
8320 +       if (!hl->hashtable) goto hashfailed;
8321 +
8322 +       for (i = 0; i < bucketnum; i++)
8323 +               INIT_LIST_HEAD(&hl->hashtable[i]);
8324 +
8325 +       INIT_LIST_HEAD(&hl->sortedlist);
8326 +
8327 +       hl->maxcount = max_entries;
8328 +       hl->count = 0;
8329 +       hl->bucketnum = bucketnum;
8330 +       hl->compare = compare;
8331 +       hl->hash_function = hash_function;
8332 +
8333 +       return hl;
8334 +
8335 +hashfailed:
8336 +       kmem_cache_destroy(hl->kmem);
8337 +       hl->kmem = NULL;
8338 +
8339 +poolfailed:
8340 +       kfree(hl);
8341 +
8342 +hlfailed:
8343 +       DEBUG(DBG_ERROR, "could not create hashlist");
8344 +
8345 +       return NULL;    
8346 +}
8347 +
8348 +/**
8349 + * hashlist_destroy - Destroy hashlist
8350 + * @hashlist: hashlist to destroy
8351 + *
8352 + * Frees all memory allocated for a hashlist.
8353 + **/
8354 +void hashlist_destroy(struct hashlist *hashlist)
8355 +{
8356 +       DEBUG_FUNC();
8357 +
8358 +       if (hashlist == NULL) return;
8359 +
8360 +       if (hashlist->hashtable) {
8361 +               kfree(hashlist->hashtable);
8362 +               hashlist->hashtable = NULL;
8363 +       }
8364 +
8365 +       if (hashlist->kmem) {
8366 +               kmem_cache_destroy(hashlist->kmem);
8367 +               hashlist->kmem = NULL;
8368 +       }
8369 +
8370 +       kfree(hashlist);
8371 +
8372 +       return;
8373 +}
8374 +
8375 +/*
8376 + * Insert a chain of entries to hashlist into correct order.  The
8377 + * entries are assumed to have valid hashkeys.  We use time_after_eq
8378 + * for comparing, since it handles wrap-around correctly, and the
8379 + * sortkey is usually jiffies.
8380 + */
8381 +static void sorted_insert(struct list_head *lh, struct hashlist_entry *he)
8382 +{
8383 +       struct list_head *p;
8384 +       struct hashlist_entry *hlp = NULL;
8385 +       unsigned long sortkey = he->sortkey;
8386 +
8387 +       if (list_empty(lh)) {
8388 +               list_add(&he->sorted, lh);
8389 +               return;
8390 +       }
8391 +       
8392 +       list_for_each(p, lh) {
8393 +               hlp = list_entry(p, typeof(*hlp), sorted);
8394 +               if (time_after_eq(hlp->sortkey, sortkey)) {
8395 +                       list_add(&he->sorted, hlp->sorted.prev);
8396 +                       return;
8397 +               }
8398 +       }
8399 +       list_add(&he->sorted, &hlp->sorted);
8400 +}
8401 +
8402 +/**
8403 + * hashlist_iterate - Apply function for all elements in a hash list
8404 + * @hashlist: pointer to hashlist
8405 + * @args: data to pass to the function
8406 + * @func: pointer to a function
8407 + *
8408 + * Apply arbitrary function @func to all elements in a hash list.
8409 + * @func must be a pointer to a function with the following prototype:
8410 + * int func(void *entry, void *arg, struct in6_addr *hashkey, unsigned
8411 + * long *sortkey).  Function must return %ITERATOR_STOP,
8412 + * %ITERATOR_CONT or %ITERATOR_DELETE_ENTRY.  %ITERATOR_STOP stops
8413 + * iterator and returns last return value from the function.
8414 + * %ITERATOR_CONT continues with iteration.  %ITERATOR_DELETE_ENTRY
8415 + * deletes current entry from the hashlist.  If function changes
8416 + * hashlist element's sortkey, iterator automatically schedules
8417 + * element to be reinserted after all elements have been processed.
8418 + */
8419 +int hashlist_iterate(
8420 +       struct hashlist *hashlist, void *args,
8421 +       hashlist_iterator_t func)
8422 +{
8423 +       int res = ITERATOR_CONT;
8424 +       unsigned long skey;
8425 +       struct list_head *p, *n, repos;
8426 +       struct hashlist_entry *he;
8427 +
8428 +       DEBUG_FUNC();
8429 +       INIT_LIST_HEAD(&repos);
8430 +
8431 +       list_for_each_safe(p, n, &hashlist->sortedlist) {
8432 +               he = list_entry(p, typeof(*he), sorted);
8433 +               if (res == ITERATOR_STOP)
8434 +                       break;
8435 +               skey = he->sortkey;
8436 +               res = func(he, args, &he->sortkey);
8437 +               if (res == ITERATOR_DELETE_ENTRY) {
8438 +                       hashlist_delete(hashlist, he);
8439 +                       hashlist_free(hashlist, he);
8440 +               } else if (skey != he->sortkey) {
8441 +                       /* iterator changed the sortkey, schedule for
8442 +                        * repositioning */
8443 +                       list_move(&he->sorted, &repos);
8444 +               }
8445 +       }
8446 +       list_for_each_safe(p, n, &repos) {      
8447 +               he = list_entry(p, typeof(*he), sorted);
8448 +               sorted_insert(&hashlist->sortedlist, he);
8449 +       }
8450 +       return res;
8451 +}
8452 +
8453 +/**
8454 + * hashlist_alloc - Allocate memory for a hashlist entry
8455 + * @hashlist: hashlist for allocated entry
8456 + * @size: size of entry in bytes
8457 + *
8458 + * Allocates @size bytes memory from @hashlist->kmem.
8459 + **/
8460 +void *hashlist_alloc(struct hashlist *hashlist, int type)
8461 +{
8462 +       if (hashlist == NULL) return NULL;
8463 +       return kmem_cache_alloc(hashlist->kmem, type);
8464 +}
8465 +
8466 +/**
8467 + * hashlist_free - Free hashlist entry
8468 + * @hashlist: hashlist where @he is
8469 + * @he: entry to free
8470 + *
8471 + * Frees an allocated hashlist entry.
8472 + **/
8473 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he)
8474 +{
8475 +       kmem_cache_free(hashlist->kmem, he);
8476 +}
8477 +
8478 +/**
8479 + * hashlist_add - Add element to hashlist
8480 + * @hashlist: pointer to hashlist
8481 + * @hashkey: hashkey for the element
8482 + * @sortkey: key for sorting
8483 + * @data: element data
8484 + *
8485 + * Add element to hashlist.  Hashlist is also sorted in a linked list
8486 + * by @sortkey.
8487 + */
8488 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8489 +                unsigned long sortkey, void *entry)
8490 +{
8491 +       struct hashlist_entry *he = (struct hashlist_entry *)entry;
8492 +       unsigned int hash;
8493 +
8494 +       if (hashlist->count >= hashlist->maxcount)
8495 +               return -1;
8496 +
8497 +       hashlist->count++;
8498 +
8499 +       /*  link the entry to sorted order  */ 
8500 +       he->sortkey = sortkey;
8501 +       sorted_insert(&hashlist->sortedlist, he);
8502 +
8503 +       /*  hash the entry  */
8504 +       hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8505 +       list_add(&he->hashlist, &hashlist->hashtable[hash]);
8506 +
8507 +       return 0;
8508 +}
8509 +
8510 +/**
8511 + * hashlist_get_ex - Get element from hashlist
8512 + * @hashlist: hashlist
8513 + * @hashkey: hashkey of the desired entry
8514 + *
8515 + * Lookup entry with @hashkey from the hash table using @compare
8516 + * function for entry comparison.  Returns entry on success, otherwise
8517 + * %NULL.
8518 + **/
8519 +struct hashlist_entry *hashlist_get_ex(
8520 +       struct hashlist *hashlist, void *hashkey,
8521 +       int (*compare)(void *data, void *hashkey))
8522 +{
8523 +       struct list_head *p, *bkt;
8524 +       __u32 hash;
8525 +
8526 +       hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8527 +       bkt = &hashlist->hashtable[hash];
8528 +
8529 +       /*  scan the entries within the same hashbucket  */
8530 +       list_for_each(p, bkt) {
8531 +               struct hashlist_entry *he = list_entry(p, typeof(*he), 
8532 +                                                      hashlist);
8533 +               if (compare(he, hashkey) == 0)
8534 +                       return he;
8535 +       }
8536 +
8537 +       return NULL;
8538 +}
8539 +
8540 +/**
8541 + * hashlist_get - Get element from hashlist
8542 + * @hashlist: hashlist
8543 + * @hashkey: hashkey of the desired entry
8544 + *
8545 + * Lookup entry with @hashkey from the hash table.  Returns entry on
8546 + * success, otherwise %NULL.
8547 + **/
8548 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey)
8549 +{
8550 +       return hashlist_get_ex(hashlist, hashkey, hashlist->compare);
8551 +}
8552 +
8553 +/**
8554 + * hashlist_reposition - set entry to new position in the list
8555 + * @hashlist: hashlist
8556 + * @he: entry to reposition
8557 + * @sortkey: new sortkey of the entry
8558 + *
8559 + * If secondary order sortkey changes, entry must be repositioned in
8560 + * the sorted list.
8561 + **/
8562 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8563 +                       unsigned long sortkey)
8564 +{
8565 +       list_del(&he->sorted);
8566 +       he->sortkey = sortkey;
8567 +       sorted_insert(&hashlist->sortedlist, he);
8568 +
8569 +       return 0;
8570 +}
8571 +
8572 +/**
8573 + * hashlist_delete - Delete entry from hashlist
8574 + * @hashlist: hashlist where entry is
8575 + * @he: entry to delete
8576 + *
8577 + * Deletes an entry from the hashlist and sorted list.
8578 + **/
8579 +void hashlist_delete(struct hashlist *hashlist,
8580 +                    struct hashlist_entry *he)
8581 +{
8582 +       list_del_init(&he->hashlist);
8583 +       list_del_init(&he->sorted);
8584 +
8585 +       hashlist->count--;
8586 +}
8587 +
8588 +/**
8589 + * hashlist_get_first - Get first item from sorted list
8590 + * @hashlist: pointer to hashlist
8591 + *
8592 + * Returns first item in the secondary sort order.
8593 + **/
8594 +void * hashlist_get_first(struct hashlist *hashlist)
8595 +{
8596 +       if (list_empty(&hashlist->sortedlist))
8597 +               return NULL;
8598 +       
8599 +       return list_entry(hashlist->sortedlist.next, struct hashlist_entry, sorted);
8600 +}
8601 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.h linux-2.4.25/net/ipv6/mobile_ip6/hashlist.h
8602 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.h     1970-01-01 01:00:00.000000000 +0100
8603 +++ linux-2.4.25/net/ipv6/mobile_ip6/hashlist.h 2004-06-26 11:29:31.000000000 +0100
8604 @@ -0,0 +1,63 @@
8605 +/*
8606 + *     MIPL Mobile IPv6 Hashlist header file
8607 + *
8608 + *     $Id$
8609 + *
8610 + *     This program is free software; you can redistribute it and/or
8611 + *      modify it under the terms of the GNU General Public License
8612 + *      as published by the Free Software Foundation; either version
8613 + *      2 of the License, or (at your option) any later version.
8614 + */
8615 +
8616 +#ifndef _HASHLIST_H
8617 +#define _HASHLIST_H
8618 +
8619 +#define ITERATOR_ERR -1
8620 +#define ITERATOR_CONT 0
8621 +#define ITERATOR_STOP 1
8622 +#define ITERATOR_DELETE_ENTRY 2
8623 +
8624 +struct kmem_cache_t;
8625 +
8626 +struct hashlist_entry {
8627 +       unsigned long sortkey;
8628 +       struct list_head sorted;
8629 +       struct list_head hashlist;
8630 +};
8631 +
8632 +struct hashlist * hashlist_create(
8633 +       int bucketnum, int max_entries, size_t size, char *name,
8634 +       void (*ctor)(void *, kmem_cache_t *, unsigned long),
8635 +       void (*dtor)(void *, kmem_cache_t *, unsigned long),
8636 +       int (*compare)(void *data, void *hashkey),
8637 +       __u32 (*hash_function)(void *hashkey));
8638 +
8639 +void hashlist_destroy(struct hashlist *hashlist);
8640 +
8641 +void *hashlist_alloc(struct hashlist *hashlist, int type);
8642 +
8643 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he);
8644 +
8645 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey);
8646 +
8647 +struct hashlist_entry *hashlist_get_ex(
8648 +       struct hashlist *hashlist, void *hashkey,
8649 +       int (*compare)(void *data, void *hashkey));
8650 +
8651 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8652 +                unsigned long sortkey, void *data);
8653 +
8654 +void hashlist_delete(struct hashlist *hashlist, struct hashlist_entry *he);
8655 +
8656 +/* iterator function */
8657 +typedef int (*hashlist_iterator_t)(void *, void *, unsigned long *);
8658 +
8659 +int hashlist_iterate(struct hashlist *hashlist, void *args,
8660 +                    hashlist_iterator_t func);
8661 +
8662 +void * hashlist_get_first(struct hashlist *hashlist);
8663 +
8664 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8665 +                       unsigned long sortkey);
8666 +
8667 +#endif
8668 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.c linux-2.4.25/net/ipv6/mobile_ip6/hmac.c
8669 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.c 1970-01-01 01:00:00.000000000 +0100
8670 +++ linux-2.4.25/net/ipv6/mobile_ip6/hmac.c     2004-06-26 11:29:31.000000000 +0100
8671 @@ -0,0 +1,658 @@
8672 +/*     Authentication algorithms       
8673 + *     
8674 + *      Authors: 
8675 + *       Alexis Olivereau              <Alexis.Olivereau@crm.mot.com>
8676 + * 
8677 + *      $Id$
8678 + *
8679 + *      This program is free software; you can redistribute it and/or
8680 + *      modify it under the terms of the GNU General Public License
8681 + *      as published by the Free Software Foundation; either version
8682 + *      2 of the License, or (at your option) any later version.
8683 + *
8684 + *      Changes: 
8685 + *      Henrik Petander     :     Cleaned up unused parts
8686 + *
8687 + */
8688 +
8689 +#include <linux/sched.h>
8690 +#include <linux/tty.h>
8691 +#include <linux/types.h>
8692 +#include <linux/slab.h>
8693 +#include <linux/in6.h>
8694 +
8695 +#include "hmac.h"
8696 +#define LROLL(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
8697 +
8698 +/* MD5 */
8699 +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8700 +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
8701 +#define H(x, y, z) ((x) ^ (y) ^ (z))
8702 +#define I(x, y, z) ((y) ^ ((x) | ~(z)))
8703 +
8704 +#define FF(a, b, c, d, m, s, t) { \
8705 + (a) += F ((b), (c), (d)) + (m) + (t); \
8706 + (a) = LROLL((a), (s)); \
8707 + (a) += (b); \
8708 + }
8709 +#define GG(a, b, c, d, m, s, t) { \
8710 + (a) += G ((b), (c), (d)) + (m) + (t); \
8711 + (a) = LROLL((a), (s)); \
8712 + (a) += (b); \
8713 + }
8714 +#define HH(a, b, c, d, m, s, t) { \
8715 + (a) += H ((b), (c), (d)) + (m) + (t); \
8716 + (a) = LROLL((a), (s)); \
8717 + (a) += (b); \
8718 + }
8719 +#define II(a, b, c, d, m, s, t) { \
8720 + (a) += I ((b), (c), (d)) + (m) + (t); \
8721 + (a) = LROLL((a), (s)); \
8722 + (a) += (b); \
8723 + }
8724 +
8725 +#define s11  7
8726 +#define s12 12
8727 +#define s13 17
8728 +#define s14 22
8729 +#define s21  5
8730 +#define s22  9
8731 +#define s23 14
8732 +#define s24 20
8733 +#define s31  4
8734 +#define s32 11
8735 +#define s33 16
8736 +#define s34 23
8737 +#define s41  6
8738 +#define s42 10
8739 +#define s43 15
8740 +#define s44 21
8741 +
8742 +/* SHA-1 */
8743 +#define f(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8744 +#define g(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
8745 +#define h(x, y, z) ((x) ^ (y) ^ (z))
8746 +
8747 +#define K1 0x5a827999
8748 +#define K2 0x6ed9eba1
8749 +#define K3 0x8f1bbcdc
8750 +#define K4 0xca62c1d6
8751 +
8752 +int ah_hmac_md5_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8753 +{
8754 +       int i;
8755 +       int key_up4;
8756 +       uint32_t ipad = 0x36363636;
8757 +       uint8_t extkey[64];
8758 +
8759 +       ahp->key_auth = key;
8760 +       ahp->key_auth_len = key_len;
8761 +       ahp->context = (void *) kmalloc(sizeof(MD5_CTX), GFP_ATOMIC);
8762 +       if (ahp->context == NULL)
8763 +               return -1;
8764 +       md5_init((MD5_CTX *) ahp->context);
8765 +       if ((64 * sizeof(uint8_t)) < ahp->key_auth_len) {
8766 +               printk("buffer overflow!");
8767 +               return -1;
8768 +       }
8769 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8770 +       if (ahp->key_auth_len % 4) {
8771 +               memset(extkey + ahp->key_auth_len, 0,
8772 +                      4 - (ahp->key_auth_len % 4));
8773 +       }
8774 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8775 +
8776 +       for (i = 0; i < key_up4; i++)
8777 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8778 +       for (i = key_up4; i < 16; i++)
8779 +               ((uint32_t *) extkey)[i] = ipad;
8780 +
8781 +       md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8782 +       return 0;
8783 +}
8784 +
8785 +void ah_hmac_md5_loop(struct ah_processing *ahp, void *str, uint32_t len)
8786 +{
8787 +       md5_compute((MD5_CTX *) ahp->context, str, len);
8788 +}
8789 +
8790 +void ah_hmac_md5_result(struct ah_processing *ahp, char *digest)
8791 +{
8792 +       uint8_t inner[HMAC_MD5_HASH_LEN];
8793 +       int i;
8794 +       int key_up4;
8795 +       uint32_t opad = 0x5c5c5c5c;
8796 +       uint8_t extkey[64];
8797 +
8798 +       md5_final((MD5_CTX *) ahp->context, inner);
8799 +       md5_init((MD5_CTX *) ahp->context);
8800 +
8801 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8802 +       if (ahp->key_auth_len % 4) {
8803 +               memset(extkey + ahp->key_auth_len, 0,
8804 +                      4 - (ahp->key_auth_len % 4));
8805 +       }
8806 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8807 +
8808 +       for (i = 0; i < key_up4; i++)
8809 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8810 +       for (i = key_up4; i < 16; i++)
8811 +               ((uint32_t *) extkey)[i] = opad;
8812 +
8813 +       md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8814 +       md5_compute((MD5_CTX *) ahp->context, inner, HMAC_MD5_HASH_LEN);
8815 +
8816 +       md5_final((MD5_CTX *) ahp->context, digest);
8817 +
8818 +       kfree(ahp->context);
8819 +}
8820 +
8821 +int ah_hmac_sha1_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8822 +{
8823 +       int i;
8824 +       int key_up4;
8825 +       uint32_t ipad = 0x36363636;
8826 +       uint8_t extkey[64];
8827 +
8828 +       ahp->key_auth = key;
8829 +       ahp->key_auth_len = key_len;
8830 +
8831 +       ahp->context = (void *) kmalloc(sizeof(SHA1_CTX), GFP_ATOMIC);
8832 +       //if (ahp->context == NULL)
8833 +       //      return -1;
8834 +
8835 +       sha1_init((SHA1_CTX *) ahp->context);
8836 +
8837 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8838 +       if (ahp->key_auth_len % 4) {
8839 +               memset(extkey + ahp->key_auth_len, 0,
8840 +                      4 - (ahp->key_auth_len % 4));
8841 +       }
8842 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8843 +
8844 +       for (i = 0; i < key_up4; i++)
8845 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8846 +       for (i = key_up4; i < 16; i++)
8847 +               ((uint32_t *) extkey)[i] = ipad;
8848 +
8849 +       sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8850 +       return 0;
8851 +}
8852 +
8853 +void ah_hmac_sha1_loop(struct ah_processing *ahp, void *str, uint32_t len)
8854 +{
8855 +       if (!ahp)
8856 +               return;
8857 +       sha1_compute((SHA1_CTX *) ahp->context, str, len);
8858 +}
8859 +
8860 +void ah_hmac_sha1_result(struct ah_processing *ahp, char *digest)
8861 +{
8862 +       uint8_t inner[HMAC_SHA1_HASH_LEN];
8863 +       int i;
8864 +       int key_up4;
8865 +       uint32_t opad = 0x5c5c5c5c;
8866 +       uint8_t extkey[64];
8867 +
8868 +       if (!ahp)
8869 +               return;
8870 +       sha1_final((SHA1_CTX *) ahp->context, inner);
8871 +       sha1_init((SHA1_CTX *) ahp->context);
8872 +
8873 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8874 +       if (ahp->key_auth_len % 4) {
8875 +               memset(extkey + ahp->key_auth_len, 0,
8876 +                      4 - (ahp->key_auth_len % 4));
8877 +       }
8878 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8879 +
8880 +       for (i = 0; i < key_up4; i++)
8881 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8882 +       for (i = key_up4; i < 16; i++)
8883 +               ((uint32_t *) extkey)[i] = opad;
8884 +
8885 +       sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8886 +       sha1_compute((SHA1_CTX *) ahp->context, inner,
8887 +                    HMAC_SHA1_HASH_LEN);
8888 +
8889 +       sha1_final((SHA1_CTX *) ahp->context, digest);
8890 +
8891 +       kfree(ahp->context);
8892 +}
8893 +
8894 +void md5_init(MD5_CTX * ctx)
8895 +{
8896 +       ctx->A = 0x67452301;
8897 +       ctx->B = 0xefcdab89;
8898 +       ctx->C = 0x98badcfe;
8899 +       ctx->D = 0x10325476;
8900 +       ctx->buf_cur = ctx->buf;
8901 +       ctx->bitlen[0] = ctx->bitlen[1] = 0;
8902 +       memset(ctx->buf, 0, 64);
8903 +}
8904 +
8905 +void md5_over_block(MD5_CTX * ctx, uint8_t * data)
8906 +{
8907 +       uint32_t M[16];
8908 +       uint32_t a = ctx->A;
8909 +       uint32_t b = ctx->B;
8910 +       uint32_t c = ctx->C;
8911 +       uint32_t d = ctx->D;
8912 +
8913 +       create_M_blocks(M, data);
8914 +
8915 +       /* Round 1 */
8916 +       FF(a, b, c, d, M[0], s11, 0xd76aa478);  /*  1 */
8917 +       FF(d, a, b, c, M[1], s12, 0xe8c7b756);  /*  2 */
8918 +       FF(c, d, a, b, M[2], s13, 0x242070db);  /*  3 */
8919 +       FF(b, c, d, a, M[3], s14, 0xc1bdceee);  /*  4 */
8920 +       FF(a, b, c, d, M[4], s11, 0xf57c0faf);  /*  5 */
8921 +       FF(d, a, b, c, M[5], s12, 0x4787c62a);  /*  6 */
8922 +       FF(c, d, a, b, M[6], s13, 0xa8304613);  /*  7 */
8923 +       FF(b, c, d, a, M[7], s14, 0xfd469501);  /*  8 */
8924 +       FF(a, b, c, d, M[8], s11, 0x698098d8);  /*  9 */
8925 +       FF(d, a, b, c, M[9], s12, 0x8b44f7af);  /* 10 */
8926 +       FF(c, d, a, b, M[10], s13, 0xffff5bb1); /* 11 */
8927 +       FF(b, c, d, a, M[11], s14, 0x895cd7be); /* 12 */
8928 +       FF(a, b, c, d, M[12], s11, 0x6b901122); /* 13 */
8929 +       FF(d, a, b, c, M[13], s12, 0xfd987193); /* 14 */
8930 +       FF(c, d, a, b, M[14], s13, 0xa679438e); /* 15 */
8931 +       FF(b, c, d, a, M[15], s14, 0x49b40821); /* 16 */
8932 +
8933 +       /* Round 2 */
8934 +       GG(a, b, c, d, M[1], s21, 0xf61e2562);  /* 17 */
8935 +       GG(d, a, b, c, M[6], s22, 0xc040b340);  /* 18 */
8936 +       GG(c, d, a, b, M[11], s23, 0x265e5a51); /* 19 */
8937 +       GG(b, c, d, a, M[0], s24, 0xe9b6c7aa);  /* 20 */
8938 +       GG(a, b, c, d, M[5], s21, 0xd62f105d);  /* 21 */
8939 +       GG(d, a, b, c, M[10], s22, 0x02441453); /* 22 */
8940 +       GG(c, d, a, b, M[15], s23, 0xd8a1e681); /* 23 */
8941 +       GG(b, c, d, a, M[4], s24, 0xe7d3fbc8);  /* 24 */
8942 +       GG(a, b, c, d, M[9], s21, 0x21e1cde6);  /* 25 */
8943 +       GG(d, a, b, c, M[14], s22, 0xc33707d6); /* 26 */
8944 +       GG(c, d, a, b, M[3], s23, 0xf4d50d87);  /* 27 */
8945 +       GG(b, c, d, a, M[8], s24, 0x455a14ed);  /* 28 */
8946 +       GG(a, b, c, d, M[13], s21, 0xa9e3e905); /* 29 */
8947 +       GG(d, a, b, c, M[2], s22, 0xfcefa3f8);  /* 30 */
8948 +       GG(c, d, a, b, M[7], s23, 0x676f02d9);  /* 31 */
8949 +       GG(b, c, d, a, M[12], s24, 0x8d2a4c8a); /* 32 */
8950 +
8951 +       /* Round 3 */
8952 +       HH(a, b, c, d, M[5], s31, 0xfffa3942);  /* 33 */
8953 +       HH(d, a, b, c, M[8], s32, 0x8771f681);  /* 34 */
8954 +       HH(c, d, a, b, M[11], s33, 0x6d9d6122); /* 35 */
8955 +       HH(b, c, d, a, M[14], s34, 0xfde5380c); /* 36 */
8956 +       HH(a, b, c, d, M[1], s31, 0xa4beea44);  /* 37 */
8957 +       HH(d, a, b, c, M[4], s32, 0x4bdecfa9);  /* 38 */
8958 +       HH(c, d, a, b, M[7], s33, 0xf6bb4b60);  /* 39 */
8959 +       HH(b, c, d, a, M[10], s34, 0xbebfbc70); /* 40 */
8960 +       HH(a, b, c, d, M[13], s31, 0x289b7ec6); /* 41 */
8961 +       HH(d, a, b, c, M[0], s32, 0xeaa127fa);  /* 42 */
8962 +       HH(c, d, a, b, M[3], s33, 0xd4ef3085);  /* 43 */
8963 +       HH(b, c, d, a, M[6], s34, 0x4881d05);   /* 44 */
8964 +       HH(a, b, c, d, M[9], s31, 0xd9d4d039);  /* 45 */
8965 +       HH(d, a, b, c, M[12], s32, 0xe6db99e5); /* 46 */
8966 +       HH(c, d, a, b, M[15], s33, 0x1fa27cf8); /* 47 */
8967 +       HH(b, c, d, a, M[2], s34, 0xc4ac5665);  /* 48 */
8968 +
8969 +       /* Round 4 */
8970 +       II(a, b, c, d, M[0], s41, 0xf4292244);  /* 49 */
8971 +       II(d, a, b, c, M[7], s42, 0x432aff97);  /* 50 */
8972 +       II(c, d, a, b, M[14], s43, 0xab9423a7); /* 51 */
8973 +       II(b, c, d, a, M[5], s44, 0xfc93a039);  /* 52 */
8974 +       II(a, b, c, d, M[12], s41, 0x655b59c3); /* 53 */
8975 +       II(d, a, b, c, M[3], s42, 0x8f0ccc92);  /* 54 */
8976 +       II(c, d, a, b, M[10], s43, 0xffeff47d); /* 55 */
8977 +       II(b, c, d, a, M[1], s44, 0x85845dd1);  /* 56 */
8978 +       II(a, b, c, d, M[8], s41, 0x6fa87e4f);  /* 57 */
8979 +       II(d, a, b, c, M[15], s42, 0xfe2ce6e0); /* 58 */
8980 +       II(c, d, a, b, M[6], s43, 0xa3014314);  /* 59 */
8981 +       II(b, c, d, a, M[13], s44, 0x4e0811a1); /* 60 */
8982 +       II(a, b, c, d, M[4], s41, 0xf7537e82);  /* 61 */
8983 +       II(d, a, b, c, M[11], s42, 0xbd3af235); /* 62 */
8984 +       II(c, d, a, b, M[2], s43, 0x2ad7d2bb);  /* 63 */
8985 +       II(b, c, d, a, M[9], s44, 0xeb86d391);  /* 64 */
8986 +
8987 +       ctx->A += a;
8988 +       ctx->B += b;
8989 +       ctx->C += c;
8990 +       ctx->D += d;
8991 +}
8992 +
8993 +void create_M_blocks(uint32_t * M, uint8_t * data)
8994 +{
8995 +#ifdef HAVE_LITTLE_ENDIAN
8996 +       memcpy((uint8_t *) M, data, 64);
8997 +#endif                         /* HAVE_LITTLE_ENDIAN */
8998 +
8999 +#ifdef HAVE_BIG_ENDIAN
9000 +       int i;
9001 +       for (i = 0; i < 16; i++, data += 4) {
9002 +               ((uint8_t *) (&M[i]))[0] = data[3];
9003 +               ((uint8_t *) (&M[i]))[1] = data[2];
9004 +               ((uint8_t *) (&M[i]))[2] = data[1];
9005 +               ((uint8_t *) (&M[i]))[3] = data[0];
9006 +       }
9007 +#endif                         /* HAVE_BIG_ENDIAN */
9008 +}
9009 +
9010 +void md5_compute(MD5_CTX * ctx, uint8_t * data, uint32_t len)
9011 +{
9012 +       uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
9013 +
9014 +       /* First we update the bit length */
9015 +       if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
9016 +               ctx->bitlen[1]++;
9017 +       ctx->bitlen[1] += (len >> 29);  /* len is expressed in bytes */
9018 +
9019 +       if (pos) {
9020 +               /* Buffer is not empty */
9021 +               if (64 - pos >= len) {
9022 +                       memcpy(ctx->buf_cur, data, len);
9023 +                       ctx->buf_cur += len;
9024 +                       pos += len;
9025 +                       if (pos == 64) {
9026 +                               /* The current block is over */
9027 +                               md5_over_block(ctx, ctx->buf);
9028 +                               ctx->buf_cur = ctx->buf;
9029 +                       }
9030 +                       return;
9031 +               } else {
9032 +                       memcpy(ctx->buf_cur, data, 64 - pos);
9033 +                       md5_over_block(ctx, ctx->buf);
9034 +                       len -= (64 - pos);
9035 +                       data += (64 - pos);
9036 +                       ctx->buf_cur = ctx->buf;
9037 +               }
9038 +       }
9039 +       while (len >= 64) {
9040 +               md5_over_block(ctx, data);
9041 +               len -= 64;
9042 +               data += 64;
9043 +       }
9044 +       if (len) {
9045 +               memcpy(ctx->buf_cur, data, len);
9046 +               ctx->buf_cur += len;
9047 +       }
9048 +}
9049 +
9050 +void md5_final(MD5_CTX * ctx, uint8_t * digest)
9051 +{
9052 +       uint32_t rem_size;
9053 +       uint8_t *buf_cur = ctx->buf_cur;
9054 +       int i;
9055 +
9056 +       rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9057 +       *(buf_cur++) = 0x80;
9058 +
9059 +       if (rem_size > 8 + 1) {
9060 +               /* We have enough room in the current block */
9061 +               for (i = 0; i < rem_size - 8 - 1; i++) {
9062 +                       *(buf_cur++) = 0;
9063 +               }
9064 +       } else {
9065 +               /* We do not have enough room and need therefore to add a new
9066 +                  64-byte block */
9067 +               for (i = 0; i < rem_size - 1; i++) {
9068 +                       *(buf_cur++) = 0;
9069 +               }
9070 +               md5_over_block(ctx, ctx->buf);
9071 +
9072 +               buf_cur = ctx->buf;
9073 +               for (i = 0; i < 64 - 8; i++) {
9074 +                       *(buf_cur++) = 0;
9075 +               }
9076 +       }
9077 +#ifdef HAVE_LITTLE_ENDIAN
9078 +       memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9079 +#endif                         /* HAVE_LITTLE_ENDIAN */
9080 +
9081 +#ifdef HAVE_BIG_ENDIAN
9082 +       *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9083 +       *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9084 +       *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9085 +       *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9086 +       *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9087 +       *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9088 +       *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9089 +       *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9090 +#endif                         /* HAVE_BIG_ENDIAN */
9091 +
9092 +       md5_over_block(ctx, ctx->buf);
9093 +
9094 +#ifdef HAVE_LITTLE_ENDIAN
9095 +       memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9096 +       memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9097 +       memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9098 +       memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9099 +#endif                         /* HAVE_LITTLE_ENDIAN */
9100 +
9101 +#ifdef HAVE_BIG_ENDIAN
9102 +       digest[0] = ((ctx->A) >> 24) & 0xff;
9103 +       digest[1] = ((ctx->A) >> 16) & 0xff;
9104 +       digest[2] = ((ctx->A) >> 8) & 0xff;
9105 +       digest[3] = ((ctx->A) >> 0) & 0xff;
9106 +       digest[4] = ((ctx->B) >> 24) & 0xff;
9107 +       digest[5] = ((ctx->B) >> 16) & 0xff;
9108 +       digest[6] = ((ctx->B) >> 8) & 0xff;
9109 +       digest[7] = ((ctx->B) >> 0) & 0xff;
9110 +       digest[8] = ((ctx->C) >> 24) & 0xff;
9111 +       digest[9] = ((ctx->C) >> 16) & 0xff;
9112 +       digest[10] = ((ctx->C) >> 8) & 0xff;
9113 +       digest[11] = ((ctx->C) >> 0) & 0xff;
9114 +       digest[12] = ((ctx->D) >> 24) & 0xff;
9115 +       digest[13] = ((ctx->D) >> 16) & 0xff;
9116 +       digest[14] = ((ctx->D) >> 8) & 0xff;
9117 +       digest[15] = ((ctx->D) >> 0) & 0xff;
9118 +#endif                         /* HAVE_BIG_ENDIAN */
9119 +}
9120 +
9121 +void sha1_init(SHA1_CTX * ctx)
9122 +{
9123 +       ctx->A = 0x67452301;
9124 +       ctx->B = 0xefcdab89;
9125 +       ctx->C = 0x98badcfe;
9126 +       ctx->D = 0x10325476;
9127 +       ctx->E = 0xc3d2e1f0;
9128 +       ctx->buf_cur = ctx->buf;
9129 +       ctx->bitlen[0] = ctx->bitlen[1] = 0;
9130 +       memset(ctx->buf, 0, 64);
9131 +}
9132 +
9133 +void sha1_over_block(SHA1_CTX * ctx, uint8_t * data)
9134 +{
9135 +       int i;
9136 +       uint32_t W[80];
9137 +       uint32_t a = ctx->A;
9138 +       uint32_t b = ctx->B;
9139 +       uint32_t c = ctx->C;
9140 +       uint32_t d = ctx->D;
9141 +       uint32_t e = ctx->E;
9142 +       uint32_t temp;
9143 +
9144 +       create_W_blocks(W, data);
9145 +
9146 +       /* Round 1 */
9147 +       for (i = 0; i < 20; i++) {
9148 +               temp = LROLL(a, 5) + f(b, c, d) + e + W[i] + K1;
9149 +               e = d;
9150 +               d = c;
9151 +               c = LROLL(b, 30);
9152 +               b = a;
9153 +               a = temp;
9154 +       }
9155 +
9156 +       /* Round 2 */
9157 +       for (i = 20; i < 40; i++) {
9158 +               temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K2;
9159 +               e = d;
9160 +               d = c;
9161 +               c = LROLL(b, 30);
9162 +               b = a;
9163 +               a = temp;
9164 +       }
9165 +
9166 +       /* Round 3 */
9167 +       for (i = 40; i < 60; i++) {
9168 +               temp = LROLL(a, 5) + g(b, c, d) + e + W[i] + K3;
9169 +               e = d;
9170 +               d = c;
9171 +               c = LROLL(b, 30);
9172 +               b = a;
9173 +               a = temp;
9174 +       }
9175 +
9176 +       /* Round 4 */
9177 +       for (i = 60; i < 80; i++) {
9178 +               temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K4;
9179 +               e = d;
9180 +               d = c;
9181 +               c = LROLL(b, 30);
9182 +               b = a;
9183 +               a = temp;
9184 +       }
9185 +
9186 +       ctx->A += a;
9187 +       ctx->B += b;
9188 +       ctx->C += c;
9189 +       ctx->D += d;
9190 +       ctx->E += e;
9191 +}
9192 +
9193 +void create_W_blocks(uint32_t * W, uint8_t * data)
9194 +{
9195 +       int i;
9196 +
9197 +#ifdef HAVE_BIG_ENDIAN
9198 +       memcpy((uint8_t *) W, data, 64);
9199 +#endif                         /* HAVE_BIG_ENDIAN */
9200 +
9201 +#ifdef HAVE_LITTLE_ENDIAN
9202 +       for (i = 0; i < 16; i++, data += 4) {
9203 +               ((uint8_t *) (&W[i]))[0] = data[3];
9204 +               ((uint8_t *) (&W[i]))[1] = data[2];
9205 +               ((uint8_t *) (&W[i]))[2] = data[1];
9206 +               ((uint8_t *) (&W[i]))[3] = data[0];
9207 +       }
9208 +#endif                         /* HAVE_LITTLE_ENDIAN */
9209 +       for (i = 16; i < 80; i++) {
9210 +               W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
9211 +               W[i] = LROLL(W[i], 1);
9212 +       }
9213 +}
9214 +
9215 +void sha1_compute(SHA1_CTX * ctx, uint8_t * data, uint32_t len)
9216 +{
9217 +       uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
9218 +
9219 +       /* First we update the bit length */
9220 +       if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
9221 +               ctx->bitlen[1]++;
9222 +       ctx->bitlen[1] += (len >> 29);  /* len is expressed in bytes */
9223 +
9224 +       if (pos) {
9225 +               /* Buffer is not empty */
9226 +               if (64 - pos >= len) {
9227 +                       memcpy(ctx->buf_cur, data, len);
9228 +                       ctx->buf_cur += len;
9229 +                       pos += len;
9230 +                       if (pos == 64) {
9231 +                               /* The current block is over */
9232 +                               sha1_over_block(ctx, ctx->buf);
9233 +                               ctx->buf_cur = ctx->buf;
9234 +                       }
9235 +                       return;
9236 +               } else {
9237 +                       memcpy(ctx->buf_cur, data, 64 - pos);
9238 +                       sha1_over_block(ctx, ctx->buf);
9239 +                       len -= (64 - pos);
9240 +                       data += (64 - pos);
9241 +                       ctx->buf_cur = ctx->buf;
9242 +               }
9243 +       }
9244 +       while (len >= 64) {
9245 +               sha1_over_block(ctx, data);
9246 +               len -= 64;
9247 +               data += 64;
9248 +       }
9249 +       if (len) {
9250 +               memcpy(ctx->buf_cur, data, len);
9251 +               ctx->buf_cur += len;
9252 +       }
9253 +}
9254 +
9255 +void sha1_final(SHA1_CTX * ctx, uint8_t * digest)
9256 +{
9257 +       uint32_t rem_size;
9258 +       uint8_t *buf_cur = ctx->buf_cur;
9259 +       int i;
9260 +
9261 +       rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9262 +       *(buf_cur++) = 0x80;
9263 +
9264 +       if (rem_size > 8 + 1) {
9265 +               /* We have enough room in the current block */
9266 +               for (i = 0; i < rem_size - 8 - 1; i++) {
9267 +                       *(buf_cur++) = 0;
9268 +               }
9269 +       } else {
9270 +               /* We do not have enough room and need therefore to add a new
9271 +                  64-byte block */
9272 +               for (i = 0; i < rem_size - 1; i++) {
9273 +                       *(buf_cur++) = 0;
9274 +               }
9275 +               sha1_over_block(ctx, ctx->buf);
9276 +
9277 +               buf_cur = ctx->buf;
9278 +               for (i = 0; i < 64 - 8; i++) {
9279 +                       *(buf_cur++) = 0;
9280 +               }
9281 +       }
9282 +#ifdef HAVE_BIG_ENDIAN
9283 +       memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9284 +#endif                         /* HAVE_BIG_ENDIAN */
9285 +
9286 +#ifdef HAVE_LITTLE_ENDIAN
9287 +       *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9288 +       *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9289 +       *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9290 +       *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9291 +       *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9292 +       *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9293 +       *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9294 +       *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9295 +#endif                         /* HAVE_LITTLE_ENDIAN */
9296 +
9297 +       sha1_over_block(ctx, ctx->buf);
9298 +
9299 +#ifdef HAVE_BIG_ENDIAN
9300 +       memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9301 +       memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9302 +       memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9303 +       memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9304 +       memcpy(digest + 16, (uint8_t *) (&(ctx->E)), sizeof(uint32_t));
9305 +#endif                         /* HAVE_BIG_ENDIAN */
9306 +
9307 +#ifdef HAVE_LITTLE_ENDIAN
9308 +       digest[0] = ((ctx->A) >> 24) & 0xff;
9309 +       digest[1] = ((ctx->A) >> 16) & 0xff;
9310 +       digest[2] = ((ctx->A) >> 8) & 0xff;
9311 +       digest[3] = ((ctx->A) >> 0) & 0xff;
9312 +       digest[4] = ((ctx->B) >> 24) & 0xff;
9313 +       digest[5] = ((ctx->B) >> 16) & 0xff;
9314 +       digest[6] = ((ctx->B) >> 8) & 0xff;
9315 +       digest[7] = ((ctx->B) >> 0) & 0xff;
9316 +       digest[8] = ((ctx->C) >> 24) & 0xff;
9317 +       digest[9] = ((ctx->C) >> 16) & 0xff;
9318 +       digest[10] = ((ctx->C) >> 8) & 0xff;
9319 +       digest[11] = ((ctx->C) >> 0) & 0xff;
9320 +       digest[12] = ((ctx->D) >> 24) & 0xff;
9321 +       digest[13] = ((ctx->D) >> 16) & 0xff;
9322 +       digest[14] = ((ctx->D) >> 8) & 0xff;
9323 +       digest[15] = ((ctx->D) >> 0) & 0xff;
9324 +       digest[16] = ((ctx->E) >> 24) & 0xff;
9325 +       digest[17] = ((ctx->E) >> 16) & 0xff;
9326 +       digest[18] = ((ctx->E) >> 8) & 0xff;
9327 +       digest[19] = ((ctx->E) >> 0) & 0xff;
9328 +#endif                         /* HAVE_LITTLE_ENDIAN */
9329 +}
9330 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.h linux-2.4.25/net/ipv6/mobile_ip6/hmac.h
9331 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.h 1970-01-01 01:00:00.000000000 +0100
9332 +++ linux-2.4.25/net/ipv6/mobile_ip6/hmac.h     2004-06-26 11:29:31.000000000 +0100
9333 @@ -0,0 +1,94 @@
9334 +/*
9335 + *      MIPL Mobile IPv6 Message authentication algorithms        
9336 + * 
9337 + *      $Id$
9338 + *
9339 + *      This program is free software; you can redistribute it and/or
9340 + *      modify it under the terms of the GNU General Public License
9341 + *      as published by the Free Software Foundation; either version
9342 + *      2 of the License, or (at your option) any later version.
9343 + */
9344 +
9345 +#ifndef _HMAC_H
9346 +#define _HMAC_H
9347 +
9348 +#include <linux/types.h>
9349 +#include <linux/in6.h>
9350 +
9351 +#define HAVE_LITTLE_ENDIAN
9352 +
9353 +#define NO_EXPIRY 1  /* For sec_as */
9354 +
9355 +#define ALG_AUTH_NONE           0
9356 +#define ALG_AUTH_HMAC_MD5       1
9357 +#define ALG_AUTH_HMAC_SHA1      2
9358 +
9359 +struct sec_as;
9360 +struct ah_processing {
9361 +       void *context;
9362 +       struct sec_as *sas;
9363 +       u_int8_t *key_auth;
9364 +       u_int32_t key_auth_len;
9365 +};
9366 +
9367 +struct antireplay {
9368 +       u_int32_t count;
9369 +       u_int32_t bitmap; 
9370 +};
9371 +
9372 +typedef struct {
9373 +  u_int32_t A, B, C, D;
9374 +  u_int32_t bitlen[2];
9375 +  u_int8_t* buf_cur;
9376 +  u_int8_t buf[64];
9377 +} MD5_CTX;
9378 +
9379 +typedef struct {
9380 +  u_int32_t A, B, C, D, E;
9381 +  u_int32_t bitlen[2];
9382 +  u_int8_t* buf_cur;
9383 +  u_int8_t buf[64];
9384 +} SHA1_CTX;
9385 +
9386 +
9387 +
9388 +int ah_hmac_md5_init (struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len);
9389 +void ah_hmac_md5_loop(struct ah_processing*, void*, u_int32_t);
9390 +void ah_hmac_md5_result(struct ah_processing*, char*);
9391 +int ah_hmac_sha1_init(struct ah_processing*, u_int8_t *key, u_int32_t key_len);
9392 +void ah_hmac_sha1_loop(struct ah_processing*, void*, u_int32_t);
9393 +void ah_hmac_sha1_result(struct ah_processing*, char*);
9394 +
9395 +
9396 +#define AH_HDR_LEN 12   /* # of bytes for Next Header, Payload Length,
9397 +                           RESERVED, Security Parameters Index and
9398 +
9399 +                           Sequence Number Field */
9400 +
9401 +void md5_init(MD5_CTX *ctx);
9402 +void md5_over_block(MD5_CTX *ctx, u_int8_t* data);
9403 +void create_M_blocks(u_int32_t* M, u_int8_t* data);
9404 +void md5_compute(MD5_CTX *ctx, u_int8_t* data, u_int32_t len);
9405 +void md5_final(MD5_CTX *ctx, u_int8_t* digest);
9406 +
9407 +void sha1_init(SHA1_CTX *ctx);
9408 +void sha1_over_block(SHA1_CTX *ctx, u_int8_t* data);
9409 +void create_W_blocks(u_int32_t* W, u_int8_t* data);
9410 +void sha1_compute(SHA1_CTX *ctx, u_int8_t* data, u_int32_t len);
9411 +void sha1_final(SHA1_CTX *ctx, u_int8_t* digest);
9412 +
9413 +struct mipv6_acq {
9414 +       struct in6_addr coa;
9415 +       struct in6_addr haddr;
9416 +       struct in6_addr peer;
9417 +       u_int32_t spi;
9418 +};
9419 +#define MIPV6_MAX_AUTH_DATA 20
9420 +
9421 +#define HMAC_MD5_HASH_LEN   16
9422 +#define HMAC_SHA1_HASH_LEN  20
9423 +#define HMAC_SHA1_KEY_SIZE  20
9424 +#define HMAC_MD5_ICV_LEN   12 /* RFC 2403 */
9425 +#define HMAC_SHA1_ICV_LEN  12 /* RFC 2404 */
9426 +
9427 +#endif /* _HMAC_H */
9428 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ioctl_mn.c linux-2.4.25/net/ipv6/mobile_ip6/ioctl_mn.c
9429 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ioctl_mn.c     1970-01-01 01:00:00.000000000 +0100
9430 +++ linux-2.4.25/net/ipv6/mobile_ip6/ioctl_mn.c 2004-06-26 11:29:31.000000000 +0100
9431 @@ -0,0 +1,142 @@
9432 +/*
9433 + *     Mobile Node IOCTL Control device
9434 + *
9435 + *     Authors:
9436 + *     Henrik Petander         <lpetande@tml.hut.fi>
9437 + *
9438 + *     $Id$
9439 + *
9440 + *     This program is free software; you can redistribute it and/or
9441 + *      modify it under the terms of the GNU General Public License
9442 + *      as published by the Free Software Foundation; either version
9443 + *      2 of the License, or (at your option) any later version.
9444 + */
9445 +
9446 +#include <linux/config.h>
9447 +#include <linux/module.h>
9448 +#include <linux/fs.h>
9449 +#include <linux/poll.h>
9450 +#include <linux/ioctl.h> 
9451 +#include <net/ipv6.h>
9452 +#include <asm/uaccess.h>
9453 +
9454 +#include "debug.h"
9455 +#include "mdetect.h"
9456 +#include "multiaccess_ctl.h"
9457 +
9458 +/* Reserved for local / experimental use */
9459 +#define MAJOR_NUM 0xf9
9460 +
9461 +/* Get Care-of address information for Mobile Node */
9462 +#define IOCTL_GET_CAREOFADDR _IOWR(MAJOR_NUM, 9, void *)
9463 +
9464 +#define MA_IOCTL_SET_IFACE_PREFERENCE _IOR (MAJOR_NUM, 13, void *)
9465 +
9466 +/* The name of the device file */
9467 +#define CTLFILE "mipv6_dev"
9468 +
9469 +static int inuse = 0;
9470 +
9471 +static int mipv6_open(struct inode *inode, struct file *file)
9472 +{
9473 +       DEBUG(DBG_INFO, "(%p)\n", file);
9474 +
9475 +       if (inuse)
9476 +               return -EBUSY;
9477 +
9478 +       inuse++;
9479 +
9480 +       MOD_INC_USE_COUNT;
9481 +
9482 +       return 0;
9483 +}
9484 +
9485 +static int mipv6_close(struct inode *inode, struct file *file)
9486 +{
9487 +       DEBUG(DBG_INFO, "(%p,%p)\n", inode, file);
9488 +       inuse--;
9489 +
9490 +       MOD_DEC_USE_COUNT;
9491 +
9492 +       return 0;
9493 +}
9494 +
9495 +int mipv6_ioctl(struct inode *inode, struct file *file, 
9496 +               unsigned int ioctl_num, /* The number of the ioctl */
9497 +               unsigned long arg)      /* The parameter to it */
9498 +{
9499 +       struct in6_addr careofaddr;
9500 +
9501 +       /* Switch according to the ioctl called */
9502 +       switch (ioctl_num) {
9503 +       case IOCTL_GET_CAREOFADDR:
9504 +               DEBUG(DBG_DATADUMP, "IOCTL_GET_CAREOFADDR");
9505 +               /* First get home address from user and then look up 
9506 +                * the care-of address and return it
9507 +                */
9508 +               if (copy_from_user(&careofaddr, (struct in6_addr *)arg, 
9509 +                                  sizeof(struct in6_addr)) < 0) {
9510 +                       DEBUG(DBG_WARNING, "Copy from user failed");
9511 +                       return -EFAULT;
9512 +               }
9513 +               mipv6_get_care_of_address(&careofaddr, &careofaddr);
9514 +               if (copy_to_user((struct in6_addr *)arg, &careofaddr,
9515 +                                sizeof(struct in6_addr)) < 0) {
9516 +                       DEBUG(DBG_WARNING, "copy_to_user failed");
9517 +                       return -EFAULT;
9518 +               }
9519 +               break;
9520 +       case MA_IOCTL_SET_IFACE_PREFERENCE:
9521 +               DEBUG(DBG_INFO, "MA_IOCTL_SET_IFACE_PREFERENCE");
9522 +               ma_ctl_set_preference(arg);
9523 +               break;
9524 +
9525 +       default:
9526 +               DEBUG(DBG_WARNING, "Unknown ioctl cmd (%d)", ioctl_num);
9527 +               return -ENOENT;
9528 +       }
9529 +       return 0;
9530 +}
9531 +
9532 +struct file_operations Fops = {
9533 +       owner: THIS_MODULE,
9534 +       read: NULL,
9535 +       write: NULL,
9536 +       poll: NULL,
9537 +       ioctl: mipv6_ioctl,
9538 +       open: mipv6_open,
9539 +       release: mipv6_close
9540 +};
9541 +
9542 +
9543 +/* Initialize the module - Register the character device */
9544 +int mipv6_ioctl_mn_init(void)
9545 +{
9546 +       int ret_val;
9547 +
9548 +       /* Register the character device (atleast try) */
9549 +       ret_val = register_chrdev(MAJOR_NUM, CTLFILE, &Fops);
9550 +
9551 +       /* Negative values signify an error */
9552 +       if (ret_val < 0) {
9553 +               DEBUG(DBG_ERROR, "failed registering char device (err=%d)",
9554 +                     ret_val);
9555 +               return ret_val;
9556 +       }
9557 +
9558 +       DEBUG(DBG_INFO, "Device number %x, success", MAJOR_NUM);
9559 +       return 0;
9560 +}
9561 +
9562 +
9563 +/* Cleanup - unregister the appropriate file from /proc */
9564 +void mipv6_ioctl_mn_exit(void)
9565 +{
9566 +       int ret;
9567 +       /* Unregister the device */
9568 +       ret = unregister_chrdev(MAJOR_NUM, CTLFILE);
9569 +
9570 +       /* If there's an error, report it */
9571 +       if (ret < 0)
9572 +               DEBUG(DBG_ERROR, "errorcode: %d\n", ret);
9573 +}
9574 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.c linux-2.4.25/net/ipv6/mobile_ip6/mdetect.c
9575 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.c      1970-01-01 01:00:00.000000000 +0100
9576 +++ linux-2.4.25/net/ipv6/mobile_ip6/mdetect.c  2004-06-26 11:29:31.000000000 +0100
9577 @@ -0,0 +1,1153 @@
9578 +/*
9579 + *      Movement Detection Module
9580 + *
9581 + *      Authors:
9582 + *      Henrik Petander                <lpetande@cc.hut.fi>
9583 + *
9584 + *      $Id$
9585 + *
9586 + *      This program is free software; you can redistribute it and/or
9587 + *      modify it under the terms of the GNU General Public License
9588 + *      as published by the Free Software Foundation; either version
9589 + *      2 of the License, or (at your option) any later version.
9590 + *
9591 + *      Handles the L3 movement detection of mobile node and also
9592 + *      changing of its routes.
9593 + *  
9594 + */
9595 +
9596 +/*
9597 + *     Changes:
9598 + *
9599 + *     Nanno Langstraat        :       Locking fixes
9600 + *      Venkata Jagana          :       Locking fix
9601 + */
9602 +
9603 +#include <linux/autoconf.h>
9604 +#include <linux/errno.h>
9605 +#include <linux/init.h>
9606 +#include <linux/if_arp.h>
9607 +#include <linux/route.h>
9608 +#include <net/ipv6.h>
9609 +#include <net/ip6_route.h>
9610 +#include <net/addrconf.h>
9611 +#include <net/mipglue.h>
9612 +#ifdef CONFIG_SYSCTL
9613 +#include <linux/sysctl.h>
9614 +#endif /* CONFIG_SYSCTL */
9615 +
9616 +#include "util.h"
9617 +#include "mdetect.h"
9618 +#include "mn.h"
9619 +#include "debug.h"
9620 +#include "multiaccess_ctl.h"
9621 +
9622 +#define START 0
9623 +#define CONTINUE 1
9624 +#define OK 2
9625 +#define DEBUG_MDETECT 7
9626 +
9627 +#define DEF_RTR_POLL_IVAL 5 /* In seconds */
9628 +
9629 +#define NO_RTR 0
9630 +#define RTR_SUSPECT 1
9631 +#define CURR_RTR_OK 2
9632 +
9633 +#define RA_RCVD 0
9634 +#define NA_RCVD 1
9635 +#define TIMEOUT 2
9636 +
9637 +#define MIPV6_MDF_NONE 0x0
9638 +#define MIPV6_MDF_HAS_RTR_PREV 0x1
9639 +
9640 +#define ROUTER_REACHABLE 1
9641 +#define RADV_MISSED 2
9642 +#define NOT_REACHABLE 3
9643 +
9644 +/* R_TIME_OUT paramater is used to make the decision when to change the 
9645 + * default  router, if the current one is unreachable. 2s is pretty aggressive 
9646 + * and may result in hopping between two routers. OTOH a small value enhances 
9647 + * the  performance
9648 + */
9649 +#define R_TIME_OUT 30*HZ
9650 +
9651 +/* maximum RA interval for router unreachability detection */
9652 +#define MAX_RADV_INTERVAL 6*HZ  /* 6000 ms... */
9653 +
9654 +/* Threshold for exponential resending of router solicitations */
9655 +#define RS_RESEND_LINEAR 10*HZ
9656 +
9657 +#define EAGER_CELL_SWITCHING 1
9658 +#define LAZY_CELL_SWITCHING 0
9659 +#define RESPECT_DAD 1
9660 +
9661 +#define ROUTER_ADDRESS 0x20
9662 +
9663 +/* RA flags */
9664 +#define ND_RA_FLAG_MANAGED  0x80
9665 +#define ND_RA_FLAG_OTHER    0x40
9666 +#define ND_RA_FLAG_HA       0x20
9667 +
9668 +/* DAD flags for global and link local addresses */
9669 +
9670 +#define COA_TENTATIVE       0x10
9671 +#define LLADDR_TENTATIVE    0x01
9672 +
9673 +struct router {
9674 +       struct list_head list;
9675 +       struct in6_addr ll_addr;
9676 +       struct in6_addr raddr; /* Also contains prefix */
9677 +       __u8 link_addr[MAX_ADDR_LEN]; /* link layer address */
9678 +       __u8 link_addr_len;
9679 +       __u8 state;
9680 +       __u8 is_current;
9681 +       __u8 reachable;
9682 +       int ifindex;
9683 +       int pfix_len; /* Length of the network prefix */
9684 +       unsigned long lifetime; /* from ra */
9685 +       __u32 last_ns_sent; 
9686 +       __u32 last_ra_rcvd;
9687 +       __u32 interval; /* ra interval in milliseconds, 0 if not set */ 
9688 +       int glob_addr; /*Whether raddr contains also routers global address*/
9689 +       __u8 flags; /* RA flags, for example ha */
9690 +        struct in6_addr CoA;     /* care-off address used with this router */
9691 +       int extra_addr_route;
9692 +};
9693 +
9694 +/* dad could also be RESPECT_DAD for duplicate address detection of
9695 +   new care-of addresses */
9696 +static int dad = 0;
9697 +
9698 +/* Only one choice, nothing else implemented */
9699 +int max_rtr_reach_time = DEF_RTR_POLL_IVAL;
9700 +
9701 +
9702 +int eager_cell_switching = EAGER_CELL_SWITCHING; /* Can be set to 0 via proc */  
9703 +static spinlock_t router_lock; 
9704 +static spinlock_t ho_lock;
9705 +
9706 +static void coa_timer_handler(unsigned long arg);
9707 +static void timer_handler(unsigned long foo);
9708 +static struct router *curr_router = NULL, *next_router = NULL;
9709 +static struct timer_list r_timer = { function: timer_handler };
9710 +static struct timer_list coa_timer = { function: coa_timer_handler };
9711 +#define MAX_ROUTERS 1000
9712 +static LIST_HEAD(rtr_list);
9713 +static int num_routers = 0;
9714 +static struct handoff *_ho = NULL;
9715 +/*
9716 + * Functions for handling the default router list, which movement
9717 + * detection uses for avoiding loops etc.
9718 + */
9719 +
9720 +/* TODO: Send NS to router after MAX interval has passed from last RA */
9721 +static int mipv6_router_state(struct router *rtr) {
9722 +       if (rtr->interval) {
9723 +               if (time_before(jiffies, (rtr->last_ra_rcvd + (rtr->interval * HZ) / 1000)))
9724 +                       return ROUTER_REACHABLE;
9725 +               else
9726 +                       return NOT_REACHABLE;
9727 +       }
9728 +       else
9729 +               if (time_after(jiffies, rtr->last_ra_rcvd + (rtr->lifetime * HZ)))
9730 +                       return NOT_REACHABLE;
9731 +       return ROUTER_REACHABLE;
9732 +}
9733 +
9734 +/* searches for a specific router or any router that is reachable, 
9735 + * if address is NULL. Also deletes obsolete routers.
9736 + */
9737 +static void mipv6_router_gc(void)
9738 +{
9739 +       struct router *curr = NULL;
9740 +       struct list_head *lh, *lh_tmp;
9741 +
9742 +       DEBUG_FUNC();
9743 +
9744 +       list_for_each_safe(lh, lh_tmp, &rtr_list) {
9745 +               curr =  list_entry(lh, struct router, list);
9746 +               if (mipv6_router_state(curr) == NOT_REACHABLE && !curr->is_current) {
9747 +                       num_routers--;
9748 +                       list_del_init(&curr->list);
9749 +                       DEBUG(DBG_DATADUMP, "Deleting unreachable router  %x:%x:%x:%x:%x:%x:%x:%x", 
9750 +                             NIPV6ADDR(&curr->raddr));
9751 +                       kfree(curr);
9752 +               }
9753 +               else {
9754 +                       DEBUG(DBG_DATADUMP, "NOT Deleting router  %x:%x:%x:%x:%x:%x:%x:%x", 
9755 +                             NIPV6ADDR(&curr->raddr));
9756 +               }
9757 +       }
9758 +}
9759 +
9760 +static struct router *mipv6_rtr_get(struct in6_addr *search_addr)
9761 +{
9762 +       struct router *rtr = NULL;
9763 +       struct list_head *lh;
9764 +
9765 +       DEBUG_FUNC();
9766 +
9767 +       if (search_addr == NULL)
9768 +               return NULL;
9769 +       list_for_each(lh, &rtr_list) {
9770 +               rtr = list_entry(lh, struct router, list);
9771 +               if(!ipv6_addr_cmp(search_addr, &rtr->raddr)) {
9772 +                       return rtr;
9773 +               }
9774 +       }
9775 +       return NULL;
9776 +}
9777 +
9778 +/*
9779 + * Adds router to list
9780 + */
9781 +static struct router *mipv6_rtr_add(struct router *nrt)
9782 +{
9783 +
9784 +       struct router *rptr;
9785 +
9786 +       DEBUG_FUNC();
9787 +
9788 +       /* check if someone is trying DoS attack, or we just have some
9789 +           memory leaks... */
9790 +       if (num_routers > MAX_ROUTERS) {
9791 +               DEBUG(DBG_CRITICAL, 
9792 +                     "failed to add new router, MAX_ROUTERS exceeded");
9793 +               return NULL;
9794 +       }
9795 +       
9796 +       rptr = kmalloc(sizeof(struct router), GFP_ATOMIC);
9797 +       if (rptr) {
9798 +               memcpy(rptr, nrt, sizeof(struct router));
9799 +               list_add(&rptr->list, &rtr_list);
9800 +               num_routers++;
9801 +       }
9802 +       DEBUG(DBG_INFO, "Adding router: %x:%x:%x:%x:%x:%x:%x:%x, "
9803 +             "lifetime : %d sec, adv.interval: %d millisec", 
9804 +             NIPV6ADDR(&rptr->raddr), rptr->lifetime, rptr->interval);
9805 +
9806 +       DEBUG(DBG_INFO, "num_routers after addition: %d", num_routers);
9807 +       return rptr;
9808 +}
9809 +
9810 +/* Cleans up the list */
9811 +static void list_free(struct router **curr_router_p)
9812 +{
9813 +       struct router *tmp;
9814 +       struct list_head *lh, *lh_tmp;
9815 +
9816 +       DEBUG_FUNC();
9817 +
9818 +       DEBUG(DBG_INFO, "Freeing the router list");
9819 +       /* set curr_router->prev_router and curr_router NULL */
9820 +       *curr_router_p = NULL;
9821 +       list_for_each_safe(lh, lh_tmp, &rtr_list) {
9822 +               tmp = list_entry(lh, struct router, list);
9823 +               DEBUG(DBG_INFO, "%x:%x:%x:%x:%x:%x:%x:%x",
9824 +                     NIPV6ADDR(&tmp->ll_addr));
9825 +               list_del(&tmp->list);
9826 +               kfree(tmp);
9827 +               num_routers--;
9828 +       }
9829 +}
9830 +
9831 +int rs_state = START;
9832 +
9833 +/* Sends router solicitations to all valid devices 
9834 + * source  = link local address (of sending interface)
9835 + * dstaddr = all routers multicast address
9836 + * Solicitations are sent at an exponentially decreasing rate
9837 + *
9838 + * TODO: send solicitation first at a normal rate (from ipv6) and
9839 + *       after that use the exponentially increasing intervals 
9840 + */
9841 +static int rs_send(void)
9842 +{
9843 +       struct net_device *dev;
9844 +       struct in6_addr raddr, lladdr;
9845 +       struct inet6_dev *in6_dev = NULL;
9846 +       static int num_rs;
9847 +
9848 +       if (rs_state == START) {
9849 +               num_rs = 0;
9850 +               rs_state = CONTINUE;
9851 +       } else if (num_rs++ > MAX_RTR_SOLICITATIONS)
9852 +               return HZ;
9853 +
9854 +       ipv6_addr_all_routers(&raddr);
9855 +       read_lock(&dev_base_lock); 
9856 +
9857 +       /*  Send router solicitations to all interfaces  */
9858 +       for (dev = dev_base; dev; dev = dev->next) {
9859 +               if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) {
9860 +                       DEBUG(DBG_DATADUMP, "Sending RS to device %s", 
9861 +                             dev->name);
9862 +                       if (!ipv6_get_lladdr(dev, &lladdr)) {
9863 +                               ndisc_send_rs(dev, &lladdr, &raddr);
9864 +                               in6_dev = in6_dev_get(dev);
9865 +                               in6_dev->if_flags |= IF_RS_SENT;
9866 +                               in6_dev_put(in6_dev);
9867 +                       } else {
9868 +                               DEBUG(DBG_DATADUMP, "%s: device doesn't have link-local address!\n", dev->name);
9869 +                               continue;
9870 +                       }
9871 +               }
9872 +               
9873 +       }
9874 +       read_unlock(&dev_base_lock);
9875 +       return RTR_SOLICITATION_INTERVAL;
9876 +}
9877 +
9878 +/* Create a new CoA for MN and also add a route to it if it is still tentative 
9879 +   to allow MN to get packets to the address immediately
9880 + */
9881 +static int form_coa(struct in6_addr *coa, struct in6_addr *pfix, 
9882 +                   int plen, int ifindex)
9883 +{
9884 +       struct net_device *dev;
9885 +       struct inet6_dev *in6_dev;
9886 +       int ret = 0;
9887 +
9888 +       if ((dev = dev_get_by_index(ifindex)) == NULL) {
9889 +               DEBUG(DBG_WARNING, "Device is not present");
9890 +               return -1;
9891 +       }
9892 +       if ((in6_dev = in6_dev_get(dev)) == NULL) {
9893 +               DEBUG(DBG_WARNING, "inet6_dev is not present");
9894 +               dev_put(dev);
9895 +               return -1;
9896 +       }
9897 +       coa->s6_addr32[0] = pfix->s6_addr32[0];
9898 +       coa->s6_addr32[1] = pfix->s6_addr32[1];
9899 +
9900 +       if (ipv6_generate_eui64(coa->s6_addr + 8, dev) &&
9901 +           ipv6_inherit_eui64(coa->s6_addr + 8, in6_dev)) {
9902 +               in6_dev_put(in6_dev);
9903 +               dev_put(dev);
9904 +               return -1;
9905 +       }
9906 +       if (ipv6_chk_addr(coa, dev) == 0) { 
9907 +               DEBUG(DBG_WARNING, "care-of address still tentative");
9908 +               ret = 1;
9909 +       }
9910 +       DEBUG(DBG_INFO, "Formed new CoA:  %x:%x:%x:%x:%x:%x:%x:%x",
9911 +             NIPV6ADDR(coa));
9912 +       
9913 +       in6_dev_put(in6_dev);
9914 +       dev_put(dev);
9915 +       return ret;
9916 +}
9917 +
9918 +static inline int rtr_is_gw(struct router *rtr, struct rt6_info *rt) 
9919 +{
9920 +       return ((rt->rt6i_flags & RTF_GATEWAY) && 
9921 +               !ipv6_addr_cmp(&rt->rt6i_gateway, &rtr->ll_addr));
9922 +}
9923 +
9924 +static inline int is_prefix_route(struct router *rtr, struct rt6_info *rt) 
9925 +{
9926 +       return (!(rt->rt6i_flags & RTF_GATEWAY) &&
9927 +               mipv6_prefix_compare(&rt->rt6i_dst.addr, &rtr->raddr, 
9928 +                                    rtr->pfix_len));
9929 +}
9930 +
9931 +/*
9932 + * Function that determines whether given rt6_info should be destroyed
9933 + * (negative => destroy rt6_info, zero or positive => do nothing) 
9934 + */
9935 +static int mn_route_cleaner(struct rt6_info *rt, void *arg)
9936 +{
9937 +       int type;
9938 +
9939 +       struct router *rtr = (struct router *)arg;
9940 +
9941 +       int ret = -1;
9942 +
9943 +       DEBUG_FUNC();
9944 +       
9945 +       if (!rt || !rtr) {
9946 +               DEBUG(DBG_ERROR, "mn_route_cleaner: rt or rtr NULL");
9947 +               return 0;
9948 +       }
9949 +
9950 +       /* Do not delete routes to local addresses or to multicast
9951 +        * addresses, since we need them to get router advertisements
9952 +        * etc. Multicast addresses are more tricky, but we don't
9953 +        * delete them in any case. The routing mechanism is not optimal for 
9954 +        * multihoming.   
9955 +        *
9956 +        * Also keep all new prefix routes, gateway routes through rtr and
9957 +        * all remaining default routes (including those used for reverse
9958 +        * tunneling)
9959 +        */
9960 +       type = ipv6_addr_type(&rt->rt6i_dst.addr);
9961 +       
9962 +       if ((type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) ||
9963 +           rt->rt6i_dev == &loopback_dev || rtr_is_gw(rtr, rt) ||
9964 +           is_prefix_route(rtr, rt) || (rt->rt6i_flags & RTF_DEFAULT))  
9965 +               ret = 0;
9966 +       
9967 +       /*   delete all others */
9968 +
9969 +       if (rt->rt6i_dev != &loopback_dev) {
9970 +               DEBUG(DEBUG_MDETECT, 
9971 +                     "%s route:\n"
9972 +                     "dev: %s,\n"
9973 +                     "gw: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9974 +                     "flags: %x,\n"
9975 +                     "metric: %d,\n"
9976 +                     "src: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9977 +                     "dst: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9978 +                     "plen: %d\n",
9979 +                     (ret ? "Deleting" : "Keeping"),
9980 +                     rt->rt6i_dev->name,              
9981 +                     NIPV6ADDR(&rt->rt6i_gateway),            
9982 +                     rt->rt6i_flags,
9983 +                     rt->rt6i_metric,
9984 +                     NIPV6ADDR(&rt->rt6i_src.addr),
9985 +                     NIPV6ADDR(&rt->rt6i_dst.addr),
9986 +                     rt->rt6i_dst.plen);
9987 +       }
9988 +       return ret;
9989 +}
9990 +
9991 +/* 
9992 + * Deletes old routes 
9993 + */
9994 +static __inline__ void delete_routes(struct router *rtr)
9995 +{
9996 +       DEBUG_FUNC();
9997 +
9998 +       /* Routing table is locked to ensure that nobody uses its */  
9999 +       write_lock_bh(&rt6_lock);
10000 +       DEBUG(DBG_INFO, "mipv6: Purging routes");
10001 +       /*  TODO: Does not prune, should it?  */
10002 +       fib6_clean_tree(&ip6_routing_table, 
10003 +                       mn_route_cleaner, 0, rtr);
10004 +       write_unlock_bh(&rt6_lock);
10005 +
10006 +}
10007 +
10008 +
10009 +static __inline__ void delete_coas(struct router *rtr)
10010 +{
10011 +       struct net_device *dev;
10012 +       struct inet6_dev *idev;
10013 +       struct inet6_ifaddr *ifa;
10014 +
10015 +       dev = dev_get_by_index(rtr->ifindex);
10016 +       if (!dev)
10017 +               return;
10018 +
10019 +       idev = in6_dev_get(dev);
10020 +       
10021 +       if (idev) {
10022 +               read_lock_bh(&idev->lock);
10023 +               ifa = idev->addr_list;
10024 +               while (ifa) {
10025 +                       int keep; 
10026 +                       spin_lock(&ifa->lock);
10027 +                       
10028 +                       keep = (ifa->flags&(IFA_F_PERMANENT|IFA_F_HOMEADDR) ||
10029 +                               !ipv6_addr_cmp(&ifa->addr, &rtr->CoA));
10030 +                       
10031 +                       spin_unlock(&ifa->lock);
10032 +                       
10033 +                       if (keep)
10034 +                               ifa = ifa->if_next;
10035 +                       else {
10036 +                               in6_ifa_hold(ifa);
10037 +                               read_unlock_bh(&idev->lock);
10038 +                               
10039 +                               ipv6_del_addr(ifa);
10040 +                               
10041 +                               read_lock_bh(&idev->lock);
10042 +                               ifa = idev->addr_list;
10043 +                       }
10044 +               }
10045 +               read_unlock_bh(&idev->lock);
10046 +               in6_dev_put(idev);
10047 +       }
10048 +       dev_put(dev);
10049 +}
10050 +
10051 +int next_mdet_state[3][3] = {{CURR_RTR_OK, NO_RTR, NO_RTR},
10052 +                            {CURR_RTR_OK, CURR_RTR_OK, NO_RTR},
10053 +                            {CURR_RTR_OK, CURR_RTR_OK, RTR_SUSPECT}};
10054
10055 +char *states[3] = {"NO_RTR", "RTR_SUSPECT", "CURR_RTR_OK"};
10056 +char *events[3] = {"RA_RCVD", "NA_RCVD", "TIMEOUT"};
10057 +
10058 +/* State transitions
10059 + * NO_RTR, RA_RCVD -> CURR_RTR_OK
10060 + * NO_RTR, NA_RCVD -> NO_RTR
10061 + * NO_RTR, TIMEOUT -> NO_RTR
10062 +
10063 + * RTR_SUSPECT, RA_RCVD -> CURR_RTR_OK
10064 + * RTR_SUSPECT, NA_RCVD -> CURR_RTR_OK
10065 + * RTR_SUSPECT, TIMEOUT -> NO_RTR
10066 +
10067 + * CURR_RTR_OK, RA_RCVD -> CURR_RTR_OK
10068 + * CURR_RTR_OK, NA_RCVD -> CURR_RTR_OK
10069 + * CURR_RTR_OK, TIMEOUT -> RTR_SUSPECT
10070 + */
10071 +static int _curr_state = NO_RTR;
10072 +
10073 +#if 0
10074 +static int get_mdet_state(void){
10075 +       int state;
10076 +       spin_lock_bh(&router_lock); 
10077 +       state = _curr_state;
10078 +       spin_unlock_bh(&router_lock);
10079 +       return state;
10080 +}
10081 +#endif
10082 +
10083 +/* Needs to be called with router_lock locked */
10084 +static int mdet_statemachine(int event)
10085 +{
10086 +       
10087 +       if (event > 2 || _curr_state > 2) {
10088 +              DEBUG(DBG_ERROR, "Got illegal event or curr_state");
10089 +              return -1;
10090 +       }
10091 +
10092 +       DEBUG(DBG_DATADUMP, "Got event %s and curr_state is %s", 
10093 +             events[event], states[_curr_state]); 
10094 +       
10095 +       _curr_state = next_mdet_state[_curr_state][event];
10096 +       DEBUG(DBG_DATADUMP, "Next state is %s", states[_curr_state]);
10097 +       return _curr_state;
10098 +}
10099 +
10100 +static void mipv6_do_ll_dad(int ifindex)
10101 +{
10102 +       struct net_device *dev = dev_get_by_index(ifindex);
10103 +       if (dev) {
10104 +               struct in6_addr lladdr;
10105 +               struct inet6_ifaddr *ifa;
10106 +               if (!ipv6_get_lladdr(dev, &lladdr) &&
10107 +                   (ifa = ipv6_get_ifaddr(&lladdr, dev)) != NULL) {
10108 +                       spin_lock_bh(&ifa->lock);
10109 +                       if (!(ifa->flags & IFA_F_TENTATIVE)) {
10110 +                               ifa->flags |= IFA_F_TENTATIVE;
10111 +                               spin_unlock_bh(&ifa->lock);
10112 +                               addrconf_dad_start(ifa, 0);
10113 +                       } else
10114 +                               spin_unlock_bh(&ifa->lock);
10115 +
10116 +               }
10117 +               dev_put(dev);
10118 +       }
10119 +}
10120 +/* 
10121 + * Changes the router, called from ndisc.c if mipv6_router_event 
10122 + * returns true.
10123 + */
10124 +
10125 +static void mipv6_change_router(void)
10126 +{
10127 +       struct in6_addr coa;
10128 +       int ret, ifindex;
10129 +       
10130 +       DEBUG_FUNC(); 
10131 +
10132 +       
10133 +       if (next_router == NULL) 
10134 +               return;
10135 +       
10136 +       spin_lock(&router_lock);
10137 +
10138 +
10139 +       if (curr_router != NULL && 
10140 +           !ipv6_addr_cmp(&curr_router->ll_addr, &next_router->ll_addr)) {
10141 +               DEBUG(DBG_INFO,"Trying to handoff from: "
10142 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
10143 +                     NIPV6ADDR(&curr_router->ll_addr));
10144 +               DEBUG(DBG_INFO,"Trying to handoff to: "
10145 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
10146 +                     NIPV6ADDR(&next_router->ll_addr));
10147 +               next_router = NULL; /* Let's not leave dangling pointers */
10148 +               spin_unlock(&router_lock);
10149 +               return;
10150 +        }
10151 +       ret = form_coa(&next_router->CoA, &next_router->raddr, 
10152 +                      next_router->pfix_len, next_router->ifindex);
10153 +       if (ret < 0) {
10154 +               DEBUG(DBG_ERROR, "handoff: Creation of coa failed");
10155 +               spin_unlock(&router_lock);
10156 +               return;
10157 +       } else if (ret > 0)
10158 +               next_router->flags |= COA_TENTATIVE;
10159 +
10160 +       mdet_statemachine(RA_RCVD); /* TODO: What if DAD fails... */
10161 +       if (next_router->interval)
10162 +               mod_timer(&r_timer, jiffies + 
10163 +                         (next_router->interval * HZ)/1000);
10164 +       else
10165 +               mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10166 +       
10167 +
10168 +       if (ret == 0) {
10169 +               ipv6_addr_copy(&coa, &next_router->CoA);
10170 +               ifindex = next_router->ifindex;
10171 +               spin_unlock(&router_lock);
10172 +               mipv6_mdet_finalize_ho(&coa, ifindex);
10173 +               return;
10174 +       }
10175 +       spin_unlock(&router_lock);
10176 +
10177 +}
10178 +static unsigned long ns_send(void)
10179 +{
10180 +       struct neighbour *neigh;
10181 +       struct net_device *dev;
10182 +       struct in6_addr *raddr;
10183 +
10184 +       DEBUG(DBG_DATADUMP, "Sending Neighbour solicitation to default router to verify its reachability");
10185 +       if (!curr_router) 
10186 +               return HZ;
10187 +       if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10188 +               return HZ;
10189 +       if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10190 +               dev_put(dev);
10191 +               return HZ;
10192 +       }
10193 +       if (curr_router->glob_addr)
10194 +               raddr = &curr_router->raddr;
10195 +       else 
10196 +               raddr = &curr_router->ll_addr;
10197 +
10198 +       curr_router->last_ns_sent = jiffies;
10199 +       ndisc_send_ns(dev, neigh, raddr, raddr, NULL);  
10200 +
10201 +       neigh_release(neigh);
10202 +       dev_put(dev);
10203 +       return HZ/5; /* Wait 200ms for a reply */
10204 +}
10205 +
10206 +static int na_rcvd(void)
10207 +{      
10208 +       int neigh_ok = 0;
10209 +       struct neighbour *neigh;
10210 +       struct net_device *dev;
10211 +
10212 +       if (!curr_router) 
10213 +               return 0;
10214 +       if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10215 +               return 0;
10216 +       if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10217 +               dev_put(dev);
10218 +               return 0;
10219 +       }
10220 +       if (neigh->flags & NTF_ROUTER && 
10221 +           (time_after(neigh->confirmed, curr_router->last_ns_sent) || 
10222 +            neigh->confirmed == curr_router->last_ns_sent)) {
10223 +               neigh_ok = 1;
10224 +               DEBUG(DBG_DATADUMP, "Mdetect event: NA rcvd from curr rtr");
10225 +       } else
10226 +               DEBUG(DBG_DATADUMP, "Mdetect event: NA NOT rcvd from curr rtr within time limit");
10227 +       neigh_release(neigh);
10228 +       dev_put(dev);
10229 +       return neigh_ok;
10230 +}
10231 +
10232 +static void coa_timer_handler(unsigned long dummy)
10233 +{
10234 +
10235 +       spin_lock_bh(&ho_lock);
10236 +       if (_ho) {
10237 +               DEBUG(DBG_INFO, "Starting handoff after DAD");
10238 +               mipv6_mobile_node_moved(_ho);
10239 +               kfree(_ho);
10240 +               _ho = NULL;
10241 +       }
10242 +       spin_unlock_bh(&ho_lock);
10243 +}
10244 +static void timer_handler(unsigned long foo)
10245 +{
10246 +       unsigned long timeout;
10247 +       int state;
10248 +       spin_lock_bh(&router_lock);
10249 +       
10250 +       if (_curr_state != NO_RTR)
10251 +               rs_state = START;
10252 +
10253 +       if (_curr_state == RTR_SUSPECT && na_rcvd()) {
10254 +               state = mdet_statemachine(NA_RCVD);
10255 +               timeout = curr_router->interval ? curr_router->interval : max_rtr_reach_time * HZ;
10256 +       } else { 
10257 +               state =  mdet_statemachine(TIMEOUT);
10258 +               if (state == NO_RTR)
10259 +                       timeout = rs_send();
10260 +               else  /* RTR_SUSPECT */
10261 +                       timeout = ns_send();
10262 +       }
10263 +       if (!timeout)
10264 +               timeout = HZ;
10265 +
10266 +       mipv6_router_gc();
10267 +       mod_timer(&r_timer, jiffies + timeout);
10268 +       spin_unlock_bh(&router_lock);
10269 +}
10270 +
10271 +/**
10272 + * mipv6_get_care_of_address - get node's care-of primary address
10273 + * @homeaddr: one of node's home addresses
10274 + * @coaddr: buffer to store care-of address
10275 + *
10276 + * Stores the current care-of address in the @coaddr, assumes
10277 + * addresses in EUI-64 format.  Since node might have several home
10278 + * addresses caller MUST supply @homeaddr.  If node is at home
10279 + * @homeaddr is stored in @coaddr.  Returns 0 on success, otherwise a
10280 + * negative value.
10281 + **/
10282 +int mipv6_get_care_of_address(
10283 +       struct in6_addr *homeaddr, struct in6_addr *coaddr)
10284 +{
10285 +       
10286 +       DEBUG_FUNC();
10287 +
10288 +       if (homeaddr == NULL)
10289 +               return -1;
10290 +       spin_lock_bh(&router_lock);
10291 +       if (curr_router == NULL || mipv6_mn_is_at_home(homeaddr) || 
10292 +           mipv6_prefix_compare(homeaddr, &curr_router->raddr, 64) || 
10293 +           curr_router->flags&COA_TENTATIVE) {
10294 +               DEBUG(DBG_INFO,
10295 +                     "mipv6_get_care_of_address: returning home address");
10296 +               ipv6_addr_copy(coaddr, homeaddr);
10297 +               spin_unlock_bh(&router_lock);
10298 +               return 0;
10299 +
10300 +       }
10301 +
10302 +       /* At home or address check failure probably due to dad wait */
10303 +       if (mipv6_prefix_compare(&curr_router->raddr, homeaddr, 
10304 +                                curr_router->pfix_len) 
10305 +                                || (dad == RESPECT_DAD && 
10306 +                                    (ipv6_chk_addr(coaddr, NULL) == 0))) { 
10307 +               ipv6_addr_copy(coaddr, homeaddr);
10308 +       } else { 
10309 +               ipv6_addr_copy(coaddr, &curr_router->CoA);
10310 +       }
10311 +
10312 +       spin_unlock_bh(&router_lock);
10313 +       return 0;
10314 +}
10315 +
10316 +int mipv6_mdet_del_if(int ifindex)
10317 +{
10318 +       struct router *curr = NULL;
10319 +       struct list_head *lh, *lh_tmp;
10320 +
10321 +       spin_lock_bh(&router_lock);
10322 +       list_for_each_safe(lh, lh_tmp, &rtr_list) {
10323 +               curr =  list_entry(lh, struct router, list);
10324 +               if (curr->ifindex == ifindex) {
10325 +                       num_routers--;
10326 +                       list_del_init(&curr->list);
10327 +                       DEBUG(DBG_DATADUMP, "Deleting router  %x:%x:%x:%x:%x:%x:%x:%x on interface %d", 
10328 +                             NIPV6ADDR(&curr->raddr), ifindex);
10329 +                       if (curr_router == curr)
10330 +                               curr_router = NULL;
10331 +                       kfree(curr);
10332 +               }
10333 +       }
10334 +       spin_unlock_bh(&router_lock);
10335 +       return 0;
10336 +}
10337 +
10338 +void mipv6_mdet_retrigger_ho(void)
10339 +{
10340 +       struct handoff ho;
10341 +
10342 +       spin_lock_bh(&router_lock);
10343 +       if (curr_router != NULL) {
10344 +               ho.coa = &curr_router->CoA;
10345 +               ho.plen = curr_router->pfix_len;
10346 +               ho.ifindex = curr_router->ifindex;
10347 +               ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10348 +               ho.home_address = (curr_router->glob_addr && 
10349 +                                  curr_router->flags&ND_RA_FLAG_HA);
10350 +       }
10351 +       spin_unlock_bh(&router_lock);
10352 +       mipv6_mobile_node_moved(&ho);
10353 +}
10354 +
10355 +void mipv6_mdet_set_curr_rtr_reachable(int reachable)
10356 +{
10357 +       spin_lock_bh(&router_lock);
10358 +       if (curr_router != NULL) {
10359 +               curr_router->reachable = reachable;
10360 +       }
10361 +       spin_unlock_bh(&router_lock);
10362 +
10363 +}
10364 +
10365 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex)
10366 +{
10367 +       int dummy;
10368 +       struct handoff ho;
10369 +       struct router *tmp;
10370 +       struct net_device *dev; 
10371 +       struct in6_addr ll_addr;
10372 +
10373 +       spin_lock_bh(&router_lock);
10374 +
10375 +       if (!next_router) {
10376 +               spin_unlock_bh(&router_lock);
10377 +               return 0;
10378 +       }
10379 +
10380 +       dev = dev_get_by_index(next_router->ifindex);
10381 +
10382 +       if (ipv6_get_lladdr(dev, &ll_addr) == 0) {
10383 +               if (ipv6_addr_cmp(&ll_addr, coa) == 0)
10384 +                       DEBUG(DBG_INFO, "DAD for link local address completed");
10385 +               next_router->flags &= ~LLADDR_TENTATIVE;
10386 +       }
10387 +
10388 +       dev_put(dev);
10389 +
10390 +       if (mipv6_prefix_compare(coa, &next_router->CoA, 
10391 +                                next_router->pfix_len)) {
10392 +               DEBUG(DBG_INFO, "DAD for Care-of address completed");
10393 +               next_router->flags &= ~COA_TENTATIVE;
10394 +       }
10395 +       if (!(next_router->flags&LLADDR_TENTATIVE) && !(next_router->flags&COA_TENTATIVE)) {
10396 +               DEBUG(DBG_INFO, "%s: Proceeding with handoff after DAD\n", __FUNCTION__);
10397 +               tmp = curr_router;
10398 +               curr_router = next_router;
10399 +               curr_router->is_current = 1;
10400 +               next_router = NULL; 
10401 +               curr_router->flags &= ~COA_TENTATIVE; 
10402 +               delete_routes(curr_router);
10403 +               delete_coas(curr_router);
10404 +               if (tmp) {
10405 +                       struct net_device *dev_old = dev_get_by_index(tmp->ifindex);
10406 +                       struct rt6_info *rt = NULL;
10407 +                       if (dev_old) {
10408 +                               rt = rt6_get_dflt_router(&tmp->ll_addr, dev_old);
10409 +                               dev_put(dev_old);
10410 +                       }
10411 +                       if (rt)
10412 +                               ip6_del_rt(rt, NULL);
10413 +                       tmp->is_current = 0;
10414 +               }
10415 +
10416 +               ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10417 +               ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10418 +
10419 +
10420 +               ho.coa = &curr_router->CoA;
10421 +               ho.plen = curr_router->pfix_len;
10422 +               ho.ifindex = curr_router->ifindex;
10423 +               ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10424 +               ho.home_address = (curr_router->glob_addr && 
10425 +                                   curr_router->flags&ND_RA_FLAG_HA);
10426 +               
10427 +               spin_unlock_bh(&router_lock);
10428 +               mipv6_mobile_node_moved(&ho);
10429 +       } else 
10430 +               spin_unlock_bh(&router_lock);
10431 +       return 0;
10432 +}
10433 +/* Decides whether router candidate is the same router as current rtr
10434 + * based on prefix / global addresses of the routers and their link local 
10435 + * addresses 
10436 + */
10437 +static int is_current_rtr(struct router *nrt, struct router *crt)
10438 +{
10439 +       DEBUG_FUNC();
10440 +       
10441 +       DEBUG(DEBUG_MDETECT, "Current router: "
10442 +             "%x:%x:%x:%x:%x:%x:%x:%x and", NIPV6ADDR(&crt->raddr));
10443 +       DEBUG(DEBUG_MDETECT, "Candidate router: "
10444 +             "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&nrt->raddr));
10445 +
10446 +       return (!ipv6_addr_cmp(&nrt->raddr,&crt->raddr) && 
10447 +               !ipv6_addr_cmp(&nrt->ll_addr, &crt->ll_addr));
10448 +}
10449 +
10450 +/* 
10451 + * Change next router to nrtr
10452 + * Returns 1, if router has been changed.
10453 + */ 
10454 +
10455 +static int change_next_rtr(struct router *nrtr, struct router *ortr)
10456 +{
10457 +       int changed = 0;
10458 +       DEBUG_FUNC();
10459 +
10460 +       if (!next_router || ipv6_addr_cmp(&nrtr->raddr, &next_router->raddr)) {
10461 +               changed = 1;
10462 +       }
10463 +       next_router = nrtr;
10464 +       return changed;
10465 +}
10466 +static int clean_ncache(struct router *nrt, struct router *ort, int same_if)
10467 +{
10468 +       struct net_device *ortdev;
10469 +       DEBUG_FUNC();
10470 +
10471 +       /* Always call ifdown after a handoff to ensure proper routing */
10472 +       
10473 +       if (!ort) 
10474 +               return 0;
10475 +       if ((ortdev = dev_get_by_index(ort->ifindex)) == NULL) {
10476 +               DEBUG(DBG_WARNING, "Device is not present");
10477 +               return -1;
10478 +       }
10479 +       neigh_ifdown(&nd_tbl, ortdev);
10480 +       dev_put(ortdev);        
10481 +       return 0;
10482 +}
10483 +
10484 +static int mdet_get_if_preference(int ifi)
10485 +{
10486 +       int pref = 0;
10487 +
10488 +       DEBUG_FUNC();
10489 +
10490 +       pref = ma_ctl_get_preference(ifi);
10491 +
10492 +       DEBUG(DEBUG_MDETECT, "ifi: %d preference %d", ifi, pref);
10493 +
10494 +       return pref;
10495 +}
10496 +
10497 +/*
10498 + * Called from mipv6_mn_ra_rcv to determine whether to do a handoff. 
10499 + */
10500 +static int mipv6_router_event(struct router *rptr)
10501 +{
10502 +       struct router *nrt = NULL;
10503 +       int new_router = 0, same_if = 1;
10504 +       int oldstate = _curr_state;
10505 +       int addrtype = ipv6_addr_type(&rptr->raddr);
10506 +
10507 +       DEBUG_FUNC();
10508 +
10509 +       if (rptr->lifetime == 0)
10510 +               return MIPV6_IGN_RTR;
10511 +       DEBUG(DEBUG_MDETECT, "Received a RA from router: "
10512 +             "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&rptr->raddr));
10513 +       spin_lock(&router_lock);
10514 +       
10515 +       /* Add or update router entry */
10516 +       if ((nrt = mipv6_rtr_get(&rptr->raddr)) == NULL) {
10517 +               if (addrtype == IPV6_ADDR_ANY || (nrt = mipv6_rtr_add(rptr)) == NULL) {
10518 +                               spin_unlock(&router_lock);
10519 +                               return MIPV6_IGN_RTR;
10520 +               }
10521 +               DEBUG(DBG_INFO, "Router not on list,adding it to the list"); 
10522 +               new_router = 1;
10523 +       }
10524 +       nrt->last_ra_rcvd = jiffies;
10525 +       nrt->state = ROUTER_REACHABLE;
10526 +       nrt->interval = rptr->interval;
10527 +       nrt->lifetime = rptr->lifetime;
10528 +       nrt->ifindex = rptr->ifindex;
10529 +       nrt->flags = rptr->flags;
10530 +       nrt->glob_addr = rptr->glob_addr;
10531 +
10532 +       /* Whether from current router */
10533 +       if (curr_router && curr_router->reachable && 
10534 +           is_current_rtr(nrt, curr_router)) {
10535 +               if (nrt->interval)
10536 +                       mod_timer(&r_timer, jiffies + (nrt->interval * HZ)/1000);
10537 +               else
10538 +                       mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10539 +               mdet_statemachine(RA_RCVD);
10540 +               spin_unlock(&router_lock);
10541 +               return MIPV6_ADD_RTR;
10542 +       } else if (oldstate == NO_RTR) {
10543 +               rt6_purge_dflt_routers(0); /* For multiple interface case */
10544 +               DEBUG(DBG_INFO, "No router or router not reachable, switching to new one");   
10545 +               goto handoff;
10546 +       }
10547 +       if (!curr_router) { 
10548 +               /* Startup */
10549 +               goto handoff;
10550 +       }
10551 +       /* Router behind same interface as current one ?*/
10552 +       same_if = (nrt->ifindex == curr_router->ifindex);
10553 +       /* Switch to new router behind same interface if eager cell 
10554 +        *  switching is used or if the interface is preferred
10555 +        */
10556 +       if ((new_router && eager_cell_switching && same_if) ||
10557 +           (mdet_get_if_preference(nrt->ifindex) > 
10558 +            mdet_get_if_preference(curr_router->ifindex))) {
10559 +               DEBUG(DBG_INFO, "Switching to new router.");
10560 +               goto handoff;
10561 +       }
10562 +       
10563 +       /* No handoff, don't add default route */
10564 +       DEBUG(DEBUG_MDETECT, "Ignoring RA");
10565 +       spin_unlock(&router_lock);
10566 +       return MIPV6_IGN_RTR;
10567 +handoff:
10568 +       clean_ncache(nrt, curr_router, same_if);
10569 +       nrt->reachable = 1;
10570 +       if (same_if && change_next_rtr(nrt, curr_router)) {
10571 +               mipv6_do_ll_dad(nrt->ifindex);
10572 +               nrt->flags |= LLADDR_TENTATIVE;
10573 +       }
10574 +       spin_unlock(&router_lock);
10575 +
10576 +       return MIPV6_CHG_RTR;
10577 +}      
10578 +
10579 +/* 
10580 + * Called from ndisc.c's router_discovery.
10581 + */
10582 +
10583 +static inline int ret_to_ha(struct in6_addr *addr)
10584 +{
10585 +       int res = 0;
10586 +       struct mn_info *minfo;
10587 +       read_lock(&mn_info_lock);
10588 +       minfo = mipv6_mninfo_get_by_ha(addr);
10589 +       if (minfo != NULL) {
10590 +               spin_lock(&minfo->lock);
10591 +               if (minfo->has_home_reg) {
10592 +                       res = 1;
10593 +               }
10594 +               spin_unlock(&minfo->lock);
10595 +       }
10596 +       read_unlock(&mn_info_lock);
10597 +       return res;
10598 +}
10599 +
10600 +static int mipv6_mn_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
10601 +{
10602 +       int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
10603 +       struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
10604 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
10605 +       struct router nrt;
10606 +       struct in6_addr *ha = NULL;
10607 +       u8 *lladdr = NULL;
10608 +       int res;
10609 +       DEBUG_FUNC();
10610 +
10611 +       memset(&nrt, 0, sizeof(struct router));
10612 +
10613 +       if (ra->icmph.icmp6_home_agent) {
10614 +               nrt.flags |= ND_RA_FLAG_HA;
10615 +               DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_HA up");
10616 +       }
10617 +
10618 +       if (ra->icmph.icmp6_addrconf_managed) {
10619 +               nrt.flags |= ND_RA_FLAG_MANAGED;
10620 +               DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_MANAGED up");
10621 +       }
10622 +
10623 +       if (ra->icmph.icmp6_addrconf_other) {
10624 +               nrt.flags |= ND_RA_FLAG_OTHER;
10625 +               DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_OTHER up");
10626 +       }
10627 +
10628 +       ipv6_addr_copy(&nrt.ll_addr, saddr);
10629 +       nrt.ifindex = ifi;
10630 +       nrt.lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
10631 +
10632 +       if (ndopts->nd_opts_src_lladdr) {
10633 +               lladdr = (u8 *) ndopts->nd_opts_src_lladdr+2;
10634 +               nrt.link_addr_len = skb->dev->addr_len;
10635 +               memcpy(nrt.link_addr, lladdr, nrt.link_addr_len);
10636 +       }
10637 +       if (ndopts->nd_opts_pi) {
10638 +               struct nd_opt_hdr *p;
10639 +               for (p = ndopts->nd_opts_pi;
10640 +                    p;
10641 +                    p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
10642 +                       struct prefix_info *pinfo;
10643 +                       int update = 0;
10644 +
10645 +                       pinfo = (struct prefix_info *) p;
10646 +
10647 +                       if (!pinfo->autoconf)
10648 +                               continue;
10649 +
10650 +                       if ((pinfo->router_address && 
10651 +                            (update = ret_to_ha(&pinfo->prefix))) ||
10652 +                           ipv6_addr_type(&nrt.raddr) != IPV6_ADDR_UNICAST) {
10653 +                               ipv6_addr_copy(&nrt.raddr, &pinfo->prefix);
10654 +                               nrt.pfix_len = pinfo->prefix_len;
10655 +                               if (pinfo->router_address)
10656 +                                       nrt.glob_addr = 1;
10657 +                               else
10658 +                                       nrt.glob_addr = 0;
10659 +                               if (update)
10660 +                                       ha = &pinfo->prefix;
10661 +                               DEBUG(DBG_DATADUMP, "Address of the received "
10662 +                                     "prefix info option: %x:%x:%x:%x:%x:%x:%x:%x", 
10663 +                                     NIPV6ADDR(&nrt.raddr));
10664 +                               DEBUG(DBG_DATADUMP, "the length of the prefix is %d", 
10665 +                                     nrt.pfix_len);
10666 +                       }
10667 +               }
10668 +       }
10669 +       if (ndopts->nd_opts_rai) {                      
10670 +               nrt.interval = ntohl(*(__u32 *)(ndopts->nd_opts_rai+4));
10671 +               DEBUG(DBG_DATADUMP, 
10672 +                     "received router interval option with interval : %d ",
10673 +                     nrt.interval / HZ);
10674 +
10675 +               if (nrt.interval > MAX_RADV_INTERVAL) {
10676 +                       nrt.interval = 0;
10677 +                       DEBUG(DBG_DATADUMP, "but we are using: %d, "
10678 +                             "because interval>MAX_RADV_INTERVAL",
10679 +                             nrt.interval / HZ);
10680 +               }
10681 +       }
10682 +
10683 +       res = mipv6_router_event(&nrt);
10684 +       
10685 +       if (ha && lladdr) {
10686 +               mipv6_mn_ha_nd_update(__dev_get_by_index(ifi), ha, lladdr);
10687 +       }
10688 +       return res;
10689 +}
10690 +
10691 +int __init mipv6_initialize_mdetect(void)
10692 +{
10693 +
10694 +       DEBUG_FUNC();
10695 +
10696 +       spin_lock_init(&router_lock);
10697 +       spin_lock_init(&ho_lock);
10698 +       init_timer(&coa_timer);
10699 +       init_timer(&r_timer);
10700 +       r_timer.expires = jiffies + HZ;
10701 +       add_timer(&r_timer);
10702 +
10703 +       /* Actual HO, also deletes old routes after the addition of new ones 
10704 +          in ndisc */
10705 +       MIPV6_SETCALL(mipv6_change_router, mipv6_change_router);
10706 +
10707 +       MIPV6_SETCALL(mipv6_ra_rcv, mipv6_mn_ra_rcv);
10708 +
10709 +       return 0;
10710 +}
10711 +
10712 +int __exit mipv6_shutdown_mdetect()
10713 +{
10714 +
10715 +       DEBUG_FUNC();
10716 +
10717 +       MIPV6_RESETCALL(mipv6_ra_rcv);
10718 +       MIPV6_RESETCALL(mipv6_change_router);
10719 +       spin_lock_bh(&router_lock);
10720 +       spin_lock(&ho_lock);
10721 +       del_timer(&coa_timer);
10722 +       del_timer(&r_timer);
10723 +       /* Free the memory allocated by router list */
10724 +       list_free(&curr_router);
10725 +       if (_ho)
10726 +               kfree(_ho);
10727 +       spin_unlock(&ho_lock);
10728 +       spin_unlock_bh(&router_lock);
10729 +       return 0;
10730 +}
10731 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.h linux-2.4.25/net/ipv6/mobile_ip6/mdetect.h
10732 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.h      1970-01-01 01:00:00.000000000 +0100
10733 +++ linux-2.4.25/net/ipv6/mobile_ip6/mdetect.h  2004-06-26 11:29:31.000000000 +0100
10734 @@ -0,0 +1,37 @@
10735 +/*
10736 + *      MIPL Mobile IPv6 Movement detection module header file
10737 + *
10738 + *      $Id$
10739 + *
10740 + *      This program is free software; you can redistribute it and/or
10741 + *      modify it under the terms of the GNU General Public License
10742 + *      as published by the Free Software Foundation; either version
10743 + *      2 of the License, or (at your option) any later version.
10744 + */
10745 +
10746 +#ifndef _MDETECT_H
10747 +#define _MDETECT_H
10748 +
10749 +struct handoff {
10750 +       int home_address; /* Is the coa a home address */
10751 +       int ifindex;
10752 +       int plen;
10753 +       struct in6_addr *coa;
10754 +       struct in6_addr rtr_addr; /* Prefix or rtr address if coa is home address */
10755 +};
10756 +
10757 +int mipv6_initialize_mdetect(void);
10758 +
10759 +int mipv6_shutdown_mdetect(void);
10760 +
10761 +int mipv6_get_care_of_address(struct in6_addr *homeaddr, struct in6_addr *coa);
10762 +
10763 +int mipv6_mdet_del_if(int ifindex);
10764 +
10765 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex);
10766 +
10767 +void mipv6_mdet_retrigger_ho(void);
10768 +
10769 +void mipv6_mdet_set_curr_rtr_reachable(int reachable);
10770 +
10771 +#endif /* _MDETECT_H */
10772 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.c linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.c
10773 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.c   1970-01-01 01:00:00.000000000 +0100
10774 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.c       2004-06-26 11:29:31.000000000 +0100
10775 @@ -0,0 +1,342 @@
10776 +/**
10777 + * Generic icmp routines
10778 + *
10779 + * Authors:
10780 + * Jaakko Laine <medved@iki.fi>,
10781 + * Ville Nuorvala <vnuorval@tcs.hut.fi> 
10782 + *
10783 + * $Id$
10784 + *
10785 + * This program is free software; you can redistribute it and/or
10786 + * modify it under the terms of the GNU General Public License
10787 + * as published by the Free Software Foundation; either version
10788 + * 2 of the License, or (at your option) any later version.
10789 + */
10790 +
10791 +#include <linux/config.h>
10792 +#include <linux/icmpv6.h>
10793 +#include <net/checksum.h>
10794 +#include <net/ipv6.h>
10795 +#include <net/ip6_route.h>
10796 +#include <net/mipv6.h>
10797 +#include <net/mipglue.h>
10798 +
10799 +#include "debug.h"
10800 +#include "bcache.h"
10801 +#include "mipv6_icmp.h"
10802 +#include "config.h"
10803 +
10804 +struct mipv6_icmpv6_msg {
10805 +       struct icmp6hdr icmph;
10806 +       __u8 *data;
10807 +       struct in6_addr *daddr;
10808 +       int len;
10809 +       __u32 csum;
10810 +};
10811 +
10812 +#define MIPV6_ICMP_HOP_LIMIT 64
10813 +
10814 +static struct socket *mipv6_icmpv6_socket = NULL;
10815 +static __u16 identifier = 0;
10816 +
10817 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb)
10818 +{
10819 +       return 0;
10820 +}
10821 +
10822 +static int mipv6_icmpv6_xmit_holder = -1;
10823 +
10824 +static int mipv6_icmpv6_xmit_lock_bh(void)
10825 +{
10826 +       if (!spin_trylock(&mipv6_icmpv6_socket->sk->lock.slock)) {
10827 +               if (mipv6_icmpv6_xmit_holder == smp_processor_id())
10828 +                       return -EAGAIN;
10829 +               spin_lock(&mipv6_icmpv6_socket->sk->lock.slock);
10830 +       }
10831 +       mipv6_icmpv6_xmit_holder = smp_processor_id();
10832 +       return 0;
10833 +}
10834 +
10835 +static __inline__ int mipv6_icmpv6_xmit_lock(void)
10836 +{
10837 +       int ret;
10838 +       local_bh_disable();
10839 +       ret = mipv6_icmpv6_xmit_lock_bh();
10840 +       if (ret)
10841 +               local_bh_enable();
10842 +       return ret;
10843 +}
10844 +
10845 +static void mipv6_icmpv6_xmit_unlock_bh(void)
10846 +{
10847 +       mipv6_icmpv6_xmit_holder = -1;
10848 +       spin_unlock(&mipv6_icmpv6_socket->sk->lock.slock);
10849 +}
10850 +
10851 +static __inline__ void mipv6_icmpv6_xmit_unlock(void)
10852 +{
10853 +       mipv6_icmpv6_xmit_unlock_bh();
10854 +       local_bh_enable();
10855 +}
10856 +
10857 +
10858 +/**
10859 + * mipv6_icmpv6_dest_unreach - Destination Unreachable ICMP error message handler
10860 + * @skb: buffer containing ICMP error message
10861 + *
10862 + * Special Mobile IPv6 ICMP handling.  If Correspondent Node receives
10863 + * persistent ICMP Destination Unreachable messages for a destination
10864 + * in its Binding Cache, the binding should be deleted.  See draft
10865 + * section 8.8.
10866 + **/
10867 +static int mipv6_icmpv6_rcv_dest_unreach(struct sk_buff *skb)
10868 +{
10869 +       struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
10870 +       struct ipv6hdr *ipv6h = (struct ipv6hdr *) (icmph + 1);
10871 +       int left = (skb->tail - skb->h.raw) - sizeof(*icmph)- sizeof(ipv6h);
10872 +       struct ipv6_opt_hdr *eh;
10873 +       struct rt2_hdr *rt2h = NULL;
10874 +       struct in6_addr *daddr = &ipv6h->daddr;
10875 +       struct in6_addr *saddr = &ipv6h->saddr;
10876 +       int hdrlen, nexthdr = ipv6h->nexthdr;
10877 +       struct mipv6_bce bce;
10878 +       DEBUG_FUNC();
10879 +
10880 +       eh = (struct ipv6_opt_hdr *) (ipv6h + 1);
10881 +
10882 +       while (left > 0) {
10883 +               if (nexthdr != NEXTHDR_HOP && nexthdr != NEXTHDR_DEST && 
10884 +                   nexthdr != NEXTHDR_ROUTING)
10885 +                       return 0;
10886 +
10887 +               hdrlen = ipv6_optlen(eh);
10888 +               if (hdrlen > left)
10889 +                       return 0;
10890 +
10891 +               if (nexthdr == NEXTHDR_ROUTING) {
10892 +                       struct ipv6_rt_hdr *rth = (struct ipv6_rt_hdr *) eh;
10893 +
10894 +                       if (rth->type == IPV6_SRCRT_TYPE_2) {
10895 +                               if (hdrlen != sizeof(struct rt2_hdr))
10896 +                                       return 0;
10897 +
10898 +                               rt2h = (struct rt2_hdr *) rth;
10899 +
10900 +                               if (rt2h->rt_hdr.segments_left > 0)
10901 +                                       daddr = &rt2h->addr;
10902 +                               break;
10903 +                       }
10904 +               }
10905 +               /* check for home address option in case this node is a MN */
10906 +               if (nexthdr == NEXTHDR_DEST) {
10907 +                       __u8 *raw = (__u8 *) eh;
10908 +                       __u16 i = 2;
10909 +                       while (1) {
10910 +                               struct mipv6_dstopt_homeaddr *hao;
10911 +                               
10912 +                               if (i + sizeof (*hao) > hdrlen)
10913 +                                       break;
10914 +                               
10915 +                               hao = (struct mipv6_dstopt_homeaddr *) &raw[i];
10916 +                               
10917 +                               if (hao->type == MIPV6_TLV_HOMEADDR &&
10918 +                                   hao->length == sizeof(struct in6_addr)) {
10919 +                                       saddr = &hao->addr;
10920 +                                       break;
10921 +                               }
10922 +                               if (hao->type)
10923 +                                       i += hao->length + 2;
10924 +                               else
10925 +                                       i++;
10926 +                       }
10927 +                       
10928 +               }
10929 +               nexthdr = eh->nexthdr;
10930 +               eh = (struct ipv6_opt_hdr *) ((u8 *) eh + hdrlen);
10931 +               left -= hdrlen;
10932 +       }
10933 +       if (rt2h == NULL) return 0;
10934 +
10935 +       if (mipv6_bcache_get(daddr, saddr, &bce) == 0 && !(bce.flags&HOME_REGISTRATION)) {
10936 +               /* A primitive algorithm for detecting persistent ICMP destination unreachable messages */
10937 +               if (bce.destunr_count &&
10938 +                   time_after(jiffies, 
10939 +                              bce.last_destunr + MIPV6_DEST_UNR_IVAL*HZ)) 
10940 +                       bce.destunr_count = 0;
10941 +
10942 +               bce.destunr_count++;
10943 +
10944 +               mipv6_bcache_icmp_err(daddr, saddr, bce.destunr_count);
10945 +
10946 +               if (bce.destunr_count > MIPV6_MAX_DESTUNREACH && mipv6_bcache_delete(daddr, saddr, CACHE_ENTRY) == 0) {
10947 +                       DEBUG(DBG_INFO, "Deleted bcache entry "
10948 +                             "%x:%x:%x:%x:%x:%x:%x:%x "
10949 +                             "%x:%x:%x:%x:%x:%x:%x:%x (reason: "
10950 +                             "%d dest unreachables) ",
10951 +                             NIPV6ADDR(daddr), NIPV6ADDR(saddr), bce.destunr_count);
10952 +               }
10953 +       }
10954 +       return 0;
10955 +}
10956 +
10957 +static int mipv6_icmpv6_getfrag(const void *data, struct in6_addr *saddr, 
10958 +                               char *buff, unsigned int offset, 
10959 +                               unsigned int len)
10960 +{
10961 +       struct mipv6_icmpv6_msg *msg = (struct mipv6_icmpv6_msg *) data;
10962 +       struct icmp6hdr *icmph;
10963 +       __u32 csum;
10964 +
10965 +       if (offset) {
10966 +               msg->csum = csum_partial_copy_nocheck(msg->data + offset -
10967 +                                                     sizeof(*icmph), buff,
10968 +                                                     len, msg->csum);
10969 +               return 0;
10970 +       }
10971 +       
10972 +       csum = csum_partial_copy_nocheck((__u8 *) &msg->icmph, buff,
10973 +                                        sizeof(*icmph), msg->csum);
10974 +       
10975 +       csum = csum_partial_copy_nocheck(msg->data, buff + sizeof(*icmph),
10976 +                                        len - sizeof(*icmph), csum);
10977 +       
10978 +       icmph = (struct icmp6hdr *) buff;
10979 +       
10980 +       icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
10981 +                                            IPPROTO_ICMPV6, csum);
10982 +       return 0; 
10983 +}
10984 +
10985 +/**
10986 + * mipv6_icmpv6_send - generic icmpv6 message send
10987 + * @daddr: destination address
10988 + * @saddr: source address
10989 + * @type: icmp type
10990 + * @code: icmp code
10991 + * @id: packet identifier. If null, uses internal counter to get new id
10992 + * @data: packet data
10993 + * @datalen: length of data in bytes
10994 + */
10995 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr, int type,
10996 +                      int code, __u16 *id, __u16 flags, void *data, int datalen)
10997 +{
10998 +       struct sock *sk = mipv6_icmpv6_socket->sk;
10999 +       struct flowi fl;
11000 +       struct mipv6_icmpv6_msg msg;
11001 +
11002 +       DEBUG_FUNC();
11003 +
11004 +       fl.proto = IPPROTO_ICMPV6;
11005 +       fl.fl6_dst = daddr;
11006 +       fl.fl6_src = saddr;
11007 +       fl.fl6_flowlabel = 0;
11008 +       fl.uli_u.icmpt.type = type;
11009 +       fl.uli_u.icmpt.code = code;
11010 +
11011 +       msg.icmph.icmp6_type = type;
11012 +       msg.icmph.icmp6_code = code;
11013 +       msg.icmph.icmp6_cksum = 0;
11014 +
11015 +       if (id)
11016 +               msg.icmph.icmp6_identifier = htons(*id);
11017 +       else
11018 +               msg.icmph.icmp6_identifier = htons(identifier++);
11019 +
11020 +       msg.icmph.icmp6_sequence = htons(flags);
11021 +       msg.data = data;
11022 +       msg.csum = 0;
11023 +       msg.len = datalen + sizeof(struct icmp6hdr);
11024 +       msg.daddr = daddr;
11025 +
11026 +       if (mipv6_icmpv6_xmit_lock())
11027 +               return;
11028 +
11029 +       ip6_build_xmit(sk, mipv6_icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
11030 +                      MSG_DONTWAIT);
11031 +
11032 +       ICMP6_INC_STATS_BH(Icmp6OutMsgs);
11033 +       mipv6_icmpv6_xmit_unlock();
11034 +}
11035 +
11036 +/**
11037 + * icmp6_rcv - ICMPv6 receive and multiplex
11038 + * @skb: buffer containing ICMP message
11039 + *
11040 + * Generic ICMPv6 receive function to multiplex messages to approriate
11041 + * handlers.  Only used for ICMP messages with special handling in
11042 + * Mobile IPv6.
11043 + **/
11044 +static void icmp6_rcv(struct sk_buff *skb)
11045 +{
11046 +       struct icmp6hdr *hdr;
11047 +
11048 +       if (skb_is_nonlinear(skb) &&
11049 +           skb_linearize(skb, GFP_ATOMIC) != 0) {
11050 +               kfree_skb(skb);
11051 +               return;
11052 +       }
11053 +       __skb_push(skb, skb->data-skb->h.raw);
11054 +
11055 +       hdr = (struct icmp6hdr *) skb->h.raw;
11056 +
11057 +       switch (hdr->icmp6_type) {
11058 +       case ICMPV6_DEST_UNREACH:
11059 +               mipv6_icmpv6_rcv_dest_unreach(skb);
11060 +               break;
11061 +
11062 +       case ICMPV6_PARAMPROB:
11063 +               mip6_fn.icmpv6_paramprob_rcv(skb);
11064 +               break;
11065 +
11066 +       case MIPV6_DHAAD_REPLY:
11067 +               mip6_fn.icmpv6_dhaad_rep_rcv(skb);
11068 +               break;
11069 +
11070 +       case MIPV6_PREFIX_ADV:
11071 +               mip6_fn.icmpv6_pfxadv_rcv(skb);
11072 +               break;
11073 +
11074 +       case MIPV6_DHAAD_REQUEST:
11075 +               mip6_fn.icmpv6_dhaad_req_rcv(skb);
11076 +               break;
11077 +
11078 +       case MIPV6_PREFIX_SOLICIT:
11079 +               mip6_fn.icmpv6_pfxsol_rcv(skb);
11080 +               break;
11081 +       }
11082 +}
11083 +
11084 +int mipv6_icmpv6_init(void)
11085 +{
11086 +       struct sock *sk;
11087 +       int err;
11088 +
11089 +       if ((mipv6_icmpv6_socket = sock_alloc()) == NULL) {
11090 +               DEBUG(DBG_ERROR, "Cannot allocate mipv6_icmpv6_socket");
11091 +               return -1;
11092 +       }
11093 +       mipv6_icmpv6_socket->type = SOCK_RAW;
11094 +
11095 +       if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMP, 
11096 +                              &mipv6_icmpv6_socket)) < 0) {
11097 +               DEBUG(DBG_ERROR, "Cannot initialize mipv6_icmpv6_socket");
11098 +               sock_release(mipv6_icmpv6_socket);
11099 +               mipv6_icmpv6_socket = NULL; /* For safety */
11100 +               return err;
11101 +       }
11102 +       sk = mipv6_icmpv6_socket->sk;
11103 +       sk->allocation = GFP_ATOMIC;
11104 +       sk->prot->unhash(sk);
11105 +
11106 +       /* Register our ICMP handler */
11107 +       MIPV6_SETCALL(mipv6_icmp_rcv, icmp6_rcv);
11108 +       return 0;
11109 +}
11110 +
11111 +void mipv6_icmpv6_exit(void)
11112 +{
11113 +       MIPV6_RESETCALL(mipv6_icmp_rcv);
11114 +       if (mipv6_icmpv6_socket)
11115 +               sock_release(mipv6_icmpv6_socket);
11116 +       mipv6_icmpv6_socket = NULL; /* For safety */
11117 +}
11118 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.h linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.h
11119 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.h   1970-01-01 01:00:00.000000000 +0100
11120 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.h       2004-06-26 11:29:31.000000000 +0100
11121 @@ -0,0 +1,43 @@
11122 +/*
11123 + *      MIPL Mobile IPv6 ICMP send and receive prototypes
11124 + *
11125 + *      $Id$
11126 + *
11127 + *      This program is free software; you can redistribute it and/or
11128 + *      modify it under the terms of the GNU General Public License
11129 + *      as published by the Free Software Foundation; either version
11130 + *      2 of the License, or (at your option) any later version.
11131 + */
11132 +
11133 +#ifndef _MIPV6_ICMP
11134 +#define _MIPV6_ICMP
11135 +
11136 +#include <linux/config.h>
11137 +#include <linux/in6.h>
11138 +
11139 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr,
11140 +                      int type, int code, __u16 *id, __u16 flags,
11141 +                      void *data, int datalen);
11142 +
11143 +void mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id);
11144 +
11145 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr);
11146 +/* No handling */
11147 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb);
11148 +
11149 +/* Receive DHAAD Reply message */
11150 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb);
11151 +/* Receive Parameter Problem message */
11152 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb);
11153 +/* Receive prefix advertisements */
11154 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb);
11155 +
11156 +/* Receive DHAAD Request message */
11157 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb);
11158 +/* Receive prefix solicitations */
11159 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb);
11160 +
11161 +int mipv6_icmpv6_init(void);
11162 +void mipv6_icmpv6_exit(void);
11163 +
11164 +#endif
11165 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_ha.c linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_ha.c
11166 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_ha.c        1970-01-01 01:00:00.000000000 +0100
11167 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_ha.c    2004-06-26 11:29:31.000000000 +0100
11168 @@ -0,0 +1,158 @@
11169 +/*
11170 + *     Home Agent specific ICMP routines
11171 + *
11172 + *     Authors:
11173 + *     Antti Tuominen  <ajtuomin@tml.hut.fi>
11174 + *     Jaakko Laine    <medved@iki.fi>
11175 + *
11176 + *      $Id$
11177 + *
11178 + *      This program is free software; you can redistribute it and/or
11179 + *      modify it under the terms of the GNU General Public License
11180 + *      as published by the Free Software Foundation; either version
11181 + *      2 of the License, or (at your option) any later version.
11182 + */
11183 +
11184 +#include <linux/autoconf.h>
11185 +#include <linux/sched.h>
11186 +#include <net/ipv6.h>
11187 +#include <net/addrconf.h>
11188 +#include <net/ip6_route.h>
11189 +#include <net/mipv6.h>
11190 +
11191 +#include "halist.h"
11192 +#include "debug.h"
11193 +#include "mipv6_icmp.h"
11194 +//#include "prefix.h"
11195 +
11196 +/* Is this the easiest way of checking on 
11197 + *  which interface an anycast address is ?
11198 + */
11199 +static int find_ac_dev(struct in6_addr *addr)
11200 +{
11201 +       int ifindex = 0;
11202 +       struct net_device *dev;
11203 +       read_lock(&dev_base_lock);
11204 +       for (dev=dev_base; dev; dev=dev->next) {
11205 +               if (ipv6_chk_acast_addr(dev, addr)) {
11206 +                       ifindex = dev->ifindex;
11207 +                       break;
11208 +               }
11209 +       }
11210 +       read_unlock(&dev_base_lock);
11211 +       return ifindex;
11212 +}
11213 +
11214 +/**
11215 + * mipv6_icmpv6_send_dhaad_rep - Reply to DHAAD Request
11216 + * @ifindex: index of interface request was received from
11217 + * @id: request's identification number
11218 + * @daddr: requester's IPv6 address
11219 + *
11220 + * When Home Agent receives Dynamic Home Agent Address Discovery
11221 + * request, it replies with a list of home agents available on the
11222 + * home link.
11223 + */
11224 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr)
11225 +{
11226 +       __u8 *data = NULL;
11227 +       struct in6_addr home, *ha_addrs = NULL;
11228 +       int addr_count, max_addrs, size = 0;
11229 +
11230 +       if (daddr == NULL)
11231 +               return;
11232 +
11233 +       if (mipv6_ha_get_addr(ifindex, &home) < 0) {
11234 +               DEBUG(DBG_INFO, "Not Home Agent in this interface");
11235 +               return;
11236 +       }
11237 +
11238 +       /* We send all available HA addresses, not exceeding a maximum
11239 +        * number we can fit in a packet with minimum IPv6 MTU (to
11240 +        * avoid fragmentation).
11241 +        */
11242 +       max_addrs = 76;
11243 +       addr_count = mipv6_ha_get_pref_list(ifindex, &ha_addrs, max_addrs);
11244 +
11245 +       if (addr_count < 0) return;
11246 +
11247 +       if (addr_count != 0 && ha_addrs == NULL) {
11248 +               DEBUG(DBG_ERROR, "addr_count = %d but return no addresses", 
11249 +                     addr_count);
11250 +               return;
11251 +       }
11252 +       data = (u8 *)ha_addrs;
11253 +
11254 +       size = addr_count * sizeof(struct in6_addr);
11255 +
11256 +       mipv6_icmpv6_send(daddr, &home, MIPV6_DHAAD_REPLY, 
11257 +                         0, &id, 0, data, size);
11258 +       if (ha_addrs) {
11259 +               data = NULL;
11260 +               kfree(ha_addrs);
11261 +       }
11262 +}
11263 +
11264 +/** 
11265 + * mipv6_icmpv6_dhaad_req - Home Agent Address Discovery Request ICMP handler
11266 + * @skb: buffer containing ICMP information message
11267 + *
11268 + * Special Mobile IPv6 ICMP message.  Handles Dynamic Home Agent
11269 + * Address Discovery Request messages.
11270 + **/
11271 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb)
11272 +{
11273 +       struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11274 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11275 +       struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11276 +       __u16 identifier;
11277 +       int ifindex = 0;
11278 +
11279 +       DEBUG_FUNC();
11280 +
11281 +       /* Invalid packet checks. */
11282 +       if (phdr->icmp6_code != 0)
11283 +               return 0;
11284 +
11285 +       identifier = ntohs(phdr->icmp6_identifier);
11286 +
11287 +       /* 
11288 +        * Make sure we have the right ifindex (if the
11289 +        * req came through another interface. 
11290 +        */
11291 +       ifindex = find_ac_dev(daddr);
11292 +       if (ifindex == 0) { 
11293 +               DEBUG(DBG_WARNING, "received dhaad request to anycast address %x:%x:%x:%x:%x:%x:%x:%x"
11294 +                     " on which prefix we are not HA",
11295 +                     NIPV6ADDR(daddr));
11296 +               return 0;
11297 +       }
11298 +
11299 +       /*
11300 +        * send reply with list
11301 +        */
11302 +       mipv6_icmpv6_send_dhaad_rep(ifindex, identifier, saddr);
11303 +       return 1;
11304 +}
11305 +#if 0
11306 +/**
11307 + * mipv6_icmpv6_handle_pfx_sol - handle prefix solicitations
11308 + * @skb: sk_buff including the icmp6 message
11309 + */
11310 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb)
11311 +{
11312 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11313 +       struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11314 +       struct inet6_ifaddr *ifp;
11315 +
11316 +       DEBUG_FUNC();
11317 +
11318 +       if (!(ifp = ipv6_get_ifaddr(daddr, NULL)))
11319 +               return -1;
11320 +
11321 +       in6_ifa_put(ifp);
11322 +       mipv6_pfx_cancel_send(saddr, -1);
11323 +
11324 +       return 0;
11325 +}
11326 +#endif
11327 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_mn.c linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_mn.c
11328 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_mn.c        1970-01-01 01:00:00.000000000 +0100
11329 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_mn.c    2004-06-26 11:29:31.000000000 +0100
11330 @@ -0,0 +1,273 @@
11331 +/*
11332 + *     Mobile Node specific ICMP routines
11333 + *
11334 + *     Authors:
11335 + *     Antti Tuominen  <ajtuomin@tml.hut.fi>
11336 + *     Jaakko Laine    <medved@iki.fi>
11337 + *
11338 + *      $Id$
11339 + *
11340 + *      This program is free software; you can redistribute it and/or
11341 + *      modify it under the terms of the GNU General Public License
11342 + *      as published by the Free Software Foundation; either version
11343 + *      2 of the License, or (at your option) any later version.
11344 + */
11345 +
11346 +#include <linux/sched.h>
11347 +#include <net/ipv6.h>
11348 +#include <net/ip6_route.h>
11349 +#include <net/addrconf.h>
11350 +#include <net/mipv6.h>
11351 +
11352 +#include "mn.h"
11353 +#include "bul.h"
11354 +#include "mdetect.h"
11355 +#include "debug.h"
11356 +#include "mipv6_icmp.h"
11357 +#include "util.h"
11358 +//#include "prefix.h"
11359 +
11360 +#define INFINITY 0xffffffff
11361 +
11362 +/**
11363 + * mipv6_icmpv6_paramprob - Parameter Problem ICMP error message handler
11364 + * @skb: buffer containing ICMP error message
11365 + *
11366 + * Special Mobile IPv6 ICMP handling.  If Mobile Node receives ICMP
11367 + * Parameter Problem message when using a Home Address Option,
11368 + * offending node should be logged and error message dropped.  If
11369 + * error is received because of a Binding Update, offending node
11370 + * should be recorded in Binding Update List and no more Binding
11371 + * Updates should be sent to this destination.  See RFC 3775 section
11372 + * 10.15.
11373 + **/
11374 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb)
11375 +{
11376 +       struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11377 +       struct in6_addr *saddr = skb ? &skb->nh.ipv6h->saddr : NULL;
11378 +       struct in6_addr *daddr = skb ? &skb->nh.ipv6h->daddr : NULL;
11379 +       struct ipv6hdr *hdr = (struct ipv6hdr *) (phdr + 1);
11380 +       int ulen = (skb->tail - (unsigned char *) (phdr + 1));
11381 +
11382 +       int errptr;
11383 +       __u8 *off_octet;
11384 +
11385 +       DEBUG_FUNC();
11386 +
11387 +       /* We only handle code 1 & 2 messages. */
11388 +       if (phdr->icmp6_code != ICMPV6_UNK_NEXTHDR &&
11389 +           phdr->icmp6_code != ICMPV6_UNK_OPTION)
11390 +               return 0;
11391 +
11392 +       /* Find offending octet in the original packet. */
11393 +       errptr = ntohl(phdr->icmp6_pointer);
11394 +
11395 +       /* There is not enough of the original packet left to figure
11396 +        * out what went wrong. Bail out. */
11397 +       if (ulen <= errptr)
11398 +               return 0;
11399 +
11400 +       off_octet = ((__u8 *) hdr + errptr);
11401 +       DEBUG(DBG_INFO, "Parameter problem: offending octet %d [0x%2x]",
11402 +             errptr, *off_octet);
11403 +
11404 +       /* If CN did not understand Mobility Header, set BUL entry to
11405 +        * ACK_ERROR so no further BUs are sumbitted to this CN. */
11406 +       if (phdr->icmp6_code == ICMPV6_UNK_NEXTHDR &&
11407 +           *off_octet == IPPROTO_MOBILITY) {
11408 +               struct bul_inval_args args;
11409 +               args.all_rr_states = 1;
11410 +               args.cn = saddr;
11411 +               args.mn = daddr;
11412 +               write_lock(&bul_lock);
11413 +               mipv6_bul_iterate(mn_bul_invalidate, &args);
11414 +               write_unlock(&bul_lock);
11415 +       }
11416 +
11417 +       /* If CN did not understand Home Address Option, we log an
11418 +        * error and discard the error message. */
11419 +       if (phdr->icmp6_code == ICMPV6_UNK_OPTION &&
11420 +           *off_octet == MIPV6_TLV_HOMEADDR) {
11421 +               DEBUG(DBG_WARNING, "Correspondent node does not "
11422 +                     "implement Home Address Option receipt.");
11423 +               return 1;
11424 +       }
11425 +       return 0;
11426 +}
11427 +
11428 +/**
11429 + * mipv6_mn_dhaad_send_req - Send DHAAD Request to home network
11430 + * @home_addr: address to do DHAAD for
11431 + * @plen: prefix length for @home_addr
11432 + *
11433 + * Send Dynamic Home Agent Address Discovery Request to the Home
11434 + * Agents anycast address in the nodes home network.
11435 + **/
11436 +void 
11437 +mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id)
11438 +{
11439 +       struct in6_addr ha_anycast;
11440 +       struct in6_addr careofaddr;
11441 +       
11442 +       if (mipv6_get_care_of_address(home_addr, &careofaddr) < 0) {
11443 +               DEBUG(DBG_WARNING, "Could not get node's Care-of Address");
11444 +               return;
11445 +       }
11446 +
11447 +       if (mipv6_ha_anycast(&ha_anycast, home_addr, plen) < 0) {
11448 +               DEBUG(DBG_WARNING, 
11449 +                     "Could not get Home Agent Anycast address for home address %x:%x.%x:%x:%x:%x:%x:%x/%d",
11450 +                     NIPV6ADDR(home_addr), plen);
11451 +               return;
11452 +       }
11453 +
11454 +       mipv6_icmpv6_send(&ha_anycast, &careofaddr, MIPV6_DHAAD_REQUEST, 0, 
11455 +                         &dhaad_id, 0, NULL, 0);
11456 +
11457 +}
11458 +
11459 +/** 
11460 + * mipv6_icmpv6_dhaad_rep - Home Agent Address Discovery Reply ICMP handler
11461 + * @skb: buffer containing ICMP information message
11462 + *
11463 + * Special Mobile IPv6 ICMP message.  Handles Dynamic Home Agent
11464 + * Address Discovery Reply messages.
11465 + **/
11466 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb)
11467 +{
11468 +       struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11469 +       struct in6_addr *address;
11470 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11471 +       __u16 identifier;
11472 +       int ulen = (skb->tail - (unsigned char *) ((__u32 *) phdr + 2));
11473 +       int i;
11474 +       struct in6_addr home_addr, coa;
11475 +       struct in6_addr *first_ha = NULL;
11476 +       struct mn_info *minfo;
11477 +       int n_addr = ulen / sizeof(struct in6_addr);
11478 +
11479 +       DEBUG_FUNC();
11480 +
11481 +       /* Invalid packet checks. */
11482 +       if (ulen % sizeof(struct in6_addr) != 0)
11483 +               return 0;
11484 +
11485 +       if (phdr->icmp6_code != 0)
11486 +               return 0;
11487 +
11488 +       identifier = ntohs(phdr->icmp6_identifier);
11489 +       if (ulen > 0) {
11490 +               address = (struct in6_addr *) ((__u32 *) phdr + 2);
11491 +       } else {
11492 +               address = saddr;
11493 +               n_addr = 1;
11494 +       }
11495 +
11496 +       /* receive list of home agent addresses
11497 +        * add to home agents list
11498 +        */
11499 +       DEBUG(DBG_INFO, "DHAAD: got %d home agents", n_addr);
11500 +
11501 +       first_ha = address;
11502 +
11503 +       /* lookup H@ with identifier */
11504 +       read_lock(&mn_info_lock);
11505 +       minfo = mipv6_mninfo_get_by_id(identifier);
11506 +       if (!minfo) {
11507 +               read_unlock(&mn_info_lock);
11508 +               DEBUG(DBG_INFO, "no mninfo with id %d", 
11509 +                     identifier);
11510 +               return 0;
11511 +       }
11512 +       spin_lock(&minfo->lock);
11513 +
11514 +       /* Logic:
11515 +        * 1. if old HA on list, prefer it
11516 +        * 2. otherwise first HA on list prefered
11517 +        */
11518 +       for (i = 0; i < n_addr; i++) {
11519 +               DEBUG(DBG_INFO, "HA[%d] %x:%x:%x:%x:%x:%x:%x:%x",
11520 +                     i, NIPV6ADDR(address));
11521 +               if (ipv6_addr_cmp(&minfo->ha, address) == 0) {
11522 +                       spin_unlock(&minfo->lock);
11523 +                       read_unlock(&mn_info_lock);
11524 +                       return 0;
11525 +               }
11526 +               address++;
11527 +       }
11528 +       ipv6_addr_copy(&minfo->ha, first_ha);
11529 +       spin_unlock(&minfo->lock);
11530 +       ipv6_addr_copy(&home_addr, &minfo->home_addr);
11531 +       read_unlock(&mn_info_lock);
11532 +
11533 +       mipv6_get_care_of_address(&home_addr, &coa);
11534 +       init_home_registration(&home_addr, &coa);
11535 +
11536 +       return 1;
11537 +}
11538 +#if 0
11539 +/**
11540 + * mipv6_icmpv6_handle_pfx_adv - handle prefix advertisements
11541 + * @skb: sk_buff including the icmp6 message
11542 + */
11543 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb)
11544 +{
11545 +       struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
11546 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11547 +       struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11548 +       __u8 *opt = (__u8 *) (hdr + 1);
11549 +       int optlen = (skb->tail - opt);
11550 +       unsigned long min_expire = INFINITY;
11551 +       struct inet6_skb_parm *parm = (struct inet6_skb_parm *) skb->cb;
11552 +
11553 +       DEBUG_FUNC();
11554 +
11555 +       while (optlen > 0) {
11556 +               int len = opt[1] << 3;
11557 +               if (len == 0)
11558 +                       goto set_timer;
11559 +
11560 +               if (opt[0] == ND_OPT_PREFIX_INFO) {
11561 +                       int ifindex;
11562 +                       unsigned long expire;
11563 +                       struct prefix_info *pinfo =
11564 +                               (struct prefix_info *) opt;
11565 +                       struct net_device *dev;
11566 +                       struct mn_info *mninfo;
11567 +
11568 +                       read_lock(&mn_info_lock);
11569 +                       mninfo = mipv6_mninfo_get_by_ha(saddr);
11570 +                       if (mninfo == NULL) {
11571 +                               ifindex = 0;
11572 +                       } else {
11573 +                               spin_lock(&mninfo->lock);
11574 +                               ifindex = mninfo->ifindex;
11575 +                               spin_unlock(&mninfo->lock);
11576 +                               mninfo = NULL;
11577 +                       }
11578 +                       read_unlock(&mn_info_lock);
11579 +
11580 +                       if (!(dev = dev_get_by_index(ifindex))) {
11581 +                               DEBUG(DBG_WARNING, "Cannot find device by index %d", parm->iif);
11582 +                               goto nextopt;
11583 +                       }
11584 +
11585 +                       expire = ntohl(pinfo->valid);
11586 +                       expire = expire == 0 ? INFINITY : expire;
11587 +
11588 +                       min_expire = expire < min_expire ? expire : min_expire;
11589 +
11590 +                       dev_put(dev);
11591 +               }
11592 +
11593 +nextopt:
11594 +               optlen -= len;
11595 +               opt += len;
11596 +       }
11597 +
11598 +set_timer:
11599 +
11600 +       mipv6_pfx_add_home(parm->iif, saddr, daddr, min_expire);
11601 +       return 0;
11602 +}
11603 +#endif
11604 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mn.c linux-2.4.25/net/ipv6/mobile_ip6/mn.c
11605 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mn.c   1970-01-01 01:00:00.000000000 +0100
11606 +++ linux-2.4.25/net/ipv6/mobile_ip6/mn.c       2004-06-26 11:29:31.000000000 +0100
11607 @@ -0,0 +1,1521 @@
11608 +/*
11609 + *      Mobile-node functionality
11610 + *
11611 + *      Authors:
11612 + *      Sami Kivisaari          <skivisaa@cc.hut.fi>
11613 + *
11614 + *      $Id$
11615 + *
11616 + *      This program is free software; you can redistribute it and/or
11617 + *      modify it under the terms of the GNU General Public License
11618 + *      as published by the Free Software Foundation; either version
11619 + *      2 of the License, or (at your option) any later version.
11620 + *
11621 + */
11622 +
11623 +#include <linux/autoconf.h>
11624 +#include <linux/sched.h>
11625 +#include <linux/ipv6.h>
11626 +#include <linux/net.h>
11627 +#include <linux/init.h>
11628 +#include <linux/skbuff.h>
11629 +#include <linux/rtnetlink.h>
11630 +#include <linux/if_arp.h>
11631 +#include <linux/ipsec.h>
11632 +#include <linux/notifier.h>
11633 +#include <linux/list.h>
11634 +#include <linux/route.h>
11635 +#include <linux/netfilter.h>
11636 +#include <linux/netfilter_ipv6.h>
11637 +#include <linux/tqueue.h>
11638 +#include <linux/proc_fs.h>
11639 +
11640 +#include <asm/uaccess.h>
11641 +
11642 +#include <net/ipv6.h>
11643 +#include <net/addrconf.h>
11644 +#include <net/neighbour.h>
11645 +#include <net/ndisc.h>
11646 +#include <net/ip6_route.h>
11647 +#include <net/mipglue.h>
11648 +
11649 +#include "util.h"
11650 +#include "mdetect.h"
11651 +#include "bul.h"
11652 +#include "mobhdr.h"
11653 +#include "debug.h"
11654 +#include "mn.h"
11655 +#include "mipv6_icmp.h"
11656 +#include "multiaccess_ctl.h"
11657 +//#include "prefix.h"
11658 +#include "tunnel_mn.h"
11659 +#include "stats.h"
11660 +#include "config.h"
11661 +
11662 +#define MIPV6_BUL_SIZE 128
11663 +
11664 +static LIST_HEAD(mn_info_list);
11665 +
11666 +/* Lock for list of MN infos */
11667 +rwlock_t mn_info_lock = RW_LOCK_UNLOCKED;
11668 +
11669 +static spinlock_t ifrh_lock = SPIN_LOCK_UNLOCKED;
11670 +
11671 +struct ifr_holder {
11672 +       struct list_head list;
11673 +       struct in6_ifreq ifr;
11674 +       int old_ifi;
11675 +       struct handoff *ho;
11676 +};
11677 +
11678 +LIST_HEAD(ifrh_list);
11679 +
11680 +static struct tq_struct mv_home_addr_task;
11681 +
11682 +/* Determines whether manually configured home addresses are preferred as 
11683 + * source addresses over dynamically configured ones
11684 + */
11685 +int mipv6_use_preconfigured_hoaddr = 1; 
11686 +
11687 +/* Determines whether home addresses, which are at home are preferred as 
11688 + * source addresses over other home addresses
11689 + */
11690 +int mipv6_use_topol_corr_hoaddr = 0;
11691 +
11692 +static spinlock_t icmpv6_id_lock = SPIN_LOCK_UNLOCKED;
11693 +static __u16 icmpv6_id = 0;
11694 +
11695 +static inline __u16 mipv6_get_dhaad_id(void)
11696 +{
11697 +       __u16 ret;
11698 +       spin_lock_bh(&icmpv6_id_lock);
11699 +       ret = ++icmpv6_id;
11700 +       spin_unlock_bh(&icmpv6_id_lock);
11701 +       return ret;
11702 +}
11703 +
11704 +/** 
11705 + * mipv6_mninfo_get_by_home - Returns mn_info for a home address
11706 + * @haddr: home address of MN
11707 + *
11708 + * Returns mn_info on success %NULL otherwise.  Caller MUST hold
11709 + * @mn_info_lock (read or write).
11710 + **/
11711 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr)
11712 +{
11713 +       struct list_head *lh;
11714 +       struct mn_info *minfo;
11715 +
11716 +       DEBUG_FUNC();
11717 +
11718 +       if (!haddr)
11719 +               return NULL;
11720 +
11721 +       list_for_each(lh, &mn_info_list) {
11722 +               minfo = list_entry(lh, struct mn_info, list);
11723 +               spin_lock(&minfo->lock);
11724 +               if (!ipv6_addr_cmp(&minfo->home_addr, haddr)) {
11725 +                       spin_unlock(&minfo->lock);
11726 +                       return minfo;
11727 +               }
11728 +               spin_unlock(&minfo->lock);
11729 +       }
11730 +       return NULL;
11731 +}
11732 +
11733 +/**
11734 + * mipv6_mninfo_get_by_ha - Lookup mn_info with Home Agent address
11735 + * @home_agent: Home Agent address
11736 + *
11737 + * Searches for a mn_info entry with @ha set to @home_agent.  You MUST
11738 + * hold @mn_info_lock when calling this function.  Returns pointer to
11739 + * mn_info entry or %NULL on failure.
11740 + **/
11741 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent)
11742 +{
11743 +       struct list_head *lh;
11744 +       struct mn_info *minfo;
11745 +
11746 +       if (!home_agent)
11747 +               return NULL;
11748 +
11749 +       list_for_each(lh, &mn_info_list) {
11750 +               minfo = list_entry(lh, struct mn_info, list);
11751 +               spin_lock(&minfo->lock);
11752 +               if (!ipv6_addr_cmp(&minfo->ha, home_agent)) {
11753 +                       spin_unlock(&minfo->lock);
11754 +                       return minfo;
11755 +               }
11756 +               spin_unlock(&minfo->lock);
11757 +       }
11758 +       return NULL;
11759 +}
11760 +
11761 +/**
11762 + * mipv6_mninfo_get_by_id - Lookup mn_info with id
11763 + * @id: DHAAD identifier
11764 + *
11765 + * Searches for a mn_info entry with @dhaad_id set to @id.  You MUST
11766 + * hold @mn_info_lock when calling this function.  Returns pointer to
11767 + * mn_info entry or %NULL on failure.
11768 + **/
11769 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id)
11770 +{
11771 +       struct list_head *lh;
11772 +       struct mn_info *minfo = 0;
11773 +
11774 +       list_for_each(lh, &mn_info_list) {
11775 +               minfo = list_entry(lh, struct mn_info, list);
11776 +               spin_lock(&minfo->lock);
11777 +               if (minfo->dhaad_id == id) {
11778 +                       spin_unlock(&minfo->lock);
11779 +                       return minfo;
11780 +               }
11781 +               spin_unlock(&minfo->lock);
11782 +       }
11783 +       return NULL;
11784 +}
11785 +
11786 +/** 
11787 + * mipv6_mninfo_add - Adds a new home info for MN
11788 + * @ifindex: Interface for home address
11789 + * @home_addr:  Home address of MN, must be set
11790 + * @plen: prefix length of the home address, must be set
11791 + * @isathome : home address at home
11792 + * @lifetime: lifetime of the home address, 0 is infinite
11793 + * @ha: home agent for the home address
11794 + * @ha_plen: prefix length of home agent's address, can be zero 
11795 + * @ha_lifetime: Lifetime of the home address, 0 is infinite
11796 + *
11797 + * The function adds a new home info entry for MN, allowing it to
11798 + * register the home address with the home agent.  Starts home
11799 + * registration process.  If @ha is %ADDRANY, DHAAD is performed to
11800 + * find a home agent.  Returns 0 on success, a negative value
11801 + * otherwise.  Caller MUST NOT hold @mn_info_lock or
11802 + * @addrconf_hash_lock.
11803 + **/
11804 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen, 
11805 +                     int isathome, unsigned long lifetime, struct in6_addr *ha, 
11806 +                     int ha_plen, unsigned long ha_lifetime, int man_conf)
11807 +{
11808 +       struct mn_info *minfo;
11809 +       struct in6_addr coa;
11810 +
11811 +       DEBUG_FUNC();
11812 +
11813 +       write_lock_bh(&mn_info_lock);
11814 +       if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL){ 
11815 +             DEBUG(1, "MN info already exists");
11816 +             write_unlock_bh(&mn_info_lock);
11817 +             return;
11818 +       }
11819 +       minfo = kmalloc(sizeof(struct mn_info), GFP_ATOMIC);
11820 +       if (!minfo) {
11821 +              write_unlock_bh(&mn_info_lock);
11822 +              return;
11823 +       }
11824 +       memset(minfo, 0, sizeof(struct mn_info));
11825 +       spin_lock_init(&minfo->lock);
11826 +
11827 +       
11828 +       ipv6_addr_copy(&minfo->home_addr, home_addr);
11829 +
11830 +       if (ha)
11831 +               ipv6_addr_copy(&minfo->ha, ha);
11832 +       if (ha_plen < 128 && ha_plen > 0)
11833 +               minfo->home_plen = ha_plen; 
11834 +       else minfo->home_plen = 64;
11835 +
11836 +       minfo->ifindex_user = ifindex; /* Ifindex for tunnel interface */
11837 +       minfo->ifindex = ifindex; /* Interface on which home address is currently conf'd */
11838 +       /* TODO: we should get home address lifetime from somewhere */
11839 +       /* minfo->home_addr_expires = jiffies + lifetime * HZ; */
11840 +
11841 +       /* manual configuration flag cannot be unset by dynamic updates 
11842 +        *  from prefix advertisements
11843 +        */
11844 +       if (!minfo->man_conf) minfo->man_conf = man_conf; 
11845 +       minfo->is_at_home = isathome;
11846 +
11847 +       list_add(&minfo->list, &mn_info_list);
11848 +       write_unlock_bh(&mn_info_lock);
11849 +
11850 +       if (mipv6_get_care_of_address(home_addr, &coa) == 0) 
11851 +               init_home_registration(home_addr, &coa);
11852 +}
11853 +
11854 +/**
11855 + * mipv6_mninfo_del - Delete home info for MN 
11856 + * @home_addr : Home address or prefix 
11857 + * @del_dyn_only : Delete only dynamically created home entries 
11858 + *
11859 + * Deletes every mn_info entry that matches the first plen bits of
11860 + * @home_addr.  Returns number of deleted entries on success and a
11861 + * negative value otherwise.  Caller MUST NOT hold @mn_info_lock.
11862 + **/
11863 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only)
11864 +{
11865 +       struct list_head *lh, *next;
11866 +       struct mn_info *minfo;
11867 +       int ret = -1;
11868 +       if (!home_addr)
11869 +               return -1;
11870 +
11871 +       write_lock(&mn_info_lock);
11872 +
11873 +       list_for_each_safe(lh, next, &mn_info_list) {
11874 +               minfo = list_entry(lh, struct mn_info, list);
11875 +               if (ipv6_addr_cmp(&minfo->home_addr, home_addr) == 0
11876 +                   && ((!minfo->man_conf && del_dyn_only) || !del_dyn_only)){
11877 +                       list_del(&minfo->list);
11878 +                       kfree(minfo);
11879 +                       ret++;
11880 +               }
11881 +       }
11882 +       write_unlock(&mn_info_lock);
11883 +       return ret;
11884 +}
11885 +
11886 +void mipv6_mn_set_home(int ifindex, struct in6_addr *homeaddr, int plen,
11887 +                      struct in6_addr *homeagent, int ha_plen)
11888 +{
11889 +       mipv6_mninfo_add(ifindex, homeaddr, plen, 0, 0, 
11890 +                        homeagent, ha_plen, 0, 1);
11891 +}
11892 +
11893 +static int skip_dad(struct in6_addr *addr)
11894 +{
11895 +       struct mn_info *minfo;
11896 +       int ret = 0;
11897 +
11898 +       if (addr == NULL) {
11899 +               DEBUG(DBG_CRITICAL, "Null argument");
11900 +               return 0;
11901 +       }
11902 +       read_lock_bh(&mn_info_lock);
11903 +       if ((minfo = mipv6_mninfo_get_by_home(addr)) != NULL) {
11904 +               if ((minfo->is_at_home != MN_NOT_AT_HOME) && (minfo->has_home_reg))
11905 +                       ret = 1;
11906 +               DEBUG(DBG_INFO, "minfo->is_at_home = %d, minfo->has_home_reg = %d",
11907 +                     minfo->is_at_home, minfo->has_home_reg);
11908 +       }
11909 +       read_unlock_bh(&mn_info_lock);
11910 +       
11911 +       return ret;
11912 +}
11913 +/**
11914 + * mipv6_mn_is_home_addr - Determines if addr is node's home address
11915 + * @addr: IPv6 address
11916 + *
11917 + * Returns 1 if addr is node's home address.  Otherwise returns zero.
11918 + **/
11919 +int mipv6_mn_is_home_addr(struct in6_addr *addr)
11920 +{
11921 +       int ret = 0;
11922 +
11923 +       if (addr == NULL) {
11924 +               DEBUG(DBG_CRITICAL, "Null argument");
11925 +               return -1;
11926 +       }
11927 +       read_lock_bh(&mn_info_lock);
11928 +       if (mipv6_mninfo_get_by_home(addr))
11929 +               ret = 1;
11930 +       read_unlock_bh(&mn_info_lock);
11931 +
11932 +       return (ret);
11933 +}
11934 +
11935 +/** 
11936 + * mipv6_mn_is_at_home - determine if node is home for a home address
11937 + * @home_addr : home address of MN
11938 + *
11939 + * Returns 1 if home address in question is in the home network, 0
11940 + * otherwise.  Caller MUST NOT not hold @mn_info_lock.
11941 + **/ 
11942 +int mipv6_mn_is_at_home(struct in6_addr *home_addr)
11943 +{
11944 +       struct mn_info *minfo;
11945 +       int ret = 0;
11946 +       read_lock_bh(&mn_info_lock);
11947 +       if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11948 +               spin_lock(&minfo->lock);
11949 +               ret = (minfo->is_at_home == MN_AT_HOME);
11950 +               spin_unlock(&minfo->lock);
11951 +       }
11952 +       read_unlock_bh(&mn_info_lock);
11953 +       return ret;
11954 +}      
11955 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg)
11956 +{
11957 +       struct mn_info *minfo;
11958 +       read_lock_bh(&mn_info_lock);
11959 +
11960 +       if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11961 +               spin_lock(&minfo->lock);
11962 +               minfo->has_home_reg = has_home_reg;
11963 +               spin_unlock(&minfo->lock);
11964 +       }
11965 +       read_unlock_bh(&mn_info_lock);
11966 +}      
11967 +
11968 +static int mn_inet6addr_event(
11969 +       struct notifier_block *nb, unsigned long event, void *ptr)
11970 +{
11971 +       struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)ptr;
11972 +
11973 +       switch (event) {
11974 +       case NETDEV_UP:
11975 +               /* Is address a valid coa ?*/
11976 +               if (!(ifp->flags & IFA_F_TENTATIVE))
11977 +                       mipv6_mdet_finalize_ho(&ifp->addr, 
11978 +                                              ifp->idev->dev->ifindex);
11979 +               else if(skip_dad(&ifp->addr))
11980 +                       ifp->flags &= ~IFA_F_TENTATIVE;
11981 +               break;
11982 +       case NETDEV_DOWN:       
11983 +#if 0
11984 +               /* This is useless with manually configured home 
11985 +                  addresses, which will not expire
11986 +               */
11987 +               mipv6_mninfo_del(&ifp->addr, 0);
11988 +#endif
11989 +         break;
11990 +
11991 +       }
11992 +
11993 +       return NOTIFY_DONE;
11994 +}
11995 +
11996 +struct notifier_block mipv6_mn_inet6addr_notifier = {
11997 +       mn_inet6addr_event,
11998 +       NULL,
11999 +       0 /* check if using zero is ok */
12000 +};
12001 +
12002 +static void mipv6_get_saddr_hook(struct in6_addr *homeaddr)
12003 +{
12004 +       int found = 0, reiter = 0;
12005 +       struct list_head *lh;
12006 +       struct mn_info *minfo = NULL;
12007 +       struct in6_addr coa;
12008 +
12009 +       read_lock_bh(&mn_info_lock);
12010 +restart:
12011 +       list_for_each(lh, &mn_info_list) {
12012 +               minfo = list_entry(lh, struct mn_info, list);
12013 +               if ((ipv6_addr_scope(homeaddr) != ipv6_addr_scope(&minfo->home_addr)) 
12014 +                   || ipv6_chk_addr(&minfo->home_addr, NULL) == 0)
12015 +                       continue; 
12016 +
12017 +               spin_lock(&minfo->lock);
12018 +               if (minfo->is_at_home == MN_AT_HOME || minfo->has_home_reg) {
12019 +                       if ((mipv6_use_topol_corr_hoaddr && 
12020 +                            minfo->is_at_home == MN_AT_HOME) || 
12021 +                           (mipv6_use_preconfigured_hoaddr && 
12022 +                            minfo->man_conf) ||
12023 +                           (!(mipv6_use_preconfigured_hoaddr || 
12024 +                              mipv6_use_topol_corr_hoaddr) || reiter)) {
12025 +                               spin_unlock(&minfo->lock);
12026 +                               ipv6_addr_copy(homeaddr, &minfo->home_addr);
12027 +                               found = 1;
12028 +                               break;
12029 +                       }
12030 +               }
12031 +               spin_unlock(&minfo->lock);
12032 +       }
12033 +       if (!found && !reiter) {
12034 +               reiter = 1;
12035 +               goto restart;
12036 +       }
12037 +
12038 +       if (!found && minfo && 
12039 +           !mipv6_get_care_of_address(&minfo->home_addr, &coa)) {
12040 +               ipv6_addr_copy(homeaddr, &coa); 
12041 +       }
12042 +       read_unlock_bh(&mn_info_lock);
12043 +
12044 +       DEBUG(DBG_DATADUMP, "Source address selection:  %x:%x:%x:%x:%x:%x:%x:%x", 
12045 +             NIPV6ADDR(homeaddr));
12046 +       return;
12047 +}
12048 +
12049 +static void mv_home_addr(void *arg)
12050 +{
12051 +       mm_segment_t oldfs;
12052 +       int err = 0, new_if = 0;
12053 +       struct list_head *lh, *next;
12054 +       struct ifr_holder *ifrh;
12055 +       LIST_HEAD(list);
12056 +       
12057 +       DEBUG(DBG_INFO, "mipv6 move home address task");
12058 +
12059 +       spin_lock_bh(&ifrh_lock);
12060 +       list_splice_init(&ifrh_list, &list);
12061 +       spin_unlock_bh(&ifrh_lock);
12062 +       
12063 +       oldfs = get_fs(); set_fs(KERNEL_DS);
12064 +       list_for_each_safe(lh, next, &list) {
12065 +               ifrh = list_entry(lh, struct ifr_holder, list);
12066 +               if (ifrh->old_ifi) {
12067 +                       new_if = ifrh->ifr.ifr6_ifindex;
12068 +                       ifrh->ifr.ifr6_ifindex = ifrh->old_ifi;
12069 +                       err = addrconf_del_ifaddr(&ifrh->ifr); 
12070 +                       ifrh->ifr.ifr6_ifindex = new_if;
12071 +                       if (err < 0)
12072 +                               DEBUG(DBG_WARNING, "removal of home address %x:%x:%x:%x:%x:%x:%x:%x from" 
12073 +                                     " old interface %d failed with status %d", 
12074 +                                     NIPV6ADDR(&ifrh->ifr.ifr6_addr), ifrh->old_ifi, err);             
12075 +               }
12076 +               if(!err) {
12077 +                       err = addrconf_add_ifaddr(&ifrh->ifr);
12078 +               }
12079 +               if (ifrh->ho) {
12080 +                       DEBUG(DBG_INFO, "Calling mobile_node moved after moving home address to new if");
12081 +                       mipv6_mobile_node_moved(ifrh->ho);
12082 +               }
12083 +               list_del(&ifrh->list);
12084 +               kfree(ifrh);
12085 +       }
12086 +       set_fs(oldfs);
12087 +
12088 +       if (err < 0)
12089 +               DEBUG(DBG_WARNING, "adding of home address to a new interface %d failed %d", new_if, err);
12090 +       else {
12091 +               DEBUG(DBG_WARNING, "adding of home address to a new interface OK");
12092 +       }
12093 +}
12094 +
12095 +struct dhaad_halist {
12096 +       struct list_head list;
12097 +       struct in6_addr addr;
12098 +       int retry;
12099 +};
12100 +
12101 +/* clear all has from candidate list.  do this when a new dhaad reply
12102 + * is received. */
12103 +int mipv6_mn_flush_ha_candidate(struct list_head *ha)
12104 +{
12105 +       struct list_head *p, *tmp;
12106 +       struct dhaad_halist *e;
12107 +
12108 +       list_for_each_safe(p, tmp, ha) {
12109 +               e = list_entry(p, struct dhaad_halist, list);
12110 +               list_del(p);
12111 +               kfree(e);
12112 +               e = NULL;
12113 +       }
12114 +       return 0;
12115 +}
12116 +
12117 +/* add new ha to candidates. only done when dhaad reply is received. */
12118 +int mipv6_mn_add_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12119 +{
12120 +       struct dhaad_halist *e;
12121 +
12122 +       e = kmalloc(sizeof(*e), GFP_ATOMIC);
12123 +       memset(e, 0, sizeof(*e));
12124 +       ipv6_addr_copy(&e->addr, addr);
12125 +
12126 +       list_add_tail(&e->list, ha);
12127 +       return 0;
12128 +}
12129 +
12130 +#define MAX_RETRIES_PER_HA 3
12131 +
12132 +/* get next ha candidate.  this is done when dhaad reply has been
12133 + * received and we want to register with the best available ha. */
12134 +int mipv6_mn_get_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12135 +{
12136 +       struct list_head *p;
12137 +
12138 +       list_for_each(p, ha) {
12139 +               struct dhaad_halist *e;
12140 +               e = list_entry(p, typeof(*e), list);
12141 +               if (e->retry >= 0 && e->retry < MAX_RETRIES_PER_HA) {
12142 +                       ipv6_addr_copy(addr, &e->addr);
12143 +                       return 0;
12144 +               }
12145 +       }
12146 +       return -1;
12147 +}
12148 +
12149 +/* change candidate status.  if registration with ha fails, we
12150 + * increase retry for ha candidate.  if retry is >= 3 we set it to -1
12151 + * (failed), do get_ha_candidate() again */
12152 +int mipv6_mn_try_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12153 +{
12154 +       struct list_head *p;
12155 +
12156 +       list_for_each(p, ha) {
12157 +               struct dhaad_halist *e;
12158 +               e = list_entry(p, typeof(*e), list);
12159 +               if (ipv6_addr_cmp(addr, &e->addr) == 0) {
12160 +                       if (e->retry >= MAX_RETRIES_PER_HA) e->retry = -1;
12161 +                       else if (e->retry >= 0) e->retry++;
12162 +                       return 0;
12163 +               }
12164 +       }
12165 +       return -1;
12166 +}
12167 +
12168 +/**
12169 + * mipv6_mn_get_bulifetime - Get lifetime for a binding update
12170 + * @home_addr: home address for BU 
12171 + * @coa: care-of address for BU
12172 + * @flags: flags used for BU 
12173 + *
12174 + * Returns maximum lifetime for BUs determined by the lifetime of
12175 + * care-of address and the lifetime of home address.
12176 + **/
12177 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr, struct in6_addr *coa,
12178 +                             __u8 flags)
12179 +{
12180 +       struct inet6_ifaddr *ifp_hoa, *ifp_coa;
12181 +       __u32 lifetime = (flags & MIPV6_BU_F_HOME ? 
12182 +                         HA_BU_DEF_LIFETIME : CN_BU_DEF_LIFETIME); 
12183 +
12184 +       ifp_hoa = ipv6_get_ifaddr(home_addr, NULL);
12185 +       if(!ifp_hoa) {
12186 +               DEBUG(DBG_INFO, "home address missing");
12187 +               return 0;
12188 +       }
12189 +       if (!(ifp_hoa->flags & IFA_F_PERMANENT)){
12190 +               if (ifp_hoa->valid_lft)
12191 +                       lifetime = min_t(__u32, lifetime, ifp_hoa->valid_lft);
12192 +               else
12193 +                       DEBUG(DBG_ERROR, "Zero lifetime for home address");
12194 +       }
12195 +       in6_ifa_put(ifp_hoa);
12196 +
12197 +       ifp_coa = ipv6_get_ifaddr(coa, NULL);
12198 +       if (!ifp_coa) { 
12199 +               DEBUG(DBG_INFO, "care-of address missing");
12200 +               return 0;
12201 +       }
12202 +       if (!(ifp_coa->flags & IFA_F_PERMANENT)) {
12203 +               if(ifp_coa->valid_lft)
12204 +                       lifetime = min_t(__u32, lifetime, ifp_coa->valid_lft);
12205 +               else
12206 +                       DEBUG(DBG_ERROR, 
12207 +                             "Zero lifetime for care-of address");
12208 +       }
12209 +       in6_ifa_put(ifp_coa);
12210 +
12211 +       DEBUG(DBG_INFO, "Lifetime for binding is %ld", lifetime);
12212 +       return lifetime;
12213 +}
12214 +
12215 +static int 
12216 +mipv6_mn_tnl_rcv_send_bu_hook(struct ip6_tnl *t, struct sk_buff *skb)
12217 +{
12218 +       struct ipv6hdr *inner;
12219 +       struct ipv6hdr *outer = skb->nh.ipv6h; 
12220 +       struct mn_info *minfo = NULL;
12221 +       __u32 lifetime;
12222 +       __u8 user_flags = 0;
12223 +
12224 +       DEBUG_FUNC();
12225 +
12226 +       if (!is_mip6_tnl(t))
12227 +               return IP6_TNL_ACCEPT;
12228 +
12229 +       if (!mip6node_cnf.accept_ret_rout) {
12230 +               DEBUG(DBG_INFO, "Return routability administratively disabled" 
12231 +                     " not doing route optimization");
12232 +               return IP6_TNL_ACCEPT;
12233 +       }
12234 +       if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*inner)))
12235 +               return IP6_TNL_DROP;
12236 +
12237 +       inner = (struct ipv6hdr *)skb->h.raw;
12238 +       
12239 +       read_lock(&mn_info_lock);
12240 +       minfo = mipv6_mninfo_get_by_home(&inner->daddr);
12241 +
12242 +       if (!minfo) {
12243 +               DEBUG(DBG_WARNING, "MN info missing");
12244 +               read_unlock(&mn_info_lock);
12245 +               return IP6_TNL_ACCEPT;
12246 +       }
12247 +       DEBUG(DBG_DATADUMP, "MIPV6 MN: Received a tunneled IPv6 packet"
12248 +             " to %x:%x:%x:%x:%x:%x:%x:%x,"
12249 +             " from %x:%x:%x:%x:%x:%x:%x:%x with\n tunnel header"
12250 +             "daddr: %x:%x:%x:%x:%x:%x:%x:%x,"
12251 +             "saddr: %x:%x:%x:%x:%x:%x:%x:%x", 
12252 +              NIPV6ADDR(&inner->daddr), NIPV6ADDR(&inner->saddr),
12253 +              NIPV6ADDR(&outer->daddr), NIPV6ADDR(&outer->saddr));
12254 +       
12255 +       spin_lock(&minfo->lock);
12256 +
12257 +       /* We don't send bus in response to all tunneled packets */
12258 +
12259 +        if (!ipv6_addr_cmp(&minfo->ha, &inner->saddr)) {
12260 +               spin_unlock(&minfo->lock);
12261 +               read_unlock(&mn_info_lock);
12262 +                DEBUG(DBG_ERROR, "HA BUG: Received a tunneled packet "
12263 +                     "originally sent by home agent, not sending BU");
12264 +               return IP6_TNL_ACCEPT;
12265 +        }
12266 +       spin_unlock(&minfo->lock);
12267 +       read_unlock(&mn_info_lock);
12268 +
12269 +       DEBUG(DBG_DATADUMP, "Sending BU to correspondent node");
12270 +
12271 +       user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12272 +
12273 +       if (inner->nexthdr != IPPROTO_DSTOPTS && 
12274 +           inner->nexthdr != IPPROTO_MOBILITY) {
12275 +               struct in6_addr coa;
12276 +               /* Don't start RR when receiving ICMP error messages */
12277 +               if (inner->nexthdr == IPPROTO_ICMPV6) {
12278 +                       int ptr = (u8*)(inner+1) - skb->data;
12279 +                       u8 type;
12280 +
12281 +                       if (skb_copy_bits(skb,
12282 +                                         ptr+offsetof(struct icmp6hdr,
12283 +                                                      icmp6_type),
12284 +                                         &type, 1)
12285 +                           || !(type & ICMPV6_INFOMSG_MASK)) {
12286 +                               return IP6_TNL_ACCEPT;
12287 +                       }
12288 +               }
12289 +               lifetime = mipv6_mn_get_bulifetime(&inner->daddr,
12290 +                                                  &outer->daddr, 0); 
12291 +               if (lifetime && 
12292 +                   !mipv6_get_care_of_address(&inner->daddr, &coa)) {
12293 +                       write_lock(&bul_lock);
12294 +                       mipv6_send_bu(&inner->daddr, &inner->saddr, &coa,
12295 +                                     INITIAL_BINDACK_TIMEOUT,
12296 +                                     MAX_BINDACK_TIMEOUT, 1, 
12297 +                                     user_flags,
12298 +                                     lifetime, NULL);
12299 +                       write_unlock(&bul_lock);
12300 +               }
12301 +       }
12302 +       DEBUG(DBG_DATADUMP, "setting rcv_tunnel flag in skb");
12303 +       skb->security |= MIPV6_RCV_TUNNEL;
12304 +       return IP6_TNL_ACCEPT;
12305 +}
12306 +
12307 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_send_bu_ops = {
12308 +       {NULL, NULL}, 
12309 +       IP6_TNL_PRE_DECAP,
12310 +       IP6_TNL_PRI_FIRST,
12311 +       mipv6_mn_tnl_rcv_send_bu_hook
12312 +};
12313 +
12314 +static int
12315 +mipv6_mn_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12316 +{
12317 +       DEBUG_FUNC();
12318 +       if (is_mip6_tnl(t))
12319 +               MIPV6_INC_STATS(n_encapsulations);
12320 +       return IP6_TNL_ACCEPT;
12321 +}
12322 +
12323 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_xmit_stats_ops = {
12324 +       {NULL, NULL},
12325 +       IP6_TNL_PRE_ENCAP,
12326 +       IP6_TNL_PRI_LAST,
12327 +       mipv6_mn_tnl_xmit_stats_hook
12328 +};
12329 +
12330 +static int
12331 +mipv6_mn_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12332 +{
12333 +       DEBUG_FUNC();   
12334 +       if (is_mip6_tnl(t))
12335 +               MIPV6_INC_STATS(n_decapsulations);
12336 +       return IP6_TNL_ACCEPT;
12337 +}
12338 +
12339 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_stats_ops = {
12340 +       {NULL, NULL},
12341 +       IP6_TNL_PRE_DECAP,
12342 +       IP6_TNL_PRI_LAST,
12343 +       mipv6_mn_tnl_rcv_stats_hook
12344 +};
12345 +
12346 +static void mn_check_tunneled_packet(struct sk_buff *skb)
12347 +{
12348 +       DEBUG_FUNC();
12349 +       /* If tunnel flag was set */
12350 +       if (skb->security & MIPV6_RCV_TUNNEL) {
12351 +               struct in6_addr coa; 
12352 +               __u32 lifetime;
12353 +               __u8 user_flags = 0;
12354 +               int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
12355 +               int len = skb->len - ptr;
12356 +               __u8 nexthdr = skb->nh.ipv6h->nexthdr;
12357 +
12358 +               if (len < 0)
12359 +                       return;
12360 +
12361 +               ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
12362 +               if (ptr < 0)
12363 +                       return;
12364 +
12365 +               if (!mip6node_cnf.accept_ret_rout) {
12366 +                       DEBUG(DBG_INFO, "Return routability administratively disabled");
12367 +                       return;
12368 +               }
12369 +               if (nexthdr == IPPROTO_MOBILITY)
12370 +                       return;
12371 +             
12372 +               /* Don't start RR when receiving ICMP error messages */
12373 +               if (nexthdr == IPPROTO_ICMPV6) {
12374 +                       u8 type;
12375 +
12376 +                       if (skb_copy_bits(skb,
12377 +                                         ptr+offsetof(struct icmp6hdr,
12378 +                                                      icmp6_type),
12379 +                                         &type, 1)
12380 +                           || !(type & ICMPV6_INFOMSG_MASK)) {
12381 +                               return;
12382 +                       }
12383 +               }
12384 +               user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12385 +               mipv6_get_care_of_address(&skb->nh.ipv6h->daddr, &coa);
12386 +               lifetime = mipv6_mn_get_bulifetime(&skb->nh.ipv6h->daddr,
12387 +                                                        &coa, 0); 
12388 +
12389 +               DEBUG(DBG_WARNING, "packet to address %x:%x:%x:%x:%x:%x:%x:%x"
12390 +                     "was tunneled. Sending BU to CN" 
12391 +                     "%x:%x:%x:%x:%x:%x:%x:%x", 
12392 +                     NIPV6ADDR(&skb->nh.ipv6h->daddr),
12393 +                     NIPV6ADDR(&skb->nh.ipv6h->saddr)); 
12394 +               /* This should work also with home address option */
12395 +               
12396 +               write_lock(&bul_lock);
12397 +               mipv6_send_bu(&skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr, 
12398 +                             &coa, INITIAL_BINDACK_TIMEOUT,
12399 +                             MAX_BINDACK_TIMEOUT, 1, user_flags,
12400 +                             lifetime, NULL);
12401 +               write_unlock(&bul_lock);
12402 +       }
12403 +}
12404 +
12405 +static int sched_mv_home_addr_task(struct in6_addr *haddr, int plen_new, 
12406 +                                  int newif, int oldif, struct handoff *ho)
12407 +{
12408 +       int alloc_size;
12409 +       struct ifr_holder *ifrh;
12410 +
12411 +       alloc_size = sizeof(*ifrh) + (ho ? sizeof(*ho): 0);
12412 +       if ((ifrh = kmalloc(alloc_size, GFP_ATOMIC)) == NULL) {
12413 +               DEBUG(DBG_ERROR, "Out of memory");
12414 +               return -1;
12415 +       } 
12416 +       if (ho) {
12417 +               ifrh->ho = (struct handoff *)((struct ifr_holder *)(ifrh + 1));
12418 +               memcpy(ifrh->ho, ho, sizeof(*ho));
12419 +       } else 
12420 +               ifrh->ho = NULL;
12421 +
12422 +       /* must queue task to avoid deadlock with rtnl */
12423 +       ifrh->ifr.ifr6_ifindex = newif;
12424 +       ifrh->ifr.ifr6_prefixlen = plen_new;
12425 +       ipv6_addr_copy(&ifrh->ifr.ifr6_addr, haddr);
12426 +       ifrh->old_ifi = oldif;
12427 +       
12428 +       spin_lock_bh(&ifrh_lock);
12429 +       list_add_tail(&ifrh->list, &ifrh_list);
12430 +       spin_unlock_bh(&ifrh_lock);
12431 +
12432 +       schedule_task(&mv_home_addr_task);
12433 +
12434 +       return 0;
12435 +}
12436 +
12437 +static void send_ret_home_ns(struct in6_addr *ha_addr, 
12438 +                            struct in6_addr *home_addr,
12439 +                            int ifindex)
12440 +{
12441 +       struct in6_addr nil;
12442 +       struct in6_addr mcaddr;
12443 +       struct net_device *dev = dev_get_by_index(ifindex);
12444 +       if (!dev)
12445 +               return;
12446 +       memset(&nil, 0, sizeof(nil));
12447 +       addrconf_addr_solict_mult(home_addr, &mcaddr);
12448 +       ndisc_send_ns(dev, NULL, home_addr, &mcaddr, &nil); 
12449 +       dev_put(dev);
12450 +}
12451 +
12452 +static inline int ha_is_reachable(int ifindex, struct in6_addr *ha)
12453 +{
12454 +       struct net_device *dev;
12455 +       int reachable = 0;
12456 +
12457 +       dev = dev_get_by_index(ifindex);
12458 +       if (dev) {
12459 +               struct neighbour *neigh;
12460 +               if ((neigh = ndisc_get_neigh(dev, ha)) != NULL) {
12461 +                       read_lock_bh(&neigh->lock);
12462 +                       if (neigh->nud_state&NUD_VALID)
12463 +                               reachable = 1;
12464 +                       read_unlock_bh(&neigh->lock);
12465 +                       neigh_release(neigh);
12466 +               }
12467 +               dev_put(dev);
12468 +       }
12469 +       return reachable;
12470 +}
12471 +
12472 +static int mn_ha_handoff(struct handoff *ho)
12473 +{
12474 +       struct list_head *lh;
12475 +       struct mn_info *minfo;
12476 +       struct in6_addr *coa= ho->coa;
12477 +       int wait_mv_home = 0; 
12478 +
12479 +       read_lock_bh(&mn_info_lock);
12480 +       list_for_each(lh, &mn_info_list) {
12481 +               __u8 has_home_reg;
12482 +               int ifindex;
12483 +               struct in6_addr ha;
12484 +               __u8 athome;
12485 +               __u32 lifetime;
12486 +               struct mipv6_bul_entry *entry = NULL;
12487 +               
12488 +               minfo = list_entry(lh, struct mn_info, list);
12489 +               spin_lock(&minfo->lock);
12490 +               has_home_reg = minfo->has_home_reg;
12491 +               ifindex = minfo->ifindex;
12492 +               ipv6_addr_copy(&ha, &minfo->ha);
12493 +               
12494 +               if (mipv6_prefix_compare(&ho->rtr_addr, &minfo->home_addr,
12495 +                                        ho->plen)) {
12496 +                       if (minfo->has_home_reg)
12497 +                               athome = minfo->is_at_home = MN_RETURNING_HOME;
12498 +                       else
12499 +                               athome = minfo->is_at_home = MN_AT_HOME;
12500 +                       coa = &minfo->home_addr;
12501 +
12502 +                       spin_unlock(&minfo->lock);
12503 +#if 0                  
12504 +                       /* Cancel prefix solicitation, rtr is our HA */
12505 +                       mipv6_pfx_cancel_send(&ho->rtr_addr, ifindex);
12506 +#endif                 
12507 +                       minfo->ifindex = ho->ifindex;
12508 +
12509 +                       if (minfo->has_home_reg && 
12510 +                           !ha_is_reachable(ho->ifindex, &minfo->ha)) {
12511 +                               send_ret_home_ns(&minfo->ha,
12512 +                                                &minfo->home_addr, 
12513 +                                                ho->ifindex);
12514 +                               mipv6_mdet_set_curr_rtr_reachable(0);
12515 +                               wait_mv_home++;
12516 +                       }
12517 +                       if (ifindex != ho->ifindex){
12518 +                               wait_mv_home++;
12519 +                               DEBUG(DBG_INFO, 
12520 +                                     "Moving home address back to "
12521 +                                     "the home interface");
12522 +                               sched_mv_home_addr_task(&minfo->home_addr, 
12523 +                                                       128,
12524 +                                                       ho->ifindex, 
12525 +                                                       ifindex, ho);
12526 +                       }
12527 +                       if (!has_home_reg || wait_mv_home)
12528 +                               continue;
12529 +                       
12530 +                       lifetime = 0;
12531 +
12532 +               } else {
12533 +                       athome = minfo->is_at_home = MN_NOT_AT_HOME;
12534 +                       if (minfo->ifindex_user != minfo->ifindex) {
12535 +                               DEBUG(DBG_INFO, "Scheduling home address move to virtual interface");
12536 +                               sched_mv_home_addr_task(&minfo->home_addr, 
12537 +                                                       128,
12538 +                                                       minfo->ifindex_user, 
12539 +                                                       minfo->ifindex, ho); /* Is minfo->ifindex correct */
12540 +                               
12541 +                               wait_mv_home++;
12542 +                       }
12543 +                       minfo->ifindex = minfo->ifindex_user;
12544 +                       spin_unlock(&minfo->lock);
12545 +                       if (wait_mv_home)
12546 +                               continue;
12547 +                       if (!has_home_reg &&
12548 +                           init_home_registration(&minfo->home_addr, 
12549 +                                                  ho->coa)) {
12550 +                               continue;
12551 +                       }
12552 +                       lifetime = mipv6_mn_get_bulifetime(&minfo->home_addr, 
12553 +                                                          ho->coa,
12554 +                                                          MIPV6_BU_F_HOME);
12555 +                       
12556 +               }
12557 +               write_lock(&bul_lock);
12558 +               if (!(entry = mipv6_bul_get(&ha, &minfo->home_addr)) ||
12559 +                   !(entry->flags & MIPV6_BU_F_HOME)) {
12560 +                       DEBUG(DBG_ERROR, 
12561 +                             "Unable to find home registration for "
12562 +                             "home address: %x:%x:%x:%x:%x:%x:%x:%x!\n",
12563 +                             NIPV6ADDR(&minfo->home_addr));
12564 +                       write_unlock(&bul_lock);
12565 +                       continue;
12566 +               }
12567 +               DEBUG(DBG_INFO, "Sending home de ? %d registration for "
12568 +                     "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" 
12569 +                     "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12570 +                     "with lifetime %ld", 
12571 +                     (athome != MN_NOT_AT_HOME),  
12572 +                     NIPV6ADDR(&entry->home_addr), 
12573 +                     NIPV6ADDR(&entry->cn_addr), lifetime);
12574 +               mipv6_send_bu(&entry->home_addr, &entry->cn_addr, 
12575 +                             coa, INITIAL_BINDACK_TIMEOUT, 
12576 +                             MAX_BINDACK_TIMEOUT, 1, entry->flags, 
12577 +                             lifetime, NULL);
12578 +               write_unlock(&bul_lock);
12579 +
12580 +       }
12581 +       read_unlock_bh(&mn_info_lock);
12582 +       return wait_mv_home;
12583 +}
12584 +/**
12585 + * mn_cn_handoff - called for every bul entry to send BU to CN
12586 + * @rawentry: bul entry
12587 + * @args: handoff event
12588 + * @sortkey:
12589 + *
12590 + * Since MN can have many home addresses and home networks, every BUL
12591 + * entry needs to be checked
12592 + **/
12593 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey)
12594 +{
12595 +       struct mipv6_bul_entry *entry = (struct mipv6_bul_entry *)rawentry;
12596 +       struct in6_addr *coa = (struct in6_addr *)args;
12597 +
12598 +       DEBUG_FUNC();
12599 +
12600 +       /* Home registrations already handled by mn_ha_handoff */
12601 +       if (entry->flags & MIPV6_BU_F_HOME)
12602 +               return ITERATOR_CONT;
12603 +
12604 +       /* BUL is locked by mipv6_mobile_node_moved which calls us 
12605 +          through mipv6_bul_iterate */
12606 +
12607 +       if (mipv6_prefix_compare(coa, 
12608 +                                &entry->home_addr,
12609 +                                64)) {
12610 +               mipv6_send_bu(&entry->home_addr, &entry->cn_addr, 
12611 +                             &entry->home_addr, INITIAL_BINDACK_TIMEOUT, 
12612 +                             MAX_BINDACK_TIMEOUT, 1, entry->flags, 0, 
12613 +                             NULL);
12614 +       } else {
12615 +               u32 lifetime = mipv6_mn_get_bulifetime(&entry->home_addr, 
12616 +                                                      coa,
12617 +                                                      entry->flags);
12618 +               mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12619 +                              coa, INITIAL_BINDACK_TIMEOUT,
12620 +                             MAX_BINDACK_TIMEOUT, 1, entry->flags,
12621 +                             lifetime, NULL);
12622 +       }
12623 +       return ITERATOR_CONT;
12624 +}
12625 +
12626 +
12627 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey)
12628 +{
12629 +       struct mipv6_bul_entry *bul = (struct mipv6_bul_entry *)rawentry;
12630 +       struct bul_inval_args *arg = (struct bul_inval_args *)args;
12631 +
12632 +       DEBUG_FUNC();
12633 +
12634 +       if (!ipv6_addr_cmp(arg->cn, &bul->cn_addr) &&
12635 +           (!ipv6_addr_cmp(arg->mn, &bul->home_addr) ||
12636 +            !ipv6_addr_cmp(arg->mn, &bul->coa))) {
12637 +               if (arg->all_rr_states || !bul->rr ||
12638 +                   (bul->rr->rr_state != RR_INIT && 
12639 +                    bul->rr->rr_state != RR_DONE)) {
12640 +                       bul->state = ACK_ERROR;
12641 +                       bul->callback = bul_entry_expired;
12642 +                       bul->callback_time = jiffies +
12643 +                               DUMB_CN_BU_LIFETIME * HZ;
12644 +                       bul->expire = bul->callback_time;
12645 +                       DEBUG(DBG_INFO, "BUL entry set to ACK_ERROR");
12646 +                       mipv6_bul_reschedule(bul);
12647 +               }
12648 +       }
12649 +       return ITERATOR_CONT;
12650 +}
12651 +/**
12652 + * init_home_registration - start Home Registration process
12653 + * @home_addr: home address
12654 + * @coa: care-of address
12655 + *
12656 + * Checks whether we have a Home Agent address for this home address.
12657 + * If not starts Dynamic Home Agent Address Discovery.  Otherwise
12658 + * tries to register with home agent if not already registered.
12659 + * Returns 1, if home registration process is started and 0 otherwise
12660 + **/
12661 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa)
12662 +{
12663 +       struct mn_info *hinfo;
12664 +       struct in6_addr ha;
12665 +       __u8 man_conf;
12666 +       int ifindex;
12667 +       __u32 lifetime;
12668 +       __u8 user_flags = 0, flags;
12669 +
12670 +       DEBUG_FUNC();
12671 +
12672 +       read_lock_bh(&mn_info_lock);
12673 +        if ((hinfo = mipv6_mninfo_get_by_home(home_addr)) == NULL) {
12674 +                DEBUG(DBG_ERROR, "No mn_info found for address: "
12675 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
12676 +                     NIPV6ADDR(home_addr));
12677 +               read_unlock_bh(&mn_info_lock);
12678 +                return -ENOENT;
12679 +        }
12680 +       spin_lock(&hinfo->lock);
12681 +       if (mipv6_prefix_compare(&hinfo->home_addr, coa, hinfo->home_plen)) { 
12682 +               spin_unlock(&hinfo->lock);
12683 +               read_unlock_bh(&mn_info_lock);
12684 +               DEBUG(DBG_INFO, "Adding home address, MN at home");
12685 +               return 1;
12686 +       }
12687 +        if (ipv6_addr_any(&hinfo->ha)) {
12688 +                int dhaad_id = mipv6_get_dhaad_id();
12689 +                hinfo->dhaad_id = dhaad_id;
12690 +               spin_unlock(&hinfo->lock);
12691 +                mipv6_icmpv6_send_dhaad_req(home_addr, hinfo->home_plen, dhaad_id);
12692 +               read_unlock_bh(&mn_info_lock);
12693 +                DEBUG(DBG_INFO,
12694 +                     "Home Agent address not set, initiating DHAAD");
12695 +                return 1;
12696 +        }
12697 +        ipv6_addr_copy(&ha, &hinfo->ha);
12698 +        man_conf = hinfo->man_conf;
12699 +        ifindex = hinfo->ifindex;
12700 +       spin_unlock(&hinfo->lock);
12701 +       read_unlock_bh(&mn_info_lock);
12702 +#if 0  
12703 +       if (man_conf)
12704 +               mipv6_pfx_add_ha(&ha, coa, ifindex);
12705 +#endif 
12706 +       if (mipv6_bul_exists(&ha, home_addr)) {
12707 +               DEBUG(DBG_INFO, "BU already sent to HA");
12708 +               return 0;
12709 +       }
12710 +       /* user flags received through sysctl */
12711 +       user_flags |= mip6node_cnf.bu_lladdr ? MIPV6_BU_F_LLADDR : 0;
12712 +       user_flags |= mip6node_cnf.bu_keymgm ? MIPV6_BU_F_KEYMGM : 0;
12713 +
12714 +       flags = MIPV6_BU_F_HOME | MIPV6_BU_F_ACK | user_flags;
12715 +
12716 +       lifetime = mipv6_mn_get_bulifetime(home_addr, coa, flags);
12717 +
12718 +       DEBUG(DBG_INFO, "Sending initial home registration for "
12719 +             "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" 
12720 +             "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12721 +             "with lifetime %ld, prefixlength %d",   
12722 +             NIPV6ADDR(home_addr), NIPV6ADDR(&ha), lifetime, 0);
12723 +
12724 +       write_lock_bh(&bul_lock);
12725 +       mipv6_send_bu(home_addr, &ha, coa, INITIAL_BINDACK_DAD_TIMEOUT,
12726 +                     MAX_BINDACK_TIMEOUT, 1, flags, lifetime, NULL);
12727 +       write_unlock_bh(&bul_lock);
12728 +
12729 +       return 1;
12730 +}
12731 +
12732 +/**
12733 + * mipv6_mobile_node_moved - Send BUs to all HAs and CNs
12734 + * @ho: handoff structure contains the new and previous routers
12735 + *
12736 + * Event for handoff.  Sends BUs everyone on Binding Update List.
12737 + **/
12738 +int mipv6_mobile_node_moved(struct handoff *ho)
12739 +{
12740 +#if 0
12741 +       int bu_to_prev_router = 1;
12742 +#endif
12743 +       int dummy;
12744 +
12745 +       DEBUG_FUNC();
12746 +
12747 +       ma_ctl_upd_iface(ho->ifindex, 
12748 +                        MA_IFACE_CURRENT | MA_IFACE_HAS_ROUTER, &dummy);
12749 +
12750 +       /* First send BU to HA, then to all other nodes that are on BU list */
12751 +       if (mn_ha_handoff(ho) != 0)
12752 +               return 0; /* Wait for move home address task */
12753 +#if 0   
12754 +       /* Add current care-of address to mn_info list, if current router acts 
12755 +          as a HA.*/ 
12756 +
12757 +       if (ho->home_address && bu_to_prev_router) 
12758 +               mipv6_mninfo_add(ho->coa, ho->plen, 
12759 +                                MN_AT_HOME, 0, &ho->rtr_addr, 
12760 +                                ho->plen, ROUTER_BU_DEF_LIFETIME,
12761 +                                0);
12762 +                                 
12763 +#endif
12764 +       return 0;               
12765 +}
12766 +
12767 +/**
12768 + * mipv6_mn_send_home_na - send NA when returning home
12769 + * @haddr: home address to advertise
12770 + *
12771 + * After returning home, MN must advertise all its valid addresses in
12772 + * home link to all nodes.
12773 + **/
12774 +void mipv6_mn_send_home_na(struct in6_addr *haddr)
12775 +{
12776 +       struct net_device *dev = NULL;
12777 +       struct in6_addr mc_allnodes;
12778 +       struct mn_info *hinfo = NULL;
12779
12780 +       read_lock(&mn_info_lock);
12781 +       hinfo = mipv6_mninfo_get_by_home(haddr);
12782 +       if (!hinfo) {
12783 +               read_unlock(&mn_info_lock);
12784 +               return;
12785 +       }
12786 +       spin_lock(&hinfo->lock);
12787 +       hinfo->is_at_home = MN_AT_HOME;
12788 +       dev = dev_get_by_index(hinfo->ifindex);
12789 +       spin_unlock(&hinfo->lock);
12790 +       read_unlock(&mn_info_lock);
12791 +       if (dev == NULL) {
12792 +               DEBUG(DBG_ERROR, "Send home_na: device not found.");
12793 +               return;
12794 +       }
12795 +       
12796 +       ipv6_addr_all_nodes(&mc_allnodes);
12797 +       ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1);
12798 +       dev_put(dev);
12799 +}
12800 +
12801 +static int mn_use_hao(struct in6_addr *daddr, struct in6_addr *saddr)
12802 +{
12803 +       struct mipv6_bul_entry *entry;
12804 +       struct mn_info *minfo = NULL;
12805 +       int add_ha = 0;
12806 +
12807 +       read_lock_bh(&mn_info_lock);
12808 +       minfo = mipv6_mninfo_get_by_home(saddr);
12809 +       if (minfo && minfo->is_at_home != MN_AT_HOME) {
12810 +               read_lock_bh(&bul_lock);
12811 +               if ((entry = mipv6_bul_get(daddr, saddr)) == NULL) {
12812 +                       read_unlock_bh(&bul_lock);
12813 +                       read_unlock_bh(&mn_info_lock);
12814 +                       return add_ha;
12815 +               }
12816 +               add_ha = (entry->state != ACK_ERROR &&
12817 +                         (!entry->rr || entry->rr->rr_state == RR_DONE || 
12818 +                          entry->flags & MIPV6_BU_F_HOME));
12819 +               read_unlock_bh(&bul_lock);
12820 +       }
12821 +       read_unlock_bh(&mn_info_lock);
12822 +       return add_ha;
12823 +}
12824 +
12825 +static int 
12826 +mn_dev_event(struct notifier_block *nb, unsigned long event, void *ptr)
12827 +{
12828 +       struct net_device *dev = ptr;
12829 +       struct list_head *lh;
12830 +       struct mn_info *minfo;
12831 +       int newif = 0;
12832 +
12833 +       /* here are probably the events we need to worry about */
12834 +       switch (event) {
12835 +       case NETDEV_UP:
12836 +               DEBUG(DBG_DATADUMP, "New netdevice %s registered.", dev->name);
12837 +               if (dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev)) 
12838 +                       ma_ctl_add_iface(dev->ifindex);
12839 +                       
12840 +               break;
12841 +       case NETDEV_GOING_DOWN:
12842 +               DEBUG(DBG_DATADUMP, "Netdevice %s disappeared.", dev->name);
12843 +               /* 
12844 +                * Go through mn_info list and move all home addresses on the
12845 +                * netdev going down to a new device. This will make it 
12846 +                 * practically impossible for the home address to return home,
12847 +                * but allow MN to retain its connections using the address.
12848 +                */
12849 +
12850 +               read_lock_bh(&mn_info_lock);
12851 +               list_for_each(lh, &mn_info_list) {
12852 +                       minfo = list_entry(lh, struct mn_info, list);
12853 +                       spin_lock(&minfo->lock);
12854 +                       if (minfo->ifindex == dev->ifindex) {
12855 +                               if (sched_mv_home_addr_task(&minfo->home_addr, 128, 
12856 +                                                           minfo->ifindex_user, 
12857 +                                                           0, NULL) < 0) {
12858 +                                       minfo->ifindex = 0;
12859 +                                       spin_unlock(&minfo->lock);
12860 +                                       read_unlock_bh(&mn_info_lock);
12861 +                                       return NOTIFY_DONE;
12862 +                               } else { 
12863 +                                       minfo->ifindex = minfo->ifindex_user;
12864 +                                       if (minfo->is_at_home) {
12865 +                                               minfo->is_at_home = 0;
12866 +
12867 +                                       }
12868 +                                       newif = minfo->ifindex_user;
12869 +                               }
12870 +                       }
12871 +                       spin_unlock(&minfo->lock);                              
12872 +               }
12873 +               
12874 +               read_unlock_bh(&mn_info_lock);
12875 +       }
12876 +       ma_ctl_upd_iface(dev->ifindex, MA_IFACE_NOT_PRESENT, &newif);
12877 +       mipv6_mdet_del_if(dev->ifindex);
12878 +
12879 +       return NOTIFY_DONE;
12880 +}
12881 +
12882 +struct notifier_block mipv6_mn_dev_notifier = {
12883 +       mn_dev_event,
12884 +       NULL,
12885 +       0 /* check if using zero is ok */
12886 +};
12887 +
12888 +static void deprecate_addr(struct mn_info *minfo)
12889 +{
12890 +       /*
12891 +        * Lookup address from IPv6 address list and set deprecated flag
12892 +        */
12893 +       
12894 +}
12895 +
12896 +/*
12897 + * Required because we can only modify addresses after the packet is
12898 + * constructed.  We otherwise mess with higher level protocol
12899 + * pseudoheaders. With strict protocol layering life would be SO much
12900 + * easier!  
12901 + */
12902 +static unsigned int modify_xmit_addrs(unsigned int hooknum,
12903 +                                     struct sk_buff **pskb,
12904 +                                     const struct net_device *in,
12905 +                                     const struct net_device *out,
12906 +                                     int (*okfn) (struct sk_buff *))
12907 +{
12908 +       struct sk_buff *skb = *pskb;
12909 +
12910 +       DEBUG_FUNC();
12911 +       
12912 +       if (skb) {
12913 +               struct ipv6hdr *hdr = skb->nh.ipv6h;
12914 +               struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
12915 +               struct mipv6_bul_entry *bule;
12916 +               struct in6_addr *daddr;
12917 +
12918 +               if (!ipv6_addr_any(&opt->hoa))
12919 +                       daddr = &opt->hoa;
12920 +               else
12921 +                       daddr = &hdr->daddr;
12922 +
12923 +               /* We don't consult bul when sending a BU to avoid deadlock, since
12924 +                * BUL is already locked. 
12925 +                */
12926 +               
12927 +
12928 +               if (opt->mipv6_flags & MIPV6_SND_HAO && 
12929 +                   !(opt->mipv6_flags & MIPV6_SND_BU)) {
12930 +                       write_lock(&bul_lock);
12931 +                       bule = mipv6_bul_get(daddr, &hdr->saddr);
12932 +                       if (!bule) {
12933 +                               write_unlock(&bul_lock);
12934 +                               return NF_ACCEPT;
12935 +                       }
12936 +                       if (!bule->rr || bule->rr->rr_state == RR_DONE || 
12937 +                           bule->flags & MIPV6_BU_F_HOME) {
12938 +                               DEBUG(DBG_DATADUMP, 
12939 +                                     "Replace source address with CoA and reroute");
12940 +                               ipv6_addr_copy(&hdr->saddr, &bule->coa);
12941 +                               skb->nfcache |= NFC_ALTERED;
12942 +                       }
12943 +                       write_unlock(&bul_lock);
12944 +               } else if (opt->mipv6_flags & MIPV6_SND_HAO) {
12945 +                       mipv6_get_care_of_address(&hdr->saddr, &hdr->saddr);
12946 +                       skb->nfcache |= NFC_ALTERED;
12947 +               }
12948 +       }
12949 +       return NF_ACCEPT;
12950 +}
12951 +
12952 +/* We set a netfilter hook so that we can modify outgoing packet's
12953 + * source addresses 
12954 + */
12955 +struct nf_hook_ops addr_modify_hook_ops = {
12956 +       {NULL, NULL},           /* List head, no predecessor, no successor */
12957 +       modify_xmit_addrs,
12958 +       PF_INET6,
12959 +       NF_IP6_LOCAL_OUT,
12960 +       NF_IP6_PRI_FIRST        /* Should be of EXTREMELY high priority since we
12961 +                                * do not want to mess with IPSec (possibly
12962 +                                * implemented as packet filter)
12963 +                                */
12964 +};
12965 +
12966 +#define MN_INFO_LEN 77
12967 +
12968 +static int mn_proc_info(char *buffer, char **start, off_t offset,
12969 +                       int length)
12970 +{
12971 +       struct list_head *p;
12972 +       struct mn_info *minfo;
12973 +       int len = 0, skip = 0;
12974 +
12975 +       DEBUG_FUNC();
12976 +
12977 +       read_lock_bh(&mn_info_lock);
12978 +       list_for_each(p, &mn_info_list) {
12979 +               if (len < offset / MN_INFO_LEN) {
12980 +                       skip++;
12981 +                       continue;
12982 +               }
12983 +               if (len >= length)
12984 +                       break;
12985 +               minfo = list_entry(p, struct mn_info, list);
12986 +               spin_lock(&minfo->lock);
12987 +               len += sprintf(buffer + len, "%02d %08x%08x%08x%08x %02x "
12988 +                              "%08x%08x%08x%08x %d %d\n",
12989 +                              minfo->ifindex,
12990 +                              ntohl(minfo->home_addr.s6_addr32[0]),
12991 +                              ntohl(minfo->home_addr.s6_addr32[1]),
12992 +                              ntohl(minfo->home_addr.s6_addr32[2]),
12993 +                              ntohl(minfo->home_addr.s6_addr32[3]),
12994 +                              minfo->home_plen,
12995 +                              ntohl(minfo->ha.s6_addr32[0]),
12996 +                              ntohl(minfo->ha.s6_addr32[1]),
12997 +                              ntohl(minfo->ha.s6_addr32[2]),
12998 +                              ntohl(minfo->ha.s6_addr32[3]),
12999 +                              minfo->is_at_home, minfo->has_home_reg);
13000 +               spin_unlock(&minfo->lock);
13001 +       }
13002 +       read_unlock_bh(&mn_info_lock);
13003 +
13004 +       *start = buffer;
13005 +       if (offset)
13006 +               *start += offset % MN_INFO_LEN;
13007 +
13008 +       len -= offset % MN_INFO_LEN;
13009 +
13010 +       if (len > length)
13011 +               len = length;
13012 +       if (len < 0)
13013 +               len = 0;
13014 +       
13015 +       return len;
13016 +}
13017 +
13018 +int mipv6_mn_ha_nd_update(struct net_device *dev,
13019 +                         struct in6_addr *ha, u8 *lladdr)
13020 +{
13021 +       int valid = 0;
13022 +       struct neighbour *neigh;
13023 +       if ((neigh = ndisc_get_neigh(dev, ha))) {
13024 +               read_lock(&neigh->lock);
13025 +               valid = neigh->nud_state & NUD_VALID;
13026 +               read_unlock(&neigh->lock);
13027 +               if (!valid && lladdr)
13028 +                       neigh_update(neigh, lladdr, NUD_REACHABLE, 0, 1);
13029 +               neigh_release(neigh);
13030 +       }
13031 +       return valid;
13032 +}
13033 +
13034 +int mipv6_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
13035 +{
13036 +       struct mn_info *minfo;
13037 +
13038 +       if (!(minfo = mipv6_mninfo_get_by_home(&ifp->addr)) ||
13039 +           ipv6_addr_any(&minfo->ha))
13040 +               return 0;
13041 +
13042 +       if (mipv6_mn_ha_nd_update(ifp->idev->dev, &minfo->ha, lladdr))
13043 +               mipv6_mdet_retrigger_ho();
13044 +       return 1;
13045 +}
13046 +
13047 +int __init mipv6_mn_init(void)
13048 +{
13049 +       struct net_device *dev;
13050 +
13051 +       DEBUG_FUNC();
13052 +
13053 +       if (mipv6_add_tnl_to_ha())
13054 +               return -ENODEV;
13055 +
13056 +       mipv6_bul_init(MIPV6_BUL_SIZE);
13057 +       mip6_fn.mn_use_hao = mn_use_hao;
13058 +       mip6_fn.mn_check_tunneled_packet = mn_check_tunneled_packet;
13059 +       INIT_TQUEUE(&mv_home_addr_task, mv_home_addr, NULL);
13060 +
13061 +       ma_ctl_init();
13062 +       for (dev = dev_base; dev; dev = dev->next) {
13063 +               if (dev->flags & IFF_UP && 
13064 +                   dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev)) {
13065 +                       ma_ctl_add_iface(dev->ifindex);
13066 +               }
13067 +       } 
13068 +       DEBUG(DBG_INFO, "Multiaccess support initialized");
13069 +
13070 +       register_netdevice_notifier(&mipv6_mn_dev_notifier);
13071 +       register_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13072 +
13073 +       ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13074 +       ip6ip6_tnl_register_hook(&mipv6_mn_tnl_xmit_stats_ops);
13075 +       ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_stats_ops);
13076 +
13077 +       MIPV6_SETCALL(mipv6_set_home, mipv6_mn_set_home);
13078 +
13079 +       mipv6_initialize_mdetect();
13080 +
13081 +       /* COA to home transformation hook */
13082 +       MIPV6_SETCALL(mipv6_get_home_address, mipv6_get_saddr_hook);
13083 +       MIPV6_SETCALL(mipv6_mn_ha_probe, mipv6_mn_ha_probe);
13084 +       MIPV6_SETCALL(mipv6_is_home_addr, mipv6_mn_is_home_addr);
13085 +       proc_net_create("mip6_mninfo", 0, mn_proc_info);
13086 +       /* Set packet modification hook (source addresses) */
13087 +       nf_register_hook(&addr_modify_hook_ops);
13088 +
13089 +       return 0;
13090 +}
13091 +
13092 +void __exit mipv6_mn_exit(void)
13093 +{
13094 +       struct list_head *lh, *tmp;
13095 +       struct mn_info *minfo;
13096 +       DEBUG_FUNC();
13097 +       
13098 +       mip6_fn.mn_use_hao = NULL;
13099 +       mip6_fn.mn_check_tunneled_packet = NULL;
13100 +       
13101 +       MIPV6_RESETCALL(mipv6_set_home);
13102 +       MIPV6_RESETCALL(mipv6_get_home_address);
13103 +       MIPV6_RESETCALL(mipv6_mn_ha_probe);
13104 +       MIPV6_RESETCALL(mipv6_is_home_addr);
13105 +       nf_unregister_hook(&addr_modify_hook_ops);
13106 +       proc_net_remove("mip6_mninfo");
13107 +       mipv6_shutdown_mdetect();
13108 +       ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_stats_ops);
13109 +       ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_xmit_stats_ops);
13110 +       ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13111 +       ma_ctl_clean();
13112 +
13113 +       unregister_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13114 +       unregister_netdevice_notifier(&mipv6_mn_dev_notifier);
13115 +       write_lock_bh(&mn_info_lock);
13116 +
13117 +       list_for_each_safe(lh, tmp, &mn_info_list) {
13118 +               minfo = list_entry(lh, struct mn_info, list);
13119 +               if (minfo->is_at_home == MN_NOT_AT_HOME) 
13120 +                       deprecate_addr(minfo);
13121 +               list_del(&minfo->list);
13122 +               kfree(minfo);
13123 +       }
13124 +       write_unlock_bh(&mn_info_lock);
13125 +       mipv6_bul_exit();
13126 +       flush_scheduled_tasks();
13127 +       mipv6_del_tnl_to_ha();
13128 +}
13129 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mn.h linux-2.4.25/net/ipv6/mobile_ip6/mn.h
13130 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mn.h   1970-01-01 01:00:00.000000000 +0100
13131 +++ linux-2.4.25/net/ipv6/mobile_ip6/mn.h       2004-06-26 11:29:31.000000000 +0100
13132 @@ -0,0 +1,96 @@
13133 +/*
13134 + *      MIPL Mobile IPv6 Mobile Node header file
13135 + *
13136 + *      $Id$
13137 + *
13138 + *      This program is free software; you can redistribute it and/or
13139 + *      modify it under the terms of the GNU General Public License
13140 + *      as published by the Free Software Foundation; either version
13141 + *      2 of the License, or (at your option) any later version.
13142 + */
13143 +
13144 +#ifndef _MN_H
13145 +#define _MN_H
13146 +
13147 +#include <linux/in6.h>
13148 +
13149 +/* constants for sending of BUs*/
13150 +#define HA_BU_DEF_LIFETIME 10000
13151 +#define CN_BU_DEF_LIFETIME 420 /* Max lifetime for RR bindings from RFC 3775 */
13152 +#define DUMB_CN_BU_LIFETIME 600 /* BUL entry lifetime in case of dumb CN */
13153 +#define ROUTER_BU_DEF_LIFETIME 30 /* For packet forwarding from previous coa */
13154 +#define ERROR_DEF_LIFETIME DUMB_CN_BU_LIFETIME
13155 +
13156 +extern rwlock_t mn_info_lock;
13157 +
13158 +#define MN_NOT_AT_HOME 0
13159 +#define MN_RETURNING_HOME 1
13160 +#define MN_AT_HOME 2
13161 +
13162 +/*
13163 + * Mobile Node information record
13164 + */
13165 +struct mn_info {
13166 +       struct in6_addr home_addr;
13167 +       struct in6_addr ha;
13168 +       __u8 home_plen;
13169 +       __u8 is_at_home;
13170 +       __u8 has_home_reg;
13171 +       __u8 man_conf;
13172 +       int ifindex;
13173 +       int ifindex_user; 
13174 +       unsigned long home_addr_expires;
13175 +       unsigned short dhaad_id;
13176 +       struct list_head list;
13177 +       spinlock_t lock;
13178 +};
13179 +
13180 +/* prototypes for interface functions */
13181 +int mipv6_mn_init(void);
13182 +void mipv6_mn_exit(void);
13183 +
13184 +struct handoff;
13185 +
13186 +/* Interface to movement detection */
13187 +int mipv6_mobile_node_moved(struct handoff *ho);
13188 +
13189 +void mipv6_mn_send_home_na(struct in6_addr *haddr);
13190 +/* Init home reg. with coa */
13191 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa);
13192 +
13193 +/* mn_info functions that require locking by caller */
13194 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr);
13195 +
13196 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent);
13197 +
13198 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id);
13199 +
13200 +/* "safe" mn_info functions */
13201 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen, 
13202 +                     int isathome, unsigned long lifetime, struct in6_addr *ha, 
13203 +                     int ha_plen, unsigned long ha_lifetime, int man_conf);
13204 +
13205 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only);
13206 +
13207 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg);
13208 +
13209 +int mipv6_mn_is_at_home(struct in6_addr *addr);
13210 +
13211 +int mipv6_mn_is_home_addr(struct in6_addr *addr);
13212 +
13213 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr, 
13214 +                             struct in6_addr *coa, __u8 flags);
13215 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey);
13216 +
13217 +int mipv6_mn_ha_nd_update(struct net_device *dev,
13218 +                         struct in6_addr *ha, u8 *lladdr);
13219 +
13220 +struct bul_inval_args {
13221 +       int all_rr_states;
13222 +       struct in6_addr *cn;
13223 +       struct in6_addr *mn;
13224 +};
13225 +
13226 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey);
13227 +
13228 +#endif /* _MN_H */
13229 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr.h linux-2.4.25/net/ipv6/mobile_ip6/mobhdr.h
13230 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr.h       1970-01-01 01:00:00.000000000 +0100
13231 +++ linux-2.4.25/net/ipv6/mobile_ip6/mobhdr.h   2004-06-26 11:29:31.000000000 +0100
13232 @@ -0,0 +1,101 @@
13233 +/*
13234 + *      MIPL Mobile IPv6 Mobility Header send and receive
13235 + *
13236 + *      $Id$
13237 + *
13238 + *      This program is free software; you can redistribute it and/or
13239 + *      modify it under the terms of the GNU General Public License
13240 + *      as published by the Free Software Foundation; either version
13241 + *      2 of the License, or (at your option) any later version.
13242 + */
13243 +
13244 +#ifndef _MOBHDR_H
13245 +#define _MOBHDR_H
13246 +
13247 +#include <net/mipv6.h>
13248 +
13249 +/* RR states for mipv6_send_bu() */
13250 +#define RR_INIT                        0x00
13251 +#define RR_WAITH               0x01
13252 +#define RR_WAITC               0x02
13253 +#define RR_WAITHC              0x13
13254 +#define RR_DONE                        0x10
13255 +
13256 +#define MH_UNKNOWN_CN 1
13257 +#define MH_AUTH_FAILED 2
13258 +#define MH_SEQUENCE_MISMATCH 3
13259 +
13260 +struct mipv6_bul_entry;
13261 +struct sk_buff;
13262 +
13263 +int mipv6_mh_common_init(void);
13264 +void mipv6_mh_common_exit(void);
13265 +int mipv6_mh_mn_init(void);
13266 +void mipv6_mh_mn_exit(void);
13267 +
13268 +struct mipv6_mh_opt {
13269 +       struct mipv6_mo_alt_coa         *alt_coa;
13270 +       struct mipv6_mo_nonce_indices   *nonce_indices;
13271 +       struct mipv6_mo_bauth_data      *auth_data;
13272 +       struct mipv6_mo_br_advice       *br_advice;
13273 +       int freelen;
13274 +       int totlen;
13275 +       u8 *next_free;
13276 +       u8 data[0];
13277 +};
13278 +
13279 +struct mobopt {
13280 +       struct mipv6_mo_alt_coa         *alt_coa;
13281 +       struct mipv6_mo_nonce_indices   *nonce_indices;
13282 +       struct mipv6_mo_bauth_data      *auth_data;
13283 +       struct mipv6_mo_br_advice       *br_advice;
13284 +};
13285 +
13286 +struct mipv6_mh_opt *alloc_mh_opts(int totlen);
13287 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data);
13288 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts);
13289 +int mipv6_add_pad(u8 *data, int n);
13290 +
13291 +struct mipv6_auth_parm {
13292 +       struct in6_addr *coa;
13293 +       struct in6_addr *cn_addr;
13294 +       __u8 *k_bu;
13295 +};
13296 +
13297 +int send_mh(struct in6_addr *daddr, struct in6_addr *saddr, 
13298 +           u8 msg_type, u8 msg_len, u8 *msg,
13299 +           struct in6_addr *hao_addr, struct in6_addr *rth_addr,
13300 +           struct mipv6_mh_opt *ops, struct mipv6_auth_parm *parm);
13301 +
13302 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13303 +       struct in6_addr *, struct in6_addr *, 
13304 +       struct in6_addr *, struct in6_addr *, struct mipv6_mh *));
13305 +
13306 +void mipv6_mh_unregister(int type);
13307 +
13308 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13309 +                  struct mipv6_mh_opt *ops);
13310 +
13311 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr, 
13312 +                 struct in6_addr *coa, __u32 initdelay, 
13313 +                 __u32 maxackdelay, __u8 exp, __u8 flags,
13314 +                 __u32 lifetime, struct mipv6_mh_opt *ops);
13315 +
13316 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr, 
13317 +                 struct in6_addr *home, __u8 status);
13318 +
13319 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr, 
13320 +                 struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13321 +                 u8 status, u16 sequence, u32 lifetime, u8 *k_bu);
13322 +
13323 +/* Binding Authentication Data Option routines */
13324 +#define MAX_HASH_LENGTH 20
13325 +#define MIPV6_RR_MAC_LENGTH 12
13326 +
13327 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa, 
13328 +                    __u8 *opt, __u8 *aud_data, __u8 *k_bu);
13329 +
13330 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa, 
13331 +                    __u8 *opt, __u8 optlen, struct mipv6_mo_bauth_data *aud, 
13332 +                    __u8 *k_bu);
13333 +#endif /* _MOBHDR_H */
13334 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_common.c linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_common.c
13335 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_common.c        1970-01-01 01:00:00.000000000 +0100
13336 +++ linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_common.c    2004-06-26 11:29:31.000000000 +0100
13337 @@ -0,0 +1,1210 @@
13338 +/*
13339 + *     Mobile IPv6 Mobility Header Common Functions
13340 + *
13341 + *     Authors:
13342 + *     Antti Tuominen <ajtuomin@tml.hut.fi>
13343 + *
13344 + *      $Id: s.mh_recv.c 1.159 02/10/16 15:01:29+03:00 antti@traci.mipl.mediapoli.com $
13345 + *
13346 + *      This program is free software; you can redistribute it and/or
13347 + *      modify it under the terms of the GNU General Public License
13348 + *      as published by the Free Software Foundation; either version
13349 + *      2 of the License, or (at your option) any later version.
13350 + *
13351 + */
13352 +
13353 +#include <linux/autoconf.h>
13354 +#include <linux/types.h>
13355 +#include <linux/in6.h>
13356 +#include <linux/skbuff.h>
13357 +#include <linux/ipsec.h>
13358 +#include <linux/init.h>
13359 +#include <net/ipv6.h>
13360 +#include <net/ip6_route.h>
13361 +#include <net/addrconf.h>
13362 +#include <net/mipv6.h>
13363 +#include <net/checksum.h>
13364 +#include <net/protocol.h>
13365 +
13366 +#include "stats.h"
13367 +#include "debug.h"
13368 +#include "mobhdr.h"
13369 +#include "bcache.h"
13370 +
13371 +#include "rr_crypto.h"
13372 +#include "exthdrs.h"
13373 +#include "config.h"
13374 +
13375 +#define MIPV6_MH_MAX MIPV6_MH_BE
13376 +struct mh_proto {
13377 +       int     (*func) (struct sk_buff *,
13378 +                        struct in6_addr *, struct in6_addr *, 
13379 +                        struct in6_addr *, struct in6_addr *, 
13380 +                        struct mipv6_mh *);
13381 +};
13382 +
13383 +static struct mh_proto mh_rcv[MIPV6_MH_MAX];
13384 +
13385 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13386 +       struct in6_addr *, struct in6_addr *, 
13387 +       struct in6_addr *, struct in6_addr *, struct mipv6_mh *))
13388 +{
13389 +       if (mh_rcv[type].func != NULL)
13390 +               return -1;
13391 +
13392 +       mh_rcv[type].func = func;
13393 +
13394 +       return 0;
13395 +}
13396 +
13397 +void mipv6_mh_unregister(int type)
13398 +{
13399 +       if (type < 0 || type > MIPV6_MH_MAX)
13400 +               return;
13401 +
13402 +       mh_rcv[type].func = NULL;
13403 +}
13404 +
13405 +struct socket *mipv6_mh_socket = NULL;
13406 +
13407 +/* TODO: Fix fragmentation */
13408 +static int dstopts_getfrag(
13409 +       const void *data, struct in6_addr *addr,
13410 +       char *buff, unsigned int offset, unsigned int len)
13411 +{
13412 +       memcpy(buff, data + offset, len);
13413 +       return 0;
13414 +}
13415 +
13416 +struct mipv6_mh_opt *alloc_mh_opts(int totlen)
13417 +{
13418 +       struct mipv6_mh_opt *ops;
13419 +
13420 +       ops = kmalloc(sizeof(*ops) + totlen, GFP_ATOMIC);
13421 +       if (ops == NULL)
13422 +               return NULL;
13423 +
13424 +       memset(ops, 0, sizeof(*ops));
13425 +       ops->next_free = ops->data;
13426 +       ops->freelen = totlen;
13427 +
13428 +       return ops;
13429 +}
13430 +
13431 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data)
13432 +{
13433 +       struct mipv6_mo *mo;
13434 +
13435 +       if (ops->next_free == NULL) {
13436 +               DEBUG(DBG_ERROR, "No free room for option");
13437 +               return -ENOMEM;
13438 +       }
13439 +       if (ops->freelen < len + 2) {
13440 +               DEBUG(DBG_ERROR, "No free room for option");
13441 +               return -ENOMEM;
13442 +       }
13443 +       else {
13444 +               ops->freelen -= (len + 2);
13445 +               ops->totlen += (len + 2);
13446 +       }
13447 +
13448 +       mo = (struct mipv6_mo *)ops->next_free;
13449 +       mo->type = type;
13450 +       mo->length = len;
13451 +
13452 +       switch (type) {
13453 +       case MIPV6_OPT_ALTERNATE_COA:
13454 +               ops->alt_coa = (struct mipv6_mo_alt_coa *)mo;
13455 +               ipv6_addr_copy(&ops->alt_coa->addr, (struct in6_addr *)data);
13456 +               break;
13457 +       case MIPV6_OPT_NONCE_INDICES:
13458 +               DEBUG(DBG_INFO, "Added nonce indices pointer");
13459 +               ops->nonce_indices = (struct mipv6_mo_nonce_indices *)mo;
13460 +               ops->nonce_indices->home_nonce_i = *(__u16 *)data;
13461 +               ops->nonce_indices->careof_nonce_i = *((__u16 *)data + 1);
13462 +               break;
13463 +       case MIPV6_OPT_AUTH_DATA:
13464 +               DEBUG(DBG_INFO, "Added opt auth_data pointer");
13465 +               ops->auth_data = (struct mipv6_mo_bauth_data *)mo;
13466 +               break;
13467 +       case MIPV6_OPT_BIND_REFRESH_ADVICE:
13468 +               ops->br_advice = (struct mipv6_mo_br_advice *)mo;
13469 +               ops->br_advice->refresh_interval = htons(*(u16 *)data);
13470 +               break;
13471 +       default:
13472 +               DEBUG(DBG_ERROR, "Unknow option type");
13473 +               break;
13474 +       }
13475 +
13476 +       if (ops->freelen == 0)
13477 +               ops->next_free = NULL;
13478 +       else
13479 +               ops->next_free += (len + 2);
13480 +
13481 +       return 0;
13482 +}
13483 +
13484 +/*
13485 + * Calculates required padding with xn + y requirement with offset
13486 + */
13487 +static inline int optpad(int xn, int y, int offset)
13488 +{
13489 +       return ((y - offset) & (xn - 1));
13490 +}
13491 +
13492 +static int option_pad(int type, int offset)
13493 +{
13494 +       if (type == MIPV6_OPT_ALTERNATE_COA)
13495 +               return optpad(8, 6, offset); /* 8n + 6 */
13496 +       if (type == MIPV6_OPT_BIND_REFRESH_ADVICE ||
13497 +           type == MIPV6_OPT_NONCE_INDICES)
13498 +               return optpad(2, 0, offset); /* 2n */
13499 +       return 0;
13500 +}
13501 +
13502 +/*
13503 + * Add Pad1 or PadN option to data
13504 + */
13505 +int mipv6_add_pad(u8 *data, int n)
13506 +{
13507 +       struct mipv6_mo_padn *padn;
13508 +
13509 +       if (n <= 0) return 0;
13510 +       if (n == 1) {
13511 +               *data = MIPV6_OPT_PAD1;
13512 +               return 1;
13513 +       }
13514 +       padn = (struct mipv6_mo_padn *)data;
13515 +       padn->type = MIPV6_OPT_PADN;
13516 +       padn->length = n - 2;
13517 +       memset(padn->data, 0, n - 2);
13518 +       return n;
13519 +}
13520 +
13521 +/*
13522 + * Write options to mobility header buffer
13523 + */
13524 +static int prepare_mh_opts(u8 *optdata, int off, struct mipv6_mh_opt *ops)
13525 +{
13526 +       u8 *nextopt = optdata;
13527 +       int offset = off, pad = 0;
13528 +
13529 +       if (ops == NULL) {
13530 +               nextopt = NULL;
13531 +               return -1;
13532 +       }
13533 +
13534 +       if (ops->alt_coa) {
13535 +               pad = option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13536 +               nextopt += mipv6_add_pad(nextopt, pad);
13537 +               memcpy(nextopt, ops->alt_coa, sizeof(struct mipv6_mo_alt_coa));
13538 +               nextopt += sizeof(struct mipv6_mo_alt_coa);
13539 +               offset += pad + sizeof(struct mipv6_mo_alt_coa);
13540 +       }
13541 +
13542 +       if (ops->br_advice) {
13543 +               pad = option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13544 +               nextopt += mipv6_add_pad(nextopt, pad);
13545 +               memcpy(nextopt, ops->br_advice, sizeof(struct mipv6_mo_br_advice));
13546 +               nextopt += sizeof(struct mipv6_mo_br_advice);
13547 +               offset += pad + sizeof(struct mipv6_mo_br_advice);
13548 +       }
13549 +
13550 +       if (ops->nonce_indices) {
13551 +               pad = option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13552 +               nextopt += mipv6_add_pad(nextopt, pad);
13553 +               memcpy(nextopt, ops->nonce_indices, sizeof(struct mipv6_mo_nonce_indices));
13554 +               nextopt += sizeof(struct mipv6_mo_nonce_indices);
13555 +               offset += pad + sizeof(struct mipv6_mo_nonce_indices);
13556 +       }
13557 +
13558 +       if (ops->auth_data) {
13559 +               /* This option should always be the last.  Header
13560 +                * length must be a multiple of 8 octects, so we pad
13561 +                * if necessary. */
13562 +               pad = optpad(8, 0, offset + ops->auth_data->length + 2);
13563 +               nextopt += mipv6_add_pad(nextopt, pad);
13564 +               memcpy(nextopt, ops->auth_data, ops->auth_data->length + 2);
13565 +               nextopt += ops->auth_data->length + 2;
13566 +       }
13567 +       nextopt = NULL;
13568 +
13569 +       return 0;
13570 +}
13571 +
13572 +static int calculate_mh_opts(struct mipv6_mh_opt *ops, int mh_len)
13573 +{
13574 +       int offset = mh_len;
13575 +
13576 +       if (ops == NULL)
13577 +               return 0;
13578 +
13579 +       if (ops->alt_coa)
13580 +               offset += sizeof(struct mipv6_mo_alt_coa)
13581 +                       + option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13582 +
13583 +       if (ops->br_advice)
13584 +               offset += sizeof(struct mipv6_mo_br_advice)
13585 +                       + option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13586 +
13587 +       if (ops->nonce_indices)
13588 +               offset += sizeof(struct mipv6_mo_nonce_indices)
13589 +                       + option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13590 +
13591 +       if (ops->auth_data) /* no alignment */
13592 +               offset += ops->auth_data->length + 2;
13593 +
13594 +       return offset - mh_len;
13595 +}
13596 +
13597 +/*
13598 + *
13599 + * Mobility Header Message send functions
13600 + *
13601 + */
13602 +
13603 +/**
13604 + * send_mh - builds and sends a MH msg
13605 + *
13606 + * @daddr: destination address for packet
13607 + * @saddr: source address for packet
13608 + * @msg_type: type of MH
13609 + * @msg_len: message length
13610 + * @msg: MH type specific data
13611 + * @hao_addr: home address for home address option
13612 + * @rth_addr: routing header address
13613 + * @ops: mobility options
13614 + * @parm: auth data
13615 + *
13616 + * Builds MH, appends the type specific msg data to the header and
13617 + * sends the packet with a home address option, if a home address was
13618 + * given. Returns 0, if everything succeeded and a negative error code
13619 + * otherwise.
13620 + **/
13621 +int send_mh(struct in6_addr *daddr, 
13622 +           struct in6_addr *saddr, 
13623 +           u8 msg_type, u8 msg_len, u8 *msg,
13624 +           struct in6_addr *hao_addr,
13625 +           struct in6_addr *rth_addr,
13626 +           struct mipv6_mh_opt *ops,
13627 +           struct mipv6_auth_parm *parm)
13628 +{
13629 +       struct flowi fl;
13630 +       struct mipv6_mh *mh; 
13631 +       struct sock *sk = mipv6_mh_socket->sk;
13632 +       struct ipv6_txoptions *txopt = NULL;
13633 +       int tot_len = sizeof(struct mipv6_mh) + msg_len;
13634 +       int padded_len = 0, txopt_len = 0;
13635 +
13636 +       DEBUG_FUNC();
13637 +       /* Add length of options */
13638 +       tot_len += calculate_mh_opts(ops, tot_len);
13639 +       /* Needs to be a multiple of 8 octets */
13640 +       padded_len = tot_len + optpad(8, 0, tot_len);
13641 +
13642 +       mh = sock_kmalloc(sk, padded_len, GFP_ATOMIC);
13643 +       if (!mh) {
13644 +               DEBUG(DBG_ERROR, "memory allocation failed");
13645 +               return -ENOMEM;
13646 +       }
13647 +
13648 +       memset(&fl, 0, sizeof(fl)); 
13649 +       fl.proto = IPPROTO_MOBILITY;
13650 +       fl.fl6_dst = daddr;
13651 +       fl.fl6_src = saddr;
13652 +       fl.fl6_flowlabel = 0;
13653 +       fl.oif = sk->bound_dev_if;
13654 +
13655 +       if (hao_addr || rth_addr) {
13656 +               __u8 *opt_ptr;
13657 +
13658 +               if (hao_addr)
13659 +                       txopt_len += sizeof(struct mipv6_dstopt_homeaddr) + 6;
13660 +               if (rth_addr)
13661 +                       txopt_len += sizeof(struct rt2_hdr);
13662 +
13663 +               txopt_len += sizeof(*txopt);
13664 +               txopt = sock_kmalloc(sk, txopt_len, GFP_ATOMIC);
13665 +               if (txopt == NULL) {
13666 +                       DEBUG(DBG_ERROR, "No socket space left");
13667 +                       sock_kfree_s(sk, mh, padded_len);
13668 +                       return -ENOMEM;
13669 +               }
13670 +               memset(txopt, 0, txopt_len);
13671 +               txopt->tot_len = txopt_len;
13672 +               opt_ptr = (__u8 *) (txopt + 1);
13673 +               if (hao_addr) {
13674 +                       int holen = sizeof(struct mipv6_dstopt_homeaddr) + 6;
13675 +                       txopt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
13676 +                       txopt->opt_flen += holen;
13677 +                       opt_ptr += holen;
13678 +                       mipv6_append_dst1opts(txopt->dst1opt, saddr, 
13679 +                                             NULL, holen);
13680 +                       txopt->mipv6_flags = MIPV6_SND_HAO | MIPV6_SND_BU;
13681 +               }
13682 +               if (rth_addr) {
13683 +                       int rtlen = sizeof(struct rt2_hdr);
13684 +                       txopt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
13685 +                       txopt->opt_nflen += rtlen;
13686 +                       opt_ptr += rtlen;
13687 +                       mipv6_append_rt2hdr(txopt->srcrt2, rth_addr);
13688 +               }
13689 +       }
13690 +
13691 +       /* Fill in the fields of MH */
13692 +       mh->payload = NEXTHDR_NONE;
13693 +       mh->length = (padded_len >> 3) - 1;     /* Units of 8 octets - 1 */
13694 +       mh->type = msg_type;
13695 +       mh->reserved = 0;
13696 +       mh->checksum = 0;
13697 +
13698 +       memcpy(mh->data, msg, msg_len);
13699 +       prepare_mh_opts(mh->data + msg_len, msg_len + sizeof(*mh), ops);
13700 +       /* If BAD is present, this is already done. */
13701 +       mipv6_add_pad((u8 *)mh + tot_len, padded_len - tot_len);
13702 +       
13703 +       if (parm && parm->k_bu && ops && ops->auth_data) {
13704 +               /* Calculate the position of the authorization data before adding checksum*/
13705 +               mipv6_auth_build(parm->cn_addr, parm->coa, (__u8 *)mh, 
13706 +                                (__u8 *)mh + padded_len - MIPV6_RR_MAC_LENGTH, parm->k_bu);
13707 +       }
13708 +       /* Calculate the MH checksum */
13709 +       mh->checksum = csum_ipv6_magic(fl.fl6_src, fl.fl6_dst, 
13710 +                                      padded_len, IPPROTO_MOBILITY,
13711 +                                      csum_partial((char *)mh, padded_len, 0));
13712 +       ip6_build_xmit(sk, dstopts_getfrag, mh, &fl, padded_len, txopt, 255,
13713 +                      MSG_DONTWAIT);
13714 +       /* dst cache must be cleared so RR messages can be routed through 
13715 +          different interfaces */
13716 +       sk_dst_reset(sk);
13717 +
13718 +       if (txopt_len)
13719 +               sock_kfree_s(sk, txopt, txopt_len);
13720 +       sock_kfree_s(sk, mh, padded_len);
13721 +       return 0;
13722 +}
13723 +
13724 +/**
13725 + * mipv6_send_brr - send a Binding Refresh Request 
13726 + * @saddr: source address for BRR
13727 + * @daddr: destination address for BRR
13728 + * @ops: mobility options
13729 + *
13730 + * Sends a binding request.  On a mobile node, use the mobile node's
13731 + * home address for @saddr.  Returns 0 on success, negative on
13732 + * failure.
13733 + **/
13734 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13735 +                  struct mipv6_mh_opt *ops)
13736 +{
13737 +       struct mipv6_mh_brr br;
13738 +
13739 +       memset(&br, 0, sizeof(br));
13740 +       /* We don't need to explicitly add a RH to brr, since it will be 
13741 +        * included automatically, if a BCE exists 
13742 +        */
13743 +       MIPV6_INC_STATS(n_brr_sent);
13744 +       return send_mh(daddr, saddr, MIPV6_MH_BRR, sizeof(br), (u8 *)&br,
13745 +                      NULL, NULL, ops, NULL);
13746 +}
13747 +
13748 +/**
13749 + * mipv6_send_ba - send a Binding Acknowledgement 
13750 + * @saddr: source address for BA
13751 + * @daddr: destination address for BA 
13752 + * @reply_coa: destination care-of address of MN
13753 + * @auth_coa: care-of address of MN used for authentication
13754 + * @status: status field value
13755 + * @sequence: sequence number from BU
13756 + * @lifetime: granted lifetime for binding in seconds
13757 + * @ops: mobility options
13758 + *
13759 + * Send a binding acknowledgement.  On a mobile node, use the mobile
13760 + * node's home address for saddr.  Returns 0 on success, non-zero on
13761 + * failure.
13762 + **/
13763 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr, 
13764 +                 struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13765 +                 u8 status, u16 sequence, u32 lifetime, u8 *k_bu)
13766 +{
13767 +       struct mipv6_mh_ba ba;
13768 +       struct mipv6_auth_parm parm;
13769 +       struct mipv6_mh_opt *ops = NULL; 
13770 +       int ops_len = 0, ret = 0;
13771 +       struct mipv6_bce bc_entry;
13772 +       int coming_home = 0;
13773 +       int bypass_tnl = 0;
13774 +
13775 +       memset(&ba, 0, sizeof(ba));
13776 +       
13777 +       ba.status = status;
13778 +       ba.sequence = htons(sequence);
13779 +       ba.lifetime = htons(lifetime >> 2);
13780 +       
13781 +       DEBUG(DBG_INFO, "sending a status %d BA %s authenticator to MN \n"
13782 +             "%x:%x:%x:%x:%x:%x:%x:%x  at care of address \n" 
13783 +             "%x:%x:%x:%x:%x:%x:%x:%x : with lifetime %d and \n" 
13784 +             " sequence number %d",
13785 +             status, k_bu ? "with" : "without", 
13786 +             NIPV6ADDR(daddr), NIPV6ADDR(auth_coa), lifetime, sequence);
13787 +
13788 +       memset(&parm, 0, sizeof(parm));
13789 +       parm.coa = auth_coa;
13790 +       parm.cn_addr = saddr;
13791 +
13792 +       if (k_bu) {
13793 +               ops_len += sizeof(struct mipv6_mo_bauth_data) + 
13794 +                       MIPV6_RR_MAC_LENGTH;
13795 +               parm.k_bu = k_bu;
13796 +       }
13797 +
13798 +       if (mip6node_cnf.binding_refresh_advice) {
13799 +               ops_len += sizeof(struct mipv6_mo_br_advice);
13800 +       }
13801 +       if (ops_len) {
13802 +               ops = alloc_mh_opts(ops_len);
13803 +               if (ops == NULL) {
13804 +                       DEBUG(DBG_WARNING, "Out of memory");
13805 +                       return -ENOMEM;
13806 +               }
13807 +               if (mip6node_cnf.binding_refresh_advice > 0) {
13808 +                       if (append_mh_opt(ops, MIPV6_OPT_BIND_REFRESH_ADVICE, 2,
13809 +                                         &mip6node_cnf.binding_refresh_advice) < 0) {
13810 +                               DEBUG(DBG_WARNING, "Adding BRA failed");
13811 +                               if (ops)
13812 +                                       kfree(ops);
13813 +                               return -ENOMEM;
13814 +                       }
13815 +               }
13816 +               if (k_bu) {
13817 +                       if (append_mh_opt(ops, MIPV6_OPT_AUTH_DATA,
13818 +                                         MIPV6_RR_MAC_LENGTH, NULL) < 0) {
13819 +                               DEBUG(DBG_WARNING, "Adding BAD failed");
13820 +                               if (ops)
13821 +                                       kfree(ops);
13822 +                               return -ENOMEM;
13823 +                       }
13824 +               }
13825 +       }
13826 +       coming_home = !ipv6_addr_cmp(rep_coa, daddr);
13827 +
13828 +       bypass_tnl = (coming_home &&
13829 +                     !mipv6_bcache_get(daddr, saddr, &bc_entry) &&
13830 +                     bc_entry.flags&MIPV6_BU_F_HOME && 
13831 +                     status >= 128);
13832 +
13833 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13834 +               mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13835 +                                      &bc_entry.our_addr,
13836 +                                      &bc_entry.home_addr);
13837 +
13838 +       if (coming_home)
13839 +               ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13840 +                             NULL, NULL, ops, &parm);
13841 +       else
13842 +               ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13843 +                             NULL, rep_coa, ops, &parm);
13844 +
13845 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13846 +               mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13847 +                                      &bc_entry.our_addr,
13848 +                                      &bc_entry.home_addr);
13849 +       
13850 +       if (ret == 0) {
13851 +               if (status < 128) {
13852 +                       MIPV6_INC_STATS(n_ba_sent);
13853 +               } else {
13854 +                       MIPV6_INC_STATS(n_ban_sent);
13855 +               }
13856 +       }
13857 +
13858 +       if (ops)
13859 +               kfree(ops);
13860 +
13861 +       return 0;
13862 +}
13863 +
13864 +/**
13865 + * mipv6_send_be - send a Binding Error message
13866 + * @saddr: source address for BE
13867 + * @daddr: destination address for BE
13868 + * @home: Home Address in offending packet (if any)
13869 + *
13870 + * Sends a binding error.  On a mobile node, use the mobile node's
13871 + * home address for @saddr.  Returns 0 on success, negative on
13872 + * failure.
13873 + **/
13874 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr, 
13875 +                 struct in6_addr *home, __u8 status)
13876 +{
13877 +       struct mipv6_mh_be be;
13878 +       int ret = 0;
13879 +       struct mipv6_bce bc_entry;
13880 +       int bypass_tnl = 0;
13881 +
13882 +       if (ipv6_addr_is_multicast(daddr))
13883 +               return -EINVAL;
13884 +
13885 +       memset(&be, 0, sizeof(be));
13886 +       be.status = status;
13887 +       if (home)
13888 +               ipv6_addr_copy(&be.home_addr, home);
13889 +
13890 +       if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0 &&
13891 +           bc_entry.flags&MIPV6_BU_F_HOME)
13892 +               bypass_tnl = 1;
13893 +
13894 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13895 +               mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13896 +                                      &bc_entry.our_addr,
13897 +                                      &bc_entry.home_addr);
13898 +
13899 +       ret = send_mh(daddr, saddr, MIPV6_MH_BE, sizeof(be), (u8 *)&be,
13900 +                     NULL, NULL, NULL, NULL);
13901 +       
13902 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13903 +               mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13904 +                                      &bc_entry.our_addr,
13905 +                                      &bc_entry.home_addr);
13906 +
13907 +       if (ret == 0)
13908 +               MIPV6_INC_STATS(n_be_sent);
13909 +
13910 +       return ret;
13911 +}
13912 +
13913 +/**
13914 + * mipv6_send_addr_test - send a HoT or CoT message
13915 + * @saddr: source address
13916 + * @daddr: destination address
13917 + * @msg_type: HoT or CoT message
13918 + * @init: HoTI or CoTI message
13919 + *
13920 + * Send a reply to HoTI or CoTI message. 
13921 + **/
13922 +static int mipv6_send_addr_test(struct in6_addr *saddr,
13923 +                               struct in6_addr *daddr,
13924 +                               int msg_type,
13925 +                               struct mipv6_mh_addr_ti *init)
13926 +{
13927 +       u_int8_t                        *kgen_token = NULL;
13928 +       struct mipv6_mh_addr_test       addr_test;      
13929 +       struct mipv6_rr_nonce           *nonce;
13930 +       struct mipv6_mh_opt *ops = NULL;
13931 +       int ret = 0;
13932 +
13933 +       DEBUG_FUNC();
13934 +
13935 +       if ((nonce = mipv6_rr_get_new_nonce())== NULL) {
13936 +               DEBUG(DBG_WARNING, "Nonce creation failed");
13937 +               return 0;
13938 +       } 
13939 +       if (mipv6_rr_cookie_create(daddr, &kgen_token, nonce->index)) {
13940 +               DEBUG(DBG_WARNING, "No cookie");
13941 +               return 0;
13942 +       }
13943 +
13944 +       addr_test.nonce_index = nonce->index;
13945 +       memcpy(addr_test.init_cookie, init->init_cookie,
13946 +                       MIPV6_RR_COOKIE_LENGTH);
13947 +       memcpy(addr_test.kgen_token, kgen_token,
13948 +                       MIPV6_RR_COOKIE_LENGTH);
13949 +
13950 +       /* No options defined */
13951 +       ret = send_mh(daddr, saddr, msg_type, sizeof(addr_test),
13952 +                     (u8 *)&addr_test, NULL, NULL, ops, NULL);
13953 +
13954 +       if (ret == 0) {
13955 +               if (msg_type == MIPV6_MH_HOT) {
13956 +                       MIPV6_INC_STATS(n_hot_sent);
13957 +               } else {
13958 +                       MIPV6_INC_STATS(n_cot_sent);
13959 +               }
13960 +       }
13961 +
13962 +       return 0;
13963 +}
13964 +
13965 +static void bc_cache_add(int ifindex, struct in6_addr *daddr,
13966 +                        struct in6_addr *haddr, struct in6_addr *coa,
13967 +                        struct in6_addr *rep_coa, __u32 lifetime,
13968 +                        __u16 sequence, __u8 flags, __u8 *k_bu)
13969 +{
13970 +       __u8 ba_status = SUCCESS;
13971 +
13972 +       if (lifetime >  MAX_RR_BINDING_LIFE)
13973 +               lifetime = MAX_RR_BINDING_LIFE;
13974 +
13975 +       if (mipv6_bcache_add(ifindex, daddr, haddr, coa, lifetime,
13976 +                            sequence, flags, CACHE_ENTRY) != 0) {
13977 +               DEBUG(DBG_ERROR, "binding failed.");
13978 +               ba_status = INSUFFICIENT_RESOURCES;
13979 +       } 
13980 +
13981 +       if (flags & MIPV6_BU_F_ACK) {
13982 +               DEBUG(DBG_INFO, "sending ack (code=%d)", ba_status);
13983 +               mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
13984 +                             lifetime, k_bu);
13985 +       }
13986 +}
13987 +
13988 +static void bc_cn_home_add(int ifindex, struct in6_addr *daddr, 
13989 +                          struct in6_addr *haddr, struct in6_addr *coa,
13990 +                          struct in6_addr *rep_coa, __u32 lifetime,
13991 +                          __u16 sequence, __u8 flags, __u8 *k_bu)
13992 +{
13993 +       mipv6_send_ba(daddr, haddr, coa, rep_coa,
13994 +                     HOME_REGISTRATION_NOT_SUPPORTED,
13995 +                     sequence, lifetime, k_bu);
13996 +}
13997 +
13998 +static void bc_cache_delete(struct in6_addr *daddr, struct in6_addr *haddr, 
13999 +                           struct in6_addr *coa, struct in6_addr *rep_coa,
14000 +                           __u16 sequence, __u8 flags,
14001 +                           __u8 *k_bu)
14002 +{
14003 +       __u8 status = SUCCESS;
14004 +
14005 +       /* Cached Care-of Address Deregistration */
14006 +       if (mipv6_bcache_exists(haddr, daddr) == CACHE_ENTRY) {
14007 +               mipv6_bcache_delete(haddr, daddr, CACHE_ENTRY);
14008 +       } else {
14009 +               DEBUG(DBG_INFO, "entry is not in cache");
14010 +               status = REASON_UNSPECIFIED;
14011 +       }
14012 +       if (flags & MIPV6_BU_F_ACK) {
14013 +               mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence, 
14014 +                             0, k_bu);
14015 +       }
14016 +}
14017 +
14018 +static void bc_cn_home_delete(struct in6_addr *daddr, struct in6_addr *haddr, 
14019 +                             struct in6_addr *coa, struct in6_addr *rep_coa,
14020 +                             __u16 sequence, __u8 flags,
14021 +                             __u8 *k_bu)
14022 +{
14023 +}
14024 +
14025 +/**
14026 + * parse_mo_tlv - Parse TLV-encoded Mobility Options
14027 + * @mos: pointer to Mobility Options
14028 + * @len: total length of options
14029 + * @opts: structure to store option pointers
14030 + *
14031 + * Parses Mobility Options passed in @mos.  Stores pointers in @opts
14032 + * to all valid mobility options found in @mos.  Unknown options and
14033 + * padding (%MIPV6_OPT_PAD1 and %MIPV6_OPT_PADN) is ignored and
14034 + * skipped.
14035 + **/
14036 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts)
14037 +{
14038 +       struct mipv6_mo *curr = (struct mipv6_mo *)mos;
14039 +       int left = len;
14040 +
14041 +       while (left > 0) {
14042 +               int optlen = 0;
14043 +               if (curr->type == MIPV6_OPT_PAD1)
14044 +                       optlen = 1;
14045 +               else
14046 +                       optlen = 2 + curr->length;
14047 +
14048 +               if (optlen > left)
14049 +                       goto bad;
14050 +
14051 +               switch (curr->type) {
14052 +               case MIPV6_OPT_PAD1:
14053 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_PAD1 at %x", curr);
14054 +                       break;
14055 +               case MIPV6_OPT_PADN:
14056 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_PADN at %x", curr);
14057 +                       break;
14058 +               case MIPV6_OPT_ALTERNATE_COA:
14059 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_ACOA at %x", curr);
14060 +                       opts->alt_coa = (struct mipv6_mo_alt_coa *)curr;
14061 +                       break;
14062 +               case MIPV6_OPT_NONCE_INDICES:
14063 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_NONCE_INDICES at %x", curr);
14064 +                       opts->nonce_indices = 
14065 +                               (struct mipv6_mo_nonce_indices *)curr;
14066 +                       break;
14067 +               case MIPV6_OPT_AUTH_DATA:
14068 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_AUTH_DATA at %x", curr);
14069 +                       opts->auth_data = (struct mipv6_mo_bauth_data *)curr;
14070 +                       break;
14071 +               case MIPV6_OPT_BIND_REFRESH_ADVICE:
14072 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_BIND_REFRESH_ADVICE at %x", curr);
14073 +                       opts->br_advice = (struct mipv6_mo_br_advice *)curr;
14074 +                       break;
14075 +               default:
14076 +                       DEBUG(DBG_INFO, "MO Unknown option type %d at %x, ignoring.",
14077 +                              curr->type, curr);
14078 +                       /* unknown mobility option, ignore and skip */
14079 +               }
14080 +
14081 +               (u8 *)curr += optlen;
14082 +               left -= optlen;
14083 +       }
14084 +
14085 +       if (left == 0)
14086 +               return 0;
14087 + bad:
14088 +       return -1;
14089 +}
14090 +
14091 +/*
14092 + *
14093 + * Mobility Header Message handlers
14094 + *
14095 + */
14096 +
14097 +static int mipv6_handle_mh_testinit(struct sk_buff *skb,
14098 +                                   struct in6_addr *cn,
14099 +                                   struct in6_addr *lcoa,
14100 +                                   struct in6_addr *saddr,
14101 +                                   struct in6_addr *fcoa,
14102 +                                   struct mipv6_mh *mh)
14103 +{
14104 +       struct mipv6_mh_addr_ti *ti = (struct mipv6_mh_addr_ti *)mh->data;
14105 +       int msg_len = (mh->length+1) << 3;
14106 +       int opt_len;
14107 +       DEBUG_FUNC();
14108 +
14109 +       if (msg_len > skb->len)
14110 +               return -1;
14111 +
14112 +       opt_len = msg_len - sizeof(*mh) - sizeof(*ti);
14113 +
14114 +       if (opt_len < 0) {
14115 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14116 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
14117 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
14118 +
14119 +               DEBUG(DBG_INFO, "Mobility Header length less than H/C TestInit");
14120 +               return -1;
14121 +       }
14122 +       if (!mip6node_cnf.accept_ret_rout) {
14123 +               DEBUG(DBG_INFO, "Return routability administratively disabled");
14124 +               return -1;
14125 +       }
14126 +       if (lcoa || fcoa) {
14127 +               DEBUG(DBG_INFO, "H/C TestInit has HAO or RTH2, dropped.");
14128 +               return -1;
14129 +       }
14130 +
14131 +       if (mh->type == MIPV6_MH_HOTI) {
14132 +               MIPV6_INC_STATS(n_hoti_rcvd);
14133 +               return mipv6_send_addr_test(cn, saddr, MIPV6_MH_HOT, ti);
14134 +       } else if (mh->type == MIPV6_MH_COTI) {
14135 +               MIPV6_INC_STATS(n_coti_rcvd);
14136 +               return mipv6_send_addr_test(cn, saddr, MIPV6_MH_COT, ti);
14137 +       } else 
14138 +               return -1; /* Impossible to get here */
14139 +}
14140 +
14141 +/**
14142 + * mipv6_handle_mh_bu - Binding Update handler
14143 + * @src: care-of address of sender
14144 + * @dst: our address
14145 + * @haddr: home address of sender
14146 + * @mh: pointer to the beginning of the Mobility Header
14147 + *
14148 + * Handles Binding Update. Packet and offset to option are passed.
14149 + * Returns 0 on success, otherwise negative.
14150 + **/
14151 +static int mipv6_handle_mh_bu(struct sk_buff *skb,
14152 +                             struct in6_addr *dst,
14153 +                             struct in6_addr *unused,
14154 +                             struct in6_addr *haddr, 
14155 +                             struct in6_addr *coaddr,
14156 +                             struct mipv6_mh *mh)
14157 +{
14158 +       struct mipv6_mh_bu *bu = (struct mipv6_mh_bu *)mh->data;
14159 +       int msg_len = (mh->length+1) << 3;
14160 +       int opt_len;
14161 +       int auth = 0;
14162 +       int dereg; /* Is this deregistration? */ 
14163 +       int addr_type;
14164 +
14165 +       struct mipv6_bce bc_entry;
14166 +       struct in6_addr *coa, *reply_coa;
14167 +       __u8 *key_bu = NULL; /* RR BU authentication key */
14168 +       __u8 flags = bu->flags;
14169 +       __u16 sequence;
14170 +       __u32 lifetime;
14171 +       __u16 nonce_ind = (__u16) -1; 
14172 +
14173 +       if (msg_len > skb->len)
14174 +               return -1;
14175 +
14176 +       opt_len = msg_len - sizeof(*mh) - sizeof(*bu);
14177 +
14178 +       if (opt_len < 0) {
14179 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14180 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
14181 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
14182 +
14183 +               DEBUG(DBG_INFO, "Mobility Header length less than BU");
14184 +               MIPV6_INC_STATS(n_bu_drop.invalid);
14185 +               return -1;
14186 +       }
14187 +
14188 +       addr_type = ipv6_addr_type(haddr);
14189 +       if (addr_type&IPV6_ADDR_LINKLOCAL || !(addr_type&IPV6_ADDR_UNICAST))
14190 +               return -EINVAL;
14191 +
14192 +       /* If HAO not present, CoA == HAddr */
14193 +       if (coaddr == NULL) 
14194 +               coa = haddr;
14195 +       else {
14196 +               coa = coaddr;
14197 +               addr_type = ipv6_addr_type(coa);
14198 +               if (addr_type&IPV6_ADDR_LINKLOCAL ||
14199 +                   !(addr_type&IPV6_ADDR_UNICAST))
14200 +                       return -EINVAL;
14201 +       }
14202 +       reply_coa = coa;
14203 +
14204 +       sequence = ntohs(bu->sequence);
14205 +       if (bu->lifetime == 0xffff)
14206 +               lifetime = 0xffffffff;
14207 +       else
14208 +               lifetime = ntohs(bu->lifetime) << 2;
14209 +
14210 +       dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14211 +
14212 +       if (opt_len > 0) {
14213 +               struct mobopt opts;
14214 +               memset(&opts, 0, sizeof(opts));
14215 +               if (parse_mo_tlv(bu + 1, opt_len, &opts) < 0) {
14216 +                       MIPV6_INC_STATS(n_bu_drop.invalid);
14217 +                       return -1;
14218 +               }
14219 +               /*
14220 +                * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_NONCE_INDICES, 
14221 +                * MIPV6_OPT_ALT_COA
14222 +                */
14223 +               if (opts.alt_coa) {
14224 +                       coa = &opts.alt_coa->addr;
14225 +                       dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14226 +               }
14227 +               addr_type = ipv6_addr_type(coa);
14228 +               if (addr_type&IPV6_ADDR_LINKLOCAL || 
14229 +                   !(addr_type&IPV6_ADDR_UNICAST))
14230 +                       return -EINVAL;
14231 +
14232 +               if (flags & MIPV6_BU_F_HOME) {
14233 +                       if (opts.nonce_indices)
14234 +                               return -1;
14235 +               } else {
14236 +                       u8 ba_status = 0;
14237 +                       u8 *h_ckie  = NULL, *c_ckie = NULL; /* Home and care-of cookies */
14238 +
14239 +                       /* BUs to CN MUST include authorization data and nonce indices options */
14240 +                       if (!opts.auth_data || !opts.nonce_indices) {
14241 +                               DEBUG(DBG_WARNING,
14242 +                                     "Route optimization BU without authorization material, aborting processing");
14243 +                               return MH_AUTH_FAILED;
14244 +                       }
14245 +                       if (mipv6_rr_cookie_create(
14246 +                                   haddr, &h_ckie, opts.nonce_indices->home_nonce_i) < 0) {
14247 +                               DEBUG(DBG_WARNING,
14248 +                                     "mipv6_rr_cookie_create failed for home cookie");
14249 +                               ba_status = EXPIRED_HOME_NONCE_INDEX;
14250 +                       }
14251 +                       nonce_ind = opts.nonce_indices->home_nonce_i;
14252 +                       /* Don't create the care-of cookie, if MN deregisters */
14253 +                       if (!dereg && mipv6_rr_cookie_create(
14254 +                                   coa, &c_ckie,
14255 +                                   opts.nonce_indices->careof_nonce_i) < 0) {
14256 +                               DEBUG(DBG_WARNING,
14257 +                                     "mipv6_rr_cookie_create failed for coa cookie");
14258 +                               if (ba_status == 0)
14259 +                                       ba_status = EXPIRED_CAREOF_NONCE_INDEX;
14260 +                               else
14261 +                                       ba_status = EXPIRED_NONCES;
14262 +                       }
14263 +                       if (ba_status == 0) {
14264 +                               if (dereg)
14265 +                                       key_bu = mipv6_rr_key_calc(h_ckie, NULL);
14266 +                               else
14267 +                                       key_bu = mipv6_rr_key_calc(h_ckie, c_ckie);            
14268 +                               mh->checksum = 0;/* TODO: Don't mangle the packet */
14269 +                               if (key_bu && mipv6_auth_check(
14270 +                                       dst, coa, (__u8 *)mh,  msg_len + sizeof(*mh), opts.auth_data, key_bu) == 0) {
14271 +                                       DEBUG(DBG_INFO, "mipv6_auth_check OK for BU");
14272 +                                       auth = 1;
14273 +                               } else {
14274 +                                       DEBUG(DBG_WARNING, 
14275 +                                             "BU Authentication failed");
14276 +                               }
14277 +                       }
14278 +                       if (h_ckie)
14279 +                               kfree(h_ckie);
14280 +                       if (c_ckie)
14281 +                               kfree(c_ckie);
14282 +                       if (ba_status != 0) {
14283 +                               MIPV6_INC_STATS(n_bu_drop.auth);
14284 +                               mipv6_send_ba(dst, haddr, coa,
14285 +                                             reply_coa, ba_status,
14286 +                                             sequence, 0, NULL);
14287 +                               goto out;
14288 +                       }
14289 +               }
14290 +
14291 +       }
14292 +       /* Require authorization option for RO, home reg is protected by IPsec */
14293 +       if (!(flags & MIPV6_BU_F_HOME) && !auth) {
14294 +               MIPV6_INC_STATS(n_bu_drop.auth);
14295 +               if (key_bu)
14296 +                       kfree(key_bu);
14297 +               return MH_AUTH_FAILED;
14298 +       }
14299 +
14300 +       if (mipv6_bcache_get(haddr, dst, &bc_entry) == 0) {
14301 +               if ((bc_entry.flags&MIPV6_BU_F_HOME) != 
14302 +                   (flags&MIPV6_BU_F_HOME)) {
14303 +                       DEBUG(DBG_INFO,
14304 +                             "Registration type change. Sending BA REG_TYPE_CHANGE_FORBIDDEN");
14305 +                       mipv6_send_ba(dst, haddr, coa, reply_coa,
14306 +                                     REG_TYPE_CHANGE_FORBIDDEN,
14307 +                                     sequence, lifetime, key_bu);
14308 +                       goto out;
14309 +               }
14310 +               if (!MIPV6_SEQ_GT(sequence, bc_entry.seq)) {
14311 +                       DEBUG(DBG_INFO,
14312 +                             "Sequence number mismatch. Sending BA SEQUENCE_NUMBER_OUT_OF_WINDOW");
14313 +                       mipv6_send_ba(dst, haddr, coa, reply_coa,
14314 +                                     SEQUENCE_NUMBER_OUT_OF_WINDOW,
14315 +                                     bc_entry.seq, lifetime, key_bu);
14316 +                       goto out;
14317 +               }
14318 +       }
14319 +
14320 +       if (!dereg) {
14321 +               int ifindex;
14322 +               struct rt6_info *rt;
14323 +
14324 +               /* Avoid looping binding cache entries */
14325 +               if (mipv6_bcache_get(coa, dst, &bc_entry) == 0) {
14326 +                       DEBUG(DBG_WARNING, "Looped BU, dropping the packet");
14327 +                       goto out;
14328 +               }
14329 +               DEBUG(DBG_INFO, "calling bu_add.");
14330 +               if ((rt = rt6_lookup(haddr, dst, 0, 0)) != NULL) {
14331 +                       ifindex = rt->rt6i_dev->ifindex;
14332 +                       dst_release(&rt->u.dst);
14333 +               } else {
14334 +                       /*
14335 +                        * Can't process the BU since the right interface is 
14336 +                        * not found.
14337 +                        */
14338 +                       DEBUG(DBG_WARNING, "No route entry found for handling "
14339 +                             "a BU request, (using 0 as index)");
14340 +                       ifindex = 0;
14341 +               }
14342 +               if (flags & MIPV6_BU_F_HOME)
14343 +                       mip6_fn.bce_home_add(ifindex, dst, haddr, coa, 
14344 +                                            reply_coa, lifetime, sequence,
14345 +                                            flags, key_bu);
14346 +               else
14347 +                       mip6_fn.bce_cache_add(ifindex, dst, haddr, coa, 
14348 +                                             reply_coa, lifetime, sequence,
14349 +                                             flags, key_bu);
14350 +       } else {
14351 +               DEBUG(DBG_INFO, "calling BCE delete.");
14352 +
14353 +               if (flags & MIPV6_BU_F_HOME)
14354 +                       mip6_fn.bce_home_del(dst, haddr, coa, reply_coa,
14355 +                                            sequence, flags, key_bu);
14356 +               else {
14357 +                       mipv6_rr_invalidate_nonce(nonce_ind);
14358 +                       mip6_fn.bce_cache_del(dst, haddr, coa, reply_coa, 
14359 +                                             sequence, flags, key_bu);
14360 +               }
14361 +       }
14362 + out:
14363 +       MIPV6_INC_STATS(n_bu_rcvd);
14364 +       if (key_bu)
14365 +               kfree(key_bu);
14366 +       return 0;
14367 +}
14368 +
14369 +static int mipv6_mh_rcv(struct sk_buff *skb)
14370 +{
14371 +       struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
14372 +       struct mipv6_mh *mh;
14373 +       struct in6_addr *lhome, *fhome, *lcoa = NULL, *fcoa = NULL;
14374 +       int ret = 0;
14375 +
14376 +       fhome = &skb->nh.ipv6h->saddr;
14377 +       lhome = &skb->nh.ipv6h->daddr;
14378 +
14379 +       if (opt->hao != 0) {
14380 +               struct mipv6_dstopt_homeaddr *hao;
14381 +               hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
14382 +               fcoa = &hao->addr;
14383 +       }
14384 +
14385 +       if (opt->srcrt2 != 0) {
14386 +               struct rt2_hdr *rt2;
14387 +               rt2 = (struct rt2_hdr *)((u8 *)skb->nh.raw + opt->srcrt2);
14388 +               lcoa = &rt2->addr;
14389 +       }
14390 +
14391 +       /* Verify checksum is correct */
14392 +       if (skb->ip_summed == CHECKSUM_HW) {
14393 +               skb->ip_summed = CHECKSUM_UNNECESSARY;
14394 +               if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14395 +                                   skb->csum)) {
14396 +                       if (net_ratelimit())
14397 +                               printk(KERN_WARNING "MIPv6 MH hw checksum failed\n");
14398 +                       skb->ip_summed = CHECKSUM_NONE;
14399 +               }
14400 +       }
14401 +       if (skb->ip_summed == CHECKSUM_NONE) {
14402 +               if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14403 +                                   skb_checksum(skb, 0, skb->len, 0))) {
14404 +                       if (net_ratelimit())
14405 +                               printk(KERN_WARNING "MIPv6 MH checksum failed\n");
14406 +                       goto bad;
14407 +               }
14408 +       }
14409 +
14410 +       if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*mh)) ||
14411 +           !pskb_may_pull(skb, 
14412 +                          skb->h.raw-skb->data+((skb->h.raw[1]+1)<<3))) {
14413 +               DEBUG(DBG_INFO, "MIPv6 MH invalid length");
14414 +               kfree_skb(skb);
14415 +               return 0;
14416 +       }
14417 +
14418 +       mh = (struct mipv6_mh *) skb->h.raw;
14419 +
14420 +       /* Verify there are no more headers after the MH */
14421 +       if (mh->payload != NEXTHDR_NONE) {
14422 +               __u32 pos = (__u32)&mh->payload - (__u32)skb->nh.raw;
14423 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
14424 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
14425 +
14426 +               DEBUG(DBG_INFO, "MIPv6 MH error");
14427 +               goto bad;
14428 +       }
14429 +
14430 +       if (mh->type > MIPV6_MH_MAX) {
14431 +               /* send binding error */
14432 +               printk("Invalid mobility header type (%d)\n", mh->type);
14433 +               mipv6_send_be(lhome, fcoa ? fcoa : fhome,
14434 +                             fcoa ? fhome : NULL, 
14435 +                             MIPV6_BE_UNKNOWN_MH_TYPE);
14436 +               goto bad;
14437 +       }
14438 +       if (mh_rcv[mh->type].func != NULL) {
14439 +               ret = mh_rcv[mh->type].func(skb, lhome, lcoa, fhome, fcoa, mh);
14440 +       } else {
14441 +               DEBUG(DBG_INFO, "No handler for MH Type %d", mh->type);
14442 +               goto bad;
14443 +       }
14444 +
14445 +       kfree_skb(skb);
14446 +       return 0;
14447 +
14448 +bad:
14449 +       MIPV6_INC_STATS(n_mh_in_error);
14450 +       kfree_skb(skb);
14451 +       return 0;
14452 +
14453 +}
14454 +
14455 +#if LINUX_VERSION_CODE >= 0x2052a
14456 +struct inet6_protocol mipv6_mh_protocol =
14457 +{
14458 +       mipv6_mh_rcv,           /* handler              */
14459 +       NULL                    /* error control        */
14460 +};
14461 +#else
14462 +struct inet6_protocol mipv6_mh_protocol = 
14463 +{
14464 +       mipv6_mh_rcv,           /* handler              */
14465 +       NULL,                   /* error control        */
14466 +       NULL,                   /* next                 */
14467 +       IPPROTO_MOBILITY,       /* protocol ID          */
14468 +       0,                      /* copy                 */
14469 +       NULL,                   /* data                 */
14470 +       "MIPv6 MH"              /* name                 */
14471 +};
14472 +#endif
14473 +
14474 +/*
14475 + *
14476 + * Code module init/exit functions
14477 + *
14478 + */
14479 +
14480 +int __init mipv6_mh_common_init(void)
14481 +{
14482 +       struct sock *sk;
14483 +       int err;
14484 +
14485 +       mip6_fn.bce_home_add = bc_cn_home_add;
14486 +       mip6_fn.bce_cache_add = bc_cache_add;
14487 +       mip6_fn.bce_home_del = bc_cn_home_delete;
14488 +       mip6_fn.bce_cache_del = bc_cache_delete;
14489 +
14490 +       mipv6_mh_socket = sock_alloc();
14491 +       if (mipv6_mh_socket == NULL) {
14492 +               printk(KERN_ERR
14493 +                      "Failed to create the MIP6 MH control socket.\n");
14494 +               return -1;
14495 +       }
14496 +       mipv6_mh_socket->type = SOCK_RAW;
14497 +
14498 +       if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_MOBILITY, 
14499 +                              &mipv6_mh_socket)) < 0) {
14500 +               printk(KERN_ERR
14501 +                      "Failed to initialize the MIP6 MH control socket (err %d).\n",
14502 +                      err);
14503 +               sock_release(mipv6_mh_socket);
14504 +               mipv6_mh_socket = NULL; /* for safety */
14505 +               return err;
14506 +       }
14507 +
14508 +       sk = mipv6_mh_socket->sk;
14509 +       sk->allocation = GFP_ATOMIC;
14510 +       sk->sndbuf = 64 * 1024 + sizeof(struct sk_buff);
14511 +       sk->prot->unhash(sk);
14512 +
14513 +       memset(&mh_rcv, 0, sizeof(mh_rcv));
14514 +       mh_rcv[MIPV6_MH_HOTI].func = mipv6_handle_mh_testinit;
14515 +       mh_rcv[MIPV6_MH_COTI].func = mipv6_handle_mh_testinit;
14516 +       mh_rcv[MIPV6_MH_BU].func =  mipv6_handle_mh_bu;
14517 +
14518 +#if LINUX_VERSION_CODE >= 0x2052a
14519 +       if (inet6_add_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY) < 0) {
14520 +               printk(KERN_ERR "Failed to register MOBILITY protocol\n");
14521 +               sock_release(mipv6_mh_socket);
14522 +               mipv6_mh_socket = NULL;
14523 +               return -EAGAIN;
14524 +       }
14525 +#else
14526 +       inet6_add_protocol(&mipv6_mh_protocol);
14527 +#endif
14528 +       /* To disable the use of dst_cache, 
14529 +        *  which slows down the sending of BUs ??
14530 +        */
14531 +       sk->dst_cache=NULL; 
14532 +
14533 +       return 0;
14534 +}
14535 +
14536 +void __exit mipv6_mh_common_exit(void)
14537 +{
14538 +       if (mipv6_mh_socket) sock_release(mipv6_mh_socket);
14539 +       mipv6_mh_socket = NULL; /* For safety. */
14540 +
14541 +#if LINUX_VERSION_CODE >= 0x2052a
14542 +       inet6_del_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY);
14543 +#else
14544 +       inet6_del_protocol(&mipv6_mh_protocol);
14545 +#endif
14546 +       memset(&mh_rcv, 0, sizeof(mh_rcv));
14547 +}
14548 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_mn.c linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_mn.c
14549 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_mn.c    1970-01-01 01:00:00.000000000 +0100
14550 +++ linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_mn.c        2004-06-26 11:29:32.000000000 +0100
14551 @@ -0,0 +1,1155 @@
14552 +/*
14553 + *     Mobile IPv6 Mobility Header Functions for Mobile Node
14554 + *
14555 + *     Authors:
14556 + *     Antti Tuominen  <ajtuomin@tml.hut.fi>
14557 + *     Niklas Kämpe    <nhkampe@cc.hut.fi>
14558 + *     Henrik Petander <henrik.petander@hut.fi>
14559 + *
14560 + *     $Id:$
14561 + *
14562 + *     This program is free software; you can redistribute it and/or
14563 + *     modify it under the terms of the GNU General Public License as
14564 + *     published by the Free Software Foundation; either version 2 of
14565 + *     the License, or (at your option) any later version.
14566 + *
14567 + */
14568 +
14569 +#include <linux/types.h>
14570 +#include <linux/sched.h>
14571 +#include <linux/init.h>
14572 +#include <net/ipv6.h>
14573 +#include <net/addrconf.h>
14574 +#include <net/mipv6.h>
14575 +
14576 +#include "mobhdr.h"
14577 +#include "mn.h"
14578 +#include "bul.h"
14579 +#include "rr_crypto.h"
14580 +#include "debug.h"
14581 +#include "util.h"
14582 +#include "stats.h"
14583 +
14584 +int rr_configured = 1;
14585 +
14586 +/* Return value of mipv6_rr_state() */
14587 +#define NO_RR                  0
14588 +#define DO_RR                  1
14589 +#define RR_FOR_COA             2
14590 +#define INPROGRESS_RR          3
14591 +
14592 +/** 
14593 + * send_bu_msg - sends a Binding Update 
14594 + * @bulentry : BUL entry with the information for building a BU
14595 + *
14596 + * Function builds a BU msg based on the contents of a bul entry.
14597 + * Does not change the bul entry.
14598 + **/
14599 +static int send_bu_msg(struct mipv6_bul_entry *binding)
14600 +{ 
14601 +       int auth = 0; /* Use auth */
14602 +       int ret = 0;
14603 +       struct mipv6_auth_parm parm;
14604 +       struct mipv6_mh_bu bu;
14605 +
14606 +       if (!binding) {
14607 +               DEBUG(DBG_ERROR, "called with a null bul entry");
14608 +               return -1;
14609 +       }
14610 +       
14611 +       memset(&parm, 0, sizeof(parm));
14612 +       if (mipv6_prefix_compare(&binding->coa, &binding->home_addr, 64))
14613 +               parm.coa = &binding->home_addr;
14614 +       else
14615 +               parm.coa = &binding->coa;
14616 +       parm.cn_addr = &binding->cn_addr;
14617 +
14618 +       if (binding->rr && binding->rr->kbu) {
14619 +               DEBUG(DBG_INFO, "Binding with key");
14620 +               auth = 1;
14621 +               parm.k_bu = binding->rr->kbu;
14622 +       }
14623 +       memset(&bu, 0, sizeof(bu));
14624 +       bu.flags = binding->flags;
14625 +       bu.sequence = htons(binding->seq);
14626 +       bu.lifetime = htons(binding->lifetime >> 2);
14627 +       bu.reserved = 0;
14628 +
14629 +       ret = send_mh(&binding->cn_addr, &binding->home_addr,
14630 +                     MIPV6_MH_BU, sizeof(bu), (u8 *)&bu, 
14631 +                     &binding->home_addr, NULL, 
14632 +                     binding->ops, &parm);
14633 +
14634 +       if (ret == 0)
14635 +               MIPV6_INC_STATS(n_bu_sent);
14636 +
14637 +       return ret;
14638 +}
14639 +
14640 +/**
14641 + * mipv6_send_addr_test_init - send a HoTI or CoTI message
14642 + * @saddr: source address for H/CoTI
14643 + * @daddr: destination address for H/CoTI
14644 + * @msg_type: Identifies whether HoTI or CoTI
14645 + * @init_cookie: the HoTi or CoTi init cookie
14646 + *
14647 + * The message will be retransmitted till we get a HoT or CoT message, since 
14648 + * our caller (mipv6_RR_start) has entered this message in the BUL with
14649 + * exponential backoff retramission set.
14650 + */
14651 +static int mipv6_send_addr_test_init(struct in6_addr *saddr,
14652 +                                    struct in6_addr *daddr,
14653 +                                    u8 msg_type,
14654 +                                    u8 *init_cookie)
14655 +{
14656 +       struct mipv6_mh_addr_ti ti;
14657 +       struct mipv6_mh_opt *ops = NULL;
14658 +       int ret = 0;
14659 +
14660 +       /* Set reserved and copy the cookie from address test init msg */
14661 +       ti.reserved = 0;
14662 +       mipv6_rr_mn_cookie_create(init_cookie);
14663 +       memcpy(ti.init_cookie, init_cookie, MIPV6_RR_COOKIE_LENGTH);
14664 +
14665 +       ret = send_mh(daddr, saddr, msg_type, sizeof(ti), (u8 *)&ti,
14666 +                     NULL, NULL, ops, NULL);
14667 +       if (ret == 0) {
14668 +               if (msg_type == MIPV6_MH_HOTI) {
14669 +                       MIPV6_INC_STATS(n_hoti_sent);
14670 +               } else {
14671 +                       MIPV6_INC_STATS(n_coti_sent);
14672 +               }
14673 +       }
14674 +
14675 +       return ret;
14676 +}
14677 +
14678 +/*
14679 + *
14680 + * Callback handlers for binding update list
14681 + *
14682 + */
14683 +
14684 +/* Return value 0 means keep entry, non-zero means discard entry. */
14685 +
14686 +/* Callback for BUs not requiring acknowledgement
14687 + */
14688 +int bul_entry_expired(struct mipv6_bul_entry *bulentry)
14689 +{
14690 +       /* Lifetime expired, delete entry. */
14691 +       DEBUG(DBG_INFO, "bul entry 0x%p lifetime expired, deleting entry", 
14692 +             bulentry);
14693 +       return 1;
14694 +}
14695 +
14696 +/* Callback for BUs requiring acknowledgement with exponential resending
14697 + * scheme */
14698 +static int bul_resend_exp(struct mipv6_bul_entry *bulentry)
14699 +{
14700 +       unsigned long now = jiffies;
14701 +       
14702 +       DEBUG(DBG_INFO, "(0x%x) resending bu", (int) bulentry);
14703 +
14704 +       
14705 +       /* If sending a de-registration, do not care about the
14706 +        * lifetime value, as de-registrations are normally sent with
14707 +        * a zero lifetime value. If the entry is a home entry get the 
14708 +        * current lifetime. 
14709 +        */
14710 +
14711 +       if (bulentry->lifetime != 0) {
14712 +               bulentry->lifetime = mipv6_mn_get_bulifetime(
14713 +                       &bulentry->home_addr, &bulentry->coa, bulentry->flags);
14714 +
14715 +               bulentry->expire = now + bulentry->lifetime * HZ;
14716 +       } else {
14717 +               bulentry->expire = now + HOME_RESEND_EXPIRE * HZ; 
14718 +       }
14719 +       if (bulentry->rr) {
14720 +               /* Redo RR, if cookies have expired */
14721 +               if (time_after(jiffies, bulentry->rr->home_time + MAX_TOKEN_LIFE * HZ)) 
14722 +                       bulentry->rr->rr_state |= RR_WAITH;
14723 +               if (time_after(jiffies, bulentry->rr->careof_time + MAX_NONCE_LIFE * HZ)) 
14724 +                       bulentry->rr->rr_state |= RR_WAITC;
14725 +
14726 +               if (bulentry->rr->rr_state & RR_WAITH) {
14727 +                       /* Resend HoTI directly */
14728 +                       mipv6_send_addr_test_init(&bulentry->home_addr, 
14729 +                                                 &bulentry->cn_addr, MIPV6_MH_HOTI,
14730 +                                                 bulentry->rr->hot_cookie);
14731 +               }
14732 +               if (bulentry->rr->rr_state & RR_WAITC) {
14733 +                               /* Resend CoTI directly */
14734 +                               mipv6_send_addr_test_init(&bulentry->coa, 
14735 +                                                         &bulentry->cn_addr, MIPV6_MH_COTI,
14736 +                                                         bulentry->rr->cot_cookie);
14737 +                       }
14738 +               goto out;
14739 +       }
14740 +       
14741 +       bulentry->seq++;
14742 +
14743 +       if (send_bu_msg(bulentry) < 0)
14744 +               DEBUG(DBG_ERROR, "Resending of BU failed");
14745 +
14746 +out:
14747 +       /* Schedule next retransmission */
14748 +       if (bulentry->delay < bulentry->maxdelay) {
14749 +               bulentry->delay = 2 * bulentry->delay;
14750 +               if (bulentry->delay > bulentry->maxdelay) {
14751 +                       /* can happen if maxdelay is not power(mindelay, 2) */
14752 +                       bulentry->delay = bulentry->maxdelay;
14753 +               }
14754 +       } else if (bulentry->flags & MIPV6_BU_F_HOME) {
14755 +               /* Home registration - continue sending BU at maxdelay rate */
14756 +               DEBUG(DBG_INFO, "Sending BU to HA after max ack wait time "
14757 +                     "reached(0x%x)", (int) bulentry);
14758 +               bulentry->delay = bulentry->maxdelay;
14759 +       } else if (!(bulentry->flags & MIPV6_BU_F_HOME)) {
14760 +               /* Failed to get BA from a CN */
14761 +               bulentry->callback_time = now;
14762 +               return -1;
14763 +       }
14764 +       
14765 +       bulentry->callback_time = now + bulentry->delay * HZ;
14766 +       return 0;
14767 +}
14768 +
14769 +
14770 +
14771 +/* Callback for sending a registration refresh BU
14772 + */
14773 +static int bul_refresh(struct mipv6_bul_entry *bulentry)
14774 +{
14775 +       unsigned long now = jiffies;
14776 +       
14777 +       /* Refresh interval passed, send new BU */
14778 +       DEBUG(DBG_INFO, "bul entry 0x%x refresh interval passed, sending new BU", (int) bulentry);
14779 +       if (bulentry->lifetime == 0)
14780 +               return 0;
14781 +
14782 +       /* Set new maximum lifetime and expiration time */
14783 +       bulentry->lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr, 
14784 +                                                    &bulentry->coa, 
14785 +                                                    bulentry->flags);
14786 +       bulentry->expire = now + bulentry->lifetime * HZ;
14787 +       bulentry->seq++;
14788 +       /* Send update */
14789 +       if (send_bu_msg(bulentry) < 0)
14790 +               DEBUG(DBG_ERROR, "Resending of BU failed");
14791 +       
14792 +       if (time_after_eq(now, bulentry->expire)) {
14793 +               /* Sanity check */
14794 +               DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs", ERROR_DEF_LIFETIME);
14795 +               bulentry->lifetime = ERROR_DEF_LIFETIME;
14796 +               bulentry->expire = now + ERROR_DEF_LIFETIME*HZ;
14797 +       }
14798 +
14799 +       /* Set up retransmission */
14800 +       bulentry->state = RESEND_EXP;
14801 +       bulentry->callback = bul_resend_exp;
14802 +       bulentry->callback_time = now + INITIAL_BINDACK_TIMEOUT*HZ;
14803 +       bulentry->delay = INITIAL_BINDACK_TIMEOUT;
14804 +       bulentry->maxdelay = MAX_BINDACK_TIMEOUT;
14805 +
14806 +       return 0;
14807 +}
14808 +
14809 +static int mipv6_send_RR_bu(struct mipv6_bul_entry *bulentry)
14810 +{
14811 +       int ret;
14812 +       int ops_len = 0;
14813 +       u16 nonces[2];
14814 +
14815 +       DEBUG(DBG_INFO, "Sending BU to CN  %x:%x:%x:%x:%x:%x:%x:%x "
14816 +             "for home address %x:%x:%x:%x:%x:%x:%x:%x", 
14817 +             NIPV6ADDR(&bulentry->cn_addr), NIPV6ADDR(&bulentry->home_addr));
14818 +       nonces[0] = bulentry->rr->home_nonce_index;
14819 +       nonces[1] = bulentry->rr->careof_nonce_index;
14820 +       ops_len = sizeof(struct mipv6_mo_bauth_data) + MIPV6_RR_MAC_LENGTH + 
14821 +                       sizeof(struct mipv6_mo_nonce_indices);
14822 +       if (bulentry->ops) {
14823 +               DEBUG(DBG_WARNING, "Bul entry had existing mobility options, freeing them");
14824 +               kfree(bulentry->ops);
14825 +       }
14826 +       bulentry->ops = alloc_mh_opts(ops_len);
14827 +
14828 +       if (!bulentry->ops)
14829 +               return -ENOMEM;
14830 +       if (append_mh_opt(bulentry->ops, MIPV6_OPT_NONCE_INDICES, 
14831 +                         sizeof(struct mipv6_mo_nonce_indices) - 2, nonces) < 0)
14832 +               return -ENOMEM;
14833 +
14834 +       if (append_mh_opt(bulentry->ops, MIPV6_OPT_AUTH_DATA,
14835 +                         MIPV6_RR_MAC_LENGTH, NULL) < 0)
14836 +               return -ENOMEM;
14837 +       /* RR procedure is over, send a BU */
14838 +       if (!(bulentry->flags & MIPV6_BU_F_ACK)) {
14839 +               DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
14840 +               bulentry->state = ACK_OK;
14841 +               bulentry->callback = bul_entry_expired;
14842 +               bulentry->callback_time = jiffies + HZ * bulentry->lifetime;
14843 +               bulentry->expire = jiffies + HZ *  bulentry->lifetime;
14844 +       }
14845 +       else {
14846 +               bulentry->callback_time = jiffies + HZ;
14847 +               bulentry->expire = jiffies + HZ *  bulentry->lifetime;
14848 +       }
14849 +
14850 +       ret  = send_bu_msg(bulentry);
14851 +       mipv6_bul_reschedule(bulentry);
14852 +       return ret;
14853 +}
14854 +
14855 +static int mipv6_rr_state(struct mipv6_bul_entry *bul, struct in6_addr *saddr,
14856 +                         struct in6_addr *coa, __u8 flags)
14857 +{
14858 +       if (!rr_configured)
14859 +               return NO_RR;
14860 +               if (flags & MIPV6_BU_F_HOME) {
14861 +               /* We don't need RR, this is a Home Registration */
14862 +               return NO_RR;
14863 +       }
14864 +       if (!bul || !bul->rr) {
14865 +               /* First time BU to CN, need RR */
14866 +               return DO_RR;
14867 +       }
14868 +
14869 +       switch (bul->rr->rr_state) {
14870 +       case RR_INIT:
14871 +               /* Need RR if first BU to CN */
14872 +               return DO_RR;
14873 +       case RR_DONE:
14874 +               /* If MN moves to a new coa, do RR for it */
14875 +               if (!ipv6_addr_cmp(&bul->coa, coa))  
14876 +                       return NO_RR; 
14877 +               else
14878 +                       return DO_RR;
14879 +       default:
14880 +               /*
14881 +                * We are in the middle of RR, the HoTI and CoTI have been
14882 +                * sent. But we haven't got HoT and CoT from the CN, so
14883 +                * don't do anything more at this time.
14884 +                */
14885 +               return INPROGRESS_RR;
14886 +       }
14887 +}
14888 +
14889 +/**
14890 + * mipv6_RR_start - Start Return Routability procedure
14891 + * @home_addr: home address
14892 + * @cn_addr: correspondent address
14893 + * @coa: care-of address
14894 + * @entry: binding update list entry (if any)
14895 + * @initdelay: initial ack timeout
14896 + * @maxackdelay: maximum ack timeout
14897 + * @flags: flags
14898 + * @lifetime: lifetime of binding
14899 + * @ops: mobility options
14900 + *
14901 + * Caller must hold @bul_lock (write).
14902 + **/
14903 +static int mipv6_RR_start(struct in6_addr *home_addr, struct in6_addr *cn_addr,
14904 +                         struct in6_addr *coa, struct mipv6_bul_entry *entry,
14905 +                         __u32 initdelay, __u32 maxackdelay, __u8 flags, 
14906 +                         __u32 lifetime, struct mipv6_mh_opt *ops)
14907 +{
14908 +       int ret = -1;
14909 +       struct mipv6_bul_entry *bulentry = entry;
14910 +       struct mipv6_rr_info *rr = NULL;
14911 +       int seq = 0;
14912 +       DEBUG_FUNC();
14913 +       
14914 +       /* Do RR procedure only for care-of address after handoff, 
14915 +          if home cookie is still valid */
14916 +       if (bulentry && bulentry->rr) {
14917 +               if (time_before(jiffies, bulentry->rr->home_time + MAX_NONCE_LIFE * HZ) &&
14918 +                   lifetime && !(ipv6_addr_cmp(home_addr, coa) == 0)) { 
14919 +                       mipv6_rr_mn_cookie_create(bulentry->rr->cot_cookie); 
14920 +                       DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for CoA");
14921 +                       ipv6_addr_copy(&bulentry->coa, coa);
14922 +                       bulentry->rr->rr_state |= RR_WAITC;
14923 +               } else if (!lifetime) { /* Send only HoTi when returning home */
14924 +                       mipv6_rr_mn_cookie_create(bulentry->rr->hot_cookie); 
14925 +                       DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for HoA");
14926 +                       ipv6_addr_copy(&bulentry->coa, coa); /* Home address as CoA */
14927 +                       bulentry->rr->rr_state |= RR_WAITH;
14928 +               }
14929 +       } else {
14930 +               DEBUG(DBG_INFO, "Doing RR for both HoA and CoA");
14931 +               rr = kmalloc(sizeof(*rr), GFP_ATOMIC);
14932 +               memset(rr, 0, sizeof(*rr));
14933 +               rr->rr_state = RR_WAITHC;
14934 +       } 
14935 +       if (bulentry) {
14936 +               if (bulentry->state == ACK_ERROR)
14937 +                       goto out;
14938 +               seq = bulentry->seq + 1;
14939 +       } else
14940 +               seq = 0;
14941 +       /* Save the info in the BUL to retransmit the BU after RR is done */
14942 +       /* Caller must hold bul_lock (write) since we don't */
14943 +       
14944 +       if ((bulentry = mipv6_bul_add(cn_addr, home_addr, coa, 
14945 +                                     min_t(__u32, lifetime, MAX_RR_BINDING_LIFE),
14946 +                                     seq, flags, bul_resend_exp, initdelay, 
14947 +                                     RESEND_EXP, initdelay, 
14948 +                                     maxackdelay, ops, 
14949 +                                     rr)) == NULL) {
14950 +               DEBUG(DBG_INFO, "couldn't update BUL for HoTi");
14951 +               goto out;
14952 +       }
14953 +
14954 +       rr = bulentry->rr; 
14955 +       if (rr->rr_state&RR_WAITH)
14956 +               mipv6_send_addr_test_init(home_addr, cn_addr, MIPV6_MH_HOTI, 
14957 +                                         rr->hot_cookie);
14958 +       if (ipv6_addr_cmp(home_addr, coa) && lifetime) 
14959 +               mipv6_send_addr_test_init(coa, cn_addr, MIPV6_MH_COTI, rr->cot_cookie);
14960 +       else {
14961 +               bulentry->rr->rr_state &= ~RR_WAITC;
14962 +       }
14963 +       ret = 0;
14964 +out:
14965 +       return ret;
14966 +}
14967 +
14968 +/*
14969 + * Status codes for mipv6_ba_rcvd()
14970 + */
14971 +#define STATUS_UPDATE 0
14972 +#define STATUS_REMOVE 1
14973 +
14974 +/**
14975 + * mipv6_ba_rcvd - Update BUL for this Binding Acknowledgement
14976 + * @ifindex: interface BA came from
14977 + * @cnaddr: sender IPv6 address
14978 + * @home_addr: home address
14979 + * @sequence: sequence number
14980 + * @lifetime: lifetime granted by Home Agent in seconds
14981 + * @refresh: recommended resend interval
14982 + * @status: %STATUS_UPDATE (ack) or %STATUS_REMOVE (nack)
14983 + *
14984 + * This function must be called to notify the module of the receipt of
14985 + * a binding acknowledgement so that it can cease retransmitting the
14986 + * option. The caller must have validated the acknowledgement before calling
14987 + * this function. 'status' can be either STATUS_UPDATE in which case the
14988 + * binding acknowledgement is assumed to be valid and the corresponding
14989 + * binding update list entry is updated, or STATUS_REMOVE in which case
14990 + * the corresponding binding update list entry is removed (this can be
14991 + * used upon receiving a negative acknowledgement).
14992 + * Returns 0 if a matching binding update has been sent or non-zero if
14993 + * not.
14994 + */
14995 +static int mipv6_ba_rcvd(int ifindex, struct in6_addr *cnaddr, 
14996 +                        struct in6_addr *home_addr, 
14997 +                        u16 sequence, u32 lifetime, 
14998 +                        u32 refresh, int status)
14999 +{
15000 +       struct mipv6_bul_entry *bulentry;
15001 +       unsigned long now = jiffies;
15002 +       struct in6_addr coa;
15003 +
15004 +       DEBUG(DBG_INFO, "BA received with sequence number 0x%x, status: %d",
15005 +             (int) sequence, status);
15006 +
15007 +       /* Find corresponding entry in binding update list. */
15008 +       write_lock(&bul_lock);
15009 +       if ((bulentry = mipv6_bul_get(cnaddr, home_addr)) == NULL) {
15010 +               DEBUG(DBG_INFO, "- discarded, no entry in bul matches BA source address");
15011 +               write_unlock(&bul_lock);
15012 +               return -1;
15013 +       }
15014 +       
15015 +       ipv6_addr_copy(&coa, &bulentry->coa); 
15016 +       if (status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
15017 +               __u32 lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr, 
15018 +                                                        &bulentry->coa, 
15019 +                                                        bulentry->flags);
15020 +               bulentry->seq = sequence;
15021 +
15022 +               mipv6_send_bu(&bulentry->home_addr, &bulentry->cn_addr, 
15023 +                             &bulentry->coa, INITIAL_BINDACK_TIMEOUT,
15024 +                             MAX_BINDACK_TIMEOUT, 1, bulentry->flags,
15025 +                             lifetime, NULL);
15026 +               write_unlock(&bul_lock);
15027 +               return 0;
15028 +       } else if (status >= REASON_UNSPECIFIED) {
15029 +               int err;
15030 +               int at_home = MN_NOT_AT_HOME;
15031 +               DEBUG(DBG_WARNING, "- NACK - BA status:  %d, deleting bul entry", status);
15032 +               if (bulentry->flags & MIPV6_BU_F_HOME) {
15033 +                       struct mn_info *minfo;
15034 +                       read_lock(&mn_info_lock);
15035 +                       minfo = mipv6_mninfo_get_by_home(home_addr);
15036 +                       if (minfo) {
15037 +                               spin_lock(&minfo->lock);
15038 +                               if (minfo->is_at_home != MN_NOT_AT_HOME)
15039 +                                       minfo->is_at_home = MN_AT_HOME;
15040 +                               at_home = minfo->is_at_home;
15041 +                               minfo->has_home_reg = 0;
15042 +                               spin_unlock(&minfo->lock);
15043 +                       }
15044 +                       read_unlock(&mn_info_lock);
15045 +                       DEBUG(DBG_ERROR, "Home registration failed: BA status:  %d, deleting bul entry", status);
15046 +               }
15047 +               write_unlock(&bul_lock);
15048 +               err = mipv6_bul_delete(cnaddr, home_addr);
15049 +               if (at_home == MN_AT_HOME) {
15050 +                       mipv6_mn_send_home_na(home_addr);
15051 +                       write_lock_bh(&bul_lock);
15052 +                       mipv6_bul_iterate(mn_cn_handoff, &coa);
15053 +                       write_unlock_bh(&bul_lock);
15054 +               }
15055 +               return err;
15056 +       }
15057 +       bulentry->state = ACK_OK;
15058 +
15059 +       if (bulentry->flags & MIPV6_BU_F_HOME && lifetime > 0) {
15060 +               /* For home registrations: schedule a refresh binding update.
15061 +                * Use the refresh interval given by home agent or 80%
15062 +                * of lifetime, whichever is less.
15063 +                *
15064 +                * Adjust binding lifetime if 'granted' lifetime
15065 +                * (lifetime value in received binding acknowledgement)
15066 +                * is shorter than 'requested' lifetime (lifetime
15067 +                * value sent in corresponding binding update).
15068 +                * max((L_remain - (L_update - L_ack)), 0)
15069 +                */
15070 +               if (lifetime * HZ < (bulentry->expire - bulentry->lastsend)) {
15071 +                       bulentry->expire = 
15072 +                               max_t(__u32, bulentry->expire - 
15073 +                                     ((bulentry->expire - bulentry->lastsend) - 
15074 +                                      lifetime * HZ), jiffies + 
15075 +                                     ERROR_DEF_LIFETIME * HZ);
15076 +               }
15077 +               if (refresh > lifetime || refresh == 0)
15078 +                       refresh = 4 * lifetime / 5;
15079 +                       DEBUG(DBG_INFO, "setting callback for expiration of"
15080 +                             " a Home Registration: lifetime:%d, refresh:%d",
15081 +                             lifetime, refresh);
15082 +               bulentry->callback = bul_refresh;
15083 +               bulentry->callback_time = now + refresh * HZ;
15084 +               bulentry->expire = now + lifetime * HZ;
15085 +               bulentry->lifetime = lifetime;
15086 +               if (time_after_eq(jiffies, bulentry->expire)) {
15087 +                       /* Sanity check */
15088 +                       DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs",
15089 +                             ERROR_DEF_LIFETIME);
15090 +                       bulentry->expire = jiffies + ERROR_DEF_LIFETIME * HZ;
15091 +               }
15092 +               mipv6_mn_set_home_reg(home_addr, 1);
15093 +               mipv6_bul_iterate(mn_cn_handoff, &coa);
15094 +       } else if ((bulentry->flags & MIPV6_BU_F_HOME) && bulentry->lifetime == 0) {
15095 +               write_unlock(&bul_lock);
15096 +               DEBUG(DBG_INFO, "Got BA for deregistration BU");
15097 +               mipv6_mn_set_home_reg(home_addr, 0);
15098 +               mipv6_bul_delete(cnaddr, home_addr);
15099 +               mipv6_mn_send_home_na(home_addr);
15100 +
15101 +               write_lock_bh(&bul_lock);
15102 +               mipv6_bul_iterate(mn_cn_handoff, &coa);
15103 +               write_unlock_bh(&bul_lock);
15104 +               return 0;
15105 +       }
15106 +
15107 +       mipv6_bul_reschedule(bulentry);
15108 +       write_unlock(&bul_lock);
15109 +
15110 +       return 0;
15111 +}
15112 +
15113 +static int mipv6_handle_mh_HC_test(struct sk_buff *skb,
15114 +                                  struct in6_addr *saddr,
15115 +                                  struct in6_addr *fcoa,
15116 +                                  struct in6_addr *cn,
15117 +                                  struct in6_addr *lcoa,
15118 +                                  struct mipv6_mh *mh)
15119 +{
15120 +       int ret = 0;
15121 +       int msg_len = (mh->length+1) << 3;
15122 +       int opt_len;
15123 +
15124 +       struct mipv6_mh_addr_test *tm = (struct mipv6_mh_addr_test *)mh->data;
15125 +       struct mipv6_bul_entry *bulentry;
15126 +
15127 +       DEBUG_FUNC();
15128 +
15129 +       if (msg_len > skb->len)
15130 +               return -1;
15131 +
15132 +       opt_len = msg_len - sizeof(*mh) - sizeof(*tm);
15133 +
15134 +       if (opt_len < 0) {
15135 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15136 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15137 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15138 +
15139 +               DEBUG(DBG_INFO, "Mobility Header length less than H/C Test");
15140 +               return -1;
15141 +       }
15142 +       if (fcoa || lcoa) {
15143 +               DEBUG(DBG_INFO, "H/C Test has HAO or RTH2, dropped.");
15144 +               return -1;
15145 +       }
15146 +       write_lock(&bul_lock);
15147 +
15148 +       /* We need to get the home address, since CoT only has the CoA*/
15149 +       if (mh->type == MIPV6_MH_COT) {
15150 +               if ((bulentry = mipv6_bul_get_by_ccookie(cn, tm->init_cookie)) == NULL) {
15151 +                       DEBUG(DBG_ERROR, "has no BUL or RR state for "
15152 +                             "source:%x:%x:%x:%x:%x:%x:%x:%x",
15153 +                             NIPV6ADDR(cn));
15154 +                       write_unlock(&bul_lock);
15155 +                       return -1;
15156 +               }
15157 +       } else { /* HoT has the home address */
15158 +               if (((bulentry = mipv6_bul_get(cn, saddr)) == NULL) || !bulentry->rr) {
15159 +                       DEBUG(DBG_ERROR, "has no BUL or RR state for "
15160 +                             "source:%x:%x:%x:%x:%x:%x:%x:%x "
15161 +                             "dest:%x:%x:%x:%x:%x:%x:%x:%x",
15162 +                             NIPV6ADDR(cn), NIPV6ADDR(saddr));
15163 +                       write_unlock(&bul_lock);
15164 +                       return -1;
15165 +               }
15166 +       }
15167 +
15168 +       switch (mh->type) {
15169 +       case MIPV6_MH_HOT:
15170 +               if ((bulentry->rr->rr_state & RR_WAITH) == 0) {
15171 +                       DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15172 +                       goto out;
15173 +               }
15174 +               /*
15175 +                * Make sure no home cookies have been received yet.
15176 +                * TODO: Check not being put in at this time since subsequent
15177 +                * BU's after this time will have home cookie stored.
15178 +                */
15179 +       
15180 +               /* Check if the cookie received is the right one */
15181 +               if (!mipv6_equal_cookies(tm->init_cookie,
15182 +                                        bulentry->rr->hot_cookie)) {
15183 +                       /* Invalid cookie, might be an old cookie */
15184 +                       DEBUG(DBG_WARNING, "Received HoT cookie does not match stored cookie");
15185 +                       goto out;
15186 +               }
15187 +               DEBUG(DBG_INFO, "Got Care-of Test message");
15188 +               bulentry->rr->rr_state &= ~RR_WAITH;
15189 +               memcpy(bulentry->rr->home_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15190 +               bulentry->rr->home_nonce_index = tm->nonce_index;
15191 +               bulentry->rr->home_time = jiffies;
15192 +               ret = 1;
15193 +               break;
15194 +
15195 +       case MIPV6_MH_COT:
15196 +               if ((bulentry->rr->rr_state & RR_WAITC) == 0) {
15197 +                       DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15198 +                       goto out;
15199 +               }
15200 +               /*
15201 +                * Make sure no home cookies have been received yet.
15202 +                * TODO: Check not being put in at this time since subsequent
15203 +                * BU's at this time will have careof cookie stored.
15204 +                */
15205 +       
15206 +               /* Check if the cookie received is the right one */
15207 +               if (!mipv6_equal_cookies(tm->init_cookie,
15208 +                                        bulentry->rr->cot_cookie)) {
15209 +                       DEBUG(DBG_INFO, "Received CoT cookie does not match stored cookie");
15210 +                       goto out;
15211 +               }
15212 +               bulentry->rr->rr_state &= ~RR_WAITC;
15213 +               memcpy(bulentry->rr->careof_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15214 +               bulentry->rr->careof_nonce_index = tm->nonce_index;
15215 +               bulentry->rr->careof_time = jiffies;
15216 +               ret = 1;
15217 +               break;
15218 +       default:
15219 +               /* Impossible to get here */
15220 +               break;
15221 +       }
15222 +out:
15223 +       if (bulentry->rr->rr_state == RR_DONE) {
15224 +               if (bulentry->rr->kbu) /* First free any old keys */
15225 +                       kfree(bulentry->rr->kbu);
15226 +               /* Store the session key to be used in BU's */
15227 +               if (ipv6_addr_cmp(&bulentry->coa, &bulentry->home_addr) && bulentry->lifetime)
15228 +                       bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15229 +                                                             bulentry->rr->careof_cookie);
15230 +               else 
15231 +                       bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15232 +                                                             NULL);
15233 +               /* RR procedure is over, send a BU */
15234 +               mipv6_send_RR_bu(bulentry);
15235 +       }
15236 +       write_unlock(&bul_lock);
15237 +       return ret;
15238 +}
15239 +
15240 +/**
15241 + * mipv6_handle_mh_brr - Binding Refresh Request handler
15242 + * @home: home address
15243 + * @coa: care-of address
15244 + * @cn: source of this packet
15245 + * @mh: pointer to the beginning of the Mobility Header
15246 + *
15247 + * Handles Binding Refresh Request.  Packet and offset to option are
15248 + * passed.  Returns 0 on success, otherwise negative.
15249 + **/
15250 +static int mipv6_handle_mh_brr(struct sk_buff *skb,
15251 +                              struct in6_addr *home,
15252 +                              struct in6_addr *unused1,
15253 +                              struct in6_addr *cn,
15254 +                              struct in6_addr *unused2,
15255 +                              struct mipv6_mh *mh)
15256 +{
15257 +       struct mipv6_mh_brr *brr = (struct mipv6_mh_brr *)mh->data;
15258 +       struct mipv6_bul_entry *binding;
15259 +       int msg_len = (mh->length+1) << 3;
15260 +       int opt_len;
15261 +
15262 +       if (msg_len > skb->len)
15263 +               return -1;
15264 +
15265 +       opt_len = msg_len - sizeof(*mh) - sizeof(*brr);
15266 +
15267 +       if (opt_len < 0) {
15268 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15269 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15270 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15271 +
15272 +               DEBUG(DBG_WARNING, "Mobility Header length less than BRR");
15273 +               MIPV6_INC_STATS(n_brr_drop.invalid);
15274 +               return -1;
15275 +       }
15276 +
15277 +       /* check we know src, else drop */
15278 +       write_lock(&bul_lock);
15279 +       if ((binding = mipv6_bul_get(cn, home)) == NULL) {
15280 +               MIPV6_INC_STATS(n_brr_drop.misc);
15281 +               write_unlock(&bul_lock);
15282 +               return MH_UNKNOWN_CN;
15283 +       }
15284 +
15285 +       MIPV6_INC_STATS(n_brr_rcvd);
15286 +
15287 +       if (opt_len > 0) {
15288 +               struct mobopt opts;
15289 +               memset(&opts, 0, sizeof(opts));
15290 +               if (parse_mo_tlv(brr + 1, opt_len, &opts) < 0) {
15291 +                       write_unlock(&bul_lock);
15292 +                       return -1;
15293 +               }
15294 +               /*
15295 +                * MIPV6_OPT_AUTH_DATA
15296 +                */
15297 +       }
15298 +
15299 +       /* must hold bul_lock (write) */
15300 +       mipv6_RR_start(home, cn, &binding->coa, binding, binding->delay, 
15301 +                      binding->maxdelay, binding->flags,
15302 +                      binding->lifetime, binding->ops);
15303 +
15304 +       write_unlock(&bul_lock);
15305 +       /* MAY also decide to delete binding and send zero lifetime BU
15306 +           with alt-coa set to home address */
15307 +
15308 +       return 0;
15309 +}
15310 +
15311 +/**
15312 + * mipv6_handle_mh_ba - Binding Acknowledgement handler
15313 + * @src: source of this packet
15314 + * @coa: care-of address
15315 + * @home: home address
15316 + * @mh: pointer to the beginning of the Mobility Header
15317 + *
15318 + **/
15319 +static int mipv6_handle_mh_ba(struct sk_buff *skb,
15320 +                             struct in6_addr *home,
15321 +                             struct in6_addr *coa,
15322 +                             struct in6_addr *src,
15323 +                             struct in6_addr *unused,
15324 +                             struct mipv6_mh *mh)
15325 +{
15326 +       struct mipv6_mh_ba *ba = (struct mipv6_mh_ba *)mh->data;
15327 +       struct mipv6_bul_entry *binding = NULL;
15328 +       struct mobopt opts;
15329 +       int msg_len = (mh->length+1) << 3;
15330 +       int opt_len;
15331 +
15332 +       int auth = 1, req_auth = 1, refresh = -1, ifindex = 0;
15333 +       u32 lifetime, sequence;
15334 +
15335 +       if (msg_len > skb->len)
15336 +               return -1;
15337 +
15338 +       opt_len = msg_len - sizeof(*mh) - sizeof(*ba);
15339 +
15340 +       if (opt_len < 0) {
15341 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15342 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15343 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15344 +
15345 +               DEBUG(DBG_WARNING, "Mobility Header length less than BA");
15346 +               MIPV6_INC_STATS(n_ba_drop.invalid);
15347 +               return -1;
15348 +       }
15349 +
15350 +       lifetime = ntohs(ba->lifetime) << 2;
15351 +       sequence = ntohs(ba->sequence);
15352 +
15353 +       if (opt_len > 0) {
15354 +               memset(&opts, 0, sizeof(opts));
15355 +               if (parse_mo_tlv(ba + 1, opt_len, &opts) < 0)
15356 +                       return -1;
15357 +               /*
15358 +                * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_BR_ADVICE
15359 +                */
15360 +               if (opts.br_advice)
15361 +                       refresh = ntohs(opts.br_advice->refresh_interval);
15362 +       }
15363 +
15364 +       if (ba->status >= EXPIRED_HOME_NONCE_INDEX && 
15365 +           ba->status <= EXPIRED_NONCES) 
15366 +               req_auth = 0;
15367 +       
15368 +       write_lock(&bul_lock);
15369 +       binding = mipv6_bul_get(src, home);
15370 +       if (!binding) {
15371 +               DEBUG(DBG_INFO, "No binding, BA dropped.");
15372 +               write_unlock(&bul_lock);
15373 +               return -1;
15374 +       }
15375 +
15376 +       if (opts.auth_data && binding->rr && 
15377 +           (mipv6_auth_check(src, coa, (__u8 *)mh, msg_len, 
15378 +                             opts.auth_data, binding->rr->kbu) == 0))
15379 +               auth = 1;
15380 +
15381 +       if (req_auth && binding->rr && !auth) {
15382 +               DEBUG(DBG_INFO, "BA Authentication failed.");
15383 +               MIPV6_INC_STATS(n_ba_drop.auth);
15384 +               write_unlock(&bul_lock);
15385 +               return MH_AUTH_FAILED;
15386 +       }
15387 +
15388 +       if (ba->status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
15389 +               DEBUG(DBG_INFO,
15390 +                     "Sequence number out of window, setting seq to %d",
15391 +                     sequence);
15392 +       } else if (binding->seq != sequence) {
15393 +               DEBUG(DBG_INFO, "BU/BA Sequence Number mismatch %d != %d",
15394 +                     binding->seq, sequence);
15395 +               MIPV6_INC_STATS(n_ba_drop.invalid);
15396 +               write_unlock(&bul_lock);
15397 +               return MH_SEQUENCE_MISMATCH;
15398 +       }
15399 +       if (ba->status == EXPIRED_HOME_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15400 +               if (binding->rr) {
15401 +                       /* Need to resend home test init to CN */
15402 +                       binding->rr->rr_state |= RR_WAITH;
15403 +                       mipv6_send_addr_test_init(&binding->home_addr, 
15404 +                                                 &binding->cn_addr, 
15405 +                                                 MIPV6_MH_HOTI,
15406 +                                                 binding->rr->hot_cookie);
15407 +                       MIPV6_INC_STATS(n_ban_rcvd);
15408 +               } else {
15409 +                       DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_NONCE_INDEX"
15410 +                             "for non-RR BU");
15411 +                       MIPV6_INC_STATS(n_ba_drop.invalid);
15412 +               }
15413 +               write_unlock(&bul_lock);
15414 +               return 0;
15415 +       } 
15416 +       if (ba->status == EXPIRED_CAREOF_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15417 +               if (binding->rr) { 
15418 +                       /* Need to resend care-of test init to CN */
15419 +                       binding->rr->rr_state |= RR_WAITC;
15420 +                       mipv6_send_addr_test_init(&binding->coa, 
15421 +                                                 &binding->cn_addr, 
15422 +                                                 MIPV6_MH_COTI,
15423 +                                                 binding->rr->cot_cookie);
15424 +                       MIPV6_INC_STATS(n_ban_rcvd);
15425 +               } else  {
15426 +                       DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_CAREOF_INDEX"
15427 +                             "for non-RR BU");
15428 +                       MIPV6_INC_STATS(n_ba_drop.invalid);
15429 +               }
15430 +               write_unlock(&bul_lock);
15431 +               return 0;
15432 +       }
15433 +       write_unlock(&bul_lock);
15434 +       
15435 +       if (ba->status >= REASON_UNSPECIFIED) {
15436 +               DEBUG(DBG_INFO, "Binding Ack status : %d indicates error", ba->status);
15437 +               mipv6_ba_rcvd(ifindex, src, home, sequence, lifetime,
15438 +                             refresh, ba->status);
15439 +               MIPV6_INC_STATS(n_ban_rcvd);
15440 +               return 0;
15441 +       }
15442 +       MIPV6_INC_STATS(n_ba_rcvd);
15443 +       if (mipv6_ba_rcvd(ifindex, src, home, ntohs(ba->sequence), lifetime,
15444 +                         refresh, ba->status)) {
15445 +               DEBUG(DBG_WARNING, "mipv6_ba_rcvd failed");
15446 +       }
15447 +       
15448 +       return 0;
15449 +}
15450 +
15451 +/**
15452 + * mipv6_handle_mh_be - Binding Error handler
15453 + * @cn: source of this packet
15454 + * @coa: care-of address
15455 + * @home: home address
15456 + * @mh: pointer to the beginning of the Mobility Header
15457 + *
15458 + **/
15459 +
15460 +static int mipv6_handle_mh_be(struct sk_buff *skb,
15461 +                             struct in6_addr *home,
15462 +                             struct in6_addr *coa,
15463 +                             struct in6_addr *cn,
15464 +                             struct in6_addr *unused,
15465 +                             struct mipv6_mh *mh)
15466 +{
15467 +       struct mipv6_mh_be *be = (struct mipv6_mh_be *)mh->data;
15468 +       int msg_len = (mh->length+1) << 3;
15469 +       int opt_len;
15470 +       struct in6_addr *hoa;
15471 +       struct bul_inval_args args;
15472 +
15473 +       DEBUG_FUNC();
15474 +
15475 +       if (msg_len > skb->len)
15476 +               return -1;
15477 +
15478 +       opt_len = msg_len - sizeof(*mh) - sizeof(*be);
15479 +
15480 +       if (opt_len < 0) {
15481 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15482 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15483 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15484 +
15485 +               DEBUG(DBG_WARNING, "Mobility Header length less than BE");
15486 +               MIPV6_INC_STATS(n_be_drop.invalid);
15487 +               return -1;
15488 +       }
15489 +
15490 +       
15491 +       if (!ipv6_addr_any(&be->home_addr))
15492 +               hoa = &be->home_addr;
15493 +       else
15494 +               hoa = home;
15495 +
15496 +       MIPV6_INC_STATS(n_be_rcvd);
15497 +
15498 +       args.all_rr_states = 0;
15499 +       args.cn = cn;
15500 +       args.mn = hoa;
15501 +
15502 +       switch (be->status) {
15503 +       case 1: /* Home Address Option used without a binding */
15504 +               /* Get ULP information about CN-MN communication.  If
15505 +                   nothing in progress, MUST delete.  Otherwise MAY
15506 +                   ignore. */
15507 +               args.all_rr_states = 1;
15508 +       case 2: /* Received unknown MH type */
15509 +               /* If not expecting ack, SHOULD ignore.  If MH
15510 +                   extension in use, stop it.  If not, stop RO for
15511 +                   this CN. */
15512 +               write_lock(&bul_lock);
15513 +               mipv6_bul_iterate(mn_bul_invalidate, &args);
15514 +               write_unlock(&bul_lock);
15515 +               break;
15516 +       }
15517 +
15518 +       return 0;
15519 +}
15520 +
15521 +/*
15522 + * mipv6_bu_rate_limit() : Takes a bulentry, a COA and 'flags' to check
15523 + * whether BU being sent is for Home Registration or not.
15524 + *
15525 + * If the number of BU's sent is fewer than MAX_FAST_UPDATES, this BU
15526 + * is allowed to be sent at the MAX_UPDATE_RATE.
15527 + * If the number of BU's sent is greater than or equal to MAX_FAST_UPDATES,
15528 + * this BU is allowed to be sent at the SLOW_UPDATE_RATE.
15529 + *
15530 + * Assumption : This function is not re-entrant. and the caller holds the
15531 + * bulentry lock (by calling mipv6_bul_get()) to stop races with other
15532 + * CPU's executing this same function.
15533 + *
15534 + * Side-Effects. Either of the following could  on success :
15535 + *     1. Sets consecutive_sends to 1 if the entry is a Home agent
15536 + *        registration or the COA has changed.
15537 + *     2. Increments consecutive_sends if the number of BU's sent so
15538 + *        far is less than MAX_FAST_UPDATES, and this BU is being sent
15539 + *        atleast MAX_UPDATE_RATE after previous one.
15540 + * 
15541 + * Return Value : 0 on Success, -1 on Failure
15542 + */
15543 +static int mipv6_bu_rate_limit(struct mipv6_bul_entry *bulentry, 
15544 +                              struct in6_addr *coa, __u8 flags)
15545 +{
15546 +       if ((flags & MIPV6_BU_F_HOME) || ipv6_addr_cmp(&bulentry->coa, coa)) {
15547 +               /* Home Agent Registration or different COA - restart from 1 */
15548 +               bulentry->consecutive_sends = 1;
15549 +               return 0;
15550 +       }
15551 +
15552 +       if (bulentry->consecutive_sends < MAX_FAST_UPDATES) {
15553 +               /* First MAX_FAST_UPDATES can be sent at MAX_UPDATE_RATE */
15554 +               if (jiffies - bulentry->lastsend < MAX_UPDATE_RATE * HZ) {
15555 +                       return -1;
15556 +               }
15557 +               bulentry->consecutive_sends ++;
15558 +       } else {
15559 +               /* Remaining updates SHOULD be sent at SLOW_UPDATE_RATE */
15560 +               if (jiffies - bulentry->lastsend < SLOW_UPDATE_RATE * HZ) {
15561 +                       return -1;
15562 +               }
15563 +               /* Don't inc 'consecutive_sends' to avoid overflow to zero */
15564 +       }
15565 +       /* OK to send a BU */
15566 +       return 0;
15567 +}
15568 +
15569 +/**
15570 + * mipv6_send_bu - send a Binding Update 
15571 + * @saddr: source address for BU
15572 + * @daddr: destination address for BU
15573 + * @coa: care-of address for MN
15574 + * @initdelay: initial BA wait timeout
15575 + * @maxackdelay: maximum BA wait timeout
15576 + * @exp: exponention back off
15577 + * @flags: flags for BU
15578 + * @lifetime: granted lifetime for binding
15579 + * @ops: mobility options
15580 + *
15581 + * Send a binding update.  'flags' may contain any of %MIPV6_BU_F_ACK,
15582 + * %MIPV6_BU_F_HOME, %MIPV6_BU_F_ROUTER bitwise ORed.  If
15583 + * %MIPV6_BU_F_ACK is included retransmission will be attempted until
15584 + * the update has been acknowledged.  Retransmission is done if no
15585 + * acknowledgement is received within @initdelay seconds.  @exp
15586 + * specifies whether to use exponential backoff (@exp != 0) or linear
15587 + * backoff (@exp == 0).  For exponential backoff the time to wait for
15588 + * an acknowledgement is doubled on each retransmission until a delay
15589 + * of @maxackdelay, after which retransmission is no longer attempted.
15590 + * For linear backoff the delay is kept constant and @maxackdelay
15591 + * specifies the maximum number of retransmissions instead.  If
15592 + * sub-options are present ops must contain all sub-options to be
15593 + * added.  On a mobile node, use the mobile node's home address for
15594 + * @saddr.  Returns 0 on success, non-zero on failure.
15595 + *
15596 + * Caller may not hold @bul_lock.
15597 + **/
15598 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr,
15599 +                 struct in6_addr *coa, u32 initdelay, 
15600 +                 u32 maxackdelay, u8 exp, u8 flags, u32 lifetime,
15601 +                 struct mipv6_mh_opt *ops)
15602 +{
15603 +       int ret;
15604 +       __u8 state;
15605 +        __u16 seq = 0;
15606 +       int (*callback)(struct mipv6_bul_entry *);
15607 +       __u32 callback_time;
15608 +       struct mipv6_bul_entry *bulentry;
15609 +       
15610 +       /* First a sanity check: don't send BU to local addresses */
15611 +       if(ipv6_chk_addr(daddr, NULL)) {
15612 +               DEBUG(DBG_ERROR, "BUG: Trying to send BU to local address");
15613 +               return -1;
15614 +       }
15615 +       DEBUG(DBG_INFO, "Sending BU to CN  %x:%x:%x:%x:%x:%x:%x:%x "
15616 +             "for home address %x:%x:%x:%x:%x:%x:%x:%x", 
15617 +             NIPV6ADDR(daddr), NIPV6ADDR(saddr));
15618 +
15619 +       if ((bulentry = mipv6_bul_get(daddr, saddr)) != NULL) {
15620 +               if (bulentry->state == ACK_ERROR) {
15621 +                       /*
15622 +                        * Don't send any more BU's to nodes which don't
15623 +                        * understanding one. 
15624 +                        */
15625 +                       DEBUG(DBG_INFO, "Not sending BU to node which doesn't"
15626 +                             " understand one");
15627 +                       return -1;
15628 +               }
15629 +               if (mipv6_bu_rate_limit(bulentry, coa, flags) < 0) {
15630 +                       DEBUG(DBG_DATADUMP, "Limiting BU sent.");
15631 +                       return 0;
15632 +               }
15633 +       }
15634 +
15635 +       switch (mipv6_rr_state(bulentry, saddr, coa, flags)) {
15636 +       case INPROGRESS_RR:
15637 +               /* We are already doing RR, don't do BU at this time, it is
15638 +                * done automatically later */
15639 +               DEBUG(DBG_INFO, "RR in progress not sending BU");
15640 +               return 0;
15641 +
15642 +       case DO_RR:
15643 +               /* Just do RR and return, BU is done automatically later */
15644 +               DEBUG(DBG_INFO, "starting RR" );
15645 +               mipv6_RR_start(saddr, daddr, coa, bulentry, initdelay,
15646 +                              maxackdelay, flags, lifetime, ops);
15647 +               return 0;
15648 +               
15649 +       case NO_RR:
15650 +               DEBUG(DBG_DATADUMP, "No RR necessary" );
15651 +       default:
15652 +               break;
15653 +       }
15654 +
15655 +       if (bulentry)
15656 +               seq = bulentry->seq + 1;
15657 +       
15658 +       /* Add to binding update list */
15659 +       
15660 +       if (flags & MIPV6_BU_F_ACK) {
15661 +               DEBUG(DBG_INFO, "Setting bul callback to bul_resend_exp");
15662 +               /* Send using exponential backoff */
15663 +               state = RESEND_EXP;
15664 +               callback = bul_resend_exp;
15665 +               callback_time = initdelay;
15666 +       } else {
15667 +               DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
15668 +               /* No acknowledgement/resending required */
15669 +               state = ACK_OK; /* pretend we got an ack */
15670 +               callback = bul_entry_expired;
15671 +               callback_time = lifetime;
15672 +       }
15673 +
15674 +       /* BU only for the home address */
15675 +       /* We must hold bul_lock (write) while calling add */
15676 +       if ((bulentry = mipv6_bul_add(daddr, saddr, coa, lifetime, seq,
15677 +                                     flags, callback, callback_time, 
15678 +                                     state, initdelay, maxackdelay, ops, 
15679 +                                     NULL)) == NULL) {
15680 +               DEBUG(DBG_INFO, "couldn't update BUL");
15681 +               return 0;
15682 +       }
15683 +       ret = send_bu_msg(bulentry);
15684 +
15685 +       return ret;
15686 +}
15687 +
15688 +int __init mipv6_mh_mn_init(void)
15689 +{
15690 +       mipv6_mh_register(MIPV6_MH_HOT, mipv6_handle_mh_HC_test);
15691 +       mipv6_mh_register(MIPV6_MH_COT, mipv6_handle_mh_HC_test);
15692 +       mipv6_mh_register(MIPV6_MH_BA, mipv6_handle_mh_ba);
15693 +       mipv6_mh_register(MIPV6_MH_BRR, mipv6_handle_mh_brr);
15694 +       mipv6_mh_register(MIPV6_MH_BE, mipv6_handle_mh_be);
15695 +
15696 +       return 0;
15697 +}
15698 +
15699 +void __exit mipv6_mh_mn_exit(void)
15700 +{
15701 +       mipv6_mh_unregister(MIPV6_MH_HOT);
15702 +       mipv6_mh_unregister(MIPV6_MH_COT);
15703 +       mipv6_mh_unregister(MIPV6_MH_BA);
15704 +       mipv6_mh_unregister(MIPV6_MH_BRR);
15705 +       mipv6_mh_unregister(MIPV6_MH_BE);
15706 +}
15707 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/module_cn.c linux-2.4.25/net/ipv6/mobile_ip6/module_cn.c
15708 --- linux-2.4.25.old/net/ipv6/mobile_ip6/module_cn.c    1970-01-01 01:00:00.000000000 +0100
15709 +++ linux-2.4.25/net/ipv6/mobile_ip6/module_cn.c        2004-06-26 11:29:31.000000000 +0100
15710 @@ -0,0 +1,167 @@
15711 +/*
15712 + *     Mobile IPv6 Common Module
15713 + *
15714 + *     Authors:
15715 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
15716 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
15717 + *
15718 + *     $Id$
15719 + *
15720 + *     This program is free software; you can redistribute it and/or
15721 + *     modify it under the terms of the GNU General Public License
15722 + *     as published by the Free Software Foundation; either version
15723 + *     2 of the License, or (at your option) any later version.
15724 + */
15725 +
15726 +#include <linux/config.h>
15727 +#include <linux/module.h>
15728 +#include <linux/init.h>
15729 +
15730 +#ifdef CONFIG_SYSCTL
15731 +#include <linux/sysctl.h>
15732 +#endif /* CONFIG_SYSCTL */
15733 +
15734 +#include <net/mipglue.h>
15735 +
15736 +#include "bcache.h"
15737 +#include "mipv6_icmp.h"
15738 +#include "stats.h"
15739 +#include "mobhdr.h"
15740 +#include "exthdrs.h"
15741 +
15742 +int mipv6_debug = 1;
15743 +
15744 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15745 +MODULE_AUTHOR("MIPL Team");
15746 +MODULE_DESCRIPTION("Mobile IPv6");
15747 +MODULE_LICENSE("GPL");
15748 +MODULE_PARM(mipv6_debug, "i");
15749 +#endif
15750 +
15751 +#include "config.h"
15752 +
15753 +struct mip6_func mip6_fn;
15754 +struct mip6_conf mip6node_cnf = {
15755 +       capabilities:           CAP_CN,
15756 +       accept_ret_rout:        1,
15757 +       max_rtr_reachable_time: 0,
15758 +       eager_cell_switching:   0,
15759 +       max_num_tunnels:        0,
15760 +       min_num_tunnels:        0,
15761 +       binding_refresh_advice: 0,
15762 +       bu_lladdr:              0,
15763 +       bu_keymgm:              0,
15764 +       bu_cn_ack:              0
15765 +};
15766 +
15767 +#define MIPV6_BCACHE_SIZE 128
15768 +
15769 +/**********************************************************************
15770 + *
15771 + * MIPv6 CN Module Init / Cleanup
15772 + *
15773 + **********************************************************************/
15774 +
15775 +#ifdef CONFIG_SYSCTL
15776 +/* Sysctl table */
15777 +ctl_table mipv6_mobility_table[] = {
15778 +       {NET_IPV6_MOBILITY_DEBUG, "debuglevel",
15779 +        &mipv6_debug, sizeof(int), 0644, NULL,
15780 +        &proc_dointvec},
15781 +       {NET_IPV6_MOBILITY_RETROUT, "accept_return_routability",
15782 +        &mip6node_cnf.accept_ret_rout, sizeof(int), 0644, NULL,
15783 +        &proc_dointvec},
15784 +       {0}
15785 +};
15786 +ctl_table mipv6_table[] = {
15787 +       {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
15788 +       {0}
15789 +};
15790 +
15791 +static struct ctl_table_header *mipv6_sysctl_header;
15792 +static struct ctl_table mipv6_net_table[];
15793 +static struct ctl_table mipv6_root_table[];
15794 +
15795 +ctl_table mipv6_net_table[] = {
15796 +       {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
15797 +       {0}
15798 +};
15799 +
15800 +ctl_table mipv6_root_table[] = {
15801 +       {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
15802 +       {0}
15803 +};
15804 +#endif /* CONFIG_SYSCTL */
15805 +
15806 +extern void mipv6_rr_init(void);
15807 +
15808 +/*  Initialize the module  */
15809 +static int __init mip6_init(void)
15810 +{
15811 +       int err = 0;
15812 +
15813 +       printk(KERN_INFO "MIPL Mobile IPv6 for Linux Correspondent Node %s (%s)\n",
15814 +              MIPLVERSION, MIPV6VERSION);
15815 +
15816 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
15817 +       printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
15818 +#endif
15819 +
15820 +       if ((err = mipv6_bcache_init(MIPV6_BCACHE_SIZE)) < 0)
15821 +               goto bcache_fail;
15822 +
15823 +       if ((err = mipv6_icmpv6_init()) < 0)
15824 +               goto icmp_fail;
15825 +
15826 +       if ((err = mipv6_stats_init()) < 0)
15827 +               goto stats_fail;
15828 +       mipv6_rr_init();
15829 +
15830 +#ifdef CONFIG_SYSCTL
15831 +       mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
15832 +#endif
15833 +
15834 +       if ((err = mipv6_mh_common_init()) < 0)
15835 +               goto mh_fail;
15836 +
15837 +       MIPV6_SETCALL(mipv6_modify_txoptions, mipv6_modify_txoptions);
15838 +               
15839 +       MIPV6_SETCALL(mipv6_handle_homeaddr, mipv6_handle_homeaddr);
15840 +       MIPV6_SETCALL(mipv6_icmp_swap_addrs, mipv6_icmp_swap_addrs);
15841 +
15842 +       return 0;
15843 +
15844 +mh_fail:
15845 +#ifdef CONFIG_SYSCTL
15846 +       unregister_sysctl_table(mipv6_sysctl_header);
15847 +#endif
15848 +       mipv6_stats_exit();
15849 +stats_fail:
15850 +       mipv6_icmpv6_exit();
15851 +icmp_fail:
15852 +       mipv6_bcache_exit();
15853 +bcache_fail:
15854 +       return err;
15855 +}
15856 +module_init(mip6_init);
15857 +
15858 +#ifdef MODULE
15859 +/*  Cleanup module  */
15860 +static void __exit mip6_exit(void)
15861 +{
15862 +       printk(KERN_INFO "mip6_base.o exiting.\n");
15863 +#ifdef CONFIG_SYSCTL
15864 +       unregister_sysctl_table(mipv6_sysctl_header);
15865 +#endif
15866 +
15867 +       /* Invalidate all custom kernel hooks.  No need to do this
15868 +           separately for all hooks. */
15869 +       mipv6_invalidate_calls();
15870 +
15871 +       mipv6_mh_common_exit();
15872 +       mipv6_stats_exit();
15873 +       mipv6_icmpv6_exit();
15874 +       mipv6_bcache_exit();
15875 +}
15876 +module_exit(mip6_exit);
15877 +#endif /* MODULE */
15878 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/module_ha.c linux-2.4.25/net/ipv6/mobile_ip6/module_ha.c
15879 --- linux-2.4.25.old/net/ipv6/mobile_ip6/module_ha.c    1970-01-01 01:00:00.000000000 +0100
15880 +++ linux-2.4.25/net/ipv6/mobile_ip6/module_ha.c        2004-06-26 11:29:31.000000000 +0100
15881 @@ -0,0 +1,264 @@
15882 +/*
15883 + *     Mobile IPv6 Home Agent Module
15884 + *
15885 + *     Authors:
15886 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
15887 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
15888 + *
15889 + *     $Id$
15890 + *
15891 + *     This program is free software; you can redistribute it and/or
15892 + *     modify it under the terms of the GNU General Public License
15893 + *     as published by the Free Software Foundation; either version
15894 + *     2 of the License, or (at your option) any later version.
15895 + */
15896 +
15897 +#include <linux/config.h>
15898 +#include <linux/module.h>
15899 +#include <linux/init.h>
15900 +
15901 +#ifdef CONFIG_SYSCTL
15902 +#include <linux/sysctl.h>
15903 +#endif /* CONFIG_SYSCTL */
15904 +
15905 +#include <net/mipglue.h>
15906 +#include <net/addrconf.h>
15907 +
15908 +#include "mobhdr.h"
15909 +#include "tunnel_ha.h"
15910 +#include "ha.h"
15911 +#include "halist.h"
15912 +#include "mipv6_icmp.h"
15913 +//#include "prefix.h"
15914 +#include "bcache.h"
15915 +#include "debug.h"
15916 +
15917 +int mipv6_use_auth = 0;
15918 +
15919 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15920 +MODULE_AUTHOR("MIPL Team");
15921 +MODULE_DESCRIPTION("Mobile IPv6 Home Agent");
15922 +MODULE_LICENSE("GPL");
15923 +#endif
15924 +
15925 +#include "config.h"
15926 +
15927 +#define MIPV6_HALIST_SIZE 128
15928 +struct ha_info_opt {
15929 +       u8 type;
15930 +       u8 len;
15931 +       u16 res;
15932 +       u16 pref;
15933 +       u16 ltime;
15934 +};
15935 +/*
15936 + * Called from ndisc.c's router_discovery.
15937 + */
15938 +static int mipv6_ha_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
15939 +{
15940 +       unsigned int ha_info_pref = 0, ha_info_lifetime;
15941 +       int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
15942 +       struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
15943 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
15944 +       struct in6_addr ll_addr;
15945 +       struct hal {
15946 +               struct in6_addr prefix;
15947 +               int plen;
15948 +               struct hal *next;
15949 +       };
15950 +       
15951 +       DEBUG_FUNC();
15952 +
15953 +       ha_info_lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
15954 +       ipv6_addr_copy(&ll_addr, saddr);
15955 +       
15956 +       if (ndopts->nd_opts_hai) {
15957 +               struct ha_info_opt *hai = (struct ha_info_opt *)ndopts->nd_opts_hai;
15958 +               ha_info_pref = ntohs(hai->pref);
15959 +               ha_info_lifetime = ntohs(hai->ltime);
15960 +               DEBUG(DBG_DATADUMP,
15961 +                     "received home agent info with preference : %d and lifetime : %d",
15962 +                     ha_info_pref, ha_info_lifetime);
15963 +       }
15964 +       if (ndopts->nd_opts_pi) {
15965 +               struct nd_opt_hdr *p;
15966 +               for (p = ndopts->nd_opts_pi;
15967 +                    p;
15968 +                    p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
15969 +                       struct prefix_info *pinfo;
15970 +                       
15971 +                       pinfo = (struct prefix_info *) p;
15972 +                       
15973 +                       if (pinfo->router_address) {
15974 +                               DEBUG(DBG_DATADUMP, "Adding router address to "
15975 +                                     "ha queue \n");
15976 +                               /* If RA has H bit set and Prefix Info
15977 +                                * Option R bit set, queue this
15978 +                                * address to be added to Home Agents
15979 +                                * List.  
15980 +                                */
15981 +                               if (ipv6_addr_type(&pinfo->prefix) &
15982 +                                   IPV6_ADDR_LINKLOCAL)
15983 +                                       continue;
15984 +                               if (!ra->icmph.icmp6_home_agent || !ha_info_lifetime) {
15985 +                                       mipv6_halist_delete(&pinfo->prefix); 
15986 +                                       continue;
15987 +                               } else {
15988 +                                       
15989 +                                       mipv6_halist_add(ifi, &pinfo->prefix, 
15990 +                                                        pinfo->prefix_len, &ll_addr, 
15991 +                                                        ha_info_pref, ha_info_lifetime);
15992 +                               } 
15993 +                               
15994 +                       }
15995 +                       
15996 +               }
15997 +       }
15998 +       return MIPV6_ADD_RTR;
15999 +}
16000 +
16001 +/**********************************************************************
16002 + *
16003 + * MIPv6 Module Init / Cleanup
16004 + *
16005 + **********************************************************************/
16006 +
16007 +#ifdef CONFIG_SYSCTL
16008 +/* Sysctl table */
16009 +extern int 
16010 +mipv6_max_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16011 +
16012 +extern int 
16013 +mipv6_min_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16014 +
16015 +int max_adv = ~(u16)0;
16016 +int min_zero = 0;
16017 +ctl_table mipv6_mobility_table[] = {
16018 +       {NET_IPV6_MOBILITY_BINDING_REFRESH, "binding_refresh_advice",
16019 +        &mip6node_cnf.binding_refresh_advice, sizeof(int), 0644, NULL,
16020 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_adv},
16021 +
16022 +       {NET_IPV6_MOBILITY_MAX_TNLS, "max_tnls", &mipv6_max_tnls, sizeof(int),
16023 +        0644, NULL, &mipv6_max_tnls_sysctl},
16024 +       {NET_IPV6_MOBILITY_MIN_TNLS, "min_tnls", &mipv6_min_tnls, sizeof(int),
16025 +        0644, NULL, &mipv6_min_tnls_sysctl},
16026 +       {0}
16027 +};
16028 +ctl_table mipv6_table[] = {
16029 +       {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
16030 +       {0}
16031 +};
16032 +
16033 +static struct ctl_table_header *mipv6_sysctl_header;
16034 +static struct ctl_table mipv6_net_table[];
16035 +static struct ctl_table mipv6_root_table[];
16036 +
16037 +ctl_table mipv6_net_table[] = {
16038 +       {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
16039 +       {0}
16040 +};
16041 +
16042 +ctl_table mipv6_root_table[] = {
16043 +       {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
16044 +       {0}
16045 +};
16046 +#endif /* CONFIG_SYSCTL */
16047 +
16048 +extern void mipv6_check_dad(struct in6_addr *haddr);
16049 +extern void mipv6_dad_init(void);
16050 +extern void mipv6_dad_exit(void);
16051 +extern int mipv6_forward(struct sk_buff *);
16052 +
16053 +/*  Initialize the module  */
16054 +static int __init mip6_ha_init(void)
16055 +{
16056 +       int err = 0;
16057 +
16058 +       printk(KERN_INFO "MIPL Mobile IPv6 for Linux Home Agent %s (%s)\n",
16059 +              MIPLVERSION, MIPV6VERSION);
16060 +       mip6node_cnf.capabilities = CAP_CN | CAP_HA;
16061 +
16062 +       mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_no_rcv;
16063 +       mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_rcv_dhaad_req;
16064 +       mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
16065 +       mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
16066 +       mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_no_rcv;
16067 +
16068 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
16069 +       printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16070 +#endif
16071 +
16072 +#ifdef CONFIG_SYSCTL
16073 +       mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16074 +#endif
16075 +       mipv6_initialize_tunnel();
16076 +
16077 +       if ((err = mipv6_ha_init()) < 0)
16078 +               goto ha_fail;
16079 +
16080 +       MIPV6_SETCALL(mipv6_ra_rcv, mipv6_ha_ra_rcv);
16081 +       MIPV6_SETCALL(mipv6_forward, mipv6_forward);
16082 +       mipv6_dad_init();
16083 +       MIPV6_SETCALL(mipv6_check_dad, mipv6_check_dad);
16084 +
16085 +       if ((err = mipv6_halist_init(MIPV6_HALIST_SIZE)) < 0)
16086 +               goto halist_fail;
16087 +
16088 +//     mipv6_initialize_pfx_icmpv6();
16089 +
16090 +       return 0;
16091 +
16092 +halist_fail:
16093 +       mipv6_dad_exit();
16094 +       mipv6_ha_exit();
16095 +ha_fail:
16096 +       mipv6_shutdown_tunnel();
16097 +
16098 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16099 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16100 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16101 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16102 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16103 +
16104 +       MIPV6_RESETCALL(mipv6_ra_rcv);
16105 +       MIPV6_RESETCALL(mipv6_forward);
16106 +       MIPV6_RESETCALL(mipv6_check_dad);
16107 +
16108 +#ifdef CONFIG_SYSCTL
16109 +       unregister_sysctl_table(mipv6_sysctl_header);
16110 +#endif
16111 +       return err;
16112 +}
16113 +module_init(mip6_ha_init);
16114 +
16115 +#ifdef MODULE
16116 +/*  Cleanup module  */
16117 +static void __exit mip6_ha_exit(void)
16118 +{
16119 +       printk(KERN_INFO "mip6_ha.o exiting.\n");
16120 +       mip6node_cnf.capabilities &= ~(int)CAP_HA;
16121 +
16122 +       mipv6_bcache_cleanup(HOME_REGISTRATION);
16123 +
16124 +       MIPV6_RESETCALL(mipv6_ra_rcv);
16125 +       MIPV6_RESETCALL(mipv6_forward);
16126 +       MIPV6_RESETCALL(mipv6_check_dad);
16127 +
16128 +       mipv6_halist_exit();
16129 +//     mipv6_shutdown_pfx_icmpv6();
16130 +
16131 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16132 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16133 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16134 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16135 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16136 +
16137 +       mipv6_dad_exit();
16138 +       mipv6_ha_exit();
16139 +       mipv6_shutdown_tunnel();
16140 +#ifdef CONFIG_SYSCTL
16141 +       unregister_sysctl_table(mipv6_sysctl_header);
16142 +#endif
16143 +}
16144 +module_exit(mip6_ha_exit);
16145 +#endif /* MODULE */
16146 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/module_mn.c linux-2.4.25/net/ipv6/mobile_ip6/module_mn.c
16147 --- linux-2.4.25.old/net/ipv6/mobile_ip6/module_mn.c    1970-01-01 01:00:00.000000000 +0100
16148 +++ linux-2.4.25/net/ipv6/mobile_ip6/module_mn.c        2004-06-26 11:29:31.000000000 +0100
16149 @@ -0,0 +1,188 @@
16150 +/*
16151 + *     Mobile IPv6 Mobile Node Module
16152 + *
16153 + *     Authors:
16154 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
16155 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
16156 + *
16157 + *     $Id$
16158 + *
16159 + *     This program is free software; you can redistribute it and/or
16160 + *     modify it under the terms of the GNU General Public License
16161 + *     as published by the Free Software Foundation; either version
16162 + *     2 of the License, or (at your option) any later version.
16163 + */
16164 +
16165 +#include <linux/config.h>
16166 +#include <linux/module.h>
16167 +#include <linux/init.h>
16168 +
16169 +#ifdef CONFIG_SYSCTL
16170 +#include <linux/sysctl.h>
16171 +#endif /* CONFIG_SYSCTL */
16172 +
16173 +#include <net/mipglue.h>
16174 +
16175 +extern int mipv6_debug;
16176 +int mipv6_use_auth = 0;
16177 +
16178 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
16179 +MODULE_AUTHOR("MIPL Team");
16180 +MODULE_DESCRIPTION("Mobile IPv6 Mobile Node");
16181 +MODULE_LICENSE("GPL");
16182 +MODULE_PARM(mipv6_debug, "i");
16183 +#endif
16184 +
16185 +#include "config.h"
16186 +
16187 +#include "mobhdr.h"
16188 +#include "mn.h"
16189 +#include "mipv6_icmp.h"
16190 +//#include "prefix.h"
16191 +
16192 +/* TODO: These will go as soon as we get rid of the last two ioctls */
16193 +extern int mipv6_ioctl_mn_init(void);
16194 +extern void mipv6_ioctl_mn_exit(void);
16195 +
16196 +/**********************************************************************
16197 + *
16198 + * MIPv6 Module Init / Cleanup
16199 + *
16200 + **********************************************************************/
16201 +
16202 +#ifdef CONFIG_SYSCTL
16203 +/* Sysctl table */
16204 +
16205 +extern int max_rtr_reach_time;
16206 +extern int eager_cell_switching;
16207 +
16208 +static int max_reach = 1000;
16209 +static int min_reach = 1;
16210 +static int max_one = 1;
16211 +static int min_zero = 0;
16212 +
16213 +extern int 
16214 +mipv6_mdetect_mech_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16215 +
16216 +extern int 
16217 +mipv6_router_reach_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16218 +
16219 +ctl_table mipv6_mobility_table[] = {
16220 +       {NET_IPV6_MOBILITY_BU_F_LLADDR, "bu_flag_lladdr",
16221 +        &mip6node_cnf.bu_lladdr, sizeof(int), 0644, NULL,
16222 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16223 +       {NET_IPV6_MOBILITY_BU_F_KEYMGM, "bu_flag_keymgm",
16224 +        &mip6node_cnf.bu_keymgm, sizeof(int), 0644, NULL,
16225 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16226 +       {NET_IPV6_MOBILITY_BU_F_CN_ACK, "bu_flag_cn_ack",
16227 +        &mip6node_cnf.bu_cn_ack, sizeof(int), 0644, NULL,
16228 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16229 +
16230 +       {NET_IPV6_MOBILITY_ROUTER_REACH, "max_router_reachable_time",
16231 +        &max_rtr_reach_time, sizeof(int), 0644, NULL,
16232 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_reach, &max_reach},
16233 +
16234 +       {NET_IPV6_MOBILITY_MDETECT_MECHANISM, "eager_cell_switching",
16235 +        &eager_cell_switching, sizeof(int), 0644, NULL,
16236 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16237 +
16238 +       {0}
16239 +};
16240 +ctl_table mipv6_table[] = {
16241 +       {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
16242 +       {0}
16243 +};
16244 +
16245 +static struct ctl_table_header *mipv6_sysctl_header;
16246 +static struct ctl_table mipv6_net_table[];
16247 +static struct ctl_table mipv6_root_table[];
16248 +
16249 +ctl_table mipv6_net_table[] = {
16250 +       {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
16251 +       {0}
16252 +};
16253 +
16254 +ctl_table mipv6_root_table[] = {
16255 +       {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
16256 +       {0}
16257 +};
16258 +#endif /* CONFIG_SYSCTL */
16259 +
16260 +/*  Initialize the module  */
16261 +static int __init mip6_mn_init(void)
16262 +{
16263 +       int err = 0;
16264 +
16265 +       printk(KERN_INFO "MIPL Mobile IPv6 for Linux Mobile Node %s (%s)\n",
16266 +              MIPLVERSION, MIPV6VERSION);
16267 +       mip6node_cnf.capabilities = CAP_CN | CAP_MN;
16268 +
16269 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
16270 +       printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16271 +#endif
16272 +
16273 +#ifdef CONFIG_SYSCTL
16274 +       mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16275 +#endif
16276 +       if ((err = mipv6_mn_init()) < 0)
16277 +               goto mn_fail;
16278 +
16279 +       mipv6_mh_mn_init();
16280 +
16281 +       mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_rcv_dhaad_rep;
16282 +       mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_no_rcv;
16283 +       mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
16284 +       mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
16285 +       mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_rcv_paramprob;
16286 +
16287 +//     mipv6_initialize_pfx_icmpv6();
16288 +
16289 +       if ((err = mipv6_ioctl_mn_init()) < 0)
16290 +               goto ioctl_fail;
16291 +
16292 +       return 0;
16293 +
16294 +ioctl_fail:
16295 +//     mipv6_shutdown_pfx_icmpv6();
16296 +
16297 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16298 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16299 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16300 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16301 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16302 +
16303 +       mipv6_mh_mn_exit();
16304 +       mipv6_mn_exit();
16305 +mn_fail:
16306 +#ifdef CONFIG_SYSCTL
16307 +       unregister_sysctl_table(mipv6_sysctl_header);
16308 +#endif
16309 +       return err;
16310 +}
16311 +module_init(mip6_mn_init);
16312 +
16313 +#ifdef MODULE
16314 +/*  Cleanup module  */
16315 +static void __exit mip6_mn_exit(void)
16316 +{
16317 +       printk(KERN_INFO "mip6_mn.o exiting.\n");
16318 +       mip6node_cnf.capabilities &= ~(int)CAP_MN;
16319 +
16320 +       mipv6_ioctl_mn_exit();
16321 +//     mipv6_shutdown_pfx_icmpv6();
16322 +
16323 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16324 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16325 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16326 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16327 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16328 +
16329 +       mipv6_mn_exit();
16330 +
16331 +/* common cleanup */
16332 +#ifdef CONFIG_SYSCTL
16333 +       unregister_sysctl_table(mipv6_sysctl_header);
16334 +#endif
16335 +}
16336 +module_exit(mip6_mn_exit);
16337 +#endif /* MODULE */
16338 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.c linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.c
16339 --- linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.c      1970-01-01 01:00:00.000000000 +0100
16340 +++ linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.c  2004-06-26 11:29:31.000000000 +0100
16341 @@ -0,0 +1,287 @@
16342 +/*  
16343 + * 2001 (c) Oy L M Ericsson Ab
16344 + *
16345 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16346 + *
16347 + * $Id$
16348 + *
16349 + */
16350 +
16351 +/*
16352 + * Vertical hand-off information manager
16353 + */
16354 +
16355 +#include <linux/netdevice.h>
16356 +#include <linux/in6.h>
16357 +#include <linux/module.h>
16358 +#include <linux/init.h>
16359 +#include <linux/proc_fs.h>
16360 +#include <linux/string.h>
16361 +#include <linux/kernel.h>
16362 +#include <asm/io.h>
16363 +#include <asm/uaccess.h>
16364 +#include <linux/list.h>
16365 +#include "multiaccess_ctl.h"
16366 +#include "debug.h"
16367 +
16368 +/*
16369 + * Local variables
16370 + */
16371 +static LIST_HEAD(if_list);
16372 +
16373 +/* Internal interface information list */
16374 +struct ma_if_info {
16375 +       struct list_head list;
16376 +       int        interface_id;
16377 +       int        preference;
16378 +       __u8       status;
16379 +};
16380 +
16381 +/**
16382 + * ma_ctl_get_preference - get preference value for interface
16383 + * @ifi: interface index
16384 + * 
16385 + * Returns integer value preference for given interface.
16386 + **/
16387 +int ma_ctl_get_preference(int ifi)
16388 +{
16389 +       struct list_head *lh;
16390 +       struct ma_if_info *info;
16391 +       int pref = 0;
16392 +
16393 +       list_for_each(lh, &if_list) {
16394 +               info = list_entry(lh, struct ma_if_info, list);
16395 +               if (info->interface_id == ifi) {
16396 +                       pref = info->preference;
16397 +                       return pref;
16398 +               }
16399 +       }
16400 +       return -1;
16401 +}
16402 +/**
16403 + * ma_ctl_get_preference - get preference value for interface
16404 + * @ifi: interface index
16405 + * 
16406 + * Returns integer value interface index for interface with highest preference.
16407 + **/
16408 +int ma_ctl_get_preferred_if(void)
16409 +{
16410 +       struct list_head *lh;
16411 +       struct ma_if_info *info, *pref_if = NULL;
16412 +       
16413 +       list_for_each(lh, &if_list) {
16414 +               info = list_entry(lh, struct ma_if_info, list);
16415 +               if (!pref_if || (info->preference > pref_if->preference)) {
16416 +                       pref_if = info;
16417 +               }
16418 +       }
16419 +       if (pref_if) return pref_if->interface_id;
16420 +       return 0;
16421 +}
16422 +/**
16423 + * ma_ctl_set_preference - set preference for interface
16424 + * @arg: ioctl args
16425 + *
16426 + * Sets preference of an existing interface (called by ioctl).
16427 + **/
16428 +void ma_ctl_set_preference(unsigned long arg)
16429 +{
16430 +       struct list_head *lh;
16431 +       struct ma_if_info *info;
16432 +       struct ma_if_uinfo uinfo;
16433 +       
16434 +       memset(&uinfo, 0, sizeof(struct ma_if_uinfo));
16435 +       if (copy_from_user(&uinfo, (struct ma_if_uinfo *)arg, 
16436 +                          sizeof(struct ma_if_uinfo)) < 0) {
16437 +               DEBUG(DBG_WARNING, "copy_from_user failed");
16438 +               return;
16439 +       }
16440 +
16441 +       /* check if the interface exists */
16442 +       list_for_each(lh, &if_list) {
16443 +               info = list_entry(lh, struct ma_if_info, list);
16444 +               if (info->interface_id == uinfo.interface_id) {
16445 +                       info->preference = uinfo.preference;
16446 +                       return;
16447 +               }
16448 +       }
16449 +}
16450 +
16451 +/**
16452 + * ma_ctl_add_iface - add new interface to list
16453 + * @if_index: interface index
16454 + *
16455 + * Adds new interface entry to preference list.  Preference is set to
16456 + * the same value as @if_index.  Entry @status is set to
16457 + * %MA_IFACE_NOT_USED.
16458 + **/
16459 +void ma_ctl_add_iface(int if_index)
16460 +{
16461 +       struct list_head *lh;
16462 +       struct ma_if_info *info;
16463 +
16464 +       DEBUG_FUNC();
16465 +       
16466 +       /* check if the interface already exists */
16467 +       list_for_each(lh, &if_list) {
16468 +               info = list_entry(lh, struct ma_if_info, list);
16469 +               if (info->interface_id == if_index) {
16470 +                       info->status = MA_IFACE_NOT_USED;
16471 +                       info->preference = if_index;
16472 +                       return;
16473 +               }
16474 +       }
16475 +
16476 +       info = kmalloc(sizeof(struct ma_if_info), GFP_ATOMIC);
16477 +       if (info == NULL) {
16478 +               DEBUG(DBG_ERROR, "Out of memory");
16479 +               return;
16480 +       }
16481 +       memset(info, 0, sizeof(struct ma_if_info));
16482 +       info->interface_id = if_index;
16483 +       info->preference = if_index;
16484 +       info->status = MA_IFACE_NOT_USED;
16485 +       list_add(&info->list, &if_list);
16486 +}
16487 +
16488 +/**
16489 + * ma_ctl_del_iface - remove entry from the list
16490 + * @if_index: interface index
16491 + *
16492 + * Removes entry for interface @if_index from preference list.
16493 + **/
16494 +int ma_ctl_del_iface(int if_index)
16495 +{
16496 +       struct list_head *lh, *next;
16497 +       struct ma_if_info *info;
16498 +
16499 +       DEBUG_FUNC();
16500 +
16501 +       /* if the iface exists, change availability to 0 */
16502 +       list_for_each_safe(lh, next, &if_list) {
16503 +               info = list_entry(lh, struct ma_if_info, list);
16504 +               if (info->interface_id == if_index) {
16505 +                       list_del(&info->list);
16506 +                       kfree(info);
16507 +                       return 0;
16508 +               }
16509 +       }
16510 +
16511 +       return -1;
16512 +}
16513 +
16514 +/**
16515 + * ma_ctl_upd_iface - update entry (and list)
16516 + * @if_index: interface to update
16517 + * @status: new status for interface
16518 + * @change_if_index: new interface
16519 + *
16520 + * Updates @if_index entry on preference list.  Entry status is set to
16521 + * @status.  If new @status is %MA_IFACE_CURRENT, updates list to have
16522 + * only one current device.  If @status is %MA_IFACE_NOT_PRESENT,
16523 + * entry is deleted and further if entry had %MA_IFACE_CURRENT set,
16524 + * new current device is looked up and returned in @change_if_index.
16525 + * New preferred interface is also returned if current device changes
16526 + * to %MA_IFACE_NOT_USED.  Returns 0 on success, otherwise negative.
16527 + **/
16528 +int ma_ctl_upd_iface(int if_index, int status, int *change_if_index)
16529 +{
16530 +       struct list_head *lh, *tmp;
16531 +       struct ma_if_info *info, *pref = NULL;
16532 +       int found = 0;
16533 +
16534 +       DEBUG_FUNC();
16535 +
16536 +       *change_if_index = 0;
16537 +
16538 +       /* check if the interface exists */
16539 +       list_for_each_safe(lh, tmp, &if_list) {
16540 +               info = list_entry(lh, struct ma_if_info, list);
16541 +               if (status == MA_IFACE_NOT_PRESENT) {
16542 +                       if (info->interface_id == if_index) {
16543 +                               list_del_init(&info->list);
16544 +                               kfree(info);
16545 +                               found = 1;
16546 +                               break;
16547 +                       }
16548 +               } else if (status == MA_IFACE_CURRENT) {
16549 +                       if (info->interface_id == if_index) {
16550 +                               info->status |= MA_IFACE_CURRENT;
16551 +                               found = 1;
16552 +                       } else {
16553 +                               info->status |= MA_IFACE_NOT_USED;
16554 +                       }
16555 +               } else if (status == MA_IFACE_NOT_USED) {
16556 +                       if (info->interface_id == if_index) {
16557 +                               if (info->status | MA_IFACE_CURRENT) {
16558 +                                       found = 1;
16559 +                               }
16560 +                               info->status &= !MA_IFACE_CURRENT;
16561 +                               info->status |= MA_IFACE_NOT_USED;
16562 +                               info->status &= !MA_IFACE_HAS_ROUTER;
16563 +                       }
16564 +                       break;
16565 +               } else if (status == MA_IFACE_HAS_ROUTER) {
16566 +                       if (info->interface_id == if_index) {
16567 +                               info->status |= MA_IFACE_HAS_ROUTER;
16568 +                       }
16569 +                       return 0;
16570 +               }
16571 +       }
16572 +
16573 +       if (status & (MA_IFACE_NOT_USED|MA_IFACE_NOT_PRESENT) && found) {
16574 +               /* select new interface */
16575 +               list_for_each(lh, &if_list) {
16576 +                       info = list_entry(lh, struct ma_if_info, list);
16577 +                       if (pref == NULL || ((info->preference > pref->preference) && 
16578 +                                            info->status & MA_IFACE_HAS_ROUTER))
16579 +                               pref = info;
16580 +               }
16581 +               if (pref) {
16582 +                       *change_if_index = pref->interface_id;
16583 +                       pref->status |= MA_IFACE_CURRENT;
16584 +               } else {
16585 +                       *change_if_index = -1;
16586 +               }
16587 +               return 0;
16588 +       }
16589 +
16590 +       if (found) return 0;
16591 +
16592 +       return -1;
16593 +}
16594 +
16595 +static int if_proc_info(char *buffer, char **start, off_t offset,
16596 +                       int length)
16597 +{
16598 +       struct list_head *lh;
16599 +       struct ma_if_info *info;
16600 +       int len = 0;
16601 +
16602 +       list_for_each(lh, &if_list) {
16603 +               info = list_entry(lh, struct ma_if_info, list);
16604 +               len += sprintf(buffer + len, "%02d %010d %1d %1d\n",
16605 +                              info->interface_id, info->preference,
16606 +                              !!(info->status & MA_IFACE_HAS_ROUTER),
16607 +                              !!(info->status & MA_IFACE_CURRENT));
16608 +       }
16609 +
16610 +       *start = buffer + offset;
16611 +
16612 +       len -= offset;
16613 +
16614 +       if (len > length) len = length;
16615 +
16616 +       return len;
16617 +
16618 +}
16619 +
16620 +void ma_ctl_init(void)
16621 +{
16622 +       proc_net_create("mip6_iface", 0, if_proc_info);
16623 +}
16624 +
16625 +void ma_ctl_clean(void)
16626 +{
16627 +       proc_net_remove("mip6_iface");
16628 +}
16629 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.h linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.h
16630 --- linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.h      1970-01-01 01:00:00.000000000 +0100
16631 +++ linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.h  2004-06-26 11:29:31.000000000 +0100
16632 @@ -0,0 +1,77 @@
16633 +/*  
16634 + * 2001 (c) Oy L M Ericsson Ab
16635 + *
16636 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16637 + *
16638 + * $Id$
16639 + *
16640 + */
16641 +
16642 +#ifndef _MULTIACCESS_CTL_H
16643 +#define _MULTIACCESS_CTL_H
16644 +
16645 +/* status */
16646 +#define MA_IFACE_NOT_PRESENT 0x01
16647 +#define MA_IFACE_NOT_USED    0x02
16648 +#define MA_IFACE_HAS_ROUTER  0x04
16649 +#define MA_IFACE_CURRENT     0x10
16650 +
16651 +struct ma_if_uinfo {
16652 +       int        interface_id;
16653 +       int        preference;
16654 +       __u8       status;
16655 +};
16656 +/*
16657 + *  @ma_ctl_get_preferred_id: returns most preferred interface id
16658 + */
16659 +int ma_ctl_get_preferred_if(void);
16660 +
16661 +/* @ma_ctl_get_preference: returns preference for an interface
16662 + * @name: name of the interface (dev->name)
16663 + */
16664 +int ma_ctl_get_preference(int ifi);
16665 +
16666 +/*
16667 + * Public function: ma_ctl_set_preference
16668 + * Description: Set preference of an existing interface (called by ioctl)
16669 + * Returns:
16670 + */
16671 +void ma_ctl_set_preference(unsigned long);
16672 +
16673 +/*
16674 + * Public function: ma_ctl_add_iface
16675 + * Description: Inform control module to insert a new interface
16676 + * Returns: 0 if success, any other number means an error
16677 + */
16678 +void ma_ctl_add_iface(int);
16679 +
16680 +/*
16681 + * Public function: ma_ctl_del_iface
16682 + * Description: Inform control module to remove an obsolete interface
16683 + * Returns: 0 if success, any other number means an error
16684 + */
16685 +int ma_ctl_del_iface(int);
16686 +
16687 +/*
16688 + * Public function: ma_ctl_upd_iface
16689 + * Description: Inform control module of status change.
16690 + * Returns: 0 if success, any other number means an error
16691 + */
16692 +int ma_ctl_upd_iface(int, int, int *);
16693 +
16694 +/*
16695 + * Public function: ma_ctl_init
16696 + * Description: XXX
16697 + * Returns: XXX
16698 + */
16699 +void ma_ctl_init(void);
16700 +
16701 +/*
16702 + * Public function: ma_ctl_clean
16703 + * Description: XXX
16704 + * Returns: -
16705 + */
16706 +void ma_ctl_clean(void);
16707 +
16708 +
16709 +#endif
16710 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ndisc_ha.c linux-2.4.25/net/ipv6/mobile_ip6/ndisc_ha.c
16711 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ndisc_ha.c     1970-01-01 01:00:00.000000000 +0100
16712 +++ linux-2.4.25/net/ipv6/mobile_ip6/ndisc_ha.c 2004-06-26 11:29:31.000000000 +0100
16713 @@ -0,0 +1,596 @@
16714 +/*
16715 + *     Mobile IPv6 Duplicate Address Detection Functions
16716 + *
16717 + *     Authors:
16718 + *     Krishna Kumar <krkumar@us.ibm.com>
16719 + *
16720 + *      $Id$
16721 + *
16722 + *      This program is free software; you can redistribute it and/or
16723 + *      modify it under the terms of the GNU General Public License
16724 + *      as published by the Free Software Foundation; either version
16725 + *      2 of the License, or (at your option) any later version.
16726 + *
16727 + */
16728 +
16729 +#include <linux/autoconf.h>
16730 +#include <linux/types.h>
16731 +#include <linux/init.h>
16732 +#include <linux/skbuff.h>
16733 +#include <linux/in6.h>
16734 +#include <net/ipv6.h>
16735 +#include <net/addrconf.h>
16736 +#include <net/mipv6.h>
16737 +
16738 +#include "debug.h"
16739 +#include "bcache.h"
16740 +#include "ha.h" /* mipv6_generate_ll_addr */
16741 +
16742 +/*
16743 + * Binding Updates from MN are cached in this structure till DAD is performed.
16744 + * This structure is used to retrieve a pending Binding Update for the HA to
16745 + * reply to after performing DAD. The first cell is different from the rest as
16746 + * follows :
16747 + *     1. The first cell is used to chain the remaining cells. 
16748 + *     2. The timeout of the first cell is used to delete expired entries
16749 + *        in the list of cells, while the timeout of the other cells are
16750 + *        used for timing out a NS request so as to reply to a BU.
16751 + *     3. The only elements of the first cell that are used are :
16752 + *        next, prev, and callback_timer.
16753 + *
16754 + * TODO : Don't we need to do pneigh_lookup on the Link Local address ?
16755 + */
16756 +struct mipv6_dad_cell {
16757 +       /* Information needed for DAD management */
16758 +       struct mipv6_dad_cell   *next;  /* Next element on the DAD list */
16759 +       struct mipv6_dad_cell   *prev;  /* Prev element on the DAD list */
16760 +       __u16                   probes; /* Number of times to probe for addr */
16761 +       __u16                   flags;  /* Entry flags - see below */
16762 +       struct timer_list       callback_timer; /* timeout for entry */
16763 +
16764 +       /* Information needed for performing DAD */
16765 +       struct inet6_ifaddr     *ifp;
16766 +       int                     ifindex;
16767 +       struct in6_addr         daddr;
16768 +       struct in6_addr         haddr;          /* home address */
16769 +       struct in6_addr         ll_haddr;       /* Link Local value of haddr */
16770 +       struct in6_addr         coa;
16771 +       struct in6_addr         rep_coa;
16772 +       __u32                   ba_lifetime;
16773 +       __u16                   sequence;
16774 +       __u8                    bu_flags;
16775 +};
16776 +
16777 +/* Values for the 'flags' field in the mipv6_dad_cell */
16778 +#define        DAD_INIT_ENTRY          0
16779 +#define        DAD_DUPLICATE_ADDRESS   1
16780 +#define        DAD_UNIQUE_ADDRESS      2
16781 +
16782 +/* Head of the pending DAD list */
16783 +static struct mipv6_dad_cell dad_cell_head;
16784 +
16785 +/* Lock to access the pending DAD list */
16786 +static rwlock_t dad_lock = RW_LOCK_UNLOCKED;
16787 +
16788 +/* Timer routine which deletes 'expired' entries in the DAD list */
16789 +static void mipv6_dad_delete_old_entries(unsigned long unused)
16790 +{
16791 +       struct mipv6_dad_cell *curr, *next;
16792 +       unsigned long next_time = 0;
16793 +
16794 +       write_lock(&dad_lock);
16795 +       curr = dad_cell_head.next;
16796 +       while (curr != &dad_cell_head) {
16797 +               next = curr->next;
16798 +               if (curr->flags != DAD_INIT_ENTRY) {
16799 +                       if (curr->callback_timer.expires <= jiffies) {
16800 +                               /* Entry has expired, free it up. */
16801 +                               curr->next->prev = curr->prev;
16802 +                               curr->prev->next = curr->next;
16803 +                               in6_ifa_put(curr->ifp);
16804 +                               kfree(curr);
16805 +                       } else if (next_time <
16806 +                                  curr->callback_timer.expires) {
16807 +                               next_time = curr->callback_timer.expires;
16808 +                       }
16809 +               }
16810 +               curr = next;
16811 +       }
16812 +       write_unlock(&dad_lock);
16813 +       if (next_time) {
16814 +               /*
16815 +                * Start another timer if more cells need to be removed at
16816 +                * a later stage.
16817 +                */
16818 +               dad_cell_head.callback_timer.expires = next_time;
16819 +               add_timer(&dad_cell_head.callback_timer);
16820 +       }
16821 +}
16822 +
16823 +/* 
16824 + * Queue a timeout routine to clean up 'expired' DAD entries.
16825 + */
16826 +static void mipv6_start_dad_head_timer(struct mipv6_dad_cell *cell)
16827 +{
16828 +       unsigned long expire = jiffies +
16829 +           cell->ifp->idev->nd_parms->retrans_time * 10;
16830 +
16831 +       if (!timer_pending(&dad_cell_head.callback_timer) ||
16832 +           expire < dad_cell_head.callback_timer.expires) {
16833 +               /*
16834 +                * Add timer if none pending, or mod the timer if new 
16835 +                * cell needs to be expired before existing timer runs.
16836 +                *
16837 +                * We let the cell remain as long as possible, so that
16838 +                * new BU's as part of retransmissions don't have to go
16839 +                * through DAD before replying.
16840 +                */
16841 +               dad_cell_head.callback_timer.expires = expire;
16842 +
16843 +               /*
16844 +                * Keep the cell around for atleast some time to handle
16845 +                * retransmissions or BU's due to fast MN movement. This
16846 +                * is needed otherwise a previous timeout can delete all
16847 +                * expired entries including this new one.
16848 +                */
16849 +               cell->callback_timer.expires = jiffies +
16850 +                   cell->ifp->idev->nd_parms->retrans_time * 5;
16851 +               if (!timer_pending(&dad_cell_head.callback_timer)) {
16852 +                       add_timer(&dad_cell_head.callback_timer);
16853 +               } else {
16854 +                       mod_timer(&dad_cell_head.callback_timer, expire);
16855 +               }
16856 +       }
16857 +}
16858 +
16859 +
16860 +/* Join solicited node MC address */
16861 +static inline void mipv6_join_sol_mc_addr(struct in6_addr *addr,
16862 +                                         struct net_device *dev)
16863 +{
16864 +       struct in6_addr maddr;
16865 +
16866 +       /* Join solicited node MC address */
16867 +       addrconf_addr_solict_mult(addr, &maddr);
16868 +       ipv6_dev_mc_inc(dev, &maddr);
16869 +}
16870 +
16871 +/* Leave solicited node MC address */
16872 +static inline void mipv6_leave_sol_mc_addr(struct in6_addr *addr,
16873 +                                          struct net_device *dev)
16874 +{
16875 +       struct in6_addr maddr;
16876 +
16877 +       addrconf_addr_solict_mult(addr, &maddr);
16878 +       ipv6_dev_mc_dec(dev, &maddr);
16879 +}
16880 +
16881 +/* Send a NS */
16882 +static inline void mipv6_dad_send_ns(struct inet6_ifaddr *ifp,
16883 +                                    struct in6_addr *haddr)
16884 +{
16885 +       struct in6_addr unspec;
16886 +       struct in6_addr mcaddr;
16887 +
16888 +       ipv6_addr_set(&unspec, 0, 0, 0, 0);
16889 +       addrconf_addr_solict_mult(haddr, &mcaddr);
16890 +
16891 +       /* addr is 'unspec' since we treat this address as transient */
16892 +       ndisc_send_ns(ifp->idev->dev, NULL, haddr, &mcaddr, &unspec);
16893 +}
16894 +
16895 +/*
16896 + * Search for a home address in the list of pending DAD's. Called from
16897 + * Neighbor Advertisement
16898 + * Return values :
16899 + *     -1 : No DAD entry found for this advertisement, or entry already
16900 + *          finished processing.
16901 + *     0  : Entry found waiting for DAD to finish.
16902 + */
16903 +static int dad_search_haddr(struct in6_addr *ll_haddr,
16904 +                           struct in6_addr *daddr, struct in6_addr *haddr,
16905 +                           struct in6_addr *coa, struct in6_addr *rep_coa,
16906 +                           __u16 * seq, struct inet6_ifaddr **ifp)
16907 +{
16908 +       struct mipv6_dad_cell *cell;
16909 +
16910 +       read_lock(&dad_lock);
16911 +       cell = dad_cell_head.next;
16912 +       while (cell != &dad_cell_head &&
16913 +              ipv6_addr_cmp(&cell->ll_haddr, ll_haddr) && 
16914 +              ipv6_addr_cmp(&cell->haddr, ll_haddr)) {
16915 +               cell = cell->next;
16916 +       }
16917 +       if (cell == &dad_cell_head || cell->flags != DAD_INIT_ENTRY) {
16918 +               /* Not found element, or element already finished processing */
16919 +               if (cell != &dad_cell_head) {
16920 +                       /*
16921 +                        * Set the state to DUPLICATE, even if it was UNIQUE
16922 +                        * earlier. It is not needed to setup timer via 
16923 +                        * mipv6_start_dad_head_timer since this must have
16924 +                        * already been done.
16925 +                        */
16926 +                       cell->flags = DAD_DUPLICATE_ADDRESS;
16927 +               }
16928 +               read_unlock(&dad_lock);
16929 +               return -1;
16930 +       }
16931 +
16932 +       /*
16933 +        * The NA found an unprocessed entry in the DAD list. Expire this
16934 +        * entry since another node advertised this address. Caller should
16935 +        * reject BU (DAD failed).
16936 +        */
16937 +       ipv6_addr_copy(daddr, &cell->daddr);
16938 +       ipv6_addr_copy(haddr, &cell->haddr);
16939 +       ipv6_addr_copy(coa, &cell->coa);
16940 +       ipv6_addr_copy(rep_coa, &cell->rep_coa);
16941 +       *seq = cell->sequence;
16942 +       *ifp = cell->ifp;
16943 +
16944 +       if (del_timer(&cell->callback_timer) == 0) {
16945 +               /* Timer already deleted, race with Timeout Handler */
16946 +               /* No action needed */
16947 +       }
16948 +
16949 +       cell->flags = DAD_DUPLICATE_ADDRESS;
16950 +
16951 +       /* Now leave this address to avoid future processing of NA's */
16952 +       mipv6_leave_sol_mc_addr(&cell->ll_haddr, cell->ifp->idev->dev);
16953 +       /* Leave also global address, if link local address was in use */
16954 +       if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16955 +               mipv6_leave_sol_mc_addr(&cell->haddr, cell->ifp->idev->dev);
16956 +       /* Start dad_head timer to remove this entry */
16957 +       mipv6_start_dad_head_timer(cell);
16958 +
16959 +       read_unlock(&dad_lock);
16960 +
16961 +       return 0;
16962 +}
16963 +
16964 +/* ENTRY routine called via Neighbor Advertisement */
16965 +void mipv6_check_dad(struct in6_addr *ll_haddr)
16966 +{
16967 +       struct in6_addr daddr, haddr, coa, rep_coa;
16968 +       struct inet6_ifaddr *ifp;
16969 +       __u16 seq;
16970 +
16971 +       if (dad_search_haddr(ll_haddr, &daddr, &haddr, &coa, &rep_coa, &seq,
16972 +                            &ifp) < 0) {
16973 +               /* 
16974 +                * Didn't find entry, or no action needed (the action has
16975 +                * already been performed).
16976 +                */
16977 +               return;
16978 +       }
16979 +
16980 +       /*
16981 +        * A DAD cell was present, meaning that there is a pending BU
16982 +        * request for 'haddr' - reject the BU.
16983 +        */
16984 +       mipv6_bu_finish(ifp, 0, DUPLICATE_ADDR_DETECT_FAIL,
16985 +                       &daddr, &haddr, &coa, &rep_coa, 0, seq, 0, NULL);
16986 +       return;
16987 +}
16988 +
16989 +/*
16990 + * Check if the passed 'cell' is in the list of pending DAD's. Called from
16991 + * the Timeout Handler.
16992 + *
16993 + * Assumes that the caller is holding the dad_lock in reader mode.
16994 + */
16995 +static int dad_search_cell(struct mipv6_dad_cell *cell)
16996 +{
16997 +       struct mipv6_dad_cell *tmp;
16998 +
16999 +       tmp = dad_cell_head.next;
17000 +       while (tmp != &dad_cell_head && tmp != cell) {
17001 +               tmp = tmp->next;
17002 +       }
17003 +       if (tmp == cell) {
17004 +               if (cell->flags == DAD_INIT_ENTRY) {
17005 +                       /* Found valid entry */
17006 +                       if (--cell->probes == 0) {
17007 +                               /*
17008 +                                * Retransmission's are over - return success.
17009 +                                */
17010 +                               cell->flags = DAD_UNIQUE_ADDRESS;
17011 +
17012 +                               /* 
17013 +                                * Leave this address to avoid future 
17014 +                                * processing of NA's.
17015 +                                */
17016 +                               mipv6_leave_sol_mc_addr(&cell->ll_haddr,
17017 +                                                       cell->ifp->idev->
17018 +                                                       dev);
17019 +                               if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
17020 +                                       mipv6_leave_sol_mc_addr(&cell->haddr, 
17021 +                                                               cell->ifp->idev->dev);
17022 +                               /* start timeout to delete this cell. */
17023 +                               mipv6_start_dad_head_timer(cell);
17024 +                               return 0;
17025 +                       }
17026 +                       /*
17027 +                        * Retransmission not finished, send another NS and
17028 +                        * return failure.
17029 +                        */
17030 +                       mipv6_dad_send_ns(cell->ifp, &cell->ll_haddr);
17031 +                       if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
17032 +                               mipv6_leave_sol_mc_addr(&cell->haddr, 
17033 +                                                       cell->ifp->idev->dev);
17034 +                       cell->callback_timer.expires = jiffies +
17035 +                           cell->ifp->idev->nd_parms->retrans_time;
17036 +                       add_timer(&cell->callback_timer);
17037 +               } else {
17038 +                       /*
17039 +                        * This means that an NA was received before the
17040 +                        * timeout and when the state changed from
17041 +                        * DAD_INIT_ENTRY, the BU got failed as a result.
17042 +                        * There is nothing to be done.
17043 +                        */
17044 +               }
17045 +       }
17046 +       return -1;
17047 +}
17048 +
17049 +/* ENTRY routine called via Timeout */
17050 +static void mipv6_dad_timeout(unsigned long arg)
17051 +{
17052 +       __u8 ba_status = SUCCESS;
17053 +       struct in6_addr daddr;
17054 +       struct in6_addr haddr;
17055 +       struct in6_addr coa;
17056 +       struct in6_addr rep_coa;
17057 +       struct inet6_ifaddr *ifp;
17058 +       int ifindex;
17059 +       __u32 ba_lifetime;
17060 +       __u16 sequence;
17061 +       __u8 flags;
17062 +       struct mipv6_dad_cell *cell = (struct mipv6_dad_cell *) arg;
17063 +
17064 +       /*
17065 +        * If entry is not in the list, we have already sent BU Failure
17066 +        * after getting a NA.
17067 +        */
17068 +       read_lock(&dad_lock);
17069 +       if (dad_search_cell(cell) < 0) {
17070 +               /*
17071 +                * 'cell' is no longer valid (may not be in the list or
17072 +                * is already processed, due to NA processing), or NS
17073 +                * retransmissions are not yet over.
17074 +                */
17075 +               read_unlock(&dad_lock);
17076 +               return;
17077 +       }
17078 +
17079 +       /* This is the final Timeout. Send Bind Ack Success */
17080 +
17081 +       ifp = cell->ifp;
17082 +       ifindex = cell->ifindex;
17083 +       ba_lifetime = cell->ba_lifetime;
17084 +       sequence = cell->sequence;
17085 +       flags = cell->bu_flags;
17086 +
17087 +       ipv6_addr_copy(&daddr, &cell->daddr);
17088 +       ipv6_addr_copy(&haddr, &cell->haddr);
17089 +       ipv6_addr_copy(&coa, &cell->coa);
17090 +       ipv6_addr_copy(&rep_coa, &cell->rep_coa);
17091 +       read_unlock(&dad_lock);
17092 +
17093 +       /* Send BU Acknowledgement Success */
17094 +       mipv6_bu_finish(ifp, ifindex, ba_status, 
17095 +                       &daddr, &haddr, &coa, &rep_coa,
17096 +                       ba_lifetime, sequence, flags, NULL);
17097 +       return;
17098 +}
17099 +
17100 +/*
17101 + * Check if original home address exists in our DAD pending list, if so return
17102 + * the cell.
17103 + *
17104 + * Assumes that the caller is holding the dad_lock in writer mode.
17105 + */
17106 +static struct mipv6_dad_cell *mipv6_dad_get_cell(struct in6_addr *haddr)
17107 +{
17108 +       struct mipv6_dad_cell *cell;
17109 +
17110 +       cell = dad_cell_head.next;
17111 +       while (cell != &dad_cell_head
17112 +              && ipv6_addr_cmp(&cell->haddr, haddr)) {
17113 +               cell = cell->next;
17114 +       }
17115 +       if (cell == &dad_cell_head) {
17116 +               /* Not found element */
17117 +               return NULL;
17118 +       }
17119 +       return cell;
17120 +}
17121 +
17122 +/*
17123 + * Save all parameters needed for doing a Bind Ack in the mipv6_dad_cell 
17124 + * structure.
17125 + */
17126 +static void mipv6_dad_save_cell(struct mipv6_dad_cell *cell,
17127 +                               struct inet6_ifaddr *ifp, int ifindex,
17128 +                               struct in6_addr *daddr,
17129 +                               struct in6_addr *haddr,
17130 +                               struct in6_addr *coa, 
17131 +                               struct in6_addr *rep_coa,
17132 +                               __u32 ba_lifetime,
17133 +                               __u16 sequence, __u8 flags)
17134 +{
17135 +       in6_ifa_hold(ifp);
17136 +       cell->ifp = ifp;
17137 +       cell->ifindex = ifindex;
17138 +
17139 +       ipv6_addr_copy(&cell->daddr, daddr);
17140 +       ipv6_addr_copy(&cell->haddr, haddr);
17141 +       ipv6_addr_copy(&cell->coa, coa);
17142 +       ipv6_addr_copy(&cell->rep_coa, rep_coa);
17143 +
17144 +       /* Convert cell->ll_haddr to Link Local address */
17145 +       if (flags & MIPV6_BU_F_LLADDR) 
17146 +               mipv6_generate_ll_addr(&cell->ll_haddr, haddr);
17147 +       else 
17148 +               ipv6_addr_copy(&cell->ll_haddr, haddr);
17149 +
17150 +       cell->ba_lifetime = ba_lifetime;
17151 +       cell->sequence = sequence;
17152 +       cell->bu_flags = flags;
17153 +}
17154 +
17155 +/*
17156 + * Top level DAD routine for performing DAD.
17157 + *
17158 + * Return values
17159 + *     0     : Don't need to do DAD.
17160 + *     1     : Need to do DAD.
17161 + *     -n    : Error, where 'n' is the reason for the error.
17162 + *
17163 + * Assumption : DAD process has been optimized by using cached values upto
17164 + * some time. However sometimes this can cause problems. Eg. when the first
17165 + * BU was received, DAD might have failed. Before the second BU arrived,
17166 + * the node using MN's home address might have stopped using it, but still
17167 + * we will return DAD_DUPLICATE_ADDRESS based on the first DAD's result. Or 
17168 + * this can go the other way around. However, it is a very small possibility
17169 + * and thus optimization is turned on by default. It is possible to change
17170 + * this feature (needs a little code-rewriting in this routine), but 
17171 + * currently DAD result is being cached for performance reasons.
17172 + */
17173 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
17174 +                   struct in6_addr *daddr, struct in6_addr *haddr,
17175 +                   struct in6_addr *coa, struct in6_addr *rep_coa,
17176 +                   __u32 ba_lifetime, __u16 sequence, __u8 flags)
17177 +{
17178 +       int found;
17179 +       struct mipv6_dad_cell *cell;
17180 +       struct mipv6_bce bc_entry;
17181 +
17182 +       if (ifp->idev->cnf.dad_transmits == 0) {
17183 +               /* DAD is not configured on the HA, return SUCCESS */
17184 +               return 0;
17185 +       }
17186 +
17187 +       if (mipv6_bcache_get(haddr, daddr, &bc_entry) == 0) {
17188 +               /*
17189 +                * We already have an entry in our cache - don't need to 
17190 +                * do DAD as we are already defending this home address.
17191 +                */
17192 +               return 0;
17193 +       }
17194 +
17195 +       write_lock(&dad_lock);
17196 +       if ((cell = mipv6_dad_get_cell(haddr)) != NULL) {
17197 +               /*
17198 +                * An existing entry for BU was found in our cache due
17199 +                * to retransmission of the BU or a new COA registration.
17200 +                */
17201 +               switch (cell->flags) {
17202 +               case DAD_INIT_ENTRY:
17203 +                       /* Old entry is waiting for DAD to complete */
17204 +                       break;
17205 +               case DAD_UNIQUE_ADDRESS:
17206 +                       /* DAD is finished successfully - return success. */
17207 +                       write_unlock(&dad_lock);
17208 +                       return 0;
17209 +               case DAD_DUPLICATE_ADDRESS:
17210 +                       /*
17211 +                        * DAD is finished and we got a NA while doing BU -
17212 +                        * return failure.
17213 +                        */
17214 +                       write_unlock(&dad_lock);
17215 +                       return -DUPLICATE_ADDR_DETECT_FAIL;
17216 +               default:
17217 +                       /* Unknown state - should never happen */
17218 +                       DEBUG(DBG_WARNING,
17219 +                             "cell entry in unknown state : %d",
17220 +                             cell->flags);
17221 +                       write_unlock(&dad_lock);
17222 +                       return -REASON_UNSPECIFIED;
17223 +               }
17224 +               found = 1;
17225 +       } else {
17226 +               if ((cell = (struct mipv6_dad_cell *)
17227 +                    kmalloc(sizeof(struct mipv6_dad_cell), GFP_ATOMIC))
17228 +                   == NULL) {
17229 +                       return -INSUFFICIENT_RESOURCES;
17230 +               }
17231 +               found = 0;
17232 +       }
17233 +
17234 +       mipv6_dad_save_cell(cell, ifp, ifindex, daddr, haddr, coa, rep_coa,
17235 +                           ba_lifetime, sequence, flags);
17236 +
17237 +       if (!found) {
17238 +               cell->flags = DAD_INIT_ENTRY;
17239 +               cell->probes = ifp->idev->cnf.dad_transmits;
17240 +
17241 +               /* Insert element on dad_cell_head list */
17242 +               dad_cell_head.prev->next = cell;
17243 +               cell->next = &dad_cell_head;
17244 +               cell->prev = dad_cell_head.prev;
17245 +               dad_cell_head.prev = cell;
17246 +               write_unlock(&dad_lock);
17247 +               if (flags & MIPV6_BU_F_LLADDR) {
17248 +                       /* join the solicited node MC of the global homeaddr.*/
17249 +                       mipv6_join_sol_mc_addr(&cell->haddr, ifp->idev->dev);
17250 +                       /* Send a NS */
17251 +                       mipv6_dad_send_ns(ifp, &cell->haddr);
17252 +               }
17253 +               /* join the solicited node MC of the homeaddr. */
17254 +               mipv6_join_sol_mc_addr(&cell->ll_haddr, ifp->idev->dev);
17255 +               
17256 +               /* Send a NS */
17257 +               mipv6_dad_send_ns(ifp, &cell->ll_haddr);
17258 +               
17259 +               /* Initialize timer for this cell to timeout the NS. */
17260 +               init_timer(&cell->callback_timer);
17261 +               cell->callback_timer.data = (unsigned long) cell;
17262 +               cell->callback_timer.function = mipv6_dad_timeout;
17263 +               cell->callback_timer.expires = jiffies +
17264 +                   ifp->idev->nd_parms->retrans_time;
17265 +               add_timer(&cell->callback_timer);
17266 +       } else {
17267 +               write_unlock(&dad_lock);
17268 +       }
17269 +       return 1;
17270 +}
17271 +
17272 +void __init mipv6_dad_init(void)
17273 +{
17274 +       dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17275 +       init_timer(&dad_cell_head.callback_timer);
17276 +       dad_cell_head.callback_timer.data = 0;
17277 +       dad_cell_head.callback_timer.function =
17278 +               mipv6_dad_delete_old_entries;
17279 +}
17280 +
17281 +void __exit mipv6_dad_exit(void)
17282 +{
17283 +       struct mipv6_dad_cell *curr, *next;
17284 +
17285 +       write_lock_bh(&dad_lock);
17286 +       del_timer(&dad_cell_head.callback_timer);
17287 +
17288 +       curr = dad_cell_head.next;
17289 +       while (curr != &dad_cell_head) {
17290 +               next = curr->next;
17291 +               del_timer(&curr->callback_timer);
17292 +               if (curr->flags == DAD_INIT_ENTRY) {
17293 +                       /*
17294 +                        * We were in DAD_INIT state and listening to the
17295 +                        * solicited node MC address - need to stop that.
17296 +                        */
17297 +                       mipv6_leave_sol_mc_addr(&curr->ll_haddr,
17298 +                                               curr->ifp->idev->dev);
17299 +                       if (ipv6_addr_cmp(&curr->ll_haddr, &curr->haddr))
17300 +                               mipv6_leave_sol_mc_addr(&curr->haddr, 
17301 +                                                       curr->ifp->idev->dev);
17302 +               }
17303 +               in6_ifa_put(curr->ifp);
17304 +               kfree(curr);
17305 +               curr = next;
17306 +       }
17307 +       dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17308 +       write_unlock_bh(&dad_lock);
17309 +}
17310 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.c linux-2.4.25/net/ipv6/mobile_ip6/prefix.c
17311 --- linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.c       1970-01-01 01:00:00.000000000 +0100
17312 +++ linux-2.4.25/net/ipv6/mobile_ip6/prefix.c   2004-06-26 11:29:31.000000000 +0100
17313 @@ -0,0 +1,217 @@
17314 +/**
17315 + * Prefix solicitation and advertisement
17316 + *
17317 + * Authors:
17318 + * Jaakko Laine <medved@iki.fi>
17319 + *
17320 + * $Id$
17321 + *
17322 + * This program is free software; you can redistribute it and/or
17323 + * modify it under the terms of the GNU General Public License
17324 + * as published by the Free Software Foundation; either version
17325 + * 2 of the License, or (at your option) any later version.
17326 + */
17327 +
17328 +#include <linux/config.h>
17329 +#include <linux/icmpv6.h>
17330 +#include <linux/net.h>
17331 +#include <linux/spinlock.h>
17332 +#include <linux/timer.h>
17333 +#include <linux/netdevice.h>
17334 +#include <net/ipv6.h>
17335 +#include <net/addrconf.h>
17336 +#include <net/ip6_route.h>
17337 +#include <net/mipv6.h>
17338 +
17339 +#include "mipv6_icmp.h"
17340 +#include "debug.h"
17341 +#include "sortedlist.h"
17342 +#include "prefix.h"
17343 +#include "config.h"
17344 +
17345 +#define INFINITY 0xffffffff
17346 +
17347 +struct timer_list pfx_timer;
17348 +
17349 +struct list_head pfx_list;
17350 +rwlock_t pfx_list_lock = RW_LOCK_UNLOCKED;
17351 +
17352 +int compare_pfx_list_entry(const void *data1, const void *data2,
17353 +                          int datalen)
17354 +{
17355 +       struct pfx_list_entry *e1 = (struct pfx_list_entry *) data1;
17356 +       struct pfx_list_entry *e2 = (struct pfx_list_entry *) data2;
17357 +
17358 +       return ((ipv6_addr_cmp(&e1->daddr, &e2->daddr) == 0)
17359 +               && (e2->ifindex == -1 || e1->ifindex == e2->ifindex));
17360 +}
17361 +
17362 +/**
17363 + * mipv6_pfx_cancel_send - cancel pending items to daddr from saddr
17364 + * @daddr: Destination address
17365 + * @ifindex: pending items on this interface will be canceled
17366 + *
17367 + * if ifindex == -1, all items to daddr will be removed
17368 + */
17369 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex)
17370 +{
17371 +       unsigned long tmp;
17372 +       struct pfx_list_entry entry;
17373 +
17374 +       DEBUG_FUNC();
17375 +
17376 +       /* We'll just be comparing these parts... */
17377 +       memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17378 +       entry.ifindex = ifindex;
17379 +
17380 +       write_lock_bh(&pfx_list_lock);
17381 +
17382 +       while (mipv6_slist_del_item(&pfx_list, &entry,
17383 +                                   compare_pfx_list_entry) == 0)
17384 +               ;
17385 +
17386 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17387 +               mod_timer(&pfx_timer, tmp);
17388 +
17389 +       write_unlock_bh(&pfx_list_lock);
17390 +}
17391 +
17392 +/**
17393 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17394 + * @daddr: address of HA
17395 + * @saddr: our address to use as source address
17396 + * @ifindex: interface index
17397 + */
17398 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17399 +                     int ifindex)
17400 +{
17401 +       unsigned long tmp;
17402 +       struct pfx_list_entry entry;
17403 +
17404 +       DEBUG_FUNC();
17405 +
17406 +       memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17407 +       memcpy(&entry.saddr, saddr, sizeof(struct in6_addr));
17408 +       entry.retries = 0;
17409 +       entry.ifindex = ifindex;
17410 +
17411 +       write_lock_bh(&pfx_list_lock);
17412 +       if (mipv6_slist_modify(&pfx_list, &entry, sizeof(struct pfx_list_entry),
17413 +                              jiffies + INITIAL_SOLICIT_TIMER * HZ,
17414 +                              compare_pfx_list_entry))
17415 +               DEBUG(DBG_WARNING, "Cannot add new HA to pfx list");
17416 +
17417 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17418 +               mod_timer(&pfx_timer, tmp);
17419 +       write_unlock_bh(&pfx_list_lock);
17420 +}
17421 +
17422 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *saddr, 
17423 +                      struct in6_addr *daddr, unsigned long min_expire)
17424 +{
17425 +       unsigned long tmp;
17426 +
17427 +       write_lock(&pfx_list_lock);
17428 +
17429 +       if (min_expire != INFINITY) {
17430 +               unsigned long expire;
17431 +               struct pfx_list_entry entry;
17432 +               
17433 +               memcpy(&entry.daddr, saddr, sizeof(struct in6_addr));
17434 +               memcpy(&entry.saddr, daddr, sizeof(struct in6_addr));
17435 +               entry.retries = 0;
17436 +               entry.ifindex = ifindex;
17437 +
17438 +               /* This is against the RFC 3775, but we need to set
17439 +                * a minimum interval for a prefix solicitation.
17440 +                * Otherwise a prefix solicitation storm will
17441 +                * result if valid lifetime of the prefix is
17442 +                * smaller than MAX_PFX_ADV_DELAY
17443 +                */
17444 +               min_expire -= MAX_PFX_ADV_DELAY;
17445 +               min_expire = min_expire < MIN_PFX_SOL_DELAY ? MIN_PFX_SOL_DELAY : min_expire;
17446 +
17447 +               expire = jiffies + min_expire * HZ;
17448 +
17449 +               if (mipv6_slist_modify(&pfx_list, &entry,
17450 +                                      sizeof(struct pfx_list_entry),
17451 +                                      expire,
17452 +                                      compare_pfx_list_entry) != 0)
17453 +                       DEBUG(DBG_WARNING, "Cannot add new entry to pfx_list");
17454 +       }
17455 +
17456 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17457 +               mod_timer(&pfx_timer, tmp);
17458 +
17459 +       write_unlock(&pfx_list_lock);
17460 +
17461 +       return 0;
17462 +}
17463 +
17464 +/**
17465 + * set_ha_pfx_list - manipulate pfx_list for HA when timer goes off
17466 + * @entry: pfx_list_entry that is due
17467 + */
17468 +static void set_ha_pfx_list(struct pfx_list_entry *entry)
17469 +{
17470 +}
17471 +
17472 +/**
17473 + * set_mn_pfx_list - manipulate pfx_list for MN when timer goes off
17474 + * @entry: pfx_list_entry that is due
17475 + */
17476 +static void set_mn_pfx_list(struct pfx_list_entry *entry)
17477 +{
17478 +}
17479 +
17480 +/**
17481 + * pfx_timer_handler - general timer handler
17482 + * @dummy: dummy
17483 + *
17484 + * calls set_ha_pfx_list and set_mn_pfx_list to do the thing when
17485 + * a timer goes off
17486 + */
17487 +static void pfx_timer_handler(unsigned long dummy)
17488 +{
17489 +       unsigned long tmp;
17490 +       struct pfx_list_entry *entry;
17491 +
17492 +       DEBUG_FUNC();
17493 +
17494 +       write_lock(&pfx_list_lock);
17495 +       if (!(entry = mipv6_slist_get_first(&pfx_list)))
17496 +               goto out;
17497 +
17498 +       if (mip6node_cnf.capabilities & CAP_HA)
17499 +               set_ha_pfx_list(entry);
17500 +       if (mip6node_cnf.capabilities & CAP_MN)
17501 +               set_mn_pfx_list(entry);
17502 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17503 +               mod_timer(&pfx_timer, tmp);
17504 +
17505 + out:
17506 +       write_unlock(&pfx_list_lock);
17507 +}
17508 +
17509 +int mipv6_initialize_pfx_icmpv6(void)
17510 +{
17511 +       INIT_LIST_HEAD(&pfx_list);
17512 +
17513 +       init_timer(&pfx_timer);
17514 +       pfx_timer.function = pfx_timer_handler;
17515 +
17516 +       return 0;
17517 +}
17518 +
17519 +void mipv6_shutdown_pfx_icmpv6(void)
17520 +{
17521 +       struct prefix_info *tmp;
17522 +
17523 +       if (timer_pending(&pfx_timer))
17524 +               del_timer(&pfx_timer);
17525 +
17526 +       write_lock_bh(&pfx_list_lock);
17527 +       while ((tmp = mipv6_slist_del_first(&pfx_list)))
17528 +               kfree(tmp);
17529 +       write_unlock_bh(&pfx_list_lock);
17530 +}
17531 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.h linux-2.4.25/net/ipv6/mobile_ip6/prefix.h
17532 --- linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.h       1970-01-01 01:00:00.000000000 +0100
17533 +++ linux-2.4.25/net/ipv6/mobile_ip6/prefix.h   2004-06-26 11:29:31.000000000 +0100
17534 @@ -0,0 +1,57 @@
17535 +/*
17536 + *      MIPL Mobile IPv6 Prefix solicitation and advertisement
17537 + *
17538 + *      $Id$
17539 + *
17540 + *      This program is free software; you can redistribute it and/or
17541 + *      modify it under the terms of the GNU General Public License
17542 + *      as published by the Free Software Foundation; either version
17543 + *      2 of the License, or (at your option) any later version.
17544 + */
17545 +
17546 +#ifndef _PREFIX_H
17547 +#define _PREFIX_H
17548 +
17549 +#include <net/addrconf.h>
17550 +
17551 +struct pfx_list_entry {
17552 +       struct in6_addr daddr;
17553 +       struct in6_addr saddr;
17554 +       int retries;
17555 +       int ifindex;
17556 +};
17557 +
17558 +extern struct list_head pfx_list;
17559 +extern rwlock_t pfx_list_lock;
17560 +extern struct timer_list pfx_timer;
17561 +
17562 +int compare_pfx_list_entry(const void *data1, const void *data2,
17563 +                          int datalen);
17564 +
17565 +/**
17566 + * mipv6_pfx_cancel_send - cancel pending pfx_advs/sols to daddr
17567 + * @daddr: destination address
17568 + * @ifindex: pending items on this interface will be canceled
17569 + *
17570 + * if ifindex == -1, all items to daddr will be removed
17571 + */
17572 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex);
17573 +
17574 +/**
17575 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17576 + * @daddr: address of HA
17577 + * @saddr: our address to use as source address
17578 + * @ifindex: interface index
17579 + */
17580 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17581 +                     int ifindex);
17582 +
17583 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex);
17584 +
17585 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *daddr,
17586 +                      struct in6_addr *saddr, unsigned long min_expire);
17587 +
17588 +int mipv6_initialize_pfx_icmpv6(void);
17589 +void mipv6_shutdown_pfx_icmpv6(void);
17590 +
17591 +#endif
17592 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/prefix_ha.c linux-2.4.25/net/ipv6/mobile_ip6/prefix_ha.c
17593 --- linux-2.4.25.old/net/ipv6/mobile_ip6/prefix_ha.c    1970-01-01 01:00:00.000000000 +0100
17594 +++ linux-2.4.25/net/ipv6/mobile_ip6/prefix_ha.c        2004-06-26 11:29:31.000000000 +0100
17595 @@ -0,0 +1,122 @@
17596 +/**
17597 + * Prefix advertisement for Home Agent
17598 + *
17599 + * Authors:
17600 + * Jaakko Laine <medved@iki.fi>
17601 + *
17602 + * $Id$
17603 + *
17604 + * This program is free software; you can redistribute it and/or
17605 + * modify it under the terms of the GNU General Public License
17606 + * as published by the Free Software Foundation; either version
17607 + * 2 of the License, or (at your option) any later version.
17608 + */
17609 +
17610 +#include <linux/config.h>
17611 +#include <linux/icmpv6.h>
17612 +#include <linux/net.h>
17613 +#include <linux/spinlock.h>
17614 +#include <linux/timer.h>
17615 +#include <linux/netdevice.h>
17616 +#include <net/ipv6.h>
17617 +#include <net/addrconf.h>
17618 +#include <net/ip6_route.h>
17619 +#include <net/mipv6.h>
17620 +
17621 +#include "mipv6_icmp.h"
17622 +#include "debug.h"
17623 +#include "sortedlist.h"
17624 +#include "util.h"
17625 +#include "bcache.h"
17626 +#include "config.h"
17627 +#include "prefix.h"
17628 +
17629 +/**
17630 + * pfx_adv_iterator - modify pfx_list entries according to new prefix info
17631 + * @data: MN's home registration bcache_entry
17632 + * @args: new prefix info
17633 + * @sortkey: ignored
17634 + */
17635 +static int pfx_adv_iterator(void *data, void *args, unsigned long sortkey)
17636 +{
17637 +       struct mipv6_bce *bc_entry = (struct mipv6_bce *) data;
17638 +       struct prefix_info *pinfo = (struct prefix_info *) args;
17639 +
17640 +       if (mipv6_prefix_compare(&bc_entry->coa, &pinfo->prefix,
17641 +                                pinfo->prefix_len) == 0) {
17642 +               struct pfx_list_entry pfx_entry;
17643 +
17644 +               memcpy(&pfx_entry.daddr, &bc_entry->coa,
17645 +                      sizeof(struct in6_addr));
17646 +               memcpy(&pfx_entry.daddr, &bc_entry->our_addr,
17647 +                      sizeof(struct in6_addr));
17648 +               pfx_entry.retries = 0;
17649 +               pfx_entry.ifindex = bc_entry->ifindex;
17650 +
17651 +               mipv6_slist_modify(&pfx_list, &pfx_entry,
17652 +                                  sizeof(struct pfx_list_entry),
17653 +                                  jiffies +
17654 +                                  net_random() % (MAX_PFX_ADV_DELAY * HZ),
17655 +                                  compare_pfx_list_entry);
17656 +       }
17657 +
17658 +       return 0;
17659 +}
17660 +
17661 +struct homereg_iterator_args {
17662 +       struct list_head *head;
17663 +       int count;
17664 +};
17665 +
17666 +static int homereg_iterator(void *data, void *args, unsigned long *sortkey)
17667 +{
17668 +       struct mipv6_bce *entry = (struct mipv6_bce *) data;
17669 +       struct homereg_iterator_args *state =
17670 +               (struct homereg_iterator_args *) args;
17671 +
17672 +       if (entry->type == HOME_REGISTRATION) {
17673 +               mipv6_slist_add(state->head, entry,
17674 +                               sizeof(struct mipv6_bce),
17675 +                               state->count);
17676 +               state->count++;
17677 +       }
17678 +       return 0;
17679 +}
17680 +
17681 +static int mipv6_bcache_get_homeregs(struct list_head *head)
17682 +{
17683 +       struct homereg_iterator_args args;
17684 +
17685 +       DEBUG_FUNC();
17686 +
17687 +       args.count = 0;
17688 +       args.head = head;
17689 +
17690 +       mipv6_bcache_iterate(homereg_iterator, &args);
17691 +       return args.count;
17692 +}
17693 +
17694 +/**
17695 + * mipv6_prefix_added - prefix was added to interface, act accordingly
17696 + * @pinfo: prefix_info that was added
17697 + * @ifindex: interface index
17698 + */
17699 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex)
17700 +{
17701 +       int count;
17702 +       unsigned long tmp;
17703 +       struct list_head home_regs;
17704 +
17705 +       DEBUG_FUNC();
17706 +
17707 +       INIT_LIST_HEAD(&home_regs);
17708 +
17709 +       if (!(count = mipv6_bcache_get_homeregs(&home_regs)))
17710 +               return;
17711 +
17712 +       write_lock_bh(&pfx_list_lock);
17713 +       mipv6_slist_for_each(&home_regs, pinfo, pfx_adv_iterator);
17714 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17715 +               mod_timer(&pfx_timer, tmp);
17716 +       write_unlock_bh(&pfx_list_lock);
17717 +}
17718 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.c linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.c
17719 --- linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.c    1970-01-01 01:00:00.000000000 +0100
17720 +++ linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.c        2004-06-26 11:29:31.000000000 +0100
17721 @@ -0,0 +1,255 @@
17722 +/*
17723 + *      rr_cookie.c - Mobile IPv6 return routability crypto  
17724 + *      Author :  Henrik Petander <henrik.petander@hut.fi>
17725 + * 
17726 + *      $Id$
17727 + *
17728 + *      This program is free software; you can redistribute it and/or
17729 + *      modify it under the terms of the GNU General Public License
17730 + *      as published by the Free Software Foundation; either version
17731 + *      2 of the License, or (at your option) any later version.
17732 + *
17733 + *
17734 + *
17735 + */
17736 +
17737 +#include <linux/kernel.h>
17738 +#include <linux/types.h>
17739 +#include <linux/spinlock.h>
17740 +#include <linux/sched.h>
17741 +#include <linux/timer.h>
17742 +#include <linux/in6.h>
17743 +#include <linux/init.h>
17744 +#include <linux/random.h>
17745 +
17746 +#include <net/ipv6.h>
17747 +
17748 +#include "debug.h"
17749 +#include "hmac.h"
17750 +#include "rr_crypto.h"
17751 +
17752 +#define DBG_RR 5
17753 +
17754 +u8 k_CN[HMAC_SHA1_KEY_SIZE]; // secret key of CN 
17755 +
17756 +u16 curr_index = 0;
17757 +
17758 +struct nonce_timestamp nonce_table[MAX_NONCES];
17759 +spinlock_t nonce_lock = SPIN_LOCK_UNLOCKED;
17760 +void update_nonces(void);
17761 +
17762 +/** nonce_is_fresh - whether the nonce was generated recently
17763 + *  
17764 + * @non_ts : table entry containing the nonce and a timestamp
17765 + * @interval : if nonce was generated within interval seconds it is fresh
17766 + *
17767 + * Returns 1 if the nonce is fresh, 0 otherwise.
17768 + */
17769 +static int nonce_is_fresh(struct nonce_timestamp *non_ts, unsigned long interval)
17770 +{
17771 +       if (time_before(jiffies, non_ts->timestamp + interval * HZ) && !non_ts->invalid)
17772 +               return 1;
17773 +       return 0;
17774 +}
17775 +void mipv6_rr_invalidate_nonce(u16 nonce_ind)
17776 +{
17777 +       spin_lock_bh(&nonce_lock);
17778 +       if (nonce_ind > MAX_NONCES) {
17779 +               spin_unlock_bh(&nonce_lock);
17780 +               return;
17781 +       }
17782 +       nonce_table[nonce_ind].invalid = 1;
17783 +       spin_unlock_bh(&nonce_lock);
17784 +}
17785 +/* Returns a pointer to a new nonce  */
17786 +struct mipv6_rr_nonce * mipv6_rr_get_new_nonce(void)
17787 +{
17788 +       struct mipv6_rr_nonce *nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17789 +
17790 +       if (!nce)
17791 +               return NULL;
17792 +       // Lock nonces here
17793 +       spin_lock_bh(&nonce_lock);
17794 +       // If nonce is not fresh create new one 
17795 +       if (!nonce_is_fresh(&nonce_table[curr_index], MIPV6_RR_NONCE_LIFETIME)) {
17796 +               // increment the last nonce pointer and create new nonce
17797 +               curr_index++;
17798 +               // Wrap around
17799 +               if (curr_index == MAX_NONCES)
17800 +                       curr_index = 0;
17801 +               // Get random data to fill the nonce data
17802 +               get_random_bytes(nonce_table[curr_index].nonce.data, MIPV6_RR_NONCE_DATA_LENGTH);
17803 +               // Fill the index field
17804 +               nonce_table[curr_index].nonce.index = curr_index;
17805 +               nonce_table[curr_index].invalid = 0;
17806 +               nonce_table[curr_index].timestamp = jiffies;
17807 +       }
17808 +       spin_unlock_bh(&nonce_lock);
17809 +       memcpy(nce, &nonce_table[curr_index].nonce, sizeof(*nce));
17810 +       // Unlock nonces
17811 +       return nce;
17812 +}
17813 +/** mipv6_rr_nonce_get_by_index - returns a nonce for index 
17814 + * @nonce_ind : index of the nonce
17815 + *
17816 + * Returns a nonce or NULL if the nonce index was invalid or the nonce 
17817 + * for the index was not fresh.
17818 + */
17819 +struct mipv6_rr_nonce * mipv6_rr_nonce_get_by_index(u16 nonce_ind)
17820 +{
17821 +       struct mipv6_rr_nonce *nce = NULL;
17822 +       
17823 +       spin_lock_bh(&nonce_lock);
17824 +       if (nonce_ind >= MAX_NONCES) {
17825 +               DEBUG(DBG_WARNING, "Nonce index field from BU invalid");
17826 +
17827 +               /* Here a double of the nonce_lifetime is used for freshness 
17828 +                * verification, since the nonces 
17829 +                * are not created in response to every initiator packet
17830 +                */
17831 +       } else if (nonce_is_fresh(&nonce_table[nonce_ind], 2 * MIPV6_RR_NONCE_LIFETIME)) {
17832 +               nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17833 +               memcpy(nce, &nonce_table[nonce_ind].nonce, sizeof(*nce));
17834 +       }
17835 +       spin_unlock_bh(&nonce_lock);
17836 +
17837 +       return nce;
17838 +}
17839 +
17840 +/* Fills rr test init cookies with random bytes */  
17841 +void mipv6_rr_mn_cookie_create(u8 *cookie)
17842 +{
17843 +       get_random_bytes(cookie, MIPV6_RR_COOKIE_LENGTH);
17844 +}
17845 +
17846 +/** mipv6_rr_cookie_create - builds a home or care-of cookie
17847 + * 
17848 + * @addr : the home or care-of address from HoTI or CoTI
17849 + * @ckie : memory where the cookie is copied to
17850 + * @nce : pointer to a nonce used for the calculation, nce is freed during the function
17851 + *
17852 + */
17853 +int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie,
17854 +               u16 nonce_index)
17855 +{
17856 +       struct ah_processing ah_proc;
17857 +       u8 digest[HMAC_SHA1_HASH_LEN];
17858 +       struct mipv6_rr_nonce *nce;
17859 +
17860 +       if ((nce = mipv6_rr_nonce_get_by_index(nonce_index))== NULL)
17861 +               return -1;
17862 +
17863 +       if (*ckie == NULL && (*ckie = kmalloc(MIPV6_RR_COOKIE_LENGTH,
17864 +                                       GFP_ATOMIC)) == NULL) {
17865 +               kfree(nce);
17866 +               return -1;
17867 +       }
17868 +       /* Calculate the full hmac-sha1 digest from address and nonce using the secret key of cn */
17869 +       
17870 +       if (ah_hmac_sha1_init(&ah_proc, k_CN, HMAC_SHA1_KEY_SIZE) < 0) {
17871 +               DEBUG(DBG_ERROR, "Hmac sha1 initialization failed");
17872 +               kfree(nce);
17873 +               return -1;
17874 +       }
17875 +
17876 +       ah_hmac_sha1_loop(&ah_proc, addr, sizeof(*addr));
17877 +       ah_hmac_sha1_loop(&ah_proc, nce->data,  MIPV6_RR_NONCE_DATA_LENGTH);
17878 +       ah_hmac_sha1_result(&ah_proc, digest);
17879 +
17880 +       
17881 +       /* clean up nonce */
17882 +       kfree(nce);
17883 +
17884 +       /* Copy first 64 bits of hash target to the cookie */ 
17885 +       memcpy(*ckie, digest, MIPV6_RR_COOKIE_LENGTH);
17886 +       return 0;
17887 +}
17888 +
17889 +/** mipv6_rr_key_calc - creates BU authentication key
17890 + * 
17891 + * @hoc : Home Cookie 
17892 + * @coc : Care-of Cookie 
17893 + * 
17894 + * Returns BU authentication key of length HMAC_SHA1_KEY_SIZE  or NULL in error cases, 
17895 + * caller needs to free the key.
17896 + */
17897 +u8 *mipv6_rr_key_calc(u8 *hoc, u8 *coc)
17898 +{
17899 +       
17900 +       u8 *key_bu = kmalloc(HMAC_SHA1_KEY_SIZE, GFP_ATOMIC);
17901 +       SHA1_CTX c;
17902 +
17903 +       if (!key_bu) {
17904 +               DEBUG(DBG_CRITICAL, "Memory allocation failed, could nort create BU authentication key");
17905 +               return NULL;
17906 +       }
17907 +
17908 +       /* Calculate the key from home and care-of cookies 
17909 +        * Kbu = sha1(home_cookie | care-of cookie) 
17910 +        * or KBu = sha1(home_cookie), if MN deregisters
17911 +        */
17912 +       sha1_init(&c);
17913 +       sha1_compute(&c, hoc, MIPV6_RR_COOKIE_LENGTH);
17914 +       if (coc)
17915 +               sha1_compute(&c, coc, MIPV6_RR_COOKIE_LENGTH);
17916 +       sha1_final(&c, key_bu);
17917 +       DEBUG(DBG_RR, "Home and Care-of cookies used for calculating key ");
17918 +       debug_print_buffer(DBG_RR, hoc,  MIPV6_RR_COOKIE_LENGTH);
17919 +       if (coc)        
17920 +               debug_print_buffer(DBG_RR, coc,  MIPV6_RR_COOKIE_LENGTH);
17921 +
17922 +       return key_bu;
17923 +}
17924 +
17925 +void mipv6_rr_init(void)
17926 +{
17927 +       get_random_bytes(k_CN, HMAC_SHA1_KEY_SIZE);
17928 +       memset(nonce_table, 0, MAX_NONCES * sizeof(struct nonce_timestamp));
17929 +}
17930 +
17931 +#ifdef TEST_MIPV6_RR_CRYPTO
17932 +void mipv6_test_rr(void)
17933 +{
17934 +       struct mipv6_rr_nonce *nonce;
17935 +       struct in6_addr a1, a2;
17936 +       int ind1, ind2;
17937 +       u8 *ckie1 = NULL, *ckie2 = NULL;
17938 +       u8 *key_mn = NULL, *key_cn = NULL;
17939 +       mipv6_init_rr();
17940 +
17941 +       nonce = mipv6_rr_get_new_nonce();
17942 +       if (!nonce) {
17943 +               printk("mipv6_rr_get_new_nonce() failed, at 1! \n");
17944 +               return;
17945 +       }
17946 +       mipv6_rr_cookie_create(&a1, &ckie1, nonce->index);
17947 +       ind1 = nonce->index;
17948 +       kfree(nonce);
17949 +
17950 +       nonce = mipv6_rr_get_new_nonce();
17951 +       if (!nonce) {
17952 +               printk("mipv6_rr_get_new_nonce() failed, at 2! \n");
17953 +               return;
17954 +       }
17955 +
17956 +       mipv6_rr_cookie_create(&a2, &ckie2, nonce->index); 
17957 +       ind2 = nonce->index;
17958 +       key_mn =  mipv6_rr_key_calc(ckie1, ckie2);
17959 +
17960 +       /* Create home and coa cookies based on indices */
17961 +       mipv6_rr_cookie_create(&a1, &ckie1, ind1);
17962 +       mipv6_rr_cookie_create(&a2, &ckie2, ind2);
17963 +       key_cn =  mipv6_rr_key_calc(ckie1, ckie2);             
17964 +       if (!key_cn || !key_mn) {
17965 +               printk("creation of secret key failed!\n");
17966 +               return;
17967 +       }
17968 +       if(memcmp(key_cn, key_mn, HMAC_SHA1_KEY_SIZE))
17969 +               printk("mipv6_rr_key_calc produced different keys for MN and CN \n");
17970 +       else
17971 +               printk("mipv6_rr_crypto test OK\n");
17972 +       kfree(nonce);
17973 +       kfree(key_cn);
17974 +       kfree(key_mn);
17975 +}
17976 +#endif
17977 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.h linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.h
17978 --- linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.h    1970-01-01 01:00:00.000000000 +0100
17979 +++ linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.h        2004-06-26 11:29:31.000000000 +0100
17980 @@ -0,0 +1,72 @@
17981 +/*
17982 + *      MIPL Mobile IPv6 Return routability crypto prototypes
17983 + *
17984 + *      $Id:$
17985 + *
17986 + *      This program is free software; you can redistribute it and/or
17987 + *      modify it under the terms of the GNU General Public License
17988 + *      as published by the Free Software Foundation; either version
17989 + *      2 of the License, or (at your option) any later version.
17990 + */
17991 +
17992 +#ifndef _RR_CRYPTO
17993 +#define _RR_CRYPTO
17994 +
17995 +#include <linux/in6.h>
17996 +
17997 +/* Macros and data structures */
17998 +
17999 +#define MIPV6_RR_NONCE_LIFETIME 60 
18000 +#define MIPV6_RR_NONCE_DATA_LENGTH 8
18001 +#define MIPV6_RR_COOKIE_LENGTH 8
18002 +#define COOKIE_SIZE 8
18003 +#define MAX_NONCES 4
18004 +#define HMAC_SHA1_KEY_SIZE 20
18005
18006 +struct mipv6_rr_nonce {
18007 +       u_int16_t index;
18008 +       u_int8_t data[MIPV6_RR_NONCE_DATA_LENGTH];
18009 +};
18010 +
18011 +struct nonce_timestamp {
18012 +       struct  mipv6_rr_nonce nonce;
18013 +       unsigned long timestamp;
18014 +       u_int8_t invalid; 
18015 +};
18016 +
18017 +/* Function definitions */
18018 +
18019 +/* Return 1 if equal, 0 if not */
18020 +static __inline__ int mipv6_equal_cookies(u8 *c1, u8 *c2)
18021 +{
18022 +       return (memcmp(c1, c2, MIPV6_RR_COOKIE_LENGTH) == 0);
18023 +}
18024 +
18025 +/* Function declarations */
18026 +
18027 +/* Create cookie for HoTi and CoTi */
18028 +extern void mipv6_rr_mn_cookie_create(u8 *cookie);
18029 +
18030 +/* Create cookie for HoT and CoT */
18031 +extern int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie, u16 nonce_index);
18032 +
18033 +/* Calculate return routability key from home and care-of cookies, key length is 
18034 + *  HMAC_SHA1_KEY_SIZE  
18035 + */
18036 +extern u_int8_t *mipv6_rr_key_calc(u8 *hoc, u8 *coc);
18037 +
18038 +extern struct mipv6_rr_nonce *mipv6_rr_get_new_nonce(void);
18039 +
18040 +/* For avoiding replay attacks when MN deregisters */
18041 +extern void mipv6_rr_invalidate_nonce(u16 nonce_index);
18042 +/*
18043 + * initializes the return routability crypto
18044 + */
18045 +
18046 +void mipv6_rr_init(void);
18047 +
18048 +#ifdef TEST_MIPV6_RR_CRYPTO
18049 +void mipv6_test_rr(void);
18050 +#endif /* TEST_MIPV6_RR_CRYPTO */
18051 +
18052 +#endif /* RR_CRYPTO */
18053 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.c linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.c
18054 --- linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.c   1970-01-01 01:00:00.000000000 +0100
18055 +++ linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.c       2004-06-26 11:29:31.000000000 +0100
18056 @@ -0,0 +1,349 @@
18057 +/**
18058 + * Sorted list - linked list with sortkey.
18059 + *
18060 + * Authors:
18061 + * Jaakko Laine <medved@iki.fi>
18062 + *
18063 + * $Id$
18064 + *
18065 + * This program is free software; you can redistribute it and/or
18066 + * modify it under the terms of the GNU General Public License
18067 + * as published by the Free Software Foundation; either version
18068 + * 2 of the License, or (at your option) any later version.
18069 + */
18070 +
18071 +#include <linux/kernel.h>
18072 +#include <linux/types.h>
18073 +#include <linux/list.h>
18074 +#include <linux/slab.h>
18075 +#include <linux/spinlock.h>
18076 +#include <linux/string.h>
18077 +
18078 +struct mipv6_sorted_list_entry {
18079 +       struct list_head list;
18080 +       void *data;
18081 +       int datalen;
18082 +       unsigned long sortkey;
18083 +};
18084 +
18085 +/**
18086 + * compare - compares two arbitrary data items
18087 + * @data1: first data item
18088 + * @data2: second data item
18089 + * @datalen: length of data items in bits
18090 + *
18091 + * datalen is in bits!
18092 + */
18093 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen)
18094 +{
18095 +       int n = datalen;
18096 +       __u8 * ptr1 = (__u8 *)data1;
18097 +       __u8 * ptr2 = (__u8 *)data2;
18098 +       
18099 +       for (; n>=0; n-=8, ptr1++, ptr2++) {
18100 +               if (n >= 8) {
18101 +                       if (*ptr1 != *ptr2)
18102 +                               return 0;
18103 +               } else {
18104 +                       if ((*ptr1 ^ *ptr2) & ((~0) << (8 - n)))
18105 +                               return 0;
18106 +               }
18107 +       }
18108 +
18109 +       return 1;
18110 +}
18111 +
18112 +/**
18113 + * mipv6_slist_add - add an entry to sorted list
18114 + * @head: list_head of the sorted list
18115 + * @data: item to store
18116 + * @datalen: length of data (in bytes)
18117 + * @key: sortkey of item
18118 + *
18119 + * Allocates memory for entry and data
18120 + */
18121 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18122 +                   unsigned long sortkey)
18123 +{
18124 +       struct list_head *pos;
18125 +       struct mipv6_sorted_list_entry *entry, *tmp, *next;
18126 +
18127 +       entry = kmalloc(sizeof(struct mipv6_sorted_list_entry), GFP_ATOMIC);
18128 +
18129 +       if (!entry)
18130 +               return -1;
18131 +
18132 +       entry->data = kmalloc(datalen, GFP_ATOMIC);
18133 +
18134 +       if (!entry->data) {
18135 +               kfree(entry);
18136 +               return -1;
18137 +       }
18138 +
18139 +       memcpy(entry->data, data, datalen);
18140 +       entry->datalen = datalen;
18141 +       entry->sortkey = sortkey;
18142 +
18143 +       if ((pos = head->next) == head) {
18144 +               list_add(&entry->list, head);
18145 +               return 0;
18146 +       }
18147 +
18148 +       tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18149 +       if (entry->sortkey < tmp->sortkey) {
18150 +               list_add(&entry->list, head);
18151 +               return 0;
18152 +       }
18153 +
18154 +       for (; pos != head; pos = pos->next) {
18155 +               tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18156 +               if (pos->next == head) {
18157 +                       list_add(&entry->list, &tmp->list);
18158 +                       return 0;
18159 +               }
18160 +               next = list_entry(pos->next, struct mipv6_sorted_list_entry, list);
18161 +               if (entry->sortkey >= tmp->sortkey && entry->sortkey < next->sortkey) {
18162 +                       list_add(&entry->list, &tmp->list);
18163 +                       return 0;
18164 +               }
18165 +       }
18166 +
18167 +       /* never reached */
18168 +       return -1;
18169 +}
18170 +
18171 +/**
18172 + * mipv6_slist_get_first - get the first data item in the list
18173 + * @head: list_head of the sorted list
18174 + *
18175 + * Returns the actual data item, not copy, so don't kfree it
18176 + */
18177 +void *mipv6_slist_get_first(struct list_head *head)
18178 +{
18179 +       struct mipv6_sorted_list_entry *entry;
18180 +
18181 +       if (list_empty(head))
18182 +               return NULL;
18183 +
18184 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18185 +       return entry->data;
18186 +}
18187 +
18188 +/**
18189 + * mipv6_slist_del_first - delete (and get) the first item in list
18190 + * @head: list_head of the sorted list
18191 + *
18192 + * Remember to kfree the item
18193 + */
18194 +void *mipv6_slist_del_first(struct list_head *head)
18195 +{
18196 +       void *tmp;
18197 +       struct mipv6_sorted_list_entry *entry;
18198 +
18199 +       if (list_empty(head))
18200 +               return NULL;
18201 +
18202 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18203 +       tmp = entry->data;
18204 +
18205 +       list_del(head->next);
18206 +       kfree(entry);
18207 +
18208 +       return tmp;
18209 +}
18210 +
18211 +/**
18212 + * mipv6_slist_del_item - delete entry
18213 + * @head: list_head of the sorted list
18214 + * @data: item to delete
18215 + * @compare: function used for comparing the data items
18216 + *
18217 + * compare function needs to have prototype
18218 + * int (*compare)(const void *data1, const void *data2, int datalen)
18219 + */
18220 +int mipv6_slist_del_item(struct list_head *head, void *data,
18221 +                        int (*compare)(const void *data1, const void *data2,
18222 +                                       int datalen))
18223 +{
18224 +       struct list_head *pos;
18225 +       struct mipv6_sorted_list_entry *entry;
18226 +
18227 +       for(pos = head->next; pos != head; pos = pos->next) {
18228 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18229 +               if (compare(data, entry->data, entry->datalen)) {
18230 +                       list_del(pos);
18231 +                       kfree(entry->data);
18232 +                       kfree(entry);
18233 +                       return 0;
18234 +               }
18235 +       }
18236 +
18237 +       return -1;
18238 +}
18239 +
18240 +/**
18241 + * mipv6_slist_get_first_key - get sortkey of the first item
18242 + * @head: list_head of the sorted list
18243 + */
18244 +unsigned long mipv6_slist_get_first_key(struct list_head *head)
18245 +{
18246 +       struct mipv6_sorted_list_entry *entry;
18247 +
18248 +       if (list_empty(head))
18249 +               return 0;
18250 +
18251 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18252 +       return entry->sortkey;
18253 +}
18254 +
18255 +/**
18256 + * mipv6_slist_get_key - get sortkey of the data item
18257 + * @head: list_head of the sorted list
18258 + * @data: the item to search for
18259 + * @compare: function used for comparing the data items
18260 + *
18261 + * compare function needs to have prototype
18262 + * int (*compare)(const void *data1, const void *data2, int datalen)
18263 + */
18264 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18265 +                                 int (*compare)(const void *data1,
18266 +                                                const void *data2,
18267 +                                                int datalen))
18268 +{
18269 +       struct list_head *pos;
18270 +       struct mipv6_sorted_list_entry *entry;
18271 +       
18272 +       for(pos = head->next; pos != head; pos = pos->next) {
18273 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18274 +               if (compare(data, entry->data, entry->datalen))
18275 +                       return entry->sortkey;
18276 +       }
18277 +       
18278 +       return 0;
18279 +}
18280 +
18281 +/**
18282 + * mipv6_slist_get_data - get the data item identified by sortkey
18283 + * @head: list_head of the sorted list
18284 + * @key: sortkey of the item
18285 + *
18286 + * Returns the actual data item, not copy, so don't kfree it
18287 + */
18288 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey)
18289 +{
18290 +       struct list_head *pos;
18291 +       struct mipv6_sorted_list_entry *entry;
18292 +
18293 +       list_for_each(pos, head) {
18294 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18295 +               if (entry->sortkey == sortkey) 
18296 +                       return entry->data;
18297 +       }
18298 +
18299 +       return NULL;
18300 +}
18301 +
18302 +/**
18303 + * reorder_entry - move an entry to a new position according to sortkey
18304 + * @head: list_head of the sorted list
18305 + * @entry_pos: current place of the entry
18306 + * @key: new sortkey
18307 + */
18308 +static void reorder_entry(struct list_head *head, struct list_head *entry_pos,
18309 +                         unsigned long sortkey)
18310 +{
18311 +       struct list_head *pos;
18312 +       struct mipv6_sorted_list_entry *entry;
18313 +
18314 +       list_del(entry_pos);
18315 +
18316 +       for (pos = head->next; pos != head; pos = pos->next) {
18317 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18318 +               if (sortkey >= entry->sortkey) {
18319 +                       list_add(entry_pos, &entry->list);
18320 +                       return;
18321 +               }
18322 +       }
18323 +
18324 +       list_add(entry_pos, head);
18325 +}
18326 +
18327 +/**
18328 + * mipv6_slist_modify - modify data item
18329 + * @head: list_head of the sorted list
18330 + * @data: item, whose sortkey is to be modified
18331 + * @datalen: datalen in bytes
18332 + * @new_key: new sortkey
18333 + * @compare: function used for comparing the data items
18334 + *
18335 + * Compies the new data on top of the old one, if compare function returns
18336 + * true. If there's no matching entry, new one will be created.
18337 + * Compare function needs to have prototype
18338 + * int (*compare)(const void *data1, const void *data2, int datalen)
18339 + */
18340 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18341 +                      unsigned long new_key,
18342 +                      int (*compare)(const void *data1, const void *data2,
18343 +                                     int datalen))
18344 +{
18345 +       struct list_head *pos;
18346 +       struct mipv6_sorted_list_entry *entry;
18347 +
18348 +       for (pos = head->next; pos != head; pos = pos->next) {
18349 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18350 +               if (compare(data, entry->data, datalen)) {
18351 +                       memcpy(entry->data, data, datalen);
18352 +                       entry->sortkey = new_key;
18353 +                       reorder_entry(head, &entry->list, new_key);
18354 +                       return 0;
18355 +               }
18356 +       }
18357 +
18358 +       return mipv6_slist_add(head, data, datalen, new_key);
18359 +}
18360 +
18361 +/**
18362 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18363 + * @head: list_head of the sorted list
18364 + * @new_key: new sortkey
18365 + */
18366 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key)
18367 +{
18368 +       struct mipv6_sorted_list_entry *entry;
18369 +
18370 +       if (list_empty(head))
18371 +               return -1;
18372 +
18373 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18374 +       entry->sortkey = new_key;
18375 +
18376 +       reorder_entry(head, head->next, new_key);
18377 +       return 0;
18378 +}
18379 +
18380 +/**
18381 + * mipv6_slist_for_each - apply func to every item in list
18382 + * @head: list_head of the sorted list
18383 + * @args: args to pass to func
18384 + * @func: function to use
18385 + *
18386 + * function must be of type
18387 + * int (*func)(void *data, void *args, unsigned long sortkey)
18388 + * List iteration will stop once func has been applied to every item
18389 + * or when func returns true
18390 + */
18391 +int mipv6_slist_for_each(struct list_head *head, void *args,
18392 +                        int (*func)(void *data, void *args,
18393 +                                    unsigned long sortkey))
18394 +{
18395 +       struct list_head *pos;
18396 +       struct mipv6_sorted_list_entry *entry;
18397 +
18398 +       list_for_each(pos, head) {
18399 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18400 +               if (func(entry->data, args, entry->sortkey))
18401 +                       break;
18402 +       }
18403 +
18404 +       return 0;
18405 +}
18406 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.h linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.h
18407 --- linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.h   1970-01-01 01:00:00.000000000 +0100
18408 +++ linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.h       2004-06-26 11:29:31.000000000 +0100
18409 @@ -0,0 +1,133 @@
18410 +/*
18411 + *      Sorted list - linked list with sortkey
18412 + *
18413 + *      $Id$
18414 + *
18415 + *      This program is free software; you can redistribute it and/or
18416 + *      modify it under the terms of the GNU General Public License
18417 + *      as published by the Free Software Foundation; either version
18418 + *      2 of the License, or (at your option) any later version.
18419 + */
18420 +
18421 +/**
18422 + * compare - compares two arbitrary data items
18423 + * @data1: first data item
18424 + * @data2: second data item
18425 + * @datalen: length of data items in bits
18426 + *
18427 + * datalen is in bits!
18428 + */
18429 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen);
18430 +
18431 +/**
18432 + * mipv6_slist_add - add an entry to sorted list
18433 + * @head: list_head of the sorted list
18434 + * @data: item to store
18435 + * @datalen: length of data (in bytes)
18436 + * @key: sortkey of item
18437 + *
18438 + * Allocates memory for entry and data
18439 + */
18440 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18441 +                   unsigned long sortkey);
18442 +
18443 +/**
18444 + * mipv6_slist_get_first - get the first data item in the list
18445 + * @head: list_head of the sorted list
18446 + *
18447 + * Returns the actual data item, not copy, so don't kfree it
18448 + */
18449 +void *mipv6_slist_get_first(struct list_head *head);
18450 +
18451 +/**
18452 + * mipv6_slist_del_first - delete (and get) the first item in list
18453 + * @head: list_head of the sorted list
18454 + *
18455 + * Remember to kfree the item
18456 + */
18457 +void *mipv6_slist_del_first(struct list_head *head);
18458 +
18459 +/**
18460 + * mipv6_slist_del_item - delete entry
18461 + * @head: list_head of the sorted list
18462 + * @data: item to delete
18463 + * @compare: function used for comparing the data items
18464 + *
18465 + * compare function needs to have prototype
18466 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18467 + * datalen is in bits
18468 + */
18469 +int mipv6_slist_del_item(struct list_head *head, void *data,
18470 +                        int (*compare)(const void *data1, const void *data2,
18471 +                                       int datalen));
18472 +
18473 +/**
18474 + * mipv6_slist_get_first_key - get sortkey of the first item
18475 + * @head: list_head of the sorted list
18476 + */
18477 +unsigned long mipv6_slist_get_first_key(struct list_head *head);
18478 +
18479 +/**
18480 + * mipv6_slist_get_key - get sortkey of the data item
18481 + * @head: list_head of the sorted list
18482 + * @data: the item to search for
18483 + * @compare: function used for comparing the data items
18484 + *
18485 + * compare function needs to have prototype
18486 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18487 + * datalen is in bits
18488 + */
18489 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18490 +                                 int (*compare)(const void *data1,
18491 +                                                const void *data2,
18492 +                                                int datalen));
18493 +
18494 +/**
18495 + * mipv6_slist_get_data - get the data item identified by sortkey
18496 + * @head: list_head of the sorted list
18497 + * @key: sortkey of the item
18498 + *
18499 + * Returns the actual data item, not copy, so don't kfree it
18500 + */
18501 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey);
18502 +
18503 +/**
18504 + * mipv6_slist_modify - modify data item
18505 + * @head: list_head of the sorted list
18506 + * @data: item, whose sortkey is to be modified
18507 + * @datalen: datalen in bytes
18508 + * @new_key: new sortkey
18509 + * @compare: function used for comparing the data items
18510 + *
18511 + * Compies the new data on top of the old one, if compare function returns
18512 + * non-negative. If there's no matching entry, new one will be created.
18513 + * Compare function needs to have prototype
18514 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18515 + * datalen is in bits.
18516 + */
18517 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18518 +                      unsigned long new_key,
18519 +                      int (*compare)(const void *data1, const void *data2,
18520 +                                     int datalen));
18521 +
18522 +/**
18523 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18524 + * @head: list_head of the sorted list
18525 + * @new_key: new sortkey
18526 + */
18527 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key);
18528 +
18529 +/**
18530 + * mipv6_slist_for_each - apply func to every item in list
18531 + * @head: list_head of the sorted list
18532 + * @args: args to pass to func
18533 + * @func: function to use
18534 + *
18535 + * function must be of type
18536 + * int (*func)(void *data, void *args, unsigned long sortkey)
18537 + * List iteration will stop once func has been applied to every item
18538 + * or when func returns true
18539 + */
18540 +int mipv6_slist_for_each(struct list_head *head, void *args,
18541 +                        int (*func)(void *data, void *args,
18542 +                                    unsigned long sortkey));
18543 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/stats.c linux-2.4.25/net/ipv6/mobile_ip6/stats.c
18544 --- linux-2.4.25.old/net/ipv6/mobile_ip6/stats.c        1970-01-01 01:00:00.000000000 +0100
18545 +++ linux-2.4.25/net/ipv6/mobile_ip6/stats.c    2004-06-26 11:29:32.000000000 +0100
18546 @@ -0,0 +1,90 @@
18547 +/*
18548 + *      Statistics module
18549 + *
18550 + *      Authors:
18551 + *      Sami Kivisaari          <skivisaa@cc.hut.fi>
18552 + *
18553 + *      $Id$
18554 + *
18555 + *      This program is free software; you can redistribute it and/or
18556 + *      modify it under the terms of the GNU General Public License
18557 + *      as published by the Free Software Foundation; either version
18558 + *      2 of the License, or (at your option) any later version.
18559 + *     
18560 + *      Changes:
18561 + *      Krishna Kumar, 
18562 + *      Venkata Jagana   :  SMP locking fix  
18563 + */
18564 +
18565 +#include <linux/config.h>
18566 +#include <linux/proc_fs.h>
18567 +#include "stats.h"
18568 +
18569 +struct mipv6_statistics mipv6_stats;
18570 +
18571 +static int proc_info_dump(
18572 +       char *buffer, char **start,
18573 +       off_t offset, int length)
18574 +{
18575 +       struct inf {
18576 +               char *name;
18577 +               int *value;
18578 +       } int_stats[] = {
18579 +               {"NEncapsulations", &mipv6_stats.n_encapsulations},
18580 +               {"NDecapsulations", &mipv6_stats.n_decapsulations},
18581 +               {"NBindRefreshRqsRcvd", &mipv6_stats.n_brr_rcvd},
18582 +               {"NHomeTestInitsRcvd", &mipv6_stats.n_hoti_rcvd},
18583 +               {"NCareofTestInitsRcvd", &mipv6_stats.n_coti_rcvd},
18584 +               {"NHomeTestRcvd", &mipv6_stats.n_hot_rcvd},
18585 +               {"NCareofTestRcvd", &mipv6_stats.n_cot_rcvd},
18586 +               {"NBindUpdatesRcvd", &mipv6_stats.n_bu_rcvd},
18587 +               {"NBindAcksRcvd", &mipv6_stats.n_ba_rcvd},
18588 +               {"NBindNAcksRcvd", &mipv6_stats.n_ban_rcvd},
18589 +               {"NBindErrorsRcvd", &mipv6_stats.n_be_rcvd},
18590 +               {"NBindRefreshRqsSent", &mipv6_stats.n_brr_sent},
18591 +               {"NHomeTestInitsSent", &mipv6_stats.n_hoti_sent},
18592 +               {"NCareofTestInitsSent", &mipv6_stats.n_coti_sent},
18593 +               {"NHomeTestSent", &mipv6_stats.n_hot_sent},
18594 +               {"NCareofTestSent", &mipv6_stats.n_cot_sent},
18595 +               {"NBindUpdatesSent", &mipv6_stats.n_bu_sent},
18596 +               {"NBindAcksSent", &mipv6_stats.n_ba_sent},
18597 +               {"NBindNAcksSent", &mipv6_stats.n_ban_sent},
18598 +               {"NBindErrorsSent", &mipv6_stats.n_be_sent},
18599 +               {"NBindUpdatesDropAuth", &mipv6_stats.n_bu_drop.auth},
18600 +               {"NBindUpdatesDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18601 +               {"NBindUpdatesDropMisc", &mipv6_stats.n_bu_drop.misc},
18602 +               {"NBindAcksDropAuth", &mipv6_stats.n_bu_drop.auth},
18603 +               {"NBindAcksDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18604 +               {"NBindAcksDropMisc", &mipv6_stats.n_bu_drop.misc},
18605 +               {"NBindRqsDropAuth", &mipv6_stats.n_bu_drop.auth},
18606 +               {"NBindRqsDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18607 +               {"NBindRqsDropMisc", &mipv6_stats.n_bu_drop.misc}
18608 +       };
18609 +
18610 +       int i;
18611 +       int len = 0;
18612 +       for(i=0; i<sizeof(int_stats) / sizeof(struct inf); i++) {
18613 +               len += sprintf(buffer + len, "%s = %d\n",
18614 +                              int_stats[i].name, *int_stats[i].value);
18615 +       }
18616 +
18617 +       *start = buffer + offset;
18618 +
18619 +       len -= offset;
18620 +
18621 +       if(len > length) len = length;
18622 +
18623 +       return len;
18624 +}
18625 +
18626 +int mipv6_stats_init(void)
18627 +{
18628 +       memset(&mipv6_stats, 0, sizeof(struct mipv6_statistics));
18629 +       proc_net_create("mip6_stat", 0, proc_info_dump);
18630 +       return 0;
18631 +}
18632 +
18633 +void mipv6_stats_exit(void)
18634 +{
18635 +       proc_net_remove("mip6_stat");
18636 +}
18637 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/stats.h linux-2.4.25/net/ipv6/mobile_ip6/stats.h
18638 --- linux-2.4.25.old/net/ipv6/mobile_ip6/stats.h        1970-01-01 01:00:00.000000000 +0100
18639 +++ linux-2.4.25/net/ipv6/mobile_ip6/stats.h    2004-06-26 11:29:32.000000000 +0100
18640 @@ -0,0 +1,71 @@
18641 +/*
18642 + *      MIPL Mobile IPv6 Statistics header file
18643 + *
18644 + *      $Id$
18645 + *
18646 + *      This program is free software; you can redistribute it and/or
18647 + *      modify it under the terms of the GNU General Public License
18648 + *      as published by the Free Software Foundation; either version
18649 + *      2 of the License, or (at your option) any later version.
18650 + */
18651 +
18652 +#ifndef _STATS_H
18653 +#define _STATS_H
18654 +
18655 +struct mipv6_drop {
18656 +       __u32 auth;
18657 +       __u32 invalid;
18658 +       __u32 misc;
18659 +};
18660 +
18661 +struct mipv6_statistics {
18662 +       int n_encapsulations;
18663 +       int n_decapsulations;
18664 +       int n_mh_in_msg;
18665 +       int n_mh_in_error;
18666 +       int n_mh_out_msg;
18667 +       int n_mh_out_error;
18668 +
18669 +       int n_brr_rcvd;
18670 +       int n_hoti_rcvd;
18671 +       int n_coti_rcvd;
18672 +       int n_hot_rcvd;
18673 +       int n_cot_rcvd;
18674 +       int n_bu_rcvd;
18675 +       int n_ba_rcvd;
18676 +       int n_ban_rcvd;
18677 +       int n_be_rcvd;
18678 +
18679 +       int n_brr_sent;
18680 +       int n_hoti_sent;
18681 +       int n_coti_sent;
18682 +       int n_hot_sent;
18683 +       int n_cot_sent;
18684 +       int n_bu_sent;
18685 +       int n_ba_sent;
18686 +       int n_ban_sent;
18687 +       int n_be_sent;
18688 +
18689 +       int n_ha_rcvd;
18690 +       int n_ha_sent;
18691 +
18692 +       struct mipv6_drop n_bu_drop;
18693 +       struct mipv6_drop n_ba_drop;
18694 +       struct mipv6_drop n_brr_drop;
18695 +       struct mipv6_drop n_be_drop;
18696 +       struct mipv6_drop n_ha_drop;
18697 +};
18698 +
18699 +extern struct mipv6_statistics mipv6_stats;
18700 +
18701 +#ifdef CONFIG_SMP
18702 +/* atomic_t is max 24 bits long */
18703 +#define MIPV6_INC_STATS(X) atomic_inc((atomic_t *)&mipv6_stats.X);
18704 +#else
18705 +#define MIPV6_INC_STATS(X) mipv6_stats.X++;
18706 +#endif
18707 +
18708 +int mipv6_stats_init(void);
18709 +void mipv6_stats_exit(void);
18710 +
18711 +#endif
18712 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel.h linux-2.4.25/net/ipv6/mobile_ip6/tunnel.h
18713 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel.h       1970-01-01 01:00:00.000000000 +0100
18714 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel.h   2004-06-26 11:29:32.000000000 +0100
18715 @@ -0,0 +1,35 @@
18716 +/*
18717 + *      MIPL Mobile IPv6 IP6-IP6 tunneling header file
18718 + *
18719 + *      $Id$
18720 + *
18721 + *      This program is free software; you can redistribute it and/or
18722 + *      modify it under the terms of the GNU General Public License
18723 + *      as published by the Free Software Foundation; either version
18724 + *      2 of the License, or (at your option) any later version.
18725 + */
18726 +
18727 +#ifndef _TUNNEL_H
18728 +#define _TUNNEL_H
18729 +
18730 +#include <linux/in6.h>
18731 +#include <linux/if_arp.h>
18732 +#include <net/ipv6_tunnel.h>
18733 +
18734 +static __inline__ int is_mip6_tnl(struct ip6_tnl *t)
18735 +{
18736 +       return (t != NULL && 
18737 +               t->parms.flags & IP6_TNL_F_KERNEL_DEV &&
18738 +               t->parms.flags & IP6_TNL_F_MIP6_DEV);
18739 +                       
18740 +}
18741 +
18742 +static __inline__ int dev_is_mip6_tnl(struct net_device *dev)
18743 +{
18744 +       struct ip6_tnl *t = (struct ip6_tnl *)dev->priv;
18745 +       return (dev->type == ARPHRD_TUNNEL6 && is_mip6_tnl(t));
18746 +}
18747 +
18748 +
18749 +#endif
18750 +
18751 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.c linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.c
18752 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.c    1970-01-01 01:00:00.000000000 +0100
18753 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.c        2004-06-26 11:29:32.000000000 +0100
18754 @@ -0,0 +1,264 @@
18755 +/*
18756 + *     IPv6-IPv6 tunneling module
18757 + *
18758 + *     Authors:
18759 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
18760 + *     Ville Nuorvala          <vnuorval@tml.hut.fi>
18761 + *
18762 + *     $Id$
18763 + *
18764 + *     This program is free software; you can redistribute it and/or
18765 + *      modify it under the terms of the GNU General Public License
18766 + *      as published by the Free Software Foundation; either version
18767 + *      2 of the License, or (at your option) any later version.
18768 + *
18769 + */
18770 +
18771 +#include <linux/net.h>
18772 +#include <linux/skbuff.h>
18773 +#include <linux/ipv6.h>
18774 +#include <linux/net.h>
18775 +#include <linux/netdevice.h>
18776 +#include <linux/init.h>
18777 +#include <linux/route.h>
18778 +#include <linux/ipv6_route.h>
18779 +
18780 +#ifdef CONFIG_SYSCTL
18781 +#include <linux/sysctl.h>
18782 +#endif /* CONFIG_SYSCTL */
18783 +
18784 +#include <net/protocol.h>
18785 +#include <net/ipv6.h>
18786 +#include <net/ip6_route.h>
18787 +#include <net/dst.h>
18788 +#include <net/addrconf.h>
18789 +
18790 +#include "tunnel.h"
18791 +#include "debug.h"
18792 +#include "stats.h"
18793 +#include "config.h"
18794 +
18795 +#define MIPV6_TNL_MAX IP6_TNL_MAX
18796 +#define MIPV6_TNL_MIN 1
18797 +
18798 +int mipv6_max_tnls = 3;
18799 +int mipv6_min_tnls = 1;
18800 +
18801 +DECLARE_MUTEX(tnl_sem);
18802 +
18803 +int mipv6_max_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18804 +                         void *buffer, size_t *lenp)
18805 +{
18806 +       int err;
18807 +       
18808 +       DEBUG_FUNC();
18809 +
18810 +       down(&tnl_sem);
18811 +       if (write) {
18812 +               int diff;
18813 +               int old_max_tnls = mipv6_max_tnls;
18814 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18815 +               if (err < 0) 
18816 +                       goto out;
18817 +               if (mipv6_max_tnls < mipv6_min_tnls || 
18818 +                   mipv6_max_tnls > MIPV6_TNL_MAX) {
18819 +                       mipv6_max_tnls = old_max_tnls;
18820 +                       goto out;
18821 +               }
18822 +               if (mipv6_max_tnls < old_max_tnls) {
18823 +                       diff = old_max_tnls - mipv6_max_tnls;
18824 +                       ip6ip6_tnl_dec_max_kdev_count(diff);
18825 +               } else if (mipv6_max_tnls > old_max_tnls) {
18826 +                       diff = mipv6_max_tnls - old_max_tnls;
18827 +                       ip6ip6_tnl_inc_max_kdev_count(diff);
18828 +               }
18829 +       } else {
18830 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18831 +       }
18832 +out:
18833 +       up(&tnl_sem);
18834 +       return err;
18835 +}
18836 +
18837 +int mipv6_min_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18838 +                         void *buffer, size_t *lenp)
18839 +{
18840 +       int err;
18841 +
18842 +       DEBUG_FUNC();
18843 +
18844 +       down(&tnl_sem);
18845 +       if (write) {
18846 +               int diff;
18847 +               int old_min_tnls = mipv6_min_tnls;
18848 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18849 +               if (err < 0) 
18850 +                       goto out;
18851 +               if (mipv6_min_tnls > mipv6_max_tnls || 
18852 +                   mipv6_min_tnls < MIPV6_TNL_MIN) {
18853 +                       mipv6_min_tnls = old_min_tnls;
18854 +                       goto out;
18855 +               }
18856 +               if (mipv6_min_tnls < old_min_tnls) {
18857 +                       diff = old_min_tnls - mipv6_min_tnls;
18858 +                       ip6ip6_tnl_dec_min_kdev_count(diff);
18859 +               } else if (mipv6_min_tnls > old_min_tnls) {
18860 +                       diff = mipv6_min_tnls - old_min_tnls;
18861 +                       ip6ip6_tnl_inc_min_kdev_count(diff);
18862 +               }
18863 +       } else {
18864 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18865 +       }
18866 +out:
18867 +       up(&tnl_sem);
18868 +       return err;
18869 +}
18870 +
18871 +static __inline__ int mipv6_tnl_add(struct in6_addr *remote, 
18872 +                                   struct in6_addr *local) 
18873 +{
18874 +       struct ip6_tnl_parm p;
18875 +       int ret;
18876 +
18877 +       DEBUG_FUNC();
18878 +
18879 +       memset(&p, 0, sizeof(p));
18880 +       p.proto = IPPROTO_IPV6;
18881 +       ipv6_addr_copy(&p.laddr, local);
18882 +       ipv6_addr_copy(&p.raddr, remote);
18883 +       p.hop_limit = 255;
18884 +       p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
18885 +                  IP6_TNL_F_IGN_ENCAP_LIMIT);
18886 +
18887 +       ret = ip6ip6_kernel_tnl_add(&p);
18888 +       if (ret > 0) {
18889 +               DEBUG(DBG_INFO, "added tunnel from: "
18890 +                     "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x", 
18891 +                     NIPV6ADDR(local), NIPV6ADDR(remote));
18892 +       } else {
18893 +               DEBUG(DBG_WARNING, "unable to add tunnel from: "
18894 +                     "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x", 
18895 +                     NIPV6ADDR(local), NIPV6ADDR(remote));             
18896 +       }
18897 +       return ret;
18898 +}
18899 +
18900 +static __inline__ int mipv6_tnl_del(struct in6_addr *remote, 
18901 +                                   struct in6_addr *local) 
18902 +{
18903 +       struct ip6_tnl *t = ip6ip6_tnl_lookup(remote, local);
18904 +       
18905 +       DEBUG_FUNC();
18906 +       
18907 +       if (t != NULL && (t->parms.flags & IP6_TNL_F_MIP6_DEV)) {
18908 +               DEBUG(DBG_INFO, "deleting tunnel from: "
18909 +                     "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x", 
18910 +                     NIPV6ADDR(local), NIPV6ADDR(remote));
18911 +
18912 +               return ip6ip6_kernel_tnl_del(t);
18913 +       }
18914 +       return 0;
18915 +}
18916 +
18917 +static int add_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr, 
18918 +                          struct in6_addr *home_addr) 
18919 +{
18920 +       struct in6_rtmsg rtmsg;
18921 +       int err;
18922 +       struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18923 +       
18924 +       if (!is_mip6_tnl(t)) {
18925 +               DEBUG(DBG_CRITICAL,"Tunnel missing");
18926 +               return -ENODEV;
18927 +       }
18928 +       
18929 +       DEBUG(DBG_INFO, "adding route to: %x:%x:%x:%x:%x:%x:%x:%x via "
18930 +             "tunnel device", NIPV6ADDR(home_addr));
18931 +
18932 +       memset(&rtmsg, 0, sizeof(rtmsg));
18933 +       ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18934 +       rtmsg.rtmsg_dst_len = 128;
18935 +       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
18936 +       rtmsg.rtmsg_flags = RTF_UP | RTF_NONEXTHOP | RTF_HOST | RTF_MOBILENODE;
18937 +       rtmsg.rtmsg_ifindex = t->dev->ifindex;
18938 +       rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18939 +       if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
18940 +               err = 0;
18941 +       }
18942 +       return err;
18943 +}
18944 +
18945 +static void del_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr, 
18946 +                           struct in6_addr *home_addr) 
18947 +{
18948 +       struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18949 +
18950 +       DEBUG_FUNC();
18951 +
18952 +       if (is_mip6_tnl(t)) {
18953 +               struct in6_rtmsg rtmsg;
18954 +
18955 +               DEBUG(DBG_INFO, "deleting route to: %x:%x:%x:%x:%x:%x:%x:%x "
18956 +                     " via tunnel device", NIPV6ADDR(home_addr));
18957 +
18958 +               memset(&rtmsg, 0, sizeof(rtmsg));
18959 +               ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18960 +               rtmsg.rtmsg_dst_len = 128;
18961 +               rtmsg.rtmsg_ifindex = t->dev->ifindex;
18962 +               rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18963 +               ip6_route_del(&rtmsg, NULL);
18964 +       }
18965 +}
18966 +
18967 +
18968 +int mipv6_add_tnl_to_mn(struct in6_addr *coa, 
18969 +                       struct in6_addr *ha_addr,
18970 +                       struct in6_addr *home_addr)
18971 +{
18972 +       int ret;
18973 +
18974 +       DEBUG_FUNC();
18975 +
18976 +       ret = mipv6_tnl_add(coa, ha_addr);
18977 +
18978 +       if (ret > 0) {
18979 +               int err = add_route_to_mn(coa, ha_addr, home_addr);
18980 +               if (err) {
18981 +                       if (err != -ENODEV) {
18982 +                               mipv6_tnl_del(coa, ha_addr);
18983 +                       }
18984 +                       return err;
18985 +               }
18986 +       }
18987 +       return ret;
18988 +} 
18989 +
18990 +int mipv6_del_tnl_to_mn(struct in6_addr *coa, 
18991 +                       struct in6_addr *ha_addr,
18992 +                       struct in6_addr *home_addr)
18993 +{
18994 +       DEBUG_FUNC();
18995 +       del_route_to_mn(coa, ha_addr, home_addr);
18996 +       return mipv6_tnl_del(coa, ha_addr);
18997 +} 
18998 +
18999 +__init void mipv6_initialize_tunnel(void)
19000 +{
19001 +       down(&tnl_sem);
19002 +       ip6ip6_tnl_inc_max_kdev_count(mipv6_max_tnls);
19003 +       ip6ip6_tnl_inc_min_kdev_count(mipv6_min_tnls);
19004 +       up(&tnl_sem);
19005 +       mip6_fn.bce_tnl_rt_add = add_route_to_mn;
19006 +       mip6_fn.bce_tnl_rt_del = del_route_to_mn;
19007 +}
19008 +
19009 +__exit void mipv6_shutdown_tunnel(void)
19010 +{
19011 +       mip6_fn.bce_tnl_rt_del = NULL;
19012 +       mip6_fn.bce_tnl_rt_add = NULL;
19013 +       down(&tnl_sem);
19014 +       ip6ip6_tnl_dec_min_kdev_count(mipv6_min_tnls);
19015 +       ip6ip6_tnl_dec_max_kdev_count(mipv6_max_tnls);
19016 +       up(&tnl_sem);
19017 +}
19018 +
19019 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.h linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.h
19020 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.h    1970-01-01 01:00:00.000000000 +0100
19021 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.h        2004-06-26 11:29:32.000000000 +0100
19022 @@ -0,0 +1,20 @@
19023 +#ifndef _TUNNEL_HA_H
19024 +#define _TUNNEL_HA_H
19025 +
19026 +#include "tunnel.h"
19027 +
19028 +extern int mipv6_max_tnls;
19029 +extern int mipv6_min_tnls;
19030 +
19031 +extern void mipv6_initialize_tunnel(void);
19032 +extern void mipv6_shutdown_tunnel(void);
19033 +
19034 +extern int mipv6_add_tnl_to_mn(struct in6_addr *coa, 
19035 +                              struct in6_addr *ha_addr,
19036 +                              struct in6_addr *home_addr);
19037 +
19038 +extern int mipv6_del_tnl_to_mn(struct in6_addr *coa, 
19039 +                              struct in6_addr *ha_addr,
19040 +                              struct in6_addr *home_addr);
19041 +
19042 +#endif
19043 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.c linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.c
19044 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.c    1970-01-01 01:00:00.000000000 +0100
19045 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.c        2004-06-26 11:29:32.000000000 +0100
19046 @@ -0,0 +1,160 @@
19047 +/*
19048 + *     IPv6-IPv6 tunneling module
19049 + *
19050 + *     Authors:
19051 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
19052 + *     Ville Nuorvala          <vnuorval@tml.hut.fi>
19053 + *
19054 + *     $Id$
19055 + *
19056 + *     This program is free software; you can redistribute it and/or
19057 + *      modify it under the terms of the GNU General Public License
19058 + *      as published by the Free Software Foundation; either version
19059 + *      2 of the License, or (at your option) any later version.
19060 + *
19061 + */
19062 +
19063 +#include <linux/net.h>
19064 +#include <linux/skbuff.h>
19065 +#include <linux/ipv6.h>
19066 +#include <linux/net.h>
19067 +#include <linux/netdevice.h>
19068 +#include <linux/init.h>
19069 +#include <linux/route.h>
19070 +#include <linux/ipv6_route.h>
19071 +
19072 +#ifdef CONFIG_SYSCTL
19073 +#include <linux/sysctl.h>
19074 +#endif /* CONFIG_SYSCTL */
19075 +
19076 +#include <net/protocol.h>
19077 +#include <net/ipv6.h>
19078 +#include <net/ip6_route.h>
19079 +#include <net/dst.h>
19080 +#include <net/addrconf.h>
19081 +
19082 +#include "tunnel.h"
19083 +#include "debug.h"
19084 +#include "stats.h"
19085 +
19086 +static struct net_device *mn_ha_tdev;
19087 +
19088 +static spinlock_t mn_ha_lock = SPIN_LOCK_UNLOCKED;
19089 +
19090 +static __inline__ int add_reverse_route(struct in6_addr *ha_addr,
19091 +                                       struct in6_addr *home_addr, 
19092 +                                       struct net_device *tdev) 
19093 +{
19094 +       struct in6_rtmsg rtmsg;
19095 +       int err;
19096 +
19097 +       DEBUG_FUNC();
19098 +
19099 +       memset(&rtmsg, 0, sizeof(rtmsg));
19100 +       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
19101 +       ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19102 +       rtmsg.rtmsg_src_len = 128;
19103 +       rtmsg.rtmsg_flags = RTF_UP | RTF_DEFAULT;
19104 +       rtmsg.rtmsg_ifindex = tdev->ifindex;
19105 +       rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19106 +       if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
19107 +               return 0;
19108 +       }
19109 +       return err;     
19110 +}
19111 +
19112 +static __inline__ void del_reverse_route(struct in6_addr *ha_addr, 
19113 +                                        struct in6_addr *home_addr,
19114 +                                        struct net_device *tdev) 
19115 +{
19116 +       struct in6_rtmsg rtmsg;
19117 +
19118 +       DEBUG(DBG_INFO, "removing reverse route via tunnel device");
19119 +
19120 +       memset(&rtmsg, 0, sizeof(rtmsg));
19121 +       ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19122 +       rtmsg.rtmsg_src_len = 128;
19123 +       rtmsg.rtmsg_ifindex = tdev->ifindex;
19124 +       rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19125 +       ip6_route_del(&rtmsg, NULL);
19126 +}
19127 +
19128 +int mipv6_add_tnl_to_ha(void)
19129 +{
19130 +       struct ip6_tnl_parm p;
19131 +       struct ip6_tnl *t;
19132 +       int err;
19133 +
19134 +       DEBUG_FUNC();
19135 +
19136 +       memset(&p, 0, sizeof(p));
19137 +       p.proto = IPPROTO_IPV6;
19138 +       p.hop_limit = 255;
19139 +       p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19140 +                  IP6_TNL_F_IGN_ENCAP_LIMIT);
19141 +       strcpy(p.name, "mip6mnha1");
19142 +
19143 +       rtnl_lock();
19144 +       if ((err = ip6ip6_tnl_create(&p, &t))) {
19145 +               rtnl_unlock();
19146 +               return err;
19147 +       }
19148 +       spin_lock_bh(&mn_ha_lock);
19149 +
19150 +       if (!mn_ha_tdev) {
19151 +               mn_ha_tdev = t->dev;
19152 +               dev_hold(mn_ha_tdev);
19153 +       }
19154 +       spin_unlock_bh(&mn_ha_lock);
19155 +       dev_open(t->dev);
19156 +       rtnl_unlock();
19157 +       return 0;
19158 +} 
19159 +
19160 +int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr,
19161 +                      struct in6_addr *coa,
19162 +                      struct in6_addr *home_addr)
19163 +{
19164 +       int err = -ENODEV;
19165 +
19166 +       DEBUG_FUNC();
19167 +
19168 +       spin_lock_bh(&mn_ha_lock);
19169 +       if (mn_ha_tdev) {
19170 +               struct ip6_tnl_parm p;
19171 +               memset(&p, 0, sizeof(p));
19172 +               p.proto = IPPROTO_IPV6;
19173 +               ipv6_addr_copy(&p.laddr, coa);
19174 +               ipv6_addr_copy(&p.raddr, ha_addr);
19175 +               p.hop_limit = 255;
19176 +               p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19177 +                          IP6_TNL_F_IGN_ENCAP_LIMIT);
19178 +
19179 +               ip6ip6_tnl_change((struct ip6_tnl *) mn_ha_tdev->priv, &p);
19180 +               if (ipv6_addr_cmp(coa, home_addr)) {
19181 +                       err = add_reverse_route(ha_addr, home_addr, 
19182 +                                               mn_ha_tdev);
19183 +               } else {
19184 +                       del_reverse_route(ha_addr, home_addr, mn_ha_tdev);
19185 +                       err = 0;
19186 +               }
19187 +       }
19188 +       spin_unlock_bh(&mn_ha_lock);
19189 +       return err;
19190 +}
19191 +
19192 +void mipv6_del_tnl_to_ha(void)
19193 +{
19194 +       struct net_device *dev;
19195 +
19196 +       DEBUG_FUNC();
19197 +
19198 +       rtnl_lock();
19199 +       spin_lock_bh(&mn_ha_lock);
19200 +       dev = mn_ha_tdev;
19201 +       mn_ha_tdev = NULL;
19202 +       spin_unlock_bh(&mn_ha_lock);
19203 +       dev_put(dev);
19204 +       unregister_netdevice(dev);
19205 +       rtnl_unlock();
19206 +}
19207 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.h linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.h
19208 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.h    1970-01-01 01:00:00.000000000 +0100
19209 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.h        2004-06-26 11:29:32.000000000 +0100
19210 @@ -0,0 +1,14 @@
19211 +#ifndef _TUNNEL_MN_H
19212 +#define _TUNNEL_MN_H
19213 +
19214 +#include "tunnel.h"
19215 +
19216 +extern int mipv6_add_tnl_to_ha(void);
19217 +
19218 +extern int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr, 
19219 +                             struct in6_addr *coa,
19220 +                             struct in6_addr *home_addr);
19221 +
19222 +extern int mipv6_del_tnl_to_ha(void);
19223 +
19224 +#endif
19225 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/util.h linux-2.4.25/net/ipv6/mobile_ip6/util.h
19226 --- linux-2.4.25.old/net/ipv6/mobile_ip6/util.h 1970-01-01 01:00:00.000000000 +0100
19227 +++ linux-2.4.25/net/ipv6/mobile_ip6/util.h     2004-06-26 11:29:32.000000000 +0100
19228 @@ -0,0 +1,91 @@
19229 +/*
19230 + *      MIPL Mobile IPv6 Utility functions
19231 + *
19232 + *      $Id$
19233 + *
19234 + *      This program is free software; you can redistribute it and/or
19235 + *      modify it under the terms of the GNU General Public License
19236 + *      as published by the Free Software Foundation; either version
19237 + *      2 of the License, or (at your option) any later version.
19238 + */
19239 +
19240 +#ifndef _UTIL_H
19241 +#define _UTIL_H
19242 +
19243 +#include <linux/in6.h>
19244 +#include <asm/byteorder.h>
19245 +
19246 +/**
19247 + * mipv6_prefix_compare - Compare two IPv6 prefixes
19248 + * @addr: IPv6 address
19249 + * @prefix: IPv6 address
19250 + * @nprefix: number of bits to compare
19251 + *
19252 + * Perform prefix comparison bitwise for the @nprefix first bits
19253 + * Returns 1, if the prefixes are the same, 0 otherwise 
19254 + **/
19255 +static inline int mipv6_prefix_compare(const struct in6_addr *addr,
19256 +                                      const struct in6_addr *prefix, 
19257 +                                      const unsigned int pfix_len)
19258 +{
19259 +       int i;
19260 +       unsigned int nprefix = pfix_len;
19261 +
19262 +       if (nprefix > 128)
19263 +               return 0;
19264 +
19265 +       for (i = 0; nprefix > 0; nprefix -= 32, i++) {
19266 +               if (nprefix >= 32) {
19267 +                       if (addr->s6_addr32[i] != prefix->s6_addr32[i])
19268 +                               return 0;
19269 +               } else {
19270 +                       if (((addr->s6_addr32[i] ^ prefix->s6_addr32[i]) &
19271 +                            ((~0) << (32 - nprefix))) != 0)
19272 +                               return 0;
19273 +                       return 1;
19274 +               }
19275 +       }
19276 +
19277 +       return 1;
19278 +}
19279 +
19280 +/**
19281 + * homeagent_anycast - Compute Home Agent anycast address
19282 + * @ac_addr: append home agent anycast suffix to passed prefix
19283 + * @prefix: prefix ha anycast address is generated from
19284 + * @plen: length of prefix in bits
19285 + *
19286 + * Calculate corresponding Home Agent Anycast Address (RFC2526) in a
19287 + * given subnet.
19288 + */
19289 +static inline int 
19290 +mipv6_ha_anycast(struct in6_addr *ac_addr, struct in6_addr *prefix, int plen)
19291 +{
19292 +       if (plen <= 0 || plen > 120)  {
19293 +               /* error, interface id should be minimum 8 bits */
19294 +               return -1;
19295 +       }
19296 +       ipv6_addr_copy(ac_addr, prefix);
19297 +
19298 +       if (plen < 32)
19299 +               ac_addr->s6_addr32[0] |= htonl((u32)(~0) >> plen);
19300 +       if (plen < 64)
19301 +               ac_addr->s6_addr32[1] |= htonl((u32)(~0) >> (plen > 32 ? plen % 32 : 0));
19302 +       if (plen < 92)
19303 +               ac_addr->s6_addr32[2] |= htonl((u32)(~0) >> (plen > 64 ? plen % 32 : 0));
19304 +       if (plen <= 120)
19305 +               ac_addr->s6_addr32[3] |= htonl((u32)(~0) >> (plen > 92 ? plen % 32 : 0));
19306 +
19307 +       /* RFC2526: for interface identifiers in EUI-64
19308 +        * format, the universal/local bit in the interface
19309 +        * identifier MUST be set to 0. */
19310 +       if (plen == 64) {
19311 +               ac_addr->s6_addr32[2] &= (int)htonl(0xfdffffff);
19312 +       }
19313 +       /* Mobile IPv6 Home-Agents anycast id (0x7e) */
19314 +       ac_addr->s6_addr32[3] &= (int)htonl(0xfffffffe);
19315 +
19316 +       return 0;
19317 +}
19318 +
19319 +#endif /* _UTIL_H */
19320 diff -uprN linux-2.4.25.old/net/ipv6/ndisc.c linux-2.4.25/net/ipv6/ndisc.c
19321 --- linux-2.4.25.old/net/ipv6/ndisc.c   2003-11-28 18:26:21.000000000 +0000
19322 +++ linux-2.4.25/net/ipv6/ndisc.c       2004-06-26 11:29:32.000000000 +0100
19323 @@ -23,6 +23,7 @@
19324   *                                             and moved to net/core.
19325   *     Pekka Savola                    :       RFC2461 validation
19326   *     YOSHIFUJI Hideaki @USAGI        :       Verify ND options properly
19327 + *     Ville Nuorvala                  :       RFC2461 fixes to proxy ND
19328   */
19329  
19330  /* Set to 3 to get tracing... */
19331 @@ -70,6 +71,7 @@
19332  #include <net/ip6_route.h>
19333  #include <net/addrconf.h>
19334  #include <net/icmp.h>
19335 +#include <net/mipglue.h>
19336  
19337  #include <net/checksum.h>
19338  #include <linux/proc_fs.h>
19339 @@ -187,6 +189,8 @@ struct ndisc_options *ndisc_parse_option
19340                 case ND_OPT_TARGET_LL_ADDR:
19341                 case ND_OPT_MTU:
19342                 case ND_OPT_REDIRECT_HDR:
19343 +               case ND_OPT_RTR_ADV_INTERVAL:
19344 +               case ND_OPT_HOME_AGENT_INFO:
19345                         if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
19346                                 ND_PRINTK2((KERN_WARNING
19347                                             "ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
19348 @@ -372,8 +376,8 @@ ndisc_build_ll_hdr(struct sk_buff *skb, 
19349   */
19350  
19351  void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
19352 -                  struct in6_addr *daddr, struct in6_addr *solicited_addr,
19353 -                  int router, int solicited, int override, int inc_opt) 
19354 +               struct in6_addr *daddr, struct in6_addr *solicited_addr, 
19355 +               int router, int solicited, int override, int inc_opt) 
19356  {
19357         static struct in6_addr tmpaddr;
19358         struct inet6_ifaddr *ifp;
19359 @@ -766,7 +770,8 @@ void ndisc_recv_ns(struct sk_buff *skb)
19360                 int addr_type = ipv6_addr_type(saddr);
19361  
19362                 if (in6_dev && in6_dev->cnf.forwarding &&
19363 -                   (addr_type & IPV6_ADDR_UNICAST) &&
19364 +                   (addr_type & IPV6_ADDR_UNICAST || 
19365 +                    addr_type == IPV6_ADDR_ANY) &&
19366                     pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
19367                         int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
19368  
19369 @@ -778,13 +783,21 @@ void ndisc_recv_ns(struct sk_buff *skb)
19370                                         nd_tbl.stats.rcv_probes_mcast++;
19371                                 else
19372                                         nd_tbl.stats.rcv_probes_ucast++;
19373 -                                       
19374 -                               neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19375  
19376 -                               if (neigh) {
19377 -                                       ndisc_send_na(dev, neigh, saddr, &msg->target,
19378 -                                                     0, 1, 0, 1);
19379 -                                       neigh_release(neigh);
19380 +                               if (addr_type & IPV6_ADDR_UNICAST) {            
19381 +                                       neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19382 +
19383 +                                       if (neigh) {
19384 +                                               ndisc_send_na(dev, neigh, saddr, &msg->target,
19385 +                                                             0, 1, 0, 1);
19386 +                                               neigh_release(neigh);
19387 +                                       }
19388 +                               } else {
19389 +                                       /* the proxy should also protect against DAD */
19390 +                                       struct in6_addr maddr;
19391 +                                       ipv6_addr_all_nodes(&maddr);
19392 +                                       ndisc_send_na(dev, NULL, &maddr, &msg->target,
19393 +                                                     0, 0, 0, 1);
19394                                 }
19395                         } else {
19396                                 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
19397 @@ -849,6 +862,9 @@ void ndisc_recv_na(struct sk_buff *skb)
19398                 if (ifp->flags & IFA_F_TENTATIVE) {
19399                         addrconf_dad_failure(ifp);
19400                         return;
19401 +               } else if (ndisc_mip_mn_ha_probe(ifp, lladdr)) {
19402 +                       in6_ifa_put(ifp);
19403 +                       return;
19404                 }
19405                 /* What should we make now? The advertisement
19406                    is invalid, but ndisc specs say nothing
19407 @@ -887,6 +903,7 @@ void ndisc_recv_na(struct sk_buff *skb)
19408                              msg->icmph.icmp6_override, 1);
19409                 neigh_release(neigh);
19410         }
19411 +       ndisc_check_mipv6_dad(&msg->target);
19412  }
19413  
19414  static void ndisc_router_discovery(struct sk_buff *skb)
19415 @@ -894,6 +911,7 @@ static void ndisc_router_discovery(struc
19416          struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
19417         struct neighbour *neigh;
19418         struct inet6_dev *in6_dev;
19419 +       int change_rtr;
19420         struct rt6_info *rt;
19421         int lifetime;
19422         struct ndisc_options ndopts;
19423 @@ -923,10 +941,6 @@ static void ndisc_router_discovery(struc
19424                 ND_PRINTK1("RA: can't find in6 device\n");
19425                 return;
19426         }
19427 -       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19428 -               in6_dev_put(in6_dev);
19429 -               return;
19430 -       }
19431  
19432         if (!ndisc_parse_options(opt, optlen, &ndopts)) {
19433                 in6_dev_put(in6_dev);
19434 @@ -935,7 +949,12 @@ static void ndisc_router_discovery(struc
19435                                    "ICMP6 RA: invalid ND option, ignored.\n");
19436                 return;
19437         }
19438 +       change_rtr = ndisc_mipv6_ra_rcv(skb, &ndopts);
19439  
19440 +       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19441 +               in6_dev_put(in6_dev);
19442 +               return;
19443 +       }
19444         if (in6_dev->if_flags & IF_RS_SENT) {
19445                 /*
19446                  *      flag that an RA was received after an RS was sent
19447 @@ -963,8 +982,7 @@ static void ndisc_router_discovery(struc
19448                 ip6_del_rt(rt, NULL);
19449                 rt = NULL;
19450         }
19451 -
19452 -       if (rt == NULL && lifetime) {
19453 +       if (rt == NULL && lifetime && change_rtr) {
19454                 ND_PRINTK2("ndisc_rdisc: adding default router\n");
19455  
19456                 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
19457 @@ -1087,6 +1105,8 @@ out:
19458         if (rt)
19459                 dst_release(&rt->u.dst);
19460         in6_dev_put(in6_dev);
19461 +
19462 +       ndisc_mipv6_change_router(change_rtr);
19463  }
19464  
19465  static void ndisc_redirect_rcv(struct sk_buff *skb)
19466 diff -uprN linux-2.4.25.old/net/ipv6/raw.c linux-2.4.25/net/ipv6/raw.c
19467 --- linux-2.4.25.old/net/ipv6/raw.c     2003-11-28 18:26:21.000000000 +0000
19468 +++ linux-2.4.25/net/ipv6/raw.c 2004-06-26 11:29:32.000000000 +0100
19469 @@ -43,6 +43,7 @@
19470  #include <net/transp_v6.h>
19471  #include <net/udp.h>
19472  #include <net/inet_common.h>
19473 +#include <net/mipglue.h>
19474  
19475  #include <net/rawv6.h>
19476  
19477 @@ -636,6 +637,7 @@ static int rawv6_sendmsg(struct sock *sk
19478                         hdr.daddr = daddr;
19479                 else
19480                         hdr.daddr = NULL;
19481 +               hdr.daddr = mipv6_get_fake_hdr_daddr(hdr.daddr, daddr);
19482  
19483                 err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
19484                                      opt, hlimit, msg->msg_flags);
19485 diff -uprN linux-2.4.25.old/net/ipv6/route.c linux-2.4.25/net/ipv6/route.c
19486 --- linux-2.4.25.old/net/ipv6/route.c   2004-02-18 13:36:32.000000000 +0000
19487 +++ linux-2.4.25/net/ipv6/route.c       2004-06-26 11:29:32.000000000 +0100
19488 @@ -49,6 +49,7 @@
19489  #include <net/addrconf.h>
19490  #include <net/tcp.h>
19491  #include <linux/rtnetlink.h>
19492 +#include <net/mipglue.h>
19493  
19494  #include <asm/uaccess.h>
19495  
19496 @@ -363,12 +364,8 @@ static struct rt6_info *rt6_cow(struct r
19497                 rt->u.dst.flags |= DST_HOST;
19498  
19499  #ifdef CONFIG_IPV6_SUBTREES
19500 -               if (rt->rt6i_src.plen && saddr) {
19501 -                       ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
19502 -                       rt->rt6i_src.plen = 128;
19503 -               }
19504 +               rt->rt6i_src.plen = ort->rt6i_src.plen;
19505  #endif
19506 -
19507                 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
19508  
19509                 dst_hold(&rt->u.dst);
19510 @@ -511,14 +508,19 @@ struct dst_entry * ip6_route_output(stru
19511         struct rt6_info *rt;
19512         int strict;
19513         int attempts = 3;
19514 +       struct in6_addr *saddr;
19515  
19516 +       if (ipv6_chk_addr(fl->nl_u.ip6_u.daddr, NULL))
19517 +               saddr = NULL;
19518 +       else
19519 +               saddr = fl->nl_u.ip6_u.saddr;
19520 +               
19521         strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
19522  
19523  relookup:
19524         read_lock_bh(&rt6_lock);
19525  
19526 -       fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
19527 -                        fl->nl_u.ip6_u.saddr);
19528 +       fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr, saddr);
19529  
19530  restart:
19531         rt = fn->leaf;
19532 @@ -663,25 +665,6 @@ out:
19533         return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size);
19534  }
19535  
19536 -/* Clean host part of a prefix. Not necessary in radix tree,
19537 -   but results in cleaner routing tables.
19538 -
19539 -   Remove it only when all the things will work!
19540 - */
19541 -
19542 -static void ipv6_addr_prefix(struct in6_addr *pfx,
19543 -                            const struct in6_addr *addr, int plen)
19544 -{
19545 -       int b = plen&0x7;
19546 -       int o = plen>>3;
19547 -
19548 -       memcpy(pfx->s6_addr, addr, o);
19549 -       if (o < 16)
19550 -               memset(pfx->s6_addr + o, 0, 16 - o);
19551 -       if (b != 0)
19552 -               pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b);
19553 -}
19554 -
19555  static int ipv6_get_mtu(struct net_device *dev)
19556  {
19557         int mtu = IPV6_MIN_MTU;
19558 @@ -810,7 +793,7 @@ int ip6_route_add(struct in6_rtmsg *rtms
19559                         if (!(gwa_type&IPV6_ADDR_UNICAST))
19560                                 goto out;
19561  
19562 -                       grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);
19563 +                       grt = rt6_lookup(gw_addr, &rtmsg->rtmsg_src, rtmsg->rtmsg_ifindex, 1);
19564  
19565                         err = -EHOSTUNREACH;
19566                         if (grt == NULL)
19567 @@ -848,7 +831,15 @@ int ip6_route_add(struct in6_rtmsg *rtms
19568                         goto out;
19569                 }
19570         }
19571 -
19572 +#ifdef USE_IPV6_MOBILITY
19573 +        /* If destination is mobile node, add special skb->dst->input
19574 +         * function for proxy ND.
19575 +         */
19576 +        if (rtmsg->rtmsg_flags & RTF_MOBILENODE) {
19577 +                rt->u.dst.input = ip6_mipv6_forward;
19578 +        }
19579 +#endif /* CONFIG_IPV6_MOBILITY */
19580 +         
19581         if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
19582                 rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;
19583         else
19584 @@ -936,7 +927,7 @@ void rt6_redirect(struct in6_addr *dest,
19585         struct rt6_info *rt, *nrt;
19586  
19587         /* Locate old route to this destination. */
19588 -       rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
19589 +       rt = rt6_lookup(dest, saddr, neigh->dev->ifindex, 1);
19590  
19591         if (rt == NULL)
19592                 return;
19593 @@ -1003,6 +994,9 @@ source_ok:
19594         nrt = ip6_rt_copy(rt);
19595         if (nrt == NULL)
19596                 goto out;
19597 +#ifdef CONFIG_IPV6_SUBTREES
19598 +       nrt->rt6i_src.plen = rt->rt6i_src.plen;
19599 +#endif
19600  
19601         nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
19602         if (on_link)
19603 @@ -1104,6 +1098,9 @@ void rt6_pmtu_discovery(struct in6_addr 
19604                 nrt = ip6_rt_copy(rt);
19605                 if (nrt == NULL)
19606                         goto out;
19607 +#ifdef CONFIG_IPV6_SUBTREES
19608 +               nrt->rt6i_src.plen = rt->rt6i_src.plen;
19609 +#endif
19610                 ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
19611                 nrt->rt6i_dst.plen = 128;
19612                 nrt->u.dst.flags |= DST_HOST;
19613 diff -uprN linux-2.4.25.old/net/ipv6/tcp_ipv6.c linux-2.4.25/net/ipv6/tcp_ipv6.c
19614 --- linux-2.4.25.old/net/ipv6/tcp_ipv6.c        2003-11-28 18:26:21.000000000 +0000
19615 +++ linux-2.4.25/net/ipv6/tcp_ipv6.c    2004-06-26 11:29:32.000000000 +0100
19616 @@ -50,6 +50,7 @@
19617  #include <net/addrconf.h>
19618  #include <net/ip6_route.h>
19619  #include <net/inet_ecn.h>
19620 +#include <net/mipglue.h>
19621  
19622  #include <asm/uaccess.h>
19623  
19624 @@ -557,6 +558,7 @@ static int tcp_v6_connect(struct sock *s
19625         struct flowi fl;
19626         struct dst_entry *dst;
19627         int addr_type;
19628 +       int reroute = 0;
19629         int err;
19630  
19631         if (addr_len < SIN6_LEN_RFC2133) 
19632 @@ -660,7 +662,7 @@ static int tcp_v6_connect(struct sock *s
19633  
19634         fl.proto = IPPROTO_TCP;
19635         fl.fl6_dst = &np->daddr;
19636 -       fl.fl6_src = saddr;
19637 +       fl.fl6_src = saddr; 
19638         fl.oif = sk->bound_dev_if;
19639         fl.uli_u.ports.dport = usin->sin6_port;
19640         fl.uli_u.ports.sport = sk->sport;
19641 @@ -669,31 +671,46 @@ static int tcp_v6_connect(struct sock *s
19642                 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19643                 fl.nl_u.ip6_u.daddr = rt0->addr;
19644         }
19645 -
19646         dst = ip6_route_output(sk, &fl);
19647 -
19648 +#ifdef CONFIG_IPV6_SUBTREES
19649 +       reroute = (saddr == NULL);
19650 +#endif
19651         if ((err = dst->error) != 0) {
19652                 dst_release(dst);
19653                 goto failure;
19654         }
19655 -
19656 -       ip6_dst_store(sk, dst, NULL);
19657 -       sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19658 -
19659 +       if (!reroute) {
19660 +               ip6_dst_store(sk, dst, NULL, NULL);
19661 +               sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19662 +       }
19663         if (saddr == NULL) {
19664                 err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
19665 +
19666 +               if (reroute)
19667 +                       dst_release(dst);
19668                 if (err)
19669                         goto failure;
19670  
19671                 saddr = &saddr_buf;
19672 +               ipv6_addr_copy(&np->rcv_saddr, saddr);
19673 +#ifdef CONFIG_IPV6_SUBTREES
19674 +               fl.fl6_src = saddr; 
19675 +               dst = ip6_route_output(sk, &fl);
19676 +
19677 +               if ((err = dst->error) != 0) {
19678 +                       dst_release(dst);
19679 +                       goto failure;
19680 +               }
19681 +               ip6_dst_store(sk, dst, NULL, NULL);
19682 +               sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19683 +#endif
19684         }
19685  
19686         /* set the source address */
19687 -       ipv6_addr_copy(&np->rcv_saddr, saddr);
19688         ipv6_addr_copy(&np->saddr, saddr);
19689         sk->rcv_saddr= LOOPBACK4_IPV6;
19690  
19691 -       tp->ext_header_len = 0;
19692 +       tp->ext_header_len = tcp_v6_get_mipv6_header_len();
19693         if (np->opt)
19694                 tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen;
19695         tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
19696 @@ -1338,7 +1355,7 @@ static struct sock * tcp_v6_syn_recv_soc
19697  #endif
19698         MOD_INC_USE_COUNT;
19699  
19700 -       ip6_dst_store(newsk, dst, NULL);
19701 +       ip6_dst_store(newsk, dst, NULL, NULL);
19702         sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19703  
19704         newtp = &(newsk->tp_pinfo.af_tcp);
19705 @@ -1383,7 +1400,7 @@ static struct sock * tcp_v6_syn_recv_soc
19706                         sock_kfree_s(sk, opt, opt->tot_len);
19707         }
19708  
19709 -       newtp->ext_header_len = 0;
19710 +       newtp->ext_header_len = tcp_v6_get_mipv6_header_len();
19711         if (np->opt)
19712                 newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen;
19713  
19714 @@ -1710,7 +1727,7 @@ static int tcp_v6_rebuild_header(struct 
19715                         return err;
19716                 }
19717  
19718 -               ip6_dst_store(sk, dst, NULL);
19719 +               ip6_dst_store(sk, dst, NULL, NULL);
19720                 sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19721         }
19722  
19723 @@ -1749,7 +1766,7 @@ static int tcp_v6_xmit(struct sk_buff *s
19724                         return -sk->err_soft;
19725                 }
19726  
19727 -               ip6_dst_store(sk, dst, NULL);
19728 +               ip6_dst_store(sk, dst, NULL, NULL);
19729         }
19730  
19731         skb->dst = dst_clone(dst);
19732 diff -uprN linux-2.4.25.old/net/ipv6/udp.c linux-2.4.25/net/ipv6/udp.c
19733 --- linux-2.4.25.old/net/ipv6/udp.c     2004-02-18 13:36:32.000000000 +0000
19734 +++ linux-2.4.25/net/ipv6/udp.c 2004-06-26 11:29:32.000000000 +0100
19735 @@ -48,6 +48,7 @@
19736  #include <net/ip.h>
19737  #include <net/udp.h>
19738  #include <net/inet_common.h>
19739 +#include <net/mipglue.h>
19740  
19741  #include <net/checksum.h>
19742  
19743 @@ -232,6 +233,7 @@ int udpv6_connect(struct sock *sk, struc
19744         struct ip6_flowlabel    *flowlabel = NULL;
19745         int                     addr_type;
19746         int                     err;
19747 +       int                     reroute = 0;
19748  
19749         if (usin->sin6_family == AF_INET) {
19750                 if (__ipv6_only_sock(sk))
19751 @@ -331,7 +333,7 @@ ipv4_connected:
19752  
19753         fl.proto = IPPROTO_UDP;
19754         fl.fl6_dst = &np->daddr;
19755 -       fl.fl6_src = &saddr;
19756 +       fl.fl6_src = NULL;
19757         fl.oif = sk->bound_dev_if;
19758         fl.uli_u.ports.dport = sk->dport;
19759         fl.uli_u.ports.sport = sk->sport;
19760 @@ -348,29 +350,44 @@ ipv4_connected:
19761                 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19762                 fl.fl6_dst = rt0->addr;
19763         }
19764 -
19765         dst = ip6_route_output(sk, &fl);
19766 -
19767         if ((err = dst->error) != 0) {
19768                 dst_release(dst);
19769                 fl6_sock_release(flowlabel);
19770 -               return err;
19771 -       }
19772 -
19773 -       ip6_dst_store(sk, dst, fl.fl6_dst);
19774 -
19775 +               return err; 
19776 +       } 
19777 +#ifdef CONFIG_IPV6_SUBTREES
19778 +       reroute = (fl.fl6_src == NULL);
19779 +#endif
19780         /* get the source adddress used in the apropriate device */
19781  
19782         err = ipv6_get_saddr(dst, daddr, &saddr);
19783  
19784 +       if (reroute)
19785 +               dst_release(dst);
19786 +
19787         if (err == 0) {
19788 -               if(ipv6_addr_any(&np->saddr))
19789 +#ifdef CONFIG_IPV6_SUBTREES
19790 +               if (reroute) {
19791 +                       fl.fl6_src = &saddr;
19792 +                       dst = ip6_route_output(sk, &fl);
19793 +                       if ((err = dst->error) != 0) {
19794 +                               dst_release(dst);
19795 +                               fl6_sock_release(flowlabel);
19796 +                               return err; 
19797 +                       } 
19798 +               }
19799 +#endif
19800 +               if(ipv6_addr_any(&np->saddr)) {
19801                         ipv6_addr_copy(&np->saddr, &saddr);
19802 -
19803 +                       fl.fl6_src = &np->saddr;
19804 +               }
19805                 if(ipv6_addr_any(&np->rcv_saddr)) {
19806                         ipv6_addr_copy(&np->rcv_saddr, &saddr);
19807                         sk->rcv_saddr = LOOPBACK4_IPV6;
19808                 }
19809 +               ip6_dst_store(sk, dst, fl.fl6_dst, 
19810 +                             fl.fl6_src == &np->saddr ? fl.fl6_src : NULL);
19811                 sk->state = TCP_ESTABLISHED;
19812         }
19813         fl6_sock_release(flowlabel);
19814 @@ -894,6 +911,7 @@ static int udpv6_sendmsg(struct sock *sk
19815                 opt = fl6_merge_options(&opt_space, flowlabel, opt);
19816         if (opt && opt->srcrt)
19817                 udh.daddr = daddr;
19818 +       udh.daddr = mipv6_get_fake_hdr_daddr(udh.daddr, daddr);
19819  
19820         udh.uh.source = sk->sport;
19821         udh.uh.len = len < 0x10000 ? htons(len) : 0;
19822 diff -uprN linux-2.4.25.old/net/netsyms.c linux-2.4.25/net/netsyms.c
19823 --- linux-2.4.25.old/net/netsyms.c      2003-11-28 18:26:21.000000000 +0000
19824 +++ linux-2.4.25/net/netsyms.c  2004-06-26 11:29:32.000000000 +0100
19825 @@ -190,6 +190,7 @@ EXPORT_SYMBOL(neigh_sysctl_register);
19826  #endif
19827  EXPORT_SYMBOL(pneigh_lookup);
19828  EXPORT_SYMBOL(pneigh_enqueue);
19829 +EXPORT_SYMBOL(pneigh_delete);
19830  EXPORT_SYMBOL(neigh_destroy);
19831  EXPORT_SYMBOL(neigh_parms_alloc);
19832  EXPORT_SYMBOL(neigh_parms_release);