FreeBSD/sys/netinet/in_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 IPv4 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.
 * FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING
 * is refactored to no longer use vifs.
 */
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 IPv4 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.
FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING
is refactored to no longer use vifs.
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 IPv4 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 . FUTURE : The IP_MULTICAST_VIF option may be eliminated if MROUTING is refactored to no longer use vifs .
int
inp_setmoptions(struct inpcb *inp, struct sockopt *sopt)
{
	struct ip_moptions	*imo;
	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 IP_MULTICAST_VIF: {
		int vifi;
		if (legal_vif_num == NULL) {
			error = EOPNOTSUPP;
			break;
		}
		error = sooptcopyin(sopt, &vifi, sizeof(int), sizeof(int));
		if (error)
			break;
		if (!legal_vif_num(vifi) && (vifi != -1)) {
			error = EINVAL;
			break;
		}
		imo = inp_findmoptions(inp);
		imo->imo_multicast_vif = vifi;
		INP_WUNLOCK(inp);
		break;
	}
	case IP_MULTICAST_IF:
		error = inp_set_multicast_if(inp, sopt);
		break;
	case IP_MULTICAST_TTL: {
		u_char ttl;
		if (sopt->sopt_valsize == sizeof(u_char)) {
			error = sooptcopyin(sopt, &ttl, sizeof(u_char),
			    sizeof(u_char));
			if (error)
				break;
		} else {
			u_int ittl;
			error = sooptcopyin(sopt, &ittl, sizeof(u_int),
			    sizeof(u_int));
			if (error)
				break;
			if (ittl > 255) {
				error = EINVAL;
				break;
			}
			ttl = (u_char)ittl;
		}
		imo = inp_findmoptions(inp);
		imo->imo_multicast_ttl = ttl;
		INP_WUNLOCK(inp);
		break;
	}
	case IP_MULTICAST_LOOP: {
		u_char loop;
		if (sopt->sopt_valsize == sizeof(u_char)) {
			error = sooptcopyin(sopt, &loop, sizeof(u_char),
			    sizeof(u_char));
			if (error)
				break;
		} else {
			u_int iloop;
			error = sooptcopyin(sopt, &iloop, sizeof(u_int),
					    sizeof(u_int));
			if (error)
				break;
			loop = (u_char)iloop;
		}
		imo = inp_findmoptions(inp);
		imo->imo_multicast_loop = !!loop;
		INP_WUNLOCK(inp);
		break;
	}
	case IP_ADD_MEMBERSHIP:
	case IP_ADD_SOURCE_MEMBERSHIP:
	case MCAST_JOIN_GROUP:
	case MCAST_JOIN_SOURCE_GROUP:
		error = inp_join_group(inp, sopt);
		break;
	case IP_DROP_MEMBERSHIP:
	case IP_DROP_SOURCE_MEMBERSHIP:
	case MCAST_LEAVE_GROUP:
	case MCAST_LEAVE_SOURCE_GROUP:
		error = inp_leave_group(inp, sopt);
		break;
	case IP_BLOCK_SOURCE:
	case IP_UNBLOCK_SOURCE:
	case MCAST_BLOCK_SOURCE:
	case MCAST_UNBLOCK_SOURCE:
		error = inp_block_unblock_source(inp, sopt);
		break;
	case IP_MSFILTER:
		error = inp_set_source_filters(inp, sopt);
		break;
	default:
		error = EOPNOTSUPP;
		break;
	}
	INP_UNLOCK_ASSERT(inp);
	return (error);
}
int inp_setmoptions ( struct inpcb * inp , struct sockopt * sopt ) { struct ip_moptions * imo ; 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 IP_MULTICAST_VIF : { int vifi ; if ( legal_vif_num == NULL ) { error = EOPNOTSUPP ; break ; } error = sooptcopyin ( sopt , & vifi , sizeof ( int ) , sizeof ( int ) ) ; if ( error ) break ; if ( ! legal_vif_num ( vifi ) && ( vifi != -1 ) ) { error = EINVAL ; break ; } imo = inp_findmoptions ( inp ) ; imo -> imo_multicast_vif = vifi ; INP_WUNLOCK ( inp ) ; break ; } case IP_MULTICAST_IF : error = inp_set_multicast_if ( inp , sopt ) ; break ; case IP_MULTICAST_TTL : { u_char ttl ; if ( sopt -> sopt_valsize == sizeof ( u_char ) ) { error = sooptcopyin ( sopt , & ttl , sizeof ( u_char ) , sizeof ( u_char ) ) ; if ( error ) break ; } else { u_int ittl ; error = sooptcopyin ( sopt , & ittl , sizeof ( u_int ) , sizeof ( u_int ) ) ; if ( error ) break ; if ( ittl > 255 ) { error = EINVAL ; break ; } ttl = ( u_char ) ittl ; } imo = inp_findmoptions ( inp ) ; imo -> imo_multicast_ttl = ttl ; INP_WUNLOCK ( inp ) ; break ; } case IP_MULTICAST_LOOP : { u_char loop ; if ( sopt -> sopt_valsize == sizeof ( u_char ) ) { error = sooptcopyin ( sopt , & loop , sizeof ( u_char ) , sizeof ( u_char ) ) ; if ( error ) break ; } else { u_int iloop ; error = sooptcopyin ( sopt , & iloop , sizeof ( u_int ) , sizeof ( u_int ) ) ; if ( error ) break ; loop = ( u_char ) iloop ; } imo = inp_findmoptions ( inp ) ; imo -> imo_multicast_loop = ! ! loop ; INP_WUNLOCK ( inp ) ; break ; } case IP_ADD_MEMBERSHIP : case IP_ADD_SOURCE_MEMBERSHIP : case MCAST_JOIN_GROUP : case MCAST_JOIN_SOURCE_GROUP : error = inp_join_group ( inp , sopt ) ; break ; case IP_DROP_MEMBERSHIP : case IP_DROP_SOURCE_MEMBERSHIP : case MCAST_LEAVE_GROUP : case MCAST_LEAVE_SOURCE_GROUP : error = inp_leave_group ( inp , sopt ) ; break ; case IP_BLOCK_SOURCE : case IP_UNBLOCK_SOURCE : case MCAST_BLOCK_SOURCE : case MCAST_UNBLOCK_SOURCE : error = inp_block_unblock_source ( inp , sopt ) ; break ; case IP_MSFILTER : error = inp_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.
	 */ /*
		 * Select a multicast VIF for transmission.
		 * Only useful if multicast forwarding is active.
		 */ /*
		 * Set the IP time-to-live for outgoing multicast packets.
		 * The original multicast API required a char argument,
		 * which is inconsistent with the rest of the socket API.
		 * We allow either a char or an int.
		 */ /*
		 * Set the loopback flag for outgoing multicast packets.
		 * Must be zero or one.  The original multicast API required a
		 * char argument, which is inconsistent with the rest
		 * of the socket API.  We allow either a char or an int.
		 */