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

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

commit fd3389dec1855e9a6cf45c9417e6c9dfb9ca0dd1
Author: p-szafonimateusz <[email protected]>
AuthorDate: Mon Nov 9 11:51:12 2026 +0100

    net/can: Add match and input hooks to CAN connections.
    
    Add match() and input() hooks to struct can_conn_s, so that can_input()
    does not depend on CAN_RAW and other CAN protocols can be added next
    to it:
    
    - can_active() becomes the static can_conn_active() in can.c.  It
      keeps the checks shared by all protocols (bound device, own
      messages) and calls conn->match() for the rest.
    - can_input_conn() calls conn->input() instead of can_callback().
    - The CAN_RAW receive filters and error mask move from struct
      can_conn_s to the new struct can_raw_conn_s in can_raw.c, together
      with can_recv_filter().  can_raw_match() applies the filters and the
      CAN FD check that were in can_active(), and can_raw_input() calls
      can_callback().
    
    No functional change.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: p-szafonimateusz <[email protected]>
---
 Documentation/os/networking/socketcan.rst |   7 +-
 net/can/can.c                             | 178 +++++++++---------------------
 net/can/can.h                             |  40 +++----
 net/can/can_raw.c                         | 174 ++++++++++++++++++++++++++---
 4 files changed, 230 insertions(+), 169 deletions(-)

diff --git a/Documentation/os/networking/socketcan.rst 
b/Documentation/os/networking/socketcan.rst
index 1ac2ce27732..2e9c03d056b 100644
--- a/Documentation/os/networking/socketcan.rst
+++ b/Documentation/os/networking/socketcan.rst
@@ -92,9 +92,10 @@ Files supporting SocketCAN can be found in the following 
locations:
 -  **Header File**: ``include/nuttx/net/can.h``
 -  **Main Modules**:
 
-   - ``can.c`` - Connection management, input, callbacks and polling
-   - ``can_raw.c`` - Socket interface, message transmission (with and without
-     buffering) and reception
+   - ``can.c`` - Protocol-independent core: connection management, input,
+     callbacks and polling
+   - ``can_raw.c`` - CAN_RAW protocol: socket interface, transmission (with
+     and without buffering), reception, filters and socket options
    - ``can_sockif.c`` - Selection of the socket interface of a CAN protocol
 
 Configuration Options
diff --git a/net/can/can.c b/net/can/can.c
index 068f06db748..5b074ceef18 100644
--- a/net/can/can.c
+++ b/net/can/can.c
@@ -212,6 +212,55 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct 
can_conn_s *conn,
   return ret;
 }
 
+/****************************************************************************
+ * Name: can_conn_active
+ *
+ * Description:
+ *   Traverse the list of NetLink connections that match dev
+ *
+ * Input Parameters:
+ *   dev  - The device to search for.
+ *   conn - The current connection; may be NULL to start the search at the
+ *          beginning
+ *
+ * Assumptions:
+ *   This function is called from NetLink device logic.
+ *
+ ****************************************************************************/
+
+static FAR struct can_conn_s *
+can_conn_active(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn)
+{
+  can_conn_list_lock();
+  while ((conn = can_conn_next(conn)) != NULL)
+    {
+      if ((conn->dev == NULL && _SS_ISBOUND(conn->sconn.s_flags)) ||
+          conn->dev == dev)
+        {
+          if (dev->d_iob->io_conn == &conn->sconn
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+              && !_SO_GETOPT(conn->sconn.s_options, CAN_RAW_RECV_OWN_MSGS)
+#endif
+             )
+            {
+              continue; /* Skip own messages */
+            }
+
+          /* Let the protocol decide if it accepts the frame */
+
+          if (!conn->match(conn, dev))
+            {
+              continue;
+            }
+
+          break;
+        }
+    }
+
+  can_conn_list_unlock();
+  return conn;
+}
+
 /****************************************************************************
  * Name: can_input_conn
  *
@@ -248,7 +297,7 @@ static int can_input_conn(FAR struct net_driver_s *dev,
 
   /* Perform the application callback */
 
