]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/mip6_md.c
16b670388f7c389b126ffcd79bae8e89e85ed93d
[apple/xnu.git] / bsd / netinet6 / mip6_md.c
1 /* $KAME: mip6_md.c,v 1.14 2000/03/25 07:23:53 sumikawa Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
18 *
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
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB
34 * All rights reserved.
35 *
36 * Author: Mattias Pettersson <mattias.pettersson@era.ericsson.se>
37 *
38 */
39
40 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
41 #include "opt_inet.h"
42 #endif
43
44 /*
45 * Mobile IPv6 Movement Detection for Mobile Nodes
46 */
47 #include <sys/param.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.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>
57
58 #include <net/if.h>
59 #include <net/if_types.h>
60 #include <net/route.h>
61
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>
70 #endif
71 #include <netinet6/in6_pcb.h>
72 #include <netinet6/mip6.h>
73
74 #include <net/net_osdep.h>
75
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;
80 /*
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.
84 */
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;
89
90
91 /*
92 ******************************************************************************
93 * Function: mip6_tell_em
94 * Description: Print state change and tell event-state machine.
95 * Ret value: -
96 ******************************************************************************
97 */
98 static void
99 mip6_tell_em(int state,
100 struct nd_prefix *hp,
101 struct nd_prefix *pp,
102 struct nd_defrouter *dr)
103 {
104 #if MIP6_DEBUG
105 mip6_debug("\nNew state: ");
106 switch (state) {
107 case MIP6_MD_HOME:
108 mip6_debug("HOME!\n");
109 break;
110 case MIP6_MD_FOREIGN:
111 mip6_debug("FOREIGN!\n");
112 break;
113 case MIP6_MD_UNDEFINED:
114 mip6_debug("UNDEFINED!\n");
115 break;
116 }
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");
123 #endif
124 mip6_new_defrtr(state, hp, pp, dr);
125 }
126
127
128 /*
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.
137 * Ret value: -
138 ******************************************************************************
139 */
140 void
141 mip6_md_init()
142 {
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 */
147 int i, s, error;
148
149 for (esp = mip6_esmq; esp; esp = esp->next) {
150
151 /*
152 * Add the home prefix statically to the prefix list.
153 * Code taken from prelist_update(), prelist_add() and
154 * in6_ifadd().
155 */
156 pr = (struct nd_prefix *)MALLOC(sizeof(*pr), M_TEMP, M_WAITOK);
157 if (pr == NULL) {
158 log(LOG_ERR, "mip6_md_init: no mem for home prefix\n");
159 } else {
160 bzero(pr, sizeof(*pr));
161
162 pr->ndpr_ifp = esp->ifp;
163 pr->ndpr_plen = esp->prefix_len;
164
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);
169
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];
174
175 /* TODO: link into interface prefix list */
176
177 /* Default settings for unadvertised home prefix */
178 pr->ndpr_raf_onlink = 0;
179 pr->ndpr_raf_auto = 0;
180
181 /*
182 * If home prefix already exists in prefix list, use that
183 * entry instead.
184 */
185 if ( (existing_pr = prefix_lookup(pr)) ) {
186 _FREE(pr, M_TEMP);
187 pr = existing_pr;
188 }
189
190 /* Update (or set) certain fields in the home prefix */
191 pr->ndpr_vltime = ND6_INFINITE_LIFETIME;
192 pr->ndpr_pltime = ND6_INFINITE_LIFETIME;
193
194 if (in6_init_prefix_ltimes(pr)) {
195 log(LOG_ERR, "mip6_md_init: bad lifetimes\n");
196 goto failure;
197 }
198
199
200 s = splnet(); /* Must be before goto statement */
201
202 if (existing_pr != NULL) {
203 #if MIP6_DEBUG
204 mip6_debug("mip6_md_init: Home prefix already exists, "
205 "no need to create new prefix.\n");
206 #endif
207 goto skip_initialization;
208 }
209
210 /* New prefix, fix all initialization. */
211
212 pr->ndpr_statef_onlink = 0; /* Should be 0 since there
213 are no adv rtrs for
214 this pfx yet */
215 LIST_INIT(&pr->ndpr_advrtrs);
216
217 skip_initialization:
218
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,
223 &pr->ndpr_addr);
224 if (ia) {
225 error = mip6_delete_ifaddr(
226 &ia->ia_addr.sin6_addr,
227 pr->ndpr_ifp);
228 if (error)
229 printf("%s: address assignment"
230 " error "
231 "(errno = %d).\n",
232 __FUNCTION__, error);
233 }
234 }
235 }
236
237 pr->ndpr_addr = esp->home_addr;
238
239 if (existing_pr == NULL) {
240 /* link ndpr_entry to nd_prefix list */
241 LIST_INSERT_HEAD(&nd_prefix, pr, ndpr_entry);
242 }
243
244 splx(s);
245 }
246 if (esp != mip6_esmq) {
247 #if MIP6_DEBUG
248 mip6_debug("%s: Only supporting one home address in this "
249 "version.\n", __FUNCTION__);
250 #endif
251 }
252 mip6_home_prefix = pr;
253
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
259 we're home. */
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;
269
270 mip6_tell_em(MIP6_MD_HOME, mip6_home_prefix, NULL, dr);
271 }
272 else {
273 if (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 "
279 "(errno = %d).\n",
280 __FUNCTION__, error);
281 mip6_route_state = MIP6_ROUTE_HOST;
282
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)) {
288 break;
289 }
290 }
291 if (pr) {
292 mip6_primary_prefix = pr;
293 mip6_primary_defrtr = dr->rtaddr;
294 mip6_tell_em(MIP6_MD_FOREIGN, mip6_home_prefix,
295 pr, dr);
296 }
297 else {
298 #if MIP6_DEBUG
299 mip6_debug("%s: At FOREIGN, but no primary "
300 "prefix found!\n", __FUNCTION__);
301 #endif
302 goto undefined;
303 }
304 }
305 else {
306 undefined:
307 mip6_md_state = MIP6_MD_UNDEFINED;
308 if ((error = mip6_add_ifaddr(&pr->ndpr_addr,
309 pr->ndpr_ifp, 64,
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;
316
317 mip6_tell_em(MIP6_MD_UNDEFINED, mip6_home_prefix,
318 NULL, NULL);
319 }
320 }
321 failure:
322 }
323 }
324
325
326 /*
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.
336 * Ret value: -
337 ******************************************************************************
338 */
339 void
340 mip6_select_defrtr()
341 {
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;
348
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;
355
356 #if MIP6_DEBUG
357 mip6_debug("\n");
358 #endif
359 #if MIP6_DEBUG
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");
364 #endif
365
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");
370 splx(s);
371 return;
372 }
373
374 if ((pfxrtr = find_pfxlist_reachable_router(pr)) != NULL) {
375 #if MIP6_DEBUG
376 mip6_debug("%s: there are (reachable) pfxrtrs at "
377 "home.\n", __FUNCTION__);
378 #endif
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))) {
382
383 /* Pick first reachable pfxrtr. */
384 state = MIP6_MD_HOME;
385
386 dr = pfxrtr->router;
387
388 /* Place dr first since its prim. */
389 TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
390 TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
391
392 #if MIP6_DEBUG
393 mip6_debug("%s: picking %s as default router "
394 "on home subnet.\n",
395 __FUNCTION__,
396 ip6_sprintf(&(dr->rtaddr)));
397 #endif
398 goto found;
399 }
400 }
401
402 if (pr->ndpr_advrtrs.lh_first == NULL) {
403 #if MIP6_DEBUG
404 mip6_debug("%s: there are no pfxrtrs at home, trying "
405 "non-home instead.\n", __FUNCTION__);
406 #endif
407 }
408
409 /*
410 * No home prefix defrtr found, just drop through and pick
411 * one by the ordinary procedure below.
412 */
413 #if MIP6_DEBUG
414 mip6_debug("%s: no home prefix router found.\n", __FUNCTION__);
415 #endif
416 }
417
418 /*
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().
422 */
423 if (TAILQ_FIRST(&nd_defrouter)) {
424 for (dr = TAILQ_FIRST(&nd_defrouter); dr;
425 dr = TAILQ_NEXT(dr, dr_entry)) {
426
427 if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
428 (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
429 ND6_IS_LLINFO_PROBREACH(ln)) {
430
431 /*
432 * Find a Care-of Address from a prefix
433 * announced by this router.
434 */
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(
439 &pr->ndpr_addr) &&
440 !IN6_IS_ADDR_MULTICAST(
441 &pr->ndpr_addr) &&
442 !IN6_IS_ADDR_LINKLOCAL(
443 &pr->ndpr_addr)) {
444 state = MIP6_MD_FOREIGN;
445
446 #if MIP6_DEBUG
447 mip6_debug("%s: new probably reachable defrtr %s on foreign subnet selected.\n", __FUNCTION__, ip6_sprintf(&dr->rtaddr));
448 #endif
449
450 /*
451 * Place dr first since
452 * its prim.
453 */
454 TAILQ_REMOVE(&nd_defrouter,
455 dr, dr_entry);
456 TAILQ_INSERT_HEAD(
457 &nd_defrouter,
458 dr, dr_entry);
459
460 goto found;
461 }
462 }
463 }
464 }
465
466 /*
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().
471 */
472 for(dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)){
473 /*
474 * Find a Care-of Address from a prefix announced by
475 * this router.
476 */
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;
483
484 #if MIP6_DEBUG
485 mip6_debug("%s: new (unreachable?) "
486 "defrtr %s on foreign subnet "
487 "selected.\n", __FUNCTION__,
488 ip6_sprintf(&dr->rtaddr));
489 #endif
490
491 /* Place dr first since its prim. */
492 TAILQ_REMOVE(&nd_defrouter, dr,
493 dr_entry);
494 TAILQ_INSERT_HEAD(&nd_defrouter, dr,
495 dr_entry);
496 goto found;
497 }
498 }
499 }
500 }
501
502 /*
503 * No new defrtr or no with an associated Care-of Address found
504 * -> State = undefined
505 */
506 pr = NULL;
507 dr = NULL;
508 state = MIP6_MD_UNDEFINED;
509 #if MIP6_DEBUG
510 mip6_debug("%s: no new good defrtr found.\n", __FUNCTION__);
511 #endif
512
513 found:
514 /* XXXYYY Hope this merge is correct now... Fingers crossed. Mattias */
515 #if MIP6_DEBUG
516 mip6_debug("%s: found: dr = %s.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL");
517 #endif
518 if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) {
519 #if MIP6_DEBUG
520 mip6_debug("%s: TAILQ: dr = %s.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL");
521 #endif
522 /*
523 * De-install the previous default gateway and install
524 * a new one.
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?
528 */
529 bzero(&anydr, sizeof(anydr));
530 defrouter_delreq(&anydr, 0);
531 defrouter_addreq(dr);
532 }
533 else {
534 /*
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.
540 */
541 if (!ip6_forwarding) {
542 /*
543 * De-install the current default route
544 * in advance.
545 */
546 bzero(&anydr, sizeof(anydr));
547 defrouter_delreq(&anydr, 0);
548 if (nd6_defifp) {
549 /*
550 * Install a route to the default interface
551 * as default route.
552 */
553 defrouter_addifreq(nd6_defifp);
554 }
555 else /* noisy log? */
556 log(LOG_INFO, "defrouter_select: "
557 "there's no default router and no default"
558 " interface\n");
559 }
560 }
561
562
563 /*
564 * If we grab a (unreachable) defrouter that actually is a home
565 * prefix router, we should consider ourself at home rather than
566 * default foreign.
567 */
568 if (dr) {
569 struct nd_pfxrouter *pfxrtr;
570
571 pfxrtr = pfxrtr_lookup(mip6_home_prefix, dr);
572 if (pfxrtr && dr == pfxrtr->router) {
573 #if MIP6_DEBUG
574 mip6_debug("%s: dr = %s is obviously a home pfxrtr.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL");
575 #endif
576 state = MIP6_MD_HOME;
577 pr = mip6_home_prefix;
578 }
579 }
580
581 /*
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.
585 */
586 if (IN6_ARE_ADDR_EQUAL(&mip6_primary_defrtr,
587 (dr ? &dr->rtaddr : &in6addr_any)) &&
588 !(dr && mip6_primary_prefix == NULL)) {
589 #if MIP6_DEBUG
590 mip6_debug("%s: Warning: Primary default router hasn't "
591 "changed! No action taken.\n", __FUNCTION__);
592 #endif
593 return;
594 }
595
596 /*
597 * Switch between network and host route for the Home Address
598 * in the following cases:
599 *
600 * md_state route_state
601 *
602 * HOME -> FOREIGN NET -> HOST
603 * UNDEFINED -> FOREIGN NET -> HOST
604 * FOREIGN -> HOME HOST -> NET
605 * FOREIGN -> UNDEFINED HOST -> NET
606 */
607
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,
612 IN6_IFF_NODAD);
613 if (error)
614 printf("%s: address assignment error (errno = %d).\n",
615 __FUNCTION__, error);
616 mip6_route_state = MIP6_ROUTE_NET;
617 }
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,
622 IN6_IFF_NODAD);
623 if (error)
624 printf("%s: address assignment error (errno = %d).\n",
625 __FUNCTION__, error);
626 mip6_route_state = MIP6_ROUTE_HOST;
627 }
628
629 /*
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.
634 */
635 #if MIP6_DEBUG
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");
638 #endif
639 if (mip6_primary_prefix && (pr != mip6_primary_prefix)) {
640 register struct llinfo_nd6 *ln;
641
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) {
646 struct rtentry *rt;
647 struct ifnet *ifp;
648 struct sockaddr_in6 *dst;
649 struct llinfo_nd6 *next = ln->ln_next;
650
651 if ((rt = ln->ln_rt) == NULL) {
652 ln = next;
653 continue;
654 }
655 if ((ifp = rt->rt_ifp) == NULL) {
656 ln = next;
657 continue;
658 }
659 dst = (struct sockaddr_in6 *)rt_key(rt);
660 /* sanity check */
661 if (!rt)
662 panic("rt=0 in %s(ln=%p)\n", __FUNCTION__, ln);
663 if (!dst)
664 panic("dst=0 in %s(ln=%p)\n", __FUNCTION__, ln);
665
666 /* Skip if the address belongs to us */
667 if (ln->ln_expire == 0) {
668 ln = next;
669 continue;
670 }
671
672 #if MIP6_DEBUG
673 mip6_debug("Checking neighbor %s\n", dst ? ip6_sprintf(&dst->sin6_addr) : "NULL");
674 #endif
675 if (in6_are_prefix_equal(&dst->sin6_addr,
676 &mip6_primary_prefix->
677 ndpr_prefix.sin6_addr,
678 mip6_primary_prefix->
679 ndpr_plen)) {
680
681 /* Fake an INCOMPLETE neighbor that we're giving up */
682 struct mbuf *m = ln->ln_hold;
683 if (m) {
684 m_freem(m);
685 }
686 ln->ln_hold = NULL;
687
688 #if MIP6_DEBUG
689 mip6_debug("Deleting Neighbor %s.\n",
690 ip6_sprintf(&(satosin6(
691 rt_key(rt))->sin6_addr)));
692 #endif
693
694 #if IPSEC
695 #ifndef __OpenBSD__
696 key_sa_routechange(rt_key(rt));
697 #endif
698 #endif
699
700 #if MIP6_DEBUG
701 mip6_debug("Ref count = %d, now pfctlinput\n",
702 rt->rt_refcnt);
703 #endif
704
705 /* New era */
706 pfctlinput(PRC_REDIRECT_HOST, rt_key(rt));
707
708 #if 0
709 #if MIP6_DEBUG
710 mip6_debug("Ref count = %d, now rt_mip6msg\n",
711 rt->rt_refcnt);
712 #endif
713
714 rt_mip6msg(RTM_DELETE, ifp, rt); /* Useless? */
715 #endif /* 0 */
716 #if MIP6_DEBUG
717 mip6_debug("Ref count = %d, now RTM_DELETE\n",
718 rt->rt_refcnt);
719 #endif
720 nd6_free(rt);
721 }
722 ln = next;
723 /*
724 * XXX Also remove the link-local addresses which
725 * aren't ours?
726 */
727 }
728
729 ln = llinfo_nd6.ln_next;
730 while (ln && ln != &llinfo_nd6) {
731 struct rtentry *rt;
732 struct ifnet *ifp;
733 struct sockaddr_dl *sdl;
734 struct sockaddr_in6 *dst;
735 struct llinfo_nd6 *next = ln->ln_next;
736
737 if ((rt = ln->ln_rt) == NULL) {
738 ln = next;
739 continue;
740 }
741 if ((ifp = rt->rt_ifp) == NULL) {
742 ln = next;
743 continue;
744 }
745 dst = (struct sockaddr_in6 *)rt_key(rt);
746 /* sanity check */
747 if (!rt)
748 panic("rt=0 in %s(ln=%p)\n", __FUNCTION__, ln);
749 if (!dst)
750 panic("dst=0 in %s(ln=%p)\n", __FUNCTION__, ln);
751
752 /* Skip if the address belongs to us */
753 if (ln->ln_expire == 0) {
754 ln = next;
755 continue;
756 }
757
758 #if MIP6_DEBUG
759 mip6_debug("Checking neighbor %s round 2\n", dst ? ip6_sprintf(&dst->sin6_addr) : "NULL");
760 #endif
761 if (in6_are_prefix_equal(&dst->sin6_addr,
762 &mip6_primary_prefix->
763 ndpr_prefix.sin6_addr,
764 mip6_primary_prefix->
765 ndpr_plen)) {
766
767 #if MIP6_DEBUG
768 mip6_debug("Deleting Neighbor %s round 2.\n",
769 ip6_sprintf(&(satosin6(
770 rt_key(rt))->sin6_addr)));
771 #endif
772
773 #if MIP6_DEBUG
774 mip6_debug("Ref count = %d, now RTM_DELETE\n",
775 rt->rt_refcnt);
776 #endif
777 if (rt && rt->rt_gateway &&
778 rt->rt_gateway->sa_family == AF_LINK) {
779 sdl = (struct sockaddr_dl *)rt->
780 rt_gateway;
781 rtrequest(RTM_DELETE, rt_key(rt),
782 (struct sockaddr *)0,
783 rt_mask(rt), 0,
784 (struct rtentry **)0);
785 }
786 }
787 ln = next;
788 /*
789 * XXX Also remove the link-local addresses which
790 * aren't ours?
791 */
792 }
793 }
794
795 /*
796 * Make decision permanent.
797 * Primary Default Router is already set above.
798 */
799 mip6_md_state = state;
800 mip6_primary_prefix = pr; /* Other depend on this */
801 /*
802 * Save rtaddr for next mip6_select_defrtr session.
803 */
804 mip6_primary_defrtr = dr ? dr->rtaddr : in6addr_any;
805
806 /*
807 * Assumptions made below:
808 * - dr is the chosen Default Router
809 * - pr is the new Primary Prefix if we're not home
810 */
811 switch (mip6_md_state) {
812 case MIP6_MD_HOME:
813 mip6_tell_em(mip6_md_state, mip6_home_prefix, NULL, dr);
814 break;
815
816 case MIP6_MD_FOREIGN:
817 mip6_tell_em(mip6_md_state, mip6_home_prefix, pr, dr);
818 break;
819 case MIP6_MD_UNDEFINED:
820 /*
821 * Note: we pass dr == NULL, but we might have a Default
822 * Router anyway, but with no prefix/Care-of Address
823 * associated.
824 */
825 mip6_tell_em(mip6_md_state, mip6_home_prefix, NULL, NULL);
826 break;
827 }
828 splx(s);
829 return;
830 }
831
832
833 /*
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.
841 * Ret value: -
842 ******************************************************************************
843 */
844 void
845 mip6_prelist_update(pr, dr)
846 struct nd_prefix *pr;
847 struct nd_defrouter *dr;
848 {
849 if (dr == NULL) {
850 return;
851 }
852 if (pr == mip6_home_prefix) {
853 /* It was the Home Prefix that was advertised. */
854
855 if (mip6_md_state != MIP6_MD_HOME) {
856 /*
857 * We're not home but here's a router advertising
858 * our home prefix => make it primary defrtr and
859 * we're home!
860 */
861 #if MIP6_DEBUG
862 mip6_debug("%s: returning home.\n", __FUNCTION__);
863 #endif
864 mip6_md_state = MIP6_MD_HOME;
865
866 /* State must be home before call. */
867 if (TAILQ_FIRST(&nd_defrouter) != NULL) {
868 defrouter_select();
869 }
870 else {
871 #if MIP6_DEBUG
872 mip6_debug("%s: Undef -> Home: no previous "
873 "router available "
874 "at this stage.\n", __FUNCTION__);
875 #endif
876 /* XXXYYY or use defrouter_select()? */
877 mip6_select_defrtr();
878 }
879 }
880 }
881 else if (mip6_md_state == MIP6_MD_UNDEFINED) {
882 /*
883 * Take care of transitions from UNDEFINED to FOREIGN, when the
884 * prefix is already known.
885 */
886 if (TAILQ_FIRST(&nd_defrouter) != NULL) {
887 defrouter_select();
888 }
889 else {
890 #if MIP6_DEBUG
891 mip6_debug("%s: Strange, no default router available"
892 "at this stage.\n", __FUNCTION__);
893 #endif
894 /* XXXYYY or use defrouter_select()? */
895 mip6_select_defrtr();
896 }
897 }
898 }
899
900
901 /*
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
907 * packet is lost.
908 * Ret value: -
909 ******************************************************************************
910 */
911 void
912 mip6_eager_md(int enable)
913 {
914 mip6_config.eager_md = enable;
915 if (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 */
920 }
921 nd6_delay = 1; /* Aggressive values */
922 nd6_umaxtries = 1;
923 }
924 else {
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 */
929 mip6_nd6_delay = 0;
930 mip6_nd6_umaxtries = 0;
931 }
932 }
933 }
934
935
936 /*
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.
943 * Ret value: -
944 ******************************************************************************
945 */
946 void
947 mip6_expired_defrouter(struct nd_defrouter *dr)
948 {
949 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
950 long time_second = time.tv_sec;
951 #endif
952
953 if (!dr)
954 return;
955
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;
960 #if MIP6_DEBUG
961 mip6_debug("Adv Int #%d lost from router %s.\n",
962 dr->advints_lost, ip6_sprintf(&dr->rtaddr));
963 #endif
964 }
965 else {
966 dr->advint_expire = 0;
967 #if MIP6_DEBUG
968 mip6_debug("Adv Int #%d lost from router %s.\n",
969 dr->advints_lost, ip6_sprintf(&dr->rtaddr));
970 #endif
971 mip6_probe_defrouter(dr);
972 }
973 }
974 }
975
976
977 /*
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.
983 * Ret value: -
984 ******************************************************************************
985 */
986 void
987 mip6_probe_defrouter(struct nd_defrouter *dr)
988 {
989 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
990 long time_second = time.tv_sec;
991 #endif
992 struct rtentry *rt;
993 struct llinfo_nd6 *ln;
994
995 if (!dr)
996 return;
997
998 if (!(rt = nd6_lookup(&dr->rtaddr, 0, NULL)))
999 return;
1000
1001 if ((rt->rt_flags & RTF_GATEWAY)
1002 || (rt->rt_flags & RTF_LLINFO) == 0
1003 || !rt->rt_llinfo
1004 || !rt->rt_gateway
1005 || rt->rt_gateway->sa_family != AF_LINK) {
1006 /* This is not a host route. */
1007 return;
1008 }
1009
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))
1015 return;
1016
1017 /* Force state to PROBE, simulate DELAY->PROBE */
1018 ln->ln_asked = 1;
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,
1023 ln, 0);
1024 #if MIP6_DEBUG
1025 mip6_debug("Probing defrouter %s\n", ip6_sprintf(&dr->rtaddr));
1026 #endif
1027 }
1028
1029
1030 /*
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.
1037 * Ret value: -
1038 ******************************************************************************
1039 */
1040 void
1041 mip6_probe_pfxrtrs()
1042 {
1043 struct nd_pfxrouter *pfr;
1044 if (!mip6_config.eager_md)
1045 return;
1046
1047 if (!mip6_primary_prefix)
1048 return;
1049
1050 #if MIP6_DEBUG
1051 mip6_debug("New or detached prefix received, probe old routers:\n");
1052 #endif
1053 for (pfr = mip6_primary_prefix->ndpr_advrtrs.lh_first;
1054 pfr; pfr = pfr->pfr_next) {
1055 mip6_probe_defrouter(pfr->router);
1056 }
1057 }
1058
1059
1060 /*
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.
1066 * Ret value: -
1067 ******************************************************************************
1068 */
1069 void
1070 mip6_store_advint(struct nd_opt_advint *ai,
1071 struct nd_defrouter *dr)
1072 {
1073 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
1074 long time_second = time.tv_sec;
1075 #endif
1076
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__);
1081 }
1082 else if (dr) {
1083 dr->advint = ntohl(ai->nd_opt_int_interval); /* milliseconds */
1084
1085 /* Sorry for delay between reception and this setting */
1086 dr->advint_expire = time_second + dr->advint / 1000;
1087 dr->advints_lost = 0;
1088 }
1089 }
1090
1091
1092 /*
1093 ******************************************************************************
1094 * Function: mip6_delete_ifaddr
1095 * Description: Similar to "ifconfig <ifp> <addr> delete".
1096 * Ret value: -
1097 ******************************************************************************
1098 */
1099 int
1100 mip6_delete_ifaddr(struct in6_addr *addr,
1101 struct ifnet *ifp)
1102 {
1103 struct in6_aliasreq *ifra, dummy;
1104 struct sockaddr_in6 *sa6;
1105 struct in6_ifaddr *ia, *oia;
1106 int s;
1107 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__)
1108 struct ifaddr *ifa;
1109 #endif
1110
1111 bzero(&dummy, sizeof(dummy));
1112 ifra = &dummy;
1113
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;
1117
1118 sa6 = &ifra->ifra_addr;
1119
1120 if (ifp == 0)
1121 return(EOPNOTSUPP);
1122
1123 s = splnet();
1124
1125 /*
1126 * Code recycled from in6_control().
1127 */
1128
1129 /*
1130 * Find address for this interface, if it exists.
1131 */
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);
1137 }
1138 else if (sa6->sin6_addr.s6_addr16[1] !=
1139 htons(ifp->if_index)) {
1140 splx(s);
1141 return(EINVAL); /* ifid is contradict */
1142 }
1143 if (sa6->sin6_scope_id) {
1144 if (sa6->sin6_scope_id !=
1145 (u_int32_t)ifp->if_index) {
1146 splx(s);
1147 return(EINVAL);
1148 }
1149 sa6->sin6_scope_id = 0; /* XXX: good way? */
1150 }
1151 }
1152 ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
1153
1154 /*
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.
1160 */
1161 if (ia == 0) {
1162 splx(s);
1163 return(EADDRNOTAVAIL);
1164 }
1165 /* FALLTHROUGH */
1166
1167 if (ia == 0) {
1168 ia = (struct in6_ifaddr *)
1169 MALLOC(sizeof(*ia), M_IFADDR, M_WAITOK);
1170 if (ia == NULL) {
1171 splx(s);
1172 return (ENOBUFS);
1173 }
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;
1180
1181 ia->ia_ifp = ifp;
1182 if ((oia = in6_ifaddr) != NULL) {
1183 for ( ; oia->ia_next; oia = oia->ia_next)
1184 continue;
1185 oia->ia_next = ia;
1186 } else
1187 in6_ifaddr = ia;
1188 ia->ia_ifa.ifa_refcnt++;
1189
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)
1193 continue;
1194 ifa->ifa_next = &ia->ia_ifa;
1195 } else
1196 ifp->if_addrlist = &ia->ia_ifa;
1197 #else
1198 TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
1199 ifa_list);
1200 #endif
1201 ia->ia_ifa.ifa_refcnt++;
1202 }
1203
1204 in6_purgeaddr(&ia->ia_ifa, ifp);
1205
1206 splx(s);
1207 return(0);
1208 }
1209
1210
1211 #if 0
1212 /*
1213 ******************************************************************************
1214 * Function: mip6_delete_ifaddr
1215 * Description: Similar to "ifconfig <ifp> <addr> delete".
1216 * Ret value: -
1217 ******************************************************************************
1218 */
1219 void
1220 mip6_delete_ifaddr(struct in6_addr *addr,
1221 struct ifnet *ifp)
1222 {
1223 struct in6_aliasreq in6_addreq;
1224 int s, error = 0;
1225
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;
1230
1231 s =splnet();
1232 error = in6_control(NULL, SIOCDIFADDR_IN6, (caddr_t)&in6_addreq, ifp
1233 #if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !define (__APPLE__)
1234 , NULL
1235 #endif
1236 );
1237 splx(s);
1238 if (error) {
1239 #if MIP6_DEBUG
1240 mip6_debug("%s: Attempt to delete addr %s failed.\n", __FUNCTION__,
1241 ip6_sprintf(addr));
1242 #endif
1243 }
1244 }
1245 #endif /* 0 */
1246
1247 struct nd_prefix *
1248 mip6_get_home_prefix(void)
1249 {
1250 return(mip6_home_prefix);
1251 }
1252
1253
1254 int
1255 mip6_get_md_state(void)
1256 {
1257 return(mip6_md_state);
1258 }
1259
1260
1261 /*
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
1269 * specified by ND.
1270 * Ret value: -
1271 ******************************************************************************
1272 */
1273 void
1274 mip6_md_exit()
1275 {
1276 struct nd_prefix *pr;
1277
1278 /*
1279 * XXXYYY Should use mip6_esmq when multiple Home Addresses are
1280 * supported.
1281 */
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);
1285
1286 prelist_remove(pr);
1287 mip6_home_prefix = NULL;
1288
1289 #if MIP6_DEBUG
1290 mip6_debug("Home Prefix and Home Address removed.\n");
1291 #endif
1292 }
1293 }