summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-21 13:47:02 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-21 10:29:41 +0200
commitbcdce02d9bc8150e1d191ed5ca9da45b7604964a (patch)
tree3b2faf509db7672ee1fc98857736470be97e7ed8 /freebsd/sys/netinet6
parentUpdate to FreeBSD head 2018-04-01 (diff)
downloadrtems-libbsd-bcdce02d9bc8150e1d191ed5ca9da45b7604964a.tar.bz2
Update to FreeBSD head 2018-06-01
Git mirror commit fb63610a69b0eb7f69a201ba05c4c1a7a2739cf9. Update #3472.
Diffstat (limited to 'freebsd/sys/netinet6')
-rw-r--r--freebsd/sys/netinet6/icmp6.c21
-rw-r--r--freebsd/sys/netinet6/in6.c215
-rw-r--r--freebsd/sys/netinet6/in6_ifattach.c62
-rw-r--r--freebsd/sys/netinet6/in6_mcast.c336
-rw-r--r--freebsd/sys/netinet6/in6_pcb.c14
-rw-r--r--freebsd/sys/netinet6/in6_proto.c3
-rw-r--r--freebsd/sys/netinet6/in6_src.c2
-rw-r--r--freebsd/sys/netinet6/in6_var.h86
-rw-r--r--freebsd/sys/netinet6/ip6_fastfwd.c14
-rw-r--r--freebsd/sys/netinet6/ip6_input.c6
-rw-r--r--freebsd/sys/netinet6/ip6_var.h3
-rw-r--r--freebsd/sys/netinet6/mld6.c159
-rw-r--r--freebsd/sys/netinet6/mld6_var.h1
-rw-r--r--freebsd/sys/netinet6/nd6.c38
-rw-r--r--freebsd/sys/netinet6/nd6_nbr.c3
-rw-r--r--freebsd/sys/netinet6/nd6_rtr.c12
-rw-r--r--freebsd/sys/netinet6/raw_ip6.c14
-rw-r--r--freebsd/sys/netinet6/sctp6_usrreq.c2
18 files changed, 569 insertions, 422 deletions
diff --git a/freebsd/sys/netinet6/icmp6.c b/freebsd/sys/netinet6/icmp6.c
index 77876599..4d06ca16 100644
--- a/freebsd/sys/netinet6/icmp6.c
+++ b/freebsd/sys/netinet6/icmp6.c
@@ -385,15 +385,6 @@ icmp6_error(struct mbuf *m, int type, int code, int param)
icmp6->icmp6_code = code;
icmp6->icmp6_pptr = htonl((u_int32_t)param);
- /*
- * icmp6_reflect() is designed to be in the input path.
- * icmp6_error() can be called from both input and output path,
- * and if we are in output path rcvif could contain bogus value.
- * clear m->m_pkthdr.rcvif for safety, we should have enough scope
- * information in ip header (nip6).
- */
- m->m_pkthdr.rcvif = NULL;
-
ICMP6STAT_INC(icp6s_outhist[type]);
icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
@@ -1700,10 +1691,10 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp,
}
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
addrsofif = 0;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa6 = (struct in6_ifaddr *)ifa;
@@ -1784,12 +1775,12 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
return (0); /* needless to copy */
IFNET_RLOCK_NOSLEEP();
- ifp = ifp0 ? ifp0 : TAILQ_FIRST(&V_ifnet);
+ ifp = ifp0 ? ifp0 : CK_STAILQ_FIRST(&V_ifnet);
again:
- for (; ifp; ifp = TAILQ_NEXT(ifp, if_link)) {
+ for (; ifp; ifp = CK_STAILQ_NEXT(ifp, if_link)) {
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa6 = (struct in6_ifaddr *)ifa;
@@ -2197,7 +2188,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
*/
m->m_flags &= ~(M_BCAST|M_MCAST);
-
+ m->m_pkthdr.rcvif = NULL;
ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
if (outif)
icmp6_ifoutstat_inc(outif, type, code);
diff --git a/freebsd/sys/netinet6/in6.c b/freebsd/sys/netinet6/in6.c
index a5d84d85..3ed80c9c 100644
--- a/freebsd/sys/netinet6/in6.c
+++ b/freebsd/sys/netinet6/in6.c
@@ -67,7 +67,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <rtems/bsd/local/opt_compat.h>
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
@@ -82,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/protosw.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -114,6 +114,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/in6_fib.h>
#include <netinet6/in6_pcb.h>
+
/*
* struct in6_ifreq and struct ifreq must be type punnable for common members
* of ifr_ifru to allow accessors to be shared.
@@ -690,7 +691,6 @@ aifaddr_out:
* The failure means address duplication was detected.
*/
}
- EVENTHANDLER_INVOKE(ifaddr_event, ifp);
break;
}
@@ -737,6 +737,30 @@ out:
}
+static struct in6_multi_mship *
+in6_joingroup_legacy(struct ifnet *ifp, const struct in6_addr *mcaddr,
+ int *errorp, int delay)
+{
+ struct in6_multi_mship *imm;
+ int error;
+
+ imm = malloc(sizeof(*imm), M_IP6MADDR, M_NOWAIT);
+ if (imm == NULL) {
+ *errorp = ENOBUFS;
+ return (NULL);
+ }
+
+ delay = (delay * PR_FASTHZ) / hz;
+
+ error = in6_joingroup(ifp, mcaddr, NULL, &imm->i6mm_maddr, delay);
+ if (error) {
+ *errorp = error;
+ free(imm, M_IP6MADDR);
+ return (NULL);
+ }
+
+ return (imm);
+}
/*
* Join necessary multicast groups. Factored out from in6_update_ifa().
* This entire work should only be done once, for the default FIB.
@@ -773,7 +797,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
*/
delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
}
- imm = in6_joingroup(ifp, &mltaddr, &error, delay);
+ imm = in6_joingroup_legacy(ifp, &mltaddr, &error, delay);
if (imm == NULL) {
nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &mltaddr),
@@ -790,7 +814,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0)
goto cleanup; /* XXX: should not fail */
- imm = in6_joingroup(ifp, &mltaddr, &error, 0);
+ imm = in6_joingroup_legacy(ifp, &mltaddr, &error, 0);
if (imm == NULL) {
nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &mltaddr),
@@ -812,7 +836,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
}
if (in6_nigroup(ifp, NULL, -1, &mltaddr) == 0) {
/* XXX jinmei */
- imm = in6_joingroup(ifp, &mltaddr, &error, delay);
+ imm = in6_joingroup_legacy(ifp, &mltaddr, &error, delay);
if (imm == NULL)
nd6log((LOG_WARNING,
"%s: in6_joingroup failed for %s on %s "
@@ -824,7 +848,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
}
if (V_icmp6_nodeinfo_oldmcprefix &&
in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr) == 0) {
- imm = in6_joingroup(ifp, &mltaddr, &error, delay);
+ imm = in6_joingroup_legacy(ifp, &mltaddr, &error, delay);
if (imm == NULL)
nd6log((LOG_WARNING,
"%s: in6_joingroup failed for %s on %s "
@@ -843,7 +867,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0)
goto cleanup; /* XXX: should not fail */
- imm = in6_joingroup(ifp, &mltaddr, &error, 0);
+ imm = in6_joingroup_legacy(ifp, &mltaddr, &error, 0);
if (imm == NULL) {
nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s "
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
@@ -1099,13 +1123,13 @@ in6_alloc_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, int flags)
ia->ia_ifp = ifp;
ifa_ref(&ia->ia_ifa); /* if_addrhead */
IF_ADDR_WLOCK(ifp);
- TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+ CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */
IN6_IFADDR_WLOCK();
- TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
- LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash);
+ CK_STAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
+ CK_LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash);
IN6_IFADDR_WUNLOCK();
return (ia);
@@ -1278,7 +1302,9 @@ in6_purgeaddr(struct ifaddr *ifa)
/* Leave multicast groups. */
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
- in6_leavegroup(imm);
+ if (imm->i6mm_maddr != NULL)
+ in6_leavegroup(imm->i6mm_maddr, NULL);
+ free(imm, M_IP6MADDR);
}
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
@@ -1301,7 +1327,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
int remove_lle;
IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+ CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_free(&ia->ia_ifa); /* if_addrhead */
@@ -1311,8 +1337,8 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
* cleanup.
*/
IN6_IFADDR_WLOCK();
- TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
- LIST_REMOVE(ia, ia6_hash);
+ CK_STAILQ_REMOVE(&V_in6_ifaddrhead, ia, in6_ifaddr, ia_link);
+ CK_LIST_REMOVE(ia, ia6_hash);
IN6_IFADDR_WUNLOCK();
/*
@@ -1366,7 +1392,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
*/
if (hostIsNew != 0) {
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifacount++;
@@ -1377,7 +1403,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
if (ifacount <= 1 && ifp->if_ioctl) {
error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
if (error)
- return (error);
+ goto done;
}
/*
@@ -1417,7 +1443,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
ia->ia_flags |= IFA_RTSELF;
error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
if (error)
- return (error);
+ goto done;
ia->ia_flags |= IFA_ROUTE;
}
@@ -1430,6 +1456,11 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
if (error == 0)
ia->ia_flags |= IFA_RTSELF;
}
+done:
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "Invoking IPv6 network device address event may sleep");
+
+ EVENTHANDLER_INVOKE(ifaddr_event, ifp);
return (error);
}
@@ -1444,7 +1475,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
struct ifaddr *ifa;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
@@ -1472,7 +1503,7 @@ in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
struct in6_ifaddr *ia;
IN6_IFADDR_RLOCK(&in6_ifa_tracker);
- LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) {
+ CK_LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) {
if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), addr)) {
if (zoneid != 0 &&
zoneid != ia->ia_addr.sin6_scope_id)
@@ -1495,7 +1526,7 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, const struct in6_addr *addr)
struct ifaddr *ifa;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) {
@@ -1520,7 +1551,7 @@ in6ifa_llaonifp(struct ifnet *ifp)
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
return (NULL);
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
@@ -1626,7 +1657,7 @@ in6_localaddr(struct in6_addr *in6)
return 1;
IN6_IFADDR_RLOCK(&in6_ifa_tracker);
- TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
&ia->ia_prefixmask.sin6_addr)) {
IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
@@ -1649,7 +1680,7 @@ in6_localip(struct in6_addr *in6)
struct in6_ifaddr *ia;
IN6_IFADDR_RLOCK(&in6_ifa_tracker);
- LIST_FOREACH(ia, IN6ADDR_HASH(in6), ia6_hash) {
+ CK_LIST_FOREACH(ia, IN6ADDR_HASH(in6), ia6_hash) {
if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) {
IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
return (1);
@@ -1675,7 +1706,7 @@ in6_ifhasaddr(struct ifnet *ifp, struct in6_addr *addr)
in6_setscope(&in6, ifp, NULL);
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia6 = (struct in6_ifaddr *)ifa;
@@ -1696,7 +1727,7 @@ in6_is_addr_deprecated(struct sockaddr_in6 *sa6)
struct in6_ifaddr *ia;
IN6_IFADDR_RLOCK(&in6_ifa_tracker);
- LIST_FOREACH(ia, IN6ADDR_HASH(&sa6->sin6_addr), ia6_hash) {
+ CK_LIST_FOREACH(ia, IN6ADDR_HASH(&sa6->sin6_addr), ia6_hash) {
if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), &sa6->sin6_addr)) {
if (ia->ia6_flags & IN6_IFF_DEPRECATED) {
IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
@@ -1802,7 +1833,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
* If none, return one of global addresses assigned other ifs.
*/
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
@@ -1839,7 +1870,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
return (besta);
}
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
@@ -1886,7 +1917,7 @@ in6_if_up(struct ifnet *ifp)
struct in6_ifaddr *ia;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
@@ -1946,7 +1977,7 @@ in6_setmaxmtu(void)
struct ifnet *ifp;
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
/* this function can be called during ifnet initialization */
if (!ifp->if_afdata[AF_INET6])
continue;
@@ -1977,12 +2008,8 @@ in6_if2idlen(struct ifnet *ifp)
case IFT_BRIDGE: /* bridge(4) only does Ethernet-like links */
case IFT_INFINIBAND:
return (64);
- case IFT_FDDI: /* RFC2467 */
- return (64);
case IFT_PPP: /* RFC2472 */
return (64);
- case IFT_ARCNET: /* RFC2497 */
- return (64);
case IFT_FRELAY: /* RFC2590 */
return (64);
case IFT_IEEE1394: /* RFC3146 */
@@ -2022,9 +2049,11 @@ struct in6_llentry {
* Do actual deallocation of @lle.
*/
static void
-in6_lltable_destroy_lle_unlocked(struct llentry *lle)
+in6_lltable_destroy_lle_unlocked(epoch_context_t ctx)
{
+ struct llentry *lle;
+ lle = __containerof(ctx, struct llentry, lle_epoch_ctx);
LLE_LOCK_DESTROY(lle);
LLE_REQ_DESTROY(lle);
free(lle, M_LLTABLE);
@@ -2039,7 +2068,7 @@ in6_lltable_destroy_lle(struct llentry *lle)
{
LLE_WUNLOCK(lle);
- in6_lltable_destroy_lle_unlocked(lle);
+ epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in6_lltable_destroy_lle_unlocked);
}
static struct llentry *
@@ -2142,11 +2171,13 @@ in6_lltable_rtcheck(struct ifnet *ifp,
* Create an ND6 cache for an IPv6 neighbor
* that is not covered by our own prefix.
*/
+ NET_EPOCH_ENTER();
ifa = ifaof_ifpforaddr(l3addr, ifp);
if (ifa != NULL) {
- ifa_free(ifa);
+ NET_EPOCH_EXIT();
return 0;
}
+ NET_EPOCH_EXIT();
log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n",
ip6_sprintf(ip6buf, &sin6->sin6_addr));
return EINVAL;
@@ -2208,7 +2239,7 @@ in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst)
hashidx = in6_lltable_hash_dst(dst, llt->llt_hsize);
lleh = &llt->lle_head[hashidx];
- LIST_FOREACH(lle, lleh, lle_next) {
+ CK_LIST_FOREACH(lle, lleh, lle_next) {
if (lle->la_flags & LLE_DELETED)
continue;
if (IN6_ARE_ADDR_EQUAL(&lle->r_l3addr.addr6, dst))
@@ -2263,7 +2294,7 @@ in6_lltable_alloc(struct lltable *llt, u_int flags,
linkhdrsize = LLE_MAX_LINKHDR;
if (lltable_calc_llheader(ifp, AF_INET6, IF_LLADDR(ifp),
linkhdr, &linkhdrsize, &lladdr_off) != 0) {
- in6_lltable_destroy_lle_unlocked(lle);
+ epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in6_lltable_destroy_lle_unlocked);
return (NULL);
}
lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
@@ -2328,62 +2359,58 @@ in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
int error;
bzero(&ndpc, sizeof(ndpc));
- /* skip deleted entries */
- if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
- return (0);
- /* Skip if jailed and not a valid IP of the prison. */
- lltable_fill_sa_entry(lle,
- (struct sockaddr *)&ndpc.sin6);
- if (prison_if(wr->td->td_ucred,
- (struct sockaddr *)&ndpc.sin6) != 0)
- return (0);
- /*
- * produce a msg made of:
- * struct rt_msghdr;
- * struct sockaddr_in6 (IPv6)
- * struct sockaddr_dl;
- */
- ndpc.rtm.rtm_msglen = sizeof(ndpc);
- ndpc.rtm.rtm_version = RTM_VERSION;
- ndpc.rtm.rtm_type = RTM_GET;
- ndpc.rtm.rtm_flags = RTF_UP;
- ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
- if (V_deembed_scopeid)
- sa6_recoverscope(&ndpc.sin6);
-
- /* publish */
- if (lle->la_flags & LLE_PUB)
- ndpc.rtm.rtm_flags |= RTF_ANNOUNCE;
-
- sdl = &ndpc.sdl;
- sdl->sdl_family = AF_LINK;
- sdl->sdl_len = sizeof(*sdl);
- sdl->sdl_index = ifp->if_index;
- sdl->sdl_type = ifp->if_type;
- if ((lle->la_flags & LLE_VALID) == LLE_VALID) {
- sdl->sdl_alen = ifp->if_addrlen;
- bcopy(lle->ll_addr, LLADDR(sdl),
- ifp->if_addrlen);
- } else {
- sdl->sdl_alen = 0;
- bzero(LLADDR(sdl), ifp->if_addrlen);
- }
- if (lle->la_expire != 0)
- ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire +
- lle->lle_remtime / hz +
- time_second - time_uptime;
- ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
- if (lle->la_flags & LLE_STATIC)
- ndpc.rtm.rtm_flags |= RTF_STATIC;
- if (lle->la_flags & LLE_IFADDR)
- ndpc.rtm.rtm_flags |= RTF_PINNED;
- if (lle->ln_router != 0)
- ndpc.rtm.rtm_flags |= RTF_GATEWAY;
- ndpc.rtm.rtm_rmx.rmx_pksent = lle->la_asked;
- /* Store state in rmx_weight value */
- ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state;
- ndpc.rtm.rtm_index = ifp->if_index;
- error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc));
+ /* skip deleted entries */
+ if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
+ return (0);
+ /* Skip if jailed and not a valid IP of the prison. */
+ lltable_fill_sa_entry(lle, (struct sockaddr *)&ndpc.sin6);
+ if (prison_if(wr->td->td_ucred, (struct sockaddr *)&ndpc.sin6) != 0)
+ return (0);
+ /*
+ * produce a msg made of:
+ * struct rt_msghdr;
+ * struct sockaddr_in6 (IPv6)
+ * struct sockaddr_dl;
+ */
+ ndpc.rtm.rtm_msglen = sizeof(ndpc);
+ ndpc.rtm.rtm_version = RTM_VERSION;
+ ndpc.rtm.rtm_type = RTM_GET;
+ ndpc.rtm.rtm_flags = RTF_UP;
+ ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ if (V_deembed_scopeid)
+ sa6_recoverscope(&ndpc.sin6);
+
+ /* publish */
+ if (lle->la_flags & LLE_PUB)
+ ndpc.rtm.rtm_flags |= RTF_ANNOUNCE;
+
+ sdl = &ndpc.sdl;
+ sdl->sdl_family = AF_LINK;
+ sdl->sdl_len = sizeof(*sdl);
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = ifp->if_type;
+ if ((lle->la_flags & LLE_VALID) == LLE_VALID) {
+ sdl->sdl_alen = ifp->if_addrlen;
+ bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
+ } else {
+ sdl->sdl_alen = 0;
+ bzero(LLADDR(sdl), ifp->if_addrlen);
+ }
+ if (lle->la_expire != 0)
+ ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire +
+ lle->lle_remtime / hz + time_second - time_uptime;
+ ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
+ if (lle->la_flags & LLE_STATIC)
+ ndpc.rtm.rtm_flags |= RTF_STATIC;
+ if (lle->la_flags & LLE_IFADDR)
+ ndpc.rtm.rtm_flags |= RTF_PINNED;
+ if (lle->ln_router != 0)
+ ndpc.rtm.rtm_flags |= RTF_GATEWAY;
+ ndpc.rtm.rtm_rmx.rmx_pksent = lle->la_asked;
+ /* Store state in rmx_weight value */
+ ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state;
+ ndpc.rtm.rtm_index = ifp->if_index;
+ error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc));
return (error);
}
diff --git a/freebsd/sys/netinet6/in6_ifattach.c b/freebsd/sys/netinet6/in6_ifattach.c
index 1ce489f5..81182b4e 100644
--- a/freebsd/sys/netinet6/in6_ifattach.c
+++ b/freebsd/sys/netinet6/in6_ifattach.c
@@ -255,7 +255,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
@@ -280,7 +280,6 @@ found:
case IFT_BRIDGE:
case IFT_ETHER:
case IFT_L2VLAN:
- case IFT_FDDI:
case IFT_ATM:
case IFT_IEEE1394:
/* IEEE802/EUI64 cases - what others? */
@@ -323,26 +322,6 @@ found:
}
break;
- case IFT_ARCNET:
- if (addrlen != 1) {
- IF_ADDR_RUNLOCK(ifp);
- return -1;
- }
- if (!addr[0]) {
- IF_ADDR_RUNLOCK(ifp);
- return -1;
- }
-
- bzero(&in6->s6_addr[8], 8);
- in6->s6_addr[15] = addr[0];
-
- /*
- * due to insufficient bitwidth, we mark it local.
- */
- in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
- in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
- break;
-
case IFT_GIF:
case IFT_STF:
/*
@@ -411,7 +390,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp,
/* next, try to get it from some other hardware interface */
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (ifp == ifp0)
continue;
if (in6_get_hw_ifid(ifp, in6) != 0)
@@ -782,7 +761,7 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp)
* nuke any of IPv6 addresses we have
* XXX: all addresses should be already removed
*/
- TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
+ CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
in6_purgeaddr(ifa);
@@ -857,7 +836,7 @@ in6_tmpaddrtimer(void *arg)
V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet);
bzero(nullbuf, sizeof(nullbuf));
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (ifp->if_afdata[AF_INET6] == NULL)
continue;
ndi = ND_IFINFO(ifp);
@@ -877,36 +856,35 @@ in6_tmpaddrtimer(void *arg)
static void
in6_purgemaddrs(struct ifnet *ifp)
{
- LIST_HEAD(,in6_multi) purgeinms;
- struct in6_multi *inm, *tinm;
- struct ifmultiaddr *ifma;
+ struct in6_multi_head purgeinms;
+ struct in6_multi *inm;
+ struct ifmultiaddr *ifma, *next;
- LIST_INIT(&purgeinms);
+ SLIST_INIT(&purgeinms);
IN6_MULTI_LOCK();
-
+ IN6_MULTI_LIST_LOCK();
+ IF_ADDR_WLOCK(ifp);
/*
* Extract list of in6_multi associated with the detaching ifp
* which the PF_INET6 layer is about to release.
- * We need to do this as IF_ADDR_LOCK() may be re-acquired
- * by code further down.
*/
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ restart:
+ CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
if (ifma->ifma_addr->sa_family != AF_INET6 ||
ifma->ifma_protospec == NULL)
continue;
inm = (struct in6_multi *)ifma->ifma_protospec;
- LIST_INSERT_HEAD(&purgeinms, inm, in6m_entry);
- }
- IF_ADDR_RUNLOCK(ifp);
-
- LIST_FOREACH_SAFE(inm, &purgeinms, in6m_entry, tinm) {
- LIST_REMOVE(inm, in6m_entry);
- in6m_release_locked(inm);
+ in6m_rele_locked(&purgeinms, inm);
+ if (__predict_false(ifma6_restart)) {
+ ifma6_restart = false;
+ goto restart;
+ }
}
+ IF_ADDR_WUNLOCK(ifp);
mld_ifdetach(ifp);
-
+ IN6_MULTI_LIST_UNLOCK();
IN6_MULTI_UNLOCK();
+ in6m_release_list_deferred(&purgeinms);
}
void
diff --git a/freebsd/sys/netinet6/in6_mcast.c b/freebsd/sys/netinet6/in6_mcast.c
index a634b18b..32660c89 100644
--- a/freebsd/sys/netinet6/in6_mcast.c
+++ b/freebsd/sys/netinet6/in6_mcast.c
@@ -43,13 +43,13 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/gtaskqueue.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
-#include <sys/protosw.h>
#include <sys/sysctl.h>
#include <sys/priv.h>
#include <sys/ktr.h>
@@ -61,8 +61,12 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
+
#include <netinet/in.h>
+#include <netinet/udp.h>
#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp_var.h>
#include <netinet6/in6_fib.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
@@ -91,7 +95,7 @@ typedef union sockunion sockunion_t;
static MALLOC_DEFINE(M_IN6MFILTER, "in6_mfilter",
"IPv6 multicast PCB-layer source filter");
-static MALLOC_DEFINE(M_IP6MADDR, "in6_multi", "IPv6 multicast group");
+MALLOC_DEFINE(M_IP6MADDR, "in6_multi", "IPv6 multicast group");
static MALLOC_DEFINE(M_IP6MOPTS, "ip6_moptions", "IPv6 multicast options");
static MALLOC_DEFINE(M_IP6MSOURCE, "ip6_msource",
"IPv6 multicast MLD-layer source filter");
@@ -109,8 +113,16 @@ RB_GENERATE(ip6_msource_tree, ip6_msource, im6s_link, ip6_msource_cmp);
* any need for in6_multi itself to be virtualized -- it is bound to an ifp
* anyway no matter what happens.
*/
-struct mtx in6_multi_mtx;
-MTX_SYSINIT(in6_multi_mtx, &in6_multi_mtx, "in6_multi_mtx", MTX_DEF);
+struct mtx in6_multi_list_mtx;
+MTX_SYSINIT(in6_multi_mtx, &in6_multi_list_mtx, "in6_multi_list_mtx", MTX_DEF);
+
+struct mtx in6_multi_free_mtx;
+MTX_SYSINIT(in6_multi_free_mtx, &in6_multi_free_mtx, "in6_multi_free_mtx", MTX_DEF);
+
+struct sx in6_multi_sx;
+SX_SYSINIT(in6_multi_sx, &in6_multi_sx, "in6_multi_sx");
+
+
static void im6f_commit(struct in6_mfilter *);
static int im6f_get_source(struct in6_mfilter *imf,
@@ -132,7 +144,7 @@ static struct in6_msource *
const struct sockaddr *);
static void im6s_merge(struct ip6_msource *ims,
const struct in6_msource *lims, const int rollback);
-static int in6_mc_get(struct ifnet *, const struct in6_addr *,
+static int in6_getmulti(struct ifnet *, const struct in6_addr *,
struct in6_multi **);
static int in6m_get_source(struct in6_multi *inm,
const struct in6_addr *addr, const int noalloc,
@@ -180,6 +192,7 @@ static SYSCTL_NODE(_net_inet6_ip6_mcast, OID_AUTO, filters,
CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip6_mcast_filters,
"Per-interface stack-wide source filters");
+int ifma6_restart = 0;
#ifdef KTR
/*
* Inline function which wraps assertions for a valid ifp.
@@ -391,7 +404,7 @@ im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp,
* Return 0 if successful, otherwise return an appropriate error code.
*/
static int
-in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
+in6_getmulti(struct ifnet *ifp, const struct in6_addr *group,
struct in6_multi **pinm)
{
struct sockaddr_in6 gsin6;
@@ -407,8 +420,8 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
* re-acquire around the call.
*/
IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK();
IF_ADDR_WLOCK(ifp);
-
inm = in6m_lookup_locked(ifp, group);
if (inm != NULL) {
/*
@@ -417,7 +430,7 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
*/
KASSERT(inm->in6m_refcount >= 1,
("%s: bad refcount %d", __func__, inm->in6m_refcount));
- ++inm->in6m_refcount;
+ in6m_acquire_locked(inm);
*pinm = inm;
goto out_locked;
}
@@ -431,10 +444,12 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
* Check if a link-layer group is already associated
* with this network-layer group on the given ifnet.
*/
+ IN6_MULTI_LIST_UNLOCK();
IF_ADDR_WUNLOCK(ifp);
error = if_addmulti(ifp, (struct sockaddr *)&gsin6, &ifma);
if (error != 0)
return (error);
+ IN6_MULTI_LIST_LOCK();
IF_ADDR_WLOCK(ifp);
/*
@@ -457,7 +472,7 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
panic("%s: ifma %p is inconsistent with %p (%p)",
__func__, ifma, inm, group);
#endif
- ++inm->in6m_refcount;
+ in6m_acquire_locked(inm);
*pinm = inm;
goto out_locked;
}
@@ -474,6 +489,7 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
*/
inm = malloc(sizeof(*inm), M_IP6MADDR, M_NOWAIT | M_ZERO);
if (inm == NULL) {
+ IN6_MULTI_LIST_UNLOCK();
IF_ADDR_WUNLOCK(ifp);
if_delmulti_ifma(ifma);
return (ENOMEM);
@@ -493,7 +509,8 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group,
ifma->ifma_protospec = inm;
*pinm = inm;
-out_locked:
+ out_locked:
+ IN6_MULTI_LIST_UNLOCK();
IF_ADDR_WUNLOCK(ifp);
return (error);
}
@@ -504,36 +521,139 @@ out_locked:
* If the refcount drops to 0, free the in6_multi record and
* delete the underlying link-layer membership.
*/
-void
-in6m_release_locked(struct in6_multi *inm)
+static void
+in6m_release(struct in6_multi *inm)
{
struct ifmultiaddr *ifma;
-
- IN6_MULTI_LOCK_ASSERT();
+ struct ifnet *ifp;
CTR2(KTR_MLD, "%s: refcount is %d", __func__, inm->in6m_refcount);
- if (--inm->in6m_refcount > 0) {
- CTR2(KTR_MLD, "%s: refcount is now %d", __func__,
- inm->in6m_refcount);
- return;
- }
-
+ MPASS(inm->in6m_refcount == 0);
CTR2(KTR_MLD, "%s: freeing inm %p", __func__, inm);
ifma = inm->in6m_ifma;
+ ifp = inm->in6m_ifp;
+ MPASS(ifma->ifma_llifma == NULL);
/* XXX this access is not covered by IF_ADDR_LOCK */
CTR2(KTR_MLD, "%s: purging ifma %p", __func__, ifma);
- KASSERT(ifma->ifma_protospec == inm,
- ("%s: ifma_protospec != inm", __func__));
- ifma->ifma_protospec = NULL;
+ KASSERT(ifma->ifma_protospec == NULL,
+ ("%s: ifma_protospec != NULL", __func__));
- in6m_purge(inm);
+ if (ifp != NULL) {
+ CURVNET_SET(ifp->if_vnet);
+ in6m_purge(inm);
+ free(inm, M_IP6MADDR);
+ if_delmulti_ifma_flags(ifma, 1);
+ CURVNET_RESTORE();
+ if_rele(ifp);
+ } else {
+ in6m_purge(inm);
+ free(inm, M_IP6MADDR);
+ if_delmulti_ifma_flags(ifma, 1);
+ }
+}
+
+static struct grouptask free_gtask;
+static struct in6_multi_head in6m_free_list;
+static void in6m_release_task(void *arg __unused);
+static void in6m_init(void)
+{
+ SLIST_INIT(&in6m_free_list);
+ taskqgroup_config_gtask_init(NULL, &free_gtask, in6m_release_task, "in6m release task");
+}
- free(inm, M_IP6MADDR);
+SYSINIT(in6m_init, SI_SUB_SMP + 1, SI_ORDER_FIRST,
+ in6m_init, NULL);
- if_delmulti_ifma(ifma);
+
+void
+in6m_release_list_deferred(struct in6_multi_head *inmh)
+{
+ if (SLIST_EMPTY(inmh))
+ return;
+ mtx_lock(&in6_multi_free_mtx);
+ SLIST_CONCAT(&in6m_free_list, inmh, in6_multi, in6m_nrele);
+ mtx_unlock(&in6_multi_free_mtx);
+ GROUPTASK_ENQUEUE(&free_gtask);
+}
+
+void
+in6m_disconnect(struct in6_multi *inm)
+{
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct in6_ifaddr *ifa6;
+ struct in6_multi_mship *imm, *imm_tmp;
+ struct ifmultiaddr *ifma, *ll_ifma;
+
+ ifp = inm->in6m_ifp;
+ IF_ADDR_WLOCK_ASSERT(ifp);
+ ifma = inm->in6m_ifma;
+
+ if_ref(ifp);
+ CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
+ MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname);
+ if ((ll_ifma = ifma->ifma_llifma) != NULL) {
+ MPASS(ifma != ll_ifma);
+ ifma->ifma_llifma = NULL;
+ MPASS(ll_ifma->ifma_llifma == NULL);
+ MPASS(ll_ifma->ifma_ifp == ifp);
+ if (--ll_ifma->ifma_refcount == 0) {
+ ifma6_restart = true;
+ CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
+ MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname);
+ if_freemulti(ll_ifma);
+ }
+ }
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ifa6 = (void *)ifa;
+ LIST_FOREACH_SAFE(imm, &ifa6->ia6_memberships,
+ i6mm_chain, imm_tmp) {
+ if (inm == imm->i6mm_maddr) {
+ LIST_REMOVE(imm, i6mm_chain);
+ free(imm, M_IP6MADDR);
+ }
+ }
+ }
+}
+
+void
+in6m_release_deferred(struct in6_multi *inm)
+{
+ struct in6_multi_head tmp;
+
+ IN6_MULTI_LIST_LOCK_ASSERT();
+ KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm));
+ if (--inm->in6m_refcount == 0) {
+ in6m_disconnect(inm);
+ SLIST_INIT(&tmp);
+ inm->in6m_ifma->ifma_protospec = NULL;
+ MPASS(inm->in6m_ifma->ifma_llifma == NULL);
+ SLIST_INSERT_HEAD(&tmp, inm, in6m_nrele);
+ in6m_release_list_deferred(&tmp);
+ }
+}
+
+static void
+in6m_release_task(void *arg __unused)
+{
+ struct in6_multi_head in6m_free_tmp;
+ struct in6_multi *inm, *tinm;
+
+ SLIST_INIT(&in6m_free_tmp);
+ mtx_lock(&in6_multi_free_mtx);
+ SLIST_CONCAT(&in6m_free_tmp, &in6m_free_list, in6_multi, in6m_nrele);
+ mtx_unlock(&in6_multi_free_mtx);
+ IN6_MULTI_LOCK();
+ SLIST_FOREACH_SAFE(inm, &in6m_free_tmp, in6m_nrele, tinm) {
+ SLIST_REMOVE_HEAD(&in6m_free_tmp, in6m_nrele);
+ in6m_release(inm);
+ }
+ IN6_MULTI_UNLOCK();
}
/*
@@ -546,7 +666,7 @@ in6m_clear_recorded(struct in6_multi *inm)
{
struct ip6_msource *ims;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
RB_FOREACH(ims, ip6_msource_tree, &inm->in6m_srcs) {
if (ims->im6s_stp) {
@@ -586,7 +706,7 @@ in6m_record_source(struct in6_multi *inm, const struct in6_addr *addr)
struct ip6_msource find;
struct ip6_msource *ims, *nims;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
find.im6s_addr = *addr;
ims = RB_FIND(ip6_msource_tree, &inm->in6m_srcs, &find);
@@ -913,6 +1033,7 @@ in6m_merge(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
schanged = 0;
error = 0;
nsrc1 = nsrc0 = 0;
+ IN6_MULTI_LIST_LOCK_ASSERT();
/*
* Update the source filters first, as this may fail.
@@ -1089,65 +1210,16 @@ in6m_purge(struct in6_multi *inm)
*
* SMPng: Assume no mc locks held by caller.
*/
-struct in6_multi_mship *
-in6_joingroup(struct ifnet *ifp, struct in6_addr *mcaddr,
- int *errorp, int delay)
-{
- struct in6_multi_mship *imm;
- int error;
-
- imm = malloc(sizeof(*imm), M_IP6MADDR, M_NOWAIT);
- if (imm == NULL) {
- *errorp = ENOBUFS;
- return (NULL);
- }
-
- delay = (delay * PR_FASTHZ) / hz;
-
- error = in6_mc_join(ifp, mcaddr, NULL, &imm->i6mm_maddr, delay);
- if (error) {
- *errorp = error;
- free(imm, M_IP6MADDR);
- return (NULL);
- }
-
- return (imm);
-}
-
-/*
- * Leave a multicast address w/o sources.
- * KAME compatibility entry point.
- *
- * SMPng: Assume no mc locks held by caller.
- */
-int
-in6_leavegroup(struct in6_multi_mship *imm)
-{
-
- if (imm->i6mm_maddr != NULL)
- in6_mc_leave(imm->i6mm_maddr, NULL);
- free(imm, M_IP6MADDR);
- return 0;
-}
-
-/*
- * Join a multicast group; unlocked entry point.
- *
- * SMPng: XXX: in6_mc_join() is called from in6_control() when upper
- * locks are not held. Fortunately, ifp is unlikely to have been detached
- * at this point, so we assume it's OK to recurse.
- */
int
-in6_mc_join(struct ifnet *ifp, const struct in6_addr *mcaddr,
+in6_joingroup(struct ifnet *ifp, const struct in6_addr *mcaddr,
/*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
const int delay)
{
int error;
IN6_MULTI_LOCK();
- error = in6_mc_join_locked(ifp, mcaddr, imf, pinm, delay);
+ error = in6_joingroup_locked(ifp, mcaddr, NULL, pinm, delay);
IN6_MULTI_UNLOCK();
-
return (error);
}
@@ -1161,12 +1233,13 @@ in6_mc_join(struct ifnet *ifp, const struct in6_addr *mcaddr,
* code is returned.
*/
int
-in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr,
+in6_joingroup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr,
/*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
const int delay)
{
struct in6_mfilter timf;
struct in6_multi *inm;
+ struct ifmultiaddr *ifma;
int error;
#ifdef KTR
char ip6tbuf[INET6_ADDRSTRLEN];
@@ -1187,6 +1260,7 @@ in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr,
#endif
IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_UNLOCK_ASSERT();
CTR4(KTR_MLD, "%s: join %s on %p(%s))", __func__,
ip6_sprintf(ip6tbuf, mcaddr), ifp, if_name(ifp));
@@ -1202,13 +1276,13 @@ in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr,
im6f_init(&timf, MCAST_UNDEFINED, MCAST_EXCLUDE);
imf = &timf;
}
-
- error = in6_mc_get(ifp, mcaddr, &inm);
+ error = in6_getmulti(ifp, mcaddr, &inm);
if (error) {
- CTR1(KTR_MLD, "%s: in6_mc_get() failure", __func__);
+ CTR1(KTR_MLD, "%s: in6_getmulti() failure", __func__);
return (error);
}
+ IN6_MULTI_LIST_LOCK();
CTR1(KTR_MLD, "%s: merge inm state", __func__);
error = in6m_merge(inm, imf);
if (error) {
@@ -1226,11 +1300,19 @@ in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr,
out_in6m_release:
if (error) {
CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
- in6m_release_locked(inm);
+ IF_ADDR_RLOCK(ifp);
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_protospec == inm) {
+ ifma->ifma_protospec = NULL;
+ break;
+ }
+ }
+ in6m_release_deferred(inm);
+ IF_ADDR_RUNLOCK(ifp);
} else {
*pinm = inm;
}
-
+ IN6_MULTI_LIST_UNLOCK();
return (error);
}
@@ -1238,14 +1320,13 @@ out_in6m_release:
* Leave a multicast group; unlocked entry point.
*/
int
-in6_mc_leave(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
+in6_leavegroup(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
{
int error;
IN6_MULTI_LOCK();
- error = in6_mc_leave_locked(inm, imf);
+ error = in6_leavegroup_locked(inm, imf);
IN6_MULTI_UNLOCK();
-
return (error);
}
@@ -1263,9 +1344,10 @@ in6_mc_leave(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
* makes a state change downcall into MLD.
*/
int
-in6_mc_leave_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
+in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
{
struct in6_mfilter timf;
+ struct ifnet *ifp;
int error;
#ifdef KTR
char ip6tbuf[INET6_ADDRSTRLEN];
@@ -1296,6 +1378,9 @@ in6_mc_leave_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
* to be allocated, and there is no opportunity to roll back
* the transaction, it MUST NOT fail.
*/
+
+ ifp = inm->in6m_ifp;
+ IN6_MULTI_LIST_LOCK();
CTR1(KTR_MLD, "%s: merge inm state", __func__);
error = in6m_merge(inm, imf);
KASSERT(error == 0, ("%s: failed to merge inm state", __func__));
@@ -1306,11 +1391,17 @@ in6_mc_leave_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
CTR1(KTR_MLD, "%s: failed mld downcall", __func__);
CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
- in6m_release_locked(inm);
+ if (ifp)
+ IF_ADDR_WLOCK(ifp);
+ in6m_release_deferred(inm);
+ if (ifp)
+ IF_ADDR_WUNLOCK(ifp);
+ IN6_MULTI_LIST_UNLOCK();
return (error);
}
+
/*
* Block or unblock an ASM multicast source on an inpcb.
* This implements the delta-based API described in RFC 3678.
@@ -1448,8 +1539,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt)
/*
* Begin state merge transaction at MLD layer.
*/
- IN6_MULTI_LOCK();
-
+ IN6_MULTI_LIST_LOCK();
CTR1(KTR_MLD, "%s: merge inm state", __func__);
error = in6m_merge(inm, imf);
if (error)
@@ -1461,7 +1551,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt)
CTR1(KTR_MLD, "%s: failed mld downcall", __func__);
}
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
out_im6f_rollback:
if (error)
@@ -1530,22 +1620,36 @@ in6p_findmoptions(struct inpcb *inp)
* Discard the IPv6 multicast options (and source filters).
*
* SMPng: NOTE: assumes INP write lock is held.
+ *
+ * XXX can all be safely deferred to epoch_call
+ *
*/
-void
-ip6_freemoptions(struct ip6_moptions *imo)
+
+static void
+inp_gcmoptions(epoch_context_t ctx)
{
+ struct ip6_moptions *imo;
struct in6_mfilter *imf;
+ struct in6_multi *inm;
+ struct ifnet *ifp;
size_t idx, nmships;
- KASSERT(imo != NULL, ("%s: ip6_moptions is NULL", __func__));
+ imo = __containerof(ctx, struct ip6_moptions, imo6_epoch_ctx);
nmships = imo->im6o_num_memberships;
for (idx = 0; idx < nmships; ++idx) {
imf = imo->im6o_mfilters ? &imo->im6o_mfilters[idx] : NULL;
if (imf)
im6f_leave(imf);
- /* XXX this will thrash the lock(s) */
- (void)in6_mc_leave(imo->im6o_membership[idx], imf);
+ inm = imo->im6o_membership[idx];
+ ifp = inm->in6m_ifp;
+ if (ifp != NULL) {
+ CURVNET_SET(ifp->if_vnet);
+ (void)in6_leavegroup(inm, imf);
+ CURVNET_RESTORE();
+ } else {
+ (void)in6_leavegroup(inm, imf);
+ }
if (imf)
im6f_purge(imf);
}
@@ -1556,6 +1660,14 @@ ip6_freemoptions(struct ip6_moptions *imo)
free(imo, M_IP6MOPTS);
}
+void
+ip6_freemoptions(struct ip6_moptions *imo)
+{
+ if (imo == NULL)
+ return;
+ epoch_call(net_epoch_preempt, &imo->imo6_epoch_ctx, inp_gcmoptions);
+}
+
/*
* Atomically get source filters on a socket for an IPv6 multicast group.
* Called with INP lock held; returns with lock released.
@@ -2036,10 +2148,12 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
/*
* Begin state merge transaction at MLD layer.
*/
+ in_pcbref(inp);
+ INP_WUNLOCK(inp);
IN6_MULTI_LOCK();
if (is_new) {
- error = in6_mc_join_locked(ifp, &gsa->sin6.sin6_addr, imf,
+ error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf,
&inm, 0);
if (error) {
IN6_MULTI_UNLOCK();
@@ -2048,6 +2162,7 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
imo->im6o_membership[idx] = inm;
} else {
CTR1(KTR_MLD, "%s: merge inm state", __func__);
+ IN6_MULTI_LIST_LOCK();
error = in6m_merge(inm, imf);
if (error)
CTR1(KTR_MLD, "%s: failed to merge inm state",
@@ -2059,10 +2174,13 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
CTR1(KTR_MLD, "%s: failed mld downcall",
__func__);
}
+ IN6_MULTI_LIST_UNLOCK();
}
IN6_MULTI_UNLOCK();
- INP_WLOCK_ASSERT(inp);
+ INP_WLOCK(inp);
+ if (in_pcbrele_wlocked(inp))
+ return (ENXIO);
if (error) {
im6f_rollback(imf);
if (is_new)
@@ -2277,6 +2395,8 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt)
/*
* Begin state merge transaction at MLD layer.
*/
+ in_pcbref(inp);
+ INP_WUNLOCK(inp);
IN6_MULTI_LOCK();
if (is_final) {
@@ -2284,9 +2404,10 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt)
* Give up the multicast address record to which
* the membership points.
*/
- (void)in6_mc_leave_locked(inm, imf);
+ (void)in6_leavegroup_locked(inm, imf);
} else {
CTR1(KTR_MLD, "%s: merge inm state", __func__);
+ IN6_MULTI_LIST_LOCK();
error = in6m_merge(inm, imf);
if (error)
CTR1(KTR_MLD, "%s: failed to merge inm state",
@@ -2298,9 +2419,13 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt)
CTR1(KTR_MLD, "%s: failed mld downcall",
__func__);
}
+ IN6_MULTI_LIST_UNLOCK();
}
IN6_MULTI_UNLOCK();
+ INP_WLOCK(inp);
+ if (in_pcbrele_wlocked(inp))
+ return (ENXIO);
if (error)
im6f_rollback(imf);
@@ -2507,7 +2632,7 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
goto out_im6f_rollback;
INP_WLOCK_ASSERT(inp);
- IN6_MULTI_LOCK();
+ IN6_MULTI_LIST_LOCK();
/*
* Begin state merge transaction at MLD layer.
@@ -2523,7 +2648,7 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
CTR1(KTR_MLD, "%s: failed mld downcall", __func__);
}
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
out_im6f_rollback:
if (error)
@@ -2714,9 +2839,9 @@ sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS)
return (retval);
IN6_MULTI_LOCK();
-
+ IN6_MULTI_LIST_LOCK();
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_INET6 ||
ifma->ifma_protospec == NULL)
continue;
@@ -2746,6 +2871,7 @@ sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS)
}
IF_ADDR_RUNLOCK(ifp);
+ IN6_MULTI_LIST_UNLOCK();
IN6_MULTI_UNLOCK();
return (retval);
diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c
index a4bbd6a9..488cca86 100644
--- a/freebsd/sys/netinet6/in6_pcb.c
+++ b/freebsd/sys/netinet6/in6_pcb.c
@@ -134,7 +134,7 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam,
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(pcbinfo);
- if (TAILQ_EMPTY(&V_in6_ifaddrhead)) /* XXX broken! */
+ if (CK_STAILQ_EMPTY(&V_in6_ifaddrhead)) /* XXX broken! */
return (EADDRNOTAVAIL);
if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
return (EINVAL);
@@ -176,9 +176,11 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam,
struct ifaddr *ifa;
sin6->sin6_port = 0; /* yech... */
+ NET_EPOCH_ENTER();
if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) ==
NULL &&
(inp->inp_flags & INP_BINDANY) == 0) {
+ NET_EPOCH_EXIT();
return (EADDRNOTAVAIL);
}
@@ -191,11 +193,10 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam,
if (ifa != NULL &&
((struct in6_ifaddr *)ifa)->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
- ifa_free(ifa);
+ NET_EPOCH_EXIT();
return (EADDRNOTAVAIL);
}
- if (ifa != NULL)
- ifa_free(ifa);
+ NET_EPOCH_EXIT();
}
if (lport) {
struct inpcb *t;
@@ -363,7 +364,7 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr *nam,
if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0)
return(error);
- if (!TAILQ_EMPTY(&V_in6_ifaddrhead)) {
+ if (!CK_STAILQ_EMPTY(&V_in6_ifaddrhead)) {
/*
* If the destination address is UNSPECIFIED addr,
* use the loopback addr, e.g ::1.
@@ -819,8 +820,7 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp)
for (i = 0; i < im6o->im6o_num_memberships; i++) {
if (im6o->im6o_membership[i]->in6m_ifp ==
ifp) {
- in6_mc_leave(im6o->im6o_membership[i],
- NULL);
+ in6_leavegroup(im6o->im6o_membership[i], NULL);
gap++;
} else if (gap != 0) {
im6o->im6o_membership[i - gap] =
diff --git a/freebsd/sys/netinet6/in6_proto.c b/freebsd/sys/netinet6/in6_proto.c
index 55fbbe80..756ea48b 100644
--- a/freebsd/sys/netinet6/in6_proto.c
+++ b/freebsd/sys/netinet6/in6_proto.c
@@ -284,7 +284,6 @@ struct protosw inet6sw[] = {
.pr_input = encap6_input,
.pr_output = rip6_output,
.pr_ctloutput = rip6_ctloutput,
- .pr_init = encap_init,
.pr_usrreqs = &rip6_usrreqs
},
#endif /* INET */
@@ -296,7 +295,6 @@ struct protosw inet6sw[] = {
.pr_input = encap6_input,
.pr_output = rip6_output,
.pr_ctloutput = rip6_ctloutput,
- .pr_init = encap_init,
.pr_usrreqs = &rip6_usrreqs
},
{
@@ -307,7 +305,6 @@ struct protosw inet6sw[] = {
.pr_input = encap6_input,
.pr_output = rip6_output,
.pr_ctloutput = rip6_ctloutput,
- .pr_init = encap_init,
.pr_usrreqs = &rip6_usrreqs
},
{
diff --git a/freebsd/sys/netinet6/in6_src.c b/freebsd/sys/netinet6/in6_src.c
index 5b110274..92f7df4e 100644
--- a/freebsd/sys/netinet6/in6_src.c
+++ b/freebsd/sys/netinet6/in6_src.c
@@ -311,7 +311,7 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
return (error);
IN6_IFADDR_RLOCK(&in6_ifa_tracker);
- TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
int new_scope = -1, new_matchlen = -1;
struct in6_addrpolicy *new_policy = NULL;
u_int32_t srczone, osrczone, dstzone;
diff --git a/freebsd/sys/netinet6/in6_var.h b/freebsd/sys/netinet6/in6_var.h
index 2e22d962..6b4fe1ab 100644
--- a/freebsd/sys/netinet6/in6_var.h
+++ b/freebsd/sys/netinet6/in6_var.h
@@ -100,6 +100,7 @@ struct nd_ifinfo;
struct scope6_id;
struct lltable;
struct mld_ifsoftc;
+struct in6_multi;
struct in6_ifextra {
counter_u64_t *in6_ifstat;
@@ -113,6 +114,10 @@ struct in6_ifextra {
#define LLTABLE6(ifp) (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->lltable)
#ifdef _KERNEL
+
+SLIST_HEAD(in6_multi_head, in6_multi);
+MALLOC_DECLARE(M_IP6MADDR);
+
struct in6_ifaddr {
struct ifaddr ia_ifa; /* protocol-independent info */
#define ia_ifp ia_ifa.ifa_ifp
@@ -122,7 +127,7 @@ struct in6_ifaddr {
struct sockaddr_in6 ia_dstaddr; /* space for destination addr */
struct sockaddr_in6 ia_prefixmask; /* prefix mask */
u_int32_t ia_plen; /* prefix length */
- TAILQ_ENTRY(in6_ifaddr) ia_link; /* list of IPv6 addresses */
+ CK_STAILQ_ENTRY(in6_ifaddr) ia_link; /* list of IPv6 addresses */
int ia6_flags;
struct in6_addrlifetime ia6_lifetime;
@@ -137,12 +142,12 @@ struct in6_ifaddr {
/* multicast addresses joined from the kernel */
LIST_HEAD(, in6_multi_mship) ia6_memberships;
/* entry in bucket of inet6 addresses */
- LIST_ENTRY(in6_ifaddr) ia6_hash;
+ CK_LIST_ENTRY(in6_ifaddr) ia6_hash;
};
/* List of in6_ifaddr's. */
-TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr);
-LIST_HEAD(in6_ifaddrlisthead, in6_ifaddr);
+CK_STAILQ_HEAD(in6_ifaddrhead, in6_ifaddr);
+CK_LIST_HEAD(in6_ifaddrlisthead, in6_ifaddr);
#endif /* _KERNEL */
/* control structure to manage address selection policy */
@@ -630,7 +635,6 @@ struct in6_multi_mship {
* w/o breaking the ABI for ifmcstat.
*/
struct in6_multi {
- LIST_ENTRY(in6_multi) in6m_entry; /* list glue */
struct in6_addr in6m_addr; /* IPv6 multicast address */
struct ifnet *in6m_ifp; /* back pointer to ifnet */
struct ifmultiaddr *in6m_ifma; /* back pointer to ifmultiaddr */
@@ -666,6 +670,8 @@ struct in6_multi {
} in6m_st[2]; /* state at t0, t1 */
};
+void in6m_disconnect(struct in6_multi *inm);
+extern int ifma6_restart;
/*
* Helper function to derive the filter mode on a source entry
* from its internal counters. Predicates are:
@@ -694,11 +700,19 @@ im6s_get_mode(const struct in6_multi *inm, const struct ip6_msource *ims,
* consumers of IN_*_MULTI() macros should acquire the locks before
* calling them; users of the in_{add,del}multi() functions should not.
*/
-extern struct mtx in6_multi_mtx;
-#define IN6_MULTI_LOCK() mtx_lock(&in6_multi_mtx)
-#define IN6_MULTI_UNLOCK() mtx_unlock(&in6_multi_mtx)
-#define IN6_MULTI_LOCK_ASSERT() mtx_assert(&in6_multi_mtx, MA_OWNED)
-#define IN6_MULTI_UNLOCK_ASSERT() mtx_assert(&in6_multi_mtx, MA_NOTOWNED)
+extern struct mtx in6_multi_list_mtx;
+extern struct sx in6_multi_sx;
+
+#define IN6_MULTI_LIST_LOCK() mtx_lock(&in6_multi_list_mtx)
+#define IN6_MULTI_LIST_UNLOCK() mtx_unlock(&in6_multi_list_mtx)
+#define IN6_MULTI_LIST_LOCK_ASSERT() mtx_assert(&in6_multi_list_mtx, MA_OWNED)
+#define IN6_MULTI_LIST_UNLOCK_ASSERT() mtx_assert(&in6_multi_list_mtx, MA_NOTOWNED)
+
+#define IN6_MULTI_LOCK() sx_xlock(&in6_multi_sx)
+#define IN6_MULTI_UNLOCK() sx_xunlock(&in6_multi_sx)
+#define IN6_MULTI_LOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XLOCKED)
+#define IN6_MULTI_UNLOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XUNLOCKED)
+
/*
* Look up an in6_multi record for an IPv6 multicast address
@@ -713,13 +727,12 @@ in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr)
struct ifmultiaddr *ifma;
struct in6_multi *inm;
- IN6_MULTI_LOCK_ASSERT();
- IF_ADDR_LOCK_ASSERT(ifp);
-
inm = NULL;
- TAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
+ CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
if (ifma->ifma_addr->sa_family == AF_INET6) {
inm = (struct in6_multi *)ifma->ifma_protospec;
+ if (inm == NULL)
+ continue;
if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr))
break;
inm = NULL;
@@ -738,11 +751,11 @@ in6m_lookup(struct ifnet *ifp, const struct in6_addr *mcaddr)
{
struct in6_multi *inm;
- IN6_MULTI_LOCK();
+ IN6_MULTI_LIST_LOCK();
IF_ADDR_RLOCK(ifp);
inm = in6m_lookup_locked(ifp, mcaddr);
IF_ADDR_RUNLOCK(ifp);
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
return (inm);
}
@@ -752,36 +765,55 @@ static __inline void
in6m_acquire_locked(struct in6_multi *inm)
{
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
++inm->in6m_refcount;
}
+static __inline void
+in6m_acquire(struct in6_multi *inm)
+{
+ IN6_MULTI_LIST_LOCK();
+ in6m_acquire_locked(inm);
+ IN6_MULTI_LIST_UNLOCK();
+}
+
+static __inline void
+in6m_rele_locked(struct in6_multi_head *inmh, struct in6_multi *inm)
+{
+ KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm));
+ IN6_MULTI_LIST_LOCK_ASSERT();
+
+ if (--inm->in6m_refcount == 0) {
+ in6m_disconnect(inm);
+ inm->in6m_ifma->ifma_protospec = NULL;
+ MPASS(inm->in6m_ifma->ifma_llifma == NULL);
+ SLIST_INSERT_HEAD(inmh, inm, in6m_nrele);
+ }
+}
+
struct ip6_moptions;
struct sockopt;
+struct inpcbinfo;
/* Multicast KPIs. */
int im6o_mc_filter(const struct ip6_moptions *, const struct ifnet *,
const struct sockaddr *, const struct sockaddr *);
-int in6_mc_join(struct ifnet *, const struct in6_addr *,
+int in6_joingroup(struct ifnet *, const struct in6_addr *,
struct in6_mfilter *, struct in6_multi **, int);
-int in6_mc_join_locked(struct ifnet *, const struct in6_addr *,
+int in6_joingroup_locked(struct ifnet *, const struct in6_addr *,
struct in6_mfilter *, struct in6_multi **, int);
-int in6_mc_leave(struct in6_multi *, struct in6_mfilter *);
-int in6_mc_leave_locked(struct in6_multi *, struct in6_mfilter *);
+int in6_leavegroup(struct in6_multi *, struct in6_mfilter *);
+int in6_leavegroup_locked(struct in6_multi *, struct in6_mfilter *);
void in6m_clear_recorded(struct in6_multi *);
void in6m_commit(struct in6_multi *);
void in6m_print(const struct in6_multi *);
int in6m_record_source(struct in6_multi *, const struct in6_addr *);
-void in6m_release_locked(struct in6_multi *);
+void in6m_release_deferred(struct in6_multi *);
+void in6m_release_list_deferred(struct in6_multi_head *);
void ip6_freemoptions(struct ip6_moptions *);
int ip6_getmoptions(struct inpcb *, struct sockopt *);
int ip6_setmoptions(struct inpcb *, struct sockopt *);
-/* Legacy KAME multicast KPIs. */
-struct in6_multi_mship *
- in6_joingroup(struct ifnet *, struct in6_addr *, int *, int);
-int in6_leavegroup(struct in6_multi_mship *);
-
/* flags to in6_update_ifa */
#define IN6_IFAUPDATE_DADDELAY 0x1 /* first time to configure an address */
diff --git a/freebsd/sys/netinet6/ip6_fastfwd.c b/freebsd/sys/netinet6/ip6_fastfwd.c
index 056f9315..f63c51bf 100644
--- a/freebsd/sys/netinet6/ip6_fastfwd.c
+++ b/freebsd/sys/netinet6/ip6_fastfwd.c
@@ -99,7 +99,8 @@ ip6_tryforward(struct mbuf *m)
* Fallback conditions to ip6_input for slow path processing.
*/
ip6 = mtod(m, struct ip6_hdr *);
- if (ip6->ip6_nxt == IPPROTO_HOPOPTS ||
+ if ((m->m_flags & (M_BCAST | M_MCAST)) != 0 ||
+ ip6->ip6_nxt == IPPROTO_HOPOPTS ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) ||
@@ -196,12 +197,19 @@ passin:
in6_ifstat_inc(rcvif, ifs6_in_noroute);
goto dropin;
}
+ if (!PFIL_HOOKED(&V_inet6_pfil_hook)) {
+ if (m->m_pkthdr.len > nh.nh_mtu) {
+ in6_ifstat_inc(nh.nh_ifp, ifs6_in_toobig);
+ icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu);
+ m = NULL;
+ goto dropout;
+ }
+ goto passout;
+ }
/*
* Outgoing packet firewall processing.
*/
- if (!PFIL_HOOKED(&V_inet6_pfil_hook))
- goto passout;
if (pfil_run_hooks(&V_inet6_pfil_hook, &m, nh.nh_ifp, PFIL_OUT,
PFIL_FWD, NULL) != 0 || m == NULL)
goto dropout;
diff --git a/freebsd/sys/netinet6/ip6_input.c b/freebsd/sys/netinet6/ip6_input.c
index 7e1007e3..77e32da8 100644
--- a/freebsd/sys/netinet6/ip6_input.c
+++ b/freebsd/sys/netinet6/ip6_input.c
@@ -224,7 +224,7 @@ ip6_init(void)
TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv);
TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr);
- TAILQ_INIT(&V_in6_ifaddrhead);
+ CK_STAILQ_INIT(&V_in6_ifaddrhead);
V_in6_ifaddrhashtbl = hashinit(IN6ADDR_NHASH, M_IFADDR,
&V_in6_ifaddrhmask);
@@ -379,10 +379,10 @@ ip6_destroy(void *unused __unused)
/* Cleanup addresses. */
IFNET_RLOCK();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
/* Cannot lock here - lock recursion. */
/* IF_ADDR_LOCK(ifp); */
- TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
+ CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
diff --git a/freebsd/sys/netinet6/ip6_var.h b/freebsd/sys/netinet6/ip6_var.h
index 42c235d1..74b5f89c 100644
--- a/freebsd/sys/netinet6/ip6_var.h
+++ b/freebsd/sys/netinet6/ip6_var.h
@@ -66,6 +66,8 @@
#ifndef _NETINET6_IP6_VAR_H_
#define _NETINET6_IP6_VAR_H_
+#include <sys/epoch.h>
+
/*
* IP6 reassembly queue structure. Each fragment
* being reassembled is attached to one of these structures.
@@ -121,6 +123,7 @@ struct ip6_moptions {
u_short im6o_max_memberships; /* max memberships this socket */
struct in6_multi **im6o_membership; /* group memberships */
struct in6_mfilter *im6o_mfilters; /* source filters */
+ struct epoch_context imo6_epoch_ctx;
};
/*
diff --git a/freebsd/sys/netinet6/mld6.c b/freebsd/sys/netinet6/mld6.c
index c1dff0c3..0c82d5ff 100644
--- a/freebsd/sys/netinet6/mld6.c
+++ b/freebsd/sys/netinet6/mld6.c
@@ -126,7 +126,7 @@ static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *,
/*const*/ struct mld_hdr *);
static int mld_v1_input_report(struct ifnet *, const struct ip6_hdr *,
/*const*/ struct mld_hdr *);
-static void mld_v1_process_group_timer(struct mld_ifsoftc *,
+static void mld_v1_process_group_timer(struct in6_multi_head *,
struct in6_multi *);
static void mld_v1_process_querier_timers(struct mld_ifsoftc *);
static int mld_v1_transmit_report(struct in6_multi *, const int);
@@ -144,7 +144,7 @@ static int mld_v2_input_query(struct ifnet *, const struct ip6_hdr *,
struct mbuf *, const int, const int);
static int mld_v2_merge_state_changes(struct in6_multi *,
struct mbufq *);
-static void mld_v2_process_group_timers(struct mld_ifsoftc *,
+static void mld_v2_process_group_timers(struct in6_multi_head *,
struct mbufq *, struct mbufq *,
struct in6_multi *, const int);
static int mld_v2_process_group_query(struct in6_multi *,
@@ -379,6 +379,7 @@ sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS)
return (error);
IN6_MULTI_LOCK();
+ IN6_MULTI_LIST_LOCK();
MLD_LOCK();
if (name[0] <= 0 || name[0] > V_if_index) {
@@ -411,6 +412,7 @@ sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS)
out_locked:
MLD_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
IN6_MULTI_UNLOCK();
return (error);
}
@@ -510,7 +512,6 @@ mli_alloc_locked(/*const*/ struct ifnet *ifp)
mli->mli_qi = MLD_QI_INIT;
mli->mli_qri = MLD_QRI_INIT;
mli->mli_uri = MLD_URI_INIT;
- SLIST_INIT(&mli->mli_relinmhead);
mbufq_init(&mli->mli_gq, MLD_MAX_RESPONSE_PACKETS);
LIST_INSERT_HEAD(&V_mli_head, mli, mli_link);
@@ -537,38 +538,41 @@ void
mld_ifdetach(struct ifnet *ifp)
{
struct mld_ifsoftc *mli;
- struct ifmultiaddr *ifma;
- struct in6_multi *inm, *tinm;
+ struct ifmultiaddr *ifma, *next;
+ struct in6_multi *inm;
+ struct in6_multi_head inmh;
CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp,
if_name(ifp));
- IN6_MULTI_LOCK_ASSERT();
+ SLIST_INIT(&inmh);
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK();
mli = MLD_IFINFO(ifp);
if (mli->mli_version == MLD_VERSION_2) {
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ IF_ADDR_WLOCK(ifp);
+ restart:
+ CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
if (ifma->ifma_addr->sa_family != AF_INET6 ||
ifma->ifma_protospec == NULL)
continue;
inm = (struct in6_multi *)ifma->ifma_protospec;
if (inm->in6m_state == MLD_LEAVING_MEMBER) {
- SLIST_INSERT_HEAD(&mli->mli_relinmhead,
- inm, in6m_nrele);
+ in6m_rele_locked(&inmh, inm);
+ ifma->ifma_protospec = NULL;
}
in6m_clear_recorded(inm);
+ if (__predict_false(ifma6_restart)) {
+ ifma6_restart = false;
+ goto restart;
+ }
}
- IF_ADDR_RUNLOCK(ifp);
- SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, in6m_nrele,
- tinm) {
- SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele);
- in6m_release_locked(inm);
- }
+ IF_ADDR_WUNLOCK(ifp);
}
MLD_UNLOCK();
+ in6m_release_list_deferred(&inmh);
}
/*
@@ -608,10 +612,6 @@ mli_delete_locked(const struct ifnet *ifp)
LIST_REMOVE(mli, mli_link);
- KASSERT(SLIST_EMPTY(&mli->mli_relinmhead),
- ("%s: there are dangling in_multi references",
- __func__));
-
free(mli, M_MLD);
return;
}
@@ -682,7 +682,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
in6_setscope(&mld->mld_addr, ifp, NULL);
}
- IN6_MULTI_LOCK();
+ IN6_MULTI_LIST_LOCK();
MLD_LOCK();
/*
@@ -703,8 +703,8 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
* interface, kick the report timer.
*/
CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)",
- ifp, if_name(ifp));
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ ifp, if_name(ifp));
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_INET6 ||
ifma->ifma_protospec == NULL)
continue;
@@ -730,7 +730,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
IF_ADDR_RUNLOCK(ifp);
MLD_UNLOCK();
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
return (0);
}
@@ -761,7 +761,7 @@ mld_v1_update_group(struct in6_multi *inm, const int timer)
ip6_sprintf(ip6tbuf, &inm->in6m_addr),
if_name(inm->in6m_ifp), timer);
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
switch (inm->in6m_state) {
case MLD_NOT_MEMBER:
@@ -884,7 +884,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
in6_setscope(&mld->mld_addr, ifp, NULL);
}
- IN6_MULTI_LOCK();
+ IN6_MULTI_LIST_LOCK();
MLD_LOCK();
mli = MLD_IFINFO(ifp);
@@ -967,7 +967,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
out_locked:
MLD_UNLOCK();
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
return (0);
}
@@ -985,7 +985,7 @@ mld_v2_process_group_query(struct in6_multi *inm, struct mld_ifsoftc *mli,
int retval;
uint16_t nsrc;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
retval = 0;
@@ -1170,7 +1170,7 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr))
in6_setscope(&mld->mld_addr, ifp, NULL);
- IN6_MULTI_LOCK();
+ IN6_MULTI_LIST_LOCK();
MLD_LOCK();
IF_ADDR_RLOCK(ifp);
@@ -1222,7 +1222,7 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
out_locked:
IF_ADDR_RUNLOCK(ifp);
MLD_UNLOCK();
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
/* XXX Clear embedded scope ID as userland won't expect it. */
in6_clearscope(&mld->mld_addr);
@@ -1333,8 +1333,9 @@ mld_fasttimo_vnet(void)
struct mbufq qrq; /* Query response packets */
struct ifnet *ifp;
struct mld_ifsoftc *mli;
- struct ifmultiaddr *ifma;
+ struct ifmultiaddr *ifma, *next;
struct in6_multi *inm, *tinm;
+ struct in6_multi_head inmh;
int uri_fasthz;
uri_fasthz = 0;
@@ -1349,7 +1350,8 @@ mld_fasttimo_vnet(void)
!V_state_change_timers_running6)
return;
- IN6_MULTI_LOCK();
+ SLIST_INIT(&inmh);
+ IN6_MULTI_LIST_LOCK();
MLD_LOCK();
/*
@@ -1393,23 +1395,28 @@ mld_fasttimo_vnet(void)
mbufq_init(&scq, MLD_MAX_STATE_CHANGE_PACKETS);
}
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ IF_ADDR_WLOCK(ifp);
+ restart:
+ CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
if (ifma->ifma_addr->sa_family != AF_INET6 ||
ifma->ifma_protospec == NULL)
continue;
inm = (struct in6_multi *)ifma->ifma_protospec;
switch (mli->mli_version) {
case MLD_VERSION_1:
- mld_v1_process_group_timer(mli, inm);
+ mld_v1_process_group_timer(&inmh, inm);
break;
case MLD_VERSION_2:
- mld_v2_process_group_timers(mli, &qrq,
+ mld_v2_process_group_timers(&inmh, &qrq,
&scq, inm, uri_fasthz);
break;
}
+ if (__predict_false(ifma6_restart)) {
+ ifma6_restart = false;
+ goto restart;
+ }
}
- IF_ADDR_RUNLOCK(ifp);
+ IF_ADDR_WUNLOCK(ifp);
switch (mli->mli_version) {
case MLD_VERSION_1:
@@ -1421,9 +1428,8 @@ mld_fasttimo_vnet(void)
* IF_ADDR_LOCK internally as well as
* ip6_output() to transmit a packet.
*/
- SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead,
- in6m_nrele, tinm) {
- SLIST_REMOVE_HEAD(&mli->mli_relinmhead,
+ SLIST_FOREACH_SAFE(inm, &inmh, in6m_nrele, tinm) {
+ SLIST_REMOVE_HEAD(&inmh,
in6m_nrele);
(void)mld_v1_transmit_report(inm,
MLD_LISTENER_REPORT);
@@ -1437,19 +1443,14 @@ mld_fasttimo_vnet(void)
* Free the in_multi reference(s) for
* this lifecycle.
*/
- SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead,
- in6m_nrele, tinm) {
- SLIST_REMOVE_HEAD(&mli->mli_relinmhead,
- in6m_nrele);
- in6m_release_locked(inm);
- }
+ in6m_release_list_deferred(&inmh);
break;
}
}
out_locked:
MLD_UNLOCK();
- IN6_MULTI_UNLOCK();
+ IN6_MULTI_LIST_UNLOCK();
}
/*
@@ -1457,11 +1458,11 @@ out_locked:
* Will update the global pending timer flags.
*/
static void
-mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm)
+mld_v1_process_group_timer(struct in6_multi_head *inmh, struct in6_multi *inm)
{
int report_timer_expired;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
if (inm->in6m_timer == 0) {
@@ -1484,8 +1485,7 @@ mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm)
case MLD_REPORTING_MEMBER:
if (report_timer_expired) {
inm->in6m_state = MLD_IDLE_MEMBER;
- SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm,
- in6m_nrele);
+ in6m_rele_locked(inmh, inm);
}
break;
case MLD_G_QUERY_PENDING_MEMBER:
@@ -1501,7 +1501,7 @@ mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm)
* Note: Unlocked read from mli.
*/
static void
-mld_v2_process_group_timers(struct mld_ifsoftc *mli,
+mld_v2_process_group_timers(struct in6_multi_head *inmh,
struct mbufq *qrq, struct mbufq *scq,
struct in6_multi *inm, const int uri_fasthz)
{
@@ -1511,7 +1511,7 @@ mld_v2_process_group_timers(struct mld_ifsoftc *mli,
char ip6tbuf[INET6_ADDRSTRLEN];
#endif
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
query_response_timer_expired = 0;
@@ -1609,8 +1609,7 @@ mld_v2_process_group_timers(struct mld_ifsoftc *mli,
if (inm->in6m_state == MLD_LEAVING_MEMBER &&
inm->in6m_scrv == 0) {
inm->in6m_state = MLD_NOT_MEMBER;
- SLIST_INSERT_HEAD(&mli->mli_relinmhead,
- inm, in6m_nrele);
+ in6m_rele_locked(inmh, inm);
}
}
break;
@@ -1654,14 +1653,16 @@ mld_set_version(struct mld_ifsoftc *mli, const int version)
static void
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
{
- struct ifmultiaddr *ifma;
+ struct ifmultiaddr *ifma, *next;
struct ifnet *ifp;
- struct in6_multi *inm, *tinm;
+ struct in6_multi *inm;
+ struct in6_multi_head inmh;
CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__,
mli->mli_ifp, if_name(mli->mli_ifp));
- IN6_MULTI_LOCK_ASSERT();
+ SLIST_INIT(&inmh);
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
/*
@@ -1677,8 +1678,9 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
ifp = mli->mli_ifp;
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ IF_ADDR_WLOCK(ifp);
+ restart:
+ CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
if (ifma->ifma_addr->sa_family != AF_INET6)
continue;
inm = (struct in6_multi *)ifma->ifma_protospec;
@@ -1696,8 +1698,8 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
* version, we need to release the final
* reference held for issuing the INCLUDE {}.
*/
- SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm,
- in6m_nrele);
+ in6m_rele_locked(&inmh, inm);
+ ifma->ifma_protospec = NULL;
/* FALLTHROUGH */
case MLD_G_QUERY_PENDING_MEMBER:
case MLD_SG_QUERY_PENDING_MEMBER:
@@ -1713,12 +1715,13 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
mbufq_drain(&inm->in6m_scq);
break;
}
+ if (__predict_false(ifma6_restart)) {
+ ifma6_restart = false;
+ goto restart;
+ }
}
- IF_ADDR_RUNLOCK(ifp);
- SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, in6m_nrele, tinm) {
- SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele);
- in6m_release_locked(inm);
- }
+ IF_ADDR_WUNLOCK(ifp);
+ in6m_release_list_deferred(&inmh);
}
/*
@@ -1790,7 +1793,7 @@ mld_v1_transmit_report(struct in6_multi *in6m, const int type)
struct mbuf *mh, *md;
struct mld_hdr *mld;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
ifp = in6m->in6m_ifp;
@@ -1881,7 +1884,7 @@ mld_change_state(struct in6_multi *inm, const int delay)
struct ifnet *ifp;
int error;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
error = 0;
@@ -1965,7 +1968,7 @@ mld_initial_join(struct in6_multi *inm, struct mld_ifsoftc *mli,
ifp = inm->in6m_ifp;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
KASSERT(mli && mli->mli_ifp == ifp, ("%s: inconsistent ifp", __func__));
@@ -1995,7 +1998,7 @@ mld_initial_join(struct in6_multi *inm, struct mld_ifsoftc *mli,
*/
if (mli->mli_version == MLD_VERSION_2 &&
inm->in6m_state == MLD_LEAVING_MEMBER)
- in6m_release_locked(inm);
+ in6m_release_deferred(inm);
inm->in6m_state = MLD_REPORTING_MEMBER;
@@ -2108,7 +2111,7 @@ mld_handle_state_change(struct in6_multi *inm, struct mld_ifsoftc *mli)
ifp = inm->in6m_ifp;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
KASSERT(mli && mli->mli_ifp == ifp,
@@ -2171,7 +2174,7 @@ mld_final_leave(struct in6_multi *inm, struct mld_ifsoftc *mli)
__func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr),
inm->in6m_ifp, if_name(inm->in6m_ifp));
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
switch (inm->in6m_state) {
@@ -2298,7 +2301,7 @@ mld_v2_enqueue_group_record(struct mbufq *mq, struct in6_multi *inm,
char ip6tbuf[INET6_ADDRSTRLEN];
#endif
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
ifp = inm->in6m_ifp;
is_filter_list_change = 0;
@@ -2681,7 +2684,7 @@ mld_v2_enqueue_filter_change(struct mbufq *mq, struct in6_multi *inm)
char ip6tbuf[INET6_ADDRSTRLEN];
#endif
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
if (inm->in6m_nsrc == 0 ||
(inm->in6m_st[0].iss_asm > 0 && inm->in6m_st[1].iss_asm > 0))
@@ -2881,7 +2884,7 @@ mld_v2_merge_state_changes(struct in6_multi *inm, struct mbufq *scq)
domerge = 0;
recslen = 0;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
/*
@@ -2980,7 +2983,7 @@ mld_v2_dispatch_general_query(struct mld_ifsoftc *mli)
struct in6_multi *inm;
int retval;
- IN6_MULTI_LOCK_ASSERT();
+ IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK_ASSERT();
KASSERT(mli->mli_version == MLD_VERSION_2,
@@ -2998,7 +3001,7 @@ mld_v2_dispatch_general_query(struct mld_ifsoftc *mli)
ifp = mli->mli_ifp;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_INET6 ||
ifma->ifma_protospec == NULL)
continue;
diff --git a/freebsd/sys/netinet6/mld6_var.h b/freebsd/sys/netinet6/mld6_var.h
index 0aeac367..166c2055 100644
--- a/freebsd/sys/netinet6/mld6_var.h
+++ b/freebsd/sys/netinet6/mld6_var.h
@@ -136,7 +136,6 @@ struct mld_ifsoftc {
uint32_t mli_qi; /* MLDv2 Query Interval (s) */
uint32_t mli_qri; /* MLDv2 Query Response Interval (s) */
uint32_t mli_uri; /* MLDv2 Unsolicited Report Interval (s) */
- SLIST_HEAD(,in6_multi) mli_relinmhead; /* released groups */
struct mbufq mli_gq; /* queue of general query responses */
};
diff --git a/freebsd/sys/netinet6/nd6.c b/freebsd/sys/netinet6/nd6.c
index a00d5421..6a36803f 100644
--- a/freebsd/sys/netinet6/nd6.c
+++ b/freebsd/sys/netinet6/nd6.c
@@ -60,10 +60,8 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_var.h>
-#include <net/if_arc.h>
#include <net/if_dl.h>
#include <net/if_types.h>
-#include <net/fddi.h>
#include <net/route.h>
#include <net/vnet.h>
@@ -305,7 +303,7 @@ nd6_ifdetach(struct ifnet *ifp, struct nd_ifinfo *nd)
struct ifaddr *ifa, *next;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
+ CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -337,18 +335,7 @@ nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi)
u_int32_t omaxmtu;
omaxmtu = ndi->maxmtu;
-
- switch (ifp->if_type) {
- case IFT_ARCNET:
- ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */
- break;
- case IFT_FDDI:
- ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); /* RFC2467 */
- break;
- default:
- ndi->maxmtu = ifp->if_mtu;
- break;
- }
+ ndi->maxmtu = ifp->if_mtu;
/*
* Decreasing the interface MTU under IPV6 minimum MTU may cause
@@ -937,7 +924,7 @@ nd6_timer(void *arg)
* XXXRW: in6_ifaddrhead locking.
*/
addrloop:
- TAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) {
+ CK_STAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) {
/* check address lifetime */
if (IFA6_IS_INVALID(ia6)) {
int regen = 0;
@@ -1083,7 +1070,7 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
ifp = ia6->ia_ifa.ifa_ifp;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct in6_ifaddr *it6;
if (ifa->ifa_addr->sa_family != AF_INET6)
@@ -1359,7 +1346,7 @@ restart:
*/
if (ifp->if_flags & IFF_POINTOPOINT) {
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != addr->sin6_family)
continue;
if (ifa->ifa_dstaddr != NULL &&
@@ -1702,7 +1689,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
* See RFC 4862, Section 5.4.5.
*/
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
@@ -1732,7 +1719,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
if (V_ip6_dad_count > 0 &&
(ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) {
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead,
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead,
ifa_link) {
if (ifa->ifa_addr->sa_family !=
AF_INET6)
@@ -1760,7 +1747,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
* assign one.
*/
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead,
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead,
ifa_link) {
if (ifa->ifa_addr->sa_family !=
AF_INET6)
@@ -1804,7 +1791,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
while ((pr = LIST_FIRST(&prl)) != NULL) {
LIST_REMOVE(pr, ndpr_entry);
/* XXXRW: in6_ifaddrhead locking. */
- TAILQ_FOREACH_SAFE(ia, &V_in6_ifaddrhead, ia_link,
+ CK_STAILQ_FOREACH_SAFE(ia, &V_in6_ifaddrhead, ia_link,
ia_next) {
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
@@ -2148,7 +2135,7 @@ nd6_slowtimo(void *arg)
callout_reset(&V_nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
nd6_slowtimo, curvnet);
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (ifp->if_afdata[AF_INET6] == NULL)
continue;
nd6if = ND_IFINFO(ifp);
@@ -2274,7 +2261,6 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
if (m != NULL && m->m_flags & M_MCAST) {
switch (ifp->if_type) {
case IFT_ETHER:
- case IFT_FDDI:
case IFT_L2VLAN:
case IFT_BRIDGE:
ETHER_MAP_IPV6_MULTICAST(&dst6->sin6_addr,
@@ -2526,15 +2512,13 @@ nd6_need_cache(struct ifnet *ifp)
{
/*
* XXX: we currently do not make neighbor cache on any interface
- * other than ARCnet, Ethernet, FDDI and GIF.
+ * other than Ethernet and GIF.
*
* RFC2893 says:
* - unidirectional tunnels needs no ND
*/
switch (ifp->if_type) {
- case IFT_ARCNET:
case IFT_ETHER:
- case IFT_FDDI:
case IFT_IEEE1394:
case IFT_L2VLAN:
case IFT_INFINIBAND:
diff --git a/freebsd/sys/netinet6/nd6_nbr.c b/freebsd/sys/netinet6/nd6_nbr.c
index e5b37877..d4ab38af 100644
--- a/freebsd/sys/netinet6/nd6_nbr.c
+++ b/freebsd/sys/netinet6/nd6_nbr.c
@@ -1092,9 +1092,7 @@ caddr_t
nd6_ifptomac(struct ifnet *ifp)
{
switch (ifp->if_type) {
- case IFT_ARCNET:
case IFT_ETHER:
- case IFT_FDDI:
case IFT_IEEE1394:
case IFT_L2VLAN:
case IFT_INFINIBAND:
@@ -1468,7 +1466,6 @@ nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp)
*/
switch (ifp->if_type) {
case IFT_ETHER:
- case IFT_FDDI:
case IFT_ATM:
case IFT_IEEE1394:
case IFT_INFINIBAND:
diff --git a/freebsd/sys/netinet6/nd6_rtr.c b/freebsd/sys/netinet6/nd6_rtr.c
index 642faa1a..fab7c7c2 100644
--- a/freebsd/sys/netinet6/nd6_rtr.c
+++ b/freebsd/sys/netinet6/nd6_rtr.c
@@ -480,7 +480,7 @@ nd6_rtmsg(int cmd, struct rtentry *rt)
ifp = rt->rt_ifp;
if (ifp != NULL) {
IF_ADDR_RLOCK(ifp);
- ifa = TAILQ_FIRST(&ifp->if_addrhead);
+ ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
info.rti_info[RTAX_IFP] = ifa->ifa_addr;
ifa_ref(ifa);
IF_ADDR_RUNLOCK(ifp);
@@ -1349,7 +1349,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
* "address".
*/
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct in6_ifaddr *ifa6;
u_int32_t remaininglifetime;
@@ -1721,7 +1721,7 @@ restart:
* The precise detection logic is same as the one for prefixes.
*/
IN6_IFADDR_RLOCK(&in6_ifa_tracker);
- TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
continue;
@@ -1738,7 +1738,7 @@ restart:
break;
}
if (ifa) {
- TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
@@ -1756,7 +1756,7 @@ restart:
}
}
} else {
- TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
@@ -1910,7 +1910,7 @@ nd6_prefix_onlink(struct nd_prefix *pr)
if (ifa == NULL) {
/* XXX: freebsd does not have ifa_ifwithaf */
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family == AF_INET6) {
ifa_ref(ifa);
break;
diff --git a/freebsd/sys/netinet6/raw_ip6.c b/freebsd/sys/netinet6/raw_ip6.c
index a4843380..c05399b3 100644
--- a/freebsd/sys/netinet6/raw_ip6.c
+++ b/freebsd/sys/netinet6/raw_ip6.c
@@ -736,23 +736,25 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return (EINVAL);
if ((error = prison_check_ip6(td->td_ucred, &addr->sin6_addr)) != 0)
return (error);
- if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
+ if (CK_STAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
return (EADDRNOTAVAIL);
if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
return (error);
+ NET_EPOCH_ENTER();
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
- (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL)
+ (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL) {
+ NET_EPOCH_EXIT();
return (EADDRNOTAVAIL);
+ }
if (ifa != NULL &&
((struct in6_ifaddr *)ifa)->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
- ifa_free(ifa);
+ NET_EPOCH_EXIT();
return (EADDRNOTAVAIL);
}
- if (ifa != NULL)
- ifa_free(ifa);
+ NET_EPOCH_EXIT();
INP_INFO_WLOCK(&V_ripcbinfo);
INP_WLOCK(inp);
inp->in6p_laddr = addr->sin6_addr;
@@ -774,7 +776,7 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
if (nam->sa_len != sizeof(*addr))
return (EINVAL);
- if (TAILQ_EMPTY(&V_ifnet))
+ if (CK_STAILQ_EMPTY(&V_ifnet))
return (EADDRNOTAVAIL);
if (addr->sin6_family != AF_INET6)
return (EAFNOSUPPORT);
diff --git a/freebsd/sys/netinet6/sctp6_usrreq.c b/freebsd/sys/netinet6/sctp6_usrreq.c
index a79e6f53..fd963fb3 100644
--- a/freebsd/sys/netinet6/sctp6_usrreq.c
+++ b/freebsd/sys/netinet6/sctp6_usrreq.c
@@ -225,7 +225,7 @@ sctp6_notify(struct sctp_inpcb *inp,
}
break;
case ICMP6_PACKET_TOO_BIG:
- if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) {
+ if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
SCTP_TCB_UNLOCK(stcb);
break;
}