-  flags = can_callback(dev, conn, CAN_NEWDATA);
+  flags = conn->input(conn, dev);
 
   /* If the operation was successful, the CAN_NEWDATA flag is removed
    * and thus the packet can be deleted (OK will be returned).
@@ -291,7 +340,7 @@ static int can_input_conn(FAR struct net_driver_s *dev,
 
 static int can_in(FAR struct net_driver_s *dev)
 {
-  FAR struct can_conn_s *conn = can_active(dev, NULL);
+  FAR struct can_conn_s *conn = can_conn_active(dev, NULL);
   FAR struct can_conn_s *nextconn;
   int ret;
 
@@ -317,7 +366,7 @@ static int can_in(FAR struct net_driver_s *dev)
 
   /* Do we have second connection that can hold this packet? */
 
-  while ((nextconn = can_active(dev, conn)) != NULL)
+  while ((nextconn = can_conn_active(dev, conn)) != NULL)
     {
       /* Yes... There are multiple listeners on the same dev.
        * We need to clone the packet and deliver it to each listener.
@@ -611,7 +660,8 @@ void can_readahead_signal(FAR struct can_conn_s *conn)
  *
  * Description:
  *   Initialize the state shared by all CAN protocols in a newly allocated
- *   connection and add it to the list of active connections.
+ *   connection and add it to the list of active connections.  The caller
+ *   sets the match() and input() hooks first.
  *
  * Input Parameters:
  *   conn - The connection to initialize
@@ -697,59 +747,6 @@ void can_conn_uninit(FAR struct can_conn_s *conn)
   can_conn_list_unlock();
 }
 
-/****************************************************************************
- * Name: can_recv_filter
- *
- * Description:
- *   filter incoming packet
- *
- * Input Parameters:
- *   conn - A pointer to the CAN connection structure
- *   id   - The CAN identifier
- *
- * Returned Value: 0 - Filter not passed, 1 - Filter passed
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_CANPROTO_OPTIONS
-static int can_recv_filter(FAR struct can_conn_s *conn, canid_t id)
-{
-  uint32_t i;
-
-#ifdef CONFIG_NET_CAN_ERRORS
-  /* error message frame */
-
-  if ((id & CAN_ERR_FLAG) != 0)
-    {
-      return id & conn->err_mask ? 1 : 0;
-    }
-#endif
-
-  for (i = 0; i < conn->filter_count; i++)
-    {
-      if (conn->filters[i].can_id & CAN_INV_FILTER)
-        {
-          if ((id & conn->filters[i].can_mask) !=
-                ((conn->filters[i].can_id & ~CAN_INV_FILTER) &
-                 conn->filters[i].can_mask))
-            {
-              return 1;
-            }
-        }
-      else
-        {
-          if ((id & conn->filters[i].can_mask) ==
-                (conn->filters[i].can_id & conn->filters[i].can_mask))
-            {
-              return 1;
-            }
-        }
-    }
-
-  return 0;
-}
-#endif
-
 /****************************************************************************
  * Name: can_conn_next
  *
@@ -796,73 +793,6 @@ void can_conn_list_unlock(void)
   nxrmutex_unlock(&g_can_conn_lock);
 }
 
-/****************************************************************************
- * Name: can_active()
- *
- * Description:
- *   Traverse the list of NetLink connections that match dev
- *
- * Input Parameters:
- *   dev  - The device to search for.
- *   conn - The current connection; may be NULL to start the search at the
- *          beginning
- *
- * Assumptions:
- *   This function is called from NetLink device logic.
- *
- ****************************************************************************/
-
-FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev,
-                                  FAR struct can_conn_s *conn)
-{
-#ifdef CONFIG_NET_CANPROTO_OPTIONS
-  canid_t can_id;
-
-  memcpy(&can_id, NETLLBUF, sizeof(canid_t));
-#endif
-
-  can_conn_list_lock();
-  while ((conn = can_conn_next(conn)) != NULL)
-    {
-      if ((conn->dev == NULL && _SS_ISBOUND(conn->sconn.s_flags)) ||
-          conn->dev == dev)
-        {
-          if (dev->d_iob->io_conn == &conn->sconn
-#ifdef CONFIG_NET_CANPROTO_OPTIONS
-              && !_SO_GETOPT(conn->sconn.s_options, CAN_RAW_RECV_OWN_MSGS)
-#endif
-             )
-            {
-              continue; /* Skip own messages */
-            }
-
-#ifdef CONFIG_NET_CANPROTO_OPTIONS
-          if (can_recv_filter(conn, can_id) == 0)
-            {
-              continue;
-            }
-#endif
-
-          /* Do not pass CAN FD frames to a classic CAN socket */
-
-#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
-          if (!_SO_GETOPT(conn->sconn.s_options, CAN_RAW_FD_FRAMES))
-#endif
-            {
-              if (dev->d_len > sizeof(struct can_frame))
-                {
-                  continue;
-                }
-            }
-
-          break;
-        }
-    }
-
-  can_conn_list_unlock();
-  return conn;
-}
-
 /****************************************************************************
  * Name: can_get_ifindex
  *
diff --git a/net/can/can.h b/net/can/can.h
index 45a4f63b3fd..7acf39947da 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -126,13 +126,17 @@ struct can_conn_s
 
   struct can_poll_s pollinfo[CONFIG_NET_CAN_NPOLLWAITERS];
 
-#ifdef CONFIG_NET_CANPROTO_OPTIONS
-  struct can_filter filters[CONFIG_NET_CAN_RAW_FILTER_MAX];
-  int32_t filter_count;
-#  ifdef CONFIG_NET_CAN_ERRORS
-  can_err_mask_t err_mask;
-#  endif
-#endif
+  /* Protocol hooks used by can_input():
+   *
+   *   match - Return true if the received frame in dev is for conn.
+   *   input - Deliver the received frame in dev to conn and return the
+   *           remaining event flags.
+   */
+
+  CODE bool (*match)(FAR struct can_conn_s *conn,
+                     FAR struct net_driver_s *dev);
+  CODE uint32_t (*input)(FAR struct can_conn_s *conn,
+                         FAR struct net_driver_s *dev);
 };
 
 /****************************************************************************
@@ -166,7 +170,8 @@ can_sockif(sa_family_t family, int type, int protocol);
  *
  * Description:
  *   Initialize the state shared by all CAN protocols in a newly allocated
- *   connection and add it to the list of active connections.
+ *   connection and add it to the list of active connections.  The caller
+ *   sets the match() and input() hooks first.
  *
  ****************************************************************************/
 
