FreeBSD/sys/netinet6/in6_mcast.c
/*
 * Set the IP multicast options in response to user setsockopt().
 *
 * Many of the socket options handled in this function duplicate the
 * functionality of socket options in the regular unicast API. However,
 * it is not possible to merge the duplicate code, because the idempotence
 * of the IPv6 multicast part of the BSD Sockets API must be preserved;
 * the effects of these options must be treated as separate and distinct.
 *
 * SMPng: XXX: Unlocked read of inp_socket believed OK.
 */
Set the IP multicast options in response to user setsockopt().
Many of the socket options handled in this function duplicate the
functionality of socket options in the regular unicast API. However,
it is not possible to merge the duplicate code, because the idempotence
of the IPv6 multicast part of the BSD Sockets API must be preserved;
the effects of these options must be treated as separate and distinct.

Unlocked read of inp_socket believed OK.
Set the IP multicast options in response to user setsockopt () . Many of the socket options handled in this function duplicate the functionality of socket options in the regular unicast API . However it is not possible to merge the duplicate code because the idempotence of the IPv6 multicast part of the BSD Sockets API must be preserved ; the effects of these options must be treated as separate and distinct . Unlocked read of inp_socket believed OK .
int
ip6_setmoptions(struct inpcb *inp, struct sockopt *sopt)
{
	struct ip6_moptions	*im6o;
	int			 error;
	error = 0;
	if (inp->inp_socket->so_proto->pr_protocol == IPPROTO_DIVERT ||
	    (inp->inp_socket->so_proto->pr_type != SOCK_RAW &&
	     inp->inp_socket->so_proto->pr_type != SOCK_DGRAM))
		return (EOPNOTSUPP);
	switch (sopt->sopt_name) {
	case IPV6_MULTICAST_IF:
		error = in6p_set_multicast_if(inp, sopt);
		break;
	case IPV6_MULTICAST_HOPS: {
		int hlim;
		if (sopt->sopt_valsize != sizeof(int)) {
			error = EINVAL;
			break;
		}
		error = sooptcopyin(sopt, &hlim, sizeof(hlim), sizeof(int));
		if (error)
			break;
		if (hlim < -1 || hlim > 255) {
			error = EINVAL;
			break;
		} else if (hlim == -1) {
			hlim = V_ip6_defmcasthlim;
		}
		im6o = in6p_findmoptions(inp);
		im6o->im6o_multicast_hlim = hlim;
		INP_WUNLOCK(inp);
		break;
	}
	case IPV6_MULTICAST_LOOP: {
		u_int loop;
		if (sopt->sopt_valsize != sizeof(u_int)) {
			error = EINVAL;
			break;
		}
		error = sooptcopyin(sopt, &loop, sizeof(u_int), sizeof(u_int));
		if (error)
			break;
		if (loop > 1) {
			error = EINVAL;
			break;
		}
		im6o = in6p_findmoptions(inp);
		im6o->im6o_multicast_loop = loop;
		INP_WUNLOCK(inp);
		break;
	}
	case IPV6_JOIN_GROUP:
	case MCAST_JOIN_GROUP:
	case MCAST_JOIN_SOURCE_GROUP:
		error = in6p_join_group(inp, sopt);
		break;
	case IPV6_LEAVE_GROUP:
	case MCAST_LEAVE_GROUP:
	case MCAST_LEAVE_SOURCE_GROUP:
		error = in6p_leave_group(inp, sopt);
		break;
	case MCAST_BLOCK_SOURCE:
	case MCAST_UNBLOCK_SOURCE:
		error = in6p_block_unblock_source(inp, sopt);
		break;
	case IPV6_MSFILTER:
		error = in6p_set_source_filters(inp, sopt);
		break;
	default:
		error = EOPNOTSUPP;
		break;
	}
	INP_UNLOCK_ASSERT(inp);
	return (error);
}
int ip6_setmoptions ( struct inpcb * inp , struct sockopt * sopt ) { struct ip6_moptions * im6o ; int error ; error = 0 ; if ( inp -> inp_socket -> so_proto -> pr_protocol == IPPROTO_DIVERT || ( inp -> inp_socket -> so_proto -> pr_type != SOCK_RAW && inp -> inp_socket -> so_proto -> pr_type != SOCK_DGRAM ) ) return ( EOPNOTSUPP ) ; switch ( sopt -> sopt_name ) { case IPV6_MULTICAST_IF : error = in6p_set_multicast_if ( inp , sopt ) ; break ; case IPV6_MULTICAST_HOPS : { int hlim ; if ( sopt -> sopt_valsize != sizeof ( int ) ) { error = EINVAL ; break ; } error = sooptcopyin ( sopt , & hlim , sizeof ( hlim ) , sizeof ( int ) ) ; if ( error ) break ; if ( hlim < -1 || hlim > 255 ) { error = EINVAL ; break ; } else if ( hlim == -1 ) { hlim = V_ip6_defmcasthlim ; } im6o = in6p_findmoptions ( inp ) ; im6o -> im6o_multicast_hlim = hlim ; INP_WUNLOCK ( inp ) ; break ; } case IPV6_MULTICAST_LOOP : { u_int loop ; if ( sopt -> sopt_valsize != sizeof ( u_int ) ) { error = EINVAL ; break ; } error = sooptcopyin ( sopt , & loop , sizeof ( u_int ) , sizeof ( u_int ) ) ; if ( error ) break ; if ( loop > 1 ) { error = EINVAL ; break ; } im6o = in6p_findmoptions ( inp ) ; im6o -> im6o_multicast_loop = loop ; INP_WUNLOCK ( inp ) ; break ; } case IPV6_JOIN_GROUP : case MCAST_JOIN_GROUP : case MCAST_JOIN_SOURCE_GROUP : error = in6p_join_group ( inp , sopt ) ; break ; case IPV6_LEAVE_GROUP : case MCAST_LEAVE_GROUP : case MCAST_LEAVE_SOURCE_GROUP : error = in6p_leave_group ( inp , sopt ) ; break ; case MCAST_BLOCK_SOURCE : case MCAST_UNBLOCK_SOURCE : error = in6p_block_unblock_source ( inp , sopt ) ; break ; case IPV6_MSFILTER : error = in6p_set_source_filters ( inp , sopt ) ; break ; default : error = EOPNOTSUPP ; break ; } INP_UNLOCK_ASSERT ( inp ) ; return ( error ) ; }
Set the IP multicast options in response to user setsockopt().
Set the IP multicast options in response to user setsockopt () .
/*
	 * If socket is neither of type SOCK_RAW or SOCK_DGRAM,
	 * or is a divert socket, reject it.
	 */ /*
		 * Set the loopback flag for outgoing multicast packets.
		 * Must be zero or one.
		 */