[BACK]Return to nd6.c CVS log [TXT][DIR] Up to [local] / sys / netinet6

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