FreeBSD/sys/netinet6/mld6.c
/*
 * Process a received MLDv1 host membership report.
 * Assumes mld points to mld_hdr in pulled up mbuf chain.
 *
 * NOTE: Can't be fully const correct as we temporarily embed scope ID in
 * mld_addr. This is OK as we own the mbuf chain.
 */
Process a received MLDv1 host membership report.
Assumes mld points to mld_hdr in pulled up mbuf chain.

Can't be fully const correct as we temporarily embed scope ID in
mld_addr. This is OK as we own the mbuf chain.
Process a received MLDv1 host membership report . Assumes mld points to mld_hdr in pulled up mbuf chain . Can ' t be fully const correct as we temporarily embed scope ID in mld_addr . This is OK as we own the mbuf chain .
static int
mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
     struct mld_hdr *mld)
{
	struct in6_addr		 src, dst;
	struct in6_ifaddr	*ia;
	struct in6_multi	*inm;
#ifdef KTR
	char			 ip6tbuf[INET6_ADDRSTRLEN];
#endif
	if (!mld_v1enable) {
		CTR3(KTR_MLD, "ignore v1 report %s on ifp %p(%s)",
		    ip6_sprintf(ip6tbuf, &mld->mld_addr),
		    ifp, if_name(ifp));
		return (0);
	}
	if (ifp->if_flags & IFF_LOOPBACK)
		return (0);
	src = ip6->ip6_src;
	in6_clearscope(&src);
	if (!IN6_IS_SCOPE_LINKLOCAL(&src) && !IN6_IS_ADDR_UNSPECIFIED(&src)) {
		CTR3(KTR_MLD, "ignore v1 query src %s on ifp %p(%s)",
		    ip6_sprintf(ip6tbuf, &ip6->ip6_src),
		    ifp, if_name(ifp));
		return (EINVAL);
	}
	dst = ip6->ip6_dst;
	in6_clearscope(&dst);
	if (!IN6_IS_ADDR_MULTICAST(&mld->mld_addr) ||
	    !IN6_ARE_ADDR_EQUAL(&mld->mld_addr, &dst)) {
		CTR3(KTR_MLD, "ignore v1 query dst %s on ifp %p(%s)",
		    ip6_sprintf(ip6tbuf, &ip6->ip6_dst),
		    ifp, if_name(ifp));
		return (EINVAL);
	}
	ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
	if ((ia && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, IA6_IN6(ia))) ||
	    (ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src))) {
		if (ia != NULL)
			ifa_free(&ia->ia_ifa);
		return (0);
	}
	if (ia != NULL)
		ifa_free(&ia->ia_ifa);
	CTR3(KTR_MLD, "process v1 report %s on ifp %p(%s)",
	    ip6_sprintf(ip6tbuf, &mld->mld_addr), ifp, if_name(ifp));
	if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr))
		in6_setscope(&mld->mld_addr, ifp, NULL);
	IN6_MULTI_LOCK();
	MLD_LOCK();
	IF_ADDR_RLOCK(ifp);
	inm = in6m_lookup_locked(ifp, &mld->mld_addr);
	if (inm != NULL) {
		struct mld_ifsoftc *mli;
		mli = inm->in6m_mli;
		KASSERT(mli != NULL,
		    ("%s: no mli for ifp %p", __func__, ifp));
		if (mli->mli_version == MLD_VERSION_2)
			goto out_locked;
		inm->in6m_timer = 0;
		switch (inm->in6m_state) {
		case MLD_NOT_MEMBER:
		case MLD_SILENT_MEMBER:
		case MLD_SLEEPING_MEMBER:
			break;
		case MLD_REPORTING_MEMBER:
		case MLD_IDLE_MEMBER:
		case MLD_AWAKENING_MEMBER:
			CTR3(KTR_MLD,
			    "report suppressed for %s on ifp %p(%s)",
			    ip6_sprintf(ip6tbuf, &mld->mld_addr),
			    ifp, if_name(ifp));
		case MLD_LAZY_MEMBER:
			inm->in6m_state = MLD_LAZY_MEMBER;
			break;
		case MLD_G_QUERY_PENDING_MEMBER:
		case MLD_SG_QUERY_PENDING_MEMBER:
		case MLD_LEAVING_MEMBER:
			break;
		}
	}
