You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/02 14:09:25 UTC

[incubator-nuttx] 07/31: Added basic poll()/select support

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

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

commit b76d6099a570a5ff08893155e79d61c3ffb66d7c
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Fri Feb 21 16:24:54 2020 +0100

    Added basic poll()/select support
    
    Futhermore addded stubs for SocketCAN sockopts
---
 include/netpacket/can.h                      |  18 +++
 include/nuttx/can.h                          |  41 +++++
 include/nuttx/mm/iob.h                       |   3 +
 include/nuttx/wqueue.h                       |   3 +-
 include/sys/socket.h                         |  10 ++
 net/can/Kconfig                              |  19 +++
 net/can/Make.defs                            |   8 +
 net/can/can.h                                |  96 ++++++++++--
 net/can/can_callback.c                       | 145 +++++++++++++++++-
 net/can/can_conn.c                           |  22 +--
 net/can/can_getsockopt.c                     | 154 +++++++++++++++++++
 net/can/{can_callback.c => can_notifier.c}   |  50 +++----
 net/can/can_poll.c                           |   2 +-
 net/can/can_recvfrom.c                       | 166 +++++++++++++++++++-
 net/can/{can_callback.c => can_setsockopt.c} | 102 ++++++++++---
 net/can/can_sockif.c                         | 216 ++++++++++++++++++---------
 net/socket/Kconfig                           |   6 +
 net/socket/getsockopt.c                      |   6 +
 18 files changed, 909 insertions(+), 158 deletions(-)

diff --git a/include/netpacket/can.h b/include/netpacket/can.h
index b93bb21..45edab5 100644
--- a/include/netpacket/can.h
+++ b/include/netpacket/can.h
@@ -47,6 +47,9 @@
 #define CAN_EFF_MASK 0x1fffffff  /* Extended frame format (EFF) */
 #define CAN_ERR_MASK 0x1fffffff  /* Omit EFF, RTR, ERR flags */
 
+#define CAN_MTU		(sizeof(struct can_frame))
+#define CANFD_MTU	(sizeof(struct canfd_frame))
+
 /* PF_CAN protocols */
 
 #define CAN_RAW      1           /* RAW sockets */
@@ -58,6 +61,21 @@
 #define CAN_J1939    7           /* SAE J1939 */
 #define CAN_NPROTO   8
 
+/* CAN_RAW socket options */
+
+#define CAN_RAW_FILTER         (__SO_PROTOCOL + 0)     
+                                 /* set 0 .. n can_filter(s) */
+#define CAN_RAW_ERR_FILTER     (__SO_PROTOCOL + 1)      
+                                 /* set filter for error frames */
+#define CAN_RAW_LOOPBACK       (__SO_PROTOCOL + 2)      
+                                 /* local loopback (default:on) */
+#define CAN_RAW_RECV_OWN_MSGS  (__SO_PROTOCOL + 3)	     
+                                 /* receive my own msgs (default:off) */
+#define CAN_RAW_FD_FRAMES      (__SO_PROTOCOL + 4)      
+                                 /* allow CAN FD frames (default:off) */
+#define CAN_RAW_JOIN_FILTERS   (__SO_PROTOCOL + 5)     
+                                 /* all filters must match to trigger */
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
diff --git a/include/nuttx/can.h b/include/nuttx/can.h
index fd86b74..02f80a8 100644
--- a/include/nuttx/can.h
+++ b/include/nuttx/can.h
@@ -45,6 +45,8 @@
 #  include <nuttx/wqueue.h>
 #endif
 
+#include <queue.h>
+
 #ifdef CONFIG_NET_CAN
 
 /************************************************************************************
@@ -187,8 +189,26 @@
  * Public Types
  ************************************************************************************/
 
+typedef FAR void *CAN_HANDLE;
+
+struct can_response_s
+{
+  sq_entry_t flink;
+
+  /* Message-specific data may follow */
+}; //FIXME remvoe
+
+
 typedef uint32_t canid_t;
 
+/*
+ * Controller Area Network Error Message Frame Mask structure
+ *
+ * bit 0-28	: error class mask (see include/uapi/linux/can/error.h)
+ * bit 29-31	: set to zero
+ */
+typedef uint32_t can_err_mask_t;
+
 /* CAN payload length and DLC definitions according to ISO 11898-1 */
 #define CAN_MAX_DLC 8
 #define CAN_MAX_DLEN 8
@@ -256,6 +276,27 @@ struct canfd_frame {
 };
 
 
+/**
+ * struct can_filter - CAN ID based filter in can_register().
+ * @can_id:   relevant bits of CAN ID which are not masked out.
+ * @can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *          <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error message frames (CAN_ERR_FLAG bit set in mask).
+ */
+struct can_filter {
+	canid_t can_id;
+	canid_t can_mask;
+};
+
+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */
+
 /************************************************************************************
  * Public Function Prototypes
  ************************************************************************************/
diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h
index 8984af6..cabd2ff 100644
--- a/include/nuttx/mm/iob.h
+++ b/include/nuttx/mm/iob.h
@@ -220,6 +220,9 @@ enum iob_user_e
 #ifdef CONFIG_WIRELESS_BLUETOOTH
   IOBUSER_WIRELESS_BLUETOOTH,
 #endif
