I think it's time...

I kept nd6_ra_input for source link layer address option processing like
nd6_rs_input.

Tests, OKs?

 net/if.c                |   10 -
 netinet6/in6.c          |   16 -
 netinet6/in6_ifattach.c |    7 +-
 netinet6/in6_var.h      |    3 -
 netinet6/nd6.c          |  372 +---------
 netinet6/nd6.h          |   61 --
 netinet6/nd6_nbr.c      |   25 +-
 netinet6/nd6_rtr.c      | 1793 +----------------------------------------------
 8 files changed, 21 insertions(+), 2266 deletions(-)

diff --git net/if.c net/if.c
index 6354484e477..e3bb1d508a6 100644
--- net/if.c
+++ net/if.c
@@ -1952,16 +1952,6 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, 
struct proc *p)
                        if (error != 0)
                                return (error);
                }
-
-               if ((ifr->ifr_flags & IFXF_AUTOCONF6) &&
-                   !(ifp->if_xflags & IFXF_AUTOCONF6)) {
-                       nd6_rs_attach(ifp);
-               }
-
-               if ((ifp->if_xflags & IFXF_AUTOCONF6) &&
-                   !(ifr->ifr_flags & IFXF_AUTOCONF6)) {
-                       nd6_rs_detach(ifp);
-               }
 #endif /* INET6 */
 
 #ifdef MPLS
diff --git netinet6/in6.c netinet6/in6.c
index 8b619f6a78e..083a068e430 100644
--- netinet6/in6.c
+++ netinet6/in6.c
@@ -897,25 +897,9 @@ in6_unlink_ifa(struct in6_ifaddr *ia6, struct ifnet *ifp)
 {
        struct ifaddr *ifa = &ia6->ia_ifa;
        extern int ifatrash;
-       int plen;
 
        NET_ASSERT_LOCKED();
 
-       /* Release the reference to the base prefix. */
-       if (ia6->ia6_ndpr == NULL) {
-               plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
-               if ((ifp->if_flags & IFF_LOOPBACK) == 0 && plen != 128) {
-                       rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED,
-                           ifa->ifa_addr);
-               }
-       } else {
-               KASSERT(ia6->ia6_flags & IN6_IFF_AUTOCONF);
-               ia6->ia6_flags &= ~IN6_IFF_AUTOCONF;
-               if (--ia6->ia6_ndpr->ndpr_refcnt == 0)
-                       prelist_remove(ia6->ia6_ndpr);
-               ia6->ia6_ndpr = NULL;
-       }
-
        rt_ifa_purge(ifa);
        ifa_del(ifp, ifa);
 
diff --git netinet6/in6_ifattach.c netinet6/in6_ifattach.c
index fad1eb130b6..7d93f0805fe 100644
--- netinet6/in6_ifattach.c
+++ netinet6/in6_ifattach.c
@@ -504,9 +504,6 @@ in6_ifattach(struct ifnet *ifp)
                }
        }
 
-       if (ifp->if_xflags & IFXF_AUTOCONF6)
-               nd6_rs_attach(ifp);
-
        return (0);
 }
 
@@ -563,8 +560,6 @@ in6_ifdetach(struct ifnet *ifp)
                rtfree(rt);
        }
 
-       if (ifp->if_xflags & IFXF_AUTOCONF6) {
-               nd6_rs_detach(ifp);
+       if (ifp->if_xflags & IFXF_AUTOCONF6)
                ifp->if_xflags &= ~IFXF_AUTOCONF6;
-       }
 }
diff --git netinet6/in6_var.h netinet6/in6_var.h
index a193e2df396..2501729da86 100644
--- netinet6/in6_var.h
+++ netinet6/in6_var.h
@@ -112,9 +112,6 @@ struct      in6_ifaddr {
                                 */
        time_t  ia6_updatetime;
 
-       /* back pointer to the prefix (for autoconf) */
-       struct nd_prefix *ia6_ndpr;
-
        /* multicast addresses joined from the kernel */
        LIST_HEAD(, in6_multi_mship) ia6_memberships;
 };
diff --git netinet6/nd6.c netinet6/nd6.c
index 7b32caec770..773e8e12b1f 100644
--- netinet6/nd6.c
+++ netinet6/nd6.c
@@ -87,9 +87,6 @@ TAILQ_HEAD(llinfo_nd6_head, llinfo_nd6) nd6_list;
 struct pool nd6_pool;          /* pool for llinfo_nd6 structures */
 int    nd6_inuse, nd6_allocated;
 
-struct nd_drhead nd_defrouter;
-struct nd_prhead nd_prefix = { 0 };
-
 int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;
 
 void nd6_slowtimo(void *);
@@ -103,9 +100,6 @@ struct timeout nd6_slowtimo_ch;
 struct timeout nd6_timer_ch;
 struct task nd6_timer_task;
 
-int fill_drlist(void *, size_t *, size_t);
-int fill_prlist(void *, size_t *, size_t);
-
 void
 nd6_init(void)
 {
@@ -121,7 +115,6 @@ nd6_init(void)
            IPL_SOFTNET, 0, "nd6", NULL);
 
        /* initialization of the default router list */
-       TAILQ_INIT(&nd_defrouter);
 
        task_set(&nd6_timer_task, nd6_timer_work, NULL);
 
@@ -133,7 +126,6 @@ nd6_init(void)
        timeout_set(&nd6_timer_ch, nd6_timer, NULL);
        timeout_add_sec(&nd6_timer_ch, nd6_prune);
 
-       nd6_rs_init();
 }
 
 struct nd_ifinfo *
@@ -433,8 +425,6 @@ nd6_llinfo_timer(void *arg)
 void
 nd6_timer_work(void *null)
 {
-       struct nd_defrouter *dr, *ndr;
-       struct nd_prefix *pr, *npr;
        struct ifnet *ifp;
        int s;
 
@@ -442,11 +432,6 @@ nd6_timer_work(void *null)
 
        timeout_add_sec(&nd6_timer_ch, nd6_prune);
 
-       /* expire default router list */
-       TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr)
-               if (dr->expire && dr->expire < time_uptime)
-                       defrtrlist_del(dr);
-
        /*
         * expire interface addresses.
         * in the past the loop was inside prefix expiry processing.
@@ -476,23 +461,6 @@ nd6_timer_work(void *null)
                }
        }
 
-       /* expire prefix list */
-       LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) {
-               /*
-                * check prefix lifetime.
-                * since pltime is just for autoconf, pltime processing for
-                * prefix is not necessary.
-                */
-               if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&
-                   time_uptime - pr->ndpr_lastupdate > pr->ndpr_vltime) {
-                       /*
-                        * address expiration and prefix expiration are
-                        * separate.  NEVER perform in6_purgeaddr here.
-                        */
-
-                       prelist_remove(pr);
-               }
-       }
        NET_UNLOCK(s);
 }
 
@@ -510,44 +478,10 @@ void
 nd6_purge(struct ifnet *ifp)
 {
        struct llinfo_nd6 *ln, *nln;
-       struct nd_defrouter *dr, *ndr;
-       struct nd_prefix *pr, *npr;
 
        NET_ASSERT_LOCKED();
 
        /*
-        * Nuke default router list entries toward ifp.
-        * We defer removal of default router list entries that is installed
-        * in the routing table, in order to keep additional side effects as
-        * small as possible.
-        */
-       TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) {
-               if (dr->installed)
-                       continue;
-
-               if (dr->ifp == ifp)
-                       defrtrlist_del(dr);
-       }
-       TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) {
-               if (!dr->installed)
-                       continue;
-
-               if (dr->ifp == ifp)
-                       defrtrlist_del(dr);
-       }
-
-       /* Nuke prefix list entries toward ifp */
-       LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) {
-               if (pr->ndpr_ifp == ifp)
-                       prelist_remove(pr);
-       }
-
-       if (ifp->if_xflags & IFXF_AUTOCONF6) {
-               /* refresh default router list */
-               defrouter_select();
-       }
-
-       /*
         * Nuke neighbor cache entries for the ifp.
         */
        TAILQ_FOREACH_SAFE(ln, &nd6_list, ln_list, nln) {
@@ -661,7 +595,6 @@ nd6_lookup(struct in6_addr *addr6, int create, struct ifnet 
*ifp,
 int
 nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
 {
-       struct nd_prefix *pr;
        struct in6_ifaddr *ia6;
        struct ifaddr *ifa;
        struct rtentry *rt;
@@ -693,22 +626,6 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct 
ifnet *ifp)
        }
 
        /*
-        * If the address matches one of our on-link prefixes, it should be a
-        * neighbor.
-        */
-       LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-               if (pr->ndpr_ifp != ifp)
-                       continue;
-
-               if (!(pr->ndpr_stateflags & NDPRF_ONLINK))
-                       continue;
-
-               if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
-                   &addr->sin6_addr, &pr->ndpr_mask))
-                       return (1);
-       }
-
-       /*
         * Even if the address matches none of our addresses, it might be
         * in the neighbor cache.
         */
