Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/igmp.c
Show First 20 Lines • Show All 622 Lines • ▼ Show 20 Lines | igmp_ifdetach(struct ifnet *ifp) | ||||
if (igi->igi_version == IGMP_VERSION_3) { | if (igi->igi_version == IGMP_VERSION_3) { | ||||
IF_ADDR_WLOCK(ifp); | IF_ADDR_WLOCK(ifp); | ||||
restart: | restart: | ||||
CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { | CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { | ||||
if (ifma->ifma_addr->sa_family != AF_INET || | if (ifma->ifma_addr->sa_family != AF_INET || | ||||
ifma->ifma_protospec == NULL) | ifma->ifma_protospec == NULL) | ||||
continue; | continue; | ||||
inm = (struct in_multi *)ifma->ifma_protospec; | inm = (struct in_multi *)ifma->ifma_protospec; | ||||
if (inm->inm_state == IGMP_LEAVING_MEMBER) | if (inm->inm_state == IGMP_LEAVING_MEMBER) { | ||||
inm_rele_locked(&inm_free_tmp, inm); | inm_rele_locked(&inm_free_tmp, inm); | ||||
ifma->ifma_protospec = NULL; | |||||
} | |||||
inm_clear_recorded(inm); | inm_clear_recorded(inm); | ||||
if (__predict_false(ifma_restart)) { | if (__predict_false(ifma_restart)) { | ||||
ifma_restart = false; | ifma_restart = false; | ||||
goto restart; | goto restart; | ||||
} | } | ||||
} | } | ||||
IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
inm_release_list_deferred(&inm_free_tmp); | inm_release_list_deferred(&inm_free_tmp); | ||||
▲ Show 20 Lines • Show All 210 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 = inm_lookup(ifp, igmp->igmp_group); | inm = inm_lookup(ifp, igmp->igmp_group); | ||||
if (inm != NULL) { | if (inm != NULL) { | ||||
CTR3(KTR_IGMPV3, | CTR3(KTR_IGMPV3, | ||||
"process v2 query 0x%08x on ifp %p(%s)", | "process v2 query 0x%08x on ifp %p(%s)", | ||||
ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname); | ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname); | ||||
igmp_v2_update_group(inm, timer); | igmp_v2_update_group(inm, timer); | ||||
inm_release_deferred(inm); | |||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
IGMP_UNLOCK(); | IGMP_UNLOCK(); | ||||
IN_MULTI_LIST_UNLOCK(); | IN_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
* Assumes m has already been pulled up to the full IGMP message length. | * Assumes m has already been pulled up to the full IGMP message length. | ||||
* 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 | ||||
igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip, | igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip, | ||||
/*const*/ struct igmpv3 *igmpv3) | /*const*/ struct igmpv3 *igmpv3) | ||||
{ | { | ||||
struct igmp_ifsoftc *igi; | struct igmp_ifsoftc *igi; | ||||
struct in_multi *inm; | struct in_multi *inm = NULL; | ||||
int is_general_query; | int is_general_query; | ||||
uint32_t maxresp, nsrc, qqi; | uint32_t maxresp, nsrc, qqi; | ||||
uint16_t timer; | uint16_t timer; | ||||
uint8_t qrv; | uint8_t qrv; | ||||
is_general_query = 0; | is_general_query = 0; | ||||
CTR2(KTR_IGMPV3, "process v3 query on ifp %p(%s)", ifp, ifp->if_xname); | CTR2(KTR_IGMPV3, "process v3 query on ifp %p(%s)", ifp, ifp->if_xname); | ||||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | if (is_general_query) { | ||||
* group-specific or group-and-source query. | * group-specific or group-and-source query. | ||||
*/ | */ | ||||
if (igi->igi_v3_timer == 0 || igi->igi_v3_timer >= timer) | if (igi->igi_v3_timer == 0 || igi->igi_v3_timer >= timer) | ||||
igmp_input_v3_group_query(inm, igi, timer, igmpv3); | igmp_input_v3_group_query(inm, igi, timer, igmpv3); | ||||
} | } | ||||
out_locked: | out_locked: | ||||
IGMP_UNLOCK(); | IGMP_UNLOCK(); | ||||
if (inm) | |||||
hselasky: After this change you need to initialize the inm pointer to NULL! | |||||
inm_release_deferred(inm); | |||||
IN_MULTI_LIST_UNLOCK(); | IN_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Process a received IGMPv3 group-specific or group-and-source-specific | * Process a received IGMPv3 group-specific or group-and-source-specific | ||||
* query. | * query. | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | if (inm != NULL) { | ||||
case IGMP_G_QUERY_PENDING_MEMBER: | case IGMP_G_QUERY_PENDING_MEMBER: | ||||
case IGMP_SG_QUERY_PENDING_MEMBER: | case IGMP_SG_QUERY_PENDING_MEMBER: | ||||
case IGMP_LEAVING_MEMBER: | case IGMP_LEAVING_MEMBER: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
if (inm) | |||||
inm_release_deferred(inm); | |||||
IN_MULTI_LIST_UNLOCK(); | IN_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Process a received IGMPv2 host membership report. | * Process a received IGMPv2 host membership report. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | case IGMP_LAZY_MEMBER: | ||||
inm->inm_state = IGMP_LAZY_MEMBER; | inm->inm_state = IGMP_LAZY_MEMBER; | ||||
break; | break; | ||||
case IGMP_G_QUERY_PENDING_MEMBER: | case IGMP_G_QUERY_PENDING_MEMBER: | ||||
case IGMP_SG_QUERY_PENDING_MEMBER: | case IGMP_SG_QUERY_PENDING_MEMBER: | ||||
case IGMP_LEAVING_MEMBER: | case IGMP_LEAVING_MEMBER: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
if (inm) | |||||
inm_release_deferred(inm); | |||||
IN_MULTI_LIST_UNLOCK(); | IN_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
igmp_input(struct mbuf **mp, int *offp, int proto) | igmp_input(struct mbuf **mp, int *offp, int proto) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 619 Lines • ▼ Show 20 Lines | case IGMP_LEAVING_MEMBER: | ||||
* If we are leaving the group and switching to | * If we are leaving the group and switching to | ||||
* compatibility mode, we need to release the final | * compatibility mode, we need to release the final | ||||
* reference held for issuing the INCLUDE {}, and | * reference held for issuing the INCLUDE {}, and | ||||
* transition to REPORTING to ensure the host leave | * transition to REPORTING to ensure the host leave | ||||
* message is sent upstream to the old querier -- | * message is sent upstream to the old querier -- | ||||
* transition to NOT would lose the leave and race. | * transition to NOT would lose the leave and race. | ||||
*/ | */ | ||||
inm_rele_locked(&inm_free_tmp, inm); | inm_rele_locked(&inm_free_tmp, inm); | ||||
ifma->ifma_protospec = NULL; | |||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case IGMP_G_QUERY_PENDING_MEMBER: | case IGMP_G_QUERY_PENDING_MEMBER: | ||||
case IGMP_SG_QUERY_PENDING_MEMBER: | case IGMP_SG_QUERY_PENDING_MEMBER: | ||||
inm_clear_recorded(inm); | inm_clear_recorded(inm); | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case IGMP_REPORTING_MEMBER: | case IGMP_REPORTING_MEMBER: | ||||
inm->inm_state = IGMP_REPORTING_MEMBER; | inm->inm_state = IGMP_REPORTING_MEMBER; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 215 Lines • ▼ Show 20 Lines | igmp_change_state(struct in_multi *inm) | ||||
error = 0; | error = 0; | ||||
IN_MULTI_LOCK_ASSERT(); | IN_MULTI_LOCK_ASSERT(); | ||||
/* | /* | ||||
* Try to detect if the upper layer just asked us to change state | * Try to detect if the upper layer just asked us to change state | ||||
* for an interface which has now gone away. | * for an interface which has now gone away. | ||||
*/ | */ | ||||
KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__)); | KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__)); | ||||
ifp = inm->inm_ifma->ifma_ifp; | ifp = inm->inm_ifma->ifma_ifp; | ||||
/* The interface address has gone away */ | |||||
if (ifp == NULL) | |||||
return (0); | |||||
/* | /* | ||||
* Sanity check that netinet's notion of ifp is the | * Sanity check that netinet's notion of ifp is the | ||||
* same as net's. | * same as net's. | ||||
*/ | */ | ||||
KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); | KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); | ||||
IGMP_LOCK(); | IGMP_LOCK(); | ||||
▲ Show 20 Lines • Show All 1,376 Lines • Show Last 20 Lines |
After this change you need to initialize the inm pointer to NULL!