net/get/setsockopt: add si_get/setsockopt interface to simply get/setsockopt

move private option to protocol sockif

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1 2022-11-22 21:15:06 +08:00 committed by Xiang Xiao
parent c5704eb1e7
commit e6f8ccda4a
14 changed files with 620 additions and 486 deletions

View file

@ -166,6 +166,12 @@ struct sock_intf_s
CODE int (*si_ioctl)(FAR struct socket *psock, CODE int (*si_ioctl)(FAR struct socket *psock,
int cmd, unsigned long arg); int cmd, unsigned long arg);
CODE int (*si_socketpair)(FAR struct socket *psocks[2]); CODE int (*si_socketpair)(FAR struct socket *psocks[2]);
#ifdef CONFIG_NET_SOCKOPTS
CODE int (*si_getsockopt)(FAR struct socket *psock, int level,
int option, FAR void *value, FAR socklen_t *value_len);
CODE int (*si_setsockopt)(FAR struct socket *psock, int level,
int option, FAR const void *value, socklen_t value_len);
#endif
#ifdef CONFIG_NET_SENDFILE #ifdef CONFIG_NET_SENDFILE
CODE ssize_t (*si_sendfile)(FAR struct socket *psock, CODE ssize_t (*si_sendfile)(FAR struct socket *psock,
FAR struct file *infile, FAR off_t *offset, FAR struct file *infile, FAR off_t *offset,
@ -210,9 +216,6 @@ struct socket_conn_s
#ifdef CONFIG_NET_SOLINGER #ifdef CONFIG_NET_SOLINGER
socktimeo_t s_linger; /* Linger timeout value (in deciseconds) */ socktimeo_t s_linger; /* Linger timeout value (in deciseconds) */
#endif #endif
#ifdef CONFIG_NET_TIMESTAMP
int32_t s_timestamp; /* Socket timestamp enabled/disabled */
#endif
#ifdef CONFIG_NET_BINDTODEVICE #ifdef CONFIG_NET_BINDTODEVICE
uint8_t s_boundto; /* Index of the interface we are bound to. uint8_t s_boundto; /* Index of the interface we are bound to.
* Unbound: 0, Bound: 1-MAX_IFINDEX */ * Unbound: 0, Bound: 1-MAX_IFINDEX */

View file

@ -111,6 +111,9 @@ struct can_conn_s
int32_t tx_deadline; int32_t tx_deadline;
# endif # endif
#endif #endif
#ifdef CONFIG_NET_TIMESTAMP
int32_t timestamp; /* Socket timestamp enabled/disabled */
#endif
}; };
/**************************************************************************** /****************************************************************************
@ -353,6 +356,7 @@ void can_readahead_signal(FAR struct can_conn_s *conn);
* *
* Input Parameters: * Input Parameters:
* psock Socket structure of socket to operate on * psock Socket structure of socket to operate on
* level Protocol level to set the option
* option identifies the option to set * option identifies the option to set
* value Points to the argument value * value Points to the argument value
* value_len The length of the argument value * value_len The length of the argument value
@ -365,7 +369,7 @@ void can_readahead_signal(FAR struct can_conn_s *conn);
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_NET_CANPROTO_OPTIONS #ifdef CONFIG_NET_CANPROTO_OPTIONS
int can_setsockopt(FAR struct socket *psock, int option, int can_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len); FAR const void *value, socklen_t value_len);
#endif #endif
@ -399,7 +403,7 @@ int can_setsockopt(FAR struct socket *psock, int option,
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_NET_CANPROTO_OPTIONS #ifdef CONFIG_NET_CANPROTO_OPTIONS
int can_getsockopt(FAR struct socket *psock, int option, int can_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len); FAR void *value, FAR socklen_t *value_len);
#endif #endif

View file

@ -123,7 +123,7 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
#ifdef CONFIG_NET_TIMESTAMP #ifdef CONFIG_NET_TIMESTAMP
/* TIMESTAMP sockopt is activated, create timestamp and copy to iob */ /* TIMESTAMP sockopt is activated, create timestamp and copy to iob */
if (conn->sconn.s_timestamp) if (conn->timestamp)
{ {
struct timespec *ts = (struct timespec *) struct timespec *ts = (struct timespec *)
&dev->d_appdata[dev->d_len]; &dev->d_appdata[dev->d_len];

View file

@ -74,7 +74,7 @@
* *
****************************************************************************/ ****************************************************************************/
int can_getsockopt(FAR struct socket *psock, int option, int can_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len) FAR void *value, FAR socklen_t *value_len)
{ {
FAR struct can_conn_s *conn; FAR struct can_conn_s *conn;
@ -84,6 +84,24 @@ int can_getsockopt(FAR struct socket *psock, int option,
psock->s_conn != NULL); psock->s_conn != NULL);
conn = (FAR struct can_conn_s *)psock->s_conn; conn = (FAR struct can_conn_s *)psock->s_conn;
#ifdef CONFIG_NET_TIMESTAMP
if (level == SOL_SOCKET && option == SO_TIMESTAMP)
{
if (*value_len != sizeof(int32_t))
{
return -EINVAL;
}
*(FAR int32_t *)value = conn->timestamp;
return OK;
}
#endif
if (level != SOL_CAN_RAW)
{
return -ENOPROTOOPT;
}
if (psock->s_type != SOCK_RAW) if (psock->s_type != SOCK_RAW)
{ {
nerr("ERROR: Not a RAW CAN socket\n"); nerr("ERROR: Not a RAW CAN socket\n");

View file

@ -434,9 +434,9 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
#endif #endif
{ {
#ifdef CONFIG_NET_TIMESTAMP #ifdef CONFIG_NET_TIMESTAMP
if ((conn->sconn.s_timestamp && (dev->d_len > if ((conn->timestamp && (dev->d_len >
sizeof(struct can_frame) + sizeof(struct timeval))) sizeof(struct can_frame) + sizeof(struct timeval)))
|| (!conn->sconn.s_timestamp && (dev->d_len > || (!conn->timestamp && (dev->d_len >
sizeof(struct can_frame)))) sizeof(struct can_frame))))
#else #else
if (dev->d_len > sizeof(struct can_frame)) if (dev->d_len > sizeof(struct can_frame))
@ -454,7 +454,7 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
can_newdata(dev, pstate); can_newdata(dev, pstate);
#ifdef CONFIG_NET_TIMESTAMP #ifdef CONFIG_NET_TIMESTAMP
if (conn->sconn.s_timestamp) if (conn->timestamp)
{ {
if (pstate->pr_msglen == sizeof(struct timeval)) if (pstate->pr_msglen == sizeof(struct timeval))
{ {
@ -587,7 +587,7 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
state.pr_buffer = msg->msg_iov->iov_base; state.pr_buffer = msg->msg_iov->iov_base;
#ifdef CONFIG_NET_TIMESTAMP #ifdef CONFIG_NET_TIMESTAMP
if (conn->sconn.s_timestamp && msg->msg_controllen >= if (conn->timestamp && msg->msg_controllen >=
(sizeof(struct cmsghdr) + sizeof(struct timeval))) (sizeof(struct cmsghdr) + sizeof(struct timeval)))
{ {
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
@ -619,7 +619,7 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
if (ret > 0) if (ret > 0)
{ {
#ifdef CONFIG_NET_TIMESTAMP #ifdef CONFIG_NET_TIMESTAMP
if (conn->sconn.s_timestamp) if (conn->timestamp)
{ {
if (state.pr_msglen == sizeof(struct timeval)) if (state.pr_msglen == sizeof(struct timeval))
{ {

View file

@ -58,6 +58,7 @@
* *
* Input Parameters: * Input Parameters:
* psock Socket structure of socket to operate on * psock Socket structure of socket to operate on
* level Protocol level to set the option
* option identifies the option to set * option identifies the option to set
* value Points to the argument value * value Points to the argument value
* value_len The length of the argument value * value_len The length of the argument value
@ -69,7 +70,7 @@
* *
****************************************************************************/ ****************************************************************************/
int can_setsockopt(FAR struct socket *psock, int option, int can_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len) FAR const void *value, socklen_t value_len)
{ {
FAR struct can_conn_s *conn; FAR struct can_conn_s *conn;
@ -81,6 +82,37 @@ int can_setsockopt(FAR struct socket *psock, int option,
conn = (FAR struct can_conn_s *)psock->s_conn; conn = (FAR struct can_conn_s *)psock->s_conn;
#ifdef CONFIG_NET_TIMESTAMP
/* Generates a timestamp for each incoming packet */
if (level == SOL_SOCKET && option == SO_TIMESTAMP)
{
/* Verify that option is at least the size of an integer. */
if (value_len < sizeof(int32_t))
{
return -EINVAL;
}
/* Lock the network so that we have exclusive access to the socket
* options.
*/
net_lock();
conn->timestamp = *((FAR int32_t *)value);
net_unlock();
return OK;
}
#endif
if (level != SOL_CAN_RAW)
{
return -ENOPROTOOPT;
}
if (psock->s_type != SOCK_RAW) if (psock->s_type != SOCK_RAW)
{ {
nerr("ERROR: Not a RAW CAN socket\n"); nerr("ERROR: Not a RAW CAN socket\n");

View file

@ -84,7 +84,13 @@ const struct sock_intf_s g_can_sockif =
can_poll_local, /* si_poll */ can_poll_local, /* si_poll */
can_sendmsg, /* si_sendmsg */ can_sendmsg, /* si_sendmsg */
can_recvmsg, /* si_recvmsg */ can_recvmsg, /* si_recvmsg */
can_close /* si_close */ can_close, /* si_close */
NULL, /* si_ioctl */
NULL /* si_socketpair */
#if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_CANPROTO_OPTIONS)
, can_getsockopt /* si_getsockopt */
, can_setsockopt /* si_setsockopt */
#endif
}; };
/**************************************************************************** /****************************************************************************

View file

@ -91,6 +91,12 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
static int inet_ioctl(FAR struct socket *psock, static int inet_ioctl(FAR struct socket *psock,
int cmd, unsigned long arg); int cmd, unsigned long arg);
static int inet_socketpair(FAR struct socket *psocks[2]); static int inet_socketpair(FAR struct socket *psocks[2]);
#ifdef CONFIG_NET_SOCKOPTS
static int inet_getsockopt(FAR struct socket *psock, int level,
int option, FAR void *value, FAR socklen_t *value_len);
static int inet_setsockopt(FAR struct socket *psock, int level,
int option, FAR const void *value, socklen_t value_len);
#endif
#ifdef CONFIG_NET_SENDFILE #ifdef CONFIG_NET_SENDFILE
static ssize_t inet_sendfile(FAR struct socket *psock, static ssize_t inet_sendfile(FAR struct socket *psock,
FAR struct file *infile, FAR off_t *offset, FAR struct file *infile, FAR off_t *offset,
@ -118,9 +124,12 @@ static const struct sock_intf_s g_inet_sockif =
inet_close, /* si_close */ inet_close, /* si_close */
inet_ioctl, /* si_ioctl */ inet_ioctl, /* si_ioctl */
inet_socketpair /* si_socketpair */ inet_socketpair /* si_socketpair */
#ifdef CONFIG_NET_SOCKOPTS
, inet_getsockopt /* si_getsockopt */
, inet_setsockopt /* si_setsockopt */
#endif
#ifdef CONFIG_NET_SENDFILE #ifdef CONFIG_NET_SENDFILE
, , inet_sendfile /* si_sendfile */
inet_sendfile /* si_sendfile */
#endif #endif
}; };
@ -562,6 +571,464 @@ static int inet_getpeername(FAR struct socket *psock,
} }
} }
#ifdef CONFIG_NET_SOCKOPTS
/****************************************************************************
* Name: inet_get_socketlevel_option
*
* Description:
* inet_get_socketlevel_option() retrieve the value for the option
* specified by the 'option' argument for the socket specified by the
* 'psock' argument. If the size of the option value is greater than
* 'value_len', the value stored in the object pointed to by the 'value'
* argument will be silently truncated. Otherwise, the length pointed to
* by the 'value_len' argument will be modified to indicate the actual
* length of the 'value'.
*
* The 'level' argument specifies the protocol level of the option. To
* retrieve options at the socket level, specify the level argument as
* SOL_SOCKET; to retrieve options at the TCP-protocol level, the level
* argument is SOL_TCP.
*
* See <sys/socket.h> a complete list of values for the socket-level
* 'option' argument. Protocol-specific options are are protocol specific
* header files (such as netinet/tcp.h for the case of the TCP protocol).
*
* Input Parameters:
* psock Socket structure of the socket to query
* level Protocol level to set the option
* option identifies the option to get
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error. See psock_getsockopt() for
* the complete list of appropriate return error codes.
*
****************************************************************************/
static int inet_get_socketlevel_option(FAR struct socket *psock, int option,
FAR void *value,
FAR socklen_t *value_len)
{
switch (option)
{
#if CONFIG_NET_RECV_BUFSIZE > 0
case SO_RCVBUF: /* Reports receive buffer size */
{
if (*value_len != sizeof(int))
{
return -EINVAL;
}
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp = psock->s_conn;
*(FAR int *)value = tcp->rcv_bufs;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp = psock->s_conn;
*(FAR int *)value = udp->rcvbufs;
}
else
#endif
{
return -ENOPROTOOPT;
}
}
break;
#endif
#if CONFIG_NET_SEND_BUFSIZE > 0
case SO_SNDBUF: /* Reports send buffer size */
{
if (*value_len != sizeof(int))
{
return -EINVAL;
}
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp = psock->s_conn;
*(FAR int *)value = tcp->snd_bufs;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp = psock->s_conn;
/* Save the send buffer size */
*(FAR int *)value = udp->sndbufs;
}
else
#endif
{
return -ENOPROTOOPT;
}
}
break;
#endif
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
case SO_KEEPALIVE:
{
/* Any connection-oriented protocol could potentially support
* SO_KEEPALIVE. However, this option is currently only available
* for TCP/IP.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given TCP connection may service
* multiple sockets (via dup'ing of the socket). There is, however,
* still only one connection to be monitored and that is a global
* attribute across all of the clones that may use the underlying
* connection.
*/
/* Verifies TCP connections active by enabling the periodic
* transmission of probes.
*/
return tcp_getsockopt(psock, option, value, value_len);
}
#endif
default:
return -ENOPROTOOPT;
}
return OK;
}
/****************************************************************************
* Name: inet_getsockopt
*
* Description:
* inet_getsockopt() retrieve the value for the option specified by the
* 'option' argument at the protocol level specified by the 'level'
* argument. If the size of the option value is greater than 'value_len',
* the value stored in the object pointed to by the 'value' argument will
* be silently truncated. Otherwise, the length pointed to by the
* 'value_len' argument will be modified to indicate the actual length
* of the 'value'.
*
* The 'level' argument specifies the protocol level of the option. To
* retrieve options at the socket level, specify the level argument as
* SOL_SOCKET.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
*
* Input Parameters:
* psock Socket structure of the socket to query
* level Protocol level to set the option
* option identifies the option to get
* value Points to the argument value
* value_len The length of the argument value
*
****************************************************************************/
static int inet_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len)
{
if (level == SOL_SOCKET)
{
return inet_get_socketlevel_option(psock, option, value, value_len);
}
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
else if (level == IPPROTO_TCP)
{
return tcp_getsockopt(psock, option, value, value_len);
}
#endif
else
{
return -ENOPROTOOPT;
}
}
/****************************************************************************
* Name: inet_set_socketlevel_option
*
* Description:
* inet_set_socketlevel_option() sets the socket-level option specified by
* the 'option' argument to the value pointed to by the 'value' argument
* for the socket specified by the 'psock' argument.
*
* See <sys/socket.h> a complete list of values for the socket level
* 'option' argument.
*
* Input Parameters:
* psock Socket structure of socket to operate on
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error. See psock_setcockopt() for
* the list of possible error values.
*
****************************************************************************/
static int inet_set_socketlevel_option(FAR struct socket *psock, int option,
FAR const void *value,
socklen_t value_len)
{
switch (option)
{
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
case SO_KEEPALIVE:
{
/* Any connection-oriented protocol could potentially support
* SO_KEEPALIVE. However, this option is currently only available
* for TCP/IP.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given TCP connection may service
* multiple sockets (via dup'ing of the socket). There is, however,
* still only one connection to be monitored and that is a global
* attribute across all of the clones that may use the underlying
* connection.
*/
/* Verifies TCP connections active by enabling the
* periodic transmission of probes
*/
return tcp_setsockopt(psock, option, value, value_len);
}
#endif
#ifdef CONFIG_NET_SOLINGER
case SO_LINGER:
{
/* Lingers on a close() if data is present */
FAR struct socket_conn_s *conn = psock->s_conn;
FAR struct linger *setting;
/* Verify that option is at least the size of an 'struct linger'. */
if (value_len < sizeof(struct linger))
{
return -EINVAL;
}
/* Get the value. Is the option being set or cleared? */
setting = (FAR struct linger *)value;
/* Lock the network so that we have exclusive access to the socket
* options.
*/
net_lock();
/* Set or clear the linger option bit and linger time
* (in deciseconds)
*/
if (setting->l_onoff)
{
_SO_SETOPT(conn->s_options, option);
conn->s_linger = 10 * setting->l_linger;
}
else
{
_SO_CLROPT(conn->s_options, option);
conn->s_linger = 0;
}
net_unlock();
}
break;
#endif
#if CONFIG_NET_RECV_BUFSIZE > 0
case SO_RCVBUF: /* Sets receive buffer size */
{
int buffersize;
/* Verify that option is the size of an 'int'. Should also check
* that 'value' is properly aligned for an 'int'
*/
if (value_len != sizeof(int))
{
return -EINVAL;
}
/* Get the value. Is the option being set or cleared? */
buffersize = *(FAR int *)value;
if (buffersize < 0)
{
return -EINVAL;
}
net_lock();
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp = psock->s_conn;
/* Save the receive buffer size */
tcp->rcv_bufs = buffersize;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp = psock->s_conn;
/* Save the receive buffer size */
udp->rcvbufs = buffersize;
}
else
#endif
{
net_unlock();
return -ENOPROTOOPT;
}
net_unlock();
}
break;
#endif
#if CONFIG_NET_SEND_BUFSIZE > 0
case SO_SNDBUF: /* Sets send buffer size */
{
int buffersize;
/* Verify that option is the size of an 'int'. Should also check
* that 'value' is properly aligned for an 'int'
*/
if (value_len != sizeof(int))
{
return -EINVAL;
}
/* Get the value. Is the option being set or cleared? */
buffersize = *(FAR int *)value;
if (buffersize < 0)
{
return -EINVAL;
}
net_lock();
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp = psock->s_conn;
/* Save the send buffer size */
tcp->snd_bufs = buffersize;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp = psock->s_conn;
/* Save the send buffer size */
udp->sndbufs = buffersize;
}
else
#endif
{
net_unlock();
return -ENOPROTOOPT;
}
net_unlock();
}
break;
#endif
default:
return -ENOPROTOOPT;
}
return OK;
}
/****************************************************************************
* Name: inet_setsockopt
*
* Description:
* inet_setsockopt() sets the option specified by the 'option' argument,
* at the protocol level specified by the 'level' argument, to the value
* pointed to by the 'value' argument for the connection.
*
* The 'level' argument specifies the protocol level of the option. To set
* options at the socket level, specify the level argument as SOL_SOCKET.
*
* See <sys/socket.h> a complete list of values for the 'option' argument.
*
* Input Parameters:
* psock Socket structure of the socket to query
* level Protocol level to set the option
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
****************************************************************************/
static int inet_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len)
{
switch (level)
{
case SOL_SOCKET:
return inet_set_socketlevel_option(psock, option, value, value_len);
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
case IPPROTO_TCP:/* TCP protocol socket options (see include/netinet/tcp.h) */
return tcp_setsockopt(psock, option, value, value_len);
#endif
#ifdef CONFIG_NET_UDPPROTO_OPTIONS
case IPPROTO_UDP:/* UDP protocol socket options (see include/netinet/udp.h) */
return udp_setsockopt(psock, option, value, value_len);
#endif
#ifdef CONFIG_NET_IPv4
case IPPROTO_IP:/* TCP protocol socket options (see include/netinet/in.h) */
return ipv4_setsockopt(psock, option, value, value_len);
#endif
#ifdef CONFIG_NET_IPv6
case IPPROTO_IPV6:/* TCP protocol socket options (see include/netinet/in.h) */
return ipv6_setsockopt(psock, option, value, value_len);
#endif
default:
return -ENOPROTOOPT;
}
}
#endif
/**************************************************************************** /****************************************************************************
* Name: inet_listen * Name: inet_listen
* *

View file

@ -33,11 +33,7 @@
#include <errno.h> #include <errno.h>
#include "socket/socket.h" #include "socket/socket.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "usrsock/usrsock.h"
#include "utils/utils.h" #include "utils/utils.h"
#include "can/can.h"
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
@ -128,39 +124,18 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
net_dsec2timeval(timeo, (struct timeval *)value); net_dsec2timeval(timeo, (struct timeval *)value);
*value_len = sizeof(struct timeval); *value_len = sizeof(struct timeval);
} }
break;
return OK;
}
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
if (option == SO_TYPE)
{
FAR struct usrsock_conn_s *uconn = psock->s_conn;
/* Return the actual socket type */
*(FAR int *)value = uconn->type;
*value_len = sizeof(int);
return OK;
}
return -ENOPROTOOPT;
}
#endif
switch (option)
{
case SO_ACCEPTCONN: /* Reports whether socket listening is enabled */ case SO_ACCEPTCONN: /* Reports whether socket listening is enabled */
if (*value_len < sizeof(int)) {
{ if (*value_len < sizeof(int))
return -EINVAL; {
} return -EINVAL;
}
*(FAR int *)value = _SS_ISLISTENING(conn->s_flags); *(FAR int *)value = _SS_ISLISTENING(conn->s_flags);
*value_len = sizeof(int); *value_len = sizeof(int);
}
break; break;
/* The following options take a point to an integer boolean value. /* The following options take a point to an integer boolean value.
@ -171,10 +146,8 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
case SO_BROADCAST: /* Permits sending of broadcast messages */ case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */ case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */ case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
#ifndef CONFIG_NET_TCPPROTO_OPTIONS
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */ * periodic transmission of probes */
#endif
case SO_OOBINLINE: /* Leaves received out-of-band data inline */ case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_REUSEADDR: /* Allow reuse of local addresses */ case SO_REUSEADDR: /* Allow reuse of local addresses */
{ {
@ -201,23 +174,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
} }
break; break;
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
/* Any connection-oriented protocol could potentially support
* SO_KEEPALIVE. However, this option is currently only available for
* TCP/IP.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given TCP connection may service multiple
* sockets (via dup'ing of the socket). There is, however, still only
* one connection to be monitored and that is a global attribute across
* all of the clones that may use the underlying connection.
*/
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
return tcp_getsockopt(psock, option, value, value_len);
#endif
case SO_TYPE: /* Reports the socket type */ case SO_TYPE: /* Reports the socket type */
{ {
/* Verify that option is the size of an 'int'. Should also check /* Verify that option is the size of an 'int'. Should also check
@ -248,97 +204,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
} }
break; break;
#ifdef CONFIG_NET_TIMESTAMP
case SO_TIMESTAMP:
{
if (*value_len != sizeof(int))
{
return -EINVAL;
}
*(FAR int *)value = (int)conn->s_timestamp;
}
break;
#endif
#if CONFIG_NET_RECV_BUFSIZE > 0
case SO_RCVBUF: /* Reports receive buffer size */
{
if (*value_len != sizeof(int))
{
return -EINVAL;
}
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp;
tcp = (FAR struct tcp_conn_s *)conn;
*(FAR int *)value = tcp->rcv_bufs;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp;
udp = (FAR struct udp_conn_s *)conn;
*(FAR int *)value = udp->rcvbufs;
}
else
#endif
{
return -ENOPROTOOPT;
}
break;
}
#endif
#if CONFIG_NET_SEND_BUFSIZE > 0
case SO_SNDBUF: /* Reports send buffer size */
{
if (*value_len != sizeof(int))
{
return -EINVAL;
}
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp;
tcp = (FAR struct tcp_conn_s *)conn;
*(FAR int *)value = tcp->snd_bufs;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp;
udp = (FAR struct udp_conn_s *)conn;
/* Save the send buffer size */
*(FAR int *)value = udp->sndbufs;
}
else
#endif
{
return -ENOPROTOOPT;
}
break;
}
#endif
default: default:
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
@ -397,7 +262,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
int psock_getsockopt(FAR struct socket *psock, int level, int option, int psock_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len) FAR void *value, FAR socklen_t *value_len)
{ {
int ret; int ret = -ENOPROTOOPT;
/* Verify that the sockfd corresponds to valid, allocated socket */ /* Verify that the sockfd corresponds to valid, allocated socket */
@ -406,49 +271,20 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
return -EBADF; return -EBADF;
} }
/* Handle retrieval of the socket option according to the level at which /* Perform the socket interface operation */
* option should be applied.
*/
switch (level) if (psock->s_sockif->si_getsockopt != NULL)
{ {
case SOL_SOCKET: /* Socket-level options (see include/sys/socket.h) */ ret = psock->s_sockif->si_getsockopt(psock, level, option,
ret = psock_socketlevel_option(psock, option, value, value_len); value, value_len);
break;
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
case IPPROTO_TCP: /* TCP protocol socket options (see include/netinet/tcp.h) */
ret = tcp_getsockopt(psock, option, value, value_len);
break;
#endif
#ifdef CONFIG_NET_CANPROTO_OPTIONS
case SOL_CAN_RAW:/* CAN protocol socket options (see include/netpacket/can.h) */
ret = can_getsockopt(psock, option, value, value_len);
break;
#endif
/* These levels are defined in sys/socket.h, but are not yet
* implemented.
*/
case IPPROTO_IP: /* TCP protocol socket options (see include/netinet/ip.h) */
case IPPROTO_IPV6: /* TCP protocol socket options (see include/netinet/ip6.h) */
case IPPROTO_UDP: /* TCP protocol socket options (see include/netinit/udp.h) */
default: /* The provided level is invalid */
ret = -ENOPROTOOPT;
break;
} }
#ifdef CONFIG_NET_USRSOCK /* Try socket level if the socket interface operation is not available */
/* Try usrsock further if the protocol not available */
if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE) if (ret == -ENOPROTOOPT && level == SOL_SOCKET)
{ {
ret = usrsock_getsockopt(psock->s_conn, level, ret = psock_socketlevel_option(psock, option, value, value_len);
option, value, value_len);
} }
#endif
return ret; return ret;
} }

View file

@ -34,15 +34,11 @@
#include <arch/irq.h> #include <arch/irq.h>
#include <nuttx/net/net.h> #include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <netdev/netdev.h> #include <netdev/netdev.h>
#include "socket/socket.h" #include "socket/socket.h"
#include "inet/inet.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "usrsock/usrsock.h"
#include "utils/utils.h" #include "utils/utils.h"
#include "can/can.h"
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
@ -134,27 +130,14 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
{ {
_SO_SETOPT(conn->s_options, option); _SO_SETOPT(conn->s_options, option);
} }
return OK;
} }
} break;
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
return -ENOPROTOOPT;
}
#endif
switch (option)
{
case SO_BROADCAST: /* Permits sending of broadcast messages */ case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */ case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */ case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
#ifndef CONFIG_NET_TCPPROTO_OPTIONS
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */ * periodic transmission of probes */
#endif
case SO_OOBINLINE: /* Leaves received out-of-band data inline */ case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_REUSEADDR: /* Allow reuse of local addresses */ case SO_REUSEADDR: /* Allow reuse of local addresses */
{ {
@ -194,212 +177,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
} }
break; break;
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
/* Any connection-oriented protocol could potentially support
* SO_KEEPALIVE. However, this option is currently only available for
* TCP/IP.
*
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
* protocol-level option. A given TCP connection may service multiple
* sockets (via dup'ing of the socket). There is, however, still only
* one connection to be monitored and that is a global attribute across
* all of the clones that may use the underlying connection.
*/
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
return tcp_setsockopt(psock, option, value, value_len);
#endif
#ifdef CONFIG_NET_SOLINGER
case SO_LINGER: /* Lingers on a close() if data is present */
{
FAR struct linger *setting;
/* Verify that option is at least the size of an 'struct linger'. */
if (value_len < sizeof(FAR struct linger))
{
return -EINVAL;
}
/* Get the value. Is the option being set or cleared? */
setting = (FAR struct linger *)value;
/* Lock the network so that we have exclusive access to the socket
* options.
*/
net_lock();
/* Set or clear the linger option bit and linger time
* (in deciseconds)
*/
if (setting->l_onoff)
{
_SO_SETOPT(conn->s_options, option);
conn->s_linger = 10 * setting->l_linger;
}
else
{
_SO_CLROPT(conn->s_options, option);
conn->s_linger = 0;
}
net_unlock();
}
break;
#endif
#ifdef CONFIG_NET_TIMESTAMP
case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
{
/* Verify that option is at least the size of an integer. */
if (value_len < sizeof(FAR int32_t))
{
return -EINVAL;
}
/* Lock the network so that we have exclusive access to the socket
* options.
*/
net_lock();
conn->s_timestamp = *((FAR int32_t *)value);
net_unlock();
}
break;
#endif
#if CONFIG_NET_RECV_BUFSIZE > 0
case SO_RCVBUF: /* Sets receive buffer size */
{
int buffersize;
/* Verify that option is the size of an 'int'. Should also check
* that 'value' is properly aligned for an 'int'
*/
if (value_len != sizeof(int))
{
return -EINVAL;
}
/* Get the value. Is the option being set or cleared? */
buffersize = *(FAR int *)value;
if (buffersize < 0)
{
return -EINVAL;
}
net_lock();
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp;
tcp = (FAR struct tcp_conn_s *)conn;
/* Save the receive buffer size */
tcp->rcv_bufs = buffersize;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp;
udp = (FAR struct udp_conn_s *)conn;
/* Save the receive buffer size */
udp->rcvbufs = buffersize;
}
else
#endif
{
net_unlock();
return -ENOPROTOOPT;
}
net_unlock();
break;
}
#endif
#if CONFIG_NET_SEND_BUFSIZE > 0
case SO_SNDBUF: /* Sets send buffer size */
{
int buffersize;
/* Verify that option is the size of an 'int'. Should also check
* that 'value' is properly aligned for an 'int'
*/
if (value_len != sizeof(int))
{
return -EINVAL;
}
/* Get the value. Is the option being set or cleared? */
buffersize = *(FAR int *)value;
if (buffersize < 0)
{
return -EINVAL;
}
net_lock();
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
if (psock->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *tcp;
tcp = (FAR struct tcp_conn_s *)conn;
/* Save the send buffer size */
tcp->snd_bufs = buffersize;
}
else
#endif
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
if (psock->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *udp;
udp = (FAR struct udp_conn_s *)conn;
/* Save the send buffer size */
udp->sndbufs = buffersize;
}
else
#endif
{
net_unlock();
return -ENOPROTOOPT;
}
net_unlock();
break;
}
#endif
#ifdef CONFIG_NET_BINDTODEVICE #ifdef CONFIG_NET_BINDTODEVICE
/* Handle the SO_BINDTODEVICE socket-level option. /* Handle the SO_BINDTODEVICE socket-level option.
* *
@ -516,7 +293,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
int psock_setsockopt(FAR struct socket *psock, int level, int option, int psock_setsockopt(FAR struct socket *psock, int level, int option,
FAR const void *value, socklen_t value_len) FAR const void *value, socklen_t value_len)
{ {
int ret; int ret = -ENOPROTOOPT;
/* Verify that the sockfd corresponds to valid, allocated socket */ /* Verify that the sockfd corresponds to valid, allocated socket */
@ -525,60 +302,20 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
return -EBADF; return -EBADF;
} }
/* Handle setting of the socket option according to the level at which /* Perform the socket interface operation */
* option should be applied.
*/
switch (level) if (psock->s_sockif->si_setsockopt != NULL)
{ {
case SOL_SOCKET: /* Socket-level options (see include/sys/socket.h) */ ret = psock->s_sockif->si_setsockopt(psock, level, option,
ret = psock_socketlevel_option(psock, option, value, value_len); value, value_len);
break;
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
case IPPROTO_TCP:/* TCP protocol socket options (see include/netinet/tcp.h) */
ret = tcp_setsockopt(psock, option, value, value_len);
break;
#endif
#ifdef CONFIG_NET_UDPPROTO_OPTIONS
case IPPROTO_UDP:/* UDP protocol socket options (see include/netinet/udp.h) */
ret = udp_setsockopt(psock, option, value, value_len);
break;
#endif
#ifdef CONFIG_NET_IPv4
case IPPROTO_IP:/* TCP protocol socket options (see include/netinet/in.h) */
ret = ipv4_setsockopt(psock, option, value, value_len);
break;
#endif
#ifdef CONFIG_NET_IPv6
case IPPROTO_IPV6:/* TCP protocol socket options (see include/netinet/in.h) */
ret = ipv6_setsockopt(psock, option, value, value_len);
break;
#endif
#ifdef CONFIG_NET_CANPROTO_OPTIONS
case SOL_CAN_RAW: /* CAN protocol socket options (see include/netpacket/can.h) */
ret = can_setsockopt(psock, option, value, value_len);
break;
#endif
default: /* The provided level is invalid */
ret = -ENOPROTOOPT;
break;
} }
#ifdef CONFIG_NET_USRSOCK /* Try socket level if the socket interface operation is not available */
/* Try usrsock further if the protocol not available */
if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE) if (ret == -ENOPROTOOPT && level == SOL_SOCKET)
{ {
ret = usrsock_setsockopt(psock->s_conn, level, ret = psock_socketlevel_option(psock, option, value, value_len);
option, value, value_len);
} }
#endif
return ret; return ret;
} }

