Example #1
0
/*
 * Bind the sctp_t to a sockaddr, which includes an address and other
 * information, such as port or flowinfo.
 */
int
sctp_bind(sctp_t *sctp, struct sockaddr *sa, socklen_t len)
{
	int		user_specified;
	boolean_t	bind_to_req_port_only;
	in_port_t	requested_port;
	in_port_t	allocated_port;
	int		err = 0;

	ASSERT(sctp != NULL);
	ASSERT(sa);

	RUN_SCTP(sctp);

	if (sctp->sctp_state > SCTPS_BOUND) {
		err = EINVAL;
		goto done;
	}

	switch (sa->sa_family) {
	case AF_INET:
		if (len < sizeof (struct sockaddr_in) ||
		    sctp->sctp_family == AF_INET6) {
			err = EINVAL;
			goto done;
		}
		requested_port = ntohs(((struct sockaddr_in *)sa)->sin_port);
		break;
	case AF_INET6:
		if (len < sizeof (struct sockaddr_in6) ||
		    sctp->sctp_family == AF_INET) {
			err = EINVAL;
			goto done;
		}
		requested_port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
		/* Set the flowinfo. */
		sctp->sctp_ip6h->ip6_vcf =
		    (IPV6_DEFAULT_VERS_AND_FLOW & IPV6_VERS_AND_FLOW_MASK) |
		    (((struct sockaddr_in6 *)sa)->sin6_flowinfo &
		    ~IPV6_VERS_AND_FLOW_MASK);
		break;
	default:
		err = EAFNOSUPPORT;
		goto done;
	}
	bind_to_req_port_only = requested_port == 0 ? B_FALSE : B_TRUE;

	err = sctp_select_port(sctp, &requested_port, &user_specified);
	if (err != 0)
		goto done;

	if ((err = sctp_bind_add(sctp, sa, 1, B_TRUE,
	    user_specified == 1 ? htons(requested_port) : 0)) != 0) {
		goto done;
	}
	err = sctp_bindi(sctp, requested_port, bind_to_req_port_only,
	    user_specified, &allocated_port);
	if (err != 0) {
		sctp_free_saddrs(sctp);
	} else {
		ASSERT(sctp->sctp_state == SCTPS_BOUND);
	}
done:
	WAKE_SCTP(sctp);
	return (err);
}
Example #2
0
/*
 * Bind the sctp_t to a sockaddr, which includes an address and other
 * information, such as port or flowinfo.
 */
int
sctp_bind(sctp_t *sctp, struct sockaddr *sa, socklen_t len)
{
	int		user_specified;
	boolean_t	bind_to_req_port_only;
	in_port_t	requested_port;
	in_port_t	allocated_port;
	int		err = 0;
	conn_t		*connp = sctp->sctp_connp;
	uint_t		scope_id;
	sin_t		*sin;
	sin6_t		*sin6;

	ASSERT(sctp != NULL);

	RUN_SCTP(sctp);

	if ((sctp->sctp_state >= SCTPS_BOUND) ||
	    (sctp->sctp_connp->conn_state_flags & CONN_CLOSING) ||
	    (sa == NULL || len == 0)) {
		/*
		 * Multiple binds not allowed for any SCTP socket
		 * Also binding with null address is not supported.
		 */
		err = EINVAL;
		goto done;
	}

	switch (sa->sa_family) {
	case AF_INET:
		sin = (sin_t *)sa;
		if (len < sizeof (struct sockaddr_in) ||
		    connp->conn_family == AF_INET6) {
			err = EINVAL;
			goto done;
		}
		requested_port = ntohs(sin->sin_port);
		break;
	case AF_INET6:
		sin6 = (sin6_t *)sa;
		if (len < sizeof (struct sockaddr_in6) ||
		    connp->conn_family == AF_INET) {
			err = EINVAL;
			goto done;
		}
		requested_port = ntohs(sin6->sin6_port);
		/* Set the flowinfo. */
		connp->conn_flowinfo =
		    sin6->sin6_flowinfo & ~IPV6_VERS_AND_FLOW_MASK;

		scope_id = sin6->sin6_scope_id;
		if (scope_id != 0 && IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) {
			connp->conn_ixa->ixa_flags |= IXAF_SCOPEID_SET;
			connp->conn_ixa->ixa_scopeid = scope_id;
			connp->conn_incoming_ifindex = scope_id;
		} else {
			connp->conn_ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
			connp->conn_incoming_ifindex = connp->conn_bound_if;
		}
		break;
	default:
		err = EAFNOSUPPORT;
		goto done;
	}
	bind_to_req_port_only = requested_port == 0 ? B_FALSE : B_TRUE;

	err = sctp_select_port(sctp, &requested_port, &user_specified);
	if (err != 0)
		goto done;

	if ((err = sctp_bind_add(sctp, sa, 1, B_TRUE,
	    user_specified == 1 ? htons(requested_port) : 0)) != 0) {
		goto done;
	}
	err = sctp_bindi(sctp, requested_port, bind_to_req_port_only,
	    user_specified, &allocated_port);
	if (err != 0) {
		sctp_free_saddrs(sctp);
	} else {
		ASSERT(sctp->sctp_state == SCTPS_BOUND);
	}
done:
	WAKE_SCTP(sctp);
	return (err);
}