mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-10-14 07:59:07 +08:00
Update to FreeBSD head 2016-12-10
Git mirror commit 80c55f08a05ab3b26a73b226ccb56adc3122a55c.
This commit is contained in:
@@ -492,7 +492,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
break;
|
||||
case ICMP6_DST_UNREACH_ADMIN:
|
||||
icmp6_ifstat_inc(ifp, ifs6_in_adminprohib);
|
||||
code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
|
||||
code = PRC_UNREACH_ADMIN_PROHIB;
|
||||
break;
|
||||
case ICMP6_DST_UNREACH_BEYONDSCOPE:
|
||||
/* I mean "source address was incorrect." */
|
||||
@@ -556,7 +556,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
icmp6_ifstat_inc(ifp, ifs6_in_echo);
|
||||
if (code != 0)
|
||||
goto badcode;
|
||||
if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
/* Give up remote */
|
||||
break;
|
||||
}
|
||||
@@ -653,7 +653,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
|
||||
IPPROTO_DONE);
|
||||
#endif
|
||||
n = m_copy(m, 0, M_COPYALL);
|
||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
if (n)
|
||||
n = ni6_input(n, off);
|
||||
/* XXX meaningless if n == NULL */
|
||||
@@ -740,36 +740,19 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_router_solicit))
|
||||
goto badlen;
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
|
||||
/* Send incoming SeND packet to user space. */
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
IP6_EXTHDR_CHECK(m, off,
|
||||
icmp6len, IPPROTO_DONE);
|
||||
error = send_sendso_input_hook(m, ifp,
|
||||
SND_IN, ip6len);
|
||||
/* -1 == no app on SEND socket */
|
||||
if (error == 0)
|
||||
return (IPPROTO_DONE);
|
||||
nd6_rs_input(m, off, icmp6len);
|
||||
} else
|
||||
nd6_rs_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
IP6_EXTHDR_CHECK(n, off,
|
||||
icmp6len, IPPROTO_DONE);
|
||||
error = send_sendso_input_hook(n, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
|
||||
error = send_sendso_input_hook(m, ifp, SND_IN, ip6len);
|
||||
if (error == 0) {
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
/* -1 == no app on SEND socket */
|
||||
nd6_rs_input(n, off, icmp6len);
|
||||
} else
|
||||
nd6_rs_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
}
|
||||
}
|
||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
nd6_rs_input(m, off, icmp6len);
|
||||
m = n;
|
||||
if (m == NULL)
|
||||
goto freeit;
|
||||
break;
|
||||
|
||||
case ND_ROUTER_ADVERT:
|
||||
@@ -778,29 +761,18 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_router_advert))
|
||||
goto badlen;
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
|
||||
/* Send incoming SeND-protected/ND packet to user space. */
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(m, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
return (IPPROTO_DONE);
|
||||
nd6_ra_input(m, off, icmp6len);
|
||||
} else
|
||||
nd6_ra_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(n, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
error = send_sendso_input_hook(m, ifp, SND_IN, ip6len);
|
||||
if (error == 0) {
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
nd6_ra_input(n, off, icmp6len);
|
||||
} else
|
||||
nd6_ra_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
}
|
||||
}
|
||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
nd6_ra_input(m, off, icmp6len);
|
||||
m = n;
|
||||
if (m == NULL)
|
||||
goto freeit;
|
||||
break;
|
||||
|
||||
case ND_NEIGHBOR_SOLICIT:
|
||||
@@ -809,27 +781,18 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_neighbor_solicit))
|
||||
goto badlen;
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(m, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
return (IPPROTO_DONE);
|
||||
nd6_ns_input(m, off, icmp6len);
|
||||
} else
|
||||
nd6_ns_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(n, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
error = send_sendso_input_hook(m, ifp, SND_IN, ip6len);
|
||||
if (error == 0) {
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
nd6_ns_input(n, off, icmp6len);
|
||||
} else
|
||||
nd6_ns_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
}
|
||||
}
|
||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
nd6_ns_input(m, off, icmp6len);
|
||||
m = n;
|
||||
if (m == NULL)
|
||||
goto freeit;
|
||||
break;
|
||||
|
||||
case ND_NEIGHBOR_ADVERT:
|
||||
@@ -838,29 +801,18 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_neighbor_advert))
|
||||
goto badlen;
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
|
||||
/* Send incoming SeND-protected/ND packet to user space. */
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(m, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
return (IPPROTO_DONE);
|
||||
nd6_na_input(m, off, icmp6len);
|
||||
} else
|
||||
nd6_na_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(n, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
error = send_sendso_input_hook(m, ifp, SND_IN, ip6len);
|
||||
if (error == 0) {
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
nd6_na_input(n, off, icmp6len);
|
||||
} else
|
||||
nd6_na_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
}
|
||||
}
|
||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
nd6_na_input(m, off, icmp6len);
|
||||
m = n;
|
||||
if (m == NULL)
|
||||
goto freeit;
|
||||
break;
|
||||
|
||||
case ND_REDIRECT:
|
||||
@@ -869,27 +821,18 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_redirect))
|
||||
goto badlen;
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(m, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
return (IPPROTO_DONE);
|
||||
icmp6_redirect_input(m, off);
|
||||
} else
|
||||
icmp6_redirect_input(m, off);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
if (send_sendso_input_hook != NULL) {
|
||||
error = send_sendso_input_hook(n, ifp,
|
||||
SND_IN, ip6len);
|
||||
if (error == 0)
|
||||
error = send_sendso_input_hook(m, ifp, SND_IN, ip6len);
|
||||
if (error == 0) {
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
icmp6_redirect_input(n, off);
|
||||
} else
|
||||
icmp6_redirect_input(n, off);
|
||||
/* m stays. */
|
||||
}
|
||||
}
|
||||
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
icmp6_redirect_input(m, off);
|
||||
m = n;
|
||||
if (m == NULL)
|
||||
goto freeit;
|
||||
break;
|
||||
|
||||
case ICMP6_ROUTER_RENUMBERING:
|
||||
@@ -2053,7 +1996,7 @@ icmp6_rip6_input(struct mbuf **mp, int off)
|
||||
}
|
||||
}
|
||||
if (n != NULL ||
|
||||
(n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
|
||||
(n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) {
|
||||
if (last->inp_flags & INP_CONTROLOPTS)
|
||||
ip6_savecontrol(last, n, &opts);
|
||||
/* strip intermediate headers */
|
||||
@@ -2217,7 +2160,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
||||
* that we do not own. Select a source address based on the
|
||||
* source address of the erroneous packet.
|
||||
*/
|
||||
in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
|
||||
in6_splitscope(&ip6->ip6_src, &dst6, &scopeid);
|
||||
error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
|
||||
scopeid, NULL, &src6, &hlim);
|
||||
|
||||
|
@@ -634,7 +634,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
/* relate the address to the prefix */
|
||||
if (ia->ia6_ndpr == NULL) {
|
||||
ia->ia6_ndpr = pr;
|
||||
pr->ndpr_refcnt++;
|
||||
pr->ndpr_addrcnt++;
|
||||
|
||||
/*
|
||||
* If this is the first autoconf address from the
|
||||
@@ -642,7 +642,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
* (when required).
|
||||
*/
|
||||
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
|
||||
V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) {
|
||||
V_ip6_use_tempaddr && pr->ndpr_addrcnt == 1) {
|
||||
int e;
|
||||
if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
|
||||
log(LOG_NOTICE, "in6_control: failed "
|
||||
@@ -651,6 +651,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
}
|
||||
}
|
||||
}
|
||||
nd6_prefix_rele(pr);
|
||||
|
||||
/*
|
||||
* this might affect the status of autoconfigured addresses,
|
||||
@@ -694,12 +695,16 @@ aifaddr_out:
|
||||
* and the prefix management. We do this, however, to provide
|
||||
* as much backward compatibility as possible in terms of
|
||||
* the ioctl operation.
|
||||
* Note that in6_purgeaddr() will decrement ndpr_refcnt.
|
||||
* Note that in6_purgeaddr() will decrement ndpr_addrcnt.
|
||||
*/
|
||||
pr = ia->ia6_ndpr;
|
||||
in6_purgeaddr(&ia->ia_ifa);
|
||||
if (pr && pr->ndpr_refcnt == 0)
|
||||
prelist_remove(pr);
|
||||
if (pr != NULL && pr->ndpr_addrcnt == 0) {
|
||||
ND6_WLOCK();
|
||||
nd6_prefix_unlink(pr, NULL);
|
||||
ND6_WUNLOCK();
|
||||
nd6_prefix_del(pr);
|
||||
}
|
||||
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
|
||||
break;
|
||||
}
|
||||
@@ -1309,9 +1314,9 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
"in6_unlink_ifa: autoconf'ed address "
|
||||
"%s has no prefix\n", ip6_sprintf(ip6buf, IA6_IN6(ia))));
|
||||
} else {
|
||||
ia->ia6_ndpr->ndpr_refcnt--;
|
||||
ia->ia6_ndpr->ndpr_addrcnt--;
|
||||
/* Do not delete lles within prefix if refcont != 0 */
|
||||
if (ia->ia6_ndpr->ndpr_refcnt == 0)
|
||||
if (ia->ia6_ndpr->ndpr_addrcnt == 0)
|
||||
remove_lle = 1;
|
||||
ia->ia6_ndpr = NULL;
|
||||
}
|
||||
|
@@ -459,6 +459,7 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
|
||||
struct in6_ifaddr *ia;
|
||||
struct in6_aliasreq ifra;
|
||||
struct nd_prefixctl pr0;
|
||||
struct nd_prefix *pr;
|
||||
int error;
|
||||
|
||||
/*
|
||||
@@ -541,10 +542,11 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
|
||||
* address, and then reconfigure another one, the prefix is still
|
||||
* valid with referring to the old link-local address.
|
||||
*/
|
||||
if (nd6_prefix_lookup(&pr0) == NULL) {
|
||||
if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
|
||||
if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
|
||||
return (error);
|
||||
}
|
||||
} else
|
||||
nd6_prefix_rele(pr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -787,15 +789,6 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp)
|
||||
if (ifp->if_afdata[AF_INET6] == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Remove neighbor management table.
|
||||
* Enabling the nd6_purge will panic on vmove for interfaces on VNET
|
||||
* teardown as the IPv6 layer is cleaned up already and the locks
|
||||
* are destroyed.
|
||||
*/
|
||||
if (purgeulp)
|
||||
nd6_purge(ifp);
|
||||
|
||||
/*
|
||||
* nuke any of IPv6 addresses we have
|
||||
* XXX: all addresses should be already removed
|
||||
@@ -814,12 +807,10 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp)
|
||||
in6_purgemaddrs(ifp);
|
||||
|
||||
/*
|
||||
* remove neighbor management table. we call it twice just to make
|
||||
* sure we nuke everything. maybe we need just one call.
|
||||
* XXX: since the first call did not release addresses, some prefixes
|
||||
* might remain. We should call nd6_purge() again to release the
|
||||
* prefixes after removing all addresses above.
|
||||
* (Or can we just delay calling nd6_purge until at this point?)
|
||||
* Remove neighbor management table.
|
||||
* Enabling the nd6_purge will panic on vmove for interfaces on VNET
|
||||
* teardown as the IPv6 layer is cleaned up already and the locks
|
||||
* are destroyed.
|
||||
*/
|
||||
if (purgeulp)
|
||||
nd6_purge(ifp);
|
||||
|
@@ -168,7 +168,8 @@ ip6_forward(struct mbuf *m, int srcrt)
|
||||
* It is important to save it before IPsec processing as IPsec
|
||||
* processing may modify the mbuf.
|
||||
*/
|
||||
mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
|
||||
mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
|
||||
M_NOWAIT);
|
||||
|
||||
#ifdef IPSEC
|
||||
/* get a security policy for this packet */
|
||||
|
@@ -1774,6 +1774,6 @@ u_char inet6ctlerrmap[PRC_NCMDS] = {
|
||||
0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
|
||||
EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
|
||||
EMSGSIZE, EHOSTUNREACH, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
ENOPROTOOPT
|
||||
0, 0, EHOSTUNREACH, 0,
|
||||
ENOPROTOOPT, ECONNREFUSED
|
||||
};
|
||||
|
@@ -1147,7 +1147,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
|
||||
MFC6_UNLOCK();
|
||||
return (ENOBUFS);
|
||||
}
|
||||
mb0 = m_copy(m, 0, M_COPYALL);
|
||||
mb0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
/*
|
||||
* Pullup packet header if needed before storing it,
|
||||
* as other references may modify it in the meantime.
|
||||
@@ -1187,7 +1187,7 @@ X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
|
||||
* Make a copy of the header to send to the user
|
||||
* level process
|
||||
*/
|
||||
mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
|
||||
mm = m_copym(mb0, 0, sizeof(struct ip6_hdr), M_NOWAIT);
|
||||
if (mm == NULL) {
|
||||
free(rte, M_MRTABLE6);
|
||||
m_freem(mb0);
|
||||
@@ -1419,7 +1419,8 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
|
||||
struct omrt6msg *oim;
|
||||
#endif
|
||||
|
||||
mm = m_copy(m, 0, sizeof(struct ip6_hdr));
|
||||
mm = m_copym(m, 0, sizeof(struct ip6_hdr),
|
||||
M_NOWAIT);
|
||||
if (mm &&
|
||||
(!M_WRITABLE(mm) ||
|
||||
mm->m_len < sizeof(struct ip6_hdr)))
|
||||
@@ -1549,7 +1550,7 @@ phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
|
||||
* the IPv6 header is actually copied, not just referenced,
|
||||
* so that ip6_output() only scribbles on the copy.
|
||||
*/
|
||||
mb_copy = m_copy(m, 0, M_COPYALL);
|
||||
mb_copy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
if (mb_copy &&
|
||||
(!M_WRITABLE(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
|
||||
mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
|
||||
@@ -1653,7 +1654,7 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
|
||||
mm->m_data += max_linkhdr;
|
||||
mm->m_len = sizeof(struct ip6_hdr);
|
||||
|
||||
if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
|
||||
if ((mm->m_next = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
|
||||
m_freem(mm);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
@@ -1872,7 +1873,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
|
||||
/*
|
||||
* make a copy of the whole header to pass to the daemon later.
|
||||
*/
|
||||
mcp = m_copy(m, 0, off + PIM6_REG_MINLEN);
|
||||
mcp = m_copym(m, 0, off + PIM6_REG_MINLEN, M_NOWAIT);
|
||||
if (mcp == NULL) {
|
||||
MRT6_DLOG(DEBUG_ANY | DEBUG_ERR, "pim register: "
|
||||
"could not copy register head");
|
||||
|
@@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_llatbl.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
#include <net/pfil.h>
|
||||
@@ -260,7 +261,7 @@ ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto,
|
||||
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
|
||||
mhip6->ip6_plen = htons((u_short)(mtu + hlen +
|
||||
sizeof(*ip6f) - sizeof(struct ip6_hdr)));
|
||||
if ((m_frgpart = m_copy(m0, off, mtu)) == NULL) {
|
||||
if ((m_frgpart = m_copym(m0, off, mtu, M_NOWAIT)) == NULL) {
|
||||
IP6STAT_INC(ip6s_odropped);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
@@ -554,6 +555,9 @@ again:
|
||||
rt = ro->ro_rt;
|
||||
ifp = ro->ro_rt->rt_ifp;
|
||||
} else {
|
||||
if (ro->ro_lle)
|
||||
LLE_FREE(ro->ro_lle); /* zeros ro_lle */
|
||||
ro->ro_lle = NULL;
|
||||
if (fwd_tag == NULL) {
|
||||
bzero(&dst_sa, sizeof(dst_sa));
|
||||
dst_sa.sin6_family = AF_INET6;
|
||||
@@ -823,6 +827,9 @@ again:
|
||||
} else {
|
||||
RO_RTFREE(ro);
|
||||
needfiblookup = 1; /* Redo the routing table lookup. */
|
||||
if (ro->ro_lle)
|
||||
LLE_FREE(ro->ro_lle); /* zeros ro_lle */
|
||||
ro->ro_lle = NULL;
|
||||
}
|
||||
}
|
||||
/* See if fib was changed by packet filter. */
|
||||
@@ -831,6 +838,9 @@ again:
|
||||
fibnum = M_GETFIB(m);
|
||||
RO_RTFREE(ro);
|
||||
needfiblookup = 1;
|
||||
if (ro->ro_lle)
|
||||
LLE_FREE(ro->ro_lle); /* zeros ro_lle */
|
||||
ro->ro_lle = NULL;
|
||||
}
|
||||
if (needfiblookup)
|
||||
goto again;
|
||||
@@ -1056,12 +1066,7 @@ sendorfree:
|
||||
IP6STAT_INC(ip6s_fragmented);
|
||||
|
||||
done:
|
||||
/*
|
||||
* Release the route if using our private route, or if
|
||||
* (with flowtable) we don't have our own reference.
|
||||
*/
|
||||
if (ro == &ip6route ||
|
||||
(ro != NULL && ro->ro_flags & RT_NORTREF))
|
||||
if (ro == &ip6route)
|
||||
RO_RTFREE(ro);
|
||||
return (error);
|
||||
|
||||
@@ -1390,6 +1395,15 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't use more than a quarter of mbuf clusters. N.B.:
|
||||
* nmbclusters is an int, but nmbclusters * MCLBYTES may overflow
|
||||
* on LP64 architectures, so cast to u_long to avoid undefined
|
||||
* behavior. ILP32 architectures cannot have nmbclusters
|
||||
* large enough to overflow for other reasons.
|
||||
*/
|
||||
#define IPV6_PKTOPTIONS_MBUF_LIMIT ((u_long)nmbclusters * MCLBYTES / 4)
|
||||
|
||||
level = sopt->sopt_level;
|
||||
op = sopt->sopt_dir;
|
||||
optname = sopt->sopt_name;
|
||||
@@ -1445,6 +1459,12 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
{
|
||||
struct mbuf *m;
|
||||
|
||||
if (optlen > IPV6_PKTOPTIONS_MBUF_LIMIT) {
|
||||
printf("ip6_ctloutput: mbuf limit hit\n");
|
||||
error = ENOBUFS;
|
||||
break;
|
||||
}
|
||||
|
||||
error = soopt_getm(sopt, &m); /* XXX */
|
||||
if (error != 0)
|
||||
break;
|
||||
@@ -2995,7 +3015,7 @@ ip6_mloopback(struct ifnet *ifp, struct mbuf *m)
|
||||
struct mbuf *copym;
|
||||
struct ip6_hdr *ip6;
|
||||
|
||||
copym = m_copy(m, 0, M_COPYALL);
|
||||
copym = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
if (copym == NULL)
|
||||
return;
|
||||
|
||||
|
@@ -40,8 +40,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <rtems/bsd/sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/callout.h>
|
||||
#include <rtems/bsd/sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/time.h>
|
||||
@@ -49,7 +51,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/protosw.h>
|
||||
#include <rtems/bsd/sys/errno.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <rtems/bsd/sys/lock.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sdt.h>
|
||||
@@ -120,6 +121,8 @@ static eventhandler_tag lle_event_eh, iflladdr_event_eh;
|
||||
VNET_DEFINE(struct nd_drhead, nd_defrouter);
|
||||
VNET_DEFINE(struct nd_prhead, nd_prefix);
|
||||
VNET_DEFINE(struct rwlock, nd6_lock);
|
||||
VNET_DEFINE(uint64_t, nd6_list_genid);
|
||||
VNET_DEFINE(struct mtx, nd6_onlink_mtx);
|
||||
|
||||
VNET_DEFINE(int, nd6_recalc_reachtm_interval) = ND6_RECALC_REACHTM_INTERVAL;
|
||||
#define V_nd6_recalc_reachtm_interval VNET(nd6_recalc_reachtm_interval)
|
||||
@@ -211,11 +214,10 @@ void
|
||||
nd6_init(void)
|
||||
{
|
||||
|
||||
rw_init(&V_nd6_lock, "nd6");
|
||||
mtx_init(&V_nd6_onlink_mtx, "nd6 onlink", NULL, MTX_DEF);
|
||||
rw_init(&V_nd6_lock, "nd6 list");
|
||||
|
||||
LIST_INIT(&V_nd_prefix);
|
||||
|
||||
/* initialization of the default router list */
|
||||
TAILQ_INIT(&V_nd_defrouter);
|
||||
|
||||
/* Start timers. */
|
||||
@@ -247,6 +249,7 @@ nd6_destroy()
|
||||
EVENTHANDLER_DEREGISTER(iflladdr_event, iflladdr_event_eh);
|
||||
}
|
||||
rw_destroy(&V_nd6_lock);
|
||||
mtx_destroy(&V_nd6_onlink_mtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -905,13 +908,15 @@ nd6_timer(void *arg)
|
||||
{
|
||||
CURVNET_SET((struct vnet *) arg);
|
||||
struct nd_drhead drq;
|
||||
struct nd_prhead prl;
|
||||
struct nd_defrouter *dr, *ndr;
|
||||
struct nd_prefix *pr, *npr;
|
||||
struct in6_ifaddr *ia6, *nia6;
|
||||
bool onlink_locked;
|
||||
|
||||
TAILQ_INIT(&drq);
|
||||
LIST_INIT(&prl);
|
||||
|
||||
/* expire default router list */
|
||||
ND6_WLOCK();
|
||||
TAILQ_FOREACH_SAFE(dr, &V_nd_defrouter, dr_entry, ndr)
|
||||
if (dr->expire && dr->expire < time_uptime)
|
||||
@@ -1018,22 +1023,50 @@ nd6_timer(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* expire prefix list */
|
||||
ND6_WLOCK();
|
||||
onlink_locked = false;
|
||||
restart:
|
||||
LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) {
|
||||
/*
|
||||
* check prefix lifetime.
|
||||
* since pltime is just for autoconf, pltime processing for
|
||||
* prefix is not necessary.
|
||||
* Expire prefixes. Since the pltime is only used for
|
||||
* autoconfigured addresses, pltime processing for prefixes is
|
||||
* not necessary.
|
||||
*
|
||||
* Only unlink after all derived addresses have expired. This
|
||||
* may not occur until two hours after the prefix has expired
|
||||
* per RFC 4862. If the prefix expires before its derived
|
||||
* addresses, mark it off-link. This will be done automatically
|
||||
* after unlinking if no address references remain.
|
||||
*/
|
||||
if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&
|
||||
time_uptime - pr->ndpr_lastupdate > pr->ndpr_vltime) {
|
||||
if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME ||
|
||||
time_uptime - pr->ndpr_lastupdate <= pr->ndpr_vltime)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* address expiration and prefix expiration are
|
||||
* separate. NEVER perform in6_purgeaddr here.
|
||||
*/
|
||||
prelist_remove(pr);
|
||||
if (pr->ndpr_addrcnt == 0) {
|
||||
nd6_prefix_unlink(pr, &prl);
|
||||
continue;
|
||||
}
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
||||
if (!onlink_locked) {
|
||||
onlink_locked = ND6_ONLINK_TRYLOCK();
|
||||
if (!onlink_locked) {
|
||||
ND6_WUNLOCK();
|
||||
ND6_ONLINK_LOCK();
|
||||
onlink_locked = true;
|
||||
ND6_WLOCK();
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
(void)nd6_prefix_offlink(pr);
|
||||
}
|
||||
}
|
||||
ND6_WUNLOCK();
|
||||
if (onlink_locked)
|
||||
ND6_ONLINK_UNLOCK();
|
||||
|
||||
while ((pr = LIST_FIRST(&prl)) != NULL) {
|
||||
LIST_REMOVE(pr, ndpr_entry);
|
||||
nd6_prefix_del(pr);
|
||||
}
|
||||
|
||||
callout_reset(&V_nd6_timer_ch, V_nd6_prune * hz,
|
||||
@@ -1120,10 +1153,12 @@ void
|
||||
nd6_purge(struct ifnet *ifp)
|
||||
{
|
||||
struct nd_drhead drq;
|
||||
struct nd_prhead prl;
|
||||
struct nd_defrouter *dr, *ndr;
|
||||
struct nd_prefix *pr, *npr;
|
||||
|
||||
TAILQ_INIT(&drq);
|
||||
LIST_INIT(&prl);
|
||||
|
||||
/*
|
||||
* Nuke default router list entries toward ifp.
|
||||
@@ -1138,33 +1173,31 @@ nd6_purge(struct ifnet *ifp)
|
||||
if (dr->ifp == ifp)
|
||||
defrouter_unlink(dr, &drq);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(dr, &V_nd_defrouter, dr_entry, ndr) {
|
||||
if (!dr->installed)
|
||||
continue;
|
||||
if (dr->ifp == ifp)
|
||||
defrouter_unlink(dr, &drq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove prefixes on ifp. We should have already removed addresses on
|
||||
* this interface, so no addresses should be referencing these prefixes.
|
||||
*/
|
||||
LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) {
|
||||
if (pr->ndpr_ifp == ifp)
|
||||
nd6_prefix_unlink(pr, &prl);
|
||||
}
|
||||
ND6_WUNLOCK();
|
||||
|
||||
/* Delete the unlinked router and prefix objects. */
|
||||
while ((dr = TAILQ_FIRST(&drq)) != NULL) {
|
||||
TAILQ_REMOVE(&drq, dr, dr_entry);
|
||||
defrouter_del(dr);
|
||||
}
|
||||
|
||||
/* Nuke prefix list entries toward ifp */
|
||||
LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) {
|
||||
if (pr->ndpr_ifp == ifp) {
|
||||
/*
|
||||
* Because if_detach() does *not* release prefixes
|
||||
* while purging addresses the reference count will
|
||||
* still be above zero. We therefore reset it to
|
||||
* make sure that the prefix really gets purged.
|
||||
*/
|
||||
pr->ndpr_refcnt = 0;
|
||||
|
||||
prelist_remove(pr);
|
||||
}
|
||||
while ((pr = LIST_FIRST(&prl)) != NULL) {
|
||||
LIST_REMOVE(pr, ndpr_entry);
|
||||
nd6_prefix_del(pr);
|
||||
}
|
||||
|
||||
/* cancel default outgoing interface setting */
|
||||
@@ -1229,8 +1262,9 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
|
||||
struct ifaddr *dstaddr;
|
||||
struct rt_addrinfo info;
|
||||
struct sockaddr_in6 rt_key;
|
||||
struct sockaddr *dst6;
|
||||
int fibnum;
|
||||
const struct sockaddr *dst6;
|
||||
uint64_t genid;
|
||||
int error, fibnum;
|
||||
|
||||
/*
|
||||
* A link-local address is always a neighbor.
|
||||
@@ -1268,19 +1302,29 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
|
||||
* If the address matches one of our on-link prefixes, it should be a
|
||||
* neighbor.
|
||||
*/
|
||||
ND6_RLOCK();
|
||||
restart:
|
||||
LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
|
||||
if (pr->ndpr_ifp != ifp)
|
||||
continue;
|
||||
|
||||
if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) {
|
||||
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
||||
/* Always use the default FIB here. */
|
||||
dst6 = (struct sockaddr *)&pr->ndpr_prefix;
|
||||
dst6 = (const struct sockaddr *)&pr->ndpr_prefix;
|
||||
|
||||
genid = V_nd6_list_genid;
|
||||
ND6_RUNLOCK();
|
||||
|
||||
/* Restore length field before retrying lookup */
|
||||
rt_key.sin6_len = sizeof(rt_key);
|
||||
if (rib_lookup_info(fibnum, dst6, 0, 0, &info) != 0)
|
||||
error = rib_lookup_info(fibnum, dst6, 0, 0, &info);
|
||||
|
||||
ND6_RLOCK();
|
||||
if (genid != V_nd6_list_genid)
|
||||
goto restart;
|
||||
if (error != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* This is the case where multiple interfaces
|
||||
* have the same prefix, but only one is installed
|
||||
@@ -1292,14 +1336,17 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
|
||||
* differ.
|
||||
*/
|
||||
if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
|
||||
&rt_key.sin6_addr))
|
||||
&rt_key.sin6_addr))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
|
||||
&addr->sin6_addr, &pr->ndpr_mask))
|
||||
&addr->sin6_addr, &pr->ndpr_mask)) {
|
||||
ND6_RUNLOCK();
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
ND6_RUNLOCK();
|
||||
|
||||
/*
|
||||
* If the address is assigned on the node of the other side of
|
||||
@@ -1730,15 +1777,22 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
|
||||
case SIOCSPFXFLUSH_IN6:
|
||||
{
|
||||
/* flush all the prefix advertised by routers */
|
||||
struct in6_ifaddr *ia, *ia_next;
|
||||
struct nd_prefix *pr, *next;
|
||||
struct nd_prhead prl;
|
||||
|
||||
LIST_INIT(&prl);
|
||||
|
||||
ND6_WLOCK();
|
||||
LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, next) {
|
||||
struct in6_ifaddr *ia, *ia_next;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
||||
continue; /* XXX */
|
||||
nd6_prefix_unlink(pr, &prl);
|
||||
}
|
||||
ND6_WUNLOCK();
|
||||
|
||||
/* do we really have to remove addresses as well? */
|
||||
while ((pr = LIST_FIRST(&prl)) != NULL) {
|
||||
LIST_REMOVE(pr, ndpr_entry);
|
||||
/* XXXRW: in6_ifaddrhead locking. */
|
||||
TAILQ_FOREACH_SAFE(ia, &V_in6_ifaddrhead, ia_link,
|
||||
ia_next) {
|
||||
@@ -1748,7 +1802,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
|
||||
if (ia->ia6_ndpr == pr)
|
||||
in6_purgeaddr(&ia->ia_ifa);
|
||||
}
|
||||
prelist_remove(pr);
|
||||
nd6_prefix_del(pr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2676,7 +2730,7 @@ nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS)
|
||||
else
|
||||
p.expire = maxexpire;
|
||||
}
|
||||
p.refcnt = pr->ndpr_refcnt;
|
||||
p.refcnt = pr->ndpr_addrcnt;
|
||||
p.flags = pr->ndpr_stateflags;
|
||||
p.advrtrs = 0;
|
||||
LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry)
|
||||
@@ -2692,9 +2746,10 @@ nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS)
|
||||
ip6_sprintf(ip6buf, &pfr->router->rtaddr));
|
||||
error = SYSCTL_OUT(req, &s6, sizeof(s6));
|
||||
if (error != 0)
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
ND6_RUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
|
@@ -256,7 +256,7 @@ struct nd_prefixctl {
|
||||
struct prf_ra ndpr_flags;
|
||||
};
|
||||
|
||||
|
||||
LIST_HEAD(nd_prhead, nd_prefix);
|
||||
struct nd_prefix {
|
||||
struct ifnet *ndpr_ifp;
|
||||
LIST_ENTRY(nd_prefix) ndpr_entry;
|
||||
@@ -275,7 +275,8 @@ struct nd_prefix {
|
||||
/* list of routers that advertise the prefix: */
|
||||
LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs;
|
||||
u_char ndpr_plen;
|
||||
int ndpr_refcnt; /* reference couter from addresses */
|
||||
int ndpr_addrcnt; /* count of derived addresses */
|
||||
volatile u_int ndpr_refcnt;
|
||||
};
|
||||
|
||||
#define ndpr_raf ndpr_flags
|
||||
@@ -314,8 +315,6 @@ struct nd_pfxrouter {
|
||||
struct nd_defrouter *router;
|
||||
};
|
||||
|
||||
LIST_HEAD(nd_prhead, nd_prefix);
|
||||
|
||||
#ifdef MALLOC_DECLARE
|
||||
MALLOC_DECLARE(M_IP6NDP);
|
||||
#endif
|
||||
@@ -346,17 +345,30 @@ VNET_DECLARE(int, nd6_onlink_ns_rfc4861);
|
||||
|
||||
/* Lock for the prefix and default router lists. */
|
||||
VNET_DECLARE(struct rwlock, nd6_lock);
|
||||
VNET_DECLARE(uint64_t, nd6_list_genid);
|
||||
#define V_nd6_lock VNET(nd6_lock)
|
||||
#define V_nd6_list_genid VNET(nd6_list_genid)
|
||||
|
||||
#define ND6_RLOCK() rw_rlock(&V_nd6_lock)
|
||||
#define ND6_RUNLOCK() rw_runlock(&V_nd6_lock)
|
||||
#define ND6_WLOCK() rw_wlock(&V_nd6_lock)
|
||||
#define ND6_WUNLOCK() rw_wunlock(&V_nd6_lock)
|
||||
#define ND6_TRY_UPGRADE() rw_try_upgrade(&V_nd6_lock)
|
||||
#define ND6_WLOCK_ASSERT() rw_assert(&V_nd6_lock, RA_WLOCKED)
|
||||
#define ND6_RLOCK_ASSERT() rw_assert(&V_nd6_lock, RA_RLOCKED)
|
||||
#define ND6_LOCK_ASSERT() rw_assert(&V_nd6_lock, RA_LOCKED)
|
||||
#define ND6_UNLOCK_ASSERT() rw_assert(&V_nd6_lock, RA_UNLOCKED)
|
||||
|
||||
/* Mutex for prefix onlink/offlink transitions. */
|
||||
VNET_DECLARE(struct mtx, nd6_onlink_mtx);
|
||||
#define V_nd6_onlink_mtx VNET(nd6_onlink_mtx)
|
||||
|
||||
#define ND6_ONLINK_LOCK() mtx_lock(&V_nd6_onlink_mtx)
|
||||
#define ND6_ONLINK_TRYLOCK() mtx_trylock(&V_nd6_onlink_mtx)
|
||||
#define ND6_ONLINK_UNLOCK() mtx_unlock(&V_nd6_onlink_mtx)
|
||||
#define ND6_ONLINK_LOCK_ASSERT() mtx_assert(&V_nd6_onlink_mtx, MA_OWNED)
|
||||
#define ND6_ONLINK_UNLOCK_ASSERT() mtx_assert(&V_nd6_onlink_mtx, MA_NOTOWNED)
|
||||
|
||||
#define nd6log(x) do { if (V_nd6_debug) log x; } while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* nd6_rtr.c */
|
||||
@@ -463,9 +475,14 @@ void defrouter_rele(struct nd_defrouter *);
|
||||
bool defrouter_remove(struct in6_addr *, struct ifnet *);
|
||||
void defrouter_unlink(struct nd_defrouter *, struct nd_drhead *);
|
||||
void defrouter_del(struct nd_defrouter *);
|
||||
void prelist_remove(struct nd_prefix *);
|
||||
int nd6_prelist_add(struct nd_prefixctl *, struct nd_defrouter *,
|
||||
struct nd_prefix **);
|
||||
struct nd_prefix **);
|
||||
void nd6_prefix_unlink(struct nd_prefix *, struct nd_prhead *);
|
||||
void nd6_prefix_del(struct nd_prefix *);
|
||||
void nd6_prefix_ref(struct nd_prefix *);
|
||||
void nd6_prefix_rele(struct nd_prefix *);
|
||||
int nd6_prefix_onlink(struct nd_prefix *);
|
||||
int nd6_prefix_offlink(struct nd_prefix *);
|
||||
void pfxlist_onlink_check(void);
|
||||
struct nd_defrouter *defrouter_lookup(struct in6_addr *, struct ifnet *);
|
||||
struct nd_defrouter *defrouter_lookup_locked(struct in6_addr *, struct ifnet *);
|
||||
|
@@ -1219,40 +1219,26 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
|
||||
struct dadq *dp;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
|
||||
KASSERT((ia->ia6_flags & IN6_IFF_TENTATIVE) != 0,
|
||||
("starting DAD on non-tentative address %p", ifa));
|
||||
|
||||
/*
|
||||
* If we don't need DAD, don't do it.
|
||||
* There are several cases:
|
||||
* - DAD is disabled (ip6_dad_count == 0)
|
||||
* - DAD is disabled globally or on the interface
|
||||
* - the interface address is anycast
|
||||
*/
|
||||
if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
|
||||
log(LOG_DEBUG,
|
||||
"nd6_dad_start: called with non-tentative address "
|
||||
"%s(%s)\n",
|
||||
ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
|
||||
ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
|
||||
return;
|
||||
}
|
||||
if (ia->ia6_flags & IN6_IFF_ANYCAST) {
|
||||
if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0 ||
|
||||
V_ip6_dad_count == 0 ||
|
||||
(ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_NO_DAD) != 0) {
|
||||
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
|
||||
return;
|
||||
}
|
||||
if (!V_ip6_dad_count) {
|
||||
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
|
||||
if ((ifa->ifa_ifp->if_flags & IFF_UP) == 0 ||
|
||||
(ifa->ifa_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
|
||||
(ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED) != 0)
|
||||
return;
|
||||
}
|
||||
if (ifa->ifa_ifp == NULL)
|
||||
panic("nd6_dad_start: ifa->ifa_ifp == NULL");
|
||||
if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_NO_DAD) {
|
||||
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
|
||||
return;
|
||||
}
|
||||
if (!(ifa->ifa_ifp->if_flags & IFF_UP) ||
|
||||
!(ifa->ifa_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
|
||||
(ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED)) {
|
||||
ia->ia6_flags |= IN6_IFF_TENTATIVE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dp = nd6_dad_find(ifa, NULL)) != NULL) {
|
||||
/*
|
||||
* DAD is already in progress. Let the existing entry
|
||||
@@ -1331,11 +1317,8 @@ nd6_dad_timer(struct dadq *dp)
|
||||
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
|
||||
/* Sanity check */
|
||||
if (ia == NULL) {
|
||||
log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
|
||||
goto err;
|
||||
}
|
||||
KASSERT(ia != NULL, ("DAD entry %p with no address", dp));
|
||||
|
||||
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
|
||||
/* Do not need DAD for ifdisabled interface. */
|
||||
log(LOG_ERR, "nd6_dad_timer: cancel DAD on %s because of "
|
||||
|
@@ -78,20 +78,16 @@ 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 *);
|
||||
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 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 nd6_prefix_onlink(struct nd_prefix *);
|
||||
static int nd6_prefix_offlink(struct nd_prefix *);
|
||||
struct in6_addrlifetime *);
|
||||
|
||||
static int rt6_deleteroute(const struct rtentry *, void *);
|
||||
|
||||
@@ -664,6 +660,7 @@ defrouter_unlink(struct nd_defrouter *dr, struct nd_drhead *drq)
|
||||
|
||||
ND6_WLOCK_ASSERT();
|
||||
TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
|
||||
V_nd6_list_genid++;
|
||||
if (drq != NULL)
|
||||
TAILQ_INSERT_TAIL(drq, dr, dr_entry);
|
||||
}
|
||||
@@ -673,6 +670,7 @@ defrouter_del(struct nd_defrouter *dr)
|
||||
{
|
||||
struct nd_defrouter *deldr = NULL;
|
||||
struct nd_prefix *pr;
|
||||
struct nd_pfxrouter *pfxrtr;
|
||||
|
||||
ND6_UNLOCK_ASSERT();
|
||||
|
||||
@@ -691,11 +689,13 @@ defrouter_del(struct nd_defrouter *dr)
|
||||
/*
|
||||
* Also delete all the pointers to the router in each prefix lists.
|
||||
*/
|
||||
ND6_WLOCK();
|
||||
LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
|
||||
struct nd_pfxrouter *pfxrtr;
|
||||
if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
|
||||
pfxrtr_del(pfxrtr);
|
||||
}
|
||||
ND6_WUNLOCK();
|
||||
|
||||
pfxlist_onlink_check();
|
||||
|
||||
/*
|
||||
@@ -855,14 +855,18 @@ static struct nd_defrouter *
|
||||
defrtrlist_update(struct nd_defrouter *new)
|
||||
{
|
||||
struct nd_defrouter *dr, *n;
|
||||
uint64_t genid;
|
||||
int oldpref;
|
||||
bool writelocked;
|
||||
|
||||
if (new->rtlifetime == 0) {
|
||||
defrouter_remove(&new->rtaddr, new->ifp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ND6_WLOCK();
|
||||
ND6_RLOCK();
|
||||
writelocked = false;
|
||||
restart:
|
||||
dr = defrouter_lookup_locked(&new->rtaddr, new->ifp);
|
||||
if (dr != NULL) {
|
||||
oldpref = rtpref(dr);
|
||||
@@ -878,10 +882,32 @@ defrtrlist_update(struct nd_defrouter *new)
|
||||
* router is still installed in the kernel.
|
||||
*/
|
||||
if (dr->installed && rtpref(new) == oldpref) {
|
||||
ND6_WUNLOCK();
|
||||
if (writelocked)
|
||||
ND6_WUNLOCK();
|
||||
else
|
||||
ND6_RUNLOCK();
|
||||
return (dr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The router needs to be reinserted into the default router
|
||||
* list, so upgrade to a write lock. If that fails and the list
|
||||
* has potentially changed while the lock was dropped, we'll
|
||||
* redo the lookup with the write lock held.
|
||||
*/
|
||||
if (!writelocked) {
|
||||
writelocked = true;
|
||||
if (!ND6_TRY_UPGRADE()) {
|
||||
genid = V_nd6_list_genid;
|
||||
ND6_RUNLOCK();
|
||||
ND6_WLOCK();
|
||||
if (genid != V_nd6_list_genid)
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
if (dr != NULL) {
|
||||
/*
|
||||
* The preferred router may have changed, so relocate this
|
||||
* router.
|
||||
@@ -915,6 +941,7 @@ defrtrlist_update(struct nd_defrouter *new)
|
||||
TAILQ_INSERT_BEFORE(dr, n, dr_entry);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry);
|
||||
V_nd6_list_genid++;
|
||||
ND6_WUNLOCK();
|
||||
|
||||
defrouter_select();
|
||||
@@ -927,11 +954,12 @@ 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);
|
||||
}
|
||||
|
||||
@@ -939,55 +967,110 @@ 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;
|
||||
new->router = dr;
|
||||
defrouter_ref(dr);
|
||||
new->router = dr;
|
||||
|
||||
LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
|
||||
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();
|
||||
|
||||
pfxlist_onlink_check();
|
||||
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);
|
||||
}
|
||||
|
||||
static struct nd_prefix *
|
||||
nd6_prefix_lookup_locked(struct nd_prefixctl *key)
|
||||
{
|
||||
struct nd_prefix *search;
|
||||
|
||||
ND6_LOCK_ASSERT();
|
||||
|
||||
LIST_FOREACH(search, &V_nd_prefix, ndpr_entry) {
|
||||
if (key->ndpr_ifp == search->ndpr_ifp &&
|
||||
key->ndpr_plen == search->ndpr_plen &&
|
||||
in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
|
||||
&search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
|
||||
nd6_prefix_ref(search);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (search);
|
||||
}
|
||||
|
||||
struct nd_prefix *
|
||||
nd6_prefix_lookup(struct nd_prefixctl *key)
|
||||
{
|
||||
struct nd_prefix *search;
|
||||
|
||||
LIST_FOREACH(search, &V_nd_prefix, ndpr_entry) {
|
||||
if (key->ndpr_ifp == search->ndpr_ifp &&
|
||||
key->ndpr_plen == search->ndpr_plen &&
|
||||
in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
|
||||
&search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ND6_RLOCK();
|
||||
search = nd6_prefix_lookup_locked(key);
|
||||
ND6_RUNLOCK();
|
||||
return (search);
|
||||
}
|
||||
|
||||
void
|
||||
nd6_prefix_ref(struct nd_prefix *pr)
|
||||
{
|
||||
|
||||
refcount_acquire(&pr->ndpr_refcnt);
|
||||
}
|
||||
|
||||
void
|
||||
nd6_prefix_rele(struct nd_prefix *pr)
|
||||
{
|
||||
|
||||
if (refcount_release(&pr->ndpr_refcnt)) {
|
||||
KASSERT(LIST_EMPTY(&pr->ndpr_advrtrs),
|
||||
("prefix %p has advertising routers", pr));
|
||||
free(pr, M_IP6NDP);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
|
||||
struct nd_prefix **newp)
|
||||
{
|
||||
struct nd_prefix *new = NULL;
|
||||
int error = 0;
|
||||
struct nd_prefix *new;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
int error;
|
||||
|
||||
new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO);
|
||||
if (new == NULL)
|
||||
return (ENOMEM);
|
||||
refcount_init(&new->ndpr_refcnt, newp != NULL ? 2 : 1);
|
||||
new->ndpr_ifp = pr->ndpr_ifp;
|
||||
new->ndpr_prefix = pr->ndpr_prefix;
|
||||
new->ndpr_plen = pr->ndpr_plen;
|
||||
@@ -1006,20 +1089,22 @@ nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
|
||||
/* make prefix in the canonical form */
|
||||
IN6_MASK_ADDR(&new->ndpr_prefix.sin6_addr, &new->ndpr_mask);
|
||||
|
||||
/* link ndpr_entry to nd_prefix list */
|
||||
ND6_WLOCK();
|
||||
LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry);
|
||||
V_nd6_list_genid++;
|
||||
ND6_WUNLOCK();
|
||||
|
||||
/* ND_OPT_PI_FLAG_ONLINK processing */
|
||||
if (new->ndpr_raf_onlink) {
|
||||
int e;
|
||||
|
||||
if ((e = nd6_prefix_onlink(new)) != 0) {
|
||||
ND6_ONLINK_LOCK();
|
||||
if ((error = nd6_prefix_onlink(new)) != 0) {
|
||||
nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
|
||||
"the prefix %s/%d on-link on %s (errno=%d)\n",
|
||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), error));
|
||||
/* proceed anyway. XXX: is it correct? */
|
||||
}
|
||||
ND6_ONLINK_UNLOCK();
|
||||
}
|
||||
|
||||
if (dr != NULL)
|
||||
@@ -1029,51 +1114,69 @@ nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a prefix from the prefix list and optionally stash it in a
|
||||
* caller-provided list.
|
||||
*
|
||||
* The ND6 lock must be held.
|
||||
*/
|
||||
void
|
||||
prelist_remove(struct nd_prefix *pr)
|
||||
nd6_prefix_unlink(struct nd_prefix *pr, struct nd_prhead *list)
|
||||
{
|
||||
|
||||
KASSERT(pr->ndpr_addrcnt == 0,
|
||||
("prefix %p has referencing addresses", pr));
|
||||
ND6_WLOCK_ASSERT();
|
||||
|
||||
LIST_REMOVE(pr, ndpr_entry);
|
||||
V_nd6_list_genid++;
|
||||
if (list != NULL)
|
||||
LIST_INSERT_HEAD(list, pr, ndpr_entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an unlinked prefix, first marking it off-link if necessary.
|
||||
*/
|
||||
void
|
||||
nd6_prefix_del(struct nd_prefix *pr)
|
||||
{
|
||||
struct nd_pfxrouter *pfr, *next;
|
||||
int e;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
|
||||
/* make sure to invalidate the prefix until it is really freed. */
|
||||
pr->ndpr_vltime = 0;
|
||||
pr->ndpr_pltime = 0;
|
||||
KASSERT(pr->ndpr_addrcnt == 0,
|
||||
("prefix %p has referencing addresses", pr));
|
||||
ND6_UNLOCK_ASSERT();
|
||||
|
||||
/*
|
||||
* Though these flags are now meaningless, we'd rather keep the value
|
||||
* of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users
|
||||
* when executing "ndp -p".
|
||||
*/
|
||||
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
|
||||
(e = nd6_prefix_offlink(pr)) != 0) {
|
||||
nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
|
||||
"on %s, errno=%d\n",
|
||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
||||
/* what should we do? */
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
||||
ND6_ONLINK_LOCK();
|
||||
if ((e = nd6_prefix_offlink(pr)) != 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"nd6_prefix_del: failed to make %s/%d offlink "
|
||||
"on %s, errno=%d\n",
|
||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
||||
/* what should we do? */
|
||||
}
|
||||
ND6_ONLINK_UNLOCK();
|
||||
}
|
||||
|
||||
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 advertised the prefix */
|
||||
LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) {
|
||||
/* Release references to routers that have advertised this prefix. */
|
||||
ND6_WLOCK();
|
||||
LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next)
|
||||
pfxrtr_del(pfr);
|
||||
}
|
||||
free(pr, M_IP6NDP);
|
||||
ND6_WUNLOCK();
|
||||
|
||||
nd6_prefix_rele(pr);
|
||||
|
||||
pfxlist_onlink_check();
|
||||
}
|
||||
|
||||
/*
|
||||
* dr - may be NULL
|
||||
*/
|
||||
|
||||
static int
|
||||
prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
|
||||
struct mbuf *m, int mcast)
|
||||
@@ -1123,21 +1226,22 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
|
||||
|
||||
if (new->ndpr_raf_onlink &&
|
||||
(pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
||||
int e;
|
||||
|
||||
if ((e = nd6_prefix_onlink(pr)) != 0) {
|
||||
ND6_ONLINK_LOCK();
|
||||
if ((error = nd6_prefix_onlink(pr)) != 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"prelist_update: failed to make "
|
||||
"the prefix %s/%d on-link on %s "
|
||||
"(errno=%d)\n",
|
||||
ip6_sprintf(ip6buf,
|
||||
&pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
||||
&pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen, if_name(pr->ndpr_ifp),
|
||||
error));
|
||||
/* proceed anyway. XXX: is it correct? */
|
||||
}
|
||||
ND6_ONLINK_UNLOCK();
|
||||
}
|
||||
|
||||
if (dr && pfxrtr_lookup(pr, dr) == NULL)
|
||||
if (dr != NULL)
|
||||
pfxrtr_add(pr, dr);
|
||||
} else {
|
||||
if (new->ndpr_vltime == 0)
|
||||
@@ -1358,7 +1462,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
|
||||
/*
|
||||
* note that we should use pr (not new) for reference.
|
||||
*/
|
||||
pr->ndpr_refcnt++;
|
||||
pr->ndpr_addrcnt++;
|
||||
ia6->ia6_ndpr = pr;
|
||||
|
||||
/*
|
||||
@@ -1396,8 +1500,10 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return error;
|
||||
end:
|
||||
if (pr != NULL)
|
||||
nd6_prefix_rele(pr);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1412,6 +1518,8 @@ find_pfxlist_reachable_router(struct nd_prefix *pr)
|
||||
struct llentry *ln;
|
||||
int canreach;
|
||||
|
||||
ND6_LOCK_ASSERT();
|
||||
|
||||
LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) {
|
||||
IF_AFDATA_RLOCK(pfxrtr->router->ifp);
|
||||
ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp);
|
||||
@@ -1434,7 +1542,7 @@ find_pfxlist_reachable_router(struct nd_prefix *pr)
|
||||
* 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
|
||||
* But, if there is no prefix that has an available router, we still regard
|
||||
* 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.
|
||||
@@ -1447,6 +1555,11 @@ pfxlist_onlink_check(void)
|
||||
struct nd_defrouter *dr;
|
||||
struct nd_pfxrouter *pfxrtr = NULL;
|
||||
struct rm_priotracker in6_ifa_tracker;
|
||||
uint64_t genid;
|
||||
uint32_t flags;
|
||||
|
||||
ND6_ONLINK_LOCK();
|
||||
ND6_RLOCK();
|
||||
|
||||
/*
|
||||
* Check if there is a prefix that has a reachable advertising
|
||||
@@ -1462,7 +1575,6 @@ pfxlist_onlink_check(void)
|
||||
* that does not advertise any prefixes.
|
||||
*/
|
||||
if (pr == NULL) {
|
||||
ND6_RLOCK();
|
||||
TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
|
||||
struct nd_prefix *pr0;
|
||||
|
||||
@@ -1473,7 +1585,6 @@ pfxlist_onlink_check(void)
|
||||
if (pfxrtr != NULL)
|
||||
break;
|
||||
}
|
||||
ND6_RUNLOCK();
|
||||
}
|
||||
if (pr != NULL || (!TAILQ_EMPTY(&V_nd_defrouter) && pfxrtr == NULL)) {
|
||||
/*
|
||||
@@ -1487,40 +1598,26 @@ pfxlist_onlink_check(void)
|
||||
*/
|
||||
LIST_FOREACH(pr, &V_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_raf_auto == 0)
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) ||
|
||||
pr->ndpr_raf_onlink == 0 ||
|
||||
pr->ndpr_raf_auto == 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 &&
|
||||
else if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
|
||||
find_pfxlist_reachable_router(pr) != NULL)
|
||||
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
||||
}
|
||||
} else {
|
||||
/* there is no prefix that has a reachable router */
|
||||
LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) ||
|
||||
pr->ndpr_raf_onlink == 0 ||
|
||||
pr->ndpr_raf_auto == 0)
|
||||
continue;
|
||||
|
||||
if (pr->ndpr_raf_onlink == 0)
|
||||
continue;
|
||||
|
||||
if (pr->ndpr_raf_auto == 0)
|
||||
continue;
|
||||
|
||||
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
|
||||
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
||||
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1532,34 +1629,30 @@ pfxlist_onlink_check(void)
|
||||
* interfaces. Such cases will be handled in nd6_prefix_onlink,
|
||||
* so we don't have to care about them.
|
||||
*/
|
||||
restart:
|
||||
LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) {
|
||||
int e;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
int e;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) ||
|
||||
pr->ndpr_raf_onlink == 0 ||
|
||||
pr->ndpr_raf_auto == 0)
|
||||
continue;
|
||||
|
||||
if (pr->ndpr_raf_onlink == 0)
|
||||
continue;
|
||||
|
||||
if (pr->ndpr_raf_auto == 0)
|
||||
continue;
|
||||
|
||||
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
|
||||
(pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
||||
if ((e = nd6_prefix_offlink(pr)) != 0) {
|
||||
flags = pr->ndpr_stateflags & (NDPRF_DETACHED | NDPRF_ONLINK);
|
||||
if (flags == 0 || flags == (NDPRF_DETACHED | NDPRF_ONLINK)) {
|
||||
genid = V_nd6_list_genid;
|
||||
ND6_RUNLOCK();
|
||||
if ((flags & NDPRF_ONLINK) != 0 &&
|
||||
(e = nd6_prefix_offlink(pr)) != 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"pfxlist_onlink_check: failed to "
|
||||
"make %s/%d offlink, errno=%d\n",
|
||||
ip6_sprintf(ip6buf,
|
||||
&pr->ndpr_prefix.sin6_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) {
|
||||
} else if ((flags & NDPRF_ONLINK) == 0 &&
|
||||
(e = nd6_prefix_onlink(pr)) != 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"pfxlist_onlink_check: failed to "
|
||||
"make %s/%d onlink, errno=%d\n",
|
||||
@@ -1567,6 +1660,9 @@ pfxlist_onlink_check(void)
|
||||
&pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen, e));
|
||||
}
|
||||
ND6_RLOCK();
|
||||
if (genid != V_nd6_list_genid)
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1627,6 +1723,8 @@ pfxlist_onlink_check(void)
|
||||
}
|
||||
}
|
||||
IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
|
||||
ND6_RUNLOCK();
|
||||
ND6_ONLINK_UNLOCK();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1707,23 +1805,20 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
|
||||
return (a_failure);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
{
|
||||
struct ifaddr *ifa;
|
||||
struct ifnet *ifp = pr->ndpr_ifp;
|
||||
struct nd_prefix *opr;
|
||||
int error = 0;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
int error;
|
||||
|
||||
/* sanity check */
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"nd6_prefix_onlink: %s/%d is already on-link\n",
|
||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen));
|
||||
ND6_ONLINK_LOCK_ASSERT();
|
||||
ND6_UNLOCK_ASSERT();
|
||||
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0)
|
||||
return (EEXIST);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the interface route associated with the prefix. Before
|
||||
@@ -1732,6 +1827,7 @@ nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
* Although such a configuration is expected to be rare, we explicitly
|
||||
* allow it.
|
||||
*/
|
||||
ND6_RLOCK();
|
||||
LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) {
|
||||
if (opr == pr)
|
||||
continue;
|
||||
@@ -1741,9 +1837,12 @@ nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
|
||||
if (opr->ndpr_plen == pr->ndpr_plen &&
|
||||
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
||||
&opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
|
||||
&opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
|
||||
ND6_RUNLOCK();
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ND6_RUNLOCK();
|
||||
|
||||
/*
|
||||
* We prefer link-local addresses as the associated interface address.
|
||||
@@ -1755,11 +1854,11 @@ nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
/* XXX: freebsd does not have ifa_ifwithaf */
|
||||
IF_ADDR_RLOCK(ifp);
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6)
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6) {
|
||||
ifa_ref(ifa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ifa != NULL)
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_RUNLOCK(ifp);
|
||||
/* should we care about ia6_flags? */
|
||||
}
|
||||
@@ -1786,7 +1885,7 @@ nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nd6_prefix_offlink(struct nd_prefix *pr)
|
||||
{
|
||||
int error = 0;
|
||||
@@ -1795,16 +1894,14 @@ nd6_prefix_offlink(struct nd_prefix *pr)
|
||||
struct sockaddr_in6 sa6, mask6;
|
||||
struct rtentry *rt;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
uint64_t genid;
|
||||
int fibnum, a_failure;
|
||||
|
||||
/* sanity check */
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"nd6_prefix_offlink: %s/%d is already off-link\n",
|
||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
|
||||
pr->ndpr_plen));
|
||||
ND6_ONLINK_LOCK_ASSERT();
|
||||
ND6_UNLOCK_ASSERT();
|
||||
|
||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0)
|
||||
return (EEXIST);
|
||||
}
|
||||
|
||||
bzero(&sa6, sizeof(sa6));
|
||||
sa6.sin6_family = AF_INET6;
|
||||
@@ -1845,18 +1942,15 @@ nd6_prefix_offlink(struct nd_prefix *pr)
|
||||
* If there's one, try to make the prefix on-link on the
|
||||
* interface.
|
||||
*/
|
||||
ND6_RLOCK();
|
||||
restart:
|
||||
LIST_FOREACH(opr, &V_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)
|
||||
if (opr == pr || (opr->ndpr_stateflags &
|
||||
(NDPRF_ONLINK | NDPRF_DETACHED)) != 0)
|
||||
continue;
|
||||
|
||||
if (opr->ndpr_plen == pr->ndpr_plen &&
|
||||
@@ -1864,6 +1958,8 @@ nd6_prefix_offlink(struct nd_prefix *pr)
|
||||
&opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
|
||||
int e;
|
||||
|
||||
genid = V_nd6_list_genid;
|
||||
ND6_RUNLOCK();
|
||||
if ((e = nd6_prefix_onlink(opr)) != 0) {
|
||||
nd6log((LOG_ERR,
|
||||
"nd6_prefix_offlink: failed to "
|
||||
@@ -1875,8 +1971,12 @@ nd6_prefix_offlink(struct nd_prefix *pr)
|
||||
if_name(opr->ndpr_ifp), e));
|
||||
} else
|
||||
a_failure = 0;
|
||||
ND6_RLOCK();
|
||||
if (genid != V_nd6_list_genid)
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
ND6_RUNLOCK();
|
||||
} else {
|
||||
/* XXX: can we still set the NDPRF_ONLINK flag? */
|
||||
nd6log((LOG_ERR,
|
||||
@@ -2116,7 +2216,7 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay)
|
||||
return (EINVAL); /* XXX */
|
||||
}
|
||||
newia->ia6_ndpr = ia0->ia6_ndpr;
|
||||
newia->ia6_ndpr->ndpr_refcnt++;
|
||||
newia->ia6_ndpr->ndpr_addrcnt++;
|
||||
ifa_free(&newia->ia_ifa);
|
||||
|
||||
/*
|
||||
|
@@ -258,7 +258,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
|
||||
}
|
||||
}
|
||||
if (last != NULL) {
|
||||
struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
|
||||
struct mbuf *n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
|
||||
|
||||
#ifdef IPSEC
|
||||
/*
|
||||
|
@@ -76,10 +76,8 @@ sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port)
|
||||
struct sctphdr *sh;
|
||||
struct sctp_chunkhdr *ch;
|
||||
int length, offset;
|
||||
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
uint8_t compute_crc;
|
||||
|
||||
#endif
|
||||
uint32_t mflowid;
|
||||
uint8_t mflowtype;
|
||||
@@ -196,7 +194,6 @@ sctp6_notify(struct sctp_inpcb *inp,
|
||||
{
|
||||
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
struct socket *so;
|
||||
|
||||
#endif
|
||||
int timer_stopped;
|
||||
|
||||
@@ -700,7 +697,6 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
||||
|
||||
#ifdef INET
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
#endif /* INET */
|
||||
/* No SPL needed since sctp_output does this */
|
||||
|
||||
@@ -802,12 +798,10 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
int error = 0;
|
||||
struct sctp_inpcb *inp;
|
||||
struct sctp_tcb *stcb;
|
||||
|
||||
#ifdef INET
|
||||
struct in6pcb *inp6;
|
||||
struct sockaddr_in6 *sin6;
|
||||
union sctp_sockstore store;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
|
@@ -50,6 +50,5 @@ void sctp6_ctlinput(int, struct sockaddr *, void *);
|
||||
void
|
||||
sctp6_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *,
|
||||
uint8_t, uint8_t, uint16_t);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -368,7 +368,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
if (last != NULL) {
|
||||
struct mbuf *n;
|
||||
|
||||
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) !=
|
||||
NULL) {
|
||||
INP_RLOCK(last);
|
||||
UDP_PROBE(receive, NULL, last, ip6,
|
||||
last, uh);
|
||||
@@ -900,7 +901,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
|
||||
UDP_PROBE(send, NULL, inp, ip6, inp, udp6);
|
||||
UDPSTAT_INC(udps_opackets);
|
||||
error = ip6_output(m, optp, NULL, flags,
|
||||
error = ip6_output(m, optp, &inp->inp_route6, flags,
|
||||
inp->in6p_moptions, NULL, inp);
|
||||
break;
|
||||
case AF_INET:
|
||||
|
Reference in New Issue
Block a user