/*
* 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
*/
/*
*/
#include <sys/sysmacros.h>
#include <sys/socketvar.h>
#include "socksdp.h"
/*
* SDP sockfs sonode operations
*/
struct cred *);
int, int, struct cred *);
struct cred *);
struct cred *);
struct cred *);
int, struct cred *);
static int sosdp_setsockopt(struct sonode *, int, int, const void *,
int32_t *);
static int sosdp_poll(struct sonode *, short, int, short *,
struct pollhead **);
/*
* Socket upcalls
*/
static void sdp_sock_connected(void *handle);
static void sdp_sock_urgdata(void *handle);
static void sdp_sock_ordrel(void *handle);
sosdp_init, /* sop_init */
sosdp_accept, /* sop_accept */
sosdp_bind, /* sop_bind */
sosdp_listen, /* sop_listen */
sosdp_connect, /* sop_connect */
sosdp_recvmsg, /* sop_recvmsg */
sosdp_sendmsg, /* sop_sendmsg */
so_sendmblk_notsupp, /* sop_sendmblk */
sosdp_getpeername, /* sop_getpeername */
sosdp_getsockname, /* sop_getsockname */
sosdp_shutdown, /* sop_shutdown */
sosdp_getsockopt, /* sop_getsockopt */
sosdp_setsockopt, /* sop_setsockopt */
sosdp_ioctl, /* sop_ioctl */
sosdp_poll, /* sop_poll */
sosdp_close, /* sop_close */
};
};
/* ARGSUSED */
static int
{
int error = 0;
/* passive open, just inherit settings from parent */
return (0);
}
return (error);
return (ENOMEM);
return (error);
}
/*
* Accept incoming connection.
*/
/* ARGSUSED */
static int
{
int error = 0;
(void *)lso->so_proto_handle));
/*
* Not a listen socket.
*/
return (EINVAL);
}
/*
* Returns right away if socket is nonblocking.
*/
if (error != 0) {
return (error);
}
return (0);
}
/*
* Bind local endpoint.
*/
/* ARGSUSED */
int
{
int error = 0;
if (!(flags & _SOBIND_LOCK_HELD)) {
} 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) {
} else {
}
done:
if (!(flags & _SOBIND_LOCK_HELD)) {
} else {
/* If the caller held the lock don't release it here */
}
return (error);
}
/*
* Turn socket into a listen socket.
*/
/* ARGSUSED */
static int
{
int error = 0;
/*
* If this socket is trying to do connect, or if it has
* been connected, disallow.
*/
goto done;
}
/*
* If listen() is only called to change backlog, we don't
* need to notify protocol module.
*/
goto done;
}
backlog);
if (error == 0) {
} else {
}
done:
return (error);
}
/*
* Active open.
*/
/*ARGSUSED*/
static int
{
int error = 0;
/*
* 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
*/
dprint(4,
("sosdp_connect: wait on so:%p "
"so_proto_handle:%p failed:%d",
}
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.
*/
/* ARGSUSED */
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.
*/
/* ARGSUSED */
static int
{
int flags;
int error;
if (msg->msg_controllen != 0) {
return (EOPNOTSUPP);
}
return (EPIPE);
}
return (error);
}
flags |= MSG_DONTWAIT;
return (ENOTCONN);
}
return (error);
}
/*
* Get address of remote node.
*/
/* ARGSUSED */
static int
{
return (ENOTCONN);
} else {
return (sdp_getpeername(
}
}
/*
* Get local address.
*/
/* ARGSUSED */
static int
{
/*
* Zero address, except for address family
*/
sizeof (struct sockaddr_in6) :
sizeof (struct sockaddr_in);
}
return (0);
} else {
return (sdp_getsockname(
}
}
/*
* Called from shutdown().
*/
/* ARGSUSED */
static int
{
int error = 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.
*/
if (!(state_change & SS_ISCONNECTED)) {
goto done;
}
switch (how) {
case SHUT_RD:
break;
case SHUT_WR:
break;
case SHUT_RDWR:
break;
default:
goto done;
}
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
*/
/* ARGSUSED */
static int
{
int error = 0;
return (EINVAL);
}
}
}
/*
* 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);
}
/* ARGSUSED */
static int
{
/* handle socket specific ioctls */
switch (cmd) {
case FIONBIO:
return (EFAULT);
}
if (value != 0) {
} else {
}
return (0);
case FIOASYNC:
return (EFAULT);
}
if (value) {
/* Turn on SIGIO */
} else {
/* Turn off SIGIO */
}
return (0);
case SIOCSPGRP:
case FIOSETOWN:
return (EFAULT);
}
return (error);
case SIOCGPGRP:
case FIOGETOWN:
return (EFAULT);
return (0);
case SIOCATMARK:
intval = 0;
return (EFAULT);
return (0);
case SIOCSENABLESDP: {
/*
* System wide enable SDP
*/
return (EFAULT);
return (EFAULT);
return (0);
}
/* from strioctl */
case FIONREAD:
/*
* Return number of bytes of data in all data messages
* in queue in "arg".
* For stream socket, amount of available data.
*/
intval = 0;
} else {
SDP_READ);
}
return (EFAULT);
return (0);
default:
return (EINVAL);
}
}
/*
* Check socktpi_poll() on why so_lock is not held in this function.
*/
static int
{
int so_state;
/*
* Not connected yet - turn off write side events
*/
}
/*
* Check for errors
*/
return (0);
}
*reventsp = 0;
/*
* Don't mark socket as writable until TX queued data is
* below watermark.
*/
if (sdp_polldata(
SDP_XMIT)) {
}
} else {
*reventsp = 0;
goto done;
}
SDP_READ)) {
}
}
done:
}
return (0);
}
/* ARGSUSED */
static int
{
int error = 0;
/*
* Need to set flags as there might be ops in progress on
* this socket.
*
* If socket already disconnected/disconnecting,
* don't send signal (again).
*/
soisdisconnected(so, 0);
/*
* Initiate connection shutdown.
*/
flag);
return (error);
}
/* ARGSUSED */
void
{
(void *)so->so_proto_handle));
}
/*
* Upcalls from SDP
*/
/*
* Incoming connection on listen socket.
*/
static void *
{
int error;
(void *)lso->so_proto_handle));
/*
* Check current # of queued conns against backlog
*/
return (NULL);
}
return (NULL);
}
return (nso);
}
/*
* For outgoing connections, the connection has been established.
*/
static void
{
(void *)so->so_proto_handle));
}
/*
* Connection got disconnected. Either with an error, or through
* normal handshake.
*/
static void
{
}
/*
* Incoming data.
*/
/*ARGSUSED*/
static int
{
so_notify_data(so, 0);
}
/*
* 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 notifies socket about receiving of conn close request from peer side.
*/
static void
{
}
static void
{
(void *)so->so_proto_handle));
}