FreeBSD Bugzilla – Attachment 201210 Details for
Bug 233535
Fix refcount leak in IPv6 MLD code leading to loss of IPv6 connectivity
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Fix MLD refcounting in IPv6 code (including additional debugging).
in6_multi.diff (text/plain), 18.77 KB, created by
Hans Petter Selasky
on 2019-01-17 14:21:10 UTC
(
hide
)
Description:
Fix MLD refcounting in IPv6 code (including additional debugging).
Filename:
MIME Type:
Creator:
Hans Petter Selasky
Created:
2019-01-17 14:21:10 UTC
Size:
18.77 KB
patch
obsolete
>Index: sys/netinet6/in6_ifattach.c >=================================================================== >--- sys/netinet6/in6_ifattach.c (revision 343111) >+++ sys/netinet6/in6_ifattach.c (working copy) >@@ -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 (revision 343111) >+++ sys/netinet6/in6_mcast.c (working copy) >@@ -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 >@@ -497,6 +500,7 @@ > inm->in6m_mli = MLD_IFINFO(ifp); > inm->in6m_ifma = ifma; > inm->in6m_refcount = 1; >+ in6m_trace("alloc", inm); > inm->in6m_state = MLD_NOT_MEMBER; > mbufq_init(&inm->in6m_scq, MLD_MAX_STATE_CHANGES); > >@@ -525,6 +529,8 @@ > struct ifmultiaddr *ifma; > struct ifnet *ifp; > >+ in6m_trace("release", inm); >+ > CTR2(KTR_MLD, "%s: refcount is %d", __func__, inm->in6m_refcount); > > MPASS(inm->in6m_refcount == 0); >@@ -572,7 +578,6 @@ > in6m_init, NULL); > #endif > >- > void > in6m_release_list_deferred(struct in6_multi_head *inmh) > { >@@ -585,8 +590,15 @@ > } > > 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; >@@ -593,10 +605,12 @@ > 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 +629,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 +646,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 +1251,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; >@@ -1261,6 +1259,7 @@ > #ifdef KTR > char ip6tbuf[INET6_ADDRSTRLEN]; > #endif >+ SLIST_INIT(&inmh); > > /* > * Sanity: Check scope zone ID was set for ifp, if and >@@ -1324,13 +1323,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 +1364,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; >@@ -1371,6 +1372,7 @@ > char ip6tbuf[INET6_ADDRSTRLEN]; > #endif > >+ SLIST_INIT(&inmh); > error = 0; > > IN6_MULTI_LOCK_ASSERT(); >@@ -1413,17 +1415,18 @@ > 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); >+ >+ in6m_trace("leave group locked", inm); >+ 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); > } > >- > /* > * Block or unblock an ASM multicast source on an inpcb. > * This implements the delta-based API described in RFC 3678. >@@ -1933,6 +1936,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 +1947,7 @@ > size_t idx; > int error, is_new; > >+ SLIST_INIT(&inmh); > ifp = NULL; > imf = NULL; > lims = NULL; >@@ -2178,7 +2183,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 +2224,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 +2233,7 @@ > > out_in6p_locked: > INP_WUNLOCK(inp); >+ in6m_release_list_deferred(&inmh); > return (error); > } > >@@ -2869,10 +2878,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 (revision 343111) >+++ sys/netinet6/in6_var.h (working copy) >@@ -670,8 +670,17 @@ > } 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); >+ >+#include <sys/kdb.h> >+ >+static inline void >+in6m_trace(const char *desc, struct in6_multi *inm) >+{ >+ printf("INM=%p REF=%d %s\n", inm, inm->in6m_refcount, desc); >+ kdb_backtrace(); >+} >+ > /* > * Helper function to derive the filter mode on a source entry > * from its internal counters. Predicates are: >@@ -713,13 +722,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 +748,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); > } > > /* >@@ -768,6 +785,8 @@ > > IN6_MULTI_LIST_LOCK_ASSERT(); > ++inm->in6m_refcount; >+ >+ in6m_trace("post acquire", inm); > } > > static __inline void >@@ -784,6 +803,8 @@ > KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm)); > IN6_MULTI_LIST_LOCK_ASSERT(); > >+ in6m_trace("pre release", inm); >+ > if (--inm->in6m_refcount == 0) { > MPASS(inm->in6m_ifp == NULL); > inm->in6m_ifma->ifma_protospec = NULL; >@@ -809,8 +830,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 (revision 343111) >+++ sys/netinet6/mld6.c (working copy) >@@ -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 { >@@ -819,6 +825,13 @@ > > is_general_query = 0; > >+ if (!mld_v2enable) { >+ CTR3(KTR_MLD, "ignore v2 query %s on ifp %p(%s)", >+ ip6_sprintf(ip6tbuf, &mld->mld_addr), >+ ifp, if_name(ifp)); >+ return (0); >+ } >+ > /* > * RFC3810 Section 6.2: MLD queries must originate from > * a router's link-local address. >@@ -1332,15 +1345,17 @@ > static void > mld_fasttimo_vnet(void) > { >+ 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 ifmultiaddr *ifma; > struct in6_multi *inm, *tinm; >- struct in6_multi_head inmh; > int uri_fasthz; > >+ SLIST_INIT(&inmh); > uri_fasthz = 0; > > /* >@@ -1353,7 +1368,6 @@ > !V_state_change_timers_running6) > return; > >- SLIST_INIT(&inmh); > IN6_MULTI_LIST_LOCK(); > MLD_LOCK(); > >@@ -1399,12 +1413,11 @@ > } > > 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); >@@ -1414,11 +1427,8 @@ > &scq, inm, uri_fasthz); > break; > } >- if (__predict_false(ifma6_restart)) { >- ifma6_restart = false; >- goto restart; >- } > } >+ NET_EPOCH_EXIT(et); > IF_ADDR_WUNLOCK(ifp); > > switch (mli->mli_version) { >@@ -1488,8 +1498,7 @@ > case MLD_REPORTING_MEMBER: > if (report_timer_expired) { > inm->in6m_state = MLD_IDLE_MEMBER; >- in6m_disconnect(inm); >- in6m_rele_locked(inmh, inm); >+ in6m_disconnect_locked(inmh, inm); > } > break; > case MLD_G_QUERY_PENDING_MEMBER: >@@ -1613,7 +1622,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 +1667,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 +1694,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 +1713,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 +1729,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 +1903,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. > */ >@@ -2007,7 +2019,9 @@ > */ > if (mli->mli_version == MLD_VERSION_2 && > inm->in6m_state == MLD_LEAVING_MEMBER) { >+ in6m_trace("pre leaving member", inm); > inm->in6m_refcount--; >+ MPASS(inm->in6m_refcount > 0); > } > inm->in6m_state = MLD_REPORTING_MEMBER; > >@@ -3012,11 +3026,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 (revision 343111) >+++ sys/netinet6/mld6_var.h (working copy) >@@ -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); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 233535
:
200199
|
200658
|
200699
|
200753
|
200887
|
200956
|
201125
|
201210
|
201211
|
201212
|
201220
|
201221
|
201228