@@ -236,25 +241,6 @@ FAR struct can_conn_s *can_conn_next(FAR struct can_conn_s 
*conn);
 void can_conn_list_lock(void);
 void can_conn_list_unlock(void);
 
-/****************************************************************************
- * Name: can_active()
- *
- * Description:
- *   Traverse the list of NetLink connections that match dev
- *
- * Input Parameters:
- *   dev  - The device to search for.
- *   conn - The current connection; may be NULL to start the search at the
- *          beginning
- *
- * Assumptions:
- *   This function is called from NetLink device logic.
- *
- ****************************************************************************/
-
-FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev,
-                                  FAR struct can_conn_s *conn);
-
 /****************************************************************************
  * Name: can_callback
  *
diff --git a/net/can/can_raw.c b/net/can/can_raw.c
index dacfa507d40..de67e49f6c9 100644
--- a/net/can/can_raw.c
+++ b/net/can/can_raw.c
@@ -75,6 +75,23 @@
  * Private Types
  ****************************************************************************/
 
+/* CAN_RAW connection: the state shared by all CAN protocols followed by
+ * the CAN_RAW receive filters.
+ */
+
+struct can_raw_conn_s
+{
+  struct can_conn_s conn;            /* Common CAN state, must be first */
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+  struct can_filter filters[CONFIG_NET_CAN_RAW_FILTER_MAX];
+  int32_t filter_count;
+#  ifdef CONFIG_NET_CAN_ERRORS
+  can_err_mask_t err_mask;
+#  endif
+#endif
+};
+
 #ifndef CONFIG_NET_CAN_WRITE_BUFFERS
 /* This structure holds the state of the send operation until it can be
  * operated upon by the event handler.
@@ -137,7 +154,7 @@ static int can_raw_setsockopt(FAR struct socket *psock, int 
level,
 
 /* The array containing all CAN_RAW connections. */
 
