FreeBSD/sys/netinet6/mld6.c
/*
 * Process a received MLDv1 general or address-specific query.
 * Assumes that the query header has been pulled up to sizeof(mld_hdr).
 *
 * 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 general or address-specific query.
Assumes that the query header has been pulled up to sizeof(mld_hdr).

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 general or address - specific query . Assumes that the query header has been pulled up to sizeof ( mld_hdr ) . 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_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
     struct mld_hdr *mld)
{
	struct ifmultiaddr	*ifma;
	struct mld_ifsoftc	*mli;
	struct in6_multi	*inm;
	int			 is_general_query;
	uint16_t		 timer;
#ifdef KTR
	char			 ip6tbuf[INET6_ADDRSTRLEN];
#endif
	is_general_query = 0;
	if (!mld_v1enable) {
		CTR3(KTR_MLD, "ignore v1 query %s on ifp %p(%s)",
		    ip6_sprintf(ip6tbuf, &mld->mld_addr),
		    ifp, if_name(ifp));
		return (0);
	}
	if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
		CTR3(KTR_MLD, "ignore v1 query src %s on ifp %p(%s)",
		    ip6_sprintf(ip6tbuf, &ip6->ip6_src),
		    ifp, if_name(ifp));
		return (0);
	}
	if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
		struct in6_addr		 dst;
		dst = ip6->ip6_dst;
		in6_clearscope(&dst);
		if (!IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes))
			return (EINVAL);
		is_general_query = 1;
	} else {
		in6_setscope(&mld->mld_addr, ifp, NULL);
	}
	IN6_MULTI_LOCK();
	MLD_LOCK();
	mli = MLD_IFINFO(ifp);
	KASSERT(mli != NULL, ("%s: no mld_ifsoftc for ifp %p", __func__, ifp));
	mld_set_version(mli, MLD_VERSION_1);
	timer = (ntohs(mld->mld_maxdelay) * PR_FASTHZ) / MLD_TIMER_SCALE;
	if (timer == 0)
		timer = 1;
	IF_ADDR_RLOCK(ifp);
	if (is_general_query) {
		CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)",
		    ifp, if_name(ifp));
		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
			if (ifma->ifma_addr->sa_family != AF_INET6 ||
			    ifma->ifma_protospec == NULL)
				continue;
			inm = (struct in6_multi *)ifma->ifma_protospec;
			mld_v1_update_group(inm, timer);
		}
	} else {
		inm = in6m_lookup_locked(ifp, &mld->mld_addr);
		if (inm != NULL) {
			CTR3(KTR_MLD, "process v1 query %s on ifp %p(%s)",
			    ip6_sprintf(ip6tbuf, &mld->mld_addr),
			    ifp, if_name(ifp));
			mld_v1_update_group(inm, timer);
		}
		in6_clearscope(&mld->mld_addr);
	}
	IF_ADDR_RUNLOCK(ifp);
	MLD_UNLOCK();
	IN6_MULTI_UNLOCK();
	return (0);
}
static int mld_v1_input_query ( struct ifnet * ifp , const struct ip6_hdr * ip6 , struct mld_hdr * mld ) { struct ifmultiaddr * ifma ; struct mld_ifsoftc * mli ; struct in6_multi * inm ; int is_general_query ; uint16_t timer ; #ifdef KTR char ip6tbuf [ INET6_ADDRSTRLEN ] ; #endif is_general_query = 0 ; if ( ! mld_v1enable ) { CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & mld -> mld_addr ) , ifp , if_name ( ifp ) ) ; return ( 0 ) ; } if ( ! IN6_IS_SCOPE_LINKLOCAL ( & ip6 -> ip6_src ) ) { CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & ip6 -> ip6_src ) , ifp , if_name ( ifp ) ) ; return ( 0 ) ; } if ( IN6_IS_ADDR_UNSPECIFIED ( & mld -> mld_addr ) ) { struct in6_addr dst ; dst = ip6 -> ip6_dst ; in6_clearscope ( & dst ) ; if ( ! IN6_ARE_ADDR_EQUAL ( & dst , & in6addr_linklocal_allnodes ) ) return ( EINVAL ) ; is_general_query = 1 ; } else { in6_setscope ( & mld -> mld_addr , ifp , NULL ) ; } IN6_MULTI_LOCK ( ) ; MLD_LOCK ( ) ; mli = MLD_IFINFO ( ifp ) ; KASSERT ( mli != NULL , ( " " , __func__ , ifp ) ) ; mld_set_version ( mli , MLD_VERSION_1 ) ; timer = ( ntohs ( mld -> mld_maxdelay ) * PR_FASTHZ ) / MLD_TIMER_SCALE ; if ( timer == 0 ) timer = 1 ; IF_ADDR_RLOCK ( ifp ) ; if ( is_general_query ) { CTR2 ( KTR_MLD , " " , ifp , if_name ( ifp ) ) ; TAILQ_FOREACH ( ifma , & ifp -> if_multiaddrs , ifma_link ) { if ( ifma -> ifma_addr -> sa_family != AF_INET6 || ifma -> ifma_protospec == NULL ) continue ; inm = ( struct in6_multi * ) ifma -> ifma_protospec ; mld_v1_update_group ( inm , timer ) ; } } else { inm = in6m_lookup_locked ( ifp , & mld -> mld_addr ) ; if ( inm != NULL ) { CTR3 ( KTR_MLD , " " , ip6_sprintf ( ip6tbuf , & mld -> mld_addr ) , ifp , if_name ( ifp ) ) ; mld_v1_update_group ( inm , timer ) ; } in6_clearscope ( & mld -> mld_addr ) ; } IF_ADDR_RUNLOCK ( ifp ) ; MLD_UNLOCK ( ) ; IN6_MULTI_UNLOCK ( ) ; return ( 0 ) ; }
Process a received MLDv1 general or address-specific query.
Process a received MLDv1 general or address - specific query .
/*const*/ /*
	 * RFC3810 Section 6.2: MLD queries must originate from
	 * a router's link-local address.
	 */ /*
	 * Do address field validation upfront before we accept
	 * the query.
	 */ /*
		 * MLDv1 General Query.
		 * If this was not sent to the all-nodes group, ignore it.
		 */ /*
		 * Embed scope ID of receiving interface in MLD query for
		 * lookup whilst we don't hold other locks.
		 */ /*
	 * Switch to MLDv1 host compatibility mode.
	 */ /*
		 * For each reporting group joined on this
		 * interface, kick the report timer.
		 */ /*
		 * MLDv1 Group-Specific Query.
		 * If this is a group-specific MLDv1 query, we need only
		 * look up the single group to process it.
		 */ /* XXX Clear embedded scope ID as userland won't expect it. */