Annotation of sys/netinet6/nd6.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: nd6.c,v 1.74 2007/06/08 09:31:38 henning Exp $ */
! 2: /* $KAME: nd6.c,v 1.280 2002/06/08 19:52:07 itojun Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the project nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: */
! 32:
! 33: #include <sys/param.h>
! 34: #include <sys/systm.h>
! 35: #include <sys/timeout.h>
! 36: #include <sys/malloc.h>
! 37: #include <sys/mbuf.h>
! 38: #include <sys/socket.h>
! 39: #include <sys/sockio.h>
! 40: #include <sys/time.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/protosw.h>
! 43: #include <sys/errno.h>
! 44: #include <sys/ioctl.h>
! 45: #include <sys/syslog.h>
! 46: #include <sys/queue.h>
! 47: #include <dev/rndvar.h>
! 48:
! 49: #include <net/if.h>
! 50: #include <net/if_dl.h>
! 51: #include <net/if_types.h>
! 52: #include <net/if_fddi.h>
! 53: #include <net/route.h>
! 54:
! 55: #include <netinet/in.h>
! 56: #include <netinet/if_ether.h>
! 57: #include <netinet/ip_ipsp.h>
! 58:
! 59: #include <netinet6/in6_var.h>
! 60: #include <netinet/ip6.h>
! 61: #include <netinet6/ip6_var.h>
! 62: #include <netinet6/nd6.h>
! 63: #include <netinet/icmp6.h>
! 64:
! 65: #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */
! 66: #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */
! 67:
! 68: #define SIN6(s) ((struct sockaddr_in6 *)s)
! 69: #define SDL(s) ((struct sockaddr_dl *)s)
! 70:
! 71: /* timer values */
! 72: int nd6_prune = 1; /* walk list every 1 seconds */
! 73: int nd6_delay = 5; /* delay first probe time 5 second */
! 74: int nd6_umaxtries = 3; /* maximum unicast query */
! 75: int nd6_mmaxtries = 3; /* maximum multicast query */
! 76: int nd6_useloopback = 1; /* use loopback interface for local traffic */
! 77: int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */
! 78:
! 79: /* preventing too many loops in ND option parsing */
! 80: int nd6_maxndopt = 10; /* max # of ND options allowed */
! 81:
! 82: int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */
! 83:
! 84: #ifdef ND6_DEBUG
! 85: int nd6_debug = 1;
! 86: #else
! 87: int nd6_debug = 0;
! 88: #endif
! 89:
! 90: /* for debugging? */
! 91: static int nd6_inuse, nd6_allocated;
! 92:
! 93: struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6};
! 94: struct nd_drhead nd_defrouter;
! 95: struct nd_prhead nd_prefix = { 0 };
! 96:
! 97: int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
! 98: static struct sockaddr_in6 all1_sa;
! 99:
! 100: static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *);
! 101: static void nd6_slowtimo(void *);
! 102: static struct llinfo_nd6 *nd6_free(struct rtentry *, int);
! 103: static void nd6_llinfo_timer(void *);
! 104:
! 105: struct timeout nd6_slowtimo_ch;
! 106: struct timeout nd6_timer_ch;
! 107: extern struct timeout in6_tmpaddrtimer_ch;
! 108:
! 109: static int fill_drlist(void *, size_t *, size_t);
! 110: static int fill_prlist(void *, size_t *, size_t);
! 111:
! 112: void
! 113: nd6_init()
! 114: {
! 115: static int nd6_init_done = 0;
! 116: int i;
! 117:
! 118: if (nd6_init_done) {
! 119: log(LOG_NOTICE, "nd6_init called more than once(ignored)\n");
! 120: return;
! 121: }
! 122:
! 123: all1_sa.sin6_family = AF_INET6;
! 124: all1_sa.sin6_len = sizeof(struct sockaddr_in6);
! 125: for (i = 0; i < sizeof(all1_sa.sin6_addr); i++)
! 126: all1_sa.sin6_addr.s6_addr[i] = 0xff;
! 127:
! 128: /* initialization of the default router list */
! 129: TAILQ_INIT(&nd_defrouter);
! 130:
! 131: nd6_init_done = 1;
! 132:
! 133: /* start timer */
! 134: timeout_set(&nd6_slowtimo_ch, nd6_slowtimo, NULL);
! 135: timeout_add(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz);
! 136: }
! 137:
! 138: struct nd_ifinfo *
! 139: nd6_ifattach(ifp)
! 140: struct ifnet *ifp;
! 141: {
! 142: struct nd_ifinfo *nd;
! 143:
! 144: nd = (struct nd_ifinfo *)malloc(sizeof(*nd), M_IP6NDP, M_WAITOK);
! 145: bzero(nd, sizeof(*nd));
! 146:
! 147: nd->initialized = 1;
! 148:
! 149: nd->chlim = IPV6_DEFHLIM;
! 150: nd->basereachable = REACHABLE_TIME;
! 151: nd->reachable = ND_COMPUTE_RTIME(nd->basereachable);
! 152: nd->retrans = RETRANS_TIMER;
! 153: /*
! 154: * Note that the default value of ip6_accept_rtadv is 0, which means
! 155: * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV
! 156: * here.
! 157: */
! 158: nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
! 159:
! 160: /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
! 161: nd6_setmtu0(ifp, nd);
! 162:
! 163: return nd;
! 164: }
! 165:
! 166: void
! 167: nd6_ifdetach(nd)
! 168: struct nd_ifinfo *nd;
! 169: {
! 170:
! 171: free(nd, M_IP6NDP);
! 172: }
! 173:
! 174: void
! 175: nd6_setmtu(ifp)
! 176: struct ifnet *ifp;
! 177: {
! 178: nd6_setmtu0(ifp, ND_IFINFO(ifp));
! 179: }
! 180:
! 181: void
! 182: nd6_setmtu0(ifp, ndi)
! 183: struct ifnet *ifp;
! 184: struct nd_ifinfo *ndi;
! 185: {
! 186: u_int32_t omaxmtu;
! 187:
! 188: omaxmtu = ndi->maxmtu;
! 189:
! 190: if (ifp->if_type == IFT_FDDI)
! 191: ndi->maxmtu = MIN(FDDIMTU, ifp->if_mtu);
! 192: else
! 193: ndi->maxmtu = ifp->if_mtu;
! 194:
! 195: /*
! 196: * Decreasing the interface MTU under IPV6 minimum MTU may cause
! 197: * undesirable situation. We thus notify the operator of the change
! 198: * explicitly. The check for omaxmtu is necessary to restrict the
! 199: * log to the case of changing the MTU, not initializing it.
! 200: */
! 201: if (omaxmtu >= IPV6_MMTU && ndi->maxmtu < IPV6_MMTU) {
! 202: log(LOG_NOTICE, "nd6_setmtu0: "
! 203: "new link MTU on %s (%lu) is too small for IPv6\n",
! 204: ifp->if_xname, (unsigned long)ndi->maxmtu);
! 205: }
! 206:
! 207: if (ndi->maxmtu > in6_maxmtu)
! 208: in6_setmaxmtu(); /* check all interfaces just in case */
! 209: }
! 210:
! 211: void
! 212: nd6_option_init(opt, icmp6len, ndopts)
! 213: void *opt;
! 214: int icmp6len;
! 215: union nd_opts *ndopts;
! 216: {
! 217:
! 218: bzero(ndopts, sizeof(*ndopts));
! 219: ndopts->nd_opts_search = (struct nd_opt_hdr *)opt;
! 220: ndopts->nd_opts_last
! 221: = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len);
! 222:
! 223: if (icmp6len == 0) {
! 224: ndopts->nd_opts_done = 1;
! 225: ndopts->nd_opts_search = NULL;
! 226: }
! 227: }
! 228:
! 229: /*
! 230: * Take one ND option.
! 231: */
! 232: struct nd_opt_hdr *
! 233: nd6_option(ndopts)
! 234: union nd_opts *ndopts;
! 235: {
! 236: struct nd_opt_hdr *nd_opt;
! 237: int olen;
! 238:
! 239: if (!ndopts)
! 240: panic("ndopts == NULL in nd6_option");
! 241: if (!ndopts->nd_opts_last)
! 242: panic("uninitialized ndopts in nd6_option");
! 243: if (!ndopts->nd_opts_search)
! 244: return NULL;
! 245: if (ndopts->nd_opts_done)
! 246: return NULL;
! 247:
! 248: nd_opt = ndopts->nd_opts_search;
! 249:
! 250: /* make sure nd_opt_len is inside the buffer */
! 251: if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) {
! 252: bzero(ndopts, sizeof(*ndopts));
! 253: return NULL;
! 254: }
! 255:
! 256: olen = nd_opt->nd_opt_len << 3;
! 257: if (olen == 0) {
! 258: /*
! 259: * Message validation requires that all included
! 260: * options have a length that is greater than zero.
! 261: */
! 262: bzero(ndopts, sizeof(*ndopts));
! 263: return NULL;
! 264: }
! 265:
! 266: ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen);
! 267: if (ndopts->nd_opts_search > ndopts->nd_opts_last) {
! 268: /* option overruns the end of buffer, invalid */
! 269: bzero(ndopts, sizeof(*ndopts));
! 270: return NULL;
! 271: } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) {
! 272: /* reached the end of options chain */
! 273: ndopts->nd_opts_done = 1;
! 274: ndopts->nd_opts_search = NULL;
! 275: }
! 276: return nd_opt;
! 277: }
! 278:
! 279: /*
! 280: * Parse multiple ND options.
! 281: * This function is much easier to use, for ND routines that do not need
! 282: * multiple options of the same type.
! 283: */
! 284: int
! 285: nd6_options(ndopts)
! 286: union nd_opts *ndopts;
! 287: {
! 288: struct nd_opt_hdr *nd_opt;
! 289: int i = 0;
! 290:
! 291: if (!ndopts)
! 292: panic("ndopts == NULL in nd6_options");
! 293: if (!ndopts->nd_opts_last)
! 294: panic("uninitialized ndopts in nd6_options");
! 295: if (!ndopts->nd_opts_search)
! 296: return 0;
! 297:
! 298: while (1) {
! 299: nd_opt = nd6_option(ndopts);
! 300: if (!nd_opt && !ndopts->nd_opts_last) {
! 301: /*
! 302: * Message validation requires that all included
! 303: * options have a length that is greater than zero.
! 304: */
! 305: icmp6stat.icp6s_nd_badopt++;
! 306: bzero(ndopts, sizeof(*ndopts));
! 307: return -1;
! 308: }
! 309:
! 310: if (!nd_opt)
! 311: goto skip1;
! 312:
! 313: switch (nd_opt->nd_opt_type) {
! 314: case ND_OPT_SOURCE_LINKADDR:
! 315: case ND_OPT_TARGET_LINKADDR:
! 316: case ND_OPT_MTU:
! 317: case ND_OPT_REDIRECTED_HEADER:
! 318: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
! 319: nd6log((LOG_INFO,
! 320: "duplicated ND6 option found (type=%d)\n",
! 321: nd_opt->nd_opt_type));
! 322: /* XXX bark? */
! 323: } else {
! 324: ndopts->nd_opt_array[nd_opt->nd_opt_type]
! 325: = nd_opt;
! 326: }
! 327: break;
! 328: case ND_OPT_PREFIX_INFORMATION:
! 329: if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) {
! 330: ndopts->nd_opt_array[nd_opt->nd_opt_type]
! 331: = nd_opt;
! 332: }
! 333: ndopts->nd_opts_pi_end =
! 334: (struct nd_opt_prefix_info *)nd_opt;
! 335: break;
! 336: default:
! 337: /*
! 338: * Unknown options must be silently ignored,
! 339: * to accommodate future extension to the protocol.
! 340: */
! 341: nd6log((LOG_DEBUG,
! 342: "nd6_options: unsupported option %d - "
! 343: "option ignored\n", nd_opt->nd_opt_type));
! 344: }
! 345:
! 346: skip1:
! 347: i++;
! 348: if (i > nd6_maxndopt) {
! 349: icmp6stat.icp6s_nd_toomanyopt++;
! 350: nd6log((LOG_INFO, "too many loop in nd opt\n"));
! 351: break;
! 352: }
! 353:
! 354: if (ndopts->nd_opts_done)
! 355: break;
! 356: }
! 357:
! 358: return 0;
! 359: }
! 360:
! 361: /*
! 362: * ND6 timer routine to handle ND6 entries
! 363: */
! 364: void
! 365: nd6_llinfo_settimer(struct llinfo_nd6 *ln, long tick)
! 366: {
! 367: int s;
! 368:
! 369: s = splsoftnet();
! 370:
! 371: if (tick < 0) {
! 372: ln->ln_expire = 0;
! 373: ln->ln_ntick = 0;
! 374: timeout_del(&ln->ln_timer_ch);
! 375: } else {
! 376: ln->ln_expire = time_second + tick / hz;
! 377: if (tick > INT_MAX) {
! 378: ln->ln_ntick = tick - INT_MAX;
! 379: timeout_add(&ln->ln_timer_ch, INT_MAX);
! 380: } else {
! 381: ln->ln_ntick = 0;
! 382: timeout_add(&ln->ln_timer_ch, tick);
! 383: }
! 384: }
! 385:
! 386: splx(s);
! 387: }
! 388:
! 389: static void
! 390: nd6_llinfo_timer(void *arg)
! 391: {
! 392: int s;
! 393: struct llinfo_nd6 *ln;
! 394: struct rtentry *rt;
! 395: struct sockaddr_in6 *dst;
! 396: struct ifnet *ifp;
! 397: struct nd_ifinfo *ndi = NULL;
! 398:
! 399: s = splsoftnet();
! 400:
! 401: ln = (struct llinfo_nd6 *)arg;
! 402:
! 403: if (ln->ln_ntick > 0) {
! 404: if (ln->ln_ntick > INT_MAX) {
! 405: ln->ln_ntick -= INT_MAX;
! 406: nd6_llinfo_settimer(ln, INT_MAX);
! 407: } else {
! 408: ln->ln_ntick = 0;
! 409: nd6_llinfo_settimer(ln, ln->ln_ntick);
! 410: }
! 411: splx(s);
! 412: return;
! 413: }
! 414:
! 415: if ((rt = ln->ln_rt) == NULL)
! 416: panic("ln->ln_rt == NULL");
! 417: if ((ifp = rt->rt_ifp) == NULL)
! 418: panic("ln->ln_rt->rt_ifp == NULL");
! 419: ndi = ND_IFINFO(ifp);
! 420: dst = (struct sockaddr_in6 *)rt_key(rt);
! 421:
! 422: /* sanity check */
! 423: if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln)
! 424: panic("rt_llinfo(%p) is not equal to ln(%p)",
! 425: rt->rt_llinfo, ln);
! 426: if (!dst)
! 427: panic("dst=0 in nd6_timer(ln=%p)", ln);
! 428:
! 429: switch (ln->ln_state) {
! 430: case ND6_LLINFO_INCOMPLETE:
! 431: if (ln->ln_asked < nd6_mmaxtries) {
! 432: ln->ln_asked++;
! 433: nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
! 434: nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
! 435: } else {
! 436: struct mbuf *m = ln->ln_hold;
! 437: if (m) {
! 438: ln->ln_hold = NULL;
! 439: /*
! 440: * Fake rcvif to make the ICMP error
! 441: * more helpful in diagnosing for the
! 442: * receiver.
! 443: * XXX: should we consider
! 444: * older rcvif?
! 445: */
! 446: m->m_pkthdr.rcvif = rt->rt_ifp;
! 447:
! 448: icmp6_error(m, ICMP6_DST_UNREACH,
! 449: ICMP6_DST_UNREACH_ADDR, 0);
! 450: }
! 451: (void)nd6_free(rt, 0);
! 452: ln = NULL;
! 453: }
! 454: break;
! 455: case ND6_LLINFO_REACHABLE:
! 456: if (!ND6_LLINFO_PERMANENT(ln)) {
! 457: ln->ln_state = ND6_LLINFO_STALE;
! 458: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
! 459: }
! 460: break;
! 461:
! 462: case ND6_LLINFO_STALE:
! 463: /* Garbage Collection(RFC 2461 5.3) */
! 464: if (!ND6_LLINFO_PERMANENT(ln)) {
! 465: (void)nd6_free(rt, 1);
! 466: ln = NULL;
! 467: }
! 468: break;
! 469:
! 470: case ND6_LLINFO_DELAY:
! 471: if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) {
! 472: /* We need NUD */
! 473: ln->ln_asked = 1;
! 474: ln->ln_state = ND6_LLINFO_PROBE;
! 475: nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
! 476: nd6_ns_output(ifp, &dst->sin6_addr,
! 477: &dst->sin6_addr, ln, 0);
! 478: } else {
! 479: ln->ln_state = ND6_LLINFO_STALE; /* XXX */
! 480: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
! 481: }
! 482: break;
! 483: case ND6_LLINFO_PROBE:
! 484: if (ln->ln_asked < nd6_umaxtries) {
! 485: ln->ln_asked++;
! 486: nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
! 487: nd6_ns_output(ifp, &dst->sin6_addr,
! 488: &dst->sin6_addr, ln, 0);
! 489: } else {
! 490: (void)nd6_free(rt, 0);
! 491: ln = NULL;
! 492: }
! 493: break;
! 494: }
! 495:
! 496: splx(s);
! 497: }
! 498:
! 499: /*
! 500: * ND6 timer routine to expire default route list and prefix list
! 501: */
! 502: void
! 503: nd6_timer(ignored_arg)
! 504: void *ignored_arg;
! 505: {
! 506: int s;
! 507: struct nd_defrouter *dr;
! 508: struct nd_prefix *pr;
! 509: struct in6_ifaddr *ia6, *nia6;
! 510: struct in6_addrlifetime *lt6;
! 511:
! 512: s = splsoftnet();
! 513: timeout_set(&nd6_timer_ch, nd6_timer, NULL);
! 514: timeout_add(&nd6_timer_ch, nd6_prune * hz);
! 515:
! 516: /* expire default router list */
! 517: dr = TAILQ_FIRST(&nd_defrouter);
! 518: while (dr) {
! 519: if (dr->expire && dr->expire < time_second) {
! 520: struct nd_defrouter *t;
! 521: t = TAILQ_NEXT(dr, dr_entry);
! 522: defrtrlist_del(dr);
! 523: dr = t;
! 524: } else {
! 525: dr = TAILQ_NEXT(dr, dr_entry);
! 526: }
! 527: }
! 528:
! 529: /*
! 530: * expire interface addresses.
! 531: * in the past the loop was inside prefix expiry processing.
! 532: * However, from a stricter spec-conformance standpoint, we should
! 533: * rather separate address lifetimes and prefix lifetimes.
! 534: */
! 535: for (ia6 = in6_ifaddr; ia6; ia6 = nia6) {
! 536: nia6 = ia6->ia_next;
! 537: /* check address lifetime */
! 538: lt6 = &ia6->ia6_lifetime;
! 539: if (IFA6_IS_INVALID(ia6)) {
! 540: in6_purgeaddr(&ia6->ia_ifa);
! 541: } else if (IFA6_IS_DEPRECATED(ia6)) {
! 542: ia6->ia6_flags |= IN6_IFF_DEPRECATED;
! 543: } else {
! 544: /*
! 545: * A new RA might have made a deprecated address
! 546: * preferred.
! 547: */
! 548: ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
! 549: }
! 550: }
! 551:
! 552: /* expire prefix list */
! 553: pr = LIST_FIRST(&nd_prefix);
! 554: while (pr != NULL) {
! 555: /*
! 556: * check prefix lifetime.
! 557: * since pltime is just for autoconf, pltime processing for
! 558: * prefix is not necessary.
! 559: */
! 560: if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&
! 561: time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) {
! 562: struct nd_prefix *t;
! 563: t = LIST_NEXT(pr, ndpr_entry);
! 564:
! 565: /*
! 566: * address expiration and prefix expiration are
! 567: * separate. NEVER perform in6_purgeaddr here.
! 568: */
! 569:
! 570: prelist_remove(pr);
! 571: pr = t;
! 572: } else
! 573: pr = LIST_NEXT(pr, ndpr_entry);
! 574: }
! 575: splx(s);
! 576: }
! 577:
! 578: /*
! 579: * Nuke neighbor cache/prefix/default router management table, right before
! 580: * ifp goes away.
! 581: */
! 582: void
! 583: nd6_purge(ifp)
! 584: struct ifnet *ifp;
! 585: {
! 586: struct llinfo_nd6 *ln, *nln;
! 587: struct nd_defrouter *dr, *ndr;
! 588: struct nd_prefix *pr, *npr;
! 589:
! 590: /*
! 591: * Nuke default router list entries toward ifp.
! 592: * We defer removal of default router list entries that is installed
! 593: * in the routing table, in order to keep additional side effects as
! 594: * small as possible.
! 595: */
! 596: for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {
! 597: ndr = TAILQ_NEXT(dr, dr_entry);
! 598: if (dr->installed)
! 599: continue;
! 600:
! 601: if (dr->ifp == ifp)
! 602: defrtrlist_del(dr);
! 603: }
! 604: for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {
! 605: ndr = TAILQ_NEXT(dr, dr_entry);
! 606: if (!dr->installed)
! 607: continue;
! 608:
! 609: if (dr->ifp == ifp)
! 610: defrtrlist_del(dr);
! 611: }
! 612:
! 613: /* Nuke prefix list entries toward ifp */
! 614: for (pr = LIST_FIRST(&nd_prefix); pr != NULL; pr = npr) {
! 615: npr = LIST_NEXT(pr, ndpr_entry);
! 616: if (pr->ndpr_ifp == ifp) {
! 617: /*
! 618: * Because if_detach() does *not* release prefixes
! 619: * while purging addresses the reference count will
! 620: * still be above zero. We therefore reset it to
! 621: * make sure that the prefix really gets purged.
! 622: */
! 623: pr->ndpr_refcnt = 0;
! 624: /*
! 625: * Previously, pr->ndpr_addr is removed as well,
! 626: * but I strongly believe we don't have to do it.
! 627: * nd6_purge() is only called from in6_ifdetach(),
! 628: * which removes all the associated interface addresses
! 629: * by itself.
! 630: * (jinmei@kame.net 20010129)
! 631: */
! 632: prelist_remove(pr);
! 633: }
! 634: }
! 635:
! 636: /* cancel default outgoing interface setting */
! 637: if (nd6_defifindex == ifp->if_index)
! 638: nd6_setdefaultiface(0);
! 639:
! 640: if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */
! 641: /* refresh default router list */
! 642: defrouter_select();
! 643: }
! 644:
! 645: /*
! 646: * Nuke neighbor cache entries for the ifp.
! 647: * Note that rt->rt_ifp may not be the same as ifp,
! 648: * due to KAME goto ours hack. See RTM_RESOLVE case in
! 649: * nd6_rtrequest(), and ip6_input().
! 650: */
! 651: ln = llinfo_nd6.ln_next;
! 652: while (ln && ln != &llinfo_nd6) {
! 653: struct rtentry *rt;
! 654: struct sockaddr_dl *sdl;
! 655:
! 656: nln = ln->ln_next;
! 657: rt = ln->ln_rt;
! 658: if (rt && rt->rt_gateway &&
! 659: rt->rt_gateway->sa_family == AF_LINK) {
! 660: sdl = (struct sockaddr_dl *)rt->rt_gateway;
! 661: if (sdl->sdl_index == ifp->if_index)
! 662: nln = nd6_free(rt, 0);
! 663: }
! 664: ln = nln;
! 665: }
! 666: }
! 667:
! 668: struct rtentry *
! 669: nd6_lookup(addr6, create, ifp)
! 670: struct in6_addr *addr6;
! 671: int create;
! 672: struct ifnet *ifp;
! 673: {
! 674: struct rtentry *rt;
! 675: struct sockaddr_in6 sin6;
! 676:
! 677: bzero(&sin6, sizeof(sin6));
! 678: sin6.sin6_len = sizeof(struct sockaddr_in6);
! 679: sin6.sin6_family = AF_INET6;
! 680: sin6.sin6_addr = *addr6;
! 681:
! 682: rt = rtalloc1((struct sockaddr *)&sin6, create, 0);
! 683: if (rt && (rt->rt_flags & RTF_LLINFO) == 0) {
! 684: /*
! 685: * This is the case for the default route.
! 686: * If we want to create a neighbor cache for the address, we
! 687: * should free the route for the destination and allocate an
! 688: * interface route.
! 689: */
! 690: if (create) {
! 691: RTFREE(rt);
! 692: rt = 0;
! 693: }
! 694: }
! 695: if (!rt) {
! 696: if (create && ifp) {
! 697: int e;
! 698:
! 699: /*
! 700: * If no route is available and create is set,
! 701: * we allocate a host route for the destination
! 702: * and treat it like an interface route.
! 703: * This hack is necessary for a neighbor which can't
! 704: * be covered by our own prefix.
! 705: */
! 706: struct ifaddr *ifa =
! 707: ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp);
! 708: if (ifa == NULL)
! 709: return (NULL);
! 710:
! 711: /*
! 712: * Create a new route. RTF_LLINFO is necessary
! 713: * to create a Neighbor Cache entry for the
! 714: * destination in nd6_rtrequest which will be
! 715: * called in rtrequest via ifa->ifa_rtrequest.
! 716: */
! 717: if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
! 718: ifa->ifa_addr, (struct sockaddr *)&all1_sa,
! 719: (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) &
! 720: ~RTF_CLONING, &rt, 0)) != 0) {
! 721: #if 0
! 722: log(LOG_ERR,
! 723: "nd6_lookup: failed to add route for a "
! 724: "neighbor(%s), errno=%d\n",
! 725: ip6_sprintf(addr6), e);
! 726: #endif
! 727: return (NULL);
! 728: }
! 729: if (rt == NULL)
! 730: return (NULL);
! 731: if (rt->rt_llinfo) {
! 732: struct llinfo_nd6 *ln =
! 733: (struct llinfo_nd6 *)rt->rt_llinfo;
! 734: ln->ln_state = ND6_LLINFO_NOSTATE;
! 735: }
! 736: } else
! 737: return (NULL);
! 738: }
! 739: rt->rt_refcnt--;
! 740: /*
! 741: * Validation for the entry.
! 742: * Note that the check for rt_llinfo is necessary because a cloned
! 743: * route from a parent route that has the L flag (e.g. the default
! 744: * route to a p2p interface) may have the flag, too, while the
! 745: * destination is not actually a neighbor.
! 746: * XXX: we can't use rt->rt_ifp to check for the interface, since
! 747: * it might be the loopback interface if the entry is for our
! 748: * own address on a non-loopback interface. Instead, we should
! 749: * use rt->rt_ifa->ifa_ifp, which would specify the REAL
! 750: * interface.
! 751: */
! 752: if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
! 753: rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL ||
! 754: (ifp && rt->rt_ifa->ifa_ifp != ifp)) {
! 755: if (create) {
! 756: nd6log((LOG_DEBUG,
! 757: "nd6_lookup: failed to lookup %s (if = %s)\n",
! 758: ip6_sprintf(addr6),
! 759: ifp ? ifp->if_xname : "unspec"));
! 760: }
! 761: return (NULL);
! 762: }
! 763: return (rt);
! 764: }
! 765:
! 766: /*
! 767: * Detect if a given IPv6 address identifies a neighbor on a given link.
! 768: * XXX: should take care of the destination of a p2p link?
! 769: */
! 770: int
! 771: nd6_is_addr_neighbor(addr, ifp)
! 772: struct sockaddr_in6 *addr;
! 773: struct ifnet *ifp;
! 774: {
! 775: struct nd_prefix *pr;
! 776: struct rtentry *rt;
! 777:
! 778: /*
! 779: * A link-local address is always a neighbor.
! 780: * XXX: we should use the sin6_scope_id field rather than the embedded
! 781: * interface index.
! 782: * XXX: a link does not necessarily specify a single interface.
! 783: */
! 784: if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) &&
! 785: ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index)
! 786: return (1);
! 787:
! 788: /*
! 789: * If the address matches one of our on-link prefixes, it should be a
! 790: * neighbor.
! 791: */
! 792: LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
! 793: if (pr->ndpr_ifp != ifp)
! 794: continue;
! 795:
! 796: if (!(pr->ndpr_stateflags & NDPRF_ONLINK))
! 797: continue;
! 798:
! 799: if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
! 800: &addr->sin6_addr, &pr->ndpr_mask))
! 801: return (1);
! 802: }
! 803:
! 804: /*
! 805: * If the default router list is empty, all addresses are regarded
! 806: * as on-link, and thus, as a neighbor.
! 807: * XXX: we restrict the condition to hosts, because routers usually do
! 808: * not have the "default router list".
! 809: */
! 810: if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL &&
! 811: nd6_defifindex == ifp->if_index) {
! 812: return (1);
! 813: }
! 814:
! 815: /*
! 816: * Even if the address matches none of our addresses, it might be
! 817: * in the neighbor cache.
! 818: */
! 819: if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL)
! 820: return (1);
! 821:
! 822: return (0);
! 823: }
! 824:
! 825: /*
! 826: * Free an nd6 llinfo entry.
! 827: * Since the function would cause significant changes in the kernel, DO NOT
! 828: * make it global, unless you have a strong reason for the change, and are sure
! 829: * that the change is safe.
! 830: */
! 831: static struct llinfo_nd6 *
! 832: nd6_free(rt, gc)
! 833: struct rtentry *rt;
! 834: int gc;
! 835: {
! 836: struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;
! 837: struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
! 838: struct nd_defrouter *dr;
! 839:
! 840: /*
! 841: * we used to have pfctlinput(PRC_HOSTDEAD) here.
! 842: * even though it is not harmful, it was not really necessary.
! 843: */
! 844:
! 845: if (!ip6_forwarding) {
! 846: int s;
! 847: s = splsoftnet();
! 848: dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
! 849: rt->rt_ifp);
! 850:
! 851: if (dr != NULL && dr->expire &&
! 852: ln->ln_state == ND6_LLINFO_STALE && gc) {
! 853: /*
! 854: * If the reason for the deletion is just garbage
! 855: * collection, and the neighbor is an active default
! 856: * router, do not delete it. Instead, reset the GC
! 857: * timer using the router's lifetime.
! 858: * Simply deleting the entry would affect default
! 859: * router selection, which is not necessarily a good
! 860: * thing, especially when we're using router preference
! 861: * values.
! 862: * XXX: the check for ln_state would be redundant,
! 863: * but we intentionally keep it just in case.
! 864: */
! 865: if (dr->expire > time_second * hz) {
! 866: nd6_llinfo_settimer(ln,
! 867: dr->expire - time_second * hz);
! 868: } else
! 869: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
! 870: splx(s);
! 871: return (ln->ln_next);
! 872: }
! 873:
! 874: if (ln->ln_router || dr) {
! 875: /*
! 876: * rt6_flush must be called whether or not the neighbor
! 877: * is in the Default Router List.
! 878: * See a corresponding comment in nd6_na_input().
! 879: */
! 880: rt6_flush(&in6, rt->rt_ifp);
! 881: }
! 882:
! 883: if (dr) {
! 884: /*
! 885: * Unreachability of a router might affect the default
! 886: * router selection and on-link detection of advertised
! 887: * prefixes.
! 888: */
! 889:
! 890: /*
! 891: * Temporarily fake the state to choose a new default
! 892: * router and to perform on-link determination of
! 893: * prefixes correctly.
! 894: * Below the state will be set correctly,
! 895: * or the entry itself will be deleted.
! 896: */
! 897: ln->ln_state = ND6_LLINFO_INCOMPLETE;
! 898:
! 899: /*
! 900: * Since defrouter_select() does not affect the
! 901: * on-link determination and MIP6 needs the check
! 902: * before the default router selection, we perform
! 903: * the check now.
! 904: */
! 905: pfxlist_onlink_check();
! 906:
! 907: /*
! 908: * refresh default router list
! 909: */
! 910: defrouter_select();
! 911: }
! 912: splx(s);
! 913: }
! 914:
! 915: /*
! 916: * Before deleting the entry, remember the next entry as the
! 917: * return value. We need this because pfxlist_onlink_check() above
! 918: * might have freed other entries (particularly the old next entry) as
! 919: * a side effect (XXX).
! 920: */
! 921: next = ln->ln_next;
! 922:
! 923: /*
! 924: * Detach the route from the routing tree and the list of neighbor
! 925: * caches, and disable the route entry not to be used in already
! 926: * cached routes.
! 927: */
! 928: rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
! 929: rt_mask(rt), 0, (struct rtentry **)0, 0);
! 930:
! 931: return (next);
! 932: }
! 933:
! 934: /*
! 935: * Upper-layer reachability hint for Neighbor Unreachability Detection.
! 936: *
! 937: * XXX cost-effective methods?
! 938: */
! 939: void
! 940: nd6_nud_hint(rt, dst6, force)
! 941: struct rtentry *rt;
! 942: struct in6_addr *dst6;
! 943: int force;
! 944: {
! 945: struct llinfo_nd6 *ln;
! 946:
! 947: /*
! 948: * If the caller specified "rt", use that. Otherwise, resolve the
! 949: * routing table by supplied "dst6".
! 950: */
! 951: if (!rt) {
! 952: if (!dst6)
! 953: return;
! 954: if (!(rt = nd6_lookup(dst6, 0, NULL)))
! 955: return;
! 956: }
! 957:
! 958: if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
! 959: (rt->rt_flags & RTF_LLINFO) == 0 ||
! 960: !rt->rt_llinfo || !rt->rt_gateway ||
! 961: rt->rt_gateway->sa_family != AF_LINK) {
! 962: /* This is not a host route. */
! 963: return;
! 964: }
! 965:
! 966: ln = (struct llinfo_nd6 *)rt->rt_llinfo;
! 967: if (ln->ln_state < ND6_LLINFO_REACHABLE)
! 968: return;
! 969:
! 970: /*
! 971: * if we get upper-layer reachability confirmation many times,
! 972: * it is possible we have false information.
! 973: */
! 974: if (!force) {
! 975: ln->ln_byhint++;
! 976: if (ln->ln_byhint > nd6_maxnudhint)
! 977: return;
! 978: }
! 979:
! 980: ln->ln_state = ND6_LLINFO_REACHABLE;
! 981: if (!ND6_LLINFO_PERMANENT(ln)) {
! 982: nd6_llinfo_settimer(ln,
! 983: (long)ND_IFINFO(rt->rt_ifp)->reachable * hz);
! 984: }
! 985: }
! 986:
! 987: void
! 988: nd6_rtrequest(req, rt, info)
! 989: int req;
! 990: struct rtentry *rt;
! 991: struct rt_addrinfo *info; /* xxx unused */
! 992: {
! 993: struct sockaddr *gate = rt->rt_gateway;
! 994: struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
! 995: static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
! 996: struct ifnet *ifp = rt->rt_ifp;
! 997: struct ifaddr *ifa;
! 998: int mine = 0;
! 999:
! 1000: if ((rt->rt_flags & RTF_GATEWAY) != 0)
! 1001: return;
! 1002:
! 1003: if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) {
! 1004: /*
! 1005: * This is probably an interface direct route for a link
! 1006: * which does not need neighbor caches (e.g. fe80::%lo0/64).
! 1007: * We do not need special treatment below for such a route.
! 1008: * Moreover, the RTF_LLINFO flag which would be set below
! 1009: * would annoy the ndp(8) command.
! 1010: */
! 1011: return;
! 1012: }
! 1013:
! 1014: if (req == RTM_RESOLVE &&
! 1015: (nd6_need_cache(ifp) == 0 || /* stf case */
! 1016: !nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp))) {
! 1017: /*
! 1018: * FreeBSD and BSD/OS often make a cloned host route based
! 1019: * on a less-specific route (e.g. the default route).
! 1020: * If the less specific route does not have a "gateway"
! 1021: * (this is the case when the route just goes to a p2p or an
! 1022: * stf interface), we'll mistakenly make a neighbor cache for
! 1023: * the host route, and will see strange neighbor solicitation
! 1024: * for the corresponding destination. In order to avoid the
! 1025: * confusion, we check if the destination of the route is
! 1026: * a neighbor in terms of neighbor discovery, and stop the
! 1027: * process if not. Additionally, we remove the LLINFO flag
! 1028: * so that ndp(8) will not try to get the neighbor information
! 1029: * of the destination.
! 1030: */
! 1031: rt->rt_flags &= ~RTF_LLINFO;
! 1032: return;
! 1033: }
! 1034:
! 1035: switch (req) {
! 1036: case RTM_ADD:
! 1037: /*
! 1038: * There is no backward compatibility :)
! 1039: *
! 1040: * if ((rt->rt_flags & RTF_HOST) == 0 &&
! 1041: * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
! 1042: * rt->rt_flags |= RTF_CLONING;
! 1043: */
! 1044: if ((rt->rt_flags & RTF_CLONING) ||
! 1045: ((rt->rt_flags & RTF_LLINFO) && !ln)) {
! 1046: /*
! 1047: * Case 1: This route should come from a route to
! 1048: * interface (RTF_CLONING case) or the route should be
! 1049: * treated as on-link but is currently not
! 1050: * (RTF_LLINFO && !ln case).
! 1051: */
! 1052: rt_setgate(rt, rt_key(rt),
! 1053: (struct sockaddr *)&null_sdl, 0);
! 1054: gate = rt->rt_gateway;
! 1055: SDL(gate)->sdl_type = ifp->if_type;
! 1056: SDL(gate)->sdl_index = ifp->if_index;
! 1057: if (ln)
! 1058: nd6_llinfo_settimer(ln, 0);
! 1059: if ((rt->rt_flags & RTF_CLONING) != 0)
! 1060: break;
! 1061: }
! 1062: /*
! 1063: * In IPv4 code, we try to announce new RTF_ANNOUNCE entry here.
! 1064: * We don't do that here since llinfo is not ready yet.
! 1065: *
! 1066: * There are also couple of other things to be discussed:
! 1067: * - unsolicited NA code needs improvement beforehand
! 1068: * - RFC2461 says we MAY send multicast unsolicited NA
! 1069: * (7.2.6 paragraph 4), however, it also says that we
! 1070: * SHOULD provide a mechanism to prevent multicast NA storm.
! 1071: * we don't have anything like it right now.
! 1072: * note that the mechanism needs a mutual agreement
! 1073: * between proxies, which means that we need to implement
! 1074: * a new protocol, or a new kludge.
! 1075: * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA.
! 1076: * we need to check ip6forwarding before sending it.
! 1077: * (or should we allow proxy ND configuration only for
! 1078: * routers? there's no mention about proxy ND from hosts)
! 1079: */
! 1080: #if 0
! 1081: /* XXX it does not work */
! 1082: if (rt->rt_flags & RTF_ANNOUNCE)
! 1083: nd6_na_output(ifp,
! 1084: &SIN6(rt_key(rt))->sin6_addr,
! 1085: &SIN6(rt_key(rt))->sin6_addr,
! 1086: ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
! 1087: 1, NULL);
! 1088: #endif
! 1089: /* FALLTHROUGH */
! 1090: case RTM_RESOLVE:
! 1091: if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
! 1092: /*
! 1093: * Address resolution isn't necessary for a point to
! 1094: * point link, so we can skip this test for a p2p link.
! 1095: */
! 1096: if (gate->sa_family != AF_LINK ||
! 1097: gate->sa_len < sizeof(null_sdl)) {
! 1098: log(LOG_DEBUG,
! 1099: "nd6_rtrequest: bad gateway value: %s\n",
! 1100: ifp->if_xname);
! 1101: break;
! 1102: }
! 1103: SDL(gate)->sdl_type = ifp->if_type;
! 1104: SDL(gate)->sdl_index = ifp->if_index;
! 1105: }
! 1106: if (ln != NULL)
! 1107: break; /* This happens on a route change */
! 1108: /*
! 1109: * Case 2: This route may come from cloning, or a manual route
! 1110: * add with a LL address.
! 1111: */
! 1112: R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln));
! 1113: rt->rt_llinfo = (caddr_t)ln;
! 1114: if (!ln) {
! 1115: log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n");
! 1116: break;
! 1117: }
! 1118: nd6_inuse++;
! 1119: nd6_allocated++;
! 1120: Bzero(ln, sizeof(*ln));
! 1121: ln->ln_rt = rt;
! 1122: timeout_set(&ln->ln_timer_ch, nd6_llinfo_timer, ln);
! 1123: /* this is required for "ndp" command. - shin */
! 1124: if (req == RTM_ADD) {
! 1125: /*
! 1126: * gate should have some valid AF_LINK entry,
! 1127: * and ln->ln_expire should have some lifetime
! 1128: * which is specified by ndp command.
! 1129: */
! 1130: ln->ln_state = ND6_LLINFO_REACHABLE;
! 1131: ln->ln_byhint = 0;
! 1132: } else {
! 1133: /*
! 1134: * When req == RTM_RESOLVE, rt is created and
! 1135: * initialized in rtrequest(), so rt_expire is 0.
! 1136: */
! 1137: ln->ln_state = ND6_LLINFO_NOSTATE;
! 1138: nd6_llinfo_settimer(ln, 0);
! 1139: }
! 1140: rt->rt_flags |= RTF_LLINFO;
! 1141: ln->ln_next = llinfo_nd6.ln_next;
! 1142: llinfo_nd6.ln_next = ln;
! 1143: ln->ln_prev = &llinfo_nd6;
! 1144: ln->ln_next->ln_prev = ln;
! 1145:
! 1146: /*
! 1147: * check if rt_key(rt) is one of my address assigned
! 1148: * to the interface.
! 1149: */
! 1150: ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp,
! 1151: &SIN6(rt_key(rt))->sin6_addr);
! 1152: if (ifa) {
! 1153: caddr_t macp = nd6_ifptomac(ifp);
! 1154: nd6_llinfo_settimer(ln, -1);
! 1155: ln->ln_state = ND6_LLINFO_REACHABLE;
! 1156: ln->ln_byhint = 0;
! 1157: mine = 1;
! 1158: if (macp) {
! 1159: Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen);
! 1160: SDL(gate)->sdl_alen = ifp->if_addrlen;
! 1161: }
! 1162: if (nd6_useloopback) {
! 1163: rt->rt_ifp = lo0ifp; /*XXX*/
! 1164: /*
! 1165: * Make sure rt_ifa be equal to the ifaddr
! 1166: * corresponding to the address.
! 1167: * We need this because when we refer
! 1168: * rt_ifa->ia6_flags in ip6_input, we assume
! 1169: * that the rt_ifa points to the address instead
! 1170: * of the loopback address.
! 1171: */
! 1172: if (ifa != rt->rt_ifa) {
! 1173: IFAFREE(rt->rt_ifa);
! 1174: ifa->ifa_refcnt++;
! 1175: rt->rt_ifa = ifa;
! 1176: }
! 1177: }
! 1178: } else if (rt->rt_flags & RTF_ANNOUNCE) {
! 1179: nd6_llinfo_settimer(ln, -1);
! 1180: ln->ln_state = ND6_LLINFO_REACHABLE;
! 1181: ln->ln_byhint = 0;
! 1182:
! 1183: /* join solicited node multicast for proxy ND */
! 1184: if (ifp->if_flags & IFF_MULTICAST) {
! 1185: struct in6_addr llsol;
! 1186: int error;
! 1187:
! 1188: llsol = SIN6(rt_key(rt))->sin6_addr;
! 1189: llsol.s6_addr16[0] = htons(0xff02);
! 1190: llsol.s6_addr16[1] = htons(ifp->if_index);
! 1191: llsol.s6_addr32[1] = 0;
! 1192: llsol.s6_addr32[2] = htonl(1);
! 1193: llsol.s6_addr8[12] = 0xff;
! 1194:
! 1195: if (in6_addmulti(&llsol, ifp, &error)) {
! 1196: nd6log((LOG_ERR, "%s: failed to join "
! 1197: "%s (errno=%d)\n", ifp->if_xname,
! 1198: ip6_sprintf(&llsol), error));
! 1199: }
! 1200: }
! 1201: }
! 1202: break;
! 1203:
! 1204: case RTM_DELETE:
! 1205: if (!ln)
! 1206: break;
! 1207: /* leave from solicited node multicast for proxy ND */
! 1208: if ((rt->rt_flags & RTF_ANNOUNCE) != 0 &&
! 1209: (ifp->if_flags & IFF_MULTICAST) != 0) {
! 1210: struct in6_addr llsol;
! 1211: struct in6_multi *in6m;
! 1212:
! 1213: llsol = SIN6(rt_key(rt))->sin6_addr;
! 1214: llsol.s6_addr16[0] = htons(0xff02);
! 1215: llsol.s6_addr16[1] = htons(ifp->if_index);
! 1216: llsol.s6_addr32[1] = 0;
! 1217: llsol.s6_addr32[2] = htonl(1);
! 1218: llsol.s6_addr8[12] = 0xff;
! 1219:
! 1220: IN6_LOOKUP_MULTI(llsol, ifp, in6m);
! 1221: if (in6m)
! 1222: in6_delmulti(in6m);
! 1223: }
! 1224: nd6_inuse--;
! 1225: ln->ln_next->ln_prev = ln->ln_prev;
! 1226: ln->ln_prev->ln_next = ln->ln_next;
! 1227: ln->ln_prev = NULL;
! 1228: nd6_llinfo_settimer(ln, -1);
! 1229: rt->rt_llinfo = 0;
! 1230: rt->rt_flags &= ~RTF_LLINFO;
! 1231: if (ln->ln_hold)
! 1232: m_freem(ln->ln_hold);
! 1233: Free((caddr_t)ln);
! 1234: }
! 1235: }
! 1236:
! 1237: int
! 1238: nd6_ioctl(cmd, data, ifp)
! 1239: u_long cmd;
! 1240: caddr_t data;
! 1241: struct ifnet *ifp;
! 1242: {
! 1243: struct in6_drlist *drl = (struct in6_drlist *)data;
! 1244: struct in6_oprlist *oprl = (struct in6_oprlist *)data;
! 1245: struct in6_ndireq *ndi = (struct in6_ndireq *)data;
! 1246: struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;
! 1247: struct in6_ndifreq *ndif = (struct in6_ndifreq *)data;
! 1248: struct nd_defrouter *dr;
! 1249: struct nd_prefix *pr;
! 1250: struct rtentry *rt;
! 1251: int i = 0, error = 0;
! 1252: int s;
! 1253:
! 1254: switch (cmd) {
! 1255: case SIOCGDRLST_IN6:
! 1256: /*
! 1257: * obsolete API, use sysctl under net.inet6.icmp6
! 1258: */
! 1259: bzero(drl, sizeof(*drl));
! 1260: s = splsoftnet();
! 1261: dr = TAILQ_FIRST(&nd_defrouter);
! 1262: while (dr && i < DRLSTSIZ) {
! 1263: drl->defrouter[i].rtaddr = dr->rtaddr;
! 1264: if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) {
! 1265: /* XXX: need to this hack for KAME stack */
! 1266: drl->defrouter[i].rtaddr.s6_addr16[1] = 0;
! 1267: } else
! 1268: log(LOG_ERR,
! 1269: "default router list contains a "
! 1270: "non-linklocal address(%s)\n",
! 1271: ip6_sprintf(&drl->defrouter[i].rtaddr));
! 1272:
! 1273: drl->defrouter[i].flags = dr->flags;
! 1274: drl->defrouter[i].rtlifetime = dr->rtlifetime;
! 1275: drl->defrouter[i].expire = dr->expire;
! 1276: drl->defrouter[i].if_index = dr->ifp->if_index;
! 1277: i++;
! 1278: dr = TAILQ_NEXT(dr, dr_entry);
! 1279: }
! 1280: splx(s);
! 1281: break;
! 1282: case SIOCGPRLST_IN6:
! 1283: /*
! 1284: * obsolete API, use sysctl under net.inet6.icmp6
! 1285: *
! 1286: * XXX the structure in6_prlist was changed in backward-
! 1287: * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6,
! 1288: * in6_prlist is used for nd6_sysctl() - fill_prlist().
! 1289: */
! 1290: /*
! 1291: * XXX meaning of fields, especially "raflags", is very
! 1292: * different between RA prefix list and RR/static prefix list.
! 1293: * how about separating ioctls into two?
! 1294: */
! 1295: bzero(oprl, sizeof(*oprl));
! 1296: s = splsoftnet();
! 1297: pr = LIST_FIRST(&nd_prefix);
! 1298: while (pr && i < PRLSTSIZ) {
! 1299: struct nd_pfxrouter *pfr;
! 1300: int j;
! 1301:
! 1302: oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr;
! 1303: oprl->prefix[i].raflags = pr->ndpr_raf;
! 1304: oprl->prefix[i].prefixlen = pr->ndpr_plen;
! 1305: oprl->prefix[i].vltime = pr->ndpr_vltime;
! 1306: oprl->prefix[i].pltime = pr->ndpr_pltime;
! 1307: oprl->prefix[i].if_index = pr->ndpr_ifp->if_index;
! 1308: oprl->prefix[i].expire = pr->ndpr_expire;
! 1309:
! 1310: pfr = LIST_FIRST(&pr->ndpr_advrtrs);
! 1311: j = 0;
! 1312: while(pfr) {
! 1313: if (j < DRLSTSIZ) {
! 1314: #define RTRADDR oprl->prefix[i].advrtr[j]
! 1315: RTRADDR = pfr->router->rtaddr;
! 1316: if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) {
! 1317: /* XXX: hack for KAME */
! 1318: RTRADDR.s6_addr16[1] = 0;
! 1319: } else
! 1320: log(LOG_ERR,
! 1321: "a router(%s) advertises "
! 1322: "a prefix with "
! 1323: "non-link local address\n",
! 1324: ip6_sprintf(&RTRADDR));
! 1325: #undef RTRADDR
! 1326: }
! 1327: j++;
! 1328: pfr = LIST_NEXT(pfr, pfr_entry);
! 1329: }
! 1330: oprl->prefix[i].advrtrs = j;
! 1331: oprl->prefix[i].origin = PR_ORIG_RA;
! 1332:
! 1333: i++;
! 1334: pr = LIST_NEXT(pr, ndpr_entry);
! 1335: }
! 1336: splx(s);
! 1337:
! 1338: break;
! 1339: case OSIOCGIFINFO_IN6:
! 1340: /* XXX: old ndp(8) assumes a positive value for linkmtu. */
! 1341: bzero(&ndi->ndi, sizeof(ndi->ndi));
! 1342: ndi->ndi.linkmtu = IN6_LINKMTU(ifp);
! 1343: ndi->ndi.maxmtu = ND_IFINFO(ifp)->maxmtu;
! 1344: ndi->ndi.basereachable = ND_IFINFO(ifp)->basereachable;
! 1345: ndi->ndi.reachable = ND_IFINFO(ifp)->reachable;
! 1346: ndi->ndi.retrans = ND_IFINFO(ifp)->retrans;
! 1347: ndi->ndi.flags = ND_IFINFO(ifp)->flags;
! 1348: ndi->ndi.recalctm = ND_IFINFO(ifp)->recalctm;
! 1349: ndi->ndi.chlim = ND_IFINFO(ifp)->chlim;
! 1350: break;
! 1351: case SIOCGIFINFO_IN6:
! 1352: ndi->ndi = *ND_IFINFO(ifp);
! 1353: break;
! 1354: case SIOCSIFINFO_FLAGS:
! 1355: ND_IFINFO(ifp)->flags = ndi->ndi.flags;
! 1356: break;
! 1357: case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */
! 1358: /* sync kernel routing table with the default router list */
! 1359: defrouter_reset();
! 1360: defrouter_select();
! 1361: break;
! 1362: case SIOCSPFXFLUSH_IN6:
! 1363: {
! 1364: /* flush all the prefix advertised by routers */
! 1365: struct nd_prefix *pr, *next;
! 1366:
! 1367: s = splsoftnet();
! 1368: for (pr = LIST_FIRST(&nd_prefix); pr; pr = next) {
! 1369: struct in6_ifaddr *ia, *ia_next;
! 1370:
! 1371: next = LIST_NEXT(pr, ndpr_entry);
! 1372:
! 1373: if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
! 1374: continue; /* XXX */
! 1375:
! 1376: /* do we really have to remove addresses as well? */
! 1377: for (ia = in6_ifaddr; ia; ia = ia_next) {
! 1378: /* ia might be removed. keep the next ptr. */
! 1379: ia_next = ia->ia_next;
! 1380:
! 1381: if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
! 1382: continue;
! 1383:
! 1384: if (ia->ia6_ndpr == pr)
! 1385: in6_purgeaddr(&ia->ia_ifa);
! 1386: }
! 1387: prelist_remove(pr);
! 1388: }
! 1389: splx(s);
! 1390: break;
! 1391: }
! 1392: case SIOCSRTRFLUSH_IN6:
! 1393: {
! 1394: /* flush all the default routers */
! 1395: struct nd_defrouter *dr, *next;
! 1396:
! 1397: s = splsoftnet();
! 1398: defrouter_reset();
! 1399: for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) {
! 1400: next = TAILQ_NEXT(dr, dr_entry);
! 1401: defrtrlist_del(dr);
! 1402: }
! 1403: defrouter_select();
! 1404: splx(s);
! 1405: break;
! 1406: }
! 1407: case SIOCGNBRINFO_IN6:
! 1408: {
! 1409: struct llinfo_nd6 *ln;
! 1410: struct in6_addr nb_addr = nbi->addr; /* make local for safety */
! 1411:
! 1412: /*
! 1413: * XXX: KAME specific hack for scoped addresses
! 1414: * XXXX: for other scopes than link-local?
! 1415: */
! 1416: if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) ||
! 1417: IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) {
! 1418: u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2];
! 1419:
! 1420: if (*idp == 0)
! 1421: *idp = htons(ifp->if_index);
! 1422: }
! 1423:
! 1424: s = splsoftnet();
! 1425: if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL ||
! 1426: (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) {
! 1427: error = EINVAL;
! 1428: splx(s);
! 1429: break;
! 1430: }
! 1431: nbi->state = ln->ln_state;
! 1432: nbi->asked = ln->ln_asked;
! 1433: nbi->isrouter = ln->ln_router;
! 1434: nbi->expire = ln->ln_expire;
! 1435: splx(s);
! 1436:
! 1437: break;
! 1438: }
! 1439: case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
! 1440: ndif->ifindex = nd6_defifindex;
! 1441: break;
! 1442: case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
! 1443: return (nd6_setdefaultiface(ndif->ifindex));
! 1444: break;
! 1445: }
! 1446: return (error);
! 1447: }
! 1448:
! 1449: /*
! 1450: * Create neighbor cache entry and cache link-layer address,
! 1451: * on reception of inbound ND6 packets. (RS/RA/NS/redirect)
! 1452: */
! 1453: struct rtentry *
! 1454: nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code)
! 1455: struct ifnet *ifp;
! 1456: struct in6_addr *from;
! 1457: char *lladdr;
! 1458: int lladdrlen;
! 1459: int type; /* ICMP6 type */
! 1460: int code; /* type dependent information */
! 1461: {
! 1462: struct rtentry *rt = NULL;
! 1463: struct llinfo_nd6 *ln = NULL;
! 1464: int is_newentry;
! 1465: struct sockaddr_dl *sdl = NULL;
! 1466: int do_update;
! 1467: int olladdr;
! 1468: int llchange;
! 1469: int newstate = 0;
! 1470:
! 1471: if (!ifp)
! 1472: panic("ifp == NULL in nd6_cache_lladdr");
! 1473: if (!from)
! 1474: panic("from == NULL in nd6_cache_lladdr");
! 1475:
! 1476: /* nothing must be updated for unspecified address */
! 1477: if (IN6_IS_ADDR_UNSPECIFIED(from))
! 1478: return NULL;
! 1479:
! 1480: /*
! 1481: * Validation about ifp->if_addrlen and lladdrlen must be done in
! 1482: * the caller.
! 1483: *
! 1484: * XXX If the link does not have link-layer address, what should
! 1485: * we do? (ifp->if_addrlen == 0)
! 1486: * Spec says nothing in sections for RA, RS and NA. There's small
! 1487: * description on it in NS section (RFC 2461 7.2.3).
! 1488: */
! 1489:
! 1490: rt = nd6_lookup(from, 0, ifp);
! 1491: if (!rt) {
! 1492: #if 0
! 1493: /* nothing must be done if there's no lladdr */
! 1494: if (!lladdr || !lladdrlen)
! 1495: return NULL;
! 1496: #endif
! 1497:
! 1498: rt = nd6_lookup(from, 1, ifp);
! 1499: is_newentry = 1;
! 1500: } else {
! 1501: /* do nothing if static ndp is set */
! 1502: if (rt->rt_flags & RTF_STATIC)
! 1503: return NULL;
! 1504: is_newentry = 0;
! 1505: }
! 1506:
! 1507: if (!rt)
! 1508: return NULL;
! 1509: if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) {
! 1510: fail:
! 1511: (void)nd6_free(rt, 0);
! 1512: return NULL;
! 1513: }
! 1514: ln = (struct llinfo_nd6 *)rt->rt_llinfo;
! 1515: if (!ln)
! 1516: goto fail;
! 1517: if (!rt->rt_gateway)
! 1518: goto fail;
! 1519: if (rt->rt_gateway->sa_family != AF_LINK)
! 1520: goto fail;
! 1521: sdl = SDL(rt->rt_gateway);
! 1522:
! 1523: olladdr = (sdl->sdl_alen) ? 1 : 0;
! 1524: if (olladdr && lladdr) {
! 1525: if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen))
! 1526: llchange = 1;
! 1527: else
! 1528: llchange = 0;
! 1529: } else
! 1530: llchange = 0;
! 1531:
! 1532: /*
! 1533: * newentry olladdr lladdr llchange (*=record)
! 1534: * 0 n n -- (1)
! 1535: * 0 y n -- (2)
! 1536: * 0 n y -- (3) * STALE
! 1537: * 0 y y n (4) *
! 1538: * 0 y y y (5) * STALE
! 1539: * 1 -- n -- (6) NOSTATE(= PASSIVE)
! 1540: * 1 -- y -- (7) * STALE
! 1541: */
! 1542:
! 1543: if (lladdr) { /* (3-5) and (7) */
! 1544: /*
! 1545: * Record source link-layer address
! 1546: * XXX is it dependent to ifp->if_type?
! 1547: */
! 1548: sdl->sdl_alen = ifp->if_addrlen;
! 1549: bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
! 1550: }
! 1551:
! 1552: if (!is_newentry) {
! 1553: if ((!olladdr && lladdr) || /* (3) */
! 1554: (olladdr && lladdr && llchange)) { /* (5) */
! 1555: do_update = 1;
! 1556: newstate = ND6_LLINFO_STALE;
! 1557: } else /* (1-2,4) */
! 1558: do_update = 0;
! 1559: } else {
! 1560: do_update = 1;
! 1561: if (!lladdr) /* (6) */
! 1562: newstate = ND6_LLINFO_NOSTATE;
! 1563: else /* (7) */
! 1564: newstate = ND6_LLINFO_STALE;
! 1565: }
! 1566:
! 1567: if (do_update) {
! 1568: /*
! 1569: * Update the state of the neighbor cache.
! 1570: */
! 1571: ln->ln_state = newstate;
! 1572:
! 1573: if (ln->ln_state == ND6_LLINFO_STALE) {
! 1574: /*
! 1575: * XXX: since nd6_output() below will cause
! 1576: * state transition to DELAY and reset the timer,
! 1577: * we must set the timer now, although it is actually
! 1578: * meaningless.
! 1579: */
! 1580: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
! 1581:
! 1582: if (ln->ln_hold) {
! 1583: /*
! 1584: * we assume ifp is not a p2p here, so just
! 1585: * set the 2nd argument as the 1st one.
! 1586: */
! 1587: nd6_output(ifp, ifp, ln->ln_hold,
! 1588: (struct sockaddr_in6 *)rt_key(rt), rt);
! 1589: ln->ln_hold = NULL;
! 1590: }
! 1591: } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
! 1592: /* probe right away */
! 1593: nd6_llinfo_settimer((void *)ln, 0);
! 1594: }
! 1595: }
! 1596:
! 1597: /*
! 1598: * ICMP6 type dependent behavior.
! 1599: *
! 1600: * NS: clear IsRouter if new entry
! 1601: * RS: clear IsRouter
! 1602: * RA: set IsRouter if there's lladdr
! 1603: * redir: clear IsRouter if new entry
! 1604: *
! 1605: * RA case, (1):
! 1606: * The spec says that we must set IsRouter in the following cases:
! 1607: * - If lladdr exist, set IsRouter. This means (1-5).
! 1608: * - If it is old entry (!newentry), set IsRouter. This means (7).
! 1609: * So, based on the spec, in (1-5) and (7) cases we must set IsRouter.
! 1610: * A question arises for (1) case. (1) case has no lladdr in the
! 1611: * neighbor cache, this is similar to (6).
! 1612: * This case is rare but we figured that we MUST NOT set IsRouter.
! 1613: *
! 1614: * newentry olladdr lladdr llchange NS RS RA redir
! 1615: * D R
! 1616: * 0 n n -- (1) c ? s
! 1617: * 0 y n -- (2) c s s
! 1618: * 0 n y -- (3) c s s
! 1619: * 0 y y n (4) c s s
! 1620: * 0 y y y (5) c s s
! 1621: * 1 -- n -- (6) c c c s
! 1622: * 1 -- y -- (7) c c s c s
! 1623: *
! 1624: * (c=clear s=set)
! 1625: */
! 1626: switch (type & 0xff) {
! 1627: case ND_NEIGHBOR_SOLICIT:
! 1628: /*
! 1629: * New entry must have is_router flag cleared.
! 1630: */
! 1631: if (is_newentry) /* (6-7) */
! 1632: ln->ln_router = 0;
! 1633: break;
! 1634: case ND_REDIRECT:
! 1635: /*
! 1636: * If the icmp is a redirect to a better router, always set the
! 1637: * is_router flag. Otherwise, if the entry is newly created,
! 1638: * clear the flag. [RFC 2461, sec 8.3]
! 1639: */
! 1640: if (code == ND_REDIRECT_ROUTER)
! 1641: ln->ln_router = 1;
! 1642: else if (is_newentry) /* (6-7) */
! 1643: ln->ln_router = 0;
! 1644: break;
! 1645: case ND_ROUTER_SOLICIT:
! 1646: /*
! 1647: * is_router flag must always be cleared.
! 1648: */
! 1649: ln->ln_router = 0;
! 1650: break;
! 1651: case ND_ROUTER_ADVERT:
! 1652: /*
! 1653: * Mark an entry with lladdr as a router.
! 1654: */
! 1655: if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */
! 1656: (is_newentry && lladdr)) { /* (7) */
! 1657: ln->ln_router = 1;
! 1658: }
! 1659: break;
! 1660: }
! 1661:
! 1662: /*
! 1663: * When the link-layer address of a router changes, select the
! 1664: * best router again. In particular, when the neighbor entry is newly
! 1665: * created, it might affect the selection policy.
! 1666: * Question: can we restrict the first condition to the "is_newentry"
! 1667: * case?
! 1668: * XXX: when we hear an RA from a new router with the link-layer
! 1669: * address option, defrouter_select() is called twice, since
! 1670: * defrtrlist_update called the function as well. However, I believe
! 1671: * we can compromise the overhead, since it only happens the first
! 1672: * time.
! 1673: * XXX: although defrouter_select() should not have a bad effect
! 1674: * for those are not autoconfigured hosts, we explicitly avoid such
! 1675: * cases for safety.
! 1676: */
! 1677: if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv)
! 1678: defrouter_select();
! 1679:
! 1680: return rt;
! 1681: }
! 1682:
! 1683: static void
! 1684: nd6_slowtimo(ignored_arg)
! 1685: void *ignored_arg;
! 1686: {
! 1687: int s = splsoftnet();
! 1688: struct nd_ifinfo *nd6if;
! 1689: struct ifnet *ifp;
! 1690:
! 1691: timeout_set(&nd6_slowtimo_ch, nd6_slowtimo, NULL);
! 1692: timeout_add(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz);
! 1693: for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
! 1694: {
! 1695: nd6if = ND_IFINFO(ifp);
! 1696: if (nd6if->basereachable && /* already initialized */
! 1697: (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) {
! 1698: /*
! 1699: * Since reachable time rarely changes by router
! 1700: * advertisements, we SHOULD insure that a new random
! 1701: * value gets recomputed at least once every few hours.
! 1702: * (RFC 2461, 6.3.4)
! 1703: */
! 1704: nd6if->recalctm = nd6_recalc_reachtm_interval;
! 1705: nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable);
! 1706: }
! 1707: }
! 1708: splx(s);
! 1709: }
! 1710:
! 1711: #define senderr(e) { error = (e); goto bad;}
! 1712: int
! 1713: nd6_output(ifp, origifp, m0, dst, rt0)
! 1714: struct ifnet *ifp;
! 1715: struct ifnet *origifp;
! 1716: struct mbuf *m0;
! 1717: struct sockaddr_in6 *dst;
! 1718: struct rtentry *rt0;
! 1719: {
! 1720: struct mbuf *m = m0;
! 1721: struct rtentry *rt = rt0;
! 1722: struct sockaddr_in6 *gw6 = NULL;
! 1723: struct llinfo_nd6 *ln = NULL;
! 1724: int error = 0;
! 1725: #ifdef IPSEC
! 1726: struct m_tag *mtag;
! 1727: #endif /* IPSEC */
! 1728:
! 1729: if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
! 1730: goto sendpkt;
! 1731:
! 1732: if (nd6_need_cache(ifp) == 0)
! 1733: goto sendpkt;
! 1734:
! 1735: /*
! 1736: * next hop determination. This routine is derived from ether_output.
! 1737: */
! 1738: if (rt) {
! 1739: if ((rt->rt_flags & RTF_UP) == 0) {
! 1740: if ((rt0 = rt = rtalloc1((struct sockaddr *)dst,
! 1741: 1, 0)) != NULL)
! 1742: {
! 1743: rt->rt_refcnt--;
! 1744: if (rt->rt_ifp != ifp)
! 1745: senderr(EHOSTUNREACH);
! 1746: } else
! 1747: senderr(EHOSTUNREACH);
! 1748: }
! 1749:
! 1750: if (rt->rt_flags & RTF_GATEWAY) {
! 1751: gw6 = (struct sockaddr_in6 *)rt->rt_gateway;
! 1752:
! 1753: /*
! 1754: * We skip link-layer address resolution and NUD
! 1755: * if the gateway is not a neighbor from ND point
! 1756: * of view, regardless of the value of nd_ifinfo.flags.
! 1757: * The second condition is a bit tricky; we skip
! 1758: * if the gateway is our own address, which is
! 1759: * sometimes used to install a route to a p2p link.
! 1760: */
! 1761: if (!nd6_is_addr_neighbor(gw6, ifp) ||
! 1762: in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
! 1763: /*
! 1764: * We allow this kind of tricky route only
! 1765: * when the outgoing interface is p2p.
! 1766: * XXX: we may need a more generic rule here.
! 1767: */
! 1768: if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
! 1769: senderr(EHOSTUNREACH);
! 1770:
! 1771: goto sendpkt;
! 1772: }
! 1773:
! 1774: if (rt->rt_gwroute == 0)
! 1775: goto lookup;
! 1776: if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
! 1777: rtfree(rt); rt = rt0;
! 1778: lookup:
! 1779: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0);
! 1780: if ((rt = rt->rt_gwroute) == 0)
! 1781: senderr(EHOSTUNREACH);
! 1782: }
! 1783: }
! 1784: }
! 1785:
! 1786: /*
! 1787: * Address resolution or Neighbor Unreachability Detection
! 1788: * for the next hop.
! 1789: * At this point, the destination of the packet must be a unicast
! 1790: * or an anycast address(i.e. not a multicast).
! 1791: */
! 1792:
! 1793: /* Look up the neighbor cache for the nexthop */
! 1794: if (rt && (rt->rt_flags & RTF_LLINFO) != 0)
! 1795: ln = (struct llinfo_nd6 *)rt->rt_llinfo;
! 1796: else {
! 1797: /*
! 1798: * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
! 1799: * the condition below is not very efficient. But we believe
! 1800: * it is tolerable, because this should be a rare case.
! 1801: */
! 1802: if (nd6_is_addr_neighbor(dst, ifp) &&
! 1803: (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL)
! 1804: ln = (struct llinfo_nd6 *)rt->rt_llinfo;
! 1805: }
! 1806: if (!ln || !rt) {
! 1807: if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
! 1808: !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) {
! 1809: log(LOG_DEBUG,
! 1810: "nd6_output: can't allocate llinfo for %s "
! 1811: "(ln=%p, rt=%p)\n",
! 1812: ip6_sprintf(&dst->sin6_addr), ln, rt);
! 1813: senderr(EIO); /* XXX: good error? */
! 1814: }
! 1815:
! 1816: goto sendpkt; /* send anyway */
! 1817: }
! 1818:
! 1819: /* We don't have to do link-layer address resolution on a p2p link. */
! 1820: if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
! 1821: ln->ln_state < ND6_LLINFO_REACHABLE) {
! 1822: ln->ln_state = ND6_LLINFO_STALE;
! 1823: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
! 1824: }
! 1825:
! 1826: /*
! 1827: * The first time we send a packet to a neighbor whose entry is
! 1828: * STALE, we have to change the state to DELAY and a sets a timer to
! 1829: * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do
! 1830: * neighbor unreachability detection on expiration.
! 1831: * (RFC 2461 7.3.3)
! 1832: */
! 1833: if (ln->ln_state == ND6_LLINFO_STALE) {
! 1834: ln->ln_asked = 0;
! 1835: ln->ln_state = ND6_LLINFO_DELAY;
! 1836: nd6_llinfo_settimer(ln, nd6_delay * hz);
! 1837: }
! 1838:
! 1839: /*
! 1840: * If the neighbor cache entry has a state other than INCOMPLETE
! 1841: * (i.e. its link-layer address is already resolved), just
! 1842: * send the packet.
! 1843: */
! 1844: if (ln->ln_state > ND6_LLINFO_INCOMPLETE)
! 1845: goto sendpkt;
! 1846:
! 1847: /*
! 1848: * There is a neighbor cache entry, but no ethernet address
! 1849: * response yet. Replace the held mbuf (if any) with this
! 1850: * latest one.
! 1851: */
! 1852: if (ln->ln_state == ND6_LLINFO_NOSTATE)
! 1853: ln->ln_state = ND6_LLINFO_INCOMPLETE;
! 1854: if (ln->ln_hold)
! 1855: m_freem(ln->ln_hold);
! 1856: ln->ln_hold = m;
! 1857: /*
! 1858: * If there has been no NS for the neighbor after entering the
! 1859: * INCOMPLETE state, send the first solicitation.
! 1860: */
! 1861: if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
! 1862: ln->ln_asked++;
! 1863: nd6_llinfo_settimer(ln,
! 1864: (long)ND_IFINFO(ifp)->retrans * hz / 1000);
! 1865: nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
! 1866: }
! 1867: return (0);
! 1868:
! 1869: sendpkt:
! 1870: #ifdef IPSEC
! 1871: /*
! 1872: * If the packet needs outgoing IPsec crypto processing and the
! 1873: * interface doesn't support it, drop it.
! 1874: */
! 1875: mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL);
! 1876: #endif /* IPSEC */
! 1877:
! 1878: if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
! 1879: #ifdef IPSEC
! 1880: if (mtag != NULL &&
! 1881: (origifp->if_capabilities & IFCAP_IPSEC) == 0) {
! 1882: /* Tell IPsec to do its own crypto. */
! 1883: ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
! 1884: error = EACCES;
! 1885: goto bad;
! 1886: }
! 1887: #endif /* IPSEC */
! 1888: return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst,
! 1889: rt));
! 1890: }
! 1891: #ifdef IPSEC
! 1892: if (mtag != NULL &&
! 1893: (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
! 1894: /* Tell IPsec to do its own crypto. */
! 1895: ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
! 1896: error = EACCES;
! 1897: goto bad;
! 1898: }
! 1899: #endif /* IPSEC */
! 1900: return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt));
! 1901:
! 1902: bad:
! 1903: if (m)
! 1904: m_freem(m);
! 1905: return (error);
! 1906: }
! 1907: #undef senderr
! 1908:
! 1909: int
! 1910: nd6_need_cache(ifp)
! 1911: struct ifnet *ifp;
! 1912: {
! 1913: /*
! 1914: * XXX: we currently do not make neighbor cache on any interface
! 1915: * other than Ethernet, FDDI and GIF.
! 1916: *
! 1917: * RFC2893 says:
! 1918: * - unidirectional tunnels needs no ND
! 1919: */
! 1920: switch (ifp->if_type) {
! 1921: case IFT_ETHER:
! 1922: case IFT_FDDI:
! 1923: case IFT_IEEE1394:
! 1924: case IFT_PROPVIRTUAL:
! 1925: case IFT_L2VLAN:
! 1926: case IFT_IEEE80211:
! 1927: case IFT_CARP:
! 1928: case IFT_GIF: /* XXX need more cases? */
! 1929: return (1);
! 1930: default:
! 1931: return (0);
! 1932: }
! 1933: }
! 1934:
! 1935: int
! 1936: nd6_storelladdr(ifp, rt, m, dst, desten)
! 1937: struct ifnet *ifp;
! 1938: struct rtentry *rt;
! 1939: struct mbuf *m;
! 1940: struct sockaddr *dst;
! 1941: u_char *desten;
! 1942: {
! 1943: struct sockaddr_dl *sdl;
! 1944:
! 1945: if (m->m_flags & M_MCAST) {
! 1946: switch (ifp->if_type) {
! 1947: case IFT_ETHER:
! 1948: case IFT_FDDI:
! 1949: ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr,
! 1950: desten);
! 1951: return (1);
! 1952: break;
! 1953: default:
! 1954: m_freem(m);
! 1955: return (0);
! 1956: }
! 1957: }
! 1958:
! 1959: if (rt == NULL) {
! 1960: /* this could happen, if we could not allocate memory */
! 1961: m_freem(m);
! 1962: return (0);
! 1963: }
! 1964: if (rt->rt_gateway->sa_family != AF_LINK) {
! 1965: printf("nd6_storelladdr: something odd happens\n");
! 1966: m_freem(m);
! 1967: return (0);
! 1968: }
! 1969: sdl = SDL(rt->rt_gateway);
! 1970: if (sdl->sdl_alen == 0) {
! 1971: /* this should be impossible, but we bark here for debugging */
! 1972: printf("nd6_storelladdr: sdl_alen == 0, dst=%s, if=%s\n",
! 1973: ip6_sprintf(&SIN6(dst)->sin6_addr), ifp->if_xname);
! 1974: m_freem(m);
! 1975: return (0);
! 1976: }
! 1977:
! 1978: bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
! 1979: return (1);
! 1980: }
! 1981:
! 1982: int
! 1983: nd6_sysctl(name, oldp, oldlenp, newp, newlen)
! 1984: int name;
! 1985: void *oldp; /* syscall arg, need copyout */
! 1986: size_t *oldlenp;
! 1987: void *newp; /* syscall arg, need copyin */
! 1988: size_t newlen;
! 1989: {
! 1990: void *p;
! 1991: size_t ol, l;
! 1992: int error;
! 1993:
! 1994: error = 0;
! 1995: l = 0;
! 1996:
! 1997: if (newp)
! 1998: return EPERM;
! 1999: if (oldp && !oldlenp)
! 2000: return EINVAL;
! 2001: ol = oldlenp ? *oldlenp : 0;
! 2002:
! 2003: if (oldp) {
! 2004: p = malloc(*oldlenp, M_TEMP, M_WAITOK);
! 2005: if (!p)
! 2006: return ENOMEM;
! 2007: } else
! 2008: p = NULL;
! 2009: switch (name) {
! 2010: case ICMPV6CTL_ND6_DRLIST:
! 2011: error = fill_drlist(p, oldlenp, ol);
! 2012: if (!error && p && oldp)
! 2013: error = copyout(p, oldp, *oldlenp);
! 2014: break;
! 2015:
! 2016: case ICMPV6CTL_ND6_PRLIST:
! 2017: error = fill_prlist(p, oldlenp, ol);
! 2018: if (!error && p && oldp)
! 2019: error = copyout(p, oldp, *oldlenp);
! 2020: break;
! 2021:
! 2022: default:
! 2023: error = ENOPROTOOPT;
! 2024: break;
! 2025: }
! 2026: if (p)
! 2027: free(p, M_TEMP);
! 2028:
! 2029: return (error);
! 2030: }
! 2031:
! 2032: static int
! 2033: fill_drlist(oldp, oldlenp, ol)
! 2034: void *oldp;
! 2035: size_t *oldlenp, ol;
! 2036: {
! 2037: int error = 0, s;
! 2038: struct in6_defrouter *d = NULL, *de = NULL;
! 2039: struct nd_defrouter *dr;
! 2040: size_t l;
! 2041:
! 2042: s = splsoftnet();
! 2043:
! 2044: if (oldp) {
! 2045: d = (struct in6_defrouter *)oldp;
! 2046: de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp);
! 2047: }
! 2048: l = 0;
! 2049:
! 2050: for (dr = TAILQ_FIRST(&nd_defrouter); dr;
! 2051: dr = TAILQ_NEXT(dr, dr_entry)) {
! 2052:
! 2053: if (oldp && d + 1 <= de) {
! 2054: bzero(d, sizeof(*d));
! 2055: d->rtaddr.sin6_family = AF_INET6;
! 2056: d->rtaddr.sin6_len = sizeof(struct sockaddr_in6);
! 2057: d->rtaddr.sin6_addr = dr->rtaddr;
! 2058: in6_recoverscope(&d->rtaddr, &d->rtaddr.sin6_addr,
! 2059: dr->ifp);
! 2060: d->flags = dr->flags;
! 2061: d->rtlifetime = dr->rtlifetime;
! 2062: d->expire = dr->expire;
! 2063: d->if_index = dr->ifp->if_index;
! 2064: }
! 2065:
! 2066: l += sizeof(*d);
! 2067: if (d)
! 2068: d++;
! 2069: }
! 2070:
! 2071: if (oldp) {
! 2072: *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */
! 2073: if (l > ol)
! 2074: error = ENOMEM;
! 2075: } else
! 2076: *oldlenp = l;
! 2077:
! 2078: splx(s);
! 2079:
! 2080: return (error);
! 2081: }
! 2082:
! 2083: static int
! 2084: fill_prlist(oldp, oldlenp, ol)
! 2085: void *oldp;
! 2086: size_t *oldlenp, ol;
! 2087: {
! 2088: int error = 0, s;
! 2089: struct nd_prefix *pr;
! 2090: struct in6_prefix *p = NULL;
! 2091: struct in6_prefix *pe = NULL;
! 2092: size_t l;
! 2093:
! 2094: s = splsoftnet();
! 2095:
! 2096: if (oldp) {
! 2097: p = (struct in6_prefix *)oldp;
! 2098: pe = (struct in6_prefix *)((caddr_t)oldp + *oldlenp);
! 2099: }
! 2100: l = 0;
! 2101:
! 2102: LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
! 2103: u_short advrtrs;
! 2104: size_t advance;
! 2105: struct sockaddr_in6 *sin6;
! 2106: struct sockaddr_in6 *s6;
! 2107: struct nd_pfxrouter *pfr;
! 2108:
! 2109: if (oldp && p + 1 <= pe)
! 2110: {
! 2111: bzero(p, sizeof(*p));
! 2112: sin6 = (struct sockaddr_in6 *)(p + 1);
! 2113:
! 2114: p->prefix = pr->ndpr_prefix;
! 2115: if (in6_recoverscope(&p->prefix,
! 2116: &p->prefix.sin6_addr, pr->ndpr_ifp) != 0)
! 2117: log(LOG_ERR,
! 2118: "scope error in prefix list (%s)\n",
! 2119: ip6_sprintf(&p->prefix.sin6_addr));
! 2120: p->raflags = pr->ndpr_raf;
! 2121: p->prefixlen = pr->ndpr_plen;
! 2122: p->vltime = pr->ndpr_vltime;
! 2123: p->pltime = pr->ndpr_pltime;
! 2124: p->if_index = pr->ndpr_ifp->if_index;
! 2125: if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
! 2126: p->expire = 0;
! 2127: else {
! 2128: time_t maxexpire;
! 2129:
! 2130: /* XXX: we assume time_t is signed. */
! 2131: maxexpire = (-1) &
! 2132: ~(1 << ((sizeof(maxexpire) * 8) - 1));
! 2133: if (pr->ndpr_vltime <
! 2134: maxexpire - pr->ndpr_lastupdate) {
! 2135: p->expire = pr->ndpr_lastupdate +
! 2136: pr->ndpr_vltime;
! 2137: } else
! 2138: p->expire = maxexpire;
! 2139: }
! 2140: p->refcnt = pr->ndpr_refcnt;
! 2141: p->flags = pr->ndpr_stateflags;
! 2142: p->origin = PR_ORIG_RA;
! 2143: advrtrs = 0;
! 2144: LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
! 2145: if ((void *)&sin6[advrtrs + 1] > (void *)pe) {
! 2146: advrtrs++;
! 2147: continue;
! 2148: }
! 2149: s6 = &sin6[advrtrs];
! 2150: s6->sin6_family = AF_INET6;
! 2151: s6->sin6_len = sizeof(struct sockaddr_in6);
! 2152: s6->sin6_addr = pfr->router->rtaddr;
! 2153: in6_recoverscope(s6, &pfr->router->rtaddr,
! 2154: pfr->router->ifp);
! 2155: advrtrs++;
! 2156: }
! 2157: p->advrtrs = advrtrs;
! 2158: }
! 2159: else {
! 2160: advrtrs = 0;
! 2161: LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry)
! 2162: advrtrs++;
! 2163: }
! 2164:
! 2165: advance = sizeof(*p) + sizeof(*sin6) * advrtrs;
! 2166: l += advance;
! 2167: if (p)
! 2168: p = (struct in6_prefix *)((caddr_t)p + advance);
! 2169: }
! 2170:
! 2171: if (oldp) {
! 2172: *oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */
! 2173: if (l > ol)
! 2174: error = ENOMEM;
! 2175: } else
! 2176: *oldlenp = l;
! 2177:
! 2178: splx(s);
! 2179:
! 2180: return (error);
! 2181: }
CVSweb