1 /* $KAME: mip6_md.c,v 1.14 2000/03/25 07:23:53 sumikawa Exp $ */
4 * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB
34 * All rights reserved.
36 * Author: Mattias Pettersson <mattias.pettersson@era.ericsson.se>
40 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
45 * Mobile IPv6 Movement Detection for Mobile Nodes
47 #include <sys/param.h>
48 #include <sys/malloc.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <sys/syslog.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
55 #include <sys/domain.h>
56 #include <sys/protosw.h>
59 #include <net/if_types.h>
60 #include <net/route.h>
62 #include <netinet/in.h>
63 #include <netinet/ip6.h>
64 #include <netinet6/in6_var.h>
65 #include <netinet6/ip6_var.h>
66 #include <netinet6/ip6protosw.h>
67 #include <netinet6/nd6.h>
68 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
69 #include <netinet/in_pcb.h>
71 #include <netinet6/in6_pcb.h>
72 #include <netinet6/mip6.h>
74 #include <net/net_osdep.h>
76 struct nd_prefix
*mip6_home_prefix
;
77 struct nd_prefix
*mip6_primary_prefix
;
78 struct in6_addr mip6_primary_defrtr
;
79 int mip6_md_state
= MIP6_MD_UNDEFINED
;
81 * Mobile IPv6 Home Address route state for the Mobile Node.
82 * route_state NET == MD_HOME == network route.
83 * route_state HOST == MD_FOREIGN|UNDEFINED == host route.
85 int mip6_route_state
= MIP6_ROUTE_NET
; /* According to MD_UNDEFINED state. */
86 int mip6_max_lost_advints
= MIP6_MAX_LOST_ADVINTS
;
87 int mip6_nd6_delay
= 0;
88 int mip6_nd6_umaxtries
= 0;
92 ******************************************************************************
93 * Function: mip6_tell_em
94 * Description: Print state change and tell event-state machine.
96 ******************************************************************************
99 mip6_tell_em(int state
,
100 struct nd_prefix
*hp
,
101 struct nd_prefix
*pp
,
102 struct nd_defrouter
*dr
)
105 mip6_debug("\nNew state: ");
108 mip6_debug("HOME!\n");
110 case MIP6_MD_FOREIGN
:
111 mip6_debug("FOREIGN!\n");
113 case MIP6_MD_UNDEFINED
:
114 mip6_debug("UNDEFINED!\n");
117 mip6_debug("Home Prefix = %s\n", hp
? ip6_sprintf(
118 &hp
->ndpr_prefix
.sin6_addr
) : "NULL");
119 mip6_debug("Primary Prefix = %s\n", pp
? ip6_sprintf(
120 &pp
->ndpr_prefix
.sin6_addr
) : "NULL");
121 mip6_debug("Default Router = %s\n", dr
? ip6_sprintf(
122 &dr
->rtaddr
) : "NULL");
124 mip6_new_defrtr(state
, hp
, pp
, dr
);
129 ******************************************************************************
130 * Function: mip6_md_init
131 * Description: Scan through the Event-State Machine List.
132 * Create a Home Prefix and a Home Address for the Mobile Node
133 * and add it to the prefix list (or just update it if the prefix
134 * is already existing). Detect which initial Movement Detection
135 * state we are in (HOME, FOREIGN or UNDEFINED) and tell the
136 * event-state machine.
138 ******************************************************************************
143 struct nd_prefix
*pr
, *existing_pr
= NULL
;
144 struct nd_defrouter
*dr
;
145 struct in6_ifaddr
*ia
;
146 struct mip6_esm
*esp
; /* Entry in the Event State machine list */
149 for (esp
= mip6_esmq
; esp
; esp
= esp
->next
) {
152 * Add the home prefix statically to the prefix list.
153 * Code taken from prelist_update(), prelist_add() and
156 pr
= (struct nd_prefix
*)MALLOC(sizeof(*pr
), M_TEMP
, M_WAITOK
);
158 log(LOG_ERR
, "mip6_md_init: no mem for home prefix\n");
160 bzero(pr
, sizeof(*pr
));
162 pr
->ndpr_ifp
= esp
->ifp
;
163 pr
->ndpr_plen
= esp
->prefix_len
;
165 pr
->ndpr_prefix
.sin6_family
= AF_INET6
;
166 pr
->ndpr_prefix
.sin6_len
= sizeof(pr
->ndpr_prefix
);
167 pr
->ndpr_prefix
.sin6_addr
= esp
->home_addr
;
168 in6_prefixlen2mask(&pr
->ndpr_mask
, pr
->ndpr_plen
);
170 /* make prefix in the canonical form */
171 for (i
= 0; i
< 4; i
++)
172 pr
->ndpr_prefix
.sin6_addr
.s6_addr32
[i
] &=
173 pr
->ndpr_mask
.s6_addr32
[i
];
175 /* TODO: link into interface prefix list */
177 /* Default settings for unadvertised home prefix */
178 pr
->ndpr_raf_onlink
= 0;
179 pr
->ndpr_raf_auto
= 0;
182 * If home prefix already exists in prefix list, use that
185 if ( (existing_pr
= prefix_lookup(pr
)) ) {
190 /* Update (or set) certain fields in the home prefix */
191 pr
->ndpr_vltime
= ND6_INFINITE_LIFETIME
;
192 pr
->ndpr_pltime
= ND6_INFINITE_LIFETIME
;
194 if (in6_init_prefix_ltimes(pr
)) {
195 log(LOG_ERR
, "mip6_md_init: bad lifetimes\n");
200 s
= splnet(); /* Must be before goto statement */
202 if (existing_pr
!= NULL
) {
204 mip6_debug("mip6_md_init: Home prefix already exists, "
205 "no need to create new prefix.\n");
207 goto skip_initialization
;
210 /* New prefix, fix all initialization. */
212 pr
->ndpr_statef_onlink
= 0; /* Should be 0 since there
215 LIST_INIT(&pr
->ndpr_advrtrs
);
219 /* If an autoconfigured address exists for pr, delete it */
220 if (existing_pr
!= NULL
) {
221 if (!IN6_IS_ADDR_UNSPECIFIED(&pr
->ndpr_addr
)) {
222 ia
= in6ifa_ifpwithaddr(pr
->ndpr_ifp
,
225 error
= mip6_delete_ifaddr(
226 &ia
->ia_addr
.sin6_addr
,
229 printf("%s: address assignment"
232 __FUNCTION__
, error
);
237 pr
->ndpr_addr
= esp
->home_addr
;
239 if (existing_pr
== NULL
) {
240 /* link ndpr_entry to nd_prefix list */
241 LIST_INSERT_HEAD(&nd_prefix
, pr
, ndpr_entry
);
246 if (esp
!= mip6_esmq
) {
248 mip6_debug("%s: Only supporting one home address in this "
249 "version.\n", __FUNCTION__
);
252 mip6_home_prefix
= pr
;
254 dr
= TAILQ_FIRST(&nd_defrouter
);
255 /* XXXYYY Add check for probably reachable router here as well. Mattias */
256 if (pr
->ndpr_advrtrs
.lh_first
&& dr
&&
257 pfxrtr_lookup(pr
, dr
)) {
258 /* If we have home pfxrtrs and defrtr is one of these, then
260 mip6_md_state
= MIP6_MD_HOME
;
261 /* XXX BUG ALERT: missing curly brace? */
262 if ((error
= mip6_add_ifaddr(&pr
->ndpr_addr
, pr
->ndpr_ifp
, 64,
263 IN6_IFF_NODAD
)) != 0)
264 printf("%s: address assignment error (errno = %d).\n",
265 __FUNCTION__
, error
);
266 mip6_route_state
= MIP6_ROUTE_NET
;
267 mip6_primary_prefix
= mip6_home_prefix
;
268 mip6_primary_defrtr
= dr
->rtaddr
;
270 mip6_tell_em(MIP6_MD_HOME
, mip6_home_prefix
, NULL
, dr
);
274 mip6_md_state
= MIP6_MD_FOREIGN
;
275 if ((error
= mip6_add_ifaddr(
276 &pr
->ndpr_addr
, pr
->ndpr_ifp
, 128,
277 IN6_IFF_NODAD
)) != 0)
278 printf("%s: address assignment error "
280 __FUNCTION__
, error
);
281 mip6_route_state
= MIP6_ROUTE_HOST
;
283 for (pr
= nd_prefix
.lh_first
; pr
; pr
= pr
->ndpr_next
) {
284 if ((pfxrtr_lookup(pr
, dr
) != NULL
) &&
285 !IN6_IS_ADDR_UNSPECIFIED(&pr
->ndpr_addr
)&&
286 !IN6_IS_ADDR_MULTICAST(&pr
->ndpr_addr
) &&
287 !IN6_IS_ADDR_LINKLOCAL(&pr
->ndpr_addr
)) {
292 mip6_primary_prefix
= pr
;
293 mip6_primary_defrtr
= dr
->rtaddr
;
294 mip6_tell_em(MIP6_MD_FOREIGN
, mip6_home_prefix
,
299 mip6_debug("%s: At FOREIGN, but no primary "
300 "prefix found!\n", __FUNCTION__
);
307 mip6_md_state
= MIP6_MD_UNDEFINED
;
308 if ((error
= mip6_add_ifaddr(&pr
->ndpr_addr
,
310 IN6_IFF_NODAD
)) != 0)
311 printf("%s: address assignment error "
312 "(errno = %d).\n", __FUNCTION__
, error
);
313 mip6_route_state
= MIP6_ROUTE_NET
;
314 mip6_primary_defrtr
= in6addr_any
;
315 mip6_primary_prefix
= NULL
;
317 mip6_tell_em(MIP6_MD_UNDEFINED
, mip6_home_prefix
,
327 ******************************************************************************
328 * Function: mip6_select_defrtr
329 * Description: Usually called as an extension to defrtrlist_del() when the
330 * previous primary default router times out. Tries to select a
331 * new default router that announces the Home Prefix if available.
332 * Manages the Movement Detection state transitions and
333 * reconfigures the Home Address with host or network route.
334 * Finally informs the event-state machine about any transitions
335 * and new default routers.
337 ******************************************************************************
342 struct nd_prefix
*pr
= NULL
/*, *prev_primary_prefix*/;
343 struct nd_defrouter
*dr
, anydr
;
344 struct nd_pfxrouter
*pfxrtr
;
345 struct rtentry
*rt
= NULL
;
346 struct llinfo_nd6
*ln
= NULL
;
347 int s
= splnet(), error
, state
;
349 pr
= mip6_primary_prefix
;
350 /* Only for sanity check */
351 dr
= mip6_primary_prefix
?
352 defrouter_lookup(&mip6_primary_defrtr
,
353 mip6_primary_prefix
->ndpr_ifp
) : NULL
;
354 state
= mip6_md_state
;
360 mip6_debug("%s: previous primary dr = %s.\n", __FUNCTION__
,
361 ip6_sprintf(&mip6_primary_defrtr
));
362 mip6_debug("%s: dr = %s.\n", __FUNCTION__
,
363 dr
? ip6_sprintf(&dr
->rtaddr
) : "NULL");
366 if ( (mip6_md_state
== MIP6_MD_HOME
) ||
367 (mip6_md_state
== MIP6_MD_UNDEFINED
) ) {
368 if ((pr
= mip6_home_prefix
) == NULL
){
369 log(LOG_ERR
, "mip6_select_defrtr: no home prefix\n");
374 if ((pfxrtr
= find_pfxlist_reachable_router(pr
)) != NULL
) {
376 mip6_debug("%s: there are (reachable) pfxrtrs at "
377 "home.\n", __FUNCTION__
);
379 if (!IN6_IS_ADDR_UNSPECIFIED(&pr
->ndpr_addr
) &&
380 !(IN6_IS_ADDR_MULTICAST(&pr
->ndpr_addr
) ||
381 IN6_IS_ADDR_LINKLOCAL(&pr
->ndpr_addr
))) {
383 /* Pick first reachable pfxrtr. */
384 state
= MIP6_MD_HOME
;
388 /* Place dr first since its prim. */
389 TAILQ_REMOVE(&nd_defrouter
, dr
, dr_entry
);
390 TAILQ_INSERT_HEAD(&nd_defrouter
, dr
, dr_entry
);
393 mip6_debug("%s: picking %s as default router "
396 ip6_sprintf(&(dr
->rtaddr
)));
402 if (pr
->ndpr_advrtrs
.lh_first
== NULL
) {
404 mip6_debug("%s: there are no pfxrtrs at home, trying "
405 "non-home instead.\n", __FUNCTION__
);
410 * No home prefix defrtr found, just drop through and pick
411 * one by the ordinary procedure below.
414 mip6_debug("%s: no home prefix router found.\n", __FUNCTION__
);
419 * Go through the Default Router List in search for a (probably)
420 * reachable router that advertises a prefix and with an associated
421 * Care-of Address. This is a merge from defrouter_select().
423 if (TAILQ_FIRST(&nd_defrouter
)) {
424 for (dr
= TAILQ_FIRST(&nd_defrouter
); dr
;
425 dr
= TAILQ_NEXT(dr
, dr_entry
)) {
427 if ((rt
= nd6_lookup(&dr
->rtaddr
, 0, dr
->ifp
)) &&
428 (ln
= (struct llinfo_nd6
*)rt
->rt_llinfo
) &&
429 ND6_IS_LLINFO_PROBREACH(ln
)) {
432 * Find a Care-of Address from a prefix
433 * announced by this router.
435 for (pr
= nd_prefix
.lh_first
; pr
;
436 pr
= pr
->ndpr_next
) {
437 if ((pfxrtr_lookup(pr
, dr
) != NULL
) &&
438 !IN6_IS_ADDR_UNSPECIFIED(
440 !IN6_IS_ADDR_MULTICAST(
442 !IN6_IS_ADDR_LINKLOCAL(
444 state
= MIP6_MD_FOREIGN
;
447 mip6_debug("%s: new probably reachable defrtr %s on foreign subnet selected.\n", __FUNCTION__
, ip6_sprintf(&dr
->rtaddr
));
451 * Place dr first since
454 TAILQ_REMOVE(&nd_defrouter
,
467 * No (probably) reachable router found that matched our requirements.
468 * Go through the Default Router List again in search for any
469 * router that advertises a prefix and with an associated
470 * Care-of Address. This is a merge from defrouter_select().
472 for(dr
= TAILQ_FIRST(&nd_defrouter
); dr
; dr
= TAILQ_NEXT(dr
, dr_entry
)){
474 * Find a Care-of Address from a prefix announced by
477 for (pr
= nd_prefix
.lh_first
; pr
; pr
= pr
->ndpr_next
) {
478 if ((pfxrtr_lookup(pr
, dr
) != NULL
) &&
479 !IN6_IS_ADDR_UNSPECIFIED(&pr
->ndpr_addr
)&&
480 !IN6_IS_ADDR_MULTICAST(&pr
->ndpr_addr
) &&
481 !IN6_IS_ADDR_LINKLOCAL(&pr
->ndpr_addr
)) {
482 state
= MIP6_MD_FOREIGN
;
485 mip6_debug("%s: new (unreachable?) "
486 "defrtr %s on foreign subnet "
487 "selected.\n", __FUNCTION__
,
488 ip6_sprintf(&dr
->rtaddr
));
491 /* Place dr first since its prim. */
492 TAILQ_REMOVE(&nd_defrouter
, dr
,
494 TAILQ_INSERT_HEAD(&nd_defrouter
, dr
,
503 * No new defrtr or no with an associated Care-of Address found
504 * -> State = undefined
508 state
= MIP6_MD_UNDEFINED
;
510 mip6_debug("%s: no new good defrtr found.\n", __FUNCTION__
);
514 /* XXXYYY Hope this merge is correct now... Fingers crossed. Mattias */
516 mip6_debug("%s: found: dr = %s.\n", __FUNCTION__
, dr
? ip6_sprintf(&dr
->rtaddr
) : "NULL");
518 if ((dr
= TAILQ_FIRST(&nd_defrouter
)) != NULL
) {
520 mip6_debug("%s: TAILQ: dr = %s.\n", __FUNCTION__
, dr
? ip6_sprintf(&dr
->rtaddr
) : "NULL");
523 * De-install the previous default gateway and install
525 * Note that if there is no reachable router in the list,
526 * the head entry will be used anyway.
527 * XXX: do we have to check the current routing table entry?
529 bzero(&anydr
, sizeof(anydr
));
530 defrouter_delreq(&anydr
, 0);
531 defrouter_addreq(dr
);
535 * The Default Router List is empty, so install the default
536 * route to an inteface.
537 * XXX: The specification does not say this mechanism should
538 * be restricted to hosts, but this would be not useful
539 * (even harmful) for routers.
541 if (!ip6_forwarding
) {
543 * De-install the current default route
546 bzero(&anydr
, sizeof(anydr
));
547 defrouter_delreq(&anydr
, 0);
550 * Install a route to the default interface
553 defrouter_addifreq(nd6_defifp
);
555 else /* noisy log? */
556 log(LOG_INFO
, "defrouter_select: "
557 "there's no default router and no default"
564 * If we grab a (unreachable) defrouter that actually is a home
565 * prefix router, we should consider ourself at home rather than
569 struct nd_pfxrouter
*pfxrtr
;
571 pfxrtr
= pfxrtr_lookup(mip6_home_prefix
, dr
);
572 if (pfxrtr
&& dr
== pfxrtr
->router
) {
574 mip6_debug("%s: dr = %s is obviously a home pfxrtr.\n", __FUNCTION__
, dr
? ip6_sprintf(&dr
->rtaddr
) : "NULL");
576 state
= MIP6_MD_HOME
;
577 pr
= mip6_home_prefix
;
582 * First case: same router as last time.
583 * Second case: coming from UNDEFINED, we might have had a router, but
584 * we didn't have a care-of address.
586 if (IN6_ARE_ADDR_EQUAL(&mip6_primary_defrtr
,
587 (dr
? &dr
->rtaddr
: &in6addr_any
)) &&
588 !(dr
&& mip6_primary_prefix
== NULL
)) {
590 mip6_debug("%s: Warning: Primary default router hasn't "
591 "changed! No action taken.\n", __FUNCTION__
);
597 * Switch between network and host route for the Home Address
598 * in the following cases:
600 * md_state route_state
602 * HOME -> FOREIGN NET -> HOST
603 * UNDEFINED -> FOREIGN NET -> HOST
604 * FOREIGN -> HOME HOST -> NET
605 * FOREIGN -> UNDEFINED HOST -> NET
608 if ((state
== MIP6_MD_HOME
|| state
== MIP6_MD_UNDEFINED
)
609 && mip6_route_state
== MIP6_ROUTE_HOST
) {
610 error
= mip6_add_ifaddr(&mip6_home_prefix
->ndpr_addr
,
611 mip6_home_prefix
->ndpr_ifp
, 64,
614 printf("%s: address assignment error (errno = %d).\n",
615 __FUNCTION__
, error
);
616 mip6_route_state
= MIP6_ROUTE_NET
;
618 else if (state
== MIP6_MD_FOREIGN
&&
619 mip6_route_state
== MIP6_ROUTE_NET
) {
620 error
= mip6_add_ifaddr(&mip6_home_prefix
->ndpr_addr
,
621 mip6_home_prefix
->ndpr_ifp
, 128,
624 printf("%s: address assignment error (errno = %d).\n",
625 __FUNCTION__
, error
);
626 mip6_route_state
= MIP6_ROUTE_HOST
;
630 * If the Mobile Node has changed its primary prefix (probably due to
631 * a move to a different subnet), clear the Neighbor Cache from entries
632 * cloned from the previous primary prefix. This does not happen when
633 * we keep the same prefix but change default router.
636 mip6_debug("mip6_primary_prefix = %s\n", mip6_primary_prefix
? ip6_sprintf(&mip6_primary_prefix
->ndpr_prefix
.sin6_addr
) : "NULL");
637 mip6_debug("pr = %s\n", pr
? ip6_sprintf(&pr
->ndpr_prefix
.sin6_addr
) : "NULL");
639 if (mip6_primary_prefix
&& (pr
!= mip6_primary_prefix
)) {
640 register struct llinfo_nd6
*ln
;
642 /* Taken from nd6_timer() */
643 ln
= llinfo_nd6
.ln_next
;
644 /* XXX BSD/OS separates this code -- itojun */
645 while (ln
&& ln
!= &llinfo_nd6
) {
648 struct sockaddr_in6
*dst
;
649 struct llinfo_nd6
*next
= ln
->ln_next
;
651 if ((rt
= ln
->ln_rt
) == NULL
) {
655 if ((ifp
= rt
->rt_ifp
) == NULL
) {
659 dst
= (struct sockaddr_in6
*)rt_key(rt
);
662 panic("rt=0 in %s(ln=%p)\n", __FUNCTION__
, ln
);
664 panic("dst=0 in %s(ln=%p)\n", __FUNCTION__
, ln
);
666 /* Skip if the address belongs to us */
667 if (ln
->ln_expire
== 0) {
673 mip6_debug("Checking neighbor %s\n", dst
? ip6_sprintf(&dst
->sin6_addr
) : "NULL");
675 if (in6_are_prefix_equal(&dst
->sin6_addr
,
676 &mip6_primary_prefix
->
677 ndpr_prefix
.sin6_addr
,
678 mip6_primary_prefix
->
681 /* Fake an INCOMPLETE neighbor that we're giving up */
682 struct mbuf
*m
= ln
->ln_hold
;
689 mip6_debug("Deleting Neighbor %s.\n",
690 ip6_sprintf(&(satosin6(
691 rt_key(rt
))->sin6_addr
)));
696 key_sa_routechange(rt_key(rt
));
701 mip6_debug("Ref count = %d, now pfctlinput\n",
706 pfctlinput(PRC_REDIRECT_HOST
, rt_key(rt
));
710 mip6_debug("Ref count = %d, now rt_mip6msg\n",
714 rt_mip6msg(RTM_DELETE
, ifp
, rt
); /* Useless? */
717 mip6_debug("Ref count = %d, now RTM_DELETE\n",
724 * XXX Also remove the link-local addresses which
729 ln
= llinfo_nd6
.ln_next
;
730 while (ln
&& ln
!= &llinfo_nd6
) {
733 struct sockaddr_dl
*sdl
;
734 struct sockaddr_in6
*dst
;
735 struct llinfo_nd6
*next
= ln
->ln_next
;
737 if ((rt
= ln
->ln_rt
) == NULL
) {
741 if ((ifp
= rt
->rt_ifp
) == NULL
) {
745 dst
= (struct sockaddr_in6
*)rt_key(rt
);
748 panic("rt=0 in %s(ln=%p)\n", __FUNCTION__
, ln
);
750 panic("dst=0 in %s(ln=%p)\n", __FUNCTION__
, ln
);
752 /* Skip if the address belongs to us */
753 if (ln
->ln_expire
== 0) {
759 mip6_debug("Checking neighbor %s round 2\n", dst
? ip6_sprintf(&dst
->sin6_addr
) : "NULL");
761 if (in6_are_prefix_equal(&dst
->sin6_addr
,
762 &mip6_primary_prefix
->
763 ndpr_prefix
.sin6_addr
,
764 mip6_primary_prefix
->
768 mip6_debug("Deleting Neighbor %s round 2.\n",
769 ip6_sprintf(&(satosin6(
770 rt_key(rt
))->sin6_addr
)));
774 mip6_debug("Ref count = %d, now RTM_DELETE\n",
777 if (rt
&& rt
->rt_gateway
&&
778 rt
->rt_gateway
->sa_family
== AF_LINK
) {
779 sdl
= (struct sockaddr_dl
*)rt
->
781 rtrequest(RTM_DELETE
, rt_key(rt
),
782 (struct sockaddr
*)0,
784 (struct rtentry
**)0);
789 * XXX Also remove the link-local addresses which
796 * Make decision permanent.
797 * Primary Default Router is already set above.
799 mip6_md_state
= state
;
800 mip6_primary_prefix
= pr
; /* Other depend on this */
802 * Save rtaddr for next mip6_select_defrtr session.
804 mip6_primary_defrtr
= dr
? dr
->rtaddr
: in6addr_any
;
807 * Assumptions made below:
808 * - dr is the chosen Default Router
809 * - pr is the new Primary Prefix if we're not home
811 switch (mip6_md_state
) {
813 mip6_tell_em(mip6_md_state
, mip6_home_prefix
, NULL
, dr
);
816 case MIP6_MD_FOREIGN
:
817 mip6_tell_em(mip6_md_state
, mip6_home_prefix
, pr
, dr
);
819 case MIP6_MD_UNDEFINED
:
821 * Note: we pass dr == NULL, but we might have a Default
822 * Router anyway, but with no prefix/Care-of Address
825 mip6_tell_em(mip6_md_state
, mip6_home_prefix
, NULL
, NULL
);
834 ******************************************************************************
835 * Function: mip6_prelist_update(pr, dr)
836 * Description: A hook to ND's prelist_update(). Checks if the Home Prefix
837 * was announced and in that case tries to force the Mobile Node
838 * to select that default router. If the Mobile Node was in
839 * UNDEFINED state we want to select that router immediately, no
840 * matter what the prefix was.
842 ******************************************************************************
845 mip6_prelist_update(pr
, dr
)
846 struct nd_prefix
*pr
;
847 struct nd_defrouter
*dr
;
852 if (pr
== mip6_home_prefix
) {
853 /* It was the Home Prefix that was advertised. */
855 if (mip6_md_state
!= MIP6_MD_HOME
) {
857 * We're not home but here's a router advertising
858 * our home prefix => make it primary defrtr and
862 mip6_debug("%s: returning home.\n", __FUNCTION__
);
864 mip6_md_state
= MIP6_MD_HOME
;
866 /* State must be home before call. */
867 if (TAILQ_FIRST(&nd_defrouter
) != NULL
) {
872 mip6_debug("%s: Undef -> Home: no previous "
874 "at this stage.\n", __FUNCTION__
);
876 /* XXXYYY or use defrouter_select()? */
877 mip6_select_defrtr();
881 else if (mip6_md_state
== MIP6_MD_UNDEFINED
) {
883 * Take care of transitions from UNDEFINED to FOREIGN, when the
884 * prefix is already known.
886 if (TAILQ_FIRST(&nd_defrouter
) != NULL
) {
891 mip6_debug("%s: Strange, no default router available"
892 "at this stage.\n", __FUNCTION__
);
894 /* XXXYYY or use defrouter_select()? */
895 mip6_select_defrtr();
902 ******************************************************************************
903 * Function: mip6_eager_md()
904 * Description: If eager Movement Detection is chosen, trim parameters to a
905 * really fast hand-off. The disadvantage is that the detection
906 * becomes very exposed to go into state UNDEFINED if one single
909 ******************************************************************************
912 mip6_eager_md(int enable
)
914 mip6_config
.eager_md
= enable
;
916 mip6_max_lost_advints
= 1; /* Aggressive values */
917 if (!mip6_nd6_delay
) {
918 mip6_nd6_delay
= nd6_delay
; /* Store */
919 mip6_nd6_umaxtries
= nd6_umaxtries
; /* Store */
921 nd6_delay
= 1; /* Aggressive values */
925 mip6_max_lost_advints
= MIP6_MAX_LOST_ADVINTS
;
926 if (mip6_nd6_delay
) {
927 nd6_delay
= mip6_nd6_delay
; /* Restore */
928 nd6_umaxtries
= mip6_nd6_umaxtries
; /* Restore */
930 mip6_nd6_umaxtries
= 0;
937 ******************************************************************************
938 * Function: mip6_expired_defrouter()
939 * Description: If the field advint_expire (which is parallel to field
940 * expire for router lifetime) times out, allow a small number
941 * of lost Router Advertisements before doubting if this
942 * particular default router is still reachable.
944 ******************************************************************************
947 mip6_expired_defrouter(struct nd_defrouter
*dr
)
949 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
950 long time_second
= time
.tv_sec
;
956 if (dr
->advint_expire
&& dr
->advint_expire
< time_second
) {
957 if (++(dr
->advints_lost
) < mip6_max_lost_advints
) {
958 /* advints_lost starts at 0. max = 1 (or more). */
959 dr
->advint_expire
= time_second
+ dr
->advint
/ 1000;
961 mip6_debug("Adv Int #%d lost from router %s.\n",
962 dr
->advints_lost
, ip6_sprintf(&dr
->rtaddr
));
966 dr
->advint_expire
= 0;
968 mip6_debug("Adv Int #%d lost from router %s.\n",
969 dr
->advints_lost
, ip6_sprintf(&dr
->rtaddr
));
971 mip6_probe_defrouter(dr
);
978 ******************************************************************************
979 * Function: mip6_probe_defrouter()
980 * Description: Probes a default router to see if it is still reachable.
981 * Ordinary Neigbor Discovery routines (NUD) takes care of the
982 * rest. Puts this router into ND state PROBE.
984 ******************************************************************************
987 mip6_probe_defrouter(struct nd_defrouter
*dr
)
989 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
990 long time_second
= time
.tv_sec
;
993 struct llinfo_nd6
*ln
;
998 if (!(rt
= nd6_lookup(&dr
->rtaddr
, 0, NULL
)))
1001 if ((rt
->rt_flags
& RTF_GATEWAY
)
1002 || (rt
->rt_flags
& RTF_LLINFO
) == 0
1005 || rt
->rt_gateway
->sa_family
!= AF_LINK
) {
1006 /* This is not a host route. */
1010 ln
= (struct llinfo_nd6
*)rt
->rt_llinfo
;
1011 if ((ln
->ln_state
== ND6_LLINFO_INCOMPLETE
)
1012 || (ln
->ln_state
== ND6_LLINFO_PROBE
)
1013 || (ln
->ln_state
== ND6_LLINFO_WAITDELETE
)
1014 || (ln
->ln_state
== ND6_LLINFO_NOSTATE
))
1017 /* Force state to PROBE, simulate DELAY->PROBE */
1019 ln
->ln_state
= ND6_LLINFO_PROBE
;
1020 ln
->ln_expire
= time_second
+
1021 nd_ifinfo
[rt
->rt_ifp
->if_index
].retrans
/ 1000;
1022 nd6_ns_output(rt
->rt_ifp
, &dr
->rtaddr
, &dr
->rtaddr
,
1025 mip6_debug("Probing defrouter %s\n", ip6_sprintf(&dr
->rtaddr
));
1031 ******************************************************************************
1032 * Function: mip6_probe_pfxrtrs()
1033 * Description: If a new or previously detached prefix is heard, probe (NUD)
1034 * all prefix routers on the current primary prefix in order to
1035 * quickly detect if we have moved. This is only enabled in
1036 * eager Movement Detection.
1038 ******************************************************************************
1041 mip6_probe_pfxrtrs()
1043 struct nd_pfxrouter
*pfr
;
1044 if (!mip6_config
.eager_md
)
1047 if (!mip6_primary_prefix
)
1051 mip6_debug("New or detached prefix received, probe old routers:\n");
1053 for (pfr
= mip6_primary_prefix
->ndpr_advrtrs
.lh_first
;
1054 pfr
; pfr
= pfr
->pfr_next
) {
1055 mip6_probe_defrouter(pfr
->router
);
1061 ******************************************************************************
1062 * Function: mip6_store_advint(ai, dr)
1063 * Description: If Advertisement Interval option is available in Router
1064 * Advertisements, keep a timer for this expiry parallel to the
1065 * ordinary Router lifetime timer.
1067 ******************************************************************************
1070 mip6_store_advint(struct nd_opt_advint
*ai
,
1071 struct nd_defrouter
*dr
)
1073 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
1074 long time_second
= time
.tv_sec
;
1077 /* Check the advertisement interval option */
1078 if (ai
->nd_opt_int_len
!= 1) {
1079 log(LOG_INFO
, "%s: bad Advertisement Interval Option "
1080 "length\n", __FUNCTION__
);
1083 dr
->advint
= ntohl(ai
->nd_opt_int_interval
); /* milliseconds */
1085 /* Sorry for delay between reception and this setting */
1086 dr
->advint_expire
= time_second
+ dr
->advint
/ 1000;
1087 dr
->advints_lost
= 0;
1093 ******************************************************************************
1094 * Function: mip6_delete_ifaddr
1095 * Description: Similar to "ifconfig <ifp> <addr> delete".
1097 ******************************************************************************
1100 mip6_delete_ifaddr(struct in6_addr
*addr
,
1103 struct in6_aliasreq
*ifra
, dummy
;
1104 struct sockaddr_in6
*sa6
;
1105 struct in6_ifaddr
*ia
, *oia
;
1107 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__)
1111 bzero(&dummy
, sizeof(dummy
));
1114 ifra
->ifra_addr
.sin6_len
= sizeof(ifra
->ifra_addr
);
1115 ifra
->ifra_addr
.sin6_family
= AF_INET6
;
1116 ifra
->ifra_addr
.sin6_addr
= *addr
;
1118 sa6
= &ifra
->ifra_addr
;
1126 * Code recycled from in6_control().
1130 * Find address for this interface, if it exists.
1132 if (IN6_IS_ADDR_LINKLOCAL(&sa6
->sin6_addr
)) {
1133 if (sa6
->sin6_addr
.s6_addr16
[1] == 0) {
1134 /* interface ID is not embedded by the user */
1135 sa6
->sin6_addr
.s6_addr16
[1] =
1136 htons(ifp
->if_index
);
1138 else if (sa6
->sin6_addr
.s6_addr16
[1] !=
1139 htons(ifp
->if_index
)) {
1141 return(EINVAL
); /* ifid is contradict */
1143 if (sa6
->sin6_scope_id
) {
1144 if (sa6
->sin6_scope_id
!=
1145 (u_int32_t
)ifp
->if_index
) {
1149 sa6
->sin6_scope_id
= 0; /* XXX: good way? */
1152 ia
= in6ifa_ifpwithaddr(ifp
, &ifra
->ifra_addr
.sin6_addr
);
1155 * for IPv4, we look for existing in6_ifaddr here to allow
1156 * "ifconfig if0 delete" to remove first IPv4 address on the
1157 * interface. For IPv6, as the spec allow multiple interface
1158 * address from the day one, we consider "remove the first one"
1159 * semantics to be not preferrable.
1163 return(EADDRNOTAVAIL
);
1168 ia
= (struct in6_ifaddr
*)
1169 MALLOC(sizeof(*ia
), M_IFADDR
, M_WAITOK
);
1174 bzero((caddr_t
)ia
, sizeof(*ia
));
1175 ia
->ia_ifa
.ifa_addr
= (struct sockaddr
*)&ia
->ia_addr
;
1176 ia
->ia_ifa
.ifa_dstaddr
1177 = (struct sockaddr
*)&ia
->ia_dstaddr
;
1178 ia
->ia_ifa
.ifa_netmask
1179 = (struct sockaddr
*)&ia
->ia_prefixmask
;
1182 if ((oia
= in6_ifaddr
) != NULL
) {
1183 for ( ; oia
->ia_next
; oia
= oia
->ia_next
)
1188 ia
->ia_ifa
.ifa_refcnt
++;
1190 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__)
1191 if ((ifa
= ifp
->if_addrlist
) != NULL
) {
1192 for ( ; ifa
->ifa_next
; ifa
= ifa
->ifa_next
)
1194 ifa
->ifa_next
= &ia
->ia_ifa
;
1196 ifp
->if_addrlist
= &ia
->ia_ifa
;
1198 TAILQ_INSERT_TAIL(&ifp
->if_addrlist
, &ia
->ia_ifa
,
1201 ia
->ia_ifa
.ifa_refcnt
++;
1204 in6_purgeaddr(&ia
->ia_ifa
, ifp
);
1213 ******************************************************************************
1214 * Function: mip6_delete_ifaddr
1215 * Description: Similar to "ifconfig <ifp> <addr> delete".
1217 ******************************************************************************
1220 mip6_delete_ifaddr(struct in6_addr
*addr
,
1223 struct in6_aliasreq in6_addreq
;
1226 bzero(&in6_addreq
, sizeof(in6_addreq
));
1227 in6_addreq
.ifra_addr
.sin6_len
= sizeof(in6_addreq
.ifra_addr
);
1228 in6_addreq
.ifra_addr
.sin6_family
= AF_INET6
;
1229 in6_addreq
.ifra_addr
.sin6_addr
= *addr
;
1232 error
= in6_control(NULL
, SIOCDIFADDR_IN6
, (caddr_t
)&in6_addreq
, ifp
1233 #if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !define (__APPLE__)
1240 mip6_debug("%s: Attempt to delete addr %s failed.\n", __FUNCTION__
,
1248 mip6_get_home_prefix(void)
1250 return(mip6_home_prefix
);
1255 mip6_get_md_state(void)
1257 return(mip6_md_state
);
1262 ******************************************************************************
1263 * Function: mip6_md_exit
1264 * Description: Tidy up after the Mobile IPv6 Movement Detection. This is
1265 * used when releasing the kernel module. The Home Prefix is
1266 * deleted (even if we're home) since it's parameters might be
1267 * way wrong. The Home Address is released as well. If at home,
1268 * the prefix and address will be automagically configured as
1271 ******************************************************************************
1276 struct nd_prefix
*pr
;
1279 * XXXYYY Should use mip6_esmq when multiple Home Addresses are
1282 pr
= mip6_home_prefix
;
1283 if (pr
&& pr
->ndpr_ifp
&& !IN6_IS_ADDR_UNSPECIFIED(&pr
->ndpr_addr
)) {
1284 mip6_delete_ifaddr(&pr
->ndpr_addr
, pr
->ndpr_ifp
);
1287 mip6_home_prefix
= NULL
;
1290 mip6_debug("Home Prefix and Home Address removed.\n");