+#if defined(CONFIG_NET_CAN)
+  IOBUSER_NET_CAN_READAHEAD,
+#endif
   IOBUSER_GLOBAL,
   IOBUSER_NENTRIES /* MUST BE LAST ENTRY */
 };
diff --git a/include/nuttx/wqueue.h b/include/nuttx/wqueue.h
index d353772..5ea8dfc 100644
--- a/include/nuttx/wqueue.h
+++ b/include/nuttx/wqueue.h
@@ -280,7 +280,8 @@ enum work_evtype_e
   WORK_TCP_DISCONNECT,   /* Notify loss of TCP connection */
   WORK_UDP_READAHEAD,    /* Notify that UDP read-ahead data is available */
   WORK_UDP_WRITEBUFFER,  /* Notify that UDP write buffer is empty */
-  WORK_NETLINK_RESPONSE  /* Notify that Netlink response is available */
+  WORK_NETLINK_RESPONSE, /* Notify thtat Netlink response is available */
+  WORK_CAN_READAHEAD     /* Notify that CAN read-ahead data is available */
 };
 
 /* This structure describes one notification and is provided as input to
diff --git a/include/sys/socket.h b/include/sys/socket.h
index e85242e..bc7cd26 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -202,6 +202,15 @@
                             * return: int
                             */
 
+                            
+/* The options are unsupported but included for compatibility
+ * and portability
+ */
+#define SO_TIMESTAMP    29
+#define SO_SNDBUFFORCE	32 
+#define SO_RCVBUFFORCE	33 
+#define SO_RXQ_OVFL     40
+
 /* Protocol-level socket operations. */
 
 #define SOL_IP          1 /* See options in include/netinet/ip.h */
@@ -212,6 +221,7 @@
 #define SOL_L2CAP       6 /* See options in include/netpacket/bluetooth.h */
 #define SOL_SCO         7 /* See options in include/netpacket/bluetooth.h */
 #define SOL_RFCOMM      8 /* See options in include/netpacket/bluetooth.h */
+#define SOL_CAN_RAW     9 /* See options in include/netpacket/can.h */
 
 /* Protocol-level socket options may begin with this value */
 
diff --git a/net/can/Kconfig b/net/can/Kconfig
index 2ae1f7b..2272db7 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -21,6 +21,25 @@ config CAN_CONNS
 	default 4
 	---help---
 		Maximum number of CAN connections (all tasks).
+		
+config NET_CAN_SOCK_OPTS
+	bool "sockopt support"
+	default n
+	select NET_CANPROTO_OPTIONS
+	---help---
+		Enable support for the CAN socket options
+		
+config NET_CAN_NOTIFIER
+	bool "Support CAN notifications"
+	default n
+	depends on SCHED_WORKQUEUE
+	select WQUEUE_NOTIFIER
+	---help---
+		Enable building of CAN notifier logic that will execute a worker
+		function on the low priority work queue when read-ahead data
+		is available or when a CAN connection is lost.  This is is a general
+		purpose notifier, but was developed specifically to support poll()
+		logic where the poll must wait for these events.
 
 endif # NET_CAN
 endmenu # CAN Socket Support
diff --git a/net/can/Make.defs b/net/can/Make.defs
index d078a05..3204b3b 100644
--- a/net/can/Make.defs
+++ b/net/can/Make.defs
@@ -28,6 +28,14 @@ SOCK_CSRCS += can_sockif.c
 SOCK_CSRCS += can_send.c
 SOCK_CSRCS += can_recvfrom.c
 
+ifeq ($(CONFIG_NET_CAN_NOTIFIER),y)
+SOCK_CSRCS += can_notifier.c
+endif
+
+ifeq ($(CONFIG_NET_CANPROTO_OPTIONS),y)
+SOCK_CSRCS += can_setsockopt.c can_getsockopt.c
+endif
+
 NET_CSRCS += can_conn.c
 NET_CSRCS += can_input.c
 NET_CSRCS += can_callback.c
diff --git a/net/can/can.h b/net/can/can.h
index c2b6857..46c7425 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -32,11 +32,16 @@
 
 #include <netpacket/can.h>
 #include <nuttx/semaphore.h>
+#include <nuttx/can.h>
 #include <nuttx/net/netdev.h>
 
 #include "devif/devif.h"
 #include "socket/socket.h"
 
+#ifdef CONFIG_NET_CAN_NOTIFIER
+#  include <nuttx/wqueue.h>
+#endif
+
 #ifdef CONFIG_NET_CAN
 
 /****************************************************************************
@@ -54,6 +59,16 @@
  * Public Type Definitions
  ****************************************************************************/
 
