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 2b61288d8ca55b4fd57762ff146e5af0f58040db Author: p-szafonimateusz <[email protected]> AuthorDate: Mon Nov 9 11:51:11 2026 +0100 net/can: Move can_recvmsg.c into can_raw.c. Move the code of can_recvmsg.c into can_raw.c without changes and remove can_recvmsg.c. Only the include lists and the file guards are merged; the functions are copied as they are. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: p-szafonimateusz <[email protected]> --- .github/CODEOWNERS | 1 - Documentation/os/networking/socketcan.rst | 3 +- net/can/CMakeLists.txt | 2 +- net/can/Make.defs | 2 - net/can/can_raw.c | 512 +++++++++++++++++++++++++++- net/can/can_recvmsg.c | 546 ------------------------------ 6 files changed, 505 insertions(+), 561 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 15daa5e325e..84e158695d4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15894,7 +15894,6 @@ net/can/can.c [email protected] [email protected] [email protected] anchao net/can/can.h [email protected] [email protected] [email protected] [email protected] [email protected] net/can/can_getsockopt.c [email protected] [email protected] [email protected] [email protected] [email protected] net/can/can_raw.c [email protected] [email protected] [email protected] [email protected] [email protected] -net/can/can_recvmsg.c [email protected] [email protected] [email protected] [email protected] [email protected] net/can/can_sendmsg.c [email protected] [email protected] [email protected] [email protected] [email protected] net/can/can_setsockopt.c [email protected] [email protected] [email protected] [email protected] [email protected] net/devif/devif.h [email protected] [email protected] [email protected] [email protected] diff --git a/Documentation/os/networking/socketcan.rst b/Documentation/os/networking/socketcan.rst index 9a3bd0b7df8..9cf1e0008ea 100644 --- a/Documentation/os/networking/socketcan.rst +++ b/Documentation/os/networking/socketcan.rst @@ -93,10 +93,9 @@ Files supporting SocketCAN can be found in the following locations: - **Main Modules**: - ``can.c`` - Connection management, input, callbacks and polling - - ``can_raw.c`` - Socket interface implementation + - ``can_raw.c`` - Socket interface and message reception - ``can_sendmsg.c`` - Message transmission - ``can_sendmsg_buffered.c`` - Message transmission with buffering - - ``can_recvmsg.c`` - Message reception Configuration Options --------------------- diff --git a/net/can/CMakeLists.txt b/net/can/CMakeLists.txt index ac01c1eb770..e89495f1eb6 100644 --- a/net/can/CMakeLists.txt +++ b/net/can/CMakeLists.txt @@ -23,7 +23,7 @@ if(CONFIG_NET_CAN) set(SRCS) # Socket layer - list(APPEND SRCS can_raw.c can_recvmsg.c) + list(APPEND SRCS can_raw.c) if(CONFIG_NET_CAN_WRITE_BUFFERS) list(APPEND SRCS can_sendmsg_buffered.c) diff --git a/net/can/Make.defs b/net/can/Make.defs index f1eee77ebec..fa55c9bb002 100644 --- a/net/can/Make.defs +++ b/net/can/Make.defs @@ -33,8 +33,6 @@ else SOCK_CSRCS += can_sendmsg.c endif -SOCK_CSRCS += can_recvmsg.c - ifeq ($(CONFIG_NET_CANPROTO_OPTIONS),y) SOCK_CSRCS += can_setsockopt.c can_getsockopt.c endif diff --git a/net/can/can_raw.c b/net/can/can_raw.c index 685bdefeaaf..e852dbdf820 100644 --- a/net/can/can_raw.c +++ b/net/can/can_raw.c @@ -26,27 +26,51 @@ #include <nuttx/config.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <stdbool.h> -#include <string.h> -#include <poll.h> -#include <sched.h> +#ifdef CONFIG_NET_CAN + #include <assert.h> #include <errno.h> -#include <nuttx/debug.h> +#include <poll.h> +#include <sched.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <utils/utils.h> +#include <arch/irq.h> + +#include <netpacket/packet.h> +#include <nuttx/debug.h> #include <nuttx/kmalloc.h> +#include <nuttx/net/net.h> +#include <nuttx/net/netdev.h> +#include <nuttx/net/netstats.h> #include <nuttx/poll.h> #include <nuttx/semaphore.h> #include <nuttx/wqueue.h> -#include <nuttx/net/net.h> #include "can/can.h" +#include "devif/devif.h" #include "netdev/netdev.h" +#include "socket/socket.h" #include "utils/utils.h" -#ifdef CONFIG_NET_CAN +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct can_recvfrom_s +{ + FAR struct can_conn_s *pr_conn; /* Connection associated with the socket */ + FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */ + FAR struct msghdr *pr_msg; /* Pointer to receive buffer */ + sem_t pr_sem; /* Semaphore signals recv completion */ + ssize_t pr_recvlen; /* The received length */ + int pr_result; /* Success:OK, failure:negated errno */ +}; /**************************************************************************** * Private Function Prototypes @@ -96,6 +120,476 @@ const struct sock_intf_s g_can_sockif = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: can_recvfrom_initialize + * + * Description: + * Initialize the state structure + * + * Input Parameters: + * conn The CAN connection of interest + * msg Receive info and buffer for receive data + * pstate A pointer to the state structure to be initialized + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void can_recvfrom_initialize(FAR struct can_conn_s *conn, + FAR struct msghdr *msg, + FAR struct can_recvfrom_s *pstate) +{ + /* Initialize the state structure. */ + + memset(pstate, 0, sizeof(struct can_recvfrom_s)); + nxsem_init(&pstate->pr_sem, 0, 0); + + pstate->pr_conn = conn; + pstate->pr_msg = msg; +} + +/**************************************************************************** + * Name: can_add_recvlen + * + * Description: + * Update information about space available for new data and update size + * of data in buffer, This logic accounts for the case where + * recvfrom_udpreadahead() sets state.pr_recvlen == -1 . + * + * Input Parameters: + * pstate recvfrom state structure + * recvlen size of new data appended to buffer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate, + size_t recvlen) +{ + if (pstate->pr_recvlen < 0) + { + pstate->pr_recvlen = 0; + } + + pstate->pr_recvlen += recvlen; +} + +/**************************************************************************** + * Name: can_recvfrom_newdata + * + * Description: + * Copy the read data from the packet + * + * Input Parameters: + * dev The structure of the network driver that caused the event. + * pstate recvfrom state structure + * + * Returned Value: + * None. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev, + FAR struct can_recvfrom_s *pstate) +{ + unsigned int offset; + ssize_t recvlen; + + if (dev->d_iob->io_conn == &pstate->pr_conn->sconn) + { + pstate->pr_msg->msg_flags |= MSG_CONFIRM; + } + +#ifdef CONFIG_NET_TIMESTAMP + cmsg_store_timestamp(pstate->pr_msg, &dev->d_iob->io_time, + pstate->pr_conn->sconn.s_options); +#endif + + /* Copy the new packet data into the user buffer */ + + offset = (dev->d_appdata - dev->d_iob->io_data) - + dev->d_iob->io_offset; + recvlen = iob_copyout_iov(pstate->pr_msg->msg_iov, + pstate->pr_msg->msg_iovlen, + dev->d_iob, dev->d_len, offset); + if (recvlen <= 0) + { + return 0; + } + + /* Trim the copied buffers */ + + dev->d_iob = iob_trimhead(dev->d_iob, recvlen + offset); + + /* 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) + { + if (can_datahandler(dev, pstate->pr_conn) < dev->d_len) + { + ninfo("Dropped %d bytes\n", dev->d_len); +#ifdef CONFIG_NET_STATISTICS + g_netstats.can.drop++; +#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 = pstate->pr_conn; + FAR struct iob_s *iob; + size_t total_recv = 0; + size_t i; + bool has_buf = false; + + /* Check there is any CAN data already buffered in a read-ahead + * buffer. + */ + + pstate->pr_recvlen = -ENODATA; + + for (i = 0; i < pstate->pr_msg->msg_iovlen; i++) + { + if (pstate->pr_msg->msg_iov[i].iov_len > 0) + { + has_buf = true; + break; + } + } + + if (has_buf && + (iob = iob_remove_queue(&conn->readahead)) != NULL) + { + DEBUGASSERT(iob->io_pktlen > 0); + +#ifdef CONFIG_NET_TIMESTAMP + cmsg_store_timestamp(pstate->pr_msg, &iob->io_time, + conn->sconn.s_options); +#endif + + if (iob->io_conn == &conn->sconn) + { + pstate->pr_msg->msg_flags |= MSG_CONFIRM; + } + + /* Transfer that buffered data from the I/O buffer chain into + * the user buffer. + */ + + total_recv = iob_copyout_iov(pstate->pr_msg->msg_iov, + pstate->pr_msg->msg_iovlen, + iob, iob->io_pktlen, 0); + + /* Update the accumulated size of the data read */ + + pstate->pr_recvlen = total_recv; + + /* The rest of a frame larger than the user buffer is discarded */ + + if (iob->io_pktlen > total_recv) + { + pstate->pr_msg->msg_flags |= MSG_TRUNC; + } + + /* We have taken all of the data we need from the I/O buffer chain, + * so release it. There is no trimming needed, since One CAN/CANFD + * frame can always fit in one IOB. + */ + + static_assert(sizeof(struct can_frame) <= CONFIG_IOB_BUFSIZE); + + /* Free the I/O buffer chain */ + + iob_free_chain(iob); + + return total_recv; + } + + return 0; +} + +static uint32_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvpriv, uint32_t flags) +{ + struct can_recvfrom_s *pstate = pvpriv; + + /* 'priv' might be null in some race conditions (?) */ + + if (pstate) + { + if ((flags & CAN_NEWDATA) != 0) + { + /* Copy the packet. can_active() does not deliver CAN FD frames + * to a classic CAN socket. + */ + + can_newdata(dev, pstate); + + /* We are finished. */ + + /* Don't allow any further call backs. */ + + pstate->pr_cb->flags = 0; + pstate->pr_cb->priv = NULL; + pstate->pr_cb->event = NULL; + + /* indicate that the data has been consumed */ + + flags &= ~CAN_NEWDATA; + + /* Wake up the waiting thread, returning the number of bytes + * actually read. + */ + + nxsem_post(&pstate->pr_sem); + } + } + + return flags; +} + +/**************************************************************************** + * Name: can_recvfrom_result + * + * Description: + * Evaluate the result of the recv operations + * + * Input Parameters: + * result The result of the conn_dev_sem_timedwait operation + * (may indicate EINTR) + * pstate A pointer to the state structure to be initialized + * + * Returned Value: + * The result of the recv operation with errno set appropriately + * + * Assumptions: + * + ****************************************************************************/ + +static ssize_t can_recvfrom_result(int result, + FAR struct can_recvfrom_s *pstate) +{ + /* Check for a error/timeout detected by the event handler. Errors are + * signaled by negative errno values for the rcv length + */ + + if (pstate->pr_result < 0) + { + /* This might return EAGAIN on a timeout */ + + return pstate->pr_result; + } + + /* If conn_dev_sem_timedwait failed, then we were probably reawakened by + * a signal. In this case, conn_dev_sem_timedwait will have returned + * negated errno appropriately. + */ + + if (result < 0) + { + return result; + } + + return pstate->pr_recvlen; +} + +/**************************************************************************** + * Name: can_recvmsg + * + * Description: + * recvmsg() receives messages from a socket, and may be used to receive + * data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument 'msg_namelen' + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * msg Buffer to receive the message + * flags Receive flags (ignored) + * + ****************************************************************************/ + +ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, + int flags) +{ + FAR struct can_conn_s *conn; + FAR struct net_driver_s *dev = NULL; + struct can_recvfrom_s state; + int ret; + + conn = psock->s_conn; + + if (psock->s_type != SOCK_RAW) + { + nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); + return -ENOSYS; + } + + if (msg->msg_iovlen == 0) + { + return -EMSGSIZE; + } + + conn_lock(&conn->sconn); + + /* Initialize the state structure. */ + + can_recvfrom_initialize(conn, msg, &state); + + /* 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) + { + goto errout_with_state; + } + + ret = state.pr_recvlen; + + /* Handle non-blocking CAN sockets */ + + if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0) + { + /* Return the number of bytes read from the read-ahead buffer if + * something was received (already in 'ret'); EAGAIN if not. + */ + + if (ret < 0) + { + /* Nothing was received */ + + ret = -EAGAIN; + goto errout_with_state; + } + } + + /* Get the device driver that will service this transfer */ + + dev = conn->dev; + if (dev == NULL && _SS_ISBOUND(conn->sconn.s_flags)) + { + dev = netdev_default(); + } + + if (dev == NULL) + { + ret = -ENODEV; + goto errout_with_state; + } + + conn_unlock(&conn->sconn); + conn_dev_lock(&conn->sconn, dev); + + /* Set up the callback in the connection */ + + state.pr_cb = can_callback_alloc(dev, conn); + if (state.pr_cb) + { + state.pr_cb->flags = (CAN_NEWDATA | CAN_POLL); + state.pr_cb->priv = (FAR void *)&state; + state.pr_cb->event = can_recvfrom_eventhandler; + + /* Wait for either the receive to complete or for an error/timeout to + * occur. NOTES: (1) conn_dev_sem_timedwait will also terminate if a + * signal is received, (2) the network is locked! It will be un-locked + * while the task sleeps and automatically re-locked when the task + * restarts. + */ + + ret = conn_dev_sem_timedwait(&state.pr_sem, true, + _SO_TIMEOUT(conn->sconn.s_rcvtimeo), + &conn->sconn, dev); + if (ret == -ETIMEDOUT) + { + ret = -EAGAIN; + } + + /* Make sure that no further events are processed */ + + can_callback_free(dev, conn, state.pr_cb); + ret = can_recvfrom_result(ret, &state); + } + else + { + ret = -EBUSY; + } + +errout_with_state: + conn_dev_unlock(&conn->sconn, dev); + nxsem_destroy(&state.pr_sem); + return ret; +} + /**************************************************************************** * Name: can_poll_eventhandler * diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c deleted file mode 100644 index 8e1aca93bc1..00000000000 --- a/net/can/can_recvmsg.c +++ /dev/null @@ -1,546 +0,0 @@ -/**************************************************************************** - * net/can/can_recvmsg.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#ifdef CONFIG_NET_CAN - -#include <sys/types.h> -#include <sys/socket.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <nuttx/debug.h> -#include <assert.h> - -#include <arch/irq.h> - -#include <nuttx/semaphore.h> -#include <nuttx/net/net.h> -#include <nuttx/net/netdev.h> -#include <nuttx/net/netstats.h> - -#include "netdev/netdev.h" -#include "devif/devif.h" -#include "can/can.h" -#include "socket/socket.h" -#include "utils/utils.h" -#include <netpacket/packet.h> - -#ifdef CONFIG_NET_TIMESTAMP -#include <sys/time.h> -#include <utils/utils.h> -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct can_recvfrom_s -{ - FAR struct can_conn_s *pr_conn; /* Connection associated with the socket */ - FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */ - FAR struct msghdr *pr_msg; /* Pointer to receive buffer */ - sem_t pr_sem; /* Semaphore signals recv completion */ - ssize_t pr_recvlen; /* The received length */ - int pr_result; /* Success:OK, failure:negated errno */ -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: can_recvfrom_initialize - * - * Description: - * Initialize the state structure - * - * Input Parameters: - * conn The CAN connection of interest - * msg Receive info and buffer for receive data - * pstate A pointer to the state structure to be initialized - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void can_recvfrom_initialize(FAR struct can_conn_s *conn, - FAR struct msghdr *msg, - FAR struct can_recvfrom_s *pstate) -{ - /* Initialize the state structure. */ - - memset(pstate, 0, sizeof(struct can_recvfrom_s)); - nxsem_init(&pstate->pr_sem, 0, 0); - - pstate->pr_conn = conn; - pstate->pr_msg = msg; -} - -/**************************************************************************** - * Name: can_add_recvlen - * - * Description: - * Update information about space available for new data and update size - * of data in buffer, This logic accounts for the case where - * recvfrom_udpreadahead() sets state.pr_recvlen == -1 . - * - * Input Parameters: - * pstate recvfrom state structure - * recvlen size of new data appended to buffer - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate, - size_t recvlen) -{ - if (pstate->pr_recvlen < 0) - { - pstate->pr_recvlen = 0; - } - - pstate->pr_recvlen += recvlen; -} - -/**************************************************************************** - * Name: can_recvfrom_newdata - * - * Description: - * Copy the read data from the packet - * - * Input Parameters: - * dev The structure of the network driver that caused the event. - * pstate recvfrom state structure - * - * Returned Value: - * None. - * - * Assumptions: - * The network is locked. - * - ****************************************************************************/ - -static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev, - FAR struct can_recvfrom_s *pstate) -{ - unsigned int offset; - ssize_t recvlen; - - if (dev->d_iob->io_conn == &pstate->pr_conn->sconn) - { - pstate->pr_msg->msg_flags |= MSG_CONFIRM; - } - -#ifdef CONFIG_NET_TIMESTAMP - cmsg_store_timestamp(pstate->pr_msg, &dev->d_iob->io_time, - pstate->pr_conn->sconn.s_options); -#endif - - /* Copy the new packet data into the user buffer */ - - offset = (dev->d_appdata - dev->d_iob->io_data) - - dev->d_iob->io_offset; - recvlen = iob_copyout_iov(pstate->pr_msg->msg_iov, - pstate->pr_msg->msg_iovlen, - dev->d_iob, dev->d_len, offset); - if (recvlen <= 0) - { - return 0; - } - - /* Trim the copied buffers */ - - dev->d_iob = iob_trimhead(dev->d_iob, recvlen + offset); - - /* 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) - { - if (can_datahandler(dev, pstate->pr_conn) < dev->d_len) - { - ninfo("Dropped %d bytes\n", dev->d_len); -#ifdef CONFIG_NET_STATISTICS - g_netstats.can.drop++; -#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 = pstate->pr_conn; - FAR struct iob_s *iob; - size_t total_recv = 0; - size_t i; - bool has_buf = false; - - /* Check there is any CAN data already buffered in a read-ahead - * buffer. - */ - - pstate->pr_recvlen = -ENODATA; - - for (i = 0; i < pstate->pr_msg->msg_iovlen; i++) - { - if (pstate->pr_msg->msg_iov[i].iov_len > 0) - { - has_buf = true; - break; - } - } - - if (has_buf && - (iob = iob_remove_queue(&conn->readahead)) != NULL) - { - DEBUGASSERT(iob->io_pktlen > 0); - -#ifdef CONFIG_NET_TIMESTAMP - cmsg_store_timestamp(pstate->pr_msg, &iob->io_time, - conn->sconn.s_options); -#endif - - if (iob->io_conn == &conn->sconn) - { - pstate->pr_msg->msg_flags |= MSG_CONFIRM; - } - - /* Transfer that buffered data from the I/O buffer chain into - * the user buffer. - */ - - total_recv = iob_copyout_iov(pstate->pr_msg->msg_iov, - pstate->pr_msg->msg_iovlen, - iob, iob->io_pktlen, 0); - - /* Update the accumulated size of the data read */ - - pstate->pr_recvlen = total_recv; - - /* The rest of a frame larger than the user buffer is discarded */ - - if (iob->io_pktlen > total_recv) - { - pstate->pr_msg->msg_flags |= MSG_TRUNC; - } - - /* We have taken all of the data we need from the I/O buffer chain, - * so release it. There is no trimming needed, since One CAN/CANFD - * frame can always fit in one IOB. - */ - - static_assert(sizeof(struct can_frame) <= CONFIG_IOB_BUFSIZE); - - /* Free the I/O buffer chain */ - - iob_free_chain(iob); - - return total_recv; - } - - return 0; -} - -static uint32_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev, - FAR void *pvpriv, uint32_t flags) -{ - struct can_recvfrom_s *pstate = pvpriv; - - /* 'priv' might be null in some race conditions (?) */ - - if (pstate) - { - if ((flags & CAN_NEWDATA) != 0) - { - /* Copy the packet. can_active() does not deliver CAN FD frames - * to a classic CAN socket. - */ - - can_newdata(dev, pstate); - - /* We are finished. */ - - /* Don't allow any further call backs. */ - - pstate->pr_cb->flags = 0; - pstate->pr_cb->priv = NULL; - pstate->pr_cb->event = NULL; - - /* indicate that the data has been consumed */ - - flags &= ~CAN_NEWDATA; - - /* Wake up the waiting thread, returning the number of bytes - * actually read. - */ - - nxsem_post(&pstate->pr_sem); - } - } - - return flags; -} - -/**************************************************************************** - * Name: can_recvfrom_result - * - * Description: - * Evaluate the result of the recv operations - * - * Input Parameters: - * result The result of the conn_dev_sem_timedwait operation - * (may indicate EINTR) - * pstate A pointer to the state structure to be initialized - * - * Returned Value: - * The result of the recv operation with errno set appropriately - * - * Assumptions: - * - ****************************************************************************/ - -static ssize_t can_recvfrom_result(int result, - FAR struct can_recvfrom_s *pstate) -{ - /* Check for a error/timeout detected by the event handler. Errors are - * signaled by negative errno values for the rcv length - */ - - if (pstate->pr_result < 0) - { - /* This might return EAGAIN on a timeout */ - - return pstate->pr_result; - } - - /* If conn_dev_sem_timedwait failed, then we were probably reawakened by - * a signal. In this case, conn_dev_sem_timedwait will have returned - * negated errno appropriately. - */ - - if (result < 0) - { - return result; - } - - return pstate->pr_recvlen; -} - -/**************************************************************************** - * Name: can_recvmsg - * - * Description: - * recvmsg() receives messages from a socket, and may be used to receive - * data on a socket whether or not it is connection-oriented. - * - * If from is not NULL, and the underlying protocol provides the source - * address, this source address is filled in. The argument 'msg_namelen' - * initialized to the size of the buffer associated with from, and modified - * on return to indicate the actual size of the address stored there. - * - * Input Parameters: - * psock A pointer to a NuttX-specific, internal socket structure - * msg Buffer to receive the message - * flags Receive flags (ignored) - * - ****************************************************************************/ - -ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, - int flags) -{ - FAR struct can_conn_s *conn; - FAR struct net_driver_s *dev = NULL; - struct can_recvfrom_s state; - int ret; - - conn = psock->s_conn; - - if (psock->s_type != SOCK_RAW) - { - nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); - return -ENOSYS; - } - - if (msg->msg_iovlen == 0) - { - return -EMSGSIZE; - } - - conn_lock(&conn->sconn); - - /* Initialize the state structure. */ - - can_recvfrom_initialize(conn, msg, &state); - - /* 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) - { - goto errout_with_state; - } - - ret = state.pr_recvlen; - - /* Handle non-blocking CAN sockets */ - - if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0) - { - /* Return the number of bytes read from the read-ahead buffer if - * something was received (already in 'ret'); EAGAIN if not. - */ - - if (ret < 0) - { - /* Nothing was received */ - - ret = -EAGAIN; - goto errout_with_state; - } - } - - /* Get the device driver that will service this transfer */ - - dev = conn->dev; - if (dev == NULL && _SS_ISBOUND(conn->sconn.s_flags)) - { - dev = netdev_default(); - } - - if (dev == NULL) - { - ret = -ENODEV; - goto errout_with_state; - } - - conn_unlock(&conn->sconn); - conn_dev_lock(&conn->sconn, dev); - - /* Set up the callback in the connection */ - - state.pr_cb = can_callback_alloc(dev, conn); - if (state.pr_cb) - { - state.pr_cb->flags = (CAN_NEWDATA | CAN_POLL); - state.pr_cb->priv = (FAR void *)&state; - state.pr_cb->event = can_recvfrom_eventhandler; - - /* Wait for either the receive to complete or for an error/timeout to - * occur. NOTES: (1) conn_dev_sem_timedwait will also terminate if a - * signal is received, (2) the network is locked! It will be un-locked - * while the task sleeps and automatically re-locked when the task - * restarts. - */ - - ret = conn_dev_sem_timedwait(&state.pr_sem, true, - _SO_TIMEOUT(conn->sconn.s_rcvtimeo), - &conn->sconn, dev); - if (ret == -ETIMEDOUT) - { - ret = -EAGAIN; - } - - /* Make sure that no further events are processed */ - - can_callback_free(dev, conn, state.pr_cb); - ret = can_recvfrom_result(ret, &state); - } - else - { - ret = -EBUSY; - } - -errout_with_state: - conn_dev_unlock(&conn->sconn, dev); - nxsem_destroy(&state.pr_sem); - return ret; -} - -#endif /* CONFIG_NET_CAN */