@@ -743,7 +660,6 @@ nd6_free(struct rtentry *rt, int gc)
 {
        struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;
        struct in6_addr in6 = satosin6(rt_key(rt))->sin6_addr;
-       struct nd_defrouter *dr;
        struct ifnet *ifp;
 
        NET_ASSERT_LOCKED();
@@ -751,33 +667,8 @@ nd6_free(struct rtentry *rt, int gc)
        ifp = if_get(rt->rt_ifidx);
 
        if (!ip6_forwarding) {
-               dr = defrouter_lookup(&satosin6(rt_key(rt))->sin6_addr,
-                   rt->rt_ifidx);
-
-               if (dr != NULL && dr->expire &&
-                   ln->ln_state == ND6_LLINFO_STALE && gc) {
-                       /*
-                        * If the reason for the deletion is just garbage
-                        * collection, and the neighbor is an active default
-                        * router, do not delete it.  Instead, reset the GC
-                        * timer using the router's lifetime.
-                        * Simply deleting the entry would affect default
-                        * router selection, which is not necessarily a good
-                        * thing, especially when we're using router preference
-                        * values.
-                        * XXX: the check for ln_state would be redundant,
-                        *      but we intentionally keep it just in case.
-                        */
-                       if (dr->expire > time_uptime) {
-                               nd6_llinfo_settimer(ln,
-                                   dr->expire - time_uptime);
-                       } else
-                               nd6_llinfo_settimer(ln, nd6_gctimer);
-                       if_put(ifp);
-                       return (TAILQ_NEXT(ln, ln_list));
-               }
-
-               if (ln->ln_router || dr) {
+               /* XXXDEL? */
+               if (ln->ln_router) {
                        /*
                         * rt6_flush must be called whether or not the neighbor
                         * is in the Default Router List.
@@ -785,43 +676,11 @@ nd6_free(struct rtentry *rt, int gc)
                         */
                        rt6_flush(&in6, ifp);
                }
-
-               if (dr) {
-                       /*
-                        * Unreachability of a router might affect the default
-                        * router selection and on-link detection of advertised
-                        * prefixes.
-                        */
-
-                       /*
-                        * Temporarily fake the state to choose a new default
-                        * router and to perform on-link determination of
-                        * prefixes correctly.
-                        * Below the state will be set correctly,
-                        * or the entry itself will be deleted.
-                        */
-                       ln->ln_state = ND6_LLINFO_INCOMPLETE;
-
-                       /*
-                        * Since defrouter_select() does not affect the
-                        * on-link determination and MIP6 needs the check
-                        * before the default router selection, we perform
-                        * the check now.
-                        */
-                       pfxlist_onlink_check();
-
-                       /*
-                        * refresh default router list
-                        */
-                       defrouter_select();
-               }
        }
 
        /*
         * Before deleting the entry, remember the next entry as the
-        * return value.  We need this because pfxlist_onlink_check() above
-        * might have freed other entries (particularly the old next entry) as
-        * a side effect (XXX).
+        * return value.
         */
        next = TAILQ_NEXT(ln, ln_list);
 
@@ -888,16 +747,6 @@ nd6_rtrequest(struct ifnet *ifp, int req, struct rtentry 
*rt)
        struct sockaddr *gate = rt->rt_gateway;
        struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
        struct ifaddr *ifa;
-       struct nd_defrouter *dr;
-
-       if (req == RTM_DELETE && (rt->rt_flags & RTF_GATEWAY) &&
-           (IN6_ARE_ADDR_EQUAL(&(satosin6(rt_key(rt)))->sin6_addr,
-           &in6addr_any) && rt_plen(rt) == 0)) {
-               dr = defrouter_lookup(&satosin6(gate)->sin6_addr,
-                   ifp->if_index);
-               if (dr)
-                       dr->installed = 0;
-       }
 
        if (ISSET(rt->rt_flags, RTF_GATEWAY|RTF_MULTICAST))
                return;
@@ -1144,63 +993,18 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
                break;
        case SIOCSNDFLUSH_IN6:  /* XXX: the ioctl name is confusing... */
                /* sync kernel routing table with the default router list */
-               defrouter_reset();
-               defrouter_select();
+               error = ENOTSUP;
                break;
        case SIOCSPFXFLUSH_IN6:
        {
                /* flush all the prefix advertised by routers */
-               struct nd_prefix *pr, *npr;
-
-               /* First purge the addresses referenced by a prefix. */
-               LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) {
-                       struct ifnet *ifp;
-                       struct ifaddr *ifa, *nifa;
-                       struct in6_ifaddr *ia6;
-
-                       if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
-                               continue; /* XXX */
-
-                       /* do we really have to remove addresses as well? */
-                       TAILQ_FOREACH(ifp, &ifnet, if_list) {
-                               TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist,
-                                   ifa_list, nifa) {
-                                       if (ifa->ifa_addr->sa_family !=
-                                           AF_INET6)
-                                               continue;
-
-                                       ia6 = ifatoia6(ifa);
-                                       if ((ia6->ia6_flags & IN6_IFF_AUTOCONF)
-                                           == 0)
-                                               continue;
-
-                                       if (ia6->ia6_ndpr == pr)
-                                               in6_purgeaddr(&ia6->ia_ifa);
-                               }
-                       }
-               }
-               /*
-                * Purging the addresses might remove the prefix as well.
-                * So run the loop again to access only prefixes that have
-                * not been freed already.
-                */
-               LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) {
-                       if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
-                               continue; /* XXX */
-
-                       prelist_remove(pr);
-               }
+               error = ENOTSUP;
                break;
        }
        case SIOCSRTRFLUSH_IN6:
        {
                /* flush all the default routers */
-               struct nd_defrouter *dr, *ndr;
-
-               defrouter_reset();
-               TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr)
-                       defrtrlist_del(dr);
-               defrouter_select();
+               error = ENOTSUP;
                break;
        }
        case SIOCGNBRINFO_IN6:
@@ -1471,21 +1275,6 @@ fail:
                break;
        }
 
-       /*
-        * When the link-layer address of a router changes, select the
-        * best router again.  In particular, when the neighbor entry is newly
-        * created, it might affect the selection policy.
-        * Question: can we restrict the first condition to the "is_newentry"
-        * case?
-        * XXX: when we hear an RA from a new router with the link-layer
-        * address option, defrouter_select() is called twice, since
-        * defrtrlist_update called the function as well.  However, I believe
-        * we can compromise the overhead, since it only happens the first
-        * time.
-        */
-       if (do_update && ln->ln_router && (ifp->if_xflags & IFXF_AUTOCONF6))
-               defrouter_select();
-
        rtfree(rt);
 }
 
@@ -1647,7 +1436,7 @@ nd6_need_cache(struct ifnet *ifp)
  * oldp - syscall arg, need copyout
  * newp - syscall arg, need copyin
  */