+/* This is a container that holds the poll-related information */
+
+struct can_poll_s
+{
+  FAR struct socket *psock;        /* Needed to handle loss of connection */
+  FAR struct net_driver_s *dev;    /* Needed to free the callback structure */
+  struct pollfd *fds;              /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
 /* This "connection" structure describes the underlying state of the socket. */
 
 struct can_conn_s
@@ -70,16 +85,26 @@ struct can_conn_s
   FAR struct devif_callback_s *list; /* NetLink callbacks */
 
   FAR struct net_driver_s *dev;      /* Reference to CAN device */
+  
+  /* Read-ahead buffering.
+   *
+   *   readahead - A singly linked list of type struct iob_qentry_s
+   *               where the CAN/IP read-ahead data is retained.
+   */
+
+  struct iob_queue_s readahead;   /* remove Read-ahead buffering */
 
   /* CAN-specific content follows */
 
   uint8_t protocol;                  /* Selected CAN protocol */
   int16_t crefs;                     /* Reference count */
+  
 
-  /* poll() support */
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
 
-  FAR sem_t *pollsem;                /* Used to wakeup poll() */
-  FAR pollevent_t *pollevent;        /* poll() wakeup event */
+  struct can_poll_s pollinfo[4]; //FIXME make dynamic
 };
 
 /****************************************************************************
@@ -166,6 +191,35 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
                       FAR struct can_conn_s *conn, uint16_t flags);
 
 /****************************************************************************
+ * Name: can_datahandler
+ *
+ * Description:
+ *   Handle data that is not accepted by the application.  This may be called
+ *   either (1) from the data receive logic if it cannot buffer the data, or
+ *   (2) from the CAN event logic is there is no listener in place ready to
+ *   receive the data.
+ *
+ * Input Parameters:
+ *   conn - A pointer to the CAN connection structure
+ *   buffer - A pointer to the buffer to be copied to the read-ahead
+ *     buffers
+ *   buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned Value:
+ *   The number of bytes actually buffered is returned.  This will be either
+ *   zero or equal to buflen; partial packets are not buffered.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ *   other handler available to process the incoming data.
+ * - Called from network stack logic with the network stack locked
+ *
+ ****************************************************************************/
+
+uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
+                         uint16_t buflen);
+
+/****************************************************************************
  * Name: can_recvfrom
  *
  * Description:
@@ -214,17 +268,6 @@ ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
 void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn);
 
 /****************************************************************************
- * Name: can_active()
- *
- * Description:
- *   Find a connection structure that is the appropriate connection for the
- *   provided NetLink address
- *
- ****************************************************************************/
-
-FAR struct can_conn_s *can_active(FAR struct sockaddr_can *addr);
-
-/****************************************************************************
  * Name: psock_can_send
  *
  * Description:
@@ -247,6 +290,31 @@ struct socket;
 ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
                        size_t len);
 
+/****************************************************************************
+ * Name: can_readahead_signal
+ *
+ * Description:
+ *   Read-ahead data has been buffered.  Signal all threads waiting for
+ *   read-ahead data to become available.
+ *
+ *   When read-ahead data becomes available, *all* of the workers waiting
+ *   for read-ahead data will be executed.  If there are multiple workers
+ *   waiting for read-ahead data then only the first to execute will get the
+ *   data.  Others will need to call can_readahead_notifier_setup() once
+ *   again.
+ *
+ * Input Parameters:
+ *   conn  - The CAN connection where read-ahead data was just buffered.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+void can_readahead_signal(FAR struct can_conn_s *conn);
+#endif
+
 
 #undef EXTERN
 #ifdef __cplusplus
diff --git a/net/can/can_callback.c b/net/can/can_callback.c
index 2fad951..6f3ae93 100644
--- a/net/can/can_callback.c
+++ b/net/can/can_callback.c
@@ -50,6 +50,61 @@
 #include "can/can.h"
 
 /****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_data_event
+ *
+ * Description:
+ *   Handle data that is not accepted by the application because there is no
+ *   listener in place ready to receive the data.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ *   other handler available to process the incoming data.
+ * - This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static inline uint16_t
+can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
+               uint16_t flags)
+{
+  uint16_t ret;
+  uint8_t *buffer = dev->d_appdata;
+  int      buflen = dev->d_len;
+  uint16_t recvlen;
+
+  ret = (flags & ~CAN_NEWDATA);
+
+  //ninfo("No listener on connection\n");
+
+   /* Save as the packet data as in the read-ahead buffer.  NOTE that
+    * partial packets will not be buffered.
+    */
+
+  recvlen = can_datahandler(conn, buffer, buflen);
+  if (recvlen < buflen)
+    {
+      /* There is no handler to receive new data and there are no free
+       * read-ahead buffers to retain the data -- drop the packet.
+       */
+
+      ninfo("Dropped %d bytes\n", dev->d_len);
+
+#ifdef CONFIG_NET_STATISTICS
+      //g_netstats.tcp.drop++;
+#endif
+    }
+        
+  /* In any event, the new data has now been handled */
+
+  dev->d_len = 0;
+  return ret;
+}
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
@@ -77,9 +132,97 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
       /* Perform the callback */
 
       flags = devif_conn_event(dev, conn, flags, conn->list);
-    }
+    
+    if ((flags & CAN_NEWDATA) != 0)
+      {
+        /* Data was not handled.. dispose of it appropriately */
 
+        flags = can_data_event(dev, conn, flags);
+      }
+  }
+  
   return flags;
 }
 
