Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/mld6.c
Show First 20 Lines • Show All 535 Lines • ▼ Show 20 Lines | |||||
* Must take IF_ADDR_LOCK() to cover if_multiaddrs iterator. | * Must take IF_ADDR_LOCK() to cover if_multiaddrs iterator. | ||||
* XXX This routine is also bitten by unlocked ifma_protospec access. | * XXX This routine is also bitten by unlocked ifma_protospec access. | ||||
*/ | */ | ||||
void | void | ||||
mld_ifdetach(struct ifnet *ifp, struct in6_multi_head *inmh) | mld_ifdetach(struct ifnet *ifp, struct in6_multi_head *inmh) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct mld_ifsoftc *mli; | struct mld_ifsoftc *mli; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma, *tifma; | ||||
struct in6_multi *inm; | struct in6_multi *inm; | ||||
CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, | CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, | ||||
if_name(ifp)); | if_name(ifp)); | ||||
IN6_MULTI_LIST_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK(); | MLD_LOCK(); | ||||
mli = MLD_IFINFO(ifp); | mli = MLD_IFINFO(ifp); | ||||
IF_ADDR_WLOCK(ifp); | IF_ADDR_WLOCK(ifp); | ||||
/* | /* | ||||
* Extract list of in6_multi associated with the detaching ifp | * Extract list of in6_multi associated with the detaching ifp | ||||
* which the PF_INET6 layer is about to release. | * which the PF_INET6 layer is about to release. | ||||
*/ | */ | ||||
// restart: | |||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, tifma) { | ||||
hselasky: There is no need for CK_STAILQ_FOREACH_SAFE() here. Elements are not freed inside the for-loop… | |||||
int released; | |||||
inm = in6m_ifmultiaddr_get_inm(ifma); | inm = in6m_ifmultiaddr_get_inm(ifma); | ||||
if (inm == NULL) | if (inm == NULL) | ||||
continue; | continue; | ||||
in6m_disconnect_locked(inmh, inm); | released = in6m_remove_members(inmh, inm); | ||||
if (mli->mli_version == MLD_VERSION_2) { | if (mli->mli_version == MLD_VERSION_2) { | ||||
in6m_clear_recorded(inm); | in6m_clear_recorded(inm); | ||||
/* | /* | ||||
* We need to release the final reference held | * We need to release the final reference held | ||||
* for issuing the INCLUDE {}. | * for issuing the INCLUDE {}. | ||||
*/ | */ | ||||
if (inm->in6m_state == MLD_LEAVING_MEMBER) { | if (inm->in6m_state == MLD_LEAVING_MEMBER) { | ||||
inm->in6m_state = MLD_NOT_MEMBER; | inm->in6m_state = MLD_NOT_MEMBER; | ||||
if (!released) | |||||
in6m_rele_locked(inmh, inm); | in6m_rele_locked(inmh, inm); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | if (is_general_query) { | ||||
* look up the single group to process it. | * look up the single group to process it. | ||||
*/ | */ | ||||
inm = in6m_lookup_locked(ifp, &mld->mld_addr); | inm = in6m_lookup_locked(ifp, &mld->mld_addr); | ||||
if (inm != NULL) { | if (inm != NULL) { | ||||
CTR3(KTR_MLD, "process v1 query %s on ifp %p(%s)", | CTR3(KTR_MLD, "process v1 query %s on ifp %p(%s)", | ||||
ip6_sprintf(ip6tbuf, &mld->mld_addr), | ip6_sprintf(ip6tbuf, &mld->mld_addr), | ||||
ifp, if_name(ifp)); | ifp, if_name(ifp)); | ||||
mld_v1_update_group(inm, timer); | mld_v1_update_group(inm, timer); | ||||
in6m_release_deferred(inm); | |||||
} | } | ||||
/* XXX Clear embedded scope ID as userland won't expect it. */ | /* XXX Clear embedded scope ID as userland won't expect it. */ | ||||
in6_clearscope(&mld->mld_addr); | in6_clearscope(&mld->mld_addr); | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_LIST_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
* Return 0 if successful, otherwise an appropriate error code is returned. | * Return 0 if successful, otherwise an appropriate error code is returned. | ||||
*/ | */ | ||||
static int | static int | ||||
mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, | mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, | ||||
struct mbuf *m, const int off, const int icmp6len) | struct mbuf *m, const int off, const int icmp6len) | ||||
{ | { | ||||
struct mld_ifsoftc *mli; | struct mld_ifsoftc *mli; | ||||
struct mldv2_query *mld; | struct mldv2_query *mld; | ||||
struct in6_multi *inm; | struct in6_multi *inm = NULL; | ||||
uint32_t maxdelay, nsrc, qqi; | uint32_t maxdelay, nsrc, qqi; | ||||
int is_general_query; | int is_general_query; | ||||
uint16_t timer; | uint16_t timer; | ||||
uint8_t qrv; | uint8_t qrv; | ||||
#ifdef KTR | #ifdef KTR | ||||
char ip6tbuf[INET6_ADDRSTRLEN]; | char ip6tbuf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | if (mli->mli_v2_timer == 0 || mli->mli_v2_timer >= timer) | ||||
mld_v2_process_group_query(inm, mli, timer, m, off); | mld_v2_process_group_query(inm, mli, timer, m, off); | ||||
/* XXX Clear embedded scope ID as userland won't expect it. */ | /* XXX Clear embedded scope ID as userland won't expect it. */ | ||||
in6_clearscope(&mld->mld_addr); | in6_clearscope(&mld->mld_addr); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
} | } | ||||
out_locked: | out_locked: | ||||
if (inm) | |||||
in6m_release_deferred(inm); | |||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_LIST_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Process a received MLDv2 group-specific or group-and-source-specific | * Process a received MLDv2 group-specific or group-and-source-specific | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6, | mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6, | ||||
/*const*/ struct mld_hdr *mld) | /*const*/ struct mld_hdr *mld) | ||||
{ | { | ||||
struct in6_addr src, dst; | struct in6_addr src, dst; | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
struct in6_multi *inm; | struct in6_multi *inm = NULL; | ||||
#ifdef KTR | #ifdef KTR | ||||
char ip6tbuf[INET6_ADDRSTRLEN]; | char ip6tbuf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
if (!mld_v1enable) { | if (!mld_v1enable) { | ||||
CTR3(KTR_MLD, "ignore v1 report %s on ifp %p(%s)", | CTR3(KTR_MLD, "ignore v1 report %s on ifp %p(%s)", | ||||
ip6_sprintf(ip6tbuf, &mld->mld_addr), | ip6_sprintf(ip6tbuf, &mld->mld_addr), | ||||
ifp, if_name(ifp)); | ifp, if_name(ifp)); | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | if (inm != NULL) { | ||||
case MLD_G_QUERY_PENDING_MEMBER: | case MLD_G_QUERY_PENDING_MEMBER: | ||||
case MLD_SG_QUERY_PENDING_MEMBER: | case MLD_SG_QUERY_PENDING_MEMBER: | ||||
case MLD_LEAVING_MEMBER: | case MLD_LEAVING_MEMBER: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
if (inm) | |||||
in6m_release_deferred(inm); | |||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_LIST_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
/* XXX Clear embedded scope ID as userland won't expect it. */ | /* XXX Clear embedded scope ID as userland won't expect it. */ | ||||
in6_clearscope(&mld->mld_addr); | in6_clearscope(&mld->mld_addr); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 365 Lines • ▼ Show 20 Lines | if (state_change_retransmit_timer_expired) { | ||||
* we release MLD's reference to it. | * we release MLD's reference to it. | ||||
* This release must be deferred using a SLIST, | * This release must be deferred using a SLIST, | ||||
* as we are called from a loop which traverses | * as we are called from a loop which traverses | ||||
* the in_ifmultiaddr TAILQ. | * the in_ifmultiaddr TAILQ. | ||||
*/ | */ | ||||
if (inm->in6m_state == MLD_LEAVING_MEMBER && | if (inm->in6m_state == MLD_LEAVING_MEMBER && | ||||
inm->in6m_scrv == 0) { | inm->in6m_scrv == 0) { | ||||
inm->in6m_state = MLD_NOT_MEMBER; | inm->in6m_state = MLD_NOT_MEMBER; | ||||
in6m_disconnect_locked(inmh, inm); | if (in6m_remove_members(inmh, inm) == 0) | ||||
in6m_rele_locked(inmh, inm); | in6m_rele_locked(inmh, inm); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Switch to a different version on the given interface, | * Switch to a different version on the given interface, | ||||
▲ Show 20 Lines • Show All 1,709 Lines • Show Last 20 Lines |
There is no need for CK_STAILQ_FOREACH_SAFE() here. Elements are not freed inside the for-loop and the next pointer of the STAILQ is valid even after rele_locked. Please explain.