out_locked:
	IF_ADDR_RUNLOCK(ifp);
	MLD_UNLOCK();
	IN6_MULTI_UNLOCK();
	in6_clearscope(&mld->mld_addr);
	return (0);
}
static int mld_v1_input_report ( struct ifnet * ifp , const struct ip6_hdr * ip6 , struct mld_hdr * mld ) { struct in6_addr src , dst ; struct in6_ifaddr * ia ; struct in6_multi * inm ; #ifdef KTR char ip6tbuf [ INET6_ADDRSTRLEN ] ; #endif if ( ! mld_v1enable ) { CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & mld -> mld_addr ) , ifp , if_name ( ifp ) ) ; return ( 0 ) ; } if ( ifp -> if_flags & IFF_LOOPBACK ) return ( 0 ) ; src = ip6 -> ip6_src ; in6_clearscope ( & src ) ; if ( ! IN6_IS_SCOPE_LINKLOCAL ( & src ) && ! IN6_IS_ADDR_UNSPECIFIED ( & src ) ) { CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & ip6 -> ip6_src ) , ifp , if_name ( ifp ) ) ; return ( EINVAL ) ; } dst = ip6 -> ip6_dst ; in6_clearscope ( & dst ) ; if ( ! IN6_IS_ADDR_MULTICAST ( & mld -> mld_addr ) || ! IN6_ARE_ADDR_EQUAL ( & mld -> mld_addr , & dst ) ) { CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & ip6 -> ip6_dst ) , ifp , if_name ( ifp ) ) ; return ( EINVAL ) ; } ia = in6ifa_ifpforlinklocal ( ifp , IN6_IFF_NOTREADY | IN6_IFF_ANYCAST ) ; if ( ( ia && IN6_ARE_ADDR_EQUAL ( & ip6 -> ip6_src , IA6_IN6 ( ia ) ) ) || ( ia == NULL && IN6_IS_ADDR_UNSPECIFIED ( & src ) ) ) { if ( ia != NULL ) ifa_free ( & ia -> ia_ifa ) ; return ( 0 ) ; } if ( ia != NULL ) ifa_free ( & ia -> ia_ifa ) ; CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & mld -> mld_addr ) , ifp , if_name ( ifp ) ) ; if ( ! IN6_IS_ADDR_UNSPECIFIED ( & mld -> mld_addr ) ) in6_setscope ( & mld -> mld_addr , ifp , NULL ) ; IN6_MULTI_LOCK ( ) ; MLD_LOCK ( ) ; IF_ADDR_RLOCK ( ifp ) ; inm = in6m_lookup_locked ( ifp , & mld -> mld_addr ) ; if ( inm != NULL ) { struct mld_ifsoftc * mli ; mli = inm -> in6m_mli ; KASSERT ( mli != NULL , ( " " , __func__ , ifp ) ) ; if ( mli -> mli_version == MLD_VERSION_2 ) goto out_locked ; inm -> in6m_timer = 0 ; switch ( inm -> in6m_state ) { case MLD_NOT_MEMBER : case MLD_SILENT_MEMBER : case MLD_SLEEPING_MEMBER : break ; case MLD_REPORTING_MEMBER : case MLD_IDLE_MEMBER : case MLD_AWAKENING_MEMBER : CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & mld -> mld_addr ) , ifp , if_name ( ifp ) ) ; case MLD_LAZY_MEMBER : inm -> in6m_state = MLD_LAZY_MEMBER ; break ; case MLD_G_QUERY_PENDING_MEMBER : case MLD_SG_QUERY_PENDING_MEMBER : case MLD_LEAVING_MEMBER : break ; } } out_locked : IF_ADDR_RUNLOCK ( ifp ) ; MLD_UNLOCK ( ) ; IN6_MULTI_UNLOCK ( ) ; in6_clearscope ( & mld -> mld_addr ) ; return ( 0 ) ; }
Process a received MLDv1 host membership report.
Process a received MLDv1 host membership report .
/*const*/ /*
	 * MLDv1 reports must originate from a host's link-local address,
	 * or the unspecified address (when booting).
	 */ /*
	 * RFC2710 Section 4: MLDv1 reports must pertain to a multicast
	 * group, and must be directed to the group itself.
	 */ /*
	 * Make sure we don't hear our own membership report, as fast
	 * leave requires knowing that we are the only member of a
	 * group. Assume we used the link-local address if available,
	 * otherwise look for ::.
	 *
	 * XXX Note that scope ID comparison is needed for the address
	 * returned by in6ifa_ifpforlinklocal(), but SHOULD NOT be
	 * performed for the on-wire address.
	 */ /*
	 * Embed scope ID of receiving interface in MLD query for lookup
	 * whilst we don't hold other locks (due to KAME locking lameness).
	 */ /*
	 * MLDv1 report suppression.
	 * If we are a member of this group, and our membership should be
	 * reported, and our group timer is pending or about to be reset,
	 * stop our group timer by transitioning to the 'lazy' state.
	 */ /*
		 * If we are in MLDv2 host mode, do not allow the
		 * other host's MLDv1 report to suppress our reports.
		 */ /* XXX Clear embedded scope ID as userland won't expect it. */