FreeBSD/sys/netinet6/mld6.c
/*
 * Perform the final leave for a multicast address.
 *
 * When leaving a group:
 *  MLDv1 sends a DONE message, if and only if we are the reporter.
 *  MLDv2 enqueues a state-change report containing a transition
 *  to INCLUDE {} for immediate transmission.
 */
Perform the final leave for a multicast address.
When leaving a group:
MLDv1 sends a DONE message, if and only if we are the reporter.
MLDv2 enqueues a state-change report containing a transition
to INCLUDE {} for immediate transmission.
Perform the final leave for a multicast address . When leaving a group : MLDv1 sends a DONE message if and only if we are the reporter . MLDv2 enqueues a state - change report containing a transition to INCLUDE {} for immediate transmission .
static void
mld_final_leave(struct in6_multi *inm, struct mld_ifsoftc *mli)
{
	int syncstates;
#ifdef KTR
	char ip6tbuf[INET6_ADDRSTRLEN];
#endif
	syncstates = 1;
	CTR4(KTR_MLD, "%s: final leave %s on ifp %p(%s)",
	    __func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr),
	    inm->in6m_ifp, if_name(inm->in6m_ifp));
	IN6_MULTI_LOCK_ASSERT();
	MLD_LOCK_ASSERT();
	switch (inm->in6m_state) {
	case MLD_NOT_MEMBER:
	case MLD_SILENT_MEMBER:
	case MLD_LEAVING_MEMBER:
		CTR1(KTR_MLD,
"%s: not kicking state machine for silent group", __func__);
		break;
	case MLD_REPORTING_MEMBER:
	case MLD_IDLE_MEMBER:
	case MLD_G_QUERY_PENDING_MEMBER:
	case MLD_SG_QUERY_PENDING_MEMBER:
		if (mli->mli_version == MLD_VERSION_1) {
#ifdef INVARIANTS
			if (inm->in6m_state == MLD_G_QUERY_PENDING_MEMBER ||
			    inm->in6m_state == MLD_SG_QUERY_PENDING_MEMBER)
			panic("%s: MLDv2 state reached, not MLDv2 mode",
			     __func__);
#endif
			mld_v1_transmit_report(inm, MLD_LISTENER_DONE);
			inm->in6m_state = MLD_NOT_MEMBER;
			V_current_state_timers_running6 = 1;
		} else if (mli->mli_version == MLD_VERSION_2) {
			mbufq_drain(&inm->in6m_scq);
			inm->in6m_timer = 0;
			inm->in6m_scrv = mli->mli_rv;
			CTR4(KTR_MLD, "%s: Leaving %s/%s with %d "
			    "pending retransmissions.", __func__,
			    ip6_sprintf(ip6tbuf, &inm->in6m_addr),
			    if_name(inm->in6m_ifp), inm->in6m_scrv);
			if (inm->in6m_scrv == 0) {
				inm->in6m_state = MLD_NOT_MEMBER;
				inm->in6m_sctimer = 0;
			} else {
				int retval;
				in6m_acquire_locked(inm);
				retval = mld_v2_enqueue_group_record(
				    &inm->in6m_scq, inm, 1, 0, 0,
				    (mli->mli_flags & MLIF_USEALLOW));
				KASSERT(retval != 0,
				    ("%s: enqueue record = %d", __func__,
				     retval));
				inm->in6m_state = MLD_LEAVING_MEMBER;
				inm->in6m_sctimer = 1;
				V_state_change_timers_running6 = 1;
				syncstates = 0;
			}
			break;
		}
		break;
	case MLD_LAZY_MEMBER:
	case MLD_SLEEPING_MEMBER:
	case MLD_AWAKENING_MEMBER:
		break;
	}
	if (syncstates) {
		in6m_commit(inm);
		CTR3(KTR_MLD, "%s: T1 -> T0 for %s/%s", __func__,
		    ip6_sprintf(ip6tbuf, &inm->in6m_addr),
		    if_name(inm->in6m_ifp));
		inm->in6m_st[1].iss_fmode = MCAST_UNDEFINED;
		CTR3(KTR_MLD, "%s: T1 now MCAST_UNDEFINED for %p/%s",
		    __func__, &inm->in6m_addr, if_name(inm->in6m_ifp));
	}
}
static void mld_final_leave ( struct in6_multi * inm , struct mld_ifsoftc * mli ) { int syncstates ; #ifdef KTR char ip6tbuf [ INET6_ADDRSTRLEN ] ; #endif syncstates = 1 ; CTR4 ( KTR_MLD , " " , __func__ , ip6_sprintf ( ip6tbuf , & inm -> in6m_addr ) , inm -> in6m_ifp , if_name ( inm -> in6m_ifp ) ) ; IN6_MULTI_LOCK_ASSERT ( ) ; MLD_LOCK_ASSERT ( ) ; switch ( inm -> in6m_state ) { case MLD_NOT_MEMBER : case MLD_SILENT_MEMBER : case MLD_LEAVING_MEMBER : CTR1 ( KTR_MLD , " " , __func__ ) ; break ; case MLD_REPORTING_MEMBER : case MLD_IDLE_MEMBER : case MLD_G_QUERY_PENDING_MEMBER : case MLD_SG_QUERY_PENDING_MEMBER : if ( mli -> mli_version == MLD_VERSION_1 ) { #ifdef INVARIANTS if ( inm -> in6m_state == MLD_G_QUERY_PENDING_MEMBER || inm -> in6m_state == MLD_SG_QUERY_PENDING_MEMBER ) panic ( " " , __func__ ) ; #endif mld_v1_transmit_report ( inm , MLD_LISTENER_DONE ) ; inm -> in6m_state = MLD_NOT_MEMBER ; V_current_state_timers_running6 = 1 ; } else if ( mli -> mli_version == MLD_VERSION_2 ) { mbufq_drain ( & inm -> in6m_scq ) ; inm -> in6m_timer = 0 ; inm -> in6m_scrv = mli -> mli_rv ; CTR4 ( KTR_MLD , " " " " , __func__ , ip6_sprintf ( ip6tbuf , & inm -> in6m_addr ) , if_name ( inm -> in6m_ifp ) , inm -> in6m_scrv ) ; if ( inm -> in6m_scrv == 0 ) { inm -> in6m_state = MLD_NOT_MEMBER ; inm -> in6m_sctimer = 0 ; } else { int retval ; in6m_acquire_locked ( inm ) ; retval = mld_v2_enqueue_group_record ( & inm -> in6m_scq , inm , 1 , 0 , 0 , ( mli -> mli_flags & MLIF_USEALLOW ) ) ; KASSERT ( retval != 0 , ( " " , __func__ , retval ) ) ; inm -> in6m_state = MLD_LEAVING_MEMBER ; inm -> in6m_sctimer = 1 ; V_state_change_timers_running6 = 1 ; syncstates = 0 ; } break ; } break ; case MLD_LAZY_MEMBER : case MLD_SLEEPING_MEMBER : case MLD_AWAKENING_MEMBER : break ; } if ( syncstates ) { in6m_commit ( inm ) ; CTR3 ( KTR_MLD , " " , __func__ , ip6_sprintf ( ip6tbuf , & inm -> in6m_addr ) , if_name ( inm -> in6m_ifp ) ) ; inm -> in6m_st [ 1 ] . iss_fmode = MCAST_UNDEFINED ; CTR3 ( KTR_MLD , " " , __func__ , & inm -> in6m_addr , if_name ( inm -> in6m_ifp ) ) ; } }
Perform the final leave for a multicast address.
Perform the final leave for a multicast address .
/* Already leaving or left; do nothing. */ /*
			 * Stop group timer and all pending reports.
			 * Immediately enqueue a state-change report
			 * TO_IN {} to be sent on the next fast timeout,
			 * giving us an opportunity to merge reports.
			 */ /* Our reports are suppressed; do nothing. */