+/****************************************************************************
+ * Name: can_datahandler
+ *
+ * Description:
+ *   Handle data that is not accepted by the application.  This may be called
+ *   either (1) from the data receive logic if it cannot buffer the data, or
+ *   (2) from the CAN event logic is there is no listener in place ready to
+ *   receive the data.
+ *
+ * Input Parameters:
+ *   conn - A pointer to the CAN connection structure
+ *   buffer - A pointer to the buffer to be copied to the read-ahead
+ *     buffers
+ *   buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned Value:
+ *   The number of bytes actually buffered is returned.  This will be either
+ *   zero or equal to buflen; partial packets are not buffered.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ *   other handler available to process the incoming data.
+ * - This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
+                         uint16_t buflen)
+{
+  FAR struct iob_s *iob;
+  int ret;
+
+  /* Try to allocate on I/O buffer to start the chain without waiting (and
+   * throttling as necessary).  If we would have to wait, then drop the
+   * packet.
+   */
+
+  iob = iob_tryalloc(true, IOBUSER_NET_CAN_READAHEAD);
+  if (iob == NULL)
+    {
+      nerr("ERROR: Failed to create new I/O buffer chain\n");
+      return 0;
+    }
+
+  /* Copy the new appdata into the I/O buffer chain (without waiting) */
+
+  ret = iob_trycopyin(iob, buffer, buflen, 0, true,
+                      IOBUSER_NET_CAN_READAHEAD);
+  if (ret < 0)
+    {
+      /* On a failure, iob_copyin return a negated error value but does
+       * not free any I/O buffers.
+       */
+
+      nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
+      iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+      return 0;
+    }
+
+  /* Add the new I/O buffer chain to the tail of the read-ahead queue (again
+   * without waiting).
+   */
+
+  ret = iob_tryadd_queue(iob, &conn->readahead);
+  if (ret < 0)
+    {
+      nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
+      iob_free_chain(iob, IOBUSER_NET_TCP_READAHEAD);
+      return 0;
+    }
+    
+#ifdef CONFIG_NET_CAN_NOTIFIER
+  /* Provide notification(s) that additional CAN read-ahead data is
+   * available.
+   */
+
+  can_readahead_signal(conn);
+#endif
+  return buflen;
+}
+
 #endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_conn.c b/net/can/can_conn.c
index 77733b3..4969f6d 100644
--- a/net/can/can_conn.c
+++ b/net/can/can_conn.c
@@ -81,6 +81,7 @@ static void _can_semgive(FAR sem_t *sem)
 {
   nxsem_post(sem);
 }
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -201,25 +202,4 @@ FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn)
     }
 }
 
-/****************************************************************************
- * Name: can_active
- *
- * Description:
- *   Find a connection structure that is the appropriate connection for the
- *   provided NetLink address
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-FAR struct can_conn_s *can_active(FAR struct sockaddr_can *addr)
-{
-  /* This function is used to handle routing of incoming messages to sockets
-   * connected to the address.  There is no such use case for NetLink
-   * sockets.
-   */
-
-  return NULL;
-}
-
 #endif /* CONFIG_NET_CAN */
diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c
new file mode 100644
index 0000000..d9e19f8
--- /dev/null
+++ b/net/can/can_getsockopt.c
@@ -0,0 +1,154 @@
+/****************************************************************************
+ * net/can/can_setsockopt.c
+ *
+ *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/time.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <netpacket/can.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/can.h>
+
+#include "socket/socket.h"
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_getsockopt
+ *
+ * Description:
+ *   can_getsockopt() retrieves 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'.
+ *
+ *   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 netpacket/can.h for the case of the CAN 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.
+ *
+ ****************************************************************************/
+
+int can_getsockopt  (FAR struct socket *psock, int option,
+                   FAR void *value, FAR socklen_t *value_len)
+{
+
+  FAR struct can_conn_s *conn;
+  int ret;
+  int count = 0;
+
+  DEBUGASSERT(psock != NULL && value != NULL && value_len != NULL &&
+              psock->s_conn != NULL);
+  conn = (FAR struct can_conn_s *)psock->s_conn;
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      nerr("ERROR:  Not a RAW CAN socket\n");
+      return -ENOTCONN;
+    }
+
+
+  switch (option)
+    {
+      
+      case CAN_RAW_FILTER:
+        if (*value_len % sizeof(struct can_filter) != 0)
+        {
+		  ret = -EINVAL;
+        }
+        
+        if (value_len > CAN_RAW_FILTER_MAX * sizeof(struct can_filter))
+        {
+		  ret = -EINVAL;
+        }
+
+		count = *value_len / sizeof(struct can_filter);
+        
+        /* FIXME pass filter to driver */
+        break;
+      
+      case CAN_RAW_ERR_FILTER:
+        break;
+      
+      case CAN_RAW_LOOPBACK:
+        break;
+      
+      case CAN_RAW_RECV_OWN_MSGS:
+        break;
+      
+      case CAN_RAW_FD_FRAMES:
+        break;
+      
+      case CAN_RAW_JOIN_FILTERS:
+        break;
+
+      default:
+        nerr("ERROR: Unrecognized RAW CAN socket option: %d\n", option);
+        ret = -ENOPROTOOPT;
+        break;
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_NET_CANPROTO_OPTIONS */
diff --git a/net/can/can_callback.c b/net/can/can_notifier.c
similarity index 70%
copy from net/can/can_callback.c
copy to net/can/can_notifier.c
index 2fad951..ffb4878 100644
--- a/net/can/can_callback.c
+++ b/net/can/can_notifier.c
@@ -1,7 +1,7 @@
 /****************************************************************************
- * net/pkt/pkt_callback.c
+ * net/can/can_notifier.c
  *
- *   Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,48 +38,46 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
 
-#include <stdint.h>
-#include <debug.h>
+#include <sys/types.h>
+#include <assert.h>
 
-#include <nuttx/net/netconfig.h>
-#include <nuttx/net/netdev.h>
+#include <nuttx/wqueue.h>
 
-#include "devif/devif.h"
 #include "can/can.h"
 
+#ifdef CONFIG_NET_CAN_NOTIFIER
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: can_callback
+ * Name: can_readahead_signal
  *
  * Description:
- *   Inform the application holding the packet socket of a change in state.
+ *   Read-ahead data has been buffered.  Signal all threads waiting for
+ *   read-ahead data to become available.
  *
- * Returned Value:
- *   OK if packet has been processed, otherwise ERROR.
+ *   When read-ahead data becomes available, *all* of the workers waiting
+ *   for read-ahead data will be executed.  If there are multiple workers
+ *   waiting for read-ahead data then only the first to execute will get the
+ *   data.  Others will need to call can_readahead_notifier_setup() once
+ *   again.
+ *
+ * Input Parameters:
+ *   conn  - The CAN connection where read-ahead data was just buffered.
  *
- * Assumptions:
- *   This function is called with the network locked.
+ * Returned Value:
+ *   None.
  *
  ****************************************************************************/
 
-uint16_t can_callback(FAR struct net_driver_s *dev,
-                      FAR struct can_conn_s *conn, uint16_t flags)
+void can_readahead_signal(FAR struct can_conn_s *conn)
 {
-  /* Some sanity checking */
-
-  if (conn)
-    {
-      /* Perform the callback */
-
-      flags = devif_conn_event(dev, conn, flags, conn->list);
-    }
+  /* This is just a simple wrapper around work_notifier_signal(). */
 
-  return flags;
+  work_notifier_signal(WORK_CAN_READAHEAD, conn);
 }
 
-#endif /* CONFIG_NET && CONFIG_NET_CAN */
+#endif /* CONFIG_NET_TCP_NOTIFIER */
diff --git a/net/can/can_poll.c b/net/can/can_poll.c
index 84aeeab..80e59a2 100644
--- a/net/can/can_poll.c
+++ b/net/can/can_poll.c
@@ -88,13 +88,13 @@ void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn)
       dev->d_sndlen  = 0;
 
       /* Perform the application callback */
-
       can_callback(dev, conn, CAN_POLL);
 
       /* Check if the application has data to send */
 
       if (dev->d_sndlen > 0)
         {
+            //FIXME missing logic
           return;
         }
     }
