Exemplo n.º 1
0
/*
 * Returns 0 for success, errno value otherwise.
 *
 * If the "bind_to_req_port_only" parameter is set and the requested port
 * number is available, then set allocated_port to it.  If not available,
 * return an error.
 *
 * If the "bind_to_req_port_only" parameter is not set and the requested port
 * number is available, then set allocated_port to it.  If not available,
 * find the first anonymous port we can and set allocated_port to that.  If no
 * anonymous ports are available, return an error.
 *
 * In either case, when succeeding, update the sctp_t to record the port number
 * and insert it in the bind hash table.
 */
int
sctp_bindi(sctp_t *sctp, in_port_t port, boolean_t bind_to_req_port_only,
    int user_specified, in_port_t *allocated_port)
{
	/* number of times we have run around the loop */
	int count = 0;
	/* maximum number of times to run around the loop */
	int loopmax;
	zoneid_t zoneid = sctp->sctp_zoneid;
	zone_t *zone = crgetzone(sctp->sctp_credp);

	/*
	 * Lookup for free addresses is done in a loop and "loopmax"
	 * influences how long we spin in the loop
	 */
	if (bind_to_req_port_only) {
		/*
		 * If the requested port is busy, don't bother to look
		 * for a new one. Setting loop maximum count to 1 has
		 * that effect.
		 */
		loopmax = 1;
	} else {
		/*
		 * If the requested port is busy, look for a free one
		 * in the anonymous port range.
		 * Set loopmax appropriately so that one does not look
		 * forever in the case all of the anonymous ports are in use.
		 */
		loopmax = (sctp_largest_anon_port -
		    sctp_smallest_anon_port + 1);
	}
	do {
		uint16_t	lport;
		sctp_tf_t	*tbf;
		sctp_t		*lsctp;
		int		addrcmp;

		lport = htons(port);

		/*
		 * Ensure that the sctp_t is not currently in the bind hash.
		 * Hold the lock on the hash bucket to ensure that
		 * the duplicate check plus the insertion is an atomic
		 * operation.
		 *
		 * This function does an inline lookup on the bind hash list
		 * Make sure that we access only members of sctp_t
		 * and that we don't look at sctp_sctp, since we are not
		 * doing a SCTPB_REFHOLD. For more details please see the notes
		 * in sctp_compress()
		 */
		sctp_bind_hash_remove(sctp);
		tbf = &sctp_bind_fanout[SCTP_BIND_HASH(port)];
		mutex_enter(&tbf->tf_lock);
		for (lsctp = tbf->tf_sctp; lsctp != NULL;
		    lsctp = lsctp->sctp_bind_hash) {

			if (lport != lsctp->sctp_lport ||
			    lsctp->sctp_state < SCTPS_BOUND)
				continue;

			/*
			 * On a labeled system, we must treat bindings to ports
			 * on shared IP addresses by sockets with MAC exemption
			 * privilege as being in all zones, as there's
			 * otherwise no way to identify the right receiver.
			 */
			if (lsctp->sctp_zoneid != zoneid &&
			    !lsctp->sctp_mac_exempt && !sctp->sctp_mac_exempt)
				continue;

			addrcmp = sctp_compare_saddrs(sctp, lsctp);
			if (addrcmp != SCTP_ADDR_DISJOINT) {
				if (!sctp->sctp_reuseaddr) {
					/* in use */
					break;
				} else if (lsctp->sctp_state == SCTPS_BOUND ||
				    lsctp->sctp_state == SCTPS_LISTEN) {
					/*
					 * socket option SO_REUSEADDR is set
					 * on the binding sctp_t.
					 *
					 * We have found a match of IP source
					 * address and source port, which is
					 * refused regardless of the
					 * SO_REUSEADDR setting, so we break.
					 */
					break;
				}
			}
		}
		if (lsctp != NULL) {
			/* The port number is busy */
			mutex_exit(&tbf->tf_lock);
		} else {
			conn_t *connp = sctp->sctp_connp;

			if (is_system_labeled()) {
				mlp_type_t addrtype, mlptype;

				/*
				 * On a labeled system we must check the type
				 * of the binding requested by the user (either
				 * MLP or SLP on shared and private addresses),
				 * and that the user's requested binding
				 * is permitted.
				 */
				addrtype = tsol_mlp_addr_type(zone->zone_id,
				    sctp->sctp_ipversion,
				    sctp->sctp_ipversion == IPV4_VERSION ?
				    (void *)&sctp->sctp_ipha->ipha_src :
				    (void *)&sctp->sctp_ip6h->ip6_src);

				/*
				 * tsol_mlp_addr_type returns the possibilities
				 * for the selected address.  Since all local
				 * addresses are either private or shared, the
				 * return value mlptSingle means "local address
				 * not valid (interface not present)."
				 */
				if (addrtype == mlptSingle) {
					mutex_exit(&tbf->tf_lock);
					return (EADDRNOTAVAIL);
				}
				mlptype = tsol_mlp_port_type(zone, IPPROTO_SCTP,
				    port, addrtype);
				if (mlptype != mlptSingle) {
					if (secpolicy_net_bindmlp(connp->
					    conn_cred) != 0) {
						mutex_exit(&tbf->tf_lock);
						return (EACCES);
					}
					/*
					 * If we're binding a shared MLP, then
					 * make sure that this zone is the one
					 * that owns that MLP.  Shared MLPs can
					 * be owned by at most one zone.
					 */

					if (mlptype == mlptShared &&
					    addrtype == mlptShared &&
					    connp->conn_zoneid !=
					    tsol_mlp_findzone(IPPROTO_SCTP,
					    lport)) {
						mutex_exit(&tbf->tf_lock);
						return (EACCES);
					}
					connp->conn_mlp_type = mlptype;
				}
			}
			/*
			 * This port is ours. Insert in fanout and mark as
			 * bound to prevent others from getting the port
			 * number.
			 */
			sctp->sctp_state = SCTPS_BOUND;
			sctp->sctp_lport = lport;
			sctp->sctp_sctph->sh_sport = lport;

			ASSERT(&sctp_bind_fanout[SCTP_BIND_HASH(port)] == tbf);
			sctp_bind_hash_insert(tbf, sctp, 1);

			mutex_exit(&tbf->tf_lock);

			/*
			 * We don't want sctp_next_port_to_try to "inherit"
			 * a port number supplied by the user in a bind.
			 *
			 * This is the only place where sctp_next_port_to_try
			 * is updated. After the update, it may or may not
			 * be in the valid range.
			 */
			if (user_specified == 0)
				sctp_next_port_to_try = port + 1;

			*allocated_port = port;

			return (0);
		}

		if ((count == 0) && (user_specified)) {
			/*
			 * We may have to return an anonymous port. So
			 * get one to start with.
			 */
			port = sctp_update_next_port(sctp_next_port_to_try,
			    zone);
			user_specified = 0;
		} else {
			port = sctp_update_next_port(port + 1, zone);
		}
		if (port == 0)
			break;

		/*
		 * Don't let this loop run forever in the case where
		 * all of the anonymous ports are in use.
		 */
	} while (++count < loopmax);

	return (bind_to_req_port_only ? EADDRINUSE : EADDRNOTAVAIL);
}
Exemplo n.º 2
0
/*
 * Common accept code.  Called by sctp_conn_request.
 * cr_pkt is the INIT / INIT ACK packet.
 */