View file

@ -546,7 +546,7 @@ ssize_t usrsock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
* See <sys/socket.h> a complete list of values for the 'option' argument. * See <sys/socket.h> a complete list of values for the 'option' argument.
* *
* Input Parameters: * Input Parameters:
* conn usrsock socket connection structure * psock Socket structure of the socket to query
* level Protocol level to set the option * level Protocol level to set the option
* option identifies the option to get * option identifies the option to get
* value Points to the argument value * value Points to the argument value
@ -554,9 +554,8 @@ ssize_t usrsock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
* *
****************************************************************************/ ****************************************************************************/
int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int level, int usrsock_getsockopt(FAR struct socket *psock, int level, int option,
int option, FAR void *value, FAR void *value, FAR socklen_t *value_len);
FAR socklen_t *value_len);
/**************************************************************************** /****************************************************************************
* Name: usrsock_setsockopt * Name: usrsock_setsockopt
@ -572,7 +571,7 @@ int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int level,
* See <sys/socket.h> a complete list of values for the 'option' argument. * See <sys/socket.h> a complete list of values for the 'option' argument.
* *
* Input Parameters: * Input Parameters:
* conn usrsock socket connection structure * psock Socket structure of the socket to query
* level Protocol level to set the option * level Protocol level to set the option
* option identifies the option to set * option identifies the option to set
* value Points to the argument value * value Points to the argument value
@ -580,9 +579,8 @@ int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int level,
* *
****************************************************************************/ ****************************************************************************/
int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int usrsock_setsockopt(FAR struct socket *psock, int level, int option,
int option, FAR const void *value, FAR const void *value, socklen_t value_len);
FAR socklen_t value_len);
/**************************************************************************** /****************************************************************************
* Name: usrsock_getsockname * Name: usrsock_getsockname

View file

@ -160,7 +160,7 @@ static int do_getsockopt_request(FAR struct usrsock_conn_s *conn, int level,
* See <sys/socket.h> a complete list of values for the 'option' argument. * See <sys/socket.h> a complete list of values for the 'option' argument.
* *
* Input Parameters: * Input Parameters:
* conn usrsock socket connection structure * psock Socket structure of the socket to query
* level Protocol level to set the option * level Protocol level to set the option
* option identifies the option to get * option identifies the option to get
* value Points to the argument value * value Points to the argument value
@ -168,10 +168,10 @@ static int do_getsockopt_request(FAR struct usrsock_conn_s *conn, int level,
* *
****************************************************************************/ ****************************************************************************/
int usrsock_getsockopt(FAR struct usrsock_conn_s *conn, int usrsock_getsockopt(FAR struct socket *psock, int level, int option,
int level, int option,
FAR void *value, FAR socklen_t *value_len) FAR void *value, FAR socklen_t *value_len)
{ {
FAR struct usrsock_conn_s *conn = psock->s_conn;
struct usrsock_data_reqstate_s state = struct usrsock_data_reqstate_s state =
{ {
}; };
@ -179,6 +179,22 @@ int usrsock_getsockopt(FAR struct usrsock_conn_s *conn,
struct iovec inbufs[1]; struct iovec inbufs[1];
int ret; int ret;
if (level == SOL_SOCKET)
{
if (option == SO_TYPE)
{
/* Return the actual socket type */
*(FAR int *)value = conn->type;
*value_len = sizeof(int);
return OK;
}
else
{
return -ENOPROTOOPT;
}
}
net_lock(); net_lock();
if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||

View file

@ -149,7 +149,7 @@ static int do_setsockopt_request(FAR struct usrsock_conn_s *conn,
* See <sys/socket.h> a complete list of values for the 'option' argument. * See <sys/socket.h> a complete list of values for the 'option' argument.
* *
* Input Parameters: * Input Parameters:
* conn usrsock socket connection structure * psock Socket structure of the socket to query
* level Protocol level to set the option * level Protocol level to set the option
* option identifies the option to set * option identifies the option to set
* value Points to the argument value * value Points to the argument value
@ -157,10 +157,10 @@ static int do_setsockopt_request(FAR struct usrsock_conn_s *conn,
* *
****************************************************************************/ ****************************************************************************/
int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int usrsock_setsockopt(FAR struct socket *psock, int level, int option,
int level, int option, FAR const void *value, socklen_t value_len)
FAR const void *value, FAR socklen_t value_len)
{ {
FAR struct usrsock_conn_s *conn = psock->s_conn;
struct usrsock_reqstate_s state = struct usrsock_reqstate_s state =
{ {
}; };
@ -168,6 +168,18 @@ int usrsock_setsockopt(FAR struct usrsock_conn_s *conn,
int ret; int ret;
DEBUGASSERT(conn); DEBUGASSERT(conn);
if (level == SOL_SOCKET)
{
if (option == SO_RCVTIMEO || option == SO_SNDTIMEO)
{
return -ENOPROTOOPT;
}
else
{
return -EINVAL;
}
}
net_lock(); net_lock();
if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||

View file

@ -66,7 +66,12 @@ const struct sock_intf_s g_usrsock_sockif =
usrsock_sendmsg, /* si_sendmsg */ usrsock_sendmsg, /* si_sendmsg */
usrsock_recvmsg, /* si_recvmsg */ usrsock_recvmsg, /* si_recvmsg */
usrsock_sockif_close, /* si_close */ usrsock_sockif_close, /* si_close */
usrsock_ioctl /* si_ioctl */ usrsock_ioctl, /* si_ioctl */
NULL /* si_socketpair */
#ifdef CONFIG_NET_SOCKOPTS
, usrsock_getsockopt /* si_getsockopt */
, usrsock_setsockopt /* si_setsockopt */
#endif
}; };
/**************************************************************************** /****************************************************************************