FreeBSD/sys/netinet/in_mcast.c
/*
 * Atomically get source filters on a socket for an IPv4 multicast group.
 * Called with INP lock held; returns with lock released.
 */
Atomically get source filters on a socket for an IPv4 multicast group.
Called with INP lock held; returns with lock released.
Atomically get source filters on a socket for an IPv4 multicast group . Called with INP lock held ; returns with lock released .
static int
inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
{
	struct __msfilterreq	 msfr;
	sockunion_t		*gsa;
	struct ifnet		*ifp;
	struct ip_moptions	*imo;
	struct in_mfilter	*imf;
	struct ip_msource	*ims;
	struct in_msource	*lims;
	struct sockaddr_in	*psin;
	struct sockaddr_storage	*ptss;
	struct sockaddr_storage	*tss;
	int			 error;
	size_t			 idx, nsrcs, ncsrcs;
	INP_WLOCK_ASSERT(inp);
	imo = inp->inp_moptions;
	KASSERT(imo != NULL, ("%s: null ip_moptions", __func__));
	INP_WUNLOCK(inp);
	error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq),
	    sizeof(struct __msfilterreq));
	if (error)
		return (error);
	if (msfr.msfr_ifindex == 0 || V_if_index < msfr.msfr_ifindex)
		return (EINVAL);
	ifp = ifnet_byindex(msfr.msfr_ifindex);
	if (ifp == NULL)
		return (EINVAL);
	INP_WLOCK(inp);
	gsa = (sockunion_t *)&msfr.msfr_group;
	idx = imo_match_group(imo, ifp, &gsa->sa);
	if (idx == -1 || imo->imo_mfilters == NULL) {
		INP_WUNLOCK(inp);
		return (EADDRNOTAVAIL);
	}
	imf = &imo->imo_mfilters[idx];
	if (imf->imf_st[1] == MCAST_UNDEFINED) {
		INP_WUNLOCK(inp);
		return (EAGAIN);
	}
	msfr.msfr_fmode = imf->imf_st[1];
	if (msfr.msfr_nsrcs > in_mcast_maxsocksrc)
		msfr.msfr_nsrcs = in_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, ip_msource_tree, &imf->imf_sources) {
		lims = (struct in_msource *)ims;
		if (lims->imsl_st[0] == MCAST_UNDEFINED ||
		    lims->imsl_st[0] != imf->imf_st[0])
			continue;
		++ncsrcs;
		if (tss != NULL && nsrcs > 0) {
			psin = (struct sockaddr_in *)ptss;
			psin->sin_family = AF_INET;
			psin->sin_len = sizeof(struct sockaddr_in);
			psin->sin_addr.s_addr = htonl(lims->ims_haddr);
			psin->sin_port = 0;
			++ptss;
			--nsrcs;
		}
	}
	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 inp_get_source_filters ( struct inpcb * inp , struct sockopt * sopt ) { struct __msfilterreq msfr ; sockunion_t * gsa ; struct ifnet * ifp ; struct ip_moptions * imo ; struct in_mfilter * imf ; struct ip_msource * ims ; struct in_msource * lims ; struct sockaddr_in * psin ; struct sockaddr_storage * ptss ; struct sockaddr_storage * tss ; int error ; size_t idx , nsrcs , ncsrcs ; INP_WLOCK_ASSERT ( inp ) ; imo = inp -> inp_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_ifindex == 0 || V_if_index < msfr . msfr_ifindex ) return ( EINVAL ) ; ifp = ifnet_byindex ( msfr . msfr_ifindex ) ; if ( ifp == NULL ) return ( EINVAL ) ; INP_WLOCK ( inp ) ; gsa = ( sockunion_t * ) & msfr . msfr_group ; idx = imo_match_group ( imo , ifp , & gsa -> sa ) ; if ( idx == -1 || imo -> imo_mfilters == NULL ) { INP_WUNLOCK ( inp ) ; return ( EADDRNOTAVAIL ) ; } imf = & imo -> imo_mfilters [ idx ] ; if ( imf -> imf_st [ 1 ] == MCAST_UNDEFINED ) { INP_WUNLOCK ( inp ) ; return ( EAGAIN ) ; } msfr . msfr_fmode = imf -> imf_st [ 1 ] ; if ( msfr . msfr_nsrcs > in_mcast_maxsocksrc ) msfr . msfr_nsrcs = in_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 , ip_msource_tree , & imf -> imf_sources ) { lims = ( struct in_msource * ) ims ; if ( lims -> imsl_st [ 0 ] == MCAST_UNDEFINED || lims -> imsl_st [ 0 ] != imf -> imf_st [ 0 ] ) continue ; ++ ncsrcs ; if ( tss != NULL && nsrcs > 0 ) { psin = ( struct sockaddr_in * ) ptss ; psin -> sin_family = AF_INET ; psin -> sin_len = sizeof ( struct sockaddr_in ) ; psin -> sin_addr . s_addr = htonl ( lims -> ims_haddr ) ; psin -> sin_port = 0 ; ++ ptss ; -- nsrcs ; } } 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 IPv4 multicast group.
Atomically get source filters on a socket for an IPv4 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.
	 */