-
+/* XXXDEL? */
 int
 nd6_sysctl(int name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
 {
@@ -1673,15 +1462,11 @@ nd6_sysctl(int name, void *oldp, size_t *oldlenp, void 
*newp, size_t newlen)
                p = NULL;
        switch (name) {
        case ICMPV6CTL_ND6_DRLIST:
-               error = fill_drlist(p, oldlenp, ol);
-               if (!error && p && oldp)
-                       error = copyout(p, oldp, *oldlenp);
+               error = ENOTSUP; /* XXXDEL? can we delete more? */
                break;
 
        case ICMPV6CTL_ND6_PRLIST:
-               error = fill_prlist(p, oldlenp, ol);
-               if (!error && p && oldp)
-                       error = copyout(p, oldp, *oldlenp);
+               error = ENOTSUP; /* XXXDEL? can we delete more? */
                break;
 
        default:
@@ -1692,142 +1477,3 @@ nd6_sysctl(int name, void *oldp, size_t *oldlenp, void 
*newp, size_t newlen)
 
        return (error);
 }
-
-int
-fill_drlist(void *oldp, size_t *oldlenp, size_t ol)
-{
-       int error = 0;
-       struct in6_defrouter *d = NULL, *de = NULL;
-       struct nd_defrouter *dr;
-       time_t expire;
-       size_t l;
-
-       if (oldp) {
-               d = (struct in6_defrouter *)oldp;
-               de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp);
-       }
-       l = 0;
-
-       TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) {
-               if (oldp && d + 1 <= de) {
-                       bzero(d, sizeof(*d));
-                       d->rtaddr.sin6_family = AF_INET6;
-                       d->rtaddr.sin6_len = sizeof(struct sockaddr_in6);
-                       in6_recoverscope(&d->rtaddr, &dr->rtaddr);
-                       d->flags = dr->flags;
-                       d->rtlifetime = dr->rtlifetime;
-                       expire = dr->expire;
-                       if (expire != 0) {
-                               expire -= time_uptime;
-                               expire += time_second;
-                       }
-                       d->expire = expire;
-                       d->if_index = dr->ifp->if_index;
-               }
-
-               l += sizeof(*d);
-               if (d)
-                       d++;
-       }
-
-       if (oldp) {
-               *oldlenp = l;   /* (caddr_t)d - (caddr_t)oldp */
-               if (l > ol)
-                       error = ENOMEM;
-       } else
-               *oldlenp = l;
-
-       return (error);
-}
-
-int
-fill_prlist(void *oldp, size_t *oldlenp, size_t ol)
-{
-       int error = 0;
-       struct nd_prefix *pr;
-       char *p = NULL, *ps = NULL;
-       char *pe = NULL;
-       size_t l;
-
-       if (oldp) {
-               ps = p = (char *)oldp;
-               pe = (char *)oldp + *oldlenp;
-       }
-       l = 0;
-
-       LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-               u_short advrtrs;
-               struct sockaddr_in6 sin6;
-               struct nd_pfxrouter *pfr;
-               struct in6_prefix pfx;
-
-               if (oldp && p + sizeof(struct in6_prefix) <= pe) {
-                       memset(&pfx, 0, sizeof(pfx));
-                       ps = p;
-
-                       pfx.prefix = pr->ndpr_prefix;
-                       in6_recoverscope(&pfx.prefix,
-                           &pfx.prefix.sin6_addr);
-                       pfx.raflags = pr->ndpr_raf;
-                       pfx.prefixlen = pr->ndpr_plen;
-                       pfx.vltime = pr->ndpr_vltime;
-                       pfx.pltime = pr->ndpr_pltime;
-                       pfx.if_index = pr->ndpr_ifp->if_index;
-                       if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
-                               pfx.expire = 0;
-                       else {
-                               time_t maxexpire;
-
-                               /* XXX: we assume time_t is signed. */
-                               maxexpire = (time_t)~(1ULL <<
-                                   ((sizeof(maxexpire) * 8) - 1));
-                               if (pr->ndpr_vltime <
-                                   maxexpire - pr->ndpr_lastupdate) {
-                                       pfx.expire = pr->ndpr_lastupdate +
-                                               pr->ndpr_vltime;
-                               } else
-                                       pfx.expire = maxexpire;
-                       }
-                       pfx.refcnt = pr->ndpr_refcnt;
-                       pfx.flags = pr->ndpr_stateflags;
-                       pfx.origin = PR_ORIG_RA;
-
-                       p += sizeof(pfx); l += sizeof(pfx);
-
-                       advrtrs = 0;
-                       LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
-                               if (p + sizeof(sin6) > pe) {
-                                       advrtrs++;
-                                       continue;
-                               }
-                               bzero(&sin6, sizeof(sin6));
-                               sin6.sin6_family = AF_INET6;
-                               sin6.sin6_len = sizeof(struct sockaddr_in6);
-                               in6_recoverscope(&sin6, &pfr->router->rtaddr);
-                               advrtrs++;
-                               memcpy(p, &sin6, sizeof(sin6));
-                               p += sizeof(sin6);
-                               l += sizeof(sin6);
-                       }
-                       pfx.advrtrs = advrtrs;
-                       memcpy(ps, &pfx, sizeof(pfx));
-               }
-               else {
-                       l += sizeof(pfx);
-                       advrtrs = 0;
-                       LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
-                               advrtrs++;
-                               l += sizeof(sin6);
-                       }
-               }
-       }
-
-       if (oldp) {
-               *oldlenp = l;   /* (caddr_t)d - (caddr_t)oldp */
-               if (l > ol)
-                       error = ENOMEM;
-       } else
-               *oldlenp = l;
-
-       return (error);
-}
diff --git netinet6/nd6.h netinet6/nd6.h
index 4274cd4dd07..508d38dc3aa 100644
--- netinet6/nd6.h
+++ netinet6/nd6.h
@@ -165,60 +165,12 @@ struct    llinfo_nd6 {
                (((MIN_RANDOM_FACTOR * (x >> 10)) + (arc4random() & \
                ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000)
 
-TAILQ_HEAD(nd_drhead, nd_defrouter);
-struct nd_defrouter {
-       TAILQ_ENTRY(nd_defrouter) dr_entry;
-       struct  in6_addr rtaddr;
-       struct  ifnet *ifp;
-       time_t  expire;
-       int     installed;      /* is installed into kernel routing table */
-       u_short rtlifetime;
-       u_char  flags;          /* flags on RA message */
-};
-
-struct nd_prefix {
-       struct ifnet *ndpr_ifp;
-       LIST_ENTRY(nd_prefix) ndpr_entry;
-       struct sockaddr_in6 ndpr_prefix;        /* prefix */
-       struct in6_addr ndpr_mask; /* netmask derived from the prefix */
-
-       struct task ndpr_task;
-
-       time_t ndpr_expire;     /* expiration time of the prefix */
-       time_t ndpr_preferred;  /* preferred time of the prefix */
-       time_t ndpr_lastupdate; /* reception time of last advertisement */
-
-       u_int32_t ndpr_vltime;  /* advertised valid lifetime */
-       u_int32_t ndpr_pltime;  /* advertised preferred lifetime */
-
-       struct prf_ra ndpr_flags;
-       u_int32_t ndpr_stateflags; /* actual state flags */
-       /* list of routers that advertise the prefix: */
-       LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs;
-       u_char  ndpr_plen;
-       int     ndpr_refcnt;    /* reference counter from addresses */
-};
-
-#define ndpr_raf               ndpr_flags
-#define ndpr_raf_onlink                ndpr_flags.onlink
-#define ndpr_raf_auto          ndpr_flags.autonomous
-#define ndpr_raf_router                ndpr_flags.router
-
-struct nd_pfxrouter {
-       LIST_ENTRY(nd_pfxrouter) pfr_entry;
-       struct nd_defrouter *router;
-};
-
-LIST_HEAD(nd_prhead, nd_prefix);
-
 extern int nd6_prune;
 extern int nd6_delay;
 extern int nd6_umaxtries;
 extern int nd6_mmaxtries;
 extern int nd6_maxnudhint;
 extern int nd6_gctimer;
-extern struct nd_drhead nd_defrouter;
-extern struct nd_prhead nd_prefix;
 extern int nd6_debug;
 
 #define nd6log(x)      do { if (nd6_debug) log x; } while (0)
@@ -279,22 +231,9 @@ void nd6_dad_start(struct ifaddr *);
 void nd6_dad_stop(struct ifaddr *);
 void nd6_ra_input(struct mbuf *, int, int);
 
-void nd6_rs_init(void);
-void nd6_rs_attach(struct ifnet *);
-void nd6_rs_detach(struct ifnet *);
 void nd6_rs_input(struct mbuf *, int, int);
 
-void prelist_del(struct nd_prefix *);
-void defrouter_reset(void);
-void defrouter_select(void);
-void defrtrlist_del(struct nd_defrouter *);
-void prelist_remove(struct nd_prefix *);
-void pfxlist_onlink_check(void);
-struct nd_defrouter *defrouter_lookup(struct in6_addr *, unsigned int);
-
-struct nd_prefix *nd6_prefix_lookup(struct nd_prefix *);
 int in6_ifdel(struct ifnet *, struct in6_addr *);
-int in6_init_prefix_ltimes(struct nd_prefix *ndpr);
 void rt6_flush(struct in6_addr *, struct ifnet *);
 
 #endif /* _KERNEL */
diff --git netinet6/nd6_nbr.c netinet6/nd6_nbr.c
index b9c985a31b9..a1647c292df 100644
--- netinet6/nd6_nbr.c
+++ netinet6/nd6_nbr.c
@@ -737,7 +737,6 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
                         * non-reachable to probably reachable, and might
                         * affect the status of associated prefixes..
                         */
-                       pfxlist_onlink_check();
                        if ((rt->rt_flags & RTF_LLINFO) == 0)
                                goto freeit;    /* ln is gone */
                }
@@ -827,29 +826,9 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
                }
 
                if (ln->ln_router && !is_router) {
-                       /*
-                        * The peer dropped the router flag.
-                        * Remove the sender from the Default Router List and
-                        * update the Destination Cache entries.
-                        */
-                       struct nd_defrouter *dr;
-                       struct in6_addr *in6;
-
-                       in6 = &satosin6(rt_key(rt))->sin6_addr;
-
-                       /*
-                        * Lock to protect the default router list.
-                        * XXX: this might be unnecessary, since this function
-                        * is only called under the network software interrupt
-                        * context.  However, we keep it just for safety.
-                        */
-                       dr = defrouter_lookup(in6, rt->rt_ifidx);
-                       if (dr)
-                               defrtrlist_del(dr);
-                       else if (!ip6_forwarding) {
+                       if (!ip6_forwarding) {
                                /*
-                                * Even if the neighbor is not in the default
-                                * router list, the neighbor may be used
+                                * The neighbor may be used
                                 * as a next hop for some destinations
                                 * (e.g. redirect case). So we must
                                 * call rt6_flush explicitly.
diff --git netinet6/nd6_rtr.c netinet6/nd6_rtr.c
index 4879c9643dd..3140cfb23ea 100644
--- netinet6/nd6_rtr.c
+++ netinet6/nd6_rtr.c
@@ -57,47 +57,10 @@
 #include <netinet6/nd6.h>
 #include <netinet/icmp6.h>
 
-int rtpref(struct nd_defrouter *);
-struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
-struct in6_ifaddr *in6_ifadd(struct nd_prefix *, int);
-struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *, struct nd_defrouter *);
-void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
-void pfxrtr_del(struct nd_pfxrouter *);
-struct nd_pfxrouter *find_pfxlist_reachable_router(struct nd_prefix *);
-void defrouter_delreq(struct nd_defrouter *);
-void purge_detached(struct ifnet *);
-int nd6_prefix_onlink(struct nd_prefix *);
-int nd6_prefix_offlink(struct nd_prefix *);
-void in6_init_address_ltimes(struct nd_prefix *, struct in6_addrlifetime *);
-int prelist_update(struct nd_prefix *, struct nd_defrouter *, struct mbuf *);
-int nd6_prelist_add(struct nd_prefix *, struct nd_defrouter *,
-       struct nd_prefix **);
-void defrouter_addreq(struct nd_defrouter *);
 int rt6_deleteroute(struct rtentry *, void *, unsigned int);
 
-void nd6_addr_add(void *);
-
-void nd6_rs_output_timo(void *);
-void nd6_rs_output_set_timo(int);
-void nd6_rs_output(struct ifnet *, struct in6_ifaddr *);
-void nd6_rs_dev_state(void *);
-
 extern int nd6_recalc_reachtm_interval;
 
-#define ND6_RS_OUTPUT_INTERVAL         60
-#define ND6_RS_OUTPUT_QUICK_INTERVAL   1
-
-struct timeout nd6_rs_output_timer;
-int            nd6_rs_output_timeout = ND6_RS_OUTPUT_INTERVAL;
-int            nd6_rs_timeout_count = 0;
-
-void
-nd6_rs_init(void)
-{
-       timeout_set_proc(&nd6_rs_output_timer, nd6_rs_output_timo, NULL);
-}
-
-
 /*
  * Receive Router Solicitation Message - just for routers.
  * Router solicitation/advertisement is mostly managed by userland program
@@ -194,173 +157,6 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
        m_freem(m);
 }
 
-void
-nd6_rs_output(struct ifnet* ifp, struct in6_ifaddr *ia6)
-{
-       struct mbuf *m;
-       struct ip6_hdr *ip6;
-       struct nd_router_solicit *rs;
-       struct ip6_moptions im6o;
-       caddr_t mac;
-       int icmp6len, maxlen;
-
-       NET_ASSERT_LOCKED();
-
-       KASSERT(ia6 != NULL);
-       KASSERT(ifp->if_flags & IFF_RUNNING);
-       KASSERT(ifp->if_xflags & IFXF_AUTOCONF6);
-       KASSERT(!(ia6->ia6_flags & IN6_IFF_TENTATIVE));
-
-       maxlen = sizeof(*ip6) + sizeof(*rs);
-       maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
-
-       MGETHDR(m, M_DONTWAIT, MT_DATA);
-       if (m && max_linkhdr + maxlen >= MHLEN) {
-               MCLGET(m, M_DONTWAIT);
-               if ((m->m_flags & M_EXT) == 0) {
-                       m_free(m);
-                       m = NULL;
-               }
-       }
-       if (m == NULL)
-               return;
-
-       m->m_pkthdr.ph_ifidx = 0;
-       m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
-       m->m_flags |= M_MCAST;
-       m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
-
-       im6o.im6o_ifidx = ifp->if_index;
-       im6o.im6o_hlim = 255;
-       im6o.im6o_loop = 0;
-
-       icmp6len = sizeof(*rs);
-       m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
-       m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
-
-       /* fill neighbor solicitation packet */
-       ip6 = mtod(m, struct ip6_hdr *);
-       ip6->ip6_flow = 0;
-       ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
-       ip6->ip6_vfc |= IPV6_VERSION;
-       /* ip6->ip6_plen will be set later */
-       ip6->ip6_nxt = IPPROTO_ICMPV6;
-       ip6->ip6_hlim = 255;
-
-       ip6->ip6_dst = in6addr_linklocal_allrouters;
-
-       ip6->ip6_src = ia6->ia_addr.sin6_addr;
-
-       rs = (struct nd_router_solicit *)(ip6 + 1);
-       rs->nd_rs_type = ND_ROUTER_SOLICIT;
-       rs->nd_rs_code = 0;
-       rs->nd_rs_cksum = 0;
-       rs->nd_rs_reserved = 0;
-
-       if ((mac = nd6_ifptomac(ifp))) {
-               int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
-               struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(rs + 1);
-               /* 8 byte alignments... */
-               optlen = (optlen + 7) & ~7;
-
-               m->m_pkthdr.len += optlen;
-               m->m_len += optlen;
-               icmp6len += optlen;
-               bzero((caddr_t)nd_opt, optlen);
-               nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-               nd_opt->nd_opt_len = optlen >> 3;
-               bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
-       }
-
-       ip6->ip6_plen = htons((u_short)icmp6len);
-
-       ip6_output(m, NULL, NULL, 0, &im6o, NULL);
-
-       icmp6stat_inc(icp6s_outhist + ND_ROUTER_SOLICIT);
-}
-
-void
-nd6_rs_output_set_timo(int timeout)
-{
-       return;
-       nd6_rs_output_timeout = timeout;
-       timeout_add_sec(&nd6_rs_output_timer, nd6_rs_output_timeout);
-}
-
-void
-nd6_rs_output_timo(void *ignored_arg)
-{
-       struct ifnet *ifp;
-       struct in6_ifaddr *ia6;
-       int s;
-
-       if (nd6_rs_timeout_count == 0)
-               return;
-
-       if (nd6_rs_output_timeout < ND6_RS_OUTPUT_INTERVAL)
-               /* exponential backoff if running quick timeouts */
-               nd6_rs_output_timeout *= 2;
-       if (nd6_rs_output_timeout > ND6_RS_OUTPUT_INTERVAL)
-               nd6_rs_output_timeout = ND6_RS_OUTPUT_INTERVAL;
-
-       NET_LOCK(s);
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
-               if (ISSET(ifp->if_flags, IFF_RUNNING) &&
-                   ISSET(ifp->if_xflags, IFXF_AUTOCONF6)) {
-                       ia6 = in6ifa_ifpforlinklocal(ifp, IN6_IFF_TENTATIVE);
-                       if (ia6 != NULL)
-                               nd6_rs_output(ifp, ia6);
-               }
-       }
-       NET_UNLOCK(s);
-       nd6_rs_output_set_timo(nd6_rs_output_timeout);
-}
-
-void
-nd6_rs_attach(struct ifnet *ifp)
-{
-       if (!ISSET(ifp->if_xflags, IFXF_AUTOCONF6)) {
-               /*
-                * We are being called from net/if.c, autoconf is not yet
-                * enabled on the interface.
-                */
-               nd6_rs_timeout_count++;
-               RS_LHCOOKIE(ifp) = hook_establish(ifp->if_linkstatehooks, 1,
-                   nd6_rs_dev_state, ifp);
-       }
-
-       /*
-        * (re)send solicitation regardless if we are enabling autoconf
-        * for the first time or if the link comes up
-        */
-       nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL);
-}
-
-void
-nd6_rs_detach(struct ifnet *ifp)
-{
-       if (ISSET(ifp->if_xflags, IFXF_AUTOCONF6)) {
-               nd6_rs_timeout_count--;
-               hook_disestablish(ifp->if_linkstatehooks, RS_LHCOOKIE(ifp));
-       }
-
-       if (nd6_rs_timeout_count == 0)
-               timeout_del(&nd6_rs_output_timer);
-}
-
-void
-nd6_rs_dev_state(void *arg)
-{
-       struct ifnet *ifp;
-
-       ifp = (struct ifnet *) arg;
-
-       if (LINK_STATE_IS_UP(ifp->if_link_state) &&
-           ifp->if_flags & IFF_RUNNING)
-               /* start quick timer, will exponentially back off */
-               nd6_rs_output_set_timo(ND6_RS_OUTPUT_QUICK_INTERVAL);
-}
-
 /*
  * Receive Router Advertisement Message.
  *
@@ -370,32 +166,15 @@ void
 nd6_ra_input(struct mbuf *m, int off, int icmp6len)
 {
        struct ifnet *ifp;
-       struct nd_ifinfo *ndi;
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        struct nd_router_advert *nd_ra;
        struct in6_addr saddr6 = ip6->ip6_src;
+       char *lladdr = NULL;
+       int lladdrlen = 0;
        union nd_opts ndopts;
-       struct nd_defrouter *dr;
        char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
 
-       ifp = if_get(m->m_pkthdr.ph_ifidx);
-       if (ifp == NULL)
-               goto freeit;
-
-       goto freeit;
-
-       /* We accept RAs only if inet6 autoconf is enabled  */
-       if (!(ifp->if_xflags & IFXF_AUTOCONF6))
-               goto freeit;
-
-       ndi = ND_IFINFO(ifp);
-       if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
-               goto freeit;
-
-       if (nd6_rs_output_timeout != ND6_RS_OUTPUT_INTERVAL)
-               /* we saw a RA, stop quick timer */
-               nd6_rs_output_set_timo(ND6_RS_OUTPUT_INTERVAL);
-
+       /* Sanity checks */
        if (ip6->ip6_hlim != 255) {
                nd6log((LOG_ERR,
                    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
@@ -416,7 +195,6 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
        IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
        if (nd_ra == NULL) {
                icmp6stat_inc(icp6s_tooshort);
-               if_put(ifp);
                return;
        }
 
@@ -429,1591 +207,38 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
                goto freeit;
        }
 
-    {
-       struct nd_defrouter dr0;
-       u_int32_t advreachable = nd_ra->nd_ra_reachable;
-
-       memset(&dr0, 0, sizeof(dr0));
-       dr0.rtaddr = saddr6;
-       dr0.flags  = nd_ra->nd_ra_flags_reserved;
-       dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
-       dr0.expire = time_uptime + dr0.rtlifetime;
-       dr0.ifp = ifp;
-       /* unspecified or not? (RFC 2461 6.3.4) */
-       if (advreachable) {
-               advreachable = ntohl(advreachable);
-               if (advreachable <= MAX_REACHABLE_TIME &&
-                   ndi->basereachable != advreachable) {
-                       ndi->basereachable = advreachable;
-                       ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
-                       ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
-               }
-       }
-       if (nd_ra->nd_ra_retransmit)
-               ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
-       if (nd_ra->nd_ra_curhoplimit) {
-               /*
-                * Ignore it.  The router doesn't know the diameter of
-                * the Internet better than this source code.
-                */
-       }
-       dr = defrtrlist_update(&dr0);
-    }
-
-       /*
-        * prefix
-        */
-       if (ndopts.nd_opts_pi) {
-               struct nd_opt_hdr *pt;
-               struct nd_opt_prefix_info *pi = NULL;
-               struct nd_prefix pr;
-
-               for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
-                    pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
-                    pt = (struct nd_opt_hdr *)((caddr_t)pt +
-                                               (pt->nd_opt_len << 3))) {
-                       if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
-                               continue;
-                       pi = (struct nd_opt_prefix_info *)pt;
-
-                       if (pi->nd_opt_pi_len != 4) {
-                               nd6log((LOG_INFO,
-                                   "nd6_ra_input: invalid option "
-                                   "len %d for prefix information option, "
-                                   "ignored\n", pi->nd_opt_pi_len));
-                               continue;
-                       }
-
-                       if (128 < pi->nd_opt_pi_prefix_len) {
-                               nd6log((LOG_INFO,
-                                   "nd6_ra_input: invalid prefix "
-                                   "len %d for prefix information option, "
-                                   "ignored\n", pi->nd_opt_pi_prefix_len));
-                               continue;
-                       }
-
-                       if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
-                        || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
-                               nd6log((LOG_INFO,
-                                   "nd6_ra_input: invalid prefix "
-                                   "%s, ignored\n",
-                                   inet_ntop(AF_INET6, &pi->nd_opt_pi_prefix,
-                                       src, sizeof(src))));
-                               continue;
-                       }
-
-                       /* aggregatable unicast address, rfc2374 */
-                       if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
-                        && pi->nd_opt_pi_prefix_len != 64) {
-                               nd6log((LOG_INFO,
-                                   "nd6_ra_input: invalid prefixlen "
-                                   "%d for rfc2374 prefix %s, ignored\n",
-                                   pi->nd_opt_pi_prefix_len,
-                                   inet_ntop(AF_INET6, &pi->nd_opt_pi_prefix,
-                                       src, sizeof(src))));
-                               continue;
-                       }
-
-                       bzero(&pr, sizeof(pr));
-                       pr.ndpr_prefix.sin6_family = AF_INET6;
-                       pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
-                       pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
-                       pr.ndpr_ifp = ifp;
-
-                       pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
-                            ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
-                       pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
-                            ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
-                       pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
-                       pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
-                       pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
-                       pr.ndpr_lastupdate = time_uptime;
-
-                       if (in6_init_prefix_ltimes(&pr))
-                               continue; /* prefix lifetime init failed */
-
-                       (void)prelist_update(&pr, dr, m);
-               }
-       }
-
-       /*
-        * Source link layer address
-        */
-    {
-       char *lladdr = NULL;
-       int lladdrlen = 0;
-
        if (ndopts.nd_opts_src_lladdr) {
                lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
                lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
        }
 
+       ifp = if_get(m->m_pkthdr.ph_ifidx);
+       if (ifp == NULL)
+               goto freeit;
+
        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
                nd6log((LOG_INFO,
                    "nd6_ra_input: lladdrlen mismatch for %s "
                    "(if %d, RA packet %d)\n",
                    inet_ntop(AF_INET6, &saddr6, src, sizeof(src)),
                    ifp->if_addrlen, lladdrlen - 2));
+               if_put(ifp);
                goto bad;
        }
 
        nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
