Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F149380457
D18887.id53115.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
19 KB
Referenced Files
None
Subscribers
None
D18887.id53115.diff
View Options
Index: sys/netinet6/in6_ifattach.c
===================================================================
--- sys/netinet6/in6_ifattach.c
+++ sys/netinet6/in6_ifattach.c
@@ -854,36 +854,22 @@
static void
in6_purgemaddrs(struct ifnet *ifp)
{
- struct in6_multi_head purgeinms;
- struct in6_multi *inm;
- struct ifmultiaddr *ifma, *next;
+ struct in6_multi_head inmh;
- SLIST_INIT(&purgeinms);
+ SLIST_INIT(&inmh);
IN6_MULTI_LOCK();
IN6_MULTI_LIST_LOCK();
- IF_ADDR_WLOCK(ifp);
+ mld_ifdetach(ifp, &inmh);
+ IN6_MULTI_LIST_UNLOCK();
+ IN6_MULTI_UNLOCK();
+ in6m_release_list_deferred(&inmh);
+
/*
- * Extract list of in6_multi associated with the detaching ifp
- * which the PF_INET6 layer is about to release.
+ * Make sure all multicast deletions invoking if_ioctl() are
+ * completed before returning. Else we risk accessing a freed
+ * ifnet structure pointer.
*/
- 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;
- in6m_disconnect(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);
+ in6m_release_wait();
}
void
Index: sys/netinet6/in6_mcast.c
===================================================================
--- sys/netinet6/in6_mcast.c
+++ sys/netinet6/in6_mcast.c
@@ -190,7 +190,6 @@
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.
@@ -405,6 +404,7 @@
in6_getmulti(struct ifnet *ifp, const struct in6_addr *group,
struct in6_multi **pinm)
{
+ struct epoch_tracker et;
struct sockaddr_in6 gsin6;
struct ifmultiaddr *ifma;
struct in6_multi *inm;
@@ -420,7 +420,10 @@
IN6_MULTI_LOCK_ASSERT();
IN6_MULTI_LIST_LOCK();
IF_ADDR_WLOCK(ifp);
+ NET_EPOCH_ENTER(et);
inm = in6m_lookup_locked(ifp, group);
+ NET_EPOCH_EXIT(et);
+
if (inm != NULL) {
/*
* If we already joined this group, just bump the
@@ -585,18 +588,28 @@
}
void
-in6m_disconnect(struct in6_multi *inm)
+in6m_release_wait(void)
{
+
+ /* Wait for all jobs to complete. */
+ gtaskqueue_drain_all(free_gtask.gt_taskqueue);
+}
+
+void
+in6m_disconnect_locked(struct in6_multi_head *inmh, 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;
+ IN6_MULTI_LIST_LOCK_ASSERT();
+
ifp = inm->in6m_ifp;
+ if (ifp == NULL)
+ return; /* already called */
- if (ifp == NULL)
- return;
inm->in6m_ifp = NULL;
IF_ADDR_WLOCK_ASSERT(ifp);
ifma = inm->in6m_ifma;
@@ -615,7 +628,6 @@
MPASS(ll_ifma->ifma_llifma == NULL);
MPASS(ll_ifma->ifma_ifp == ifp);
if (--ll_ifma->ifma_refcount == 0) {
- ifma6_restart = true;
if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
@@ -633,28 +645,12 @@
if (inm == imm->i6mm_maddr) {
LIST_REMOVE(imm, i6mm_chain);
free(imm, M_IP6MADDR);
+ in6m_rele_locked(inmh, inm);
}
}
}
}
-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) {
- MPASS(inm->in6m_ifp == NULL);
- 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)
{
@@ -1254,6 +1250,7 @@
/*const*/ struct in6_mfilter *imf, struct in6_multi **pinm,
const int delay)
{
+ struct in6_multi_head inmh;
struct in6_mfilter timf;
struct in6_multi *inm;
struct ifmultiaddr *ifma;
@@ -1313,6 +1310,7 @@
}
out_in6m_release:
+ SLIST_INIT(&inmh);
if (error) {
struct epoch_tracker et;
@@ -1324,13 +1322,14 @@
break;
}
}
- in6m_disconnect(inm);
- in6m_release_deferred(inm);
+ in6m_disconnect_locked(&inmh, inm);
+ in6m_rele_locked(&inmh, inm);
NET_EPOCH_EXIT(et);
} else {
*pinm = inm;
}
IN6_MULTI_LIST_UNLOCK();
+ in6m_release_list_deferred(&inmh);
return (error);
}
@@ -1364,6 +1363,7 @@
int
in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf)
{
+ struct in6_multi_head inmh;
struct in6_mfilter timf;
struct ifnet *ifp;
int error;
@@ -1413,13 +1413,15 @@
CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
if (ifp)
IF_ADDR_WLOCK(ifp);
- if (inm->in6m_refcount == 1 && inm->in6m_ifp != NULL)
- in6m_disconnect(inm);
- in6m_release_deferred(inm);
+
+ SLIST_INIT(&inmh);
+ if (inm->in6m_refcount == 1)
+ in6m_disconnect_locked(&inmh, inm);
+ in6m_rele_locked(&inmh, inm);
if (ifp)
IF_ADDR_WUNLOCK(ifp);
IN6_MULTI_LIST_UNLOCK();
-
+ in6m_release_list_deferred(&inmh);
return (error);
}
@@ -1933,6 +1935,7 @@
static int
in6p_join_group(struct inpcb *inp, struct sockopt *sopt)
{
+ struct in6_multi_head inmh;
struct group_source_req gsr;
sockunion_t *gsa, *ssa;
struct ifnet *ifp;
@@ -1943,6 +1946,7 @@
size_t idx;
int error, is_new;
+ SLIST_INIT(&inmh);
ifp = NULL;
imf = NULL;
lims = NULL;
@@ -2178,7 +2182,10 @@
IN6_MULTI_UNLOCK();
goto out_im6o_free;
}
- in6m_acquire(inm);
+ /*
+ * NOTE: Refcount from in6_joingroup_locked()
+ * is protecting membership.
+ */
imo->im6o_membership[idx] = inm;
} else {
CTR1(KTR_MLD, "%s: merge inm state", __func__);
@@ -2216,7 +2223,7 @@
inm = imo->im6o_membership[idx];
if (inm != NULL) {
IN6_MULTI_LIST_LOCK();
- in6m_release_deferred(inm);
+ in6m_rele_locked(&inmh, inm);
IN6_MULTI_LIST_UNLOCK();
}
imo->im6o_membership[idx] = NULL;
@@ -2225,6 +2232,7 @@
out_in6p_locked:
INP_WUNLOCK(inp);
+ in6m_release_list_deferred(&inmh);
return (error);
}
@@ -2869,10 +2877,9 @@
IN6_MULTI_LIST_LOCK();
NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
- if (ifma->ifma_addr->sa_family != AF_INET6 ||
- ifma->ifma_protospec == NULL)
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
continue;
- inm = (struct in6_multi *)ifma->ifma_protospec;
if (!IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, &mcaddr))
continue;
fmode = inm->in6m_st[1].iss_fmode;
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -645,6 +645,7 @@
/* New fields for MLDv2 follow. */
struct mld_ifsoftc *in6m_mli; /* MLD info */
SLIST_ENTRY(in6_multi) in6m_nrele; /* to-be-released by MLD */
+ SLIST_ENTRY(in6_multi) in6m_defer; /* deferred MLDv1 */
struct ip6_msource_tree in6m_srcs; /* tree of sources */
u_long in6m_nsrc; /* # of tree entries */
@@ -670,8 +671,8 @@
} in6m_st[2]; /* state at t0, t1 */
};
-void in6m_disconnect(struct in6_multi *inm);
-extern int ifma6_restart;
+void in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm);
+
/*
* Helper function to derive the filter mode on a source entry
* from its internal counters. Predicates are:
@@ -713,13 +714,25 @@
#define IN6_MULTI_LOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XLOCKED)
#define IN6_MULTI_UNLOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XUNLOCKED)
+/*
+ * Get the in6_multi pointer from a ifmultiaddr.
+ * Returns NULL if ifmultiaddr is no longer valid.
+ */
+static __inline struct in6_multi *
+in6m_ifmultiaddr_get_inm(struct ifmultiaddr *ifma)
+{
+ NET_EPOCH_ASSERT();
+
+ return ((ifma->ifma_addr->sa_family != AF_INET6 ||
+ (ifma->ifma_flags & IFMA_F_ENQUEUED) == 0) ? NULL :
+ ifma->ifma_protospec);
+}
+
/*
* Look up an in6_multi record for an IPv6 multicast address
* on the interface ifp.
* If no record found, return NULL.
- *
- * SMPng: The IN6_MULTI_LOCK and IF_ADDR_LOCK on ifp must be held.
*/
static __inline struct in6_multi *
in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr)
@@ -727,18 +740,14 @@
struct ifmultiaddr *ifma;
struct in6_multi *inm;
- inm = NULL;
- 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;
- }
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
+ continue;
+ if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr))
+ return (inm);
}
- return (inm);
+ return (NULL);
}
/*
@@ -809,8 +818,8 @@
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_deferred(struct in6_multi *);
void in6m_release_list_deferred(struct in6_multi_head *);
+void in6m_release_wait(void);
void ip6_freemoptions(struct ip6_moptions *);
int ip6_getmoptions(struct inpcb *, struct sockopt *);
int ip6_setmoptions(struct inpcb *, struct sockopt *);
Index: sys/netinet6/mld6.c
===================================================================
--- sys/netinet6/mld6.c
+++ sys/netinet6/mld6.c
@@ -110,7 +110,7 @@
static void mld_dispatch_packet(struct mbuf *);
static void mld_dispatch_queue(struct mbufq *, int);
static void mld_final_leave(struct in6_multi *, struct mld_ifsoftc *);
-static void mld_fasttimo_vnet(void);
+static void mld_fasttimo_vnet(struct in6_multi_head *inmh);
static int mld_handle_state_change(struct in6_multi *,
struct mld_ifsoftc *);
static int mld_initial_join(struct in6_multi *, struct mld_ifsoftc *,
@@ -243,6 +243,10 @@
SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN,
&mld_v1enable, 0, "Enable fallback to MLDv1");
+static int mld_v2enable = 1;
+SYSCTL_INT(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_RWTUN,
+ &mld_v2enable, 0, "Enable MLDv2");
+
static int mld_use_allow = 1;
SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN,
&mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
@@ -533,45 +537,48 @@
* XXX This routine is also bitten by unlocked ifma_protospec access.
*/
void
-mld_ifdetach(struct ifnet *ifp)
+mld_ifdetach(struct ifnet *ifp, struct in6_multi_head *inmh)
{
+ struct epoch_tracker et;
struct mld_ifsoftc *mli;
- struct ifmultiaddr *ifma, *next;
+ struct ifmultiaddr *ifma;
struct in6_multi *inm;
- struct in6_multi_head inmh;
CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp,
if_name(ifp));
- SLIST_INIT(&inmh);
IN6_MULTI_LIST_LOCK_ASSERT();
MLD_LOCK();
mli = MLD_IFINFO(ifp);
- if (mli->mli_version == MLD_VERSION_2) {
- 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_ADDR_WLOCK(ifp);
+ /*
+ * Extract list of in6_multi associated with the detaching ifp
+ * which the PF_INET6 layer is about to release.
+ */
+ NET_EPOCH_ENTER(et);
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
+ continue;
+ in6m_disconnect_locked(inmh, inm);
+
+ if (mli->mli_version == MLD_VERSION_2) {
+ in6m_clear_recorded(inm);
+
+ /*
+ * We need to release the final reference held
+ * for issuing the INCLUDE {}.
+ */
if (inm->in6m_state == MLD_LEAVING_MEMBER) {
- in6m_disconnect(inm);
- in6m_rele_locked(&inmh, inm);
- ifma->ifma_protospec = NULL;
+ inm->in6m_state = MLD_NOT_MEMBER;
+ in6m_rele_locked(inmh, inm);
}
- in6m_clear_recorded(inm);
- if (__predict_false(ifma6_restart)) {
- ifma6_restart = false;
- goto restart;
- }
}
- IF_ADDR_WUNLOCK(ifp);
}
-
+ NET_EPOCH_EXIT(et);
+ IF_ADDR_WUNLOCK(ifp);
MLD_UNLOCK();
- in6m_release_list_deferred(&inmh);
}
/*
@@ -705,10 +712,9 @@
CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)",
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)
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
continue;
- inm = (struct in6_multi *)ifma->ifma_protospec;
mld_v1_update_group(inm, timer);
}
} else {
@@ -817,7 +823,12 @@
char ip6tbuf[INET6_ADDRSTRLEN];
#endif
- is_general_query = 0;
+ if (!mld_v2enable) {
+ CTR3(KTR_MLD, "ignore v2 query src %s on ifp %p(%s)",
+ ip6_sprintf(ip6tbuf, &ip6->ip6_src),
+ ifp, if_name(ifp));
+ return (0);
+ }
/*
* RFC3810 Section 6.2: MLD queries must originate from
@@ -830,6 +841,8 @@
return (0);
}
+ is_general_query = 0;
+
CTR2(KTR_MLD, "input v2 query on ifp %p(%s)", ifp, if_name(ifp));
mld = (struct mldv2_query *)(mtod(m, uint8_t *) + off);
@@ -1313,15 +1326,19 @@
void
mld_fasttimo(void)
{
+ struct in6_multi_head inmh;
VNET_ITERATOR_DECL(vnet_iter);
+ SLIST_INIT(&inmh);
+
VNET_LIST_RLOCK_NOSLEEP();
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
- mld_fasttimo_vnet();
+ mld_fasttimo_vnet(&inmh);
CURVNET_RESTORE();
}
VNET_LIST_RUNLOCK_NOSLEEP();
+ in6m_release_list_deferred(&inmh);
}
/*
@@ -1330,15 +1347,15 @@
* VIMAGE: Assume caller has set up our curvnet.
*/
static void
-mld_fasttimo_vnet(void)
+mld_fasttimo_vnet(struct in6_multi_head *inmh)
{
+ struct epoch_tracker et;
struct mbufq scq; /* State-change packets */
struct mbufq qrq; /* Query response packets */
struct ifnet *ifp;
struct mld_ifsoftc *mli;
- struct ifmultiaddr *ifma, *next;
- struct in6_multi *inm, *tinm;
- struct in6_multi_head inmh;
+ struct ifmultiaddr *ifma;
+ struct in6_multi *inm;
int uri_fasthz;
uri_fasthz = 0;
@@ -1353,7 +1370,6 @@
!V_state_change_timers_running6)
return;
- SLIST_INIT(&inmh);
IN6_MULTI_LIST_LOCK();
MLD_LOCK();
@@ -1399,25 +1415,20 @@
}
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)
+ NET_EPOCH_ENTER(et);
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
continue;
- inm = (struct in6_multi *)ifma->ifma_protospec;
switch (mli->mli_version) {
case MLD_VERSION_1:
- mld_v1_process_group_timer(&inmh, inm);
+ mld_v1_process_group_timer(inmh, inm);
break;
case MLD_VERSION_2:
- mld_v2_process_group_timers(&inmh, &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_WUNLOCK(ifp);
@@ -1431,9 +1442,8 @@
* IF_ADDR_LOCK internally as well as
* ip6_output() to transmit a packet.
*/
- SLIST_FOREACH_SAFE(inm, &inmh, in6m_nrele, tinm) {
- SLIST_REMOVE_HEAD(&inmh,
- in6m_nrele);
+ while ((inm = SLIST_FIRST(inmh)) != NULL) {
+ SLIST_REMOVE_HEAD(inmh, in6m_defer);
(void)mld_v1_transmit_report(inm,
MLD_LISTENER_REPORT);
}
@@ -1441,14 +1451,9 @@
case MLD_VERSION_2:
mld_dispatch_queue(&qrq, 0);
mld_dispatch_queue(&scq, 0);
-
- /*
- * Free the in_multi reference(s) for
- * this lifecycle.
- */
- in6m_release_list_deferred(&inmh);
break;
}
+ NET_EPOCH_EXIT(et);
}
out_locked:
@@ -1488,8 +1493,7 @@
case MLD_REPORTING_MEMBER:
if (report_timer_expired) {
inm->in6m_state = MLD_IDLE_MEMBER;
- in6m_disconnect(inm);
- in6m_rele_locked(inmh, inm);
+ SLIST_INSERT_HEAD(inmh, inm, in6m_defer);
}
break;
case MLD_G_QUERY_PENDING_MEMBER:
@@ -1613,7 +1617,7 @@
if (inm->in6m_state == MLD_LEAVING_MEMBER &&
inm->in6m_scrv == 0) {
inm->in6m_state = MLD_NOT_MEMBER;
- in6m_disconnect(inm);
+ in6m_disconnect_locked(inmh, inm);
in6m_rele_locked(inmh, inm);
}
}
@@ -1658,10 +1662,11 @@
static void
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli)
{
- struct ifmultiaddr *ifma, *next;
+ struct epoch_tracker et;
+ struct in6_multi_head inmh;
+ struct ifmultiaddr *ifma;
struct ifnet *ifp;
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));
@@ -1684,12 +1689,11 @@
ifp = mli->mli_ifp;
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)
+ NET_EPOCH_ENTER(et);
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
continue;
- inm = (struct in6_multi *)ifma->ifma_protospec;
switch (inm->in6m_state) {
case MLD_NOT_MEMBER:
case MLD_SILENT_MEMBER:
@@ -1704,9 +1708,7 @@
* version, we need to release the final
* reference held for issuing the INCLUDE {}.
*/
- in6m_disconnect(inm);
in6m_rele_locked(&inmh, inm);
- ifma->ifma_protospec = NULL;
/* FALLTHROUGH */
case MLD_G_QUERY_PENDING_MEMBER:
case MLD_SG_QUERY_PENDING_MEMBER:
@@ -1722,11 +1724,8 @@
mbufq_drain(&inm->in6m_scq);
break;
}
- if (__predict_false(ifma6_restart)) {
- ifma6_restart = false;
- goto restart;
- }
}
+ NET_EPOCH_EXIT(et);
IF_ADDR_WUNLOCK(ifp);
in6m_release_list_deferred(&inmh);
}
@@ -1899,6 +1898,14 @@
error = 0;
/*
+ * Check if the in6_multi has already been disconnected.
+ */
+ if (inm->in6m_ifp == NULL) {
+ CTR1(KTR_MLD, "%s: inm is disconnected", __func__);
+ return (0);
+ }
+
+ /*
* Try to detect if the upper layer just asked us to change state
* for an interface which has now gone away.
*/
@@ -2008,6 +2015,7 @@
if (mli->mli_version == MLD_VERSION_2 &&
inm->in6m_state == MLD_LEAVING_MEMBER) {
inm->in6m_refcount--;
+ MPASS(inm->in6m_refcount > 0);
}
inm->in6m_state = MLD_REPORTING_MEMBER;
@@ -3012,11 +3020,9 @@
NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
- if (ifma->ifma_addr->sa_family != AF_INET6 ||
- ifma->ifma_protospec == NULL)
+ inm = in6m_ifmultiaddr_get_inm(ifma);
+ if (inm == NULL)
continue;
-
- inm = (struct in6_multi *)ifma->ifma_protospec;
KASSERT(ifp == inm->in6m_ifp,
("%s: inconsistent ifp", __func__));
Index: sys/netinet6/mld6_var.h
===================================================================
--- sys/netinet6/mld6_var.h
+++ sys/netinet6/mld6_var.h
@@ -160,12 +160,13 @@
#define MLD_IFINFO(ifp) \
(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->mld_ifinfo)
+struct in6_multi_head;
int mld_change_state(struct in6_multi *, const int);
struct mld_ifsoftc *
mld_domifattach(struct ifnet *);
void mld_domifdetach(struct ifnet *);
void mld_fasttimo(void);
-void mld_ifdetach(struct ifnet *);
+void mld_ifdetach(struct ifnet *, struct in6_multi_head *);
int mld_input(struct mbuf *, int, int);
void mld_slowtimo(void);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 25, 2:12 AM (17 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30290653
Default Alt Text
D18887.id53115.diff (19 KB)
Attached To
Mode
D18887: Fix refcounting leaks in IPv6 MLD code leading to loss of IPv6 connectivity
Attached
Detach File
Event Timeline
Log In to Comment