[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.5

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

CVSweb <webmaster@jp.NetBSD.org>