sctp_bind.c revision f4b3ec61df05330d25f55a36b975b4d7519fdeb1
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#define _SUN_TPI_VERSION 2
#include <inet/ipclassifier.h>
#include "sctp_impl.h"
#include "sctp_asconf.h"
#include "sctp_addr.h"
/*
* Returns 0 on success, EACCES on permission failure.
*/
static int
{
/*
* Get a valid port (within the anonymous range and should not
* be a privileged one) to use if the user has not given a port.
* If multiple threads are here, they may all start with
* with the same initial port. But, it should be fine as long as
* sctp_bindi will ensure that no two threads will be assigned
* the same port.
*/
if (*requested_port == 0) {
if (*requested_port == 0)
return (EACCES);
*user_specified = 0;
} else {
int i;
/*
* If the requested_port is in the well-known privileged range,
* verify that the stream was opened by a privileged user.
* Note: No locks are held when inspecting sctp_g_*epriv_ports
* but instead the code relies on:
* - the fact that the address of the array and its size never
* changes
* - the atomic assignment of the elements of the array
*/
} else {
for (i = 0; i < sctps->sctps_g_num_epriv_ports; i++) {
if (*requested_port ==
sctps->sctps_g_epriv_ports[i]) {
break;
}
}
}
if (priv) {
/*
* sctp_bind() should take a cred_t argument so that
* we can use it here.
*/
*requested_port) != 0) {
dprint(1,
("sctp_bind(x): no prive for port %d",
*requested_port));
return (EACCES);
}
}
*user_specified = 1;
}
return (0);
}
int
{
/*
* TCP handles listen() increasing the backlog, need to check
* if it should be handled here too
*/
return (EINVAL);
}
/* Do an anonymous bind for unbound socket doing listen(). */
if (sctp->sctp_nsaddrs == 0) {
struct sockaddr_storage ss;
int ret;
sizeof (ss))) != 0)
return (ret);
}
return (0);
}
/*
* Bind the sctp_t to a sockaddr, which includes an address and other
* information, such as port or flowinfo.
*/
int
{
int user_specified;
int err = 0;
goto done;
}
case AF_INET:
if (len < sizeof (struct sockaddr_in) ||
goto done;
}
break;
case AF_INET6:
if (len < sizeof (struct sockaddr_in6) ||
goto done;
}
/* Set the flowinfo. */
break;
default:
err = EAFNOSUPPORT;
goto done;
}
if (err != 0)
goto done;
goto done;
}
if (err != 0) {
} else {
}
done:
return (err);
}
/*
*/
int
{
switch (bindop) {
case SCTP_BINDX_ADD_ADDR:
sctp->sctp_lport));
case SCTP_BINDX_REM_ADDR:
default:
return (EINVAL);
}
}
/*
* Add a list of addresses to a sctp_t.
*/
int
{
int err = 0;
if (!caller_hold_lock)
if (!caller_hold_lock)
return (EINVAL);
}
/*
* Let's do some checking here rather than undoing the
* add later (for these reasons).
*/
if (!sctps->sctps_addip_enabled ||
if (!caller_hold_lock)
return (EINVAL);
}
}
/*
* On a clustered node, for an inaddr_any bind, we will pass the list
* of all the addresses in the global list, minus any address on the
* loopback interface, and expect the clustering susbsystem to give us
* the correct list for the 'port'. For explicit binds we give the
* list of addresses and the clustering module validates it for the
* 'port'.
*
* On a non-clustered node, cl_sctp_check_addrs will be NULL and
* we proceed as usual.
*/
if (cl_sctp_check_addrs != NULL) {
int unspec = 0;
/*
* If we are adding addresses after listening, but before
* an association is established, we need to update the
* clustering module with this info.
*/
cl_sctp_listen != NULL;
if (err != 0) {
if (!caller_hold_lock)
return (err);
}
if (addrcnt == 0) {
/* We free the list */
if (!caller_hold_lock)
return (EINVAL);
}
if (do_listen) {
}
lsize);
/* list will be freed by the clustering module */
}
/* free the list we allocated */
} else {
}
if (err != 0) {
if (!caller_hold_lock)
return (err);
}
/* Need to send ASCONF messages */
if (do_asconf) {
if (err != 0) {
if (!caller_hold_lock)
return (err);
}
}
if (!caller_hold_lock)
if (do_asconf)
return (0);
}
/*
* Remove one or more addresses bound to the sctp_t.
*/
int
{
int error = 0;
if (!caller_hold_lock)
if (!caller_hold_lock)
return (EINVAL);
}
/*
* Fail the remove if we are beyond listen, but can't send this
* to the peer.
*/
if (!sctps->sctps_addip_enabled ||
if (!caller_hold_lock)
return (EINVAL);
}
}
/* Can't delete the last address nor all of the addresses */
if (!caller_hold_lock)
return (EINVAL);
}
}
if (error != 0) {
if (!caller_hold_lock)
return (error);
}
/* ulist will be non-NULL only if cl_sctp_unlisten is non-NULL */
sctp->sctp_lport);
/* ulist will be freed by the clustering module */
}
if (!caller_hold_lock)
if (do_asconf)
return (error);
}
/*
* 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
{
/* number of times we have run around the loop */
int count = 0;
/* maximum number of times to run around the loop */
int loopmax;
/*
* 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.
*/
}
do {
int addrcmp;
/*
* 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()
*/
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.
*/
continue;
if (addrcmp != SCTP_ADDR_DISJOINT) {
if (!sctp->sctp_reuseaddr) {
/* in use */
break;
/*
* 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;
}
}
}
/* The port number is busy */
} else {
if (is_system_labeled()) {
/*
* 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.
*/
/*
* 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) {
return (EADDRNOTAVAIL);
}
if (mlptype != mlptSingle) {
if (secpolicy_net_bindmlp(connp->
conn_cred) != 0) {
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.
*
* No need to handle exclusive-stack
* zones since ALL_ZONES only applies
* to the shared stack.
*/
if (mlptype == mlptShared &&
addrtype == mlptShared &&
connp->conn_zoneid !=
lport)) {
return (EACCES);
}
}
}
/*
* This port is ours. Insert in fanout and mark as
* bound to prevent others from getting the port
* number.
*/
/*
* 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)
*allocated_port = port;
return (0);
}
if ((count == 0) && (user_specified)) {
/*
* We may have to return an anonymous port. So
* get one to start with.
*/
user_specified = 0;
} else {
}
if (port == 0)
break;
/*
* Don't let this loop run forever in the case where
* all of the anonymous ports are in use.
*/
}
/*
* Don't let port fall into the privileged range.
* Since the extra privileged ports can be arbitrary we also
* ensure that we exclude those from consideration.
* sctp_g_epriv_ports is not sorted thus we loop over it until
* there are no changes.
*
* Note: No locks are held when inspecting sctp_g_*epriv_ports
* but instead the code relies on:
* - the fact that the address of the array and its size never changes
* - the atomic assignment of the elements of the array
*/
{
int i;
if (restart)
return (0);
}
for (i = 0; i < sctps->sctps_g_num_epriv_ports; i++) {
port++;
/*
* Make sure whether the port is in the
* valid range.
*
* XXX Note that if sctp_g_epriv_ports contains
* all the anonymous ports this will be an
* infinite loop.
*/
goto retry;
}
}
if (is_system_labeled() &&
port = i;
goto retry;
}
return (port);
}