[BACK]Return to nd6_rtr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/nd6_rtr.c, Revision 1.17

1.17    ! itojun      1: /*     $NetBSD: nd6_rtr.c,v 1.16 2000/06/13 02:54:11 itojun Exp $      */
        !             2: /*     $KAME: nd6_rtr.c,v 1.40 2000/06/13 03:02:29 jinmei Exp $        */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.16      itojun      7:  *
1.2       itojun      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.
1.16      itojun     19:  *
1.2       itojun     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/malloc.h>
                     36: #include <sys/mbuf.h>
                     37: #include <sys/socket.h>
                     38: #include <sys/sockio.h>
                     39: #include <sys/time.h>
                     40: #include <sys/kernel.h>
                     41: #include <sys/errno.h>
                     42: #include <sys/ioctl.h>
                     43: #include <sys/syslog.h>
                     44:
                     45: #include <net/if.h>
                     46: #include <net/if_types.h>
                     47: #include <net/if_dl.h>
                     48: #include <net/route.h>
                     49: #include <net/radix.h>
                     50:
                     51: #include <netinet/in.h>
                     52: #include <netinet6/in6_var.h>
1.11      itojun     53: #include <netinet/ip6.h>
1.2       itojun     54: #include <netinet6/ip6_var.h>
                     55: #include <netinet6/nd6.h>
1.11      itojun     56: #include <netinet/icmp6.h>
1.2       itojun     57:
1.7       itojun     58: #include <net/net_osdep.h>
1.2       itojun     59:
                     60: #define SDL(s) ((struct sockaddr_dl *)s)
                     61:
                     62: static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
                     63: static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *));
                     64: static struct nd_prefix *prefix_lookup __P((struct nd_prefix *));
                     65: static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *,
                     66:                          struct in6_addr *, int));
                     67: static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
                     68:                                               struct nd_defrouter *));
                     69: static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
                     70: static void pfxrtr_del __P((struct nd_pfxrouter *));
1.7       itojun     71: static struct nd_pfxrouter *find_pfxlist_reachable_router __P((struct nd_prefix *));
1.2       itojun     72: static void nd6_detach_prefix __P((struct nd_prefix *));
                     73: static void nd6_attach_prefix __P((struct nd_prefix *));
1.7       itojun     74: static void defrouter_addifreq __P((struct ifnet *));
1.2       itojun     75:
                     76: static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
1.7       itojun     77:                                         struct in6_addrlifetime *lt6,
                     78:                                         int update_vltime));
1.2       itojun     79:
                     80: static int rt6_deleteroute __P((struct radix_node *, void *));
                     81:
                     82: extern int nd6_recalc_reachtm_interval;
                     83:
1.7       itojun     84: struct ifnet *nd6_defifp;
                     85: int nd6_defifindex;
                     86:
1.2       itojun     87: /*
                     88:  * Receive Router Solicitation Message - just for routers.
                     89:  * Router solicitation/advertisement is mostly managed by userland program
                     90:  * (rtadvd) so here we have no function like nd6_ra_output().
                     91:  *
                     92:  * Based on RFC 2461
                     93:  */
                     94: void
                     95: nd6_rs_input(m, off, icmp6len)
                     96:        struct  mbuf *m;
                     97:        int off, icmp6len;
                     98: {
                     99:        struct ifnet *ifp = m->m_pkthdr.rcvif;
                    100:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.12      itojun    101:        struct nd_router_solicit *nd_rs;
1.2       itojun    102:        struct in6_addr saddr6 = ip6->ip6_src;
                    103: #if 0
                    104:        struct in6_addr daddr6 = ip6->ip6_dst;
                    105: #endif
                    106:        char *lladdr = NULL;
                    107:        int lladdrlen = 0;
                    108: #if 0
                    109:        struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL;
                    110:        struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL;
                    111:        struct rtentry *rt = NULL;
                    112:        int is_newentry;
                    113: #endif
                    114:        union nd_opts ndopts;
                    115:
                    116:        /* If I'm not a router, ignore it. */
                    117:        if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
1.12      itojun    118:                goto freeit;
1.2       itojun    119:
                    120:        /* Sanity checks */
                    121:        if (ip6->ip6_hlim != 255) {
                    122:                log(LOG_ERR,
                    123:                    "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
1.12      itojun    124:                goto freeit;
1.2       itojun    125:        }
                    126:
                    127:        /*
                    128:         * Don't update the neighbor cache, if src = ::.
                    129:         * This indicates that the src has no IP address assigned yet.
                    130:         */
                    131:        if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
1.12      itojun    132:                goto freeit;
                    133:
                    134: #ifndef PULLDOWN_TEST
                    135:        IP6_EXTHDR_CHECK(m, off, icmp6len,);
                    136:        nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
                    137: #else
                    138:        IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
                    139:        if (nd_rs == NULL) {
                    140:                icmp6stat.icp6s_tooshort++;
1.2       itojun    141:                return;
1.12      itojun    142:        }
                    143: #endif
1.2       itojun    144:
                    145:        icmp6len -= sizeof(*nd_rs);
                    146:        nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
                    147:        if (nd6_options(&ndopts) < 0) {
                    148:                log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n");
1.12      itojun    149:                goto freeit;
1.2       itojun    150:        }
                    151:
                    152:        if (ndopts.nd_opts_src_lladdr) {
                    153:                lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
                    154:                lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
                    155:        }
                    156:
                    157:        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
                    158:                log(LOG_INFO,
                    159:                    "nd6_rs_input: lladdrlen mismatch for %s "
                    160:                    "(if %d, RS packet %d)\n",
                    161:                        ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
                    162:        }
                    163:
1.6       itojun    164:        nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
1.12      itojun    165:
                    166:  freeit:
                    167:        m_freem(m);
1.2       itojun    168: }
                    169:
                    170: /*
                    171:  * Receive Router Advertisement Message.
                    172:  *
                    173:  * Based on RFC 2461
                    174:  * TODO: on-link bit on prefix information
                    175:  * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
                    176:  */
                    177: void
                    178: nd6_ra_input(m, off, icmp6len)
                    179:        struct  mbuf *m;
                    180:        int off, icmp6len;
                    181: {
                    182:        struct ifnet *ifp = m->m_pkthdr.rcvif;
                    183:        struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
                    184:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.12      itojun    185:        struct nd_router_advert *nd_ra;
1.2       itojun    186:        struct in6_addr saddr6 = ip6->ip6_src;
                    187: #if 0
                    188:        struct in6_addr daddr6 = ip6->ip6_dst;
1.12      itojun    189:        int flags; /* = nd_ra->nd_ra_flags_reserved; */
1.2       itojun    190:        int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
                    191:        int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
                    192: #endif
                    193:        union nd_opts ndopts;
                    194:        struct nd_defrouter *dr;
                    195:
                    196:        if (ip6_accept_rtadv == 0)
1.12      itojun    197:                goto freeit;
1.2       itojun    198:
                    199:        if (ip6->ip6_hlim != 255) {
                    200:                log(LOG_ERR,
                    201:                    "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
1.12      itojun    202:                goto freeit;
1.2       itojun    203:        }
                    204:
                    205:        if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
                    206:                log(LOG_ERR,
                    207:                    "nd6_ra_input: src %s is not link-local\n",
                    208:                    ip6_sprintf(&saddr6));
1.12      itojun    209:                goto freeit;
                    210:        }
                    211:
                    212: #ifndef PULLDOWN_TEST
                    213:        IP6_EXTHDR_CHECK(m, off, icmp6len,);
                    214:        nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
                    215: #else
                    216:        IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
                    217:        if (nd_ra == NULL) {
                    218:                icmp6stat.icp6s_tooshort++;
1.2       itojun    219:                return;
                    220:        }
1.12      itojun    221: #endif
1.2       itojun    222:
                    223:        icmp6len -= sizeof(*nd_ra);
                    224:        nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
                    225:        if (nd6_options(&ndopts) < 0) {
                    226:                log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n");
1.12      itojun    227:                goto freeit;
1.2       itojun    228:        }
                    229:
                    230:     {
                    231:        struct nd_defrouter dr0;
                    232:        u_int32_t advreachable = nd_ra->nd_ra_reachable;
1.7       itojun    233:        long time_second = time.tv_sec;
1.2       itojun    234:
                    235:        dr0.rtaddr = saddr6;
                    236:        dr0.flags  = nd_ra->nd_ra_flags_reserved;
                    237:        dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
                    238:        dr0.expire = time_second + dr0.rtlifetime;
                    239:        dr0.ifp = ifp;
                    240:        /* unspecified or not? (RFC 2461 6.3.4) */
                    241:        if (advreachable) {
                    242:                NTOHL(advreachable);
                    243:                if (advreachable <= MAX_REACHABLE_TIME &&
                    244:                    ndi->basereachable != advreachable) {
                    245:                        ndi->basereachable = advreachable;
                    246:                        ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
                    247:                        ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
                    248:                }
                    249:        }
                    250:        if (nd_ra->nd_ra_retransmit)
                    251:                ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
                    252:        if (nd_ra->nd_ra_curhoplimit)
                    253:                ndi->chlim = nd_ra->nd_ra_curhoplimit;
                    254:        dr = defrtrlist_update(&dr0);
                    255:     }
                    256:
                    257:        /*
                    258:         * prefix
                    259:         */
                    260:        if (ndopts.nd_opts_pi) {
                    261:                struct nd_opt_hdr *pt;
                    262:                struct nd_opt_prefix_info *pi;
                    263:                struct nd_prefix pr;
                    264:
                    265:                for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
                    266:                     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
                    267:                     pt = (struct nd_opt_hdr *)((caddr_t)pt +
                    268:                                                (pt->nd_opt_len << 3))) {
                    269:                        if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
                    270:                                continue;
                    271:                        pi = (struct nd_opt_prefix_info *)pt;
                    272:
                    273:                        if (pi->nd_opt_pi_len != 4) {
                    274:                                log(LOG_INFO, "nd6_ra_input: invalid option "
                    275:                                        "len %d for prefix information option, "
                    276:                                        "ignored\n", pi->nd_opt_pi_len);
                    277:                                continue;
                    278:                        }
                    279:
                    280:                        if (128 < pi->nd_opt_pi_prefix_len) {
                    281:                                log(LOG_INFO, "nd6_ra_input: invalid prefix "
                    282:                                        "len %d for prefix information option, "
                    283:                                        "ignored\n", pi->nd_opt_pi_prefix_len);
                    284:                                continue;
                    285:                        }
                    286:
                    287:                        if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
                    288:                         || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
                    289:                                log(LOG_INFO, "nd6_ra_input: invalid prefix "
                    290:                                        "%s, ignored\n",
                    291:                                        ip6_sprintf(&pi->nd_opt_pi_prefix));
                    292:                                continue;
                    293:                        }
                    294:
                    295:                        /* aggregatable unicast address, rfc2374 */
                    296:                        if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
                    297:                         && pi->nd_opt_pi_prefix_len != 64) {
                    298:                                log(LOG_INFO, "nd6_ra_input: invalid prefixlen "
                    299:                                        "%d for rfc2374 prefix %s, ignored\n",
                    300:                                        pi->nd_opt_pi_prefix_len,
                    301:                                        ip6_sprintf(&pi->nd_opt_pi_prefix));
                    302:                                continue;
                    303:                        }
                    304:
                    305:                        bzero(&pr, sizeof(pr));
                    306:                        pr.ndpr_prefix.sin6_family = AF_INET6;
                    307:                        pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
                    308:                        pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
                    309:                        pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
                    310:
                    311:                        pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
                    312:                                              ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
                    313:                        pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
                    314:                                            ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
                    315:                        pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
                    316:                        pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
                    317:                        pr.ndpr_pltime =
                    318:                                ntohl(pi->nd_opt_pi_preferred_time);
                    319:
                    320:                        if (in6_init_prefix_ltimes(&pr))
                    321:                                continue; /* prefix lifetime init failed */
                    322:
                    323:                        (void)prelist_update(&pr, dr, m);
                    324:                }
                    325:        }
                    326:
                    327:        /*
                    328:         * MTU
                    329:         */
                    330:        if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
                    331:                u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
                    332:
                    333:                /* lower bound */
                    334:                if (mtu < IPV6_MMTU) {
                    335:                        log(LOG_INFO, "nd6_ra_input: bogus mtu option "
                    336:                            "mtu=%d sent from %s, ignoring\n",
                    337:                            mtu, ip6_sprintf(&ip6->ip6_src));
                    338:                        goto skip;
                    339:                }
                    340:
                    341:                /* upper bound */
                    342:                if (ndi->maxmtu) {
                    343:                        if (mtu <= ndi->maxmtu) {
                    344:                                int change = (ndi->linkmtu != mtu);
                    345:
                    346:                                ndi->linkmtu = mtu;
                    347:                                if (change) /* in6_maxmtu may change */
                    348:                                        in6_setmaxmtu();
                    349:                        } else {
                    350:                                log(LOG_INFO, "nd6_ra_input: bogus mtu "
                    351:                                    "mtu=%d sent from %s; "
                    352:                                    "exceeds maxmtu %d, ignoring\n",
                    353:                                    mtu, ip6_sprintf(&ip6->ip6_src),
                    354:                                    ndi->maxmtu);
                    355:                        }
                    356:                } else {
                    357:                        log(LOG_INFO, "nd6_ra_input: mtu option "
                    358:                            "mtu=%d sent from %s; maxmtu unknown, "
                    359:                            "ignoring\n",
                    360:                            mtu, ip6_sprintf(&ip6->ip6_src));
                    361:                }
                    362:        }
                    363:
                    364:  skip:
                    365:
                    366:        /*
                    367:         * Src linkaddress
                    368:         */
                    369:     {
                    370:        char *lladdr = NULL;
                    371:        int lladdrlen = 0;
                    372:
                    373:        if (ndopts.nd_opts_src_lladdr) {
                    374:                lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
                    375:                lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
                    376:        }
                    377:
                    378:        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
                    379:                log(LOG_INFO,
                    380:                    "nd6_ra_input: lladdrlen mismatch for %s "
                    381:                    "(if %d, RA packet %d)\n",
                    382:                        ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
                    383:        }
                    384:
1.6       itojun    385:        nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
1.7       itojun    386:
                    387:        /*
                    388:         * Installing a link-layer address might change the state of the
                    389:         * router's neighbor cache, which might also affect our on-link
                    390:         * detection of adveritsed prefixes.
                    391:         */
                    392:        pfxlist_onlink_check();
1.2       itojun    393:     }
1.12      itojun    394:
1.16      itojun    395: freeit:
1.12      itojun    396:        m_freem(m);
1.2       itojun    397: }
                    398:
                    399: /*
                    400:  * default router list proccessing sub routines
                    401:  */
                    402: void
                    403: defrouter_addreq(new)
                    404:        struct nd_defrouter *new;
                    405: {
                    406:        struct sockaddr_in6 def, mask, gate;
                    407:        int s;
                    408:
                    409:        Bzero(&def, sizeof(def));
                    410:        Bzero(&mask, sizeof(mask));
                    411:        Bzero(&gate, sizeof(gate));
                    412:
                    413:        def.sin6_len = mask.sin6_len = gate.sin6_len
                    414:                = sizeof(struct sockaddr_in6);
                    415:        def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
                    416:        gate.sin6_addr = new->rtaddr;
                    417:
1.4       itojun    418:        s = splsoftnet();
1.2       itojun    419:        (void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
                    420:                (struct sockaddr *)&gate, (struct sockaddr *)&mask,
                    421:                RTF_GATEWAY, NULL);
                    422:        splx(s);
                    423:        return;
                    424: }
                    425:
1.7       itojun    426: /* Add a route to a given interface as default */
                    427: static void
                    428: defrouter_addifreq(ifp)
                    429:        struct ifnet *ifp;
                    430: {
                    431:        struct sockaddr_in6 def, mask;
                    432:        struct ifaddr *ifa;
                    433:        int error, flags;
                    434:
                    435:        bzero(&def, sizeof(def));
                    436:        bzero(&mask, sizeof(mask));
                    437:
                    438:        def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
                    439:        def.sin6_family = mask.sin6_family = AF_INET6;
                    440:
                    441:        /*
                    442:         * Search for an ifaddr beloging to the specified interface.
                    443:         * XXX: An IPv6 address are required to be assigned on the interface.
                    444:         */
                    445:        if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {
                    446:                log(LOG_ERR,    /* better error? */
                    447:                    "defrouter_addifreq: failed to find an ifaddr "
                    448:                    "to install a route to interface %s\n",
                    449:                    if_name(ifp));
                    450:                return;
                    451:        }
                    452:
                    453:        flags = ifa->ifa_flags;
                    454:        if ((ifp->if_flags & IFF_POINTOPOINT) != 0)
                    455:                flags &= ~RTF_CLONING;
                    456:        if ((error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
                    457:                               ifa->ifa_addr, (struct sockaddr *)&mask,
                    458:                               flags, NULL)) != 0) {
                    459:                log(LOG_ERR,
                    460:                    "defrouter_addifreq: failed to install a route to "
                    461:                    "interface %s (errno = %d)\n",
                    462:                    if_name(ifp), error);
                    463:        }
                    464: }
                    465:
1.2       itojun    466: struct nd_defrouter *
                    467: defrouter_lookup(addr, ifp)
                    468:        struct in6_addr *addr;
                    469:        struct ifnet *ifp;
                    470: {
                    471:        struct nd_defrouter *dr;
                    472:
1.7       itojun    473:        for (dr = TAILQ_FIRST(&nd_defrouter); dr;
                    474:             dr = TAILQ_NEXT(dr, dr_entry)) {
1.2       itojun    475:                if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
                    476:                        return(dr);
1.7       itojun    477:        }
1.2       itojun    478:
                    479:        return(NULL);           /* search failed */
                    480: }
                    481:
                    482: void
                    483: defrouter_delreq(dr, dofree)
                    484:        struct nd_defrouter *dr;
                    485:        int dofree;
                    486: {
                    487:        struct sockaddr_in6 def, mask, gate;
                    488:
                    489:        Bzero(&def, sizeof(def));
                    490:        Bzero(&mask, sizeof(mask));
                    491:        Bzero(&gate, sizeof(gate));
                    492:
                    493:        def.sin6_len = mask.sin6_len = gate.sin6_len
                    494:                = sizeof(struct sockaddr_in6);
                    495:        def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
                    496:        gate.sin6_addr = dr->rtaddr;
                    497:
                    498:        rtrequest(RTM_DELETE, (struct sockaddr *)&def,
                    499:                  (struct sockaddr *)&gate,
                    500:                  (struct sockaddr *)&mask,
                    501:                  RTF_GATEWAY, (struct rtentry **)0);
                    502:
1.7       itojun    503:        if (dofree)             /* XXX: necessary? */
1.2       itojun    504:                free(dr, M_IP6NDP);
                    505: }
                    506:
                    507: void
                    508: defrtrlist_del(dr)
                    509:        struct nd_defrouter *dr;
                    510: {
                    511:        struct nd_defrouter *deldr = NULL;
                    512:        struct nd_prefix *pr;
                    513:
                    514:        /*
                    515:         * Flush all the routing table entries that use the router
                    516:         * as a next hop.
                    517:         */
                    518:        if (!ip6_forwarding && ip6_accept_rtadv) {
                    519:                /* above is a good condition? */
                    520:                rt6_flush(&dr->rtaddr, dr->ifp);
                    521:        }
                    522:
1.7       itojun    523:        if (dr == TAILQ_FIRST(&nd_defrouter))
1.2       itojun    524:                deldr = dr;     /* The router is primary. */
                    525:
1.7       itojun    526:        TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
1.2       itojun    527:
                    528:        /*
                    529:         * Also delete all the pointers to the router in each prefix lists.
                    530:         */
                    531:        for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
                    532:                struct nd_pfxrouter *pfxrtr;
                    533:                if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
                    534:                        pfxrtr_del(pfxrtr);
                    535:        }
                    536:        pfxlist_onlink_check();
                    537:
                    538:        /*
1.7       itojun    539:         * If the router is the primary one, choose a new one.
                    540:         * Note that defrouter_select() will remove the current gateway
                    541:         * from the routing table.
1.2       itojun    542:         */
                    543:        if (deldr)
1.7       itojun    544:                defrouter_select();
                    545:
1.2       itojun    546:        free(dr, M_IP6NDP);
                    547: }
                    548:
1.7       itojun    549: /*
                    550:  * Default Router Selection according to Section 6.3.6 of RFC 2461:
                    551:  * 1) Routers that are reachable or probably reachable should be
                    552:  *    preferred.
                    553:  * 2) When no routers on the list are known to be reachable or
                    554:  *    probably reachable, routers SHOULD be selected in a round-robin
                    555:  *    fashion.
                    556:  * 3) If the Default Router List is empty, assume that all
                    557:  *    destinations are on-link.
                    558:  */
                    559: void
                    560: defrouter_select()
                    561: {
                    562:        int s = splsoftnet();
                    563:        struct nd_defrouter *dr, anydr;
                    564:        struct rtentry *rt = NULL;
                    565:        struct llinfo_nd6 *ln = NULL;
                    566:
                    567:        /*
                    568:         * Search for a (probably) reachable router from the list.
                    569:         */
                    570:        for (dr = TAILQ_FIRST(&nd_defrouter); dr;
                    571:             dr = TAILQ_NEXT(dr, dr_entry)) {
                    572:                if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
                    573:                    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
                    574:                    ND6_IS_LLINFO_PROBREACH(ln)) {
                    575:                        /* Got it, and move it to the head */
                    576:                        TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
                    577:                        TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
                    578:                        break;
                    579:                }
                    580:        }
                    581:
                    582:        if ((dr = TAILQ_FIRST(&nd_defrouter))) {
                    583:                /*
                    584:                 * De-install the previous default gateway and install
                    585:                 * a new one.
                    586:                 * Note that if there is no reachable router in the list,
                    587:                 * the head entry will be used anyway.
                    588:                 * XXX: do we have to check the current routing table entry?
                    589:                 */
                    590:                bzero(&anydr, sizeof(anydr));
                    591:                defrouter_delreq(&anydr, 0);
                    592:                defrouter_addreq(dr);
                    593:        }
                    594:        else {
                    595:                /*
                    596:                 * The Default Router List is empty, so install the default
                    597:                 * route to an inteface.
                    598:                 * XXX: The specification does not say this mechanism should
                    599:                 * be restricted to hosts, but this would be not useful
                    600:                 * (even harmful) for routers.
                    601:                 */
                    602:                if (!ip6_forwarding) {
                    603:                        /*
                    604:                         * De-install the current default route
                    605:                         * in advance.
                    606:                         */
                    607:                        bzero(&anydr, sizeof(anydr));
                    608:                        defrouter_delreq(&anydr, 0);
                    609:                        if (nd6_defifp) {
                    610:                                /*
                    611:                                 * Install a route to the default interface
                    612:                                 * as default route.
                    613:                                 */
                    614:                                defrouter_addifreq(nd6_defifp);
                    615:                        }
1.15      itojun    616: #ifdef ND6_DEBUG
1.7       itojun    617:                        else    /* noisy log? */
                    618:                                log(LOG_INFO, "defrouter_select: "
                    619:                                    "there's no default router and no default"
                    620:                                    " interface\n");
1.14      thorpej   621: #endif
1.7       itojun    622:                }
                    623:        }
                    624:
                    625:        splx(s);
                    626:        return;
                    627: }
                    628:
1.2       itojun    629: static struct nd_defrouter *
                    630: defrtrlist_update(new)
                    631:        struct nd_defrouter *new;
                    632: {
                    633:        struct nd_defrouter *dr, *n;
1.4       itojun    634:        int s = splsoftnet();
1.2       itojun    635:
                    636:        if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
                    637:                /* entry exists */
                    638:                if (new->rtlifetime == 0) {
                    639:                        defrtrlist_del(dr);
                    640:                        dr = NULL;
                    641:                } else {
                    642:                        /* override */
                    643:                        dr->flags = new->flags; /* xxx flag check */
                    644:                        dr->rtlifetime = new->rtlifetime;
                    645:                        dr->expire = new->expire;
                    646:                }
                    647:                splx(s);
                    648:                return(dr);
                    649:        }
                    650:
                    651:        /* entry does not exist */
                    652:        if (new->rtlifetime == 0) {
                    653:                splx(s);
                    654:                return(NULL);
                    655:        }
                    656:
                    657:        n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
                    658:        if (n == NULL) {
                    659:                splx(s);
                    660:                return(NULL);
                    661:        }
                    662:        bzero(n, sizeof(*n));
                    663:        *n = *new;
1.7       itojun    664:
                    665:        /*
                    666:         * Insert the new router at the end of the Default Router List.
                    667:         * If there is no other router, install it anyway. Otherwise,
1.16      itojun    668:         * just continue to use the current default router.
1.7       itojun    669:         */
                    670:        TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
                    671:        if (TAILQ_FIRST(&nd_defrouter) == n)
                    672:                defrouter_select();