static int
sctp_accept_comm(sctp_t *listener, sctp_t *acceptor, mblk_t *cr_pkt,
    uint_t ip_hdr_len, sctp_init_chunk_t *iack)
{

	sctp_hdr_t		*sctph;
	sctp_chunk_hdr_t	*ich;
	sctp_init_chunk_t	*init;
	int			err;
	uint_t			sctp_options;
	conn_t			*aconnp;
	conn_t			*lconnp;
	sctp_stack_t	*sctps = listener->sctp_sctps;

	sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
	ASSERT(OK_32PTR(sctph));

	aconnp = acceptor->sctp_connp;
	lconnp = listener->sctp_connp;
	aconnp->conn_lport = lconnp->conn_lport;
	aconnp->conn_fport = sctph->sh_sport;

	ich = (sctp_chunk_hdr_t *)(iack + 1);
	init = (sctp_init_chunk_t *)(ich + 1);

	/* acceptor isn't in any fanouts yet, so don't need to hold locks */
	ASSERT(acceptor->sctp_faddrs == NULL);
	err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich,
	    &sctp_options);
	if (err != 0)
		return (err);

	if ((err = sctp_set_hdraddrs(acceptor)) != 0)
		return (err);

	if ((err = sctp_build_hdrs(acceptor, KM_NOSLEEP)) != 0)
		return (err);

	if ((sctp_options & SCTP_PRSCTP_OPTION) &&
	    listener->sctp_prsctp_aware && sctps->sctps_prsctp_enabled) {
		acceptor->sctp_prsctp_aware = B_TRUE;
	} else {
		acceptor->sctp_prsctp_aware = B_FALSE;
	}

	/* Get  initial TSNs */
	acceptor->sctp_ltsn = ntohl(iack->sic_inittsn);
	acceptor->sctp_recovery_tsn = acceptor->sctp_lastack_rxd =
	    acceptor->sctp_ltsn - 1;
	acceptor->sctp_adv_pap = acceptor->sctp_lastack_rxd;
	/* Serial numbers are initialized to the same value as the TSNs */
	acceptor->sctp_lcsn = acceptor->sctp_ltsn;

	if (!sctp_initialize_params(acceptor, init, iack))
		return (ENOMEM);

	/*
	 * Copy sctp_secret from the listener in case we need to validate
	 * a possibly delayed cookie.
	 */
	bcopy(listener->sctp_secret, acceptor->sctp_secret, SCTP_SECRET_LEN);
	bcopy(listener->sctp_old_secret, acceptor->sctp_old_secret,
	    SCTP_SECRET_LEN);
	acceptor->sctp_last_secret_update = ddi_get_lbolt64();

	/*
	 * After acceptor is inserted in the hash list, it can be found.
	 * So we need to lock it here.
	 */
	RUN_SCTP(acceptor);

	sctp_conn_hash_insert(&sctps->sctps_conn_fanout[
	    SCTP_CONN_HASH(sctps, aconnp->conn_ports)], acceptor, 0);
	sctp_bind_hash_insert(&sctps->sctps_bind_fanout[
	    SCTP_BIND_HASH(ntohs(aconnp->conn_lport))], acceptor, 0);

	/*
	 * No need to check for multicast destination since ip will only pass
	 * up multicasts to those that have expressed interest
	 * TODO: what about rejecting broadcasts?
	 * Also check that source is not a multicast or broadcast address.
	 */
	/* XXXSCTP */
	acceptor->sctp_state = SCTPS_ESTABLISHED;
	acceptor->sctp_assoc_start_time = (uint32_t)ddi_get_lbolt();
	/*
	 * listener->sctp_rwnd should be the default window size or a
	 * window size changed via SO_RCVBUF option.
	 */
	acceptor->sctp_rwnd = listener->sctp_rwnd;
	acceptor->sctp_irwnd = acceptor->sctp_rwnd;
	acceptor->sctp_pd_point = acceptor->sctp_rwnd;
	acceptor->sctp_upcalls = listener->sctp_upcalls;

	return (0);
}