You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/11/23 07:02:02 UTC

[incubator-nuttx] 01/02: net/get/setsockopt: add si_get/setsockopt interface to simply get/setsockopt

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit e6f8ccda4a7e533effc8483a2d2a53f7839d4d62
Author: dongjiuzhu1 <do...@xiaomi.com>
AuthorDate: Tue Nov 22 21:15:06 2022 +0800

    net/get/setsockopt: add si_get/setsockopt interface to simply get/setsockopt
    
    move private option to protocol sockif
    
    Signed-off-by: dongjiuzhu1 <do...@xiaomi.com>
---
 include/nuttx/net/net.h          |   9 +-
 net/can/can.h                    |   8 +-
 net/can/can_callback.c           |   2 +-
 net/can/can_getsockopt.c         |  20 +-
 net/can/can_recvmsg.c            |  10 +-
 net/can/can_setsockopt.c         |  34 ++-
 net/can/can_sockif.c             |   8 +-
 net/inet/inet_sockif.c           | 471 ++++++++++++++++++++++++++++++++++++++-
 net/socket/getsockopt.c          | 198 ++--------------
 net/socket/setsockopt.c          | 283 +----------------------
 net/usrsock/usrsock.h            |  14 +-
 net/usrsock/usrsock_getsockopt.c |  22 +-
 net/usrsock/usrsock_setsockopt.c |  20 +-
 net/usrsock/usrsock_sockif.c     |   7 +-
 14 files changed, 620 insertions(+), 486 deletions(-)

diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index cc7fab801e..bdabcbaf83 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -166,6 +166,12 @@ struct sock_intf_s
   CODE int        (*si_ioctl)(FAR struct socket *psock,
                     int cmd, unsigned long arg);
   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
   CODE ssize_t    (*si_sendfile)(FAR struct socket *psock,
                     FAR struct file *infile, FAR off_t *offset,
@@ -210,9 +216,6 @@ struct socket_conn_s
 #ifdef CONFIG_NET_SOLINGER
   socktimeo_t   s_linger;    /* Linger timeout value (in deciseconds) */
 #endif
-#ifdef CONFIG_NET_TIMESTAMP
-  int32_t       s_timestamp; /* Socket timestamp enabled/disabled */
-#endif
 #ifdef CONFIG_NET_BINDTODEVICE
   uint8_t       s_boundto;   /* Index of the interface we are bound to.
                               * Unbound: 0, Bound: 1-MAX_IFINDEX */
diff --git a/net/can/can.h b/net/can/can.h
index d317fea6f7..b1180c11aa 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -111,6 +111,9 @@ struct can_conn_s
   int32_t tx_deadline;
 # 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:
  *   psock     Socket structure of socket to operate on
+ *   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
@@ -365,7 +369,7 @@ void can_readahead_signal(FAR struct can_conn_s *conn);
  ****************************************************************************/
 
 #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);
 #endif
 
@@ -399,7 +403,7 @@ int can_setsockopt(FAR struct socket *psock, int option,
  ****************************************************************************/
 
 #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);
 #endif
 
diff --git a/net/can/can_callback.c b/net/can/can_callback.c
index 394c1d51ac..a5f3e17937 100644
--- a/net/can/can_callback.c
+++ b/net/can/can_callback.c
@@ -123,7 +123,7 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
 #ifdef CONFIG_NET_TIMESTAMP
       /* TIMESTAMP sockopt is activated, create timestamp and copy to iob */
 
-      if (conn->sconn.s_timestamp)
+      if (conn->timestamp)
         {
           struct timespec *ts = (struct timespec *)
                                                 &dev->d_appdata[dev->d_len];
diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c
index 17a4b18850..af6253ca3a 100644
--- a/net/can/can_getsockopt.c
+++ b/net/can/can_getsockopt.c
@@ -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 struct can_conn_s *conn;
@@ -84,6 +84,24 @@ int can_getsockopt(FAR struct socket *psock, int option,
               psock->s_conn != NULL);
   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)
     {
       nerr("ERROR:  Not a RAW CAN socket\n");
diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c
index 189505f717..8ef711de8b 100644
--- a/net/can/can_recvmsg.c
+++ b/net/can/can_recvmsg.c
@@ -434,9 +434,9 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
 #endif
             {
 #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)))
-                  || (!conn->sconn.s_timestamp && (dev->d_len >
+                  || (!conn->timestamp && (dev->d_len >
                    sizeof(struct can_frame))))
 #else
               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);
 
 #ifdef CONFIG_NET_TIMESTAMP
-          if (conn->sconn.s_timestamp)
+          if (conn->timestamp)
             {
               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;
 
 #ifdef CONFIG_NET_TIMESTAMP
-  if (conn->sconn.s_timestamp && msg->msg_controllen >=
+  if (conn->timestamp && msg->msg_controllen >=
         (sizeof(struct cmsghdr) + sizeof(struct timeval)))
     {
       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)
     {
 #ifdef CONFIG_NET_TIMESTAMP
-      if (conn->sconn.s_timestamp)
+      if (conn->timestamp)
         {
           if (state.pr_msglen == sizeof(struct timeval))
             {
diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c
index 2b43c1de98..efa87ef9d5 100644
--- a/net/can/can_setsockopt.c
+++ b/net/can/can_setsockopt.c
@@ -58,6 +58,7 @@
  *
  * Input Parameters:
  *   psock     Socket structure of socket to operate on
+ *   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
@@ -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 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;
 
+#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)
     {
       nerr("ERROR:  Not a RAW CAN socket\n");
diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c
index 3e9ccc27b0..3fb1623a2f 100644
--- a/net/can/can_sockif.c
+++ b/net/can/can_sockif.c
@@ -84,7 +84,13 @@ const struct sock_intf_s g_can_sockif =
   can_poll_local,   /* si_poll */
   can_sendmsg,      /* si_sendmsg */
   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
 };
 
 /****************************************************************************
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index c198c14c87..a7b1030a80 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -91,6 +91,12 @@ static ssize_t    inet_recvmsg(FAR struct socket *psock,
 static int        inet_ioctl(FAR struct socket *psock,
                     int cmd, unsigned long arg);
 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
 static ssize_t    inet_sendfile(FAR struct socket *psock,
                     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_ioctl,       /* si_ioctl */
   inet_socketpair   /* si_socketpair */
+#ifdef CONFIG_NET_SOCKOPTS
+  , inet_getsockopt /* si_getsockopt */
+  , inet_setsockopt /* si_setsockopt */
+#endif
 #ifdef CONFIG_NET_SENDFILE
-  ,
-  inet_sendfile     /* si_sendfile */
+  , inet_sendfile   /* si_sendfile */
 #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
  *
diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c
index 4c3c75878c..f2f45e73e2 100644
--- a/net/socket/getsockopt.c
+++ b/net/socket/getsockopt.c
@@ -33,11 +33,7 @@
 #include <errno.h>
 
 #include "socket/socket.h"
-#include "tcp/tcp.h"
-#include "udp/udp.h"
-#include "usrsock/usrsock.h"
 #include "utils/utils.h"
-#include "can/can.h"
 
 /****************************************************************************
  * Private Functions
@@ -128,39 +124,18 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
           net_dsec2timeval(timeo, (struct timeval *)value);
           *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 */
-        if (*value_len < sizeof(int))
-          {
-            return -EINVAL;
-          }
+        {
+          if (*value_len < sizeof(int))
+            {
+              return -EINVAL;
+            }
 
-        *(FAR int *)value = _SS_ISLISTENING(conn->s_flags);
-        *value_len        = sizeof(int);
+          *(FAR int *)value = _SS_ISLISTENING(conn->s_flags);
+          *value_len        = sizeof(int);
+        }
         break;
 
       /* 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_DEBUG:      /* Enables recording of debugging information */
       case SO_DONTROUTE:  /* Requests outgoing messages bypass standard routing */
-#ifndef CONFIG_NET_TCPPROTO_OPTIONS
       case SO_KEEPALIVE:  /* Verifies TCP connections active by enabling the
                            * periodic transmission of probes */
-#endif
       case SO_OOBINLINE:  /* Leaves received out-of-band data inline */
       case SO_REUSEADDR:  /* Allow reuse of local addresses */
         {
@@ -201,23 +174,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
         }
         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 */
         {
           /* 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;
 
-#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:
         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,
                      FAR void *value, FAR socklen_t *value_len)
 {
-  int ret;
+  int ret = -ENOPROTOOPT;
 
   /* 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;
     }
 
-  /* Handle retrieval of the socket option according to the level at which
-   * option should be applied.
-   */
+  /* Perform the socket interface operation */
 
-  switch (level)
+  if (psock->s_sockif->si_getsockopt != NULL)
     {
-      case SOL_SOCKET:   /* Socket-level options (see include/sys/socket.h) */
-       ret = psock_socketlevel_option(psock, option, 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;
+      ret = psock->s_sockif->si_getsockopt(psock, level, option,
+                                           value, value_len);
     }
 
-#ifdef CONFIG_NET_USRSOCK
-  /* Try usrsock further if the protocol not available */
+  /* Try socket level if the socket interface operation is not available */
 
-  if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE)
+  if (ret == -ENOPROTOOPT && level == SOL_SOCKET)
     {
-      ret = usrsock_getsockopt(psock->s_conn, level,
-                               option, value, value_len);
+      ret = psock_socketlevel_option(psock, option, value, value_len);
     }
-#endif
 
   return ret;
 }
diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c
index ba72e84696..a7ede25744 100644
--- a/net/socket/setsockopt.c
+++ b/net/socket/setsockopt.c
@@ -34,15 +34,11 @@
 #include <arch/irq.h>
 
 #include <nuttx/net/net.h>
+#include <nuttx/net/netdev.h>
 #include <netdev/netdev.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 "can/can.h"
 
 /****************************************************************************
  * Public Functions
@@ -134,27 +130,14 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
             {
               _SO_SETOPT(conn->s_options, option);
             }
-
-          return OK;
         }
-    }
-
-#ifdef CONFIG_NET_USRSOCK
-    if (psock->s_type == SOCK_USRSOCK_TYPE)
-      {
-        return -ENOPROTOOPT;
-      }
-#endif
+        break;
 
-  switch (option)
-    {
       case SO_BROADCAST:  /* Permits sending of broadcast messages */
       case SO_DEBUG:      /* Enables recording of debugging information */
       case SO_DONTROUTE:  /* Requests outgoing messages bypass standard routing */
-#ifndef CONFIG_NET_TCPPROTO_OPTIONS
       case SO_KEEPALIVE:  /* Verifies TCP connections active by enabling the
                            * periodic transmission of probes */
-#endif
       case SO_OOBINLINE:  /* Leaves received out-of-band data inline */
       case SO_REUSEADDR:  /* Allow reuse of local addresses */
         {
@@ -194,212 +177,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
         }
         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
       /* 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,
                      FAR const void *value, socklen_t value_len)
 {
-  int ret;
+  int ret = -ENOPROTOOPT;
 
   /* 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;
     }
 
-  /* Handle setting of the socket option according to the level at which
-   * option should be applied.
-   */
+  /* Perform the socket interface operation */
 
-  switch (level)
+  if (psock->s_sockif->si_setsockopt != NULL)
     {
-      case SOL_SOCKET: /* Socket-level options (see include/sys/socket.h) */
-        ret = psock_socketlevel_option(psock, option, 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;
+      ret = psock->s_sockif->si_setsockopt(psock, level, option,
+                                           value, value_len);
     }
 
-#ifdef CONFIG_NET_USRSOCK
-  /* Try usrsock further if the protocol not available */
+  /* Try socket level if the socket interface operation is not available */
 
-  if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE)
+  if (ret == -ENOPROTOOPT && level == SOL_SOCKET)
     {
-      ret = usrsock_setsockopt(psock->s_conn, level,
-                               option, value, value_len);
+      ret = psock_socketlevel_option(psock, option, value, value_len);
     }
-#endif
 
   return ret;
 }
diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h
index 061afc3b10..7cbb0fd7dd 100644
--- a/net/usrsock/usrsock.h
+++ b/net/usrsock/usrsock.h
@@ -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.
  *
  * Input Parameters:
- *   conn      usrsock socket connection structure
+ *   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
@@ -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 option, FAR void *value,
-                       FAR socklen_t *value_len);
+int usrsock_getsockopt(FAR struct socket *psock, int level, int option,
+                       FAR void *value, FAR socklen_t *value_len);
 
 /****************************************************************************
  * 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.
  *
  * Input Parameters:
- *   conn      usrsock socket connection structure
+ *   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
@@ -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 option, FAR const void *value,
-                       FAR socklen_t value_len);
+int usrsock_setsockopt(FAR struct socket *psock, int level, int option,
+                       FAR const void *value, socklen_t value_len);
 
 /****************************************************************************
  * Name: usrsock_getsockname
diff --git a/net/usrsock/usrsock_getsockopt.c b/net/usrsock/usrsock_getsockopt.c
index 0b8b25e39e..07f57a26e8 100644
--- a/net/usrsock/usrsock_getsockopt.c
+++ b/net/usrsock/usrsock_getsockopt.c
@@ -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.
  *
  * Input Parameters:
- *   conn      usrsock socket connection structure
+ *   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
@@ -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 level, int option,
+int usrsock_getsockopt(FAR struct socket *psock, int level, int option,
                        FAR void *value, FAR socklen_t *value_len)
 {
+  FAR struct usrsock_conn_s *conn = psock->s_conn;
   struct usrsock_data_reqstate_s state =
   {
   };
@@ -179,6 +179,22 @@ int usrsock_getsockopt(FAR struct usrsock_conn_s *conn,
   struct iovec inbufs[1];
   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();
 
   if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||
diff --git a/net/usrsock/usrsock_setsockopt.c b/net/usrsock/usrsock_setsockopt.c
index 70302f6c98..922da98e27 100644
--- a/net/usrsock/usrsock_setsockopt.c
+++ b/net/usrsock/usrsock_setsockopt.c
@@ -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.
  *
  * Input Parameters:
- *   conn      usrsock socket connection structure
+ *   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
@@ -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 level, int option,
-                       FAR const void *value, FAR socklen_t value_len)
+int usrsock_setsockopt(FAR struct socket *psock, int level, int option,
+                       FAR const void *value, socklen_t value_len)
 {
+  FAR struct usrsock_conn_s *conn = psock->s_conn;
   struct usrsock_reqstate_s state =
   {
   };
@@ -168,6 +168,18 @@ int usrsock_setsockopt(FAR struct usrsock_conn_s *conn,
   int ret;
 
   DEBUGASSERT(conn);
+  if (level == SOL_SOCKET)
+    {
+      if (option == SO_RCVTIMEO || option == SO_SNDTIMEO)
+        {
+          return -ENOPROTOOPT;
+        }
+      else
+        {
+          return -EINVAL;
+        }
+    }
+
   net_lock();
 
   if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||
diff --git a/net/usrsock/usrsock_sockif.c b/net/usrsock/usrsock_sockif.c
index 5791ec6e68..6f83ca30fa 100644
--- a/net/usrsock/usrsock_sockif.c
+++ b/net/usrsock/usrsock_sockif.c
@@ -66,7 +66,12 @@ const struct sock_intf_s g_usrsock_sockif =
   usrsock_sendmsg,            /* si_sendmsg */
   usrsock_recvmsg,            /* si_recvmsg */
   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
 };
 
 /****************************************************************************