diff options
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/in6_ifattach.c | 29 | ||||
-rw-r--r-- | sys/netinet6/in6_mcast.c | 60 | ||||
-rw-r--r-- | sys/netinet6/in6_var.h | 40 | ||||
-rw-r--r-- | sys/netinet6/mld6.c | 141 | ||||
-rw-r--r-- | sys/netinet6/mld6_var.h | 3 |
5 files changed, 126 insertions, 147 deletions
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 14df5fff6450..03285b60d2d4 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -854,36 +854,15 @@ in6_tmpaddrtimer(void *arg) 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); - /* - * Extract list of in6_multi associated with the detaching ifp - * which the PF_INET6 layer is about to release. - */ - 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); + mld_ifdetach(ifp, &inmh); IN6_MULTI_LIST_UNLOCK(); IN6_MULTI_UNLOCK(); - in6m_release_list_deferred(&purgeinms); + in6m_release_list_deferred(&inmh); /* * Make sure all multicast deletions invoking if_ioctl() are diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index 693345b1c5ee..3b60d26c84ee 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -190,7 +190,6 @@ 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. @@ -405,6 +404,7 @@ static int 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_getmulti(struct ifnet *ifp, const struct in6_addr *group, 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 @@ -593,7 +596,7 @@ in6m_release_wait(void) } void -in6m_disconnect(struct in6_multi *inm) +in6m_disconnect_locked(struct in6_multi_head *inmh, struct in6_multi *inm) { struct ifnet *ifp; struct ifaddr *ifa; @@ -601,10 +604,12 @@ in6m_disconnect(struct in6_multi *inm) struct in6_multi_mship *imm, *imm_tmp; struct ifmultiaddr *ifma, *ll_ifma; - ifp = inm->in6m_ifp; + IN6_MULTI_LIST_LOCK_ASSERT(); + ifp = inm->in6m_ifp; if (ifp == NULL) - return; + return; /* already called */ + inm->in6m_ifp = NULL; IF_ADDR_WLOCK_ASSERT(ifp); ifma = inm->in6m_ifma; @@ -623,7 +628,6 @@ in6m_disconnect(struct in6_multi *inm) 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; @@ -641,28 +645,12 @@ in6m_disconnect(struct in6_multi *inm) 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) { @@ -1262,6 +1250,7 @@ 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_multi_head inmh; struct in6_mfilter timf; struct in6_multi *inm; struct ifmultiaddr *ifma; @@ -1321,6 +1310,7 @@ in6_joingroup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr, } out_in6m_release: + SLIST_INIT(&inmh); if (error) { struct epoch_tracker et; @@ -1332,13 +1322,14 @@ out_in6m_release: 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); } @@ -1372,6 +1363,7 @@ in6_leavegroup(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) 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; @@ -1421,13 +1413,15 @@ in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) 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); } @@ -1941,6 +1935,7 @@ in6p_lookup_mcast_ifp(const struct inpcb *in6p, 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; @@ -1951,6 +1946,7 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) size_t idx; int error, is_new; + SLIST_INIT(&inmh); ifp = NULL; imf = NULL; lims = NULL; @@ -2227,7 +2223,7 @@ out_im6o_free: 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; @@ -2236,6 +2232,7 @@ out_im6o_free: out_in6p_locked: INP_WUNLOCK(inp); + in6m_release_list_deferred(&inmh); return (error); } @@ -2880,10 +2877,9 @@ sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS) 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; diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index a19747d97918..3e965c2d4b32 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -645,6 +645,7 @@ struct in6_multi { /* 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 @@ struct in6_multi { } 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 @@ extern struct sx 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) +/* + * 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 @@ in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr) 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,7 +818,6 @@ 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_deferred(struct in6_multi *); void in6m_release_list_deferred(struct in6_multi_head *); void in6m_release_wait(void); void ip6_freemoptions(struct ip6_moptions *); diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 9536f4591b1c..62632e989c88 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -110,7 +110,7 @@ static void mli_delete_locked(const struct ifnet *); 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 *, @@ -537,45 +537,48 @@ out: * 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 (inm->in6m_state == MLD_LEAVING_MEMBER) { - in6m_disconnect(inm); - in6m_rele_locked(&inmh, inm); - ifma->ifma_protospec = NULL; - } + 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); - if (__predict_false(ifma6_restart)) { - ifma6_restart = false; - goto restart; + + /* + * We need to release the final reference held + * for issuing the INCLUDE {}. + */ + if (inm->in6m_state == MLD_LEAVING_MEMBER) { + inm->in6m_state = MLD_NOT_MEMBER; + in6m_rele_locked(inmh, inm); } } - IF_ADDR_WUNLOCK(ifp); } - + NET_EPOCH_EXIT(et); + IF_ADDR_WUNLOCK(ifp); MLD_UNLOCK(); - in6m_release_list_deferred(&inmh); } /* @@ -709,10 +712,9 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, 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 { @@ -1324,15 +1326,19 @@ mld_input(struct mbuf *m, int off, int icmp6len) 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); } /* @@ -1341,15 +1347,15 @@ mld_fasttimo(void) * 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; @@ -1364,7 +1370,6 @@ mld_fasttimo_vnet(void) !V_state_change_timers_running6) return; - SLIST_INIT(&inmh); IN6_MULTI_LIST_LOCK(); MLD_LOCK(); @@ -1410,25 +1415,20 @@ mld_fasttimo_vnet(void) } 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); @@ -1442,9 +1442,8 @@ mld_fasttimo_vnet(void) * 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); } @@ -1452,14 +1451,9 @@ mld_fasttimo_vnet(void) 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: @@ -1499,8 +1493,7 @@ mld_v1_process_group_timer(struct in6_multi_head *inmh, struct in6_multi *inm) 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: @@ -1624,7 +1617,7 @@ mld_v2_process_group_timers(struct in6_multi_head *inmh, 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); } } @@ -1669,10 +1662,11 @@ mld_set_version(struct mld_ifsoftc *mli, const int version) 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)); @@ -1695,12 +1689,11 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) 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: @@ -1715,9 +1708,7 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) * 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: @@ -1733,11 +1724,8 @@ 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; - } } + NET_EPOCH_EXIT(et); IF_ADDR_WUNLOCK(ifp); in6m_release_list_deferred(&inmh); } @@ -1910,6 +1898,14 @@ mld_change_state(struct in6_multi *inm, const int delay) 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. */ @@ -2019,6 +2015,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) { inm->in6m_refcount--; + MPASS(inm->in6m_refcount > 0); } inm->in6m_state = MLD_REPORTING_MEMBER; @@ -3023,11 +3020,9 @@ mld_v2_dispatch_general_query(struct mld_ifsoftc *mli) 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__)); diff --git a/sys/netinet6/mld6_var.h b/sys/netinet6/mld6_var.h index 166c20555b96..8dc2ffa4cd7c 100644 --- a/sys/netinet6/mld6_var.h +++ b/sys/netinet6/mld6_var.h @@ -160,12 +160,13 @@ struct mld_ifsoftc { #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); |