summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/nd6.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/nd6.c')
-rw-r--r--freebsd/sys/netinet6/nd6.c331
1 files changed, 165 insertions, 166 deletions
diff --git a/freebsd/sys/netinet6/nd6.c b/freebsd/sys/netinet6/nd6.c
index 999855ca..89b15e56 100644
--- a/freebsd/sys/netinet6/nd6.c
+++ b/freebsd/sys/netinet6/nd6.c
@@ -372,6 +372,14 @@ nd6_options(union nd_opts *ndopts)
ndopts->nd_opts_pi_end =
(struct nd_opt_prefix_info *)nd_opt;
break;
+ /* What about ND_OPT_ROUTE_INFO? RFC 4191 */
+ case ND_OPT_RDNSS: /* RFC 6106 */
+ case ND_OPT_DNSSL: /* RFC 6106 */
+ /*
+ * Silently ignore options we know and do not care about
+ * in the kernel.
+ */
+ break;
default:
/*
* Unknown options must be silently ignored,
@@ -564,26 +572,18 @@ nd6_timer(void *arg)
{
CURVNET_SET((struct vnet *) arg);
int s;
- struct nd_defrouter *dr;
- struct nd_prefix *pr;
+ struct nd_defrouter *dr, *ndr;
+ struct nd_prefix *pr, *npr;
struct in6_ifaddr *ia6, *nia6;
- struct in6_addrlifetime *lt6;
callout_reset(&V_nd6_timer_ch, V_nd6_prune * hz,
nd6_timer, curvnet);
/* expire default router list */
s = splnet();
- dr = TAILQ_FIRST(&V_nd_defrouter);
- while (dr) {
- if (dr->expire && dr->expire < time_second) {
- struct nd_defrouter *t;
- t = TAILQ_NEXT(dr, dr_entry);
+ TAILQ_FOREACH_SAFE(dr, &V_nd_defrouter, dr_entry, ndr) {
+ if (dr->expire && dr->expire < time_second)
defrtrlist_del(dr);
- dr = t;
- } else {
- dr = TAILQ_NEXT(dr, dr_entry);
- }
}
/*
@@ -597,7 +597,6 @@ nd6_timer(void *arg)
addrloop:
TAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) {
/* check address lifetime */
- lt6 = &ia6->ia6_lifetime;
if (IFA6_IS_INVALID(ia6)) {
int regen = 0;
@@ -660,8 +659,7 @@ nd6_timer(void *arg)
}
/* expire prefix list */
- pr = V_nd_prefix.lh_first;
- while (pr) {
+ LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) {
/*
* check prefix lifetime.
* since pltime is just for autoconf, pltime processing for
@@ -669,18 +667,13 @@ nd6_timer(void *arg)
*/
if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&
time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) {
- struct nd_prefix *t;
- t = pr->ndpr_next;
/*
* address expiration and prefix expiration are
* separate. NEVER perform in6_purgeaddr here.
*/
-
prelist_remove(pr);
- pr = t;
- } else
- pr = pr->ndpr_next;
+ }
}
splx(s);
CURVNET_RESTORE();
@@ -697,7 +690,7 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
struct in6_ifaddr *public_ifa6 = NULL;
ifp = ia6->ia_ifa.ifa_ifp;
- IF_ADDR_LOCK(ifp);
+ IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct in6_ifaddr *it6;
@@ -739,7 +732,7 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
if (public_ifa6 != NULL)
ifa_ref(&public_ifa6->ia_ifa);
}
- IF_ADDR_UNLOCK(ifp);
+ IF_ADDR_RUNLOCK(ifp);
if (public_ifa6 != NULL) {
int e;
@@ -773,8 +766,7 @@ nd6_purge(struct ifnet *ifp)
* in the routing table, in order to keep additional side effects as
* small as possible.
*/
- for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; dr = ndr) {
- ndr = TAILQ_NEXT(dr, dr_entry);
+ TAILQ_FOREACH_SAFE(dr, &V_nd_defrouter, dr_entry, ndr) {
if (dr->installed)
continue;
@@ -782,8 +774,7 @@ nd6_purge(struct ifnet *ifp)
defrtrlist_del(dr);
}
- for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; dr = ndr) {
- ndr = TAILQ_NEXT(dr, dr_entry);
+ TAILQ_FOREACH_SAFE(dr, &V_nd_defrouter, dr_entry, ndr) {
if (!dr->installed)
continue;
@@ -792,8 +783,7 @@ nd6_purge(struct ifnet *ifp)
}
/* Nuke prefix list entries toward ifp */
- for (pr = V_nd_prefix.lh_first; pr; pr = npr) {
- npr = pr->ndpr_next;
+ LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) {
if (pr->ndpr_ifp == ifp) {
/*
* Because if_detach() does *not* release prefixes
@@ -908,13 +898,16 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
* If the address matches one of our on-link prefixes, it should be a
* neighbor.
*/
- for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
+ LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
if (pr->ndpr_ifp != ifp)
continue;
if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) {
struct rtentry *rt;
- rt = rtalloc1((struct sockaddr *)&pr->ndpr_prefix, 0, 0);
+
+ /* Always use the default FIB here. */
+ rt = in6_rtalloc1((struct sockaddr *)&pr->ndpr_prefix,
+ 0, 0, RT_DEFAULT_FIB);
if (rt == NULL)
continue;
/*
@@ -959,7 +952,7 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
* XXX: we restrict the condition to hosts, because routers usually do
* not have the "default router list".
*/
- if (!V_ip6_forwarding && TAILQ_FIRST(&V_nd_defrouter) == NULL &&
+ if (!V_ip6_forwarding && TAILQ_EMPTY(&V_nd_defrouter) &&
V_nd6_defifindex == ifp->if_index) {
return (1);
}
@@ -986,12 +979,12 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
* Even if the address matches none of our addresses, it might be
* in the neighbor cache.
*/
- IF_AFDATA_LOCK(ifp);
+ IF_AFDATA_RLOCK(ifp);
if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) {
LLE_RUNLOCK(lle);
rc = 1;
}
- IF_AFDATA_UNLOCK(ifp);
+ IF_AFDATA_RUNLOCK(ifp);
return (rc);
}
@@ -1172,6 +1165,46 @@ done:
}
+/*
+ * Rejuvenate this function for routing operations related
+ * processing.
+ */
+void
+nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
+{
+ struct sockaddr_in6 *gateway = (struct sockaddr_in6 *)rt->rt_gateway;
+ struct nd_defrouter *dr;
+ struct ifnet *ifp = rt->rt_ifp;
+
+ RT_LOCK_ASSERT(rt);
+
+ switch (req) {
+ case RTM_ADD:
+ break;
+
+ case RTM_DELETE:
+ if (!ifp)
+ return;
+ /*
+ * Only indirect routes are interesting.
+ */
+ if ((rt->rt_flags & RTF_GATEWAY) == 0)
+ return;
+ /*
+ * check for default route
+ */
+ if (IN6_ARE_ADDR_EQUAL(&in6addr_any,
+ &SIN6(rt_key(rt))->sin6_addr)) {
+
+ dr = defrouter_lookup(&gateway->sin6_addr, ifp);
+ if (dr != NULL)
+ dr->installed = 0;
+ }
+ break;
+ }
+}
+
+
int
nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
{
@@ -1192,8 +1225,9 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
*/
bzero(drl, sizeof(*drl));
s = splnet();
- dr = TAILQ_FIRST(&V_nd_defrouter);
- while (dr && i < DRLSTSIZ) {
+ TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
+ if (i >= DRLSTSIZ)
+ break;
drl->defrouter[i].rtaddr = dr->rtaddr;
in6_clearscope(&drl->defrouter[i].rtaddr);
@@ -1202,7 +1236,6 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
drl->defrouter[i].expire = dr->expire;
drl->defrouter[i].if_index = dr->ifp->if_index;
i++;
- dr = TAILQ_NEXT(dr, dr_entry);
}
splx(s);
break;
@@ -1221,11 +1254,12 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
*/
bzero(oprl, sizeof(*oprl));
s = splnet();
- pr = V_nd_prefix.lh_first;
- while (pr && i < PRLSTSIZ) {
+ LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
struct nd_pfxrouter *pfr;
int j;
+ if (i >= PRLSTSIZ)
+ break;
oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr;
oprl->prefix[i].raflags = pr->ndpr_raf;
oprl->prefix[i].prefixlen = pr->ndpr_plen;
@@ -1250,9 +1284,8 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
oprl->prefix[i].expire = maxexpire;
}
- pfr = pr->ndpr_advrtrs.lh_first;
j = 0;
- while (pfr) {
+ LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
if (j < DRLSTSIZ) {
#define RTRADDR oprl->prefix[i].advrtr[j]
RTRADDR = pfr->router->rtaddr;
@@ -1260,13 +1293,11 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
#undef RTRADDR
}
j++;
- pfr = pfr->pfr_next;
}
oprl->prefix[i].advrtrs = j;
oprl->prefix[i].origin = PR_ORIG_RA;
i++;
- pr = pr->ndpr_next;
}
splx(s);
@@ -1330,11 +1361,9 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
struct nd_prefix *pr, *next;
s = splnet();
- for (pr = V_nd_prefix.lh_first; pr; pr = next) {
+ LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, next) {
struct in6_ifaddr *ia, *ia_next;
- next = pr->ndpr_next;
-
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
continue; /* XXX */
@@ -1360,8 +1389,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
s = splnet();
defrouter_reset();
- for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; dr = next) {
- next = TAILQ_NEXT(dr, dr_entry);
+ TAILQ_FOREACH_SAFE(dr, &V_nd_defrouter, dr_entry, next) {
defrtrlist_del(dr);
}
defrouter_select();
@@ -1376,9 +1404,9 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0)
return (error);
- IF_AFDATA_LOCK(ifp);
+ IF_AFDATA_RLOCK(ifp);
ln = nd6_lookup(&nb_addr, 0, ifp);
- IF_AFDATA_UNLOCK(ifp);
+ IF_AFDATA_RUNLOCK(ifp);
if (ln == NULL) {
error = EINVAL;
@@ -1683,8 +1711,7 @@ nd6_slowtimo(void *arg)
callout_reset(&V_nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
nd6_slowtimo, curvnet);
IFNET_RLOCK_NOSLEEP();
- for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
- ifp = TAILQ_NEXT(ifp, if_list)) {
+ TAILQ_FOREACH(ifp, &V_ifnet, if_list) {
nd6if = ND_IFINFO(ifp);
if (nd6if->basereachable && /* already initialized */
(nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) {
@@ -1919,14 +1946,15 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
if (*chain == NULL)
*chain = m;
else {
- struct mbuf *m = *chain;
+ struct mbuf *mb;
/*
* append mbuf to end of deferred chain
*/
- while (m->m_nextpkt != NULL)
- m = m->m_nextpkt;
- m->m_nextpkt = m;
+ mb = *chain;
+ while (mb->m_nextpkt != NULL)
+ mb = mb->m_nextpkt;
+ mb->m_nextpkt = m;
}
return (error);
}
@@ -2070,9 +2098,9 @@ nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
/*
* the entry should have been created in nd6_store_lladdr
*/
- IF_AFDATA_LOCK(ifp);
+ IF_AFDATA_RLOCK(ifp);
ln = lla_lookup(LLTABLE6(ifp), 0, dst);
- IF_AFDATA_UNLOCK(ifp);
+ IF_AFDATA_RUNLOCK(ifp);
if ((ln == NULL) || !(ln->la_flags & LLE_VALID)) {
if (ln != NULL)
LLE_RUNLOCK(ln);
@@ -2120,130 +2148,101 @@ SYSCTL_VNET_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MAXQLEN, nd6_maxqueuelen,
static int
nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS)
{
- int error;
- char buf[1024] __aligned(4);
- struct in6_defrouter *d, *de;
+ struct in6_defrouter d;
struct nd_defrouter *dr;
+ int error;
if (req->newptr)
- return EPERM;
- error = 0;
-
- for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
- dr = TAILQ_NEXT(dr, dr_entry)) {
- d = (struct in6_defrouter *)buf;
- de = (struct in6_defrouter *)(buf + sizeof(buf));
-
- if (d + 1 <= de) {
- bzero(d, sizeof(*d));
- d->rtaddr.sin6_family = AF_INET6;
- d->rtaddr.sin6_len = sizeof(d->rtaddr);
- d->rtaddr.sin6_addr = dr->rtaddr;
- error = sa6_recoverscope(&d->rtaddr);
- if (error != 0)
- return (error);
- d->flags = dr->flags;
- d->rtlifetime = dr->rtlifetime;
- d->expire = dr->expire;
- d->if_index = dr->ifp->if_index;
- } else
- panic("buffer too short");
-
- error = SYSCTL_OUT(req, buf, sizeof(*d));
- if (error)
- break;
- }
+ return (EPERM);
- return (error);
+ bzero(&d, sizeof(d));
+ d.rtaddr.sin6_family = AF_INET6;
+ d.rtaddr.sin6_len = sizeof(d.rtaddr);
+
+ /*
+ * XXX locking
+ */
+ TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
+ d.rtaddr.sin6_addr = dr->rtaddr;
+ error = sa6_recoverscope(&d.rtaddr);
+ if (error != 0)
+ return (error);
+ d.flags = dr->flags;
+ d.rtlifetime = dr->rtlifetime;
+ d.expire = dr->expire;
+ d.if_index = dr->ifp->if_index;
+ error = SYSCTL_OUT(req, &d, sizeof(d));
+ if (error != 0)
+ return (error);
+ }
+ return (0);
}
static int
nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS)
{
- int error;
- char buf[1024] __aligned(4);
- struct in6_prefix *p, *pe;
+ struct in6_prefix p;
+ struct sockaddr_in6 s6;
struct nd_prefix *pr;
+ struct nd_pfxrouter *pfr;
+ time_t maxexpire;
+ int error;
char ip6buf[INET6_ADDRSTRLEN];
if (req->newptr)
- return EPERM;
- error = 0;
-
- for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
- u_short advrtrs;
- size_t advance;
- struct sockaddr_in6 *sin6, *s6;
- struct nd_pfxrouter *pfr;
+ return (EPERM);
- p = (struct in6_prefix *)buf;
- pe = (struct in6_prefix *)(buf + sizeof(buf));
+ bzero(&p, sizeof(p));
+ p.origin = PR_ORIG_RA;
+ bzero(&s6, sizeof(s6));
+ s6.sin6_family = AF_INET6;
+ s6.sin6_len = sizeof(s6);
- if (p + 1 <= pe) {
- bzero(p, sizeof(*p));
- sin6 = (struct sockaddr_in6 *)(p + 1);
-
- p->prefix = pr->ndpr_prefix;
- if (sa6_recoverscope(&p->prefix)) {
+ /*
+ * XXX locking
+ */
+ LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
+ p.prefix = pr->ndpr_prefix;
+ if (sa6_recoverscope(&p.prefix)) {
+ log(LOG_ERR, "scope error in prefix list (%s)\n",
+ ip6_sprintf(ip6buf, &p.prefix.sin6_addr));
+ /* XXX: press on... */
+ }
+ p.raflags = pr->ndpr_raf;
+ p.prefixlen = pr->ndpr_plen;
+ p.vltime = pr->ndpr_vltime;
+ p.pltime = pr->ndpr_pltime;
+ p.if_index = pr->ndpr_ifp->if_index;
+ if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
+ p.expire = 0;
+ else {
+ /* XXX: we assume time_t is signed. */
+ maxexpire = (-1) &
+ ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1));
+ if (pr->ndpr_vltime < maxexpire - pr->ndpr_lastupdate)
+ p.expire = pr->ndpr_lastupdate +
+ pr->ndpr_vltime;
+ else
+ p.expire = maxexpire;
+ }
+ p.refcnt = pr->ndpr_refcnt;
+ p.flags = pr->ndpr_stateflags;
+ p.advrtrs = 0;
+ LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry)
+ p.advrtrs++;
+ error = SYSCTL_OUT(req, &p, sizeof(p));
+ if (error != 0)
+ return (error);
+ LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) {
+ s6.sin6_addr = pfr->router->rtaddr;
+ if (sa6_recoverscope(&s6))
log(LOG_ERR,
"scope error in prefix list (%s)\n",
- ip6_sprintf(ip6buf, &p->prefix.sin6_addr));
- /* XXX: press on... */
- }
- p->raflags = pr->ndpr_raf;
- p->prefixlen = pr->ndpr_plen;
- p->vltime = pr->ndpr_vltime;
- p->pltime = pr->ndpr_pltime;
- p->if_index = pr->ndpr_ifp->if_index;
- if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
- p->expire = 0;
- else {
- time_t maxexpire;
-
- /* XXX: we assume time_t is signed. */
- maxexpire = (-1) &
- ~((time_t)1 <<
- ((sizeof(maxexpire) * 8) - 1));
- if (pr->ndpr_vltime <
- maxexpire - pr->ndpr_lastupdate) {
- p->expire = pr->ndpr_lastupdate +
- pr->ndpr_vltime;
- } else
- p->expire = maxexpire;
- }
- p->refcnt = pr->ndpr_refcnt;
- p->flags = pr->ndpr_stateflags;
- p->origin = PR_ORIG_RA;
- advrtrs = 0;
- for (pfr = pr->ndpr_advrtrs.lh_first; pfr;
- pfr = pfr->pfr_next) {
- if ((void *)&sin6[advrtrs + 1] > (void *)pe) {
- advrtrs++;
- continue;
- }
- s6 = &sin6[advrtrs];
- bzero(s6, sizeof(*s6));
- s6->sin6_family = AF_INET6;
- s6->sin6_len = sizeof(*sin6);
- s6->sin6_addr = pfr->router->rtaddr;
- if (sa6_recoverscope(s6)) {
- log(LOG_ERR,
- "scope error in "
- "prefix list (%s)\n",
- ip6_sprintf(ip6buf,
- &pfr->router->rtaddr));
- }
- advrtrs++;
- }
- p->advrtrs = advrtrs;
- } else
- panic("buffer too short");
-
- advance = sizeof(*p) + sizeof(*sin6) * advrtrs;
- error = SYSCTL_OUT(req, buf, advance);
- if (error)
- break;
+ ip6_sprintf(ip6buf, &pfr->router->rtaddr));
+ error = SYSCTL_OUT(req, &s6, sizeof(s6));
+ if (error != 0)
+ return (error);
+ }
}
-
- return (error);
+ return (0);
}