From owner-svn-src-all@freebsd.org Tue Nov 19 20:34:33 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 7F2671BD332; Tue, 19 Nov 2019 20:34:33 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 47Hcxj3X2cz3PYw; Tue, 19 Nov 2019 20:34:33 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 5C3E8FFC3; Tue, 19 Nov 2019 20:34:33 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id xAJKYXwc072451; Tue, 19 Nov 2019 20:34:33 GMT (envelope-from bz@FreeBSD.org) Received: (from bz@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id xAJKYXFB072450; Tue, 19 Nov 2019 20:34:33 GMT (envelope-from bz@FreeBSD.org) Message-Id: <201911192034.xAJKYXFB072450@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bz set sender to bz@FreeBSD.org using -f From: "Bjoern A. Zeeb" Date: Tue, 19 Nov 2019 20:34:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354861 - head/sys/netinet6 X-SVN-Group: head X-SVN-Commit-Author: bz X-SVN-Commit-Paths: head/sys/netinet6 X-SVN-Commit-Revision: 354861 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Nov 2019 20:34:33 -0000 Author: bz Date: Tue Nov 19 20:34:33 2019 New Revision: 354861 URL: https://svnweb.freebsd.org/changeset/base/354861 Log: nd6_rtr: re-sort functions Resort functions within file in a way that they depend on each other as that makes it easier to rework various things. Also allows us to remove file local function declarations. No functional changes. MFC after: 3 weeks Sponsored by: Netflix Modified: head/sys/netinet6/nd6_rtr.c Modified: head/sys/netinet6/nd6_rtr.c ============================================================================== --- head/sys/netinet6/nd6_rtr.c Tue Nov 19 19:05:05 2019 (r354860) +++ head/sys/netinet6/nd6_rtr.c Tue Nov 19 20:34:33 2019 (r354861) @@ -73,25 +73,10 @@ __FBSDID("$FreeBSD$"); #include #include -static int rtpref(struct nd_defrouter *); static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *, struct mbuf *, int); -static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); -static struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *, - struct nd_defrouter *); -static void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); -static void pfxrtr_del(struct nd_pfxrouter *); -static struct nd_pfxrouter *find_pfxlist_reachable_router(struct nd_prefix *); -static void defrouter_delreq(struct nd_defrouter *); -static void nd6_rtmsg(int, struct rtentry *); -static int in6_init_prefix_ltimes(struct nd_prefix *); -static void in6_init_address_ltimes(struct nd_prefix *, - struct in6_addrlifetime *); - -static int rt6_deleteroute(const struct rtentry *, void *); - TAILQ_HEAD(nd6_drhead, nd_defrouter); VNET_DEFINE_STATIC(struct nd6_drhead, nd6_defrouter); #define V_nd6_defrouter VNET(nd6_defrouter) @@ -115,6 +100,8 @@ VNET_DEFINE(int, ip6_temp_regen_advance) = TEMPADDR_RE VNET_DEFINE(int, nd6_ignore_ipv6_only_ra) = 1; #endif +SYSCTL_DECL(_net_inet6_icmp6); + /* RTPREF_MEDIUM has to be 0! */ #define RTPREF_HIGH 1 #define RTPREF_MEDIUM 0 @@ -644,11 +631,72 @@ nd6_rtmsg(int cmd, struct rtentry *rt) ifa_free(ifa); } -/* - * default router list processing sub routines - */ +/* PFXRTR */ +static struct nd_pfxrouter * +pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) +{ + struct nd_pfxrouter *search; + ND6_LOCK_ASSERT(); + + LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { + if (search->router == dr) + break; + } + return (search); +} + static void +pfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) +{ + struct nd_pfxrouter *new; + bool update; + + ND6_UNLOCK_ASSERT(); + + ND6_RLOCK(); + if (pfxrtr_lookup(pr, dr) != NULL) { + ND6_RUNLOCK(); + return; + } + ND6_RUNLOCK(); + + new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO); + if (new == NULL) + return; + defrouter_ref(dr); + new->router = dr; + + ND6_WLOCK(); + if (pfxrtr_lookup(pr, dr) == NULL) { + LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); + update = true; + } else { + /* We lost a race to add the reference. */ + defrouter_rele(dr); + free(new, M_IP6NDP); + update = false; + } + ND6_WUNLOCK(); + + if (update) + pfxlist_onlink_check(); +} + +static void +pfxrtr_del(struct nd_pfxrouter *pfr) +{ + + ND6_WLOCK_ASSERT(); + + LIST_REMOVE(pfr, pfr_entry); + defrouter_rele(pfr->router); + free(pfr, M_IP6NDP); +} + + +/* Default router list processing sub routines. */ +static void defrouter_addreq(struct nd_defrouter *new) { struct sockaddr_in6 def, mask, gate; @@ -675,31 +723,6 @@ defrouter_addreq(struct nd_defrouter *new) new->installed = 1; } -struct nd_defrouter * -defrouter_lookup_locked(struct in6_addr *addr, struct ifnet *ifp) -{ - struct nd_defrouter *dr; - - ND6_LOCK_ASSERT(); - TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) - if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) { - defrouter_ref(dr); - return (dr); - } - return (NULL); -} - -struct nd_defrouter * -defrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) -{ - struct nd_defrouter *dr; - - ND6_RLOCK(); - dr = defrouter_lookup_locked(addr, ifp); - ND6_RUNLOCK(); - return (dr); -} - /* * Remove the default route for a given router. * This is just a subroutine function for defrouter_select_fib(), and @@ -731,49 +754,6 @@ defrouter_delreq(struct nd_defrouter *dr) dr->installed = 0; } -/* - * Remove all default routes from default router list. - */ -void -defrouter_reset(void) -{ - struct nd_defrouter *dr, **dra; - int count, i; - - count = i = 0; - - /* - * We can't delete routes with the ND lock held, so make a copy of the - * current default router list and use that when deleting routes. - */ - ND6_RLOCK(); - TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) - count++; - ND6_RUNLOCK(); - - dra = malloc(count * sizeof(*dra), M_TEMP, M_WAITOK | M_ZERO); - - ND6_RLOCK(); - TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) { - if (i == count) - break; - defrouter_ref(dr); - dra[i++] = dr; - } - ND6_RUNLOCK(); - - for (i = 0; i < count && dra[i] != NULL; i++) { - defrouter_delreq(dra[i]); - defrouter_rele(dra[i]); - } - free(dra, M_TEMP); - - /* - * XXX should we also nuke any default routers in the kernel, by - * going through them by rtalloc1()? - */ -} - static void defrouter_del(struct nd_defrouter *dr) { @@ -826,7 +806,75 @@ defrouter_del(struct nd_defrouter *dr) } +struct nd_defrouter * +defrouter_lookup_locked(struct in6_addr *addr, struct ifnet *ifp) +{ + struct nd_defrouter *dr; + + ND6_LOCK_ASSERT(); + TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) + if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) { + defrouter_ref(dr); + return (dr); + } + return (NULL); +} + +struct nd_defrouter * +defrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) +{ + struct nd_defrouter *dr; + + ND6_RLOCK(); + dr = defrouter_lookup_locked(addr, ifp); + ND6_RUNLOCK(); + return (dr); +} + /* + * Remove all default routes from default router list. + */ +void +defrouter_reset(void) +{ + struct nd_defrouter *dr, **dra; + int count, i; + + count = i = 0; + + /* + * We can't delete routes with the ND lock held, so make a copy of the + * current default router list and use that when deleting routes. + */ + ND6_RLOCK(); + TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) + count++; + ND6_RUNLOCK(); + + dra = malloc(count * sizeof(*dra), M_TEMP, M_WAITOK | M_ZERO); + + ND6_RLOCK(); + TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) { + if (i == count) + break; + defrouter_ref(dr); + dra[i++] = dr; + } + ND6_RUNLOCK(); + + for (i = 0; i < count && dra[i] != NULL; i++) { + defrouter_delreq(dra[i]); + defrouter_rele(dra[i]); + } + free(dra, M_TEMP); + + /* + * XXX should we also nuke any default routers in the kernel, by + * going through them by rtalloc1()? + */ +} + +/* * Look up a matching default router list entry and remove it. Returns true if a * matching entry was found, false otherwise. */ @@ -850,6 +898,33 @@ defrouter_remove(struct in6_addr *addr, struct ifnet * } /* + * for default router selection + * regards router-preference field as a 2-bit signed integer + */ +static int +rtpref(struct nd_defrouter *dr) +{ + switch (dr->raflags & 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\n", dr->raflags); + return (RTPREF_INVALID); + } + /* NOTREACHED */ +} + +/* * 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. @@ -987,33 +1062,6 @@ defrouter_select_fib(int fibnum) defrouter_rele(selected_dr); } -/* - * for default router selection - * regards router-preference field as a 2-bit signed integer - */ -static int -rtpref(struct nd_defrouter *dr) -{ - switch (dr->raflags & 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\n", dr->raflags); - return (RTPREF_INVALID); - } - /* NOTREACHED */ -} - static struct nd_defrouter * defrtrlist_update(struct nd_defrouter *new) { @@ -1112,66 +1160,154 @@ restart: return (n); } -static struct nd_pfxrouter * -pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) +static int +in6_init_prefix_ltimes(struct nd_prefix *ndpr) { - struct nd_pfxrouter *search; + 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; - ND6_LOCK_ASSERT(); + return 0; +} - LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { - if (search->router == dr) - break; +static void +in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) +{ + /* 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; } - return (search); + + /* 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; + } } -static void -pfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) +static struct in6_ifaddr * +in6_ifadd(struct nd_prefixctl *pr, int mcast) { - struct nd_pfxrouter *new; - bool update; + struct ifnet *ifp = pr->ndpr_ifp; + struct ifaddr *ifa; + struct in6_aliasreq ifra; + struct in6_ifaddr *ia, *ib; + int error, plen0; + struct in6_addr mask; + int prefixlen = pr->ndpr_plen; + int updateflags; + char ip6buf[INET6_ADDRSTRLEN]; - ND6_UNLOCK_ASSERT(); + in6_prefixlen2mask(&mask, prefixlen); - ND6_RLOCK(); - if (pfxrtr_lookup(pr, dr) != NULL) { - ND6_RUNLOCK(); - return; + /* + * 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 an 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 = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ + if (ifa) + ib = (struct in6_ifaddr *)ifa; + else + return NULL; + + /* prefixlen + ifidlen must be equal to 128 */ + plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); + if (prefixlen != plen0) { + ifa_free(ifa); + nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " + "(prefix=%d ifid=%d)\n", + if_name(ifp), prefixlen, 128 - plen0)); + return NULL; } - ND6_RUNLOCK(); - new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO); - if (new == NULL) - return; - defrouter_ref(dr); - new->router = dr; + /* make ifaddr */ + in6_prepare_ifra(&ifra, &pr->ndpr_prefix.sin6_addr, &mask); - ND6_WLOCK(); - if (pfxrtr_lookup(pr, dr) == NULL) { - LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); - update = true; - } else { - /* We lost a race to add the reference. */ - defrouter_rele(dr); - free(new, M_IP6NDP); - update = false; - } - ND6_WUNLOCK(); + IN6_MASK_ADDR(&ifra.ifra_addr.sin6_addr, &mask); + /* interface ID */ + ifra.ifra_addr.sin6_addr.s6_addr32[0] |= + (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); + ifra.ifra_addr.sin6_addr.s6_addr32[1] |= + (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); + ifra.ifra_addr.sin6_addr.s6_addr32[2] |= + (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); + ifra.ifra_addr.sin6_addr.s6_addr32[3] |= + (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); + ifa_free(ifa); - if (update) - pfxlist_onlink_check(); -} + /* lifetimes. */ + ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; + ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; -static void -pfxrtr_del(struct nd_pfxrouter *pfr) -{ + /* XXX: scope zone ID? */ - ND6_WLOCK_ASSERT(); + ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ - LIST_REMOVE(pfr, pfr_entry); - defrouter_rele(pfr->router); - free(pfr, M_IP6NDP); + /* + * Make sure that we do not have this address already. This should + * usually not happen, but we can still see this case, e.g., if we + * have manually configured the exact address to be configured. + */ + ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, + &ifra.ifra_addr.sin6_addr); + if (ifa != NULL) { + ifa_free(ifa); + /* this should be rare enough to make an explicit log */ + log(LOG_INFO, "in6_ifadd: %s is already configured\n", + ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); + return (NULL); + } + + /* + * Allocate ifaddr structure, link into chain, etc. + * If we are going to create a new address upon receiving a multicasted + * RA, we need to impose a random delay before starting DAD. + * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] + */ + updateflags = 0; + if (mcast) + updateflags |= IN6_IFAUPDATE_DADDELAY; + if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { + nd6log((LOG_ERR, + "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", + ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), + if_name(ifp), error)); + return (NULL); /* ifaddr must not have been allocated. */ + } + + ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); + /* + * XXXRW: Assumption of non-NULLness here might not be true with + * fine-grained locking -- should we validate it? Or just return + * earlier ifa rather than looking it up again? + */ + return (ia); /* this is always non-NULL and referenced. */ } static struct nd_prefix * @@ -2171,121 +2307,6 @@ restart: return (error); } -static struct in6_ifaddr * -in6_ifadd(struct nd_prefixctl *pr, int mcast) -{ - struct ifnet *ifp = pr->ndpr_ifp; - struct ifaddr *ifa; - struct in6_aliasreq ifra; - struct in6_ifaddr *ia, *ib; - int error, plen0; - struct in6_addr mask; - int prefixlen = pr->ndpr_plen; - int updateflags; - char ip6buf[INET6_ADDRSTRLEN]; - - 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 an 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 = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ - if (ifa) - ib = (struct in6_ifaddr *)ifa; - else - return NULL; - - /* prefixlen + ifidlen must be equal to 128 */ - plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); - if (prefixlen != plen0) { - ifa_free(ifa); - nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " - "(prefix=%d ifid=%d)\n", - if_name(ifp), prefixlen, 128 - plen0)); - return NULL; - } - - /* make ifaddr */ - in6_prepare_ifra(&ifra, &pr->ndpr_prefix.sin6_addr, &mask); - - IN6_MASK_ADDR(&ifra.ifra_addr.sin6_addr, &mask); - /* interface ID */ - ifra.ifra_addr.sin6_addr.s6_addr32[0] |= - (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); - ifra.ifra_addr.sin6_addr.s6_addr32[1] |= - (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); - ifra.ifra_addr.sin6_addr.s6_addr32[2] |= - (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); - ifra.ifra_addr.sin6_addr.s6_addr32[3] |= - (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); - ifa_free(ifa); - - /* lifetimes. */ - ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; - ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; - - /* XXX: scope zone ID? */ - - ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ - - /* - * Make sure that we do not have this address already. This should - * usually not happen, but we can still see this case, e.g., if we - * have manually configured the exact address to be configured. - */ - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, - &ifra.ifra_addr.sin6_addr); - if (ifa != NULL) { - ifa_free(ifa); - /* this should be rare enough to make an explicit log */ - log(LOG_INFO, "in6_ifadd: %s is already configured\n", - ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); - return (NULL); - } - - /* - * Allocate ifaddr structure, link into chain, etc. - * If we are going to create a new address upon receiving a multicasted - * RA, we need to impose a random delay before starting DAD. - * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] - */ - updateflags = 0; - if (mcast) - updateflags |= IN6_IFAUPDATE_DADDELAY; - if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { - nd6log((LOG_ERR, - "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", - ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), - if_name(ifp), error)); - return (NULL); /* ifaddr must not have been allocated. */ - } - - ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); - /* - * XXXRW: Assumption of non-NULLness here might not be true with - * fine-grained locking -- should we validate it? Or just return - * earlier ifa rather than looking it up again? - */ - return (ia); /* this is always non-NULL and referenced. */ -} - /* * ia0 - corresponding public address */ @@ -2411,58 +2432,6 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcege } static int -in6_init_prefix_ltimes(struct nd_prefix *ndpr) -{ - 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; -} - -static void -in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) -{ - /* 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. - */ -void -rt6_flush(struct in6_addr *gateway, struct ifnet *ifp) -{ - - /* We'll care only link-local addresses */ - if (!IN6_IS_ADDR_LINKLOCAL(gateway)) - return; - - /* XXX Do we really need to walk any but the default FIB? */ - rt_foreach_fib_walk_del(AF_INET6, rt6_deleteroute, (void *)gateway); -} - -static int rt6_deleteroute(const struct rtentry *rt, void *arg) { #define SIN6(s) ((struct sockaddr_in6 *)s) @@ -2494,6 +2463,23 @@ rt6_deleteroute(const struct rtentry *rt, void *arg) #undef SIN6 } +/* + * 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. + */ +void +rt6_flush(struct in6_addr *gateway, struct ifnet *ifp) +{ + + /* We'll care only link-local addresses */ + if (!IN6_IS_ADDR_LINKLOCAL(gateway)) + return; + + /* XXX Do we really need to walk any but the default FIB? */ + rt_foreach_fib_walk_del(AF_INET6, rt6_deleteroute, (void *)gateway); +} + int nd6_setdefaultiface(int ifindex) { @@ -2522,47 +2508,6 @@ nd6_setdefaultiface(int ifindex) return (error); } -static int -nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS) -{ - struct in6_defrouter d; - struct nd_defrouter *dr; - int error; - - if (req->newptr != NULL) - return (EPERM); - - error = sysctl_wire_old_buffer(req, 0); - if (error != 0) - return (error); - - bzero(&d, sizeof(d)); - d.rtaddr.sin6_family = AF_INET6; - d.rtaddr.sin6_len = sizeof(d.rtaddr); - - ND6_RLOCK(); - TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) { - d.rtaddr.sin6_addr = dr->rtaddr; - error = sa6_recoverscope(&d.rtaddr); - if (error != 0) - break; - d.flags = dr->raflags; - d.rtlifetime = dr->rtlifetime; - d.expire = dr->expire + (time_second - time_uptime); - d.if_index = dr->ifp->if_index; - error = SYSCTL_OUT(req, &d, sizeof(d)); - if (error != 0) - break; - } - ND6_RUNLOCK(); - return (error); -} -SYSCTL_DECL(_net_inet6_icmp6); -SYSCTL_PROC(_net_inet6_icmp6, ICMPV6CTL_ND6_DRLIST, nd6_drlist, - CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, - NULL, 0, nd6_sysctl_drlist, "S,in6_defrouter", - "NDP default router list"); - bool nd6_defrouter_list_empty(void) { @@ -2650,3 +2595,43 @@ nd6_defrouter_init(void) TAILQ_INIT(&V_nd6_defrouter); } + +static int +nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS) +{ + struct in6_defrouter d; + struct nd_defrouter *dr; + int error; + + if (req->newptr != NULL) + return (EPERM); + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); + + bzero(&d, sizeof(d)); + d.rtaddr.sin6_family = AF_INET6; + d.rtaddr.sin6_len = sizeof(d.rtaddr); + + ND6_RLOCK(); + TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry) { + d.rtaddr.sin6_addr = dr->rtaddr; + error = sa6_recoverscope(&d.rtaddr); + if (error != 0) + break; + d.flags = dr->raflags; + d.rtlifetime = dr->rtlifetime; + d.expire = dr->expire + (time_second - time_uptime); + d.if_index = dr->ifp->if_index; + error = SYSCTL_OUT(req, &d, sizeof(d)); + if (error != 0) + break; + } + ND6_RUNLOCK(); + return (error); +} +SYSCTL_PROC(_net_inet6_icmp6, ICMPV6CTL_ND6_DRLIST, nd6_drlist, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, nd6_sysctl_drlist, "S,in6_defrouter", + "NDP default router list");