diff --git a/net/can/can_recvfrom.c b/net/can/can_recvfrom.c
index 4062ed3..990786d 100644
--- a/net/can/can_recvfrom.c
+++ b/net/can/can_recvfrom.c
@@ -68,6 +68,7 @@
 
 struct can_recvfrom_s
 {
+  FAR struct socket       *pr_sock;      /* The parent socket structure */
   FAR struct devif_callback_s *pr_cb;  /* Reference to callback instance */
   sem_t        pr_sem;                 /* Semaphore signals recv completion */
   size_t       pr_buflen;              /* Length of receive buffer */
@@ -128,7 +129,7 @@ static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate,
  *
  ****************************************************************************/
 
-static void can_recvfrom_newdata(FAR struct net_driver_s *dev,
+static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev,
                                  FAR struct can_recvfrom_s *pstate)
 {
   size_t recvlen;
@@ -150,6 +151,150 @@ static void can_recvfrom_newdata(FAR struct net_driver_s *dev,
   /* Update the accumulated size of the data read */
 
   can_add_recvlen(pstate, recvlen);
+
+  return recvlen;
+}
+
+
+/****************************************************************************
+ * Name: can_newdata
+ *
+ * Description:
+ *   Copy the read data from the packet
+ *
+ * Input Parameters:
+ *   dev      The structure of the network driver that generated the event
+ *   pstate   recvfrom state structure
+ *
+ * Returned Value:
+ *   None.
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static inline void can_newdata(FAR struct net_driver_s *dev,
+                               FAR struct can_recvfrom_s *pstate)
+{
+  /* Take as much data from the packet as we can */
+
+  size_t recvlen = can_recvfrom_newdata(dev, pstate);
+
+  /* If there is more data left in the packet that we could not buffer, then
+   * add it to the read-ahead buffers.
+   */
+
+  if (recvlen < dev->d_len)
+    {
+      FAR struct can_conn_s *conn = (FAR struct can_conn_s *)pstate->pr_sock->s_conn;
+      FAR uint8_t *buffer = (FAR uint8_t *)dev->d_appdata + recvlen;
+      uint16_t buflen = dev->d_len - recvlen;
+#ifdef CONFIG_DEBUG_NET
+      uint16_t nsaved;
+
+      nsaved = can_datahandler(conn, buffer, buflen);
+#else
+      can_datahandler(conn, buffer, buflen);
+#endif
+
+      /* There are complicated buffering issues that are not addressed fully
+       * here.  For example, what if up_datahandler() cannot buffer the
+       * remainder of the packet?  In that case, the data will be dropped but
+       * still ACKed.  Therefore it would not be resent.
+       *
+       * This is probably not an issue here because we only get here if the
+       * read-ahead buffers are empty and there would have to be something
+       * serioulsy wrong with the configuration not to be able to buffer a
+       * partial packet in this context.
+       */
+
+#ifdef CONFIG_DEBUG_NET
+      if (nsaved < buflen)
+        {
+          nerr("ERROR: packet data not saved (%d bytes)\n", buflen - nsaved);
+        }
+#endif
+    }
+
+  /* Indicate no data in the buffer */
+
+  dev->d_len = 0;
+}
+
+/****************************************************************************
+ * Name: can_readahead
+ *
+ * Description:
+ *   Copy the read-ahead data from the packet
+ *
+ * Input Parameters:
+ *   pstate   recvfrom state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static inline int can_readahead(struct can_recvfrom_s *pstate)
+{
+  FAR struct can_conn_s *conn = (FAR struct can_conn_s *)pstate->pr_sock->s_conn;
+  FAR struct iob_s *iob;
+  int recvlen;
+
+  /* Check there is any CAN data already buffered in a read-ahead
+   * buffer.
+   */
+
+  if((iob = iob_peek_queue(&conn->readahead)) != NULL &&
+          pstate->pr_buflen > 0)
+    {
+      DEBUGASSERT(iob->io_pktlen > 0);
+
+      /* Transfer that buffered data from the I/O buffer chain into
+       * the user buffer.
+       */
+
+      recvlen = iob_copyout(pstate->pr_buffer, iob, pstate->pr_buflen, 0);
+
+      /* If we took all of the data from the I/O buffer chain is empty, then
+       * release it.  If there is still data available in the I/O buffer
+       * chain, then just trim the data that we have taken from the
+       * beginning of the I/O buffer chain.
+       */
+
+      if (recvlen >= iob->io_pktlen)
+        {
+          FAR struct iob_s *tmp;
+
+          /* Remove the I/O buffer chain from the head of the read-ahead
+           * buffer queue.
+           */
+
+          tmp = iob_remove_queue(&conn->readahead);
+          DEBUGASSERT(tmp == iob);
+          UNUSED(tmp);
+
+          /* And free the I/O buffer chain */
+
+          iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+        }
+      else
+        {
+          /* The bytes that we have received from the head of the I/O
+           * buffer chain (probably changing the head of the I/O
+           * buffer queue).
+           */
+
+          iob_trimhead_queue(&conn->readahead, recvlen,
+                             IOBUSER_NET_CAN_READAHEAD);
+        }
+        return recvlen;
+    }
+    return 0;
 }
 
 static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