-NET_BUFPOOL_DECLARE(g_can_raw_connections, sizeof(struct can_conn_s),
+NET_BUFPOOL_DECLARE(g_can_raw_connections, sizeof(struct can_raw_conn_s),
                     CONFIG_NET_CAN_PREALLOC_CONNS,
                     CONFIG_NET_CAN_ALLOC_CONNS,
                     CONFIG_NET_CAN_MAX_CONNS);
@@ -174,6 +191,127 @@ const struct sock_intf_s g_can_raw_sockif =
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: can_recv_filter
+ *
+ * Description:
+ *   filter incoming packet
+ *
+ * Input Parameters:
+ *   raw  - A pointer to the CAN_RAW connection structure
+ *   id   - The CAN identifier
+ *
+ * Returned Value: 0 - Filter not passed, 1 - Filter passed
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+static int can_recv_filter(FAR struct can_raw_conn_s *raw, canid_t id)
+{
+  uint32_t i;
+
+#ifdef CONFIG_NET_CAN_ERRORS
+  /* error message frame */
+
+  if ((id & CAN_ERR_FLAG) != 0)
+    {
+      return id & raw->err_mask ? 1 : 0;
+    }
+#endif
+
+  for (i = 0; i < raw->filter_count; i++)
+    {
+      if (raw->filters[i].can_id & CAN_INV_FILTER)
+        {
+          if ((id & raw->filters[i].can_mask) !=
+                ((raw->filters[i].can_id & ~CAN_INV_FILTER) &
+                 raw->filters[i].can_mask))
+            {
+              return 1;
+            }
+        }
+      else
+        {
+          if ((id & raw->filters[i].can_mask) ==
+                (raw->filters[i].can_id & raw->filters[i].can_mask))
+            {
+              return 1;
+            }
+        }
+    }
+
+  return 0;
+}
+#endif
+
+/****************************************************************************
+ * Name: can_raw_match
+ *
+ * Description:
+ *   conn->match() hook of CAN_RAW connections: apply the receive filters
+ *   and do not pass CAN FD frames to a classic CAN socket.
+ *
+ * Input Parameters:
+ *   conn - The CAN_RAW connection
+ *   dev  - The device holding the received frame
+ *
+ * Returned Value:
+ *   true if the frame is delivered to conn.
+ *
+ ****************************************************************************/
+
+static bool can_raw_match(FAR struct can_conn_s *conn,
+                          FAR struct net_driver_s *dev)
+{
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+  FAR struct can_raw_conn_s *raw = (FAR struct can_raw_conn_s *)conn;
+  canid_t can_id;
+
+  memcpy(&can_id, NETLLBUF, sizeof(canid_t));
+
+  if (can_recv_filter(raw, can_id) == 0)
+    {
+      return false;
+    }
+#endif
+
+  /* Do not pass CAN FD frames to a classic CAN socket */
+
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+  if (!_SO_GETOPT(conn->sconn.s_options, CAN_RAW_FD_FRAMES))
+#endif
+    {
+      if (dev->d_len > sizeof(struct can_frame))
+        {
+          return false;
+        }
+    }
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: can_raw_input
+ *
+ * Description:
+ *   conn->input() hook of CAN_RAW connections: deliver the frame to the
+ *   socket callbacks.
+ *
+ * Input Parameters:
+ *   conn - The CAN_RAW connection
+ *   dev  - The device holding the received frame
+ *
+ * Returned Value:
+ *   The flags returned by can_callback().
+ *
+ ****************************************************************************/
+
+static uint32_t can_raw_input(FAR struct can_conn_s *conn,
+                              FAR struct net_driver_s *dev)
+{
+  return can_callback(dev, conn, CAN_NEWDATA);
+}
+
 /****************************************************************************
  * Name: can_raw_alloc()
  *
@@ -185,14 +323,14 @@ const struct sock_intf_s g_can_raw_sockif =
 
 static FAR struct can_conn_s *can_raw_alloc(void)
 {
-  FAR struct can_conn_s *conn;
+  FAR struct can_raw_conn_s *raw;
 
   /* The free list is protected by a a mutex. */
 
   NET_BUFPOOL_LOCK(g_can_raw_connections);
 
-  conn = NET_BUFPOOL_TRYALLOC(g_can_raw_connections);
-  if (conn != NULL)
+  raw = NET_BUFPOOL_TRYALLOC(g_can_raw_connections);
+  if (raw != NULL)
     {
       /* FIXME SocketCAN default behavior enables loopback */
 
@@ -203,24 +341,26 @@ static FAR struct can_conn_s *can_raw_alloc(void)
        * struct can_filter_t catchall_filter;
        * filter.can_id = 0;
        * filter.can_mask = 0;
-       * conn->filters[0] = catchall_filter;
+       * raw->filters[0] = catchall_filter;
        *
        * However memset already sets the filter to 0
        * therefore we only have to set the filter count to 1
        */
 
-      conn->filter_count = 1;
+      raw->filter_count = 1;
 #endif
 
       /* Initialize the shared state and enqueue the connection into the
        * active list
        */
 
-      can_conn_init(conn);
+      raw->conn.match = can_raw_match;
+      raw->conn.input = can_raw_input;
+      can_conn_init(&raw->conn);
     }
 
   NET_BUFPOOL_UNLOCK(g_can_raw_connections);
-  return conn;
+  return raw != NULL ? &raw->conn : NULL;
 }
 
 /****************************************************************************
@@ -1496,11 +1636,13 @@ static int can_raw_getsockopt(FAR struct socket *psock, 
int level,
                               int option, FAR void *value,
                               FAR socklen_t *value_len)
 {
+  FAR struct can_raw_conn_s *raw;
   FAR struct can_conn_s *conn;
   int ret = OK;
 
   DEBUGASSERT(value != NULL && value_len != NULL);
   conn = psock->s_conn;
+  raw  = (FAR struct can_raw_conn_s *)conn;
 
   /* SO_RCVBUF and SO_SNDBUF are socket-level options that are kept in
    * the CAN connection; psock_socketlevel_option() handles the others.
@@ -1538,7 +1680,7 @@ static int can_raw_getsockopt(FAR struct socket *psock, 
int level,
           }
         else
           {
-            int count = conn->filter_count;
+            int count = raw->filter_count;
             int i;
 
             if (*value_len < count * sizeof(struct can_filter))
@@ -1552,7 +1694,7 @@ static int can_raw_getsockopt(FAR struct socket *psock, 
int level,
 
             for (i = 0; i < count; i++)
               {
-                ((FAR struct can_filter *)value)[i] = conn->filters[i];
+                ((FAR struct can_filter *)value)[i] = raw->filters[i];
               }
           }
         break;
@@ -1567,7 +1709,7 @@ static int can_raw_getsockopt(FAR struct socket *psock, 
int level,
           {
             FAR can_err_mask_t *mask = (FAR can_err_mask_t *)value;
 
-            *mask = conn->err_mask;
+            *mask = raw->err_mask;
             *value_len = sizeof(can_err_mask_t);
           }
         break;
@@ -1669,6 +1811,7 @@ static int can_raw_setsockopt(FAR struct socket *psock, 
int level,
                               int option, FAR const void *value,
                               socklen_t value_len)
 {
+  FAR struct can_raw_conn_s *raw;
   FAR struct can_conn_s *conn;
   int ret = OK;
   int count = 0;
@@ -1676,6 +1819,7 @@ static int can_raw_setsockopt(FAR struct socket *psock, 
int level,
   DEBUGASSERT(value_len == 0 || value != NULL);
 
   conn = psock->s_conn;
+  raw  = (FAR struct can_raw_conn_s *)conn;
 
   /* SO_RCVBUF and SO_SNDBUF are socket-level options that are kept in
    * the CAN connection; psock_socketlevel_option() handles the others.
@@ -1704,7 +1848,7 @@ static int can_raw_setsockopt(FAR struct socket *psock, 
int level,
       case CAN_RAW_FILTER:
         if (value_len == 0)
           {
-            conn->filter_count = 0;
+            raw->filter_count = 0;
             ret = OK;
           }
         else if (value_len % sizeof(struct can_filter) != 0)
@@ -1724,10 +1868,10 @@ static int can_raw_setsockopt(FAR struct socket *psock, 
int level,
 
             for (i = 0; i < count; i++)
               {
-                conn->filters[i] = ((struct can_filter *)value)[i];
+                raw->filters[i] = ((struct can_filter *)value)[i];
               }
 
-            conn->filter_count = count;
+            raw->filter_count = count;
 
             ret = OK;
           }
@@ -1740,7 +1884,7 @@ static int can_raw_setsockopt(FAR struct socket *psock, 
int level,
             return -EINVAL;
           }
 
-        conn->err_mask = *(FAR can_err_mask_t *)value;
+        raw->err_mask = *(FAR can_err_mask_t *)value;
         break;
 #endif
 

Reply via email to