FreeBSD/sys/netinet6/in6_mcast.c
/*
 * Atomically get source filters on a socket for an IPv6 multicast group.
 * Called with INP lock held; returns with lock released.
 */
Atomically get source filters on a socket for an IPv6 multicast group.
Called with INP lock held; returns with lock released.
Atomically get source filters on a socket for an IPv6 multicast group . Called with INP lock held ; returns with lock released .
static int
in6p_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
{
	struct __msfilterreq	 msfr;
	sockunion_t		*gsa;
	struct ifnet		*ifp;
	struct ip6_moptions	*imo;
	struct in6_mfilter	*imf;
	struct ip6_msource	*ims;
	struct in6_msource	*lims;
	struct sockaddr_in6	*psin;
	struct sockaddr_storage	*ptss;
	struct sockaddr_storage	*tss;
	int			 error;
	size_t			 idx, nsrcs, ncsrcs;
	INP_WLOCK_ASSERT(inp);
	imo = inp->in6p_moptions;
	KASSERT(imo != NULL, ("%s: null ip6_moptions", __func__));
	INP_WUNLOCK(inp);
	error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq),
	    sizeof(struct __msfilterreq));
	if (error)
		return (error);
	if (msfr.msfr_group.ss_family != AF_INET6 ||
	    msfr.msfr_group.ss_len != sizeof(struct sockaddr_in6))
		return (EINVAL);
	gsa = (sockunion_t *)&msfr.msfr_group;
	if (!IN6_IS_ADDR_MULTICAST(&gsa->sin6.sin6_addr))
		return (EINVAL);
	if (msfr.msfr_ifindex == 0 || V_if_index < msfr.msfr_ifindex)
		return (EADDRNOTAVAIL);
	ifp = ifnet_byindex(msfr.msfr_ifindex);
	if (ifp == NULL)
		return (EADDRNOTAVAIL);
	(void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL);
	INP_WLOCK(inp);
	idx = im6o_match_group(imo, ifp, &gsa->sa);
	if (idx == -1 || imo->im6o_mfilters == NULL) {
		INP_WUNLOCK(inp);
		return (EADDRNOTAVAIL);
	}
	imf = &imo->im6o_mfilters[idx];
	if (imf->im6f_st[1] == MCAST_UNDEFINED) {
		INP_WUNLOCK(inp);
		return (EAGAIN);
	}
	msfr.msfr_fmode = imf->im6f_st[1];
	if (msfr.msfr_nsrcs > in6_mcast_maxsocksrc)
		msfr.msfr_nsrcs = in6_mcast_maxsocksrc;
	tss = NULL;
	if (msfr.msfr_srcs != NULL && msfr.msfr_nsrcs > 0) {
		tss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs,
		    M_TEMP, M_NOWAIT | M_ZERO);
		if (tss == NULL) {
			INP_WUNLOCK(inp);
			return (ENOBUFS);
		}
	}
	nsrcs = msfr.msfr_nsrcs;
	ncsrcs = 0;
	ptss = tss;
	RB_FOREACH(ims, ip6_msource_tree, &imf->im6f_sources) {
		lims = (struct in6_msource *)ims;
		if (lims->im6sl_st[0] == MCAST_UNDEFINED ||
		    lims->im6sl_st[0] != imf->im6f_st[0])
			continue;
		++ncsrcs;
		if (tss != NULL && nsrcs > 0) {
			psin = (struct sockaddr_in6 *)ptss;
			psin->sin6_family = AF_INET6;
			psin->sin6_len = sizeof(struct sockaddr_in6);
			psin->sin6_addr = lims->im6s_addr;
			psin->sin6_port = 0;
			--nsrcs;
			++ptss;
		}
	}
	INP_WUNLOCK(inp);
	if (tss != NULL) {
		error = copyout(tss, msfr.msfr_srcs,
		    sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs);
		free(tss, M_TEMP);
		if (error)
			return (error);
	}
	msfr.msfr_nsrcs = ncsrcs;
	error = sooptcopyout(sopt, &msfr, sizeof(struct __msfilterreq));
	return (error);
}
static int in6p_get_source_filters ( struct inpcb * inp , struct sockopt * sopt ) { struct __msfilterreq msfr ; sockunion_t * gsa ; struct ifnet * ifp ; struct ip6_moptions * imo ; struct in6_mfilter * imf ; struct ip6_msource * ims ; struct in6_msource * lims ; struct sockaddr_in6 * psin ; struct sockaddr_storage * ptss ; struct sockaddr_storage * tss ; int error ; size_t idx , nsrcs , ncsrcs ; INP_WLOCK_ASSERT ( inp ) ; imo = inp -> in6p_moptions ; KASSERT ( imo != NULL , ( " " , __func__ ) ) ; INP_WUNLOCK ( inp ) ; error = sooptcopyin ( sopt , & msfr , sizeof ( struct __msfilterreq ) , sizeof ( struct __msfilterreq ) ) ; if ( error ) return ( error ) ; if ( msfr . msfr_group . ss_family != AF_INET6 || msfr . msfr_group . ss_len != sizeof ( struct sockaddr_in6 ) ) return ( EINVAL ) ; gsa = ( sockunion_t * ) & msfr . msfr_group ; if ( ! IN6_IS_ADDR_MULTICAST ( & gsa -> sin6 . sin6_addr ) ) return ( EINVAL ) ; if ( msfr . msfr_ifindex == 0 || V_if_index < msfr . msfr_ifindex ) return ( EADDRNOTAVAIL ) ; ifp = ifnet_byindex ( msfr . msfr_ifindex ) ; if ( ifp == NULL ) return ( EADDRNOTAVAIL ) ; ( void ) in6_setscope ( & gsa -> sin6 . sin6_addr , ifp , NULL ) ; INP_WLOCK ( inp ) ; idx = im6o_match_group ( imo , ifp , & gsa -> sa ) ; if ( idx == -1 || imo -> im6o_mfilters == NULL ) { INP_WUNLOCK ( inp ) ; return ( EADDRNOTAVAIL ) ; } imf = & imo -> im6o_mfilters [ idx ] ; if ( imf -> im6f_st [ 1 ] == MCAST_UNDEFINED ) { INP_WUNLOCK ( inp ) ; return ( EAGAIN ) ; } msfr . msfr_fmode = imf -> im6f_st [ 1 ] ; if ( msfr . msfr_nsrcs > in6_mcast_maxsocksrc ) msfr . msfr_nsrcs = in6_mcast_maxsocksrc ; tss = NULL ; if ( msfr . msfr_srcs != NULL && msfr . msfr_nsrcs > 0 ) { tss = malloc ( sizeof ( struct sockaddr_storage ) * msfr . msfr_nsrcs , M_TEMP , M_NOWAIT | M_ZERO ) ; if ( tss == NULL ) { INP_WUNLOCK ( inp ) ; return ( ENOBUFS ) ; } } nsrcs = msfr . msfr_nsrcs ; ncsrcs = 0 ; ptss = tss ; RB_FOREACH ( ims , ip6_msource_tree , & imf -> im6f_sources ) { lims = ( struct in6_msource * ) ims ; if ( lims -> im6sl_st [ 0 ] == MCAST_UNDEFINED || lims -> im6sl_st [ 0 ] != imf -> im6f_st [ 0 ] ) continue ; ++ ncsrcs ; if ( tss != NULL && nsrcs > 0 ) { psin = ( struct sockaddr_in6 * ) ptss ; psin -> sin6_family = AF_INET6 ; psin -> sin6_len = sizeof ( struct sockaddr_in6 ) ; psin -> sin6_addr = lims -> im6s_addr ; psin -> sin6_port = 0 ; -- nsrcs ; ++ ptss ; } } INP_WUNLOCK ( inp ) ; if ( tss != NULL ) { error = copyout ( tss , msfr . msfr_srcs , sizeof ( struct sockaddr_storage ) * msfr . msfr_nsrcs ) ; free ( tss , M_TEMP ) ; if ( error ) return ( error ) ; } msfr . msfr_nsrcs = ncsrcs ; error = sooptcopyout ( sopt , & msfr , sizeof ( struct __msfilterreq ) ) ; return ( error ) ; }
Atomically get source filters on a socket for an IPv6 multicast group.
Atomically get source filters on a socket for an IPv6 multicast group .
/*
	 * Lookup group on the socket.
	 */ /*
	 * Ignore memberships which are in limbo.
	 */ /*
	 * If the user specified a buffer, copy out the source filter
	 * entries to userland gracefully.
	 * We only copy out the number of entries which userland
	 * has asked for, but we always tell userland how big the
	 * buffer really needs to be.
	 */ /*
	 * Count number of sources in-mode at t0.
	 * If buffer space exists and remains, copy out source entries.
	 */