FreeBSD/sys/netinet/in_mcast.c
/*
 * Leave a multicast group; real entry point.
 * All source filters will be expunged.
 *
 * Only preserves atomicity at inm level.
 *
 * Holding the write lock for the INP which contains imf
 * is highly advisable. We can't assert for it as imf does not
 * contain a back-pointer to the owning inp.
 *
 * Note: This is not the same as inm_release(*) as this function also
 * makes a state change downcall into IGMP.
 */
Leave a multicast group; real entry point.
All source filters will be expunged.

Only preserves atomicity at inm level.

Holding the write lock for the INP which contains imf
is highly advisable. We can't assert for it as imf does not
contain a back-pointer to the owning inp.

This is not the same as inm_release(*) as this function also
makes a state change downcall into IGMP.
Leave a multicast group ; real entry point . All source filters will be expunged . Only preserves atomicity at inm level . Holding the write lock for the INP which contains imf is highly advisable . We can ' t assert for it as imf does not contain a back - pointer to the owning inp . This is not the same as inm_release ( * ) as this function also makes a state change downcall into IGMP .
int
in_leavegroup_locked(struct in_multi *inm,  struct in_mfilter *imf)
{
	struct in_mfilter	 timf;
	int			 error;
	error = 0;
	IN_MULTI_LOCK_ASSERT();
	CTR5(KTR_IGMPV3, "%s: leave inm %p, %s/%s, imf %p", __func__,
	    inm, inet_ntoa(inm->inm_addr),
	    (inm_is_ifp_detached(inm) ? "null" : inm->inm_ifp->if_xname),
	    imf);
	if (imf == NULL) {
		imf_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED);
		imf = &timf;
	}
	CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
	error = inm_merge(inm, imf);
	KASSERT(error == 0, ("%s: failed to merge inm state", __func__));
	CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
	CURVNET_SET(inm->inm_ifp->if_vnet);
	error = igmp_change_state(inm);
	CURVNET_RESTORE();
	if (error)
		CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
	CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm);
	inm_release_locked(inm);
	return (error);
}
int in_leavegroup_locked ( struct in_multi * inm , struct in_mfilter * imf ) { struct in_mfilter timf ; int error ; error = 0 ; IN_MULTI_LOCK_ASSERT ( ) ; CTR5 ( KTR_IGMPV3 , " " , __func__ , inm , inet_ntoa ( inm -> inm_addr ) , ( inm_is_ifp_detached ( inm ) ? " " : inm -> inm_ifp -> if_xname ) , imf ) ; if ( imf == NULL ) { imf_init ( & timf , MCAST_EXCLUDE , MCAST_UNDEFINED ) ; imf = & timf ; } CTR1 ( KTR_IGMPV3 , " " , __func__ ) ; error = inm_merge ( inm , imf ) ; KASSERT ( error == 0 , ( " " , __func__ ) ) ; CTR1 ( KTR_IGMPV3 , " " , __func__ ) ; CURVNET_SET ( inm -> inm_ifp -> if_vnet ) ; error = igmp_change_state ( inm ) ; CURVNET_RESTORE ( ) ; if ( error ) CTR1 ( KTR_IGMPV3 , " " , __func__ ) ; CTR2 ( KTR_IGMPV3 , " " , __func__ , inm ) ; inm_release_locked ( inm ) ; return ( error ) ; }
Leave a multicast group; real entry point.
Leave a multicast group ; real entry point .
/*const*/ /*
	 * If no imf was specified (i.e. kernel consumer),
	 * fake one up and assume it is an ASM join.
	 */ /*
	 * Begin state merge transaction at IGMP layer.
	 *
	 * As this particular invocation should not cause any memory
	 * to be allocated, and there is no opportunity to roll back
	 * the transaction, it MUST NOT fail.
	 */