FreeBSD/sys/netinet6/in6_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 in6m_release(*) as this function also
 * makes a state change downcall into MLD.
 */
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 in6m_release(*) as this function also
makes a state change downcall into MLD.
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 in6m_release ( * ) as this function also makes a state change downcall into MLD .
int
in6_mc_leave_locked(struct in6_multi *inm,  struct in6_mfilter *imf)
{
	struct in6_mfilter	 timf;
	int			 error;
#ifdef KTR
	char			 ip6tbuf[INET6_ADDRSTRLEN];
#endif
	error = 0;
	IN6_MULTI_LOCK_ASSERT();
	CTR5(KTR_MLD, "%s: leave inm %p, %s/%s, imf %p", __func__,
	    inm, ip6_sprintf(ip6tbuf, &inm->in6m_addr),
	    (in6m_is_ifp_detached(inm) ? "null" : if_name(inm->in6m_ifp)),
	    imf);
	if (imf == NULL) {
		im6f_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED);
		imf = &timf;
	}
	CTR1(KTR_MLD, "%s: merge inm state", __func__);
	error = in6m_merge(inm, imf);
	KASSERT(error == 0, ("%s: failed to merge inm state", __func__));
	CTR1(KTR_MLD, "%s: doing mld downcall", __func__);
	error = mld_change_state(inm, 0);
	if (error)
		CTR1(KTR_MLD, "%s: failed mld downcall", __func__);
	CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm);
	in6m_release_locked(inm);
	return (error);
}
int in6_mc_leave_locked ( struct in6_multi * inm , struct in6_mfilter * imf ) { struct in6_mfilter timf ; int error ; #ifdef KTR char ip6tbuf [ INET6_ADDRSTRLEN ] ; #endif error = 0 ; IN6_MULTI_LOCK_ASSERT ( ) ; CTR5 ( KTR_MLD , " " , __func__ , inm , ip6_sprintf ( ip6tbuf , & inm -> in6m_addr ) , ( in6m_is_ifp_detached ( inm ) ? " " : if_name ( inm -> in6m_ifp ) ) , imf ) ; if ( imf == NULL ) { im6f_init ( & timf , MCAST_EXCLUDE , MCAST_UNDEFINED ) ; imf = & timf ; } CTR1 ( KTR_MLD , " " , __func__ ) ; error = in6m_merge ( inm , imf ) ; KASSERT ( error == 0 , ( " " , __func__ ) ) ; CTR1 ( KTR_MLD , " " , __func__ ) ; error = mld_change_state ( inm , 0 ) ; if ( error ) CTR1 ( KTR_MLD , " " , __func__ ) ; CTR2 ( KTR_MLD , " " , __func__ , inm ) ; in6m_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 MLD 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.
	 */