socksdp.c revision 74e20cfe817b82802b16fac8690dadcda76f54f5
/*
* 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"
#include <sys/sysmacros.h>
#include <sys/socketvar.h>
#include "socksdp.h"
/*
* SDP sockfs sonode operations
*/
static int sosdp_listen(struct sonode *, int);
int, int);
static int sosdp_getpeername(struct sonode *);
static int sosdp_getsockname(struct sonode *);
static int sosdp_shutdown(struct sonode *, int);
int);
static int sosdp_setsockopt(struct sonode *, int, int, const void *,
/*
* Socket upcalls
*/
static void sdp_sock_connected(void *handle);
static void sdp_sock_urgdata(void *handle);
static void sdp_sock_ordrel(void *handle);
static kmem_cache_t *sosdp_sockcache;
sosdp_accept, /* sop_accept */
sosdp_bind, /* sop_bind */
sosdp_listen, /* sop_listen */
sosdp_connect, /* sop_connect */
sosdp_recvmsg, /* sop_recvmsg */
sosdp_sendmsg, /* sop_sendmsg */
sosdp_getpeername, /* sop_getpeername */
sosdp_getsockname, /* sop_getsockname */
sosdp_shutdown, /* sop_shutdown */
sosdp_getsockopt, /* sop_getsockopt */
sosdp_setsockopt /* sop_setsockopt */
};
};
/*ARGSUSED*/
static int
{
so->so_nl7c_flags = 0;
return (-1);
}
return (0);
}
/*ARGSUSED*/
static void
{
}
int
sosdp_init(void)
{
int error;
if (error != 0) {
return (error);
}
sizeof (struct sdp_sonode), 0, sosdp_sock_constructor,
return (0);
}
static struct vnode *
int kmflags)
{
struct sdp_sonode *ss;
return (NULL);
}
now = gethrestime_sec();
so->so_pushcnt = 0;
so->so_options = 0;
so->so_delayed_error = 0;
so->so_oobsigcnt = 0;
so->so_delayed_error = 0;
ss->ss_rxqueued = 0;
return (vp);
}
/*
* Creates a sdp socket data structure.
* tso is non-NULL if it's passive open.
*/
struct sonode *
{
int error;
int soflags;
if (is_system_labeled()) {
*errorp = EOPNOTSUPP;
return (NULL);
}
if (version == SOV_STREAM) {
return (NULL);
}
/*
* We only support one type of SDP socket. Let sotpi_create()
* handle all other cases, such as raw socket.
*/
!(type == SOCK_STREAM)) {
}
} else {
/*
* sosdp_makevp() only fails when there is no memory.
*/
return (NULL);
}
}
return (NULL);
}
if (version == SOV_DEFAULT) {
}
return (so);
}
/*
* Free SDP socket data structure.
* Closes incoming connections which were never accepted, frees
* resources.
*/
void
{
/*
* Need to clear these out so that sockfree() doesn't think that
* there's memory in need of free'ing.
*/
}
}
/*
* Accept incoming connection.
*/
static int
{
int error = 0;
/*
* Not a listen socket.
*/
return (EINVAL);
}
/*
* Returns right away if socket is nonblocking.
*/
if (error != 0) {
return (error);
}
/*
* accept() needs remote address right away.
*/
(void) sosdp_getpeername(nso);
return (0);
}
/*
* Bind local endpoint.
*/
int
int flags)
{
int error = 0;
if (!(flags & _SOBIND_LOCK_HELD)) {
/* LINTED - statement has no conseq */
} else {
}
/*
* Multiple binds not allowed for any SDP socket.
* Also binding with null address is not supported.
*/
goto done;
}
/*
*/
goto done;
}
/*
* Protocol module does address family checks.
*/
if (error == 0) {
/* LINTED - statement has no conseq */
} else {
}
done:
if (!(flags & _SOBIND_LOCK_HELD)) {
/* LINTED - statement has no conseq */
} else {
/* If the caller held the lock don't release it here */
}
return (error);
}
/*
* Turn socket into a listen socket.
*/
static int
{
int error = 0;
/*
* If this socket is trying to do connect, or if it has
* been connected, disallow.
*/
goto done;
}
if (backlog < 0) {
backlog = 0;
}
/*
* Use the same qlimit as in BSD. BSD checks the qlimit
* before queuing the next connection implying that a
* listen(sock, 0) allows one connection to be queued.
* BSD also uses 1.5 times the requested backlog.
*
* XNS Issue 4 required a strict interpretation of the backlog.
* This has been waived subsequently for Issue 4 and the change
* incorporated in XNS Issue 5. So we aren't required to do
* anything special for XPG apps.
*/
else
/*
* If listen() is only called to change backlog, we don't
* need to notify protocol module.
*/
goto done;
}
if (error == 0) {
/* LINTED - statement has no conseq */
} else {
}
done:
return (error);
}
/*
* Active open.
*/
/*ARGSUSED*/
static int
{
int error;
/*
* Can't connect() after listen(), or if the socket is already
* connected.
*/
} else {
error = EOPNOTSUPP;
}
goto done;
}
/*
* Check for failure of an earlier call
*/
goto done;
}
/*
* Connection is closing, or closed, don't allow reconnect.
* TCP allows this to proceed, but the socket remains unwriteable.
* BSD returns EINVAL.
*/
SS_CANTSENDMORE)) {
goto done;
}
goto done;
}
if (error == 0) {
/*
* Allow other threads to access the socket
*/
}
switch (error) {
case 0:
case EINPROGRESS:
case EALREADY:
case EINTR:
/* Non-fatal errors */
break;
default:
/* clear SS_ISCONNECTING in case it was set */
break;
}
done:
return (error);
}
/*
* Receive data.
*/
int
{
int size;
SS_CANTRCVMORE))) {
return (ENOTCONN);
}
/*
* flag possibilities:
*
* MSG_PEEK Don't consume data
* MSG_WAITALL Wait for full quantity of data (ignored if MSG_PEEK)
* MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK)
*
* MSG_WAITALL can return less than the full buffer if either
*
* 1. we would block and we are non-blocking
* 2. a full message cannot be delivered
*
*/
/*
* Allow just one reader at a time.
*/
if (error != 0) {
return (error);
}
flags |= MSG_DONTWAIT;
}
} else {
msg->msg_controllen = 0;
msg->msg_namelen = 0;
}
done:
return (error);
}
/*
* Send message.
*/
static int
{
int flags;
int error;
if (msg->msg_controllen != 0) {
return (EOPNOTSUPP);
}
return (EPIPE);
}
return (error);
}
flags |= MSG_DONTWAIT;
return (ENOTCONN);
}
if (error == 0)
return (0);
/*
* We received shutdown between the time lock was
* lifted and call to sdp_sendmsg().
*/
return (EPIPE);
}
return (error);
}
/*
* Get address of remote node.
*/
static int
{
int error;
} else {
&so->so_faddr_len);
}
return (error);
}
/*
* Get local address.
*/
static int
{
int error;
/*
* Zero address, except for address family
*/
sizeof (struct sockaddr_in6) : sizeof (struct sockaddr_in);
error = 0;
} else {
&so->so_laddr_len);
}
return (error);
}
/*
* Called from shutdown().
*/
static int
{
int error = 0;
short wakesig = 0;
/*
* Record the current state and then perform any state changes.
* Then use the difference between the old and new states to
* determine which needs to be done.
*/
switch (how) {
case SHUT_RD:
break;
case SHUT_WR:
break;
case SHUT_RDWR:
break;
default:
goto done;
}
if (state_change & SS_CANTRCVMORE) {
}
if (state_change & SS_CANTSENDMORE) {
}
if (state_change & SS_CANTSENDMORE) {
}
done:
/*
* HACK: sdp_disconnect() may return EWOULDBLOCK. But this error is
* not documented in standard socket API. Catch it here.
*/
if (error == EWOULDBLOCK)
error = 0;
return (error);
}
/*
* Get socket options.
*/
/*ARGSUSED*/
static int
{
int error = 0;
if (level == SOL_SOCKET) {
switch (option_name) {
case SO_TYPE:
case SO_ERROR:
case SO_DEBUG:
case SO_ACCEPTCONN:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_USELOOPBACK:
case SO_OOBINLINE:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_SNDLOWAT:
case SO_RCVLOWAT:
case SO_DGRAM_ERRIND:
goto done;
}
break;
case SO_LINGER:
goto done;
}
break;
}
switch (option_name) {
case SO_TYPE:
goto copyout;
case SO_ERROR:
goto copyout;
case SO_ACCEPTCONN:
SO_ACCEPTCONN : 0;
goto copyout;
case SO_DEBUG:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_USELOOPBACK:
case SO_OOBINLINE:
case SO_DGRAM_ERRIND:
goto copyout;
/*
* The following options are only returned by sockfs
* when sdp_get_opt() fails.
*/
case SO_LINGER:
break;
case SO_SNDBUF:
len = (t_uscalar_t)sizeof (int);
goto copyout;
case SO_RCVBUF:
len = (t_uscalar_t)sizeof (int);
goto copyout;
case SO_SNDLOWAT:
len = (t_uscalar_t)sizeof (int);
goto copyout;
case SO_RCVLOWAT:
len = (t_uscalar_t)sizeof (int);
goto copyout;
default:
break;
}
}
}
if (error != 0) {
/* We have no fallback value */
goto free;
}
error = 0;
goto copyout;
}
free:
}
done:
return (error);
}
/*
* Set socket options
*/
static int
{
int error;
return (EINVAL);
}
/* Caller allocates aligned optval, or passes null */
/* No SDP options should be zero-length */
if (optlen == 0) {
return (error);
}
}
}
/*
* Check for SOL_SOCKET options and record their values.
* If we know about a SOL_SOCKET parameter and the transport
* failed it with TBADOPT or TOUTSTATE (i.e. ENOPROTOOPT or
* EPROTO) we let the setsockopt succeed.
*/
if (level == SOL_SOCKET) {
/* Check parameters */
switch (option_name) {
case SO_DEBUG:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_USELOOPBACK:
case SO_OOBINLINE:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_SNDLOWAT:
case SO_RCVLOWAT:
case SO_DGRAM_ERRIND:
goto done;
}
break;
case SO_LINGER:
goto done;
}
break;
}
switch (option_name) {
case SO_TYPE:
case SO_ERROR:
case SO_ACCEPTCONN:
/* Can't be set */
error = ENOPROTOOPT;
goto done;
case SO_LINGER: {
if (l->l_onoff) {
} else {
}
break;
}
case SO_DEBUG:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_USELOOPBACK:
case SO_OOBINLINE:
case SO_DGRAM_ERRIND:
if (intvalue != 0) {
("sosdp_setsockopt: setting 0x%x\n",
option_name));
} else {
("sosdp_setsockopt: clearing 0x%x\n",
option_name));
}
break;
case SO_SNDBUF:
}
break;
case SO_RCVBUF:
}
break;
case SO_SNDLOWAT:
}
break;
case SO_RCVLOWAT:
}
break;
}
if (error != 0) {
("sosdp_setsockopt: ignoring error %d "
error = 0;
}
}
}
done:
return (error);
}
/*
* Upcalls from SDP
*/
/*
* Incoming connection on listen socket.
*/
static void *
{
struct sdp_sonode *nss;
int error;
/*
* Check current # of queued conns against backlog
*/
return (NULL);
}
/*
* Need to create a new socket.
*/
return (NULL);
}
return (NULL);
}
/*
* Inherit socket properties
*/
++lss->ss_rxqueued;
/*
* Copy pointer to new socket to connind queue message
*/
/*
* Wake people who're waiting incoming conns. Note that
* soqueueconnind gets so_lock.
*/
return (nss);
}
/*
* For outgoing connections, the connection has been established.
*/
static void
sdp_sock_connected(void *handle)
{
/*
* Wake ones who're waiting for conn to become established.
*/
}
/*
* Connection got disconnected. Either with an error, or through
* normal handshake.
*/
static void
{
int event = 0;
/*
* If socket is already disconnected/disconnecting,
* don't (re)send signal.
*/
event |= SDPSIG_READ;
event |= SDPSIG_WRITE;
if (event != 0)
}
/*
* Incoming data.
*/
/*ARGSUSED*/
static int
{
}
/*
* TX queued data got acknowledged.
*/
static void
{
/*
* Only do pollwakeup if the amount of queued data is less than
* watermark.
*/
if (!writeable) {
} else {
}
}
/*
* SDP notifies socket for presence of urgent data.
*/
static void
sdp_sock_urgdata(void *handle)
{
}
/*
* SDP notifies socket about receiving of conn close request from peer side.
*/
static void
sdp_sock_ordrel(void *handle)
{
/* LINTED */
}
static void
{
}