@@ -170,7 +315,7 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
         {
           /* Copy the packet */
 
-          can_recvfrom_newdata(dev, pstate);
+          can_newdata(dev, pstate);
 
           /* We are finished. */
 
@@ -228,7 +373,7 @@ static ssize_t can_recvfrom_result(int result,
   if (pstate->pr_result < 0)
     {
       /* This might return EAGAIN on a timeout or ENOTCONN on loss of
-       * connection (TCP only)
+       * connection (CAN only)
        */
 
       return pstate->pr_result;
@@ -307,6 +452,19 @@ ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf,
 
   state.pr_buflen = len;
   state.pr_buffer = buf;
+  state.pr_sock   = psock;
+  
+  /* Handle any any CAN data already buffered in a read-ahead buffer.  NOTE
+   * that there may be read-ahead data to be retrieved even after the
+   * socket has been disconnected.
+   */
+  ret = can_readahead(&state);
+  if(ret > 0)
+  {
+      net_unlock();
+      nxsem_destroy(&state.pr_sem);
+      return ret;
+  }    
   
   /* Get the device driver that will service this transfer */
 
@@ -317,7 +475,7 @@ ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf,
       goto errout_with_state;
     }
     
-    /* Set up the callback in the connection */
+  /* Set up the callback in the connection */
 
   state.pr_cb = can_callback_alloc(dev, conn);
   if (state.pr_cb)
diff --git a/net/can/can_callback.c b/net/can/can_setsockopt.c
similarity index 51%
copy from net/can/can_callback.c
copy to net/can/can_setsockopt.c
index 2fad951..db4cb76 100644
--- a/net/can/can_callback.c
+++ b/net/can/can_setsockopt.c
@@ -1,7 +1,7 @@
 /****************************************************************************
- * net/pkt/pkt_callback.c
+ * net/can/can_setsockopt.c
  *
- *   Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2018, 2020 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,48 +38,110 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
 
+#include <sys/time.h>
 #include <stdint.h>
+#include <errno.h>
+#include <assert.h>
 #include <debug.h>
 
-#include <nuttx/net/netconfig.h>
-#include <nuttx/net/netdev.h>
+#include <netpacket/can.h>
 
-#include "devif/devif.h"
+#include <nuttx/net/net.h>
+#include <nuttx/net/can.h>
+
+#include "socket/socket.h"
+#include "utils/utils.h"
 #include "can/can.h"
 
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: can_callback
+ * Name: can_setsockopt
  *
  * Description:
- *   Inform the application holding the packet socket of a change in state.
+ *   can_setsockopt() sets the CAN-protocol option specified by the
+ *   'option' argument to the value pointed to by the 'value' argument for
+ *   the socket specified by the 'psock' argument.
  *
- * Returned Value:
- *   OK if packet has been processed, otherwise ERROR.
+ *   See <netinet/can.h> for the a complete list of values of CAN protocol
+ *   options.
  *
- * Assumptions:
- *   This function is called with the network locked.
+ * 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.
  *
  ****************************************************************************/
 
-uint16_t can_callback(FAR struct net_driver_s *dev,
-                      FAR struct can_conn_s *conn, uint16_t flags)
+int can_setsockopt(FAR struct socket *psock, int option,
+                   FAR const void *value, socklen_t value_len)
 {
-  /* Some sanity checking */
+    
+  FAR struct can_conn_s *conn;
+  int ret;
+  int count = 0;
+
+  DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL);
+  conn = (FAR struct can_conn_s *)psock->s_conn;
 
-  if (conn)
+  if (psock->s_type != SOCK_RAW)
     {
-      /* Perform the callback */
+      nerr("ERROR:  Not a RAW CAN socket\n");
+      return -ENOTCONN;
+    }
+
+
+  switch (option)
+    {
+      case CAN_RAW_FILTER:
+        if (value_len % sizeof(struct can_filter) != 0)
+        {
+		  ret = -EINVAL;
+        }
+        
+        if (value_len > CAN_RAW_FILTER_MAX * sizeof(struct can_filter))
+        {
+		  ret = -EINVAL;
+        }
+
+		count = value_len / sizeof(struct can_filter);
+        
+        /* FIXME pass filter to driver */
+        break;
+      
+      case CAN_RAW_ERR_FILTER:
+        break;
+      
+      case CAN_RAW_LOOPBACK:
+        break;
+      
+      case CAN_RAW_RECV_OWN_MSGS:
+        break;
+      
+      case CAN_RAW_FD_FRAMES:
+        break;
+      
+      case CAN_RAW_JOIN_FILTERS:
+        break;
 
-      flags = devif_conn_event(dev, conn, flags, conn->list);
+      default:
+        nerr("ERROR: Unrecognized CAN option: %d\n", option);
+        ret = -ENOPROTOOPT;
+        break;
     }
 
-  return flags;
+  return ret;
 }
 
-#endif /* CONFIG_NET && CONFIG_NET_CAN */
+#endif /* CONFIG_NET_CANPROTO_OPTIONS */
diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c
index 0cd389a..5c8415e 100644
--- a/net/can/can_sockif.c
+++ b/net/can/can_sockif.c
@@ -86,7 +86,7 @@ const struct sock_intf_s g_can_sockif =
   can_listen,       /* si_listen */
   can_connect,      /* si_connect */
   can_accept,       /* si_accept */
-  can_poll_local,         /* si_poll */
+  can_poll_local,   /* si_poll */
   can_send,         /* si_send */
   can_sendto,       /* si_sendto */
 #ifdef CONFIG_NET_SENDFILE
@@ -102,6 +102,73 @@ const struct sock_intf_s g_can_sockif =
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: can_poll_eventhandler
+ *
+ * Description:
+ *   This function is called to perform the actual CAN receive operation
+ *   via the device interface layer.
+ *
+ * Input Parameters:
+ *   dev      The structure of the network driver that caused the event
+ *   conn     The connection structure associated with the socket
+ *   flags    Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static uint16_t can_poll_eventhandler(FAR struct net_driver_s *dev,
+                                      FAR void *conn,
+                                      FAR void *pvpriv, uint16_t flags)
+{
+  FAR struct can_poll_s *info = (FAR struct can_poll_s *)pvpriv;
+
+  DEBUGASSERT(!info || (info->psock && info->fds));
+
+  /* 'priv' might be null in some race conditions (?) */
+
+  if (info)
+    {
+      pollevent_t eventset = 0;
+
+      /* Check for data or connection availability events. */
+
+      if ((flags & CAN_NEWDATA) != 0)
+        {
+          eventset |= (POLLIN & info->fds->events);
+        }
+
+      /* Check for loss of connection events. */
+
+      if ((flags & NETDEV_DOWN) != 0)
+        {
+          eventset |= (POLLHUP | POLLERR);
+        }
+
+      /* A poll is a sign that we are free to send data. */
+
+     /* else if ((flags & CAN_POLL) != 0 && psock_udp_cansend(info->psock) >= 0)
+        {
+          eventset |= (POLLOUT & info->fds->events);
+        }*/
+
+      /* Awaken the caller of poll() is requested event occurred. */
+
+      if (eventset)
+        {
+          info->fds->revents |= eventset;
+          nxsem_post(info->fds->sem);
+        }
+    }
+
+  return flags;
+}
+
+/****************************************************************************
  * Name: can_setup
  *
  * Description:
@@ -506,100 +573,109 @@ static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
                         bool setup)
 {
   FAR struct can_conn_s *conn;
-  int ret;
+  FAR struct can_poll_s *info;
+  FAR struct devif_callback_s *cb;
+  int ret = OK;
 
   DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
   conn = (FAR struct can_conn_s *)psock->s_conn;
+  info = conn->pollinfo;
+  
+  //FIXME add NETDEV_DOWN support
 
   /* Check if we are setting up or tearing down the poll */
 
   if (setup)
     {
-      /* If POLLOUT is selected, return immediately (maybe) */
-
-      pollevent_t revents = POLLOUT;
-
-      /* If POLLIN is selected and a response is available, return
-       * immediately if POLLIN and/or POLLIN are included in the
-       * requested event set.
-       */
-
+        
       net_lock();
-
-#warning Missing logic
-
-      revents &= fds->events;
-      if (revents != 0)
+      
+      info->dev = conn->dev;
+      
+      cb = can_callback_alloc(info->dev, conn);
+      if (cb == NULL)
         {
-          fds->revents = revents;
-          nxsem_post(fds->sem);
-          net_unlock();
-          return OK;
+          ret = -EBUSY;
+          goto errout_with_lock;
         }
 
-      /* Set up to be notified when a response is available if POLLIN is
-       * requested.
+      /* Initialize the poll info container */
+    
+      info->psock  = psock;
+      info->fds    = fds;
+      info->cb     = cb;
+    
+      /* Initialize the callback structure.  Save the reference to the info
+       * structure as callback private data so that it will be available during
+       * callback processing.
        */
-
+    
+      cb->flags    = NETDEV_DOWN;
+      cb->priv     = (FAR void *)info;
+      cb->event    = can_poll_eventhandler;
+    
+      if ((fds->events & POLLOUT) != 0)
+        {
+          cb->flags |= CAN_POLL;
+        }
+    
       if ((fds->events & POLLIN) != 0)
         {
-          /* Some limitations:  There can be only a single outstanding POLLIN
-           * on the CAN connection.
-           */
-
-          if (conn->pollsem != NULL || conn->pollevent != NULL)
-            {
-              nerr("ERROR: Multiple polls() on socket not supported.\n");
-              net_unlock();
-              return -EBUSY;
-            }
-
-          /* Set up the notification */
-
-          conn->pollsem    = fds->sem;
-          conn->pollevent  = &fds->revents;
-
-#warning Missing logic
-
-          if (ret < 0)
-            {
-              /* Failed to set up notification */
-
-              conn->pollsem   = NULL;
-              conn->pollevent = NULL;
-            }
-          else
-            {
-              /* Setup to receive a notification when CAN data is available */
-
-#warning Missing logic
-
-              ret = OK;
-            }
+          cb->flags |= CAN_NEWDATA;
         }
-
-      /* Set up to be notified when we are able to send CAN data without
-       * waiting.
+    
+      /* Save the reference in the poll info structure as fds private as well
+       * for use during poll teardown as well.
        */
-
-      else if ((fds->events & POLLOUT) != 0)
+    
+      fds->priv = (FAR void *)info;
+    
+      /* Check for read data availability now */
+    
+      if (!IOB_QEMPTY(&conn->readahead))
         {
+          /* Normal data may be read without blocking. */
+    
+          fds->revents |= (POLLRDNORM & fds->events);
         }
-      else
+    
+    #if 0
+      if (psock_udp_cansend(psock) >= 0)
         {
-          /* There will not be any wakeups coming?  Probably an error? */
-
-          ret = OK;
+          /* Normal data may be sent without blocking (at least one byte). */
+    
+          fds->revents |= (POLLWRNORM & fds->events);
         }
-
+    #endif
+    
+      /* Check if any requested events are already in effect */
+    
+      if (fds->revents != 0)
+        {
+          /* Yes.. then signal the poll logic */
+          nxsem_post(fds->sem);
+        }
+    
+errout_with_lock:
       net_unlock();
     }
-  else
+  else 
     {
-      /* Cancel any response notifications */
+      info = (FAR struct can_poll_s *)fds->priv;
+        
+      if (info != NULL)
+      {
+        /* Cancel any response notifications */      
+        can_callback_free(info->dev, conn, info->cb);
+
+        /* Release the poll/select data slot */
+
+        info->fds->priv = NULL;
+
+        /* Then free the poll info container */
 
-      conn->pollsem   = NULL;
-      conn->pollevent = NULL;
+        info->psock = NULL;
+      }
     }
 
   return ret;
diff --git a/net/socket/Kconfig b/net/socket/Kconfig
index c627ea5..8b71ade 100644
--- a/net/socket/Kconfig
+++ b/net/socket/Kconfig
@@ -37,6 +37,12 @@ config NET_UDPPROTO_OPTIONS
 	---help---
 		Enable or disable support for UDP protocol level socket options.
 
+config NET_CANPROTO_OPTIONS
+	bool
+	default n
+	---help---
+		Enable or disable support for CAN protocol level socket option
+
 if NET_SOCKOPTS
 
 config NET_SOLINGER
diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c
index e7474ad..bc07a03 100644
--- a/net/socket/getsockopt.c
+++ b/net/socket/getsockopt.c
@@ -371,6 +371,12 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
        break;
 #endif
 
+      case SOL_CAN_RAW:
+#ifdef CONFIG_NET_TCPPROTO_OPTIONS
+       ret = can_getsockopt(psock, option, value, value_len);
+#endif
+       break;
+       
       /* These levels are defined in sys/socket.h, but are not yet
        * implemented.
        */