1.2       itojun    673:        splx(s);
                    674:
                    675:        return(n);
                    676: }
                    677:
                    678: static struct nd_pfxrouter *
                    679: pfxrtr_lookup(pr, dr)
                    680:        struct nd_prefix *pr;
                    681:        struct nd_defrouter *dr;
                    682: {
                    683:        struct nd_pfxrouter *search;
                    684:
                    685:        for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
                    686:                if (search->router == dr)
                    687:                        break;
                    688:        }
                    689:
                    690:        return(search);
                    691: }
                    692:
                    693: static void
                    694: pfxrtr_add(pr, dr)
                    695:        struct nd_prefix *pr;
                    696:        struct nd_defrouter *dr;
                    697: {
                    698:        struct nd_pfxrouter *new;
                    699:
                    700:        new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
                    701:        if (new == NULL)
                    702:                return;
                    703:        bzero(new, sizeof(*new));
                    704:        new->router = dr;
                    705:
                    706:        LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
                    707:
                    708:        pfxlist_onlink_check();
                    709: }
                    710:
                    711: static void
                    712: pfxrtr_del(pfr)
                    713:        struct nd_pfxrouter *pfr;
                    714: {
                    715:        LIST_REMOVE(pfr, pfr_entry);
                    716:        free(pfr, M_IP6NDP);
                    717: }
                    718:
                    719: static struct nd_prefix *
                    720: prefix_lookup(pr)
                    721:        struct nd_prefix *pr;
                    722: {
                    723:        struct nd_prefix *search;
                    724:
                    725:        for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
                    726:                if (pr->ndpr_ifp == search->ndpr_ifp &&
                    727:                    pr->ndpr_plen == search->ndpr_plen &&
                    728:                    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
                    729:                                         &search->ndpr_prefix.sin6_addr,
                    730:                                         pr->ndpr_plen)
                    731:                    ) {
                    732:                        break;
                    733:                }
                    734:        }
                    735:
                    736:        return(search);
                    737: }
                    738:
                    739: static int
                    740: prelist_add(pr, dr)
                    741:        struct nd_prefix *pr;
                    742:        struct nd_defrouter *dr;
                    743: {
                    744:        struct nd_prefix *new;
                    745:        int i, s;
                    746:
                    747:        new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
                    748:        if (new == NULL)
                    749:                return ENOMEM;
                    750:        bzero(new, sizeof(*new));
                    751:        *new = *pr;
                    752:
                    753:        /* initilization */
                    754:        new->ndpr_statef_onlink = pr->ndpr_statef_onlink;
                    755:        LIST_INIT(&new->ndpr_advrtrs);
                    756:        in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
                    757:        /* make prefix in the canonical form */
                    758:        for (i = 0; i < 4; i++)
                    759:                new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
                    760:                        new->ndpr_mask.s6_addr32[i];
                    761:
                    762:        /* xxx ND_OPT_PI_FLAG_ONLINK processing */
                    763:
1.4       itojun    764:        s = splsoftnet();
1.2       itojun    765:        /* link ndpr_entry to nd_prefix list */
                    766:        LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
                    767:        splx(s);
                    768:
                    769:        if (dr)
                    770:                pfxrtr_add(new, dr);
                    771:
                    772:        return 0;
                    773: }
                    774:
                    775: void
                    776: prelist_remove(pr)
                    777:        struct nd_prefix *pr;
                    778: {
                    779:        struct nd_pfxrouter *pfr, *next;
                    780:        int s;
                    781:
1.4       itojun    782:        s = splsoftnet();
1.2       itojun    783:        /* unlink ndpr_entry from nd_prefix list */
                    784:        LIST_REMOVE(pr, ndpr_entry);
                    785:        splx(s);
                    786:
                    787:        /* free list of routers that adversed the prefix */
                    788:        for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
                    789:                next = pfr->pfr_next;
                    790:
                    791:                free(pfr, M_IP6NDP);
                    792:        }
                    793:        free(pr, M_IP6NDP);
                    794:
                    795:        pfxlist_onlink_check();
                    796: }
                    797:
                    798: /*
                    799:  * NOTE: We set address lifetime to keep
                    800:  *     address lifetime <= prefix lifetime
                    801:  * invariant.  This is to simplify on-link determination code.
                    802:  * If onlink determination is udated, this routine may have to be updated too.
                    803:  */
                    804: int
                    805: prelist_update(new, dr, m)
                    806:        struct nd_prefix *new;
                    807:        struct nd_defrouter *dr; /* may be NULL */
                    808:        struct mbuf *m;
                    809: {
                    810:        struct in6_ifaddr *ia6 = NULL;
                    811:        struct nd_prefix *pr;
1.4       itojun    812:        int s = splsoftnet();
1.2       itojun    813:        int error = 0;
                    814:        int auth;
                    815:        struct in6_addrlifetime *lt6;
                    816:
1.7       itojun    817:        auth = 0;
1.2       itojun    818:        if (m) {
                    819:                /*
                    820:                 * Authenticity for NA consists authentication for
                    821:                 * both IP header and IP datagrams, doesn't it ?
                    822:                 */
1.7       itojun    823: #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
1.2       itojun    824:                auth = (m->m_flags & M_AUTHIPHDR
                    825:                     && m->m_flags & M_AUTHIPDGM) ? 1 : 0;
1.7       itojun    826: #endif
                    827:        }
1.2       itojun    828:
                    829:        if ((pr = prefix_lookup(new)) != NULL) {
                    830:                if (pr->ndpr_ifp != new->ndpr_ifp) {
                    831:                        error = EADDRNOTAVAIL;
                    832:                        goto end;
                    833:                }
                    834:                /* update prefix information */
1.7       itojun    835:                pr->ndpr_flags = new->ndpr_flags;
1.2       itojun    836:                pr->ndpr_vltime = new->ndpr_vltime;
                    837:                pr->ndpr_pltime = new->ndpr_pltime;
                    838:                pr->ndpr_preferred = new->ndpr_preferred;
                    839:                pr->ndpr_expire = new->ndpr_expire;
                    840:
                    841:                /*
                    842:                 * RFC 2462 5.5.3 (d) or (e)
                    843:                 * We got a prefix which we have seen in the past.
                    844:                 */
                    845:                if (!new->ndpr_raf_auto)
                    846:                        goto noautoconf1;
                    847:
                    848:                if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
                    849:                        ia6 = NULL;
                    850:                else
                    851:                        ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
                    852:
                    853:                if (ia6 == NULL) {
                    854:                        /*
                    855:                         * Special case:
                    856:                         * (1) We have seen the prefix advertised before, but
                    857:                         * we have never performed autoconfig for this prefix.
                    858:                         * This is because Autonomous bit was 0 previously, or
                    859:                         * autoconfig failed due to some other reasons.
                    860:                         * (2) We have seen the prefix advertised before and
                    861:                         * we have performed autoconfig in the past, but
                    862:                         * we seem to have no interface address right now.
                    863:                         * This is because the interface address have expired.
                    864:                         *
                    865:                         * This prefix is fresh, with respect to autoconfig
                    866:                         * process.
                    867:                         *
                    868:                         * Add an address based on RFC 2462 5.5.3 (d).
                    869:                         */
                    870:                        ia6 = in6_ifadd(pr->ndpr_ifp,
                    871:                                &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr,
                    872:                                new->ndpr_plen);
                    873:                        if (!ia6) {
                    874:                                error = EADDRNOTAVAIL;
                    875:                                log(LOG_ERR, "prelist_update: failed to add a "
                    876:                                    "new address\n");
                    877:                                goto noautoconf1;
                    878:                        }
                    879:
                    880:                        lt6 = &ia6->ia6_lifetime;
                    881:
                    882:                        /* address lifetime <= prefix lifetime */
                    883:                        lt6->ia6t_vltime = new->ndpr_vltime;
                    884:                        lt6->ia6t_pltime = new->ndpr_pltime;
1.7       itojun    885:                        in6_init_address_ltimes(new, lt6, 1);
1.2       itojun    886:                } else {
                    887: #define TWOHOUR                (120*60)
                    888:                        /*
                    889:                         * We have seen the prefix before, and we have added
                    890:                         * interface address in the past.  We still have
                    891:                         * the interface address assigned.
                    892:                         *
                    893:                         * update address lifetime based on RFC 2462
                    894:                         * 5.5.3 (e).
                    895:                         */
                    896:                        int update = 0;
                    897:
                    898:                        lt6 = &ia6->ia6_lifetime;
                    899:
                    900: #if 0  /* RFC 2462 5.5.3 (e) */
                    901:                        lt6->ia6t_pltime = new->ndpr_pltime;
                    902:                        if (TWOHOUR < new->ndpr_vltime
                    903:                         || lt6pr->nd < new->ndpr_vltime) {
                    904:                                lt6->ia6t_vltime = new->ndpr_vltime;
                    905:                                update++;
                    906:                        } else if (auth
                    907:                                && lt6->ia6t_vltime <= TWOHOUR0
                    908:                                && new->ndpr_vltime <= lt6->ia6t_vltime) {
                    909:                                lt6->ia6t_vltime = new->ndpr_vltime;
                    910:                                update++;
                    911:                        } else {
                    912:                                lt6->ia6t_vltime = TWOHOUR;
                    913:                                update++;
                    914:                        }
                    915:
1.7       itojun    916:                        /* 2 hour rule is not imposed for pref lifetime */
                    917:                        new->ndpr_apltime = new->ndpr_pltime;
                    918:                        lt6->ia6t_pltime = new->ndpr_pltime;
1.2       itojun    919: #else  /* update from Jim Bound, (ipng 6712) */
                    920:                        if (TWOHOUR < new->ndpr_vltime
                    921:                         || lt6->ia6t_vltime < new->ndpr_vltime) {
                    922:                                lt6->ia6t_vltime = new->ndpr_vltime;
                    923:                                update++;
                    924:                        } else if (auth) {
1.7       itojun    925:                                lt6->ia6t_vltime = new->ndpr_vltime;
1.2       itojun    926:                                update++;
                    927:                        }
1.7       itojun    928:
                    929:                        /* jim bound rule is not imposed for pref lifetime */
                    930:                        lt6->ia6t_pltime = new->ndpr_pltime;
1.2       itojun    931: #endif
1.7       itojun    932:                        in6_init_address_ltimes(new, lt6, update);
1.2       itojun    933:                }
                    934:
                    935:  noautoconf1:
                    936:
                    937: #if 0
                    938:                /* address lifetime expire processing, RFC 2462 5.5.4. */
                    939:                if (pr->ndpr_preferred && pr->ndpr_preferred < time_second) {
                    940:                        struct in6_ifaddr *ia6;
                    941:
                    942:                        ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
                    943:                        if (ia6)
                    944:                                ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
                    945:                }
                    946: #endif
                    947:
                    948:                if (dr && pfxrtr_lookup(pr, dr) == NULL)
                    949:                        pfxrtr_add(pr, dr);
                    950:        } else {
                    951:                int error_tmp;
                    952:
                    953:                if (new->ndpr_vltime == 0) goto end;
                    954:
                    955:                bzero(&new->ndpr_addr, sizeof(struct in6_addr));
                    956:
                    957:                /*
                    958:                 * RFC 2462 5.5.3 (d)
                    959:                 * We got a fresh prefix.  Perform some sanity checks
                    960:                 * and add an interface address by appending interface ID
                    961:                 * to the advertised prefix.
                    962:                 */
                    963:                if (!new->ndpr_raf_auto)
                    964:                        goto noautoconf2;
                    965:
                    966:                ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr,
                    967:                          &new->ndpr_addr, new->ndpr_plen);
                    968:                if (!ia6) {
                    969:                        error = EADDRNOTAVAIL;
                    970:                        log(LOG_ERR, "prelist_update: "
                    971:                                "failed to add a new address\n");
                    972:                        goto noautoconf2;
                    973:                }
                    974:                /* set onlink bit if an interface route is configured */
                    975:                new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0;
                    976:
                    977:                lt6 = &ia6->ia6_lifetime;
                    978:
                    979:                /* address lifetime <= prefix lifetime */
                    980:                lt6->ia6t_vltime = new->ndpr_vltime;
                    981:                lt6->ia6t_pltime = new->ndpr_pltime;
1.7       itojun    982:                in6_init_address_ltimes(new, lt6, 1);
1.2       itojun    983:
                    984:  noautoconf2:
                    985:                error_tmp = prelist_add(new, dr);
                    986:                error = error_tmp ? error_tmp : error;
                    987:        }
                    988:
                    989:  end:
                    990:        splx(s);
                    991:        return error;
                    992: }
                    993:
                    994: /*
1.7       itojun    995:  * A supplement function used in the on-link detection below;
                    996:  * detect if a given prefix has a (probably) reachable advertising router.
                    997:  * XXX: lengthy function name...
                    998:  */
                    999: static struct nd_pfxrouter *
                   1000: find_pfxlist_reachable_router(pr)
                   1001:        struct nd_prefix *pr;
                   1002: {
                   1003:        struct nd_pfxrouter *pfxrtr;
                   1004:        struct rtentry *rt;
                   1005:        struct llinfo_nd6 *ln;
                   1006:
                   1007:        for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
                   1008:             pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
                   1009:                if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
                   1010:                                     pfxrtr->router->ifp)) &&
                   1011:                    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
                   1012:                    ND6_IS_LLINFO_PROBREACH(ln))
                   1013:                        break;  /* found */
                   1014:        }
                   1015:
                   1016:        return(pfxrtr);
                   1017:
                   1018: }
                   1019:
                   1020: /*
1.2       itojun   1021:  * Check if each prefix in the prefix list has at least one available router
1.7       itojun   1022:  * that advertised the prefix (A router is "available" if its neighbor cache
                   1023:  * entry has reachable or probably reachable).
                   1024:  * If the check fails, the prefix may be off-link, because, for example,
1.2       itojun   1025:  * we have moved from the network but the lifetime of the prefix has not
                   1026:  * been expired yet. So we should not use the prefix if there is another
                   1027:  * prefix that has an available router.
1.7       itojun   1028:  * But if there is no prefix that has an available router, we still regards
1.2       itojun   1029:  * all the prefixes as on-link. This is because we can't tell if all the
                   1030:  * routers are simply dead or if we really moved from the network and there
                   1031:  * is no router around us.
                   1032:  */
1.7       itojun   1033: void
1.2       itojun   1034: pfxlist_onlink_check()
                   1035: {
                   1036:        struct nd_prefix *pr;
                   1037:
1.7       itojun   1038:        /*
                   1039:         * Check if there is a prefix that has a reachable advertising
                   1040:         * router.
                   1041:         */
                   1042:        for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
                   1043:                if (find_pfxlist_reachable_router(pr))
1.2       itojun   1044:                        break;
1.7       itojun   1045:        }
1.2       itojun   1046:
                   1047:        if (pr) {
                   1048:                /*
1.7       itojun   1049:                 * There is at least one prefix that has a reachable router.
                   1050:                 * First, detach prefixes which has no reachable advertising
                   1051:                 * router and then attach other prefixes.
                   1052:                 * The order is important since an attached prefix and a
                   1053:                 * detached prefix may have a same interface route.
1.2       itojun   1054:                 */
                   1055:                for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
1.7       itojun   1056:                        if (find_pfxlist_reachable_router(pr) == NULL &&
1.2       itojun   1057:                            pr->ndpr_statef_onlink) {
                   1058:                                pr->ndpr_statef_onlink = 0;
                   1059:                                nd6_detach_prefix(pr);
                   1060:                        }
                   1061:                }
                   1062:                for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
1.7       itojun   1063:                        if (find_pfxlist_reachable_router(pr) &&
                   1064:                            pr->ndpr_statef_onlink == 0)
1.2       itojun   1065:                                nd6_attach_prefix(pr);
                   1066:                }
                   1067:        }
                   1068:        else {
1.7       itojun   1069:                /* there is no prefix that has a reachable router */
1.2       itojun   1070:                for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next)
                   1071:                        if (pr->ndpr_statef_onlink == 0)
                   1072:                                nd6_attach_prefix(pr);
                   1073:        }
                   1074: }
                   1075:
                   1076: static void
                   1077: nd6_detach_prefix(pr)
                   1078:        struct nd_prefix *pr;
                   1079: {
                   1080:        struct in6_ifaddr *ia6;
                   1081:        struct sockaddr_in6 sa6, mask6;
                   1082:
                   1083:        /*
                   1084:         * Delete the interface route associated with the prefix.
                   1085:         */
                   1086:        bzero(&sa6, sizeof(sa6));
                   1087:        sa6.sin6_family = AF_INET6;
                   1088:        sa6.sin6_len = sizeof(sa6);
                   1089:        bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
                   1090:              sizeof(struct in6_addr));
                   1091:        bzero(&mask6, sizeof(mask6));
                   1092:        mask6.sin6_family = AF_INET6;
                   1093:        mask6.sin6_len = sizeof(sa6);
                   1094:        bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
                   1095:        {
                   1096:                int e;
                   1097:
                   1098:                e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
                   1099:                              (struct sockaddr *)&mask6, 0, NULL);
                   1100:                if (e) {
                   1101:                        log(LOG_ERR,
                   1102:                            "nd6_detach_prefix: failed to delete route: "
                   1103:                            "%s/%d (errno = %d)\n",
                   1104:                            ip6_sprintf(&sa6.sin6_addr),
1.7       itojun   1105:                            pr->ndpr_plen,
1.2       itojun   1106:                            e);
                   1107:                }
                   1108:        }
                   1109:
                   1110:        /*
                   1111:         * Mark the address derived from the prefix detached so that
                   1112:         * it won't be used as a source address for a new connection.
                   1113:         */
                   1114:        if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
                   1115:                ia6 = NULL;
                   1116:        else
                   1117:                ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
                   1118:        if (ia6)
                   1119:                ia6->ia6_flags |= IN6_IFF_DETACHED;
                   1120: }
                   1121:
                   1122: static void
                   1123: nd6_attach_prefix(pr)
                   1124:        struct nd_prefix *pr;
                   1125: {
                   1126:        struct ifaddr *ifa;
                   1127:        struct in6_ifaddr *ia6;
                   1128:
                   1129:        /*
                   1130:         * Add the interface route associated with the prefix(if necessary)
                   1131:         * Should we consider if the L bit is set in pr->ndpr_flags?
                   1132:         */
                   1133:        ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix,
                   1134:                               pr->ndpr_ifp);
                   1135:        if (ifa == NULL) {
                   1136:                log(LOG_ERR,
                   1137:                    "nd6_attach_prefix: failed to find any ifaddr"
                   1138:                    " to add route for a prefix(%s/%d)\n",
                   1139:                    ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen);
                   1140:        }
                   1141:        else {
                   1142:                int e;
                   1143:                struct sockaddr_in6 mask6;
                   1144:
                   1145:                bzero(&mask6, sizeof(mask6));
                   1146:                mask6.sin6_family = AF_INET6;
                   1147:                mask6.sin6_len = sizeof(mask6);
                   1148:                mask6.sin6_addr = pr->ndpr_mask;
                   1149:                e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
                   1150:                              ifa->ifa_addr, (struct sockaddr *)&mask6,
                   1151:                              ifa->ifa_flags, NULL);
                   1152:                if (e == 0)
                   1153:                        pr->ndpr_statef_onlink = 1;
                   1154:                else {
                   1155:                        log(LOG_ERR,
                   1156:                            "nd6_attach_prefix: failed to add route for"
                   1157:                            " a prefix(%s/%d), errno = %d\n",
                   1158:                            ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e);
                   1159:                }
                   1160:        }
                   1161:
                   1162:        /*
                   1163:         * Now the address derived from the prefix can be used as a source
                   1164:         * for a new connection, so clear the detached flag.
                   1165:         */
                   1166:        if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
                   1167:                ia6 = NULL;
                   1168:        else
                   1169:                ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
                   1170:        if (ia6) {
                   1171:                ia6->ia6_flags &= ~IN6_IFF_DETACHED;
                   1172:                if (pr->ndpr_statef_onlink)
                   1173:                        ia6->ia_flags |= IFA_ROUTE;
                   1174:        }
                   1175: }
                   1176:
                   1177: static struct in6_ifaddr *
                   1178: in6_ifadd(ifp, in6, addr, prefixlen)
                   1179:        struct ifnet *ifp;
                   1180:        struct in6_addr *in6;
                   1181:        struct in6_addr *addr;
                   1182:        int prefixlen;  /* prefix len of the new prefix in "in6" */
                   1183: {
                   1184:        struct ifaddr *ifa;
                   1185:        struct in6_ifaddr *ia, *ib, *oia;
                   1186:        int s, error;
                   1187:        struct in6_addr mask;
                   1188:
                   1189:        in6_len2mask(&mask, prefixlen);
                   1190:
                   1191:        /* find link-local address (will be interface ID) */
1.12      itojun   1192:        ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */
1.2       itojun   1193:        if (ifa)
                   1194:                ib = (struct in6_ifaddr *)ifa;
                   1195:        else
                   1196:                return NULL;
                   1197:
                   1198: #if 0 /* don't care link local addr state, and always do DAD */
                   1199:        /* if link-local address is not eligible, do not autoconfigure. */
                   1200:        if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
                   1201:                printf("in6_ifadd: link-local address not ready\n");
                   1202:                return NULL;
                   1203:        }
                   1204: #endif
                   1205:
                   1206:        /* prefixlen + ifidlen must be equal to 128 */
                   1207:        if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) {
                   1208:                log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s"
1.7       itojun   1209:                        "(prefix=%d ifid=%d)\n", if_name(ifp),
1.2       itojun   1210:                        prefixlen,
                   1211:                        128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr));
                   1212:                return NULL;
                   1213:        }
                   1214:
                   1215:        /* make ifaddr */
                   1216:        ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT);
                   1217:        if (ia == NULL) {
                   1218:                printf("ENOBUFS in in6_ifadd %d\n", __LINE__);
                   1219:                return NULL;
                   1220:        }
                   1221:
                   1222:        bzero((caddr_t)ia, sizeof(*ia));
                   1223:        ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
1.13      itojun   1224:        if (ifp->if_flags & IFF_POINTOPOINT)
                   1225:                ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
                   1226:        else
                   1227:                ia->ia_ifa.ifa_dstaddr = NULL;
1.2       itojun   1228:        ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
                   1229:        ia->ia_ifp = ifp;
                   1230:
                   1231:        /* link to in6_ifaddr */
                   1232:        if ((oia = in6_ifaddr) != NULL) {
                   1233:                for( ; oia->ia_next; oia = oia->ia_next)
                   1234:                        continue;
                   1235:                oia->ia_next = ia;
1.17    ! itojun   1236:        } else {
        !          1237:                /*
        !          1238:                 * This should be impossible, since we have at least one
        !          1239:                 * link-local address (see the beginning of this function).
        !          1240:                 * XXX: should we rather panic here?
        !          1241:                 */
        !          1242:                printf("in6_ifadd: in6_ifaddr is NULL (impossible!)\n");
1.2       itojun   1243:                in6_ifaddr = ia;
1.17    ! itojun   1244:        }
1.16      itojun   1245:        /* gain a refcnt for the link from in6_ifaddr */
1.9       thorpej  1246:        IFAREF((struct ifaddr *)ia);
1.2       itojun   1247:
                   1248:        /* link to if_addrlist */
1.16      itojun   1249:        TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                   1250:        /* gain another refcnt for the link from if_addrlist */
                   1251:        IFAREF((struct ifaddr *)ia);
1.2       itojun   1252:
                   1253:        /* new address */
                   1254:        ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
                   1255:        ia->ia_addr.sin6_family = AF_INET6;
                   1256:        /* prefix */
                   1257:        bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr));
                   1258:        ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
                   1259:        ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
                   1260:        ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
                   1261:        ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
                   1262:        /* interface ID */
                   1263:        ia->ia_addr.sin6_addr.s6_addr32[0]
                   1264:                |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
                   1265:        ia->ia_addr.sin6_addr.s6_addr32[1]
                   1266:                |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
                   1267:        ia->ia_addr.sin6_addr.s6_addr32[2]
                   1268:                |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
                   1269:        ia->ia_addr.sin6_addr.s6_addr32[3]
                   1270:                |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
                   1271:
                   1272:        /* new prefix */
                   1273:        ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                   1274:        ia->ia_prefixmask.sin6_family = AF_INET6;
                   1275:        bcopy(&mask, &ia->ia_prefixmask.sin6_addr,
                   1276:                sizeof(ia->ia_prefixmask.sin6_addr));
                   1277:
                   1278:        /* same routine */
                   1279:        ia->ia_ifa.ifa_rtrequest =
                   1280:                (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest;
                   1281:        ia->ia_ifa.ifa_flags |= RTF_CLONING;
                   1282:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                   1283:
                   1284:        /* add interface route */
                   1285:        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) {
                   1286:                log(LOG_NOTICE, "in6_ifadd: failed to add an interface route "
                   1287:                    "for %s/%d on %s, errno = %d\n",
                   1288:                    ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen,
1.7       itojun   1289:                    if_name(ifp), error);
1.2       itojun   1290:        }
                   1291:        else
                   1292:                ia->ia_flags |= IFA_ROUTE;
                   1293:
                   1294:        *addr = ia->ia_addr.sin6_addr;
                   1295:
                   1296:        if (ifp->if_flags & IFF_MULTICAST) {
                   1297:                int error;      /* not used */
                   1298:                struct in6_addr sol6;
                   1299:
                   1300:                /* Restore saved multicast addresses(if any). */
                   1301:                in6_restoremkludge(ia, ifp);
                   1302:
                   1303:                /* join solicited node multicast address */
                   1304:                bzero(&sol6, sizeof(sol6));
                   1305:                sol6.s6_addr16[0] = htons(0xff02);
                   1306:                sol6.s6_addr16[1] = htons(ifp->if_index);
                   1307:                sol6.s6_addr32[1] = 0;
                   1308:                sol6.s6_addr32[2] = htonl(1);
                   1309:                sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
                   1310:                sol6.s6_addr8[12] = 0xff;
                   1311:                (void)in6_addmulti(&sol6, ifp, &error);
                   1312:        }
                   1313:
                   1314:        ia->ia6_flags |= IN6_IFF_TENTATIVE;
                   1315:
                   1316:        /*
                   1317:         * To make the interface up. Only AF_INET6 in ia is used...
                   1318:         */
                   1319:        s = splimp();
                   1320:        if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) {
                   1321:                splx(s);
                   1322:                return NULL;
                   1323:        }
                   1324:        splx(s);
                   1325:
                   1326:        /* Perform DAD, if needed. */
                   1327:        nd6_dad_start((struct ifaddr *)ia, NULL);
                   1328:
                   1329:        return ia;
                   1330: }
                   1331:
                   1332: int
                   1333: in6_ifdel(ifp, in6)
                   1334:        struct ifnet *ifp;
                   1335:        struct in6_addr *in6;
                   1336: {
                   1337:        struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL;
                   1338:        struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL;
                   1339:
                   1340:        if (!ifp)
                   1341:                return -1;
                   1342:
                   1343:        ia = in6ifa_ifpwithaddr(ifp, in6);
                   1344:        if (!ia)
                   1345:                return -1;
                   1346:
                   1347:        if (ifp->if_flags & IFF_MULTICAST) {
                   1348:                /*
                   1349:                 * delete solicited multicast addr for deleting host id
                   1350:                 */
                   1351:                struct in6_multi *in6m;
                   1352:                struct in6_addr llsol;
                   1353:                bzero(&llsol, sizeof(struct in6_addr));
                   1354:                llsol.s6_addr16[0] = htons(0xff02);
                   1355:                llsol.s6_addr16[1] = htons(ifp->if_index);
                   1356:                llsol.s6_addr32[1] = 0;
                   1357:                llsol.s6_addr32[2] = htonl(1);
                   1358:                llsol.s6_addr32[3] =
                   1359:                                ia->ia_addr.sin6_addr.s6_addr32[3];
                   1360:                llsol.s6_addr8[12] = 0xff;
                   1361:
                   1362:                IN6_LOOKUP_MULTI(llsol, ifp, in6m);
                   1363:                if (in6m)
                   1364:                        in6_delmulti(in6m);
                   1365:        }
                   1366:
                   1367:        if (ia->ia_flags & IFA_ROUTE) {
                   1368:                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
                   1369:                ia->ia_flags &= ~IFA_ROUTE;
                   1370:        }
                   1371:
                   1372:        TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1.12      itojun   1373:        IFAFREE(&ia->ia_ifa);
1.2       itojun   1374:
                   1375:        /* lladdr is never deleted */
                   1376:        oia = ia;
                   1377:        if (oia == (ia = in6_ifaddr))
                   1378:                in6_ifaddr = ia->ia_next;
                   1379:        else {
                   1380:                while (ia->ia_next && (ia->ia_next != oia))
                   1381:                        ia = ia->ia_next;
                   1382:                if (ia->ia_next)
                   1383:                        ia->ia_next = oia->ia_next;
                   1384:                else
                   1385:                        return -1;
                   1386:        }
                   1387:
                   1388:        in6_savemkludge(oia);
                   1389:        IFAFREE((&oia->ia_ifa));
                   1390: /* xxx
                   1391:        rtrequest(RTM_DELETE,
                   1392:                  (struct sockaddr *)&ia->ia_addr,
                   1393:                  (struct sockaddr *)0
                   1394:                  (struct sockaddr *)&ia->ia_prefixmask,
                   1395:                  RTF_UP|RTF_CLONING,
                   1396:                  (struct rtentry **)0);
                   1397: */
                   1398:        return 0;
                   1399: }
                   1400:
                   1401: int
                   1402: in6_init_prefix_ltimes(struct nd_prefix *ndpr)
                   1403: {
1.7       itojun   1404:        long time_second = time.tv_sec;
                   1405:
1.2       itojun   1406:        /* check if preferred lifetime > valid lifetime */
                   1407:        if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
                   1408:                log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
                   1409:                    "(%d) is greater than valid lifetime(%d)\n",
                   1410:                    (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime);
                   1411:                return (EINVAL);
                   1412:        }
1.7       itojun   1413:        if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
1.2       itojun   1414:                ndpr->ndpr_preferred = 0;
                   1415:        else
                   1416:                ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
1.7       itojun   1417:        if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
1.2       itojun   1418:                ndpr->ndpr_expire = 0;
                   1419:        else
                   1420:                ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
                   1421:
                   1422:        return 0;
                   1423: }
                   1424:
                   1425: static void
1.7       itojun   1426: in6_init_address_ltimes(struct nd_prefix *new,
                   1427:                        struct in6_addrlifetime *lt6,
                   1428:                        int update_vltime)
1.2       itojun   1429: {
1.7       itojun   1430:        long time_second = time.tv_sec;
                   1431:
                   1432:        /* Valid lifetime must not be updated unless explicitly specified. */
                   1433:        if (update_vltime) {
                   1434:                /* init ia6t_expire */
                   1435:                if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
                   1436:                        lt6->ia6t_expire = 0;
                   1437:                else {
                   1438:                        lt6->ia6t_expire = time_second;
                   1439:                        lt6->ia6t_expire += lt6->ia6t_vltime;
                   1440:                }
                   1441:                /* Ensure addr lifetime <= prefix lifetime. */
                   1442:                if (new->ndpr_expire && lt6->ia6t_expire &&
                   1443:                    new->ndpr_expire < lt6->ia6t_expire)
                   1444:                        lt6->ia6t_expire = new->ndpr_expire;
1.2       itojun   1445:        }
1.7       itojun   1446:
1.2       itojun   1447:        /* init ia6t_preferred */
1.7       itojun   1448:        if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
1.2       itojun   1449:                lt6->ia6t_preferred = 0;
                   1450:        else {
                   1451:                lt6->ia6t_preferred = time_second;
                   1452:                lt6->ia6t_preferred += lt6->ia6t_pltime;
                   1453:        }
1.7       itojun   1454:         /* Ensure addr lifetime <= prefix lifetime. */
1.2       itojun   1455:        if (new->ndpr_preferred && lt6->ia6t_preferred
                   1456:            && new->ndpr_preferred < lt6->ia6t_preferred)
                   1457:                lt6->ia6t_preferred = new->ndpr_preferred;
                   1458: }
                   1459:
                   1460: /*
                   1461:  * Delete all the routing table entries that use the specified gateway.
                   1462:  * XXX: this function causes search through all entries of routing table, so
1.16      itojun   1463:  * it shouldn't be called when acting as a router.
1.2       itojun   1464:  */
                   1465: void
                   1466: rt6_flush(gateway, ifp)
                   1467:     struct in6_addr *gateway;
                   1468:     struct ifnet *ifp;
                   1469: {
                   1470:        struct radix_node_head *rnh = rt_tables[AF_INET6];
1.4       itojun   1471:        int s = splsoftnet();
1.2       itojun   1472:
                   1473:        /* We'll care only link-local addresses */
                   1474:        if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
                   1475:                splx(s);
                   1476:                return;
                   1477:        }
                   1478:        /* XXX: hack for KAME's link-local address kludge */
                   1479:        gateway->s6_addr16[1] = htons(ifp->if_index);
                   1480:
                   1481:        rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
                   1482:        splx(s);
                   1483: }
                   1484:
                   1485: static int
                   1486: rt6_deleteroute(rn, arg)
                   1487:        struct radix_node *rn;
                   1488:        void *arg;
                   1489: {
                   1490: #define SIN6(s)        ((struct sockaddr_in6 *)s)
                   1491:        struct rtentry *rt = (struct rtentry *)rn;
                   1492:        struct in6_addr *gate = (struct in6_addr *)arg;
                   1493:
                   1494:        if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
                   1495:                return(0);
                   1496:
                   1497:        if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
                   1498:                return(0);
                   1499:
                   1500:        /*
                   1501:         * We delete only host route. This means, in particular, we don't
                   1502:         * delete default route.
                   1503:         */
                   1504:        if ((rt->rt_flags & RTF_HOST) == 0)
                   1505:                return(0);
                   1506:
                   1507:        return(rtrequest(RTM_DELETE, rt_key(rt),
                   1508:                         rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
                   1509: #undef SIN6
                   1510: }
1.7       itojun   1511:
                   1512: int
                   1513: nd6_setdefaultiface(ifindex)
                   1514:        int ifindex;
                   1515: {
                   1516:        int error = 0;
                   1517:
                   1518:        if (ifindex < 0 || if_index < ifindex)
                   1519:                return(EINVAL);
                   1520:
                   1521:        if (nd6_defifindex != ifindex) {
                   1522:                nd6_defifindex = ifindex;
                   1523:                if (nd6_defifindex > 0)
                   1524:                        nd6_defifp = ifindex2ifnet[nd6_defifindex];
                   1525:                else
                   1526:                        nd6_defifp = NULL;
                   1527:
                   1528:                /*
                   1529:                 * If the Default Router List is empty, install a route
                   1530:                 * to the specified interface as default or remove the default
                   1531:                 * route when the default interface becomes canceled.
                   1532:                 * The check for the queue is actually redundant, but
                   1533:                 * we do this here to avoid re-install the default route
                   1534:                 * if the list is NOT empty.
                   1535:                 */
                   1536:                if (TAILQ_FIRST(&nd_defrouter) == NULL)
                   1537:                        defrouter_select();
                   1538:        }
                   1539:
                   1540:        return(error);
                   1541: }

CVSweb <webmaster@jp.NetBSD.org>