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 */

Reply via email to