-
-       /*
-        * Installing a link-layer address might change the state of the
-        * router's neighbor cache, which might also affect our on-link
-        * detection of advertised prefixes.
-        */
-       pfxlist_onlink_check();
-    }
+       if_put(ifp);
 
  freeit:
-       if_put(ifp);
        m_freem(m);
        return;
 
  bad:
        icmp6stat_inc(icp6s_badra);
-       if_put(ifp);
        m_freem(m);
 }
 
 /*
- * default router list processing sub routines
- */
-void
-defrouter_addreq(struct nd_defrouter *new)
-{
-       struct rt_addrinfo info;
-       struct sockaddr_in6 def, mask, gate;
-       struct rtentry *rt;
-       int error;
-
-       memset(&def, 0, sizeof(def));
-       memset(&mask, 0, sizeof(mask));
-       memset(&gate, 0, sizeof(gate)); /* for safety */
-       memset(&info, 0, sizeof(info));
-
-       def.sin6_len = mask.sin6_len = gate.sin6_len =
-           sizeof(struct sockaddr_in6);
-       def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
-       gate.sin6_addr = new->rtaddr;
-       gate.sin6_scope_id = 0; /* XXX */
-
-       info.rti_ifa = NULL;
-       info.rti_flags = RTF_GATEWAY;
-       info.rti_info[RTAX_DST] = sin6tosa(&def);
-       info.rti_info[RTAX_GATEWAY] = sin6tosa(&gate);
-       info.rti_info[RTAX_NETMASK] = sin6tosa(&mask);
-
-       error = rtrequest(RTM_ADD, &info, RTP_DEFAULT, &rt,
-           new->ifp->if_rdomain);
-       if (error == 0) {
-               KERNEL_LOCK();
-               rtm_send(rt, RTM_ADD, new->ifp->if_rdomain);
-               KERNEL_UNLOCK();
-               rtfree(rt);
-               new->installed = 1;
-       }
-}
-
-struct nd_defrouter *
-defrouter_lookup(struct in6_addr *addr, unsigned int ifidx)
-{
-       struct nd_defrouter *dr;
-
-       TAILQ_FOREACH(dr, &nd_defrouter, dr_entry)
-               if (dr->ifp->if_index == ifidx &&
-                   IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
-                       return (dr);
-
-       return (NULL);          /* search failed */
-}
-
-void
-defrtrlist_del(struct nd_defrouter *dr)
-{
-       struct nd_defrouter *deldr = NULL;
-       struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6];
-       struct nd_prefix *pr;
-
-       /*
-        * Flush all the routing table entries that use the router
-        * as a next hop.
-        */
-       /* XXX: better condition? */
-       if (!ip6_forwarding)
-               rt6_flush(&dr->rtaddr, dr->ifp);
-
-       if (dr->installed) {
-               deldr = dr;
-               defrouter_delreq(dr);
-       }
-       TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
-
-       /*
-        * Also delete all the pointers to the router in each prefix lists.
-        */
-       LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-               struct nd_pfxrouter *pfxrtr;
-               if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
-                       pfxrtr_del(pfxrtr);
-       }
-       pfxlist_onlink_check();
-
-       /*
-        * If the router is the primary one, choose a new one.
-        * Note that defrouter_select() will remove the current gateway
-        * from the routing table.
-        */
-       if (deldr)
-               defrouter_select();
-
-       ext->ndefrouters--;
-       if (ext->ndefrouters < 0) {
-               log(LOG_WARNING, "%s: negative count on %s\n", __func__,
-                   dr->ifp->if_xname);
-       }
-
-       free(dr, M_IP6NDP, sizeof(*dr));
-}
-
-/*
- * Remove the default route for a given router.
- * This is just a subroutine function for defrouter_select(), and should
- * not be called from anywhere else.
- */
-void
-defrouter_delreq(struct nd_defrouter *dr)
-{
-       struct rt_addrinfo info;
-       struct sockaddr_in6 def, mask, gw;
-       struct rtentry *rt;
-       int error;
-
-#ifdef DIAGNOSTIC
-       if (!dr)
-               panic("dr == NULL in defrouter_delreq");
-#endif
-
-       memset(&info, 0, sizeof(info));
-       memset(&def, 0, sizeof(def));
-       memset(&mask, 0, sizeof(mask));
-       memset(&gw, 0, sizeof(gw));     /* for safety */
-
-       def.sin6_len = mask.sin6_len = gw.sin6_len =
-           sizeof(struct sockaddr_in6);
-       def.sin6_family = mask.sin6_family = gw.sin6_family = AF_INET6;
-       gw.sin6_addr = dr->rtaddr;
-       gw.sin6_scope_id = 0;   /* XXX */
-
-       info.rti_flags = RTF_GATEWAY;
-       info.rti_info[RTAX_DST] = sin6tosa(&def);
-       info.rti_info[RTAX_GATEWAY] = sin6tosa(&gw);
-       info.rti_info[RTAX_NETMASK] = sin6tosa(&mask);
-
-       error = rtrequest_delete(&info, RTP_DEFAULT, dr->ifp, &rt,
-           dr->ifp->if_rdomain);
-       if (error == 0) {
-               KERNEL_LOCK();
-               rtm_send(rt, RTM_DELETE, dr->ifp->if_rdomain);
-               KERNEL_UNLOCK();
-               rtfree(rt);
-       }
-
-       dr->installed = 0;
-}
-
-/*
- * remove all default routes from default router list
- */
-void
-defrouter_reset(void)
-{
-       struct nd_defrouter *dr;
-
-       TAILQ_FOREACH(dr, &nd_defrouter, dr_entry)
-               defrouter_delreq(dr);
-
-       /*
-        * XXX should we also nuke any default routers in the kernel, by
-        * going through them by rtalloc()?
-        */
-}
-
-/*
- * Default Router Selection according to Section 6.3.6 of RFC 2461 and
- * draft-ietf-ipngwg-router-selection:
- * 1) Routers that are reachable or probably reachable should be preferred.
- *    If we have more than one (probably) reachable router, prefer ones
- *    with the highest router preference.
- * 2) When no routers on the list are known to be reachable or
- *    probably reachable, routers SHOULD be selected in a round-robin
- *    fashion, regardless of router preference values.
- * 3) If the Default Router List is empty, assume that all
- *    destinations are on-link.
- *
- * We assume nd_defrouter is sorted by router preference value.
- * Since the code below covers both with and without router preference cases,
- * we do not need to classify the cases by ifdef.
- *
- * At this moment, we do not try to install more than one default router,
- * even when the multipath routing is available, because we're not sure about
- * the benefits for stub hosts comparing to the risk of making the code
- * complicated and the possibility of introducing bugs.
- */
-void
-defrouter_select(void)
-{
-       struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
-       struct rtentry *rt = NULL;
-       struct llinfo_nd6 *ln = NULL;
-
-       /*
-        * Let's handle easy case (3) first:
-        * If default router list is empty, there's nothing to be done.
-        */
-       if (TAILQ_EMPTY(&nd_defrouter)) {
-               return;
-       }
-
-       /*
-        * Search for a (probably) reachable router from the list.
-        * We just pick up the first reachable one (if any), assuming that
-        * the ordering rule of the list described in defrtrlist_update().
-        */
-       TAILQ_FOREACH(dr, &nd_defrouter, dr_entry) {
-               if (!(dr->ifp->if_xflags & IFXF_AUTOCONF6))
-                       continue;
-               if (!selected_dr) {
-                       rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp,
-                           dr->ifp->if_rdomain);
-                       if ((rt != NULL) &&
-                           (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
-                           ND6_IS_LLINFO_PROBREACH(ln)) {
-                               selected_dr = dr;
-                       }
-                       rtfree(rt);
-               }
-
-               if (dr->installed && !installed_dr)
-                       installed_dr = dr;
-               else if (dr->installed && installed_dr) {
-                       /* this should not happen.  warn for diagnosis. */
-                       log(LOG_ERR, "defrouter_select: more than one router"
-                           " is installed\n");
-               }
-       }
-       /*
-        * If none of the default routers was found to be reachable,
-        * round-robin the list regardless of preference.
-        * Otherwise, if we have an installed router, check if the selected
-        * (reachable) router should really be preferred to the installed one.
-        * We only prefer the new router when the old one is not reachable
-        * or when the new one has a really higher preference value.
-        */
-       if (!selected_dr) {
-               if (!installed_dr || !TAILQ_NEXT(installed_dr, dr_entry))
-                       selected_dr = TAILQ_FIRST(&nd_defrouter);
-               else
-                       selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
-       } else if (installed_dr) {
-               rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp,
-                   installed_dr->ifp->if_rdomain);
-               if ((rt != NULL) && (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
-                   ND6_IS_LLINFO_PROBREACH(ln) &&
-                   rtpref(selected_dr) <= rtpref(installed_dr)) {
-                       selected_dr = installed_dr;
-               }
-               rtfree(rt);
-       }
-
-       /*
-        * If the selected router is different than the installed one,
-        * remove the installed router and install the selected one.
-        * Note that the selected router is never NULL here.
-        */
-       if (installed_dr != selected_dr) {
-               if (installed_dr)
-                       defrouter_delreq(installed_dr);
-               defrouter_addreq(selected_dr);
-       }
-}
-
-/*
- * for default router selection
- * regards router-preference field as a 2-bit signed integer
- */
-int
-rtpref(struct nd_defrouter *dr)
-{
-#ifdef RTPREF
-       switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
-       case ND_RA_FLAG_RTPREF_HIGH:
-               return RTPREF_HIGH;
-       case ND_RA_FLAG_RTPREF_MEDIUM:
-       case ND_RA_FLAG_RTPREF_RSV:
-               return RTPREF_MEDIUM;
-       case ND_RA_FLAG_RTPREF_LOW:
-               return RTPREF_LOW;
-       default:
-               /*
-                * This case should never happen.  If it did, it would mean a
-                * serious bug of kernel internal.  We thus always bark here.
-                * Or, can we even panic?
-                */
-               log(LOG_ERR, "rtpref: impossible RA flag %x", dr->flags);
-               return RTPREF_INVALID;
-       }
-       /* NOTREACHED */
-#else
-       return 0;
-#endif
-}
-
-struct nd_defrouter *
-defrtrlist_update(struct nd_defrouter *new)
-{
-       struct nd_defrouter *dr, *n;
-       struct in6_ifextra *ext = new->ifp->if_afdata[AF_INET6];
-
-       NET_ASSERT_LOCKED();
-
-       if ((dr = defrouter_lookup(&new->rtaddr, new->ifp->if_index)) != NULL) {
-               /* entry exists */
-               if (new->rtlifetime == 0) {
-                       defrtrlist_del(dr);
-                       dr = NULL;
-               } else {
-                       int oldpref = rtpref(dr);
-
-                       /* override */
-                       dr->flags = new->flags; /* xxx flag check */
-                       dr->rtlifetime = new->rtlifetime;
-                       dr->expire = new->expire;
-
-                       if (!dr->installed)
-                               defrouter_select();
-
-                       /*
-                        * If the preference does not change, there's no need
-                        * to sort the entries.
-                        */
-                       if (rtpref(new) == oldpref) {
-                               return (dr);
-                       }
-
-                       /*
-                        * preferred router may be changed, so relocate
-                        * this router.
-                        * XXX: calling TAILQ_REMOVE directly is a bad manner.
-                        * However, since defrtrlist_del() has many side
-                        * effects, we intentionally do so here.
-                        * defrouter_select() below will handle routing
-                        * changes later.
-                        */
-                       TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
-                       n = dr;
-                       goto insert;
-               }
-               return (dr);
-       }
-
-       /* entry does not exist */
-       if (new->rtlifetime == 0) {
-               /* flush all possible redirects */
-               if (new->ifp->if_xflags & IFXF_AUTOCONF6)
-                       rt6_flush(&new->rtaddr, new->ifp);
-               return (NULL);
-       }
-
-       if (ip6_maxifdefrouters >= 0 &&
-           ext->ndefrouters >= ip6_maxifdefrouters) {
-               return (NULL);
-       }
-
-       n = malloc(sizeof(*n), M_IP6NDP, M_NOWAIT | M_ZERO);
-       if (n == NULL) {
-               return (NULL);
-       }
-       *n = *new;
-
-insert:
-       /*
-        * Insert the new router in the Default Router List;
-        * The Default Router List should be in the descending order
-        * of router-preference.  Routers with the same preference are
-        * sorted in the arriving time order.
-        */
-
-       /* insert at the end of the group */
-       TAILQ_FOREACH(dr, &nd_defrouter, dr_entry)
-               if (rtpref(n) > rtpref(dr))
-                       break;
-       if (dr)
-               TAILQ_INSERT_BEFORE(dr, n, dr_entry);
-       else
-               TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
-
-       defrouter_select();
-
-       ext->ndefrouters++;
-
-       return (n);
-}
-
-struct nd_pfxrouter *
-pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
-{
-       struct nd_pfxrouter *search;
-
-       LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) {
-               if (search->router == dr)
-                       break;
-       }
-
-       return (search);
-}
-
-void
-pfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr)
-{
-       struct nd_pfxrouter *new;
-
-       new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO);
-       if (new == NULL)
-               return;
-       new->router = dr;
-
-       LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
-
-       pfxlist_onlink_check();
-}
-
-void
-pfxrtr_del(struct nd_pfxrouter *pfr)
-{
-       LIST_REMOVE(pfr, pfr_entry);
-       free(pfr, M_IP6NDP, sizeof(*pfr));
-}
-
-struct nd_prefix *
-nd6_prefix_lookup(struct nd_prefix *pr)
-{
-       struct nd_prefix *search;
-
-       LIST_FOREACH(search, &nd_prefix, ndpr_entry) {
-               if (pr->ndpr_ifp == search->ndpr_ifp &&
-                   pr->ndpr_plen == search->ndpr_plen &&
-                   in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
-                   &search->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
-                       break;
-               }
-       }
-
-       return (search);
-}
-
-void
-purge_detached(struct ifnet *ifp)
-{
-       struct nd_prefix *pr, *pr_next;
-       struct in6_ifaddr *ia6;
-       struct ifaddr *ifa, *ifa_next;
-
-       NET_ASSERT_LOCKED();
-
-       LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, pr_next) {
-               /*
-                * This function is called when we need to make more room for
-                * new prefixes rather than keeping old, possibly stale ones.
-                * Detached prefixes would be a good candidate; if all routers
-                * that advertised the prefix expired, the prefix is also
-                * probably stale.
-                */
-               if (pr->ndpr_ifp != ifp ||
-                   IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) ||
-                   ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
-                   !LIST_EMPTY(&pr->ndpr_advrtrs)))
-                       continue;
-
-               TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, ifa_next) {
-                       if (ifa->ifa_addr->sa_family != AF_INET6)
-                               continue;
-                       ia6 = ifatoia6(ifa);
-                       if ((ia6->ia6_flags & IN6_IFF_AUTOCONF) ==
-                           IN6_IFF_AUTOCONF && ia6->ia6_ndpr == pr) {
-                               in6_purgeaddr(ifa);
-                       }
-               }
-       }
-}
-
-int
-nd6_prelist_add(struct nd_prefix *pr, struct nd_defrouter *dr,
-    struct nd_prefix **newp)
-{
-       struct nd_prefix *new = NULL;
-       struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6];
-       int i;
-
-       NET_ASSERT_LOCKED();
-
-       if (ip6_maxifprefixes >= 0) {
-               if (ext->nprefixes >= ip6_maxifprefixes / 2) {
-                       purge_detached(pr->ndpr_ifp);
-               }
-               if (ext->nprefixes >= ip6_maxifprefixes)
-                       return(ENOMEM);
-       }
-
-       new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO);
-       if (new == NULL)
-               return ENOMEM;
-       *new = *pr;
-       if (newp != NULL)
-               *newp = new;
-
-       /* initialization */
-       LIST_INIT(&new->ndpr_advrtrs);
-       in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
-       /* make prefix in the canonical form */
-       for (i = 0; i < 4; i++)
-               new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
-                   new->ndpr_mask.s6_addr32[i];
-
-       task_set(&new->ndpr_task, nd6_addr_add, new);
-
-       /* link ndpr_entry to nd_prefix list */
-       LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
-
-       /* ND_OPT_PI_FLAG_ONLINK processing */
-       if (new->ndpr_raf_onlink) {
-               char addr[INET6_ADDRSTRLEN];
-               int e;
-
-               if ((e = nd6_prefix_onlink(new)) != 0) {
-                       nd6log((LOG_ERR, "%s: failed to make the prefix %s/%d"
-                           " on-link on %s (errno=%d)\n", __func__,
-                           inet_ntop(AF_INET6, &pr->ndpr_prefix.sin6_addr,
-                               addr, sizeof(addr)),
-                           pr->ndpr_plen, pr->ndpr_ifp->if_xname, e));
-                       /* proceed anyway. XXX: is it correct? */
-               }
-       }
-
-       if (dr)
-               pfxrtr_add(new, dr);
-
-       ext->nprefixes++;
-
-       return 0;
-}
-
-void
-prelist_remove(struct nd_prefix *pr)
-{
-       struct nd_pfxrouter *pfr, *next;
-       struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6];
-       int e;
-
-       NET_ASSERT_LOCKED();
-
-       /* make sure to invalidate the prefix until it is really freed. */
-       pr->ndpr_vltime = 0;
-       pr->ndpr_pltime = 0;
-
-       if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
-           (e = nd6_prefix_offlink(pr)) != 0) {
-               char addr[INET6_ADDRSTRLEN];
-               nd6log((LOG_ERR, "%s: failed to make %s/%d offlink "
-                   "on %s, errno=%d\n", __func__,
-                   inet_ntop(AF_INET6, &pr->ndpr_prefix.sin6_addr,
-                       addr, sizeof(addr)),
-                   pr->ndpr_plen, pr->ndpr_ifp->if_xname, e));
-               /* what should we do? */
-       }
-
-       if (pr->ndpr_refcnt > 0)
-               return;         /* notice here? */
-
-       /* unlink ndpr_entry from nd_prefix list */
-       LIST_REMOVE(pr, ndpr_entry);
-
-       /* free list of routers that adversed the prefix */
-       LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next)
-               free(pfr, M_IP6NDP, sizeof(*pfr));
-
-       ext->nprefixes--;
-       if (ext->nprefixes < 0) {
-               log(LOG_WARNING, "%s: negative count on %s\n", __func__,
-                   pr->ndpr_ifp->if_xname);
-       }
-
-       free(pr, M_IP6NDP, sizeof(*pr));
-
-       pfxlist_onlink_check();
-}
-
-/*
- * dr - may be NULL
- */
-
-int
-prelist_update(struct nd_prefix *new, struct nd_defrouter *dr, struct mbuf *m)
-{
-       struct in6_ifaddr *ia6_match = NULL;
-       struct ifaddr *ifa;
-       struct ifnet *ifp = new->ndpr_ifp;
-       struct nd_prefix *pr;
-       int error = 0;
-       int tempaddr_preferred = 0, autoconf = 0, statique = 0;
-       int auth;
-       struct in6_addrlifetime lt6_tmp;
-       char addr[INET6_ADDRSTRLEN];
-
-       NET_ASSERT_LOCKED();
-
-       auth = 0;
-       if (m) {
-               /*
-                * Authenticity for NA consists authentication for
-                * both IP header and IP datagrams, doesn't it ?
-                */
-               auth = (m->m_flags & M_AUTH);
-       }
-
-       if ((pr = nd6_prefix_lookup(new)) != NULL) {
-               /*
-                * nd6_prefix_lookup() ensures that pr and new have the same
-                * prefix on a same interface.
-                */
-
-               /*
-                * Update prefix information.  Note that the on-link (L) bit
-                * and the autonomous (A) bit should NOT be changed from 1
-                * to 0.
-                */
-               if (new->ndpr_raf_onlink == 1)
-                       pr->ndpr_raf_onlink = 1;
-               if (new->ndpr_raf_auto == 1)
-                       pr->ndpr_raf_auto = 1;
-               if (new->ndpr_raf_onlink) {
-                       pr->ndpr_vltime = new->ndpr_vltime;
-                       pr->ndpr_pltime = new->ndpr_pltime;
-                       pr->ndpr_preferred = new->ndpr_preferred;
-                       pr->ndpr_expire = new->ndpr_expire;
-                       pr->ndpr_lastupdate = new->ndpr_lastupdate;
-               }
-
-               if (new->ndpr_raf_onlink &&
-                   (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
-                       int e;
-
-                       if ((e = nd6_prefix_onlink(pr)) != 0) {
-                               nd6log((LOG_ERR, "%s: failed to make the prefix"
-                                   " %s/%d on-link on %s (errno=%d)\n",
-                                   __func__, inet_ntop(AF_INET6,
-                                       &pr->ndpr_prefix.sin6_addr,
-                                       addr, sizeof(addr)),
-                                   pr->ndpr_plen, pr->ndpr_ifp->if_xname, e));
-                               /* proceed anyway. XXX: is it correct? */
-                       }
-               }
-
-               if (dr && pfxrtr_lookup(pr, dr) == NULL)
-                       pfxrtr_add(pr, dr);
-       } else {
-               struct nd_prefix *newpr = NULL;
-
-               if (new->ndpr_vltime == 0)
-                       goto end;
-               if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
-                       goto end;
-
-               error = nd6_prelist_add(new, dr, &newpr);
-               if (error != 0 || newpr == NULL) {
-                       nd6log((LOG_NOTICE, "%s: nd6_prelist_add failed for"
-                           " %s/%d on %s errno=%d, returnpr=%p\n", __func__,
-                           inet_ntop(AF_INET6, &new->ndpr_prefix.sin6_addr,
-                               addr, sizeof(addr)),
-                           new->ndpr_plen, new->ndpr_ifp->if_xname,
-                           error, newpr));
-                       goto end; /* we should just give up in this case. */
-               }
-
-               pr = newpr;
-       }
-
-       /*
-        * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
-        * Note that pr must be non NULL at this point.
-        */
-
-       /* 5.5.3 (a). Ignore the prefix without the A bit set. */
-       if (!new->ndpr_raf_auto)
-               goto end;
-
-       /*
-        * 5.5.3 (b). the link-local prefix should have been ignored in
-        * nd6_ra_input.
-        */
-
-       /*
-        * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime.
-        * This should have been done in nd6_ra_input.
-        */
-
-       /*
-        * 5.5.3 (d). If the prefix advertised does not match the prefix of an
-        * address already in the list, and the Valid Lifetime is not 0,
-        * form an address.  Note that even a manually configured address
-        * should reject autoconfiguration of a new address.
-        */
-       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
-               struct in6_ifaddr *ia6;
-               int ifa_plen;
-               u_int32_t storedlifetime;
-
-               if (ifa->ifa_addr->sa_family != AF_INET6)
-                       continue;
-
-               ia6 = ifatoia6(ifa);
-
-               /*
-                * Spec is not clear here, but I believe we should concentrate
-                * on unicast (i.e. not anycast) addresses.
-                * XXX: other ia6_flags? detached or duplicated?
-                */
-               if ((ia6->ia6_flags & IN6_IFF_ANYCAST) != 0)
-                       continue;
-
-               ifa_plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
-               if (ifa_plen != new->ndpr_plen ||
-                   !in6_are_prefix_equal(&ia6->ia_addr.sin6_addr,
-                   &new->ndpr_prefix.sin6_addr, ifa_plen))
-                       continue;
-
-               if (ia6_match == NULL) /* remember the first one */
-                       ia6_match = ia6;
-
-               if ((ia6->ia6_flags & IN6_IFF_AUTOCONF) == 0) {
-                       statique = 1;
-                       continue;
-               }
-
-               /*
-                * An already autoconfigured address matched.  Now that we
-                * are sure there is at least one matched address, we can
-                * proceed to 5.5.3. (e): update the lifetimes according to the
-                * "two hours" rule and the privacy extension.
-                */
-#define TWOHOUR                (120*60)
-               /*
-                * RFC2462 introduces the notion of StoredLifetime to the
-                * "two hours" rule as follows:
-                *   the Lifetime associated with the previously autoconfigured
-                *   address.
-                * Our interpretation of this definition is "the remaining
-                * lifetime to expiration at the evaluation time".  One might
-                * be wondering if this interpretation is really conform to the
-                * RFC, because the text can read that "Lifetimes" are never
-                * decreased, and our definition of the "storedlifetime" below
-                * essentially reduces the "Valid Lifetime" advertised in the
-                * previous RA.  But, this is due to the wording of the text,
-                * and our interpretation is the same as an author's intention.
-                * See the discussion in the IETF ipngwg ML in August 2001,
-                * with the Subject "StoredLifetime in RFC 2462".
-                */
-               lt6_tmp = ia6->ia6_lifetime;
-
-               /* RFC 4941 temporary addresses (privacy extension). */
-               if (ia6->ia6_flags & IN6_IFF_PRIVACY) {
-                       /* Do we still have a non-deprecated address? */
-                       if ((ia6->ia6_flags & IN6_IFF_DEPRECATED) == 0)
-                               tempaddr_preferred = 1;
-                       /* Don't extend lifetime for temporary addresses. */
-                       if (new->ndpr_vltime >= lt6_tmp.ia6t_vltime)
-                               continue;
-                       if (new->ndpr_pltime >= lt6_tmp.ia6t_pltime)
-                               continue;
-               } else if ((ia6->ia6_flags & IN6_IFF_DEPRECATED) == 0)
-                       /* We have a regular SLAAC address. */
-                       autoconf = 1;
-
-               if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
-                       storedlifetime = ND6_INFINITE_LIFETIME;
-               else if (time_uptime - ia6->ia6_updatetime >
-                        lt6_tmp.ia6t_vltime) {
-                       /*
-                        * The case of "invalid" address.  We should usually
-                        * not see this case.
-                        */
-                       storedlifetime = 0;
-               } else
-                       storedlifetime = lt6_tmp.ia6t_vltime -
-                               (time_uptime - ia6->ia6_updatetime);
-               if (TWOHOUR < new->ndpr_vltime ||
-                   storedlifetime < new->ndpr_vltime) {
-                       lt6_tmp.ia6t_vltime = new->ndpr_vltime;
-               } else if (storedlifetime <= TWOHOUR
-#if 0
-                          /*
-                           * This condition is logically redundant, so we just
-                           * omit it.
-                           * See IPng 6712, 6717, and 6721.
-                           */
-                          && new->ndpr_vltime <= storedlifetime
-#endif
-                       ) {
-                       if (auth) {
-                               lt6_tmp.ia6t_vltime = new->ndpr_vltime;
-                       }
-               } else {
-                       /*
-                        * new->ndpr_vltime <= TWOHOUR &&
-                        * TWOHOUR < storedlifetime
-                        */
-                       lt6_tmp.ia6t_vltime = TWOHOUR;
-               }
-
-               /* The 2 hour rule is not imposed for preferred lifetime. */
-               lt6_tmp.ia6t_pltime = new->ndpr_pltime;
-
-               in6_init_address_ltimes(pr, &lt6_tmp);
-
-               ia6->ia6_lifetime = lt6_tmp;
-               ia6->ia6_updatetime = time_uptime;
-       }
-
-       if ((!autoconf || ((ifp->if_xflags & IFXF_INET6_NOPRIVACY) == 0 &&
-            !tempaddr_preferred)) &&
-           new->ndpr_vltime != 0 && new->ndpr_pltime != 0 &&
-           !((ifp->if_xflags & IFXF_INET6_NOPRIVACY) && statique)) {
-               /*
-                * There is no SLAAC address and/or there is no preferred RFC
-                * 4941 temporary address. And prefix lifetimes are non-zero.
-                * And there is no static address in the same prefix.
-                * Create new addresses in process context.
-                * Increment prefix refcount to ensure the prefix is not
-                * removed before the task is done.
-                */
-               pr->ndpr_refcnt++;
-               if (task_add(systq, &pr->ndpr_task) == 0)
-                       pr->ndpr_refcnt--;
-       }
-
- end:
-       return error;
-}
-
-void
-nd6_addr_add(void *prptr)
-{
-       struct nd_prefix *pr = (struct nd_prefix *)prptr;
-       struct in6_ifaddr *ia6;
-       struct ifaddr *ifa;
-       int ifa_plen, autoconf, privacy, s;
-
-       NET_LOCK(s);
-
-       autoconf = 1;
-       privacy = (pr->ndpr_ifp->if_xflags & IFXF_INET6_NOPRIVACY) == 0;
-
-       /*
-        * Check again if a non-deprecated address has already
-        * been autoconfigured for this prefix.
-        */
-       TAILQ_FOREACH(ifa, &pr->ndpr_ifp->if_addrlist, ifa_list) {
-               if (ifa->ifa_addr->sa_family != AF_INET6)
-                       continue;
-
-               ia6 = ifatoia6(ifa);
-
-               /*
-                * Spec is not clear here, but I believe we should concentrate
-                * on unicast (i.e. not anycast) addresses.
-                * XXX: other ia6_flags? detached or duplicated?
-                */
-               if ((ia6->ia6_flags & IN6_IFF_ANYCAST) != 0)
-                       continue;
-
-               if ((ia6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
-                       continue;
-
-               if ((ia6->ia6_flags & IN6_IFF_DEPRECATED) != 0)
-                       continue;
-
-               ifa_plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
-               if (ifa_plen == pr->ndpr_plen &&
-                   in6_are_prefix_equal(&ia6->ia_addr.sin6_addr,
-                   &pr->ndpr_prefix.sin6_addr, ifa_plen)) {
-                       if ((ia6->ia6_flags & IN6_IFF_PRIVACY) == 0)
-                               autoconf = 0;
-                       else
-                               privacy = 0;
-                       if (!autoconf && !privacy)
-                               break;
-               }
-       }
-
-       if (autoconf && (ia6 = in6_ifadd(pr, 0)) != NULL) {
-               ia6->ia6_ndpr = pr;
-               pr->ndpr_refcnt++;
-       } else
-               autoconf = 0;
-
-       if (privacy && (ia6 = in6_ifadd(pr, 1)) != NULL) {
-               ia6->ia6_ndpr = pr;
-               pr->ndpr_refcnt++;
-       } else
-               privacy = 0;
-
-       /*
-        * A newly added address might affect the status
-        * of other addresses, so we check and update it.
-        * XXX: what if address duplication happens?
-        */
-       if (autoconf || privacy)
-               pfxlist_onlink_check();
-
-       /* Decrement prefix refcount now that the task is done. */
-       if (--pr->ndpr_refcnt == 0)
-               prelist_remove(pr);
-
-       NET_UNLOCK(s);
-}
-
-/*
- * A supplement function used in the on-link detection below;
- * detect if a given prefix has a (probably) reachable advertising router.
- * XXX: lengthy function name...
- */
-struct nd_pfxrouter *
-find_pfxlist_reachable_router(struct nd_prefix *pr)
-{
-       struct nd_pfxrouter *pfxrtr;
-       struct rtentry *rt = NULL;
-       struct llinfo_nd6 *ln;
-
-       LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) {
-               if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
-                   pfxrtr->router->ifp, pfxrtr->router->ifp->if_rdomain)) &&
-                   (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
-                   ND6_IS_LLINFO_PROBREACH(ln)) {
-                       rtfree(rt);
-                       break;  /* found */
-               }
-               rtfree(rt);
-       }
-
-       return (pfxrtr);
-}
-
-/*
- * Check if each prefix in the prefix list has at least one available router
- * that advertised the prefix (a router is "available" if its neighbor cache
- * entry is reachable or probably reachable).
- * If the check fails, the prefix may be off-link, because, for example,
- * we have moved from the network but the lifetime of the prefix has not
- * expired yet.  So we should not use the prefix if there is another prefix
- * that has an available router.
- * But, if there is no prefix that has an available router, we still regards
- * all the prefixes as on-link.  This is because we can't tell if all the
- * routers are simply dead or if we really moved from the network and there
- * is no router around us.
- */
-void
-pfxlist_onlink_check(void)
-{
-       struct ifnet *ifp;
-       struct ifaddr *ifa;
-       struct nd_prefix *pr;
-       struct in6_ifaddr *ia6, *pia6 = NULL;
-       char addr[INET6_ADDRSTRLEN];
-
-       /*
-        * Check if there is a prefix that has a reachable advertising
-        * router.
-        */
-       LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-               if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
-                       break;
-       }
-       if (pr != NULL || !TAILQ_EMPTY(&nd_defrouter)) {
-               /*
-                * There is at least one prefix that has a reachable router,
-                * or at least a router which probably does not advertise
-                * any prefixes.  The latter would be the case when we move
-                * to a new link where we have a router that does not provide
-                * prefixes and we configure an address by hand.
-                * Detach prefixes which have no reachable advertising
-                * router, and attach other prefixes.
-                */
-               LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-                       /* XXX: a link-local prefix should never be detached */
-                       if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
-                               continue;
-
-                       /*
-                        * we aren't interested in prefixes without the L bit
-                        * set.
-                        */
-                       if (pr->ndpr_raf_onlink == 0)
-                               continue;
-
-                       if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
-                           find_pfxlist_reachable_router(pr) == NULL)
-                               pr->ndpr_stateflags |= NDPRF_DETACHED;
-                       if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
-                           find_pfxlist_reachable_router(pr) != 0)
-                               pr->ndpr_stateflags &= ~NDPRF_DETACHED;
-               }
-       } else {
-               /* there is no prefix that has a reachable router */
-               LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-                       if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
-                               continue;
-
-                       if (pr->ndpr_raf_onlink == 0)
-                               continue;
-
-                       if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
-                               pr->ndpr_stateflags &= ~NDPRF_DETACHED;
-               }
-       }
-
-       /*
-        * Remove each interface route associated with a (just) detached
-        * prefix, and reinstall the interface route for a (just) attached
-        * prefix.  Note that all attempt of reinstallation does not
-        * necessarily success, when a same prefix is shared among multiple
-        * interfaces.  Such cases will be handled in nd6_prefix_onlink,
-        * so we don't have to care about them.
-        */
-       LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
-               int e;
-
-               if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
-                       continue;
-
-               if (pr->ndpr_raf_onlink == 0)
-                       continue;
-
-               if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
-                   (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
-                       if ((e = nd6_prefix_offlink(pr)) != 0) {
-                               nd6log((LOG_ERR, "%s: failed to make %s/%d "
-                                   "offlink, errno=%d\n", __func__,
-                                   inet_ntop(AF_INET6,
-                                       &pr->ndpr_prefix.sin6_addr,
-                                       addr, sizeof(addr)),
-                                   pr->ndpr_plen, e));
-                       }
-               }
-               if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
-                   (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
-                   pr->ndpr_raf_onlink) {
-                       if ((e = nd6_prefix_onlink(pr)) != 0) {
-                               nd6log((LOG_ERR, "%s: failed to make %s/%d "
-                                   "offlink, errno=%d\n", __func__,
-                                   inet_ntop(AF_INET6,
-                                       &pr->ndpr_prefix.sin6_addr,
-                                       addr, sizeof(addr)),
-                                   pr->ndpr_plen, e));
-                       }
-               }
-       }
-
-       /*
-        * Changes on the prefix status might affect address status as well.
-        * Make sure that all addresses derived from an attached prefix are
-        * attached, and that all addresses derived from a detached prefix are
-        * detached.  Note, however, that a manually configured address should
-        * always be attached.
-        * The precise detection logic is same as the one for prefixes.
-        */
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
-               TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
-                       if (ifa->ifa_addr->sa_family != AF_INET6)
-                               continue;
-
-                       ia6 = ifatoia6(ifa);
-                       if ((ia6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
-                               continue;
-
-                       /*
-                        * This can happen when we first configure the address
-                        * (i.e. the address exists, but the prefix does not).
-                        * XXX: complicated relationships...
-                        */
-                       if (ia6->ia6_ndpr == NULL)
-                               continue;
-
-                       if (find_pfxlist_reachable_router(ia6->ia6_ndpr)) {
-                               pia6 = ia6;
-                               break;
-                       }
-               }
-
-               if (pia6 != NULL)
-                       break;
-       }
-
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
-               TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
-                       if (ifa->ifa_addr->sa_family != AF_INET6)
-                               continue;
-
-                       ia6 = ifatoia6(ifa);
-                       if ((ia6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
-                               continue;
-
-                       if (pia6 != NULL) {
-                               /* XXX: see above. */
-                               if (ia6->ia6_ndpr == NULL)
-                                       continue;
-
-                               if 
(find_pfxlist_reachable_router(ia6->ia6_ndpr))
-                                       ia6->ia6_flags &= ~IN6_IFF_DETACHED;
-                               else
-                                       ia6->ia6_flags |= IN6_IFF_DETACHED;
-                       } else {
-                               ia6->ia6_flags &= ~IN6_IFF_DETACHED;
-                       }
-               }
-       }
-}
-
-int
-nd6_prefix_onlink(struct nd_prefix *pr)
-{
-       struct ifnet *ifp = pr->ndpr_ifp;
-       struct ifaddr *ifa;
-       struct nd_prefix *opr;
-       char addr[INET6_ADDRSTRLEN];
-       int error, rtflags = 0;
-
-       /* sanity check */
-       if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0)
-               return (EEXIST);
-
-       /*
-        * Add the interface route associated with the prefix.  Before
-        * installing the route, check if there's the same prefix on another
-        * interface, and the prefix has already installed the interface route.
-        * Although such a configuration is expected to be rare, we explicitly
-        * allow it.
-        */
-       LIST_FOREACH(opr, &nd_prefix, ndpr_entry) {
-               if (opr == pr)
-                       continue;
-
-               if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
-                       continue;
-
-               if (opr->ndpr_plen == pr->ndpr_plen &&
-                   in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
-                   &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
-                       return (0);
-       }
-
-       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
-               if (ifa->ifa_addr->sa_family != AF_INET6)
-                       continue;
-               if (ifatoia6(ifa)->ia6_ndpr == pr)
-                       break;
-       }
-       if (ifa == NULL) {
-               /*
-                * This can still happen, when, for example, we receive an RA
-                * containing a prefix with the L bit set and the A bit clear,
-                * after removing all IPv6 addresses on the receiving
-                * interface.  This should, of course, be rare though.
-                */
-               nd6log((LOG_NOTICE,
-                   "nd6_prefix_onlink: failed to find any ifaddr"
-                   " to add route for a prefix(%s/%d) on %s\n",
-                   inet_ntop(AF_INET6, &pr->ndpr_prefix.sin6_addr,
-                       addr, sizeof(addr)),
-                   pr->ndpr_plen, ifp->if_xname));
-               return (0);
-       }
-
-       if (nd6_need_cache(ifp))
-               rtflags = RTF_CLONING | RTF_CONNECTED;
-
-       error = rt_ifa_add(ifa, rtflags, sin6tosa(&pr->ndpr_prefix));
-       if (error == 0)
-               pr->ndpr_stateflags |= NDPRF_ONLINK;
-
-       return (error);
-}
-
-int
-nd6_prefix_offlink(struct nd_prefix *pr)
-{
-       struct ifnet *ifp = pr->ndpr_ifp;
-       struct ifaddr *ifa;
-       struct nd_prefix *opr;
-       char addr[INET6_ADDRSTRLEN];
-       int error, rtflags = 0;
-
-       /* sanity check */
-       if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
-               nd6log((LOG_ERR,
-                   "nd6_prefix_offlink: %s/%d is already off-link\n",
-                   inet_ntop(AF_INET6, &pr->ndpr_prefix.sin6_addr,
-                       addr, sizeof(addr)),
-                   pr->ndpr_plen));
-               return (EEXIST);
-       }
-
-       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
-               if (ifa->ifa_addr->sa_family != AF_INET6)
-                       continue;
-               if (ifatoia6(ifa)->ia6_ndpr == pr)
-                       break;
-       }
-       if (ifa == NULL)
-               return (EINVAL);
-
-       if (nd6_need_cache(ifp))
-               rtflags = RTF_CLONING | RTF_CONNECTED;
-
-       error = rt_ifa_del(ifa, rtflags, sin6tosa(&pr->ndpr_prefix));
-       if (error == 0) {
-               pr->ndpr_stateflags &= ~NDPRF_ONLINK;
-
-               /*
-                * There might be the same prefix on another interface,
-                * the prefix which could not be on-link just because we have
-                * the interface route (see comments in nd6_prefix_onlink).
-                * If there's one, try to make the prefix on-link on the
-                * interface.
-                */
-               LIST_FOREACH(opr, &nd_prefix, ndpr_entry) {
-                       if (opr == pr)
-                               continue;
-
-                       if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
-                               continue;
-
-                       /*
-                        * KAME specific: detached prefixes should not be
-                        * on-link.
-                        */
-                       if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
-                               continue;
-
-                       if (opr->ndpr_plen == pr->ndpr_plen &&
-                           in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
-                           &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
-                               int e;
-
-                               if ((e = nd6_prefix_onlink(opr)) != 0) {
-                                       nd6log((LOG_ERR,
-                                           "nd6_prefix_offlink: failed to "
-                                           "recover a prefix %s/%d from %s "
-                                           "to %s (errno = %d)\n",
-                                           inet_ntop(AF_INET6,
-                                               &pr->ndpr_prefix.sin6_addr,
-                                               addr, sizeof(addr)),
-                                           opr->ndpr_plen, ifp->if_xname,
-                                           opr->ndpr_ifp->if_xname, e));
-                               }
-                       }
-               }
-       }
-
-       return (error);
-}
-
-struct in6_ifaddr *
-in6_ifadd(struct nd_prefix *pr, int privacy)
-{
-       struct ifnet *ifp = pr->ndpr_ifp;
-       struct ifaddr *ifa;
-       struct in6_aliasreq ifra;
-       struct in6_ifaddr *ia6;
-       int error, plen0;
-       struct in6_addr mask, rand_ifid;
-       int prefixlen = pr->ndpr_plen;
-
-       NET_ASSERT_LOCKED();
-
-       in6_prefixlen2mask(&mask, prefixlen);
-
-       /*
-        * find a link-local address (will be interface ID).
-        * Is it really mandatory? Theoretically, a global or a site-local
-        * address can be configured without a link-local address, if we
-        * have a unique interface identifier...
-        *
-        * it is not mandatory to have a link-local address, we can generate
-        * interface identifier on the fly.  we do this because:
-        * (1) it should be the easiest way to find interface identifier.
-        * (2) RFC2462 5.4 suggesting the use of the same interface identifier
-        * for multiple addresses on a single interface, and possible shortcut
-        * of DAD.  we omitted DAD for this reason in the past.
-        * (3) a user can prevent autoconfiguration of global address
-        * by removing link-local address by hand (this is partly because we
-        * don't have other way to control the use of IPv6 on a interface.
-        * this has been our design choice - cf. NRL's "ifconfig auto").
-        * (4) it is easier to manage when an interface has addresses
-        * with the same interface identifier, than to have multiple addresses
-        * with different interface identifiers.
-        */
-       ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa; /* 0 is OK? */
-       if (ifa)
-               ia6 = ifatoia6(ifa);
-       else
-               return NULL;
-
-       /* prefixlen + ifidlen must be equal to 128 */
-       plen0 = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
-       if (prefixlen != plen0) {
-               nd6log((LOG_INFO, "%s: wrong prefixlen for %s "
-                   "(prefix=%d ifid=%d)\n", __func__,
-                   ifp->if_xname, prefixlen, 128 - plen0));
-               return NULL;
-       }
-
-       /* make ifaddr */
-       bzero(&ifra, sizeof(ifra));
-       strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
-       ifra.ifra_addr.sin6_family = AF_INET6;
-       ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
-       /* prefix */
-       bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr,
-           sizeof(ifra.ifra_addr.sin6_addr));
-       ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
-       ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
-       ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
-       ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
-
-       /* interface ID */
-       if (privacy) {
-               ifra.ifra_flags |= IN6_IFF_PRIVACY;
-               bcopy(&pr->ndpr_prefix.sin6_addr, &rand_ifid,
-                   sizeof(rand_ifid));
-               in6_get_rand_ifid(ifp, &rand_ifid);
-               ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
-                   (rand_ifid.s6_addr32[0] & ~mask.s6_addr32[0]);
-               ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
-                   (rand_ifid.s6_addr32[1] & ~mask.s6_addr32[1]);
-               ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
-                   (rand_ifid.s6_addr32[2] & ~mask.s6_addr32[2]);
-               ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
-                   (rand_ifid.s6_addr32[3] & ~mask.s6_addr32[3]);
-       } else {
-               ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
-                   (ia6->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
-               ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
-                   (ia6->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
-               ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
-                   (ia6->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
-               ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
-                   (ia6->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
-       }
-
-       /* new prefix mask. */
-       ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
-       ifra.ifra_prefixmask.sin6_family = AF_INET6;
-       bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
-           sizeof(ifra.ifra_prefixmask.sin6_addr));
-
-       /*
-        * lifetime.
-        * XXX: in6_init_address_ltimes would override these values later.
-        * We should reconsider this logic.
-        */
-       ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
-       ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
-
-       if (privacy) {
-           if (ifra.ifra_lifetime.ia6t_vltime > ND6_PRIV_VALID_LIFETIME)
-               ifra.ifra_lifetime.ia6t_vltime = ND6_PRIV_VALID_LIFETIME;
-           if (ifra.ifra_lifetime.ia6t_pltime > ND6_PRIV_PREFERRED_LIFETIME)
-               ifra.ifra_lifetime.ia6t_pltime = ND6_PRIV_PREFERRED_LIFETIME
-                       - arc4random_uniform(ND6_PRIV_MAX_DESYNC_FACTOR);
-       }
-
-       /* XXX: scope zone ID? */
-
-       ifra.ifra_flags |= IN6_IFF_AUTOCONF|IN6_IFF_TENTATIVE;
-
-       /* If this address already exists, update it. */
-       ia6 = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
-
-       error = in6_update_ifa(ifp, &ifra, ia6);
-
-       if (error != 0) {
-               char addr[INET6_ADDRSTRLEN];
-
-               nd6log((LOG_ERR,
-                   "%s: failed to make ifaddr %s on %s (errno=%d)\n", __func__,
-                   inet_ntop(AF_INET6, &ifra.ifra_addr.sin6_addr,
-                       addr, sizeof(addr)),
-                   ifp->if_xname, error));
-               return (NULL);  /* ifaddr must not have been allocated. */
-       }
-
-       ia6 = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
-
-       /* Perform DAD, if needed. */
-       if (ia6 != NULL && ia6->ia6_flags & IN6_IFF_TENTATIVE)
-               nd6_dad_start(&ia6->ia_ifa);
-
-       return (ia6);
-}
-
-int
-in6_init_prefix_ltimes(struct nd_prefix *ndpr)
-{
-
-       /* check if preferred lifetime > valid lifetime.  RFC2462 5.5.3 (c) */
-       if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
-               nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
-                   "(%d) is greater than valid lifetime(%d)\n",
-                   (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime));
-               return (EINVAL);
-       }
-       if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
-               ndpr->ndpr_preferred = 0;
-       else
-               ndpr->ndpr_preferred = time_uptime + ndpr->ndpr_pltime;
-       if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
-               ndpr->ndpr_expire = 0;
-       else
-               ndpr->ndpr_expire = time_uptime + ndpr->ndpr_vltime;
-
-       return 0;
-}
-
-void
-in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
-{
-
-       /* Valid lifetime must not be updated unless explicitly specified. */
-       /* init ia6t_expire */
-       if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
-               lt6->ia6t_expire = 0;
-       else {
-               lt6->ia6t_expire = time_uptime;
-               lt6->ia6t_expire += lt6->ia6t_vltime;
-       }
-
-       /* init ia6t_preferred */
-       if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
-               lt6->ia6t_preferred = 0;
-       else {
-               lt6->ia6t_preferred = time_uptime;
-               lt6->ia6t_preferred += lt6->ia6t_pltime;
-       }
-}
-
-/*
  * Delete all the routing table entries that use the specified gateway.
  * XXX: this function causes search through all entries of routing table, so
  * it shouldn't be called when acting as a router.


-- 
I'm not entirely sure you are real.

Reply via email to