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
