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 9ac2e841fed25def8e1848852875eaec19d01aca
Author: p-szafonimateusz <[email protected]>
AuthorDate: Mon Nov 9 11:51:11 2026 +0100

    net/can: Move can_sendmsg_buffered.c into can_raw.c.
    
    Move the code of can_sendmsg_buffered.c into can_raw.c without changes and 
remove
    can_sendmsg_buffered.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]>
---
 Documentation/os/networking/socketcan.rst |   4 +-
 net/can/CMakeLists.txt                    |   4 -
 net/can/Make.defs                         |   3 -
 net/can/can_raw.c                         | 457 ++++++++++++++++++++++++++
 net/can/can_sendmsg_buffered.c            | 512 ------------------------------
 5 files changed, 459 insertions(+), 521 deletions(-)

diff --git a/Documentation/os/networking/socketcan.rst 
b/Documentation/os/networking/socketcan.rst
index fadfdbd1a93..4dea9ddef29 100644
--- a/Documentation/os/networking/socketcan.rst
+++ b/Documentation/os/networking/socketcan.rst
@@ -93,8 +93,8 @@ 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, message transmission and reception
-   - ``can_sendmsg_buffered.c`` - Message transmission with buffering
+   - ``can_raw.c`` - Socket interface, message transmission (with and without
+     buffering) and reception
 
 Configuration Options
 ---------------------
diff --git a/net/can/CMakeLists.txt b/net/can/CMakeLists.txt
index 0344d890b3c..a5201b4b334 100644
--- a/net/can/CMakeLists.txt
+++ b/net/can/CMakeLists.txt
@@ -25,10 +25,6 @@ if(CONFIG_NET_CAN)
   # Socket layer
   list(APPEND SRCS can_raw.c)
 
-  if(CONFIG_NET_CAN_WRITE_BUFFERS)
-    list(APPEND SRCS can_sendmsg_buffered.c)
-  endif()
-
   if(CONFIG_NET_CANPROTO_OPTIONS)
     list(APPEND SRCS can_setsockopt.c can_getsockopt.c)
   endif()
diff --git a/net/can/Make.defs b/net/can/Make.defs
index 9dfdd90bf17..8c88ab4abd8 100644
--- a/net/can/Make.defs
+++ b/net/can/Make.defs
@@ -27,9 +27,6 @@ ifeq ($(CONFIG_NET_CAN),y)
 # Socket layer
 
 SOCK_CSRCS += can_raw.c
-ifeq ($(CONFIG_NET_CAN_WRITE_BUFFERS),y)
-SOCK_CSRCS += can_sendmsg_buffered.c
-endif
 
 ifeq ($(CONFIG_NET_CANPROTO_OPTIONS),y)
 SOCK_CSRCS += can_setsockopt.c can_getsockopt.c
diff --git a/net/can/can_raw.c b/net/can/can_raw.c
index e92b09c4f70..f1cedd69825 100644
--- a/net/can/can_raw.c
+++ b/net/can/can_raw.c
@@ -45,6 +45,7 @@
 #include <netpacket/packet.h>
 #include <nuttx/debug.h>
 #include <nuttx/kmalloc.h>
+#include <nuttx/net/can.h>
 #include <nuttx/net/ip.h>
 #include <nuttx/net/net.h>
 #include <nuttx/net/netdev.h>
@@ -929,6 +930,427 @@ int psock_can_cansend(FAR struct socket *psock)
   return OK;
 }
 
+#else
+/****************************************************************************
+ * Name: psock_send_eventhandler
+ ****************************************************************************/
+
+static uint32_t psock_send_eventhandler(FAR struct net_driver_s *dev,
+                                        FAR void *pvpriv, uint32_t flags)
+{
+  FAR struct can_conn_s *conn = pvpriv;
+
+  DEBUGASSERT(dev != NULL && conn != NULL);
+
+  /* Check if the outgoing packet is available. It may have been claimed
+   * by a send event handler serving a different thread -OR- if the
+   * output buffer currently contains unprocessed incoming data. In
+   * these cases we will just have to wait for the next polling cycle.
+   */
+
+  if (dev->d_sndlen > 0 || (flags & CAN_NEWDATA) != 0)
+    {
+      /* Another thread has beat us sending data or the buffer is busy,
+       * Check for a timeout. If not timed out, wait for the next
+       * polling cycle and check again.
+       */
+
+      /* No timeout. Just wait for the next polling cycle */
+
+      return flags;
+    }
+
+  /* It looks like we are good to send the data */
+
+  else
+    {
+      uint32_t write_q_len;
+      FAR struct iob_s *wrb_iob;
+
+      /* Copy the packet data into the device packet buffer and send it */
+
+      write_q_len = iob_get_queue_entry_count(&conn->write_q);
+
+      if (write_q_len == 0)
+        {
+          return flags;
+        }
+
+      /* Peek at the head of the write queue (but don't remove anything
+       * from the write queue yet).  We know from the above test that
+       * the write_q is not empty.
+       */
+
+      wrb_iob = (FAR struct iob_s *)iob_remove_queue(&conn->write_q);
+      DEBUGASSERT(wrb_iob != NULL);
+
+      /* Then set-up to send that amount of data with the offset
+       * corresponding to the size of the IP-dependent address structure.
+       */
+
+      netdev_iob_replace(dev, wrb_iob);
+
+      /* Get the amount of data that we can send in the next packet.
+       * We will send either the remaining data in the buffer I/O
+       * buffer chain, or as much as will fit given the MSS and current
+       * window size.
+       */
+
+      dev->d_sndlen = wrb_iob->io_pktlen;
+      ninfo("wrb=%p sndlen=%d\n", wrb_iob, dev->d_sndlen);
+
+      if (write_q_len > 1)
+        {
+          /* Set up for the next packet transfer
+           * next packet now at the header of the write buffer queue.
+           */
+
+          /* Notify the device driver that new TX data is available. */
+
+          netdev_txnotify_dev(dev, CAN_POLL);
+        }
+      else
+        {
+          /* stifle any further callbacks until more write data is
+           * enqueued.
+           */
+
+          conn->sndcb->flags = 0;
+          conn->sndcb->priv = NULL;
+          conn->sndcb->event = NULL;
+        }
+
+      /* Only one data can be sent by low level driver at once,
+       * tell the caller stop polling the other connections.
+       */
+
+      flags &= ~CAN_POLL;
+
+#if CONFIG_NET_SEND_BUFSIZE > 0
+      can_sendbuffer_notify(conn);
+#endif
+    }
+
+  return flags;
+}
+
+/****************************************************************************
+ * Name: can_sendmsg
+ *
+ * Description:
+ *   The can_sendmsg() call may be used only when the packet socket is
+ *   in a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   msg      CAN frame and optional CMSG
+ *   flags    Send flags (ignored)
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   a negated errno value is retruend.  See sendmsg() for the complete list
+ *   of return values.
+ *
+ ****************************************************************************/
+
+ssize_t can_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg,
+                    int flags)
+{
+  FAR struct net_driver_s *dev;
+  FAR struct can_conn_s *conn;
+  FAR struct iob_s *wb_iob;
+  size_t total_len = 0;
+  size_t i;
+  bool empty;
+  bool nonblock;
+  int ret = OK;
+
+  /* Only SOCK_RAW is supported */
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
+       * no peer address is set.
+       */
+
+      return -EDESTADDRREQ;
+    }
+
+  conn = psock->s_conn;
+
+  /* Get the device driver that will service this transfer */
+
+  dev = conn->dev;
+  if (dev == NULL)
+    {
+      return -ENODEV;
+    }
+
+  if (msg->msg_iovlen == 0)
+    {
+      return -EMSGSIZE;
+    }
+
+  for (i = 0; i < msg->msg_iovlen; i++)
+    {
+      if (msg->msg_iov[i].iov_len > CANFD_MTU - total_len)
+        {
+          return -EINVAL;
+        }
+
+      total_len += msg->msg_iov[i].iov_len;
+    }
+
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+  if (_SO_GETOPT(conn->sconn.s_options, CAN_RAW_FD_FRAMES))
+    {
+      if (total_len != CANFD_MTU && total_len != CAN_MTU)
+        {
+          return -EINVAL;
+        }
+    }
+  else
+#endif
+    {
+      if (total_len != CAN_MTU)
+        {
+          return -EINVAL;
+        }
+    }
+
+  nonblock =
+      _SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0;
+
+  /* Perform the send operation */
+
+  /* Initialize the state structure. This is done with the network locked
+   * because we don't want anything to happen until we are ready.
+   */
+
+  conn_dev_lock(&conn->sconn, dev);
+
+#if CONFIG_NET_SEND_BUFSIZE > 0
+  /* Wait until the frame fits.  The semaphore can be posted while there is
+   * still no room, so check again after every wake-up.  A frame is always
+   * accepted into an empty queue, even if it is larger than sndbufs.
+   */
+
+  while (!IOB_QEMPTY(&conn->write_q) &&
+         (iob_get_queue_size(&conn->write_q) + total_len) >
+         conn->sndbufs)
+    {
+      /* send buffer size exceeds the send limit */
+
+      if (nonblock)
+        {
+          nerr("ERROR: Buffer overflow\n");
+          ret = -EAGAIN;
+          goto errout_with_lock;
+        }
+
+      ret = conn_dev_sem_timedwait(&conn->sndsem, false,
+                                   _SO_TIMEOUT(conn->sconn.s_sndtimeo),
+                                   &conn->sconn, dev);
+      if (ret < 0)
+        {
+          goto errout_with_lock;
+        }
+    }
+#endif
+
+  if (nonblock)
+    {
+      wb_iob = can_iob_timedalloc(0);
+    }
+  else
+    {
+      wb_iob = can_iob_timedalloc(_SO_TIMEOUT(conn->sconn.s_sndtimeo));
+    }
+
+  if (wb_iob == NULL)
+    {
+      /* A buffer allocation error occurred */
+
+      nerr("ERROR: Failed to allocate write buffer\n");
+
+      if (nonblock)
+        {
+          ret = -EAGAIN;
+        }
+      else
+        {
+          ret = -ENOMEM;
+        }
+
+      goto errout_with_lock;
+    }
+
+  iob_reserve(wb_iob, CONFIG_NET_LL_GUARDSIZE);
+  iob_update_pktlen(wb_iob, 0, false);
+
+  wb_iob->io_conn = &conn->sconn;
+
+  /* Copy the user data into the write buffer.  We cannot wait for
+   * buffer space if the socket was opened non-blocking.
+   */
+
+  if (nonblock)
+    {
+      ret = iob_trycopyin_iov(wb_iob, msg->msg_iov, msg->msg_iovlen, 0,
+                              false);
+    }
+  else
+    {
+      /* iob_copyin might wait for buffers to be freed, but if
+       * network is locked this might never happen, since network
+       * driver is also locked, therefore we need to break the lock
+       */
+
+      conn_dev_unlock(&conn->sconn, dev);
+      ret = iob_copyin_iov(wb_iob, msg->msg_iov, msg->msg_iovlen, 0, false);
+      conn_dev_lock(&conn->sconn, dev);
+    }
+
+  if (ret < 0 || ret != total_len)
+    {
+      nerr("ERROR: Failed to copy data into write buffer\n");
+      if (ret >= 0)
+        {
+          ret = -ENOMEM;
+        }
+
+      goto errout_with_wrb;
+    }
+
+  /* Check if the write queue is empty */
+
+  empty = (iob_get_queue_entry_count(&conn->write_q) == 0);
+
+  /* Add the write buffer to the write queue */
+
+  if (nonblock)
+    {
+      ret = iob_tryadd_queue(wb_iob, &conn->write_q);
+    }
+  else
+    {
+      ret = iob_add_queue(wb_iob, &conn->write_q);
+    }
+
+  if (ret < 0)
+    {
+      nerr("ERROR: Failed to add buffer to w_queue\n");
+      goto errout_with_wrb;
+    }
+
+  /* The new write buffer lies at the head of the write queue.
+   * Set up for the next packet transfer.
+   */
+
+  if (empty)
+    {
+      /* Allocate resource to receive a callback */
+
+      if (conn->sndcb == NULL)
+        {
+          conn->sndcb = can_callback_alloc(dev, conn);
+        }
+
+      /* Test if the callback has been allocated */
+
+      if (conn->sndcb == NULL)
+        {
+          /* A buffer allocation error occurred */
+
+          nerr("ERROR: Failed to allocate callback\n");
+          ret = -ENOMEM;
+          goto errout_with_wq;
+        }
+
+      /* Set up the callback in the connection */
+
+      conn->sndcb->flags = CAN_POLL;
+      conn->sndcb->priv  = (FAR void *)conn;
+      conn->sndcb->event = psock_send_eventhandler;
+
+      /* Notify the device driver that new TX data is available. */
+
+      netdev_txnotify_dev(dev, CAN_POLL);
+    }
+
+  /* unlock */
+
+  conn_dev_unlock(&conn->sconn, dev);
+
+  return total_len;
+
+errout_with_wrb:
+  iob_free_chain(wb_iob);
+
+errout_with_wq:
+  iob_free_queue(&conn->write_q);
+
+errout_with_lock:
+  conn_dev_unlock(&conn->sconn, dev);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: psock_can_cansend
+ *
+ * Description:
+ *   psock_can_cansend() returns a value indicating if a write to the socket
+ *   would block.  No space in the buffer is actually reserved, so it is
+ *   possible that the write may still block if the buffer is filled by
+ *   another means.
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *
+ * Returned Value:
+ *   OK
+ *     At least one byte of data could be successfully written.
+ *   -EWOULDBLOCK
+ *     There is no room in the output buffer.
+ *   -EBADF
+ *     An invalid descriptor was specified.
+ *
+ ****************************************************************************/
+
+int psock_can_cansend(FAR struct socket *psock)
+{
+#if CONFIG_NET_SEND_BUFSIZE > 0
+  FAR struct can_conn_s *conn;
+#endif
+
+  /* Verify that we received a valid socket */
+
+  if (psock == NULL || psock->s_conn == NULL)
+    {
+      nerr("ERROR: Invalid socket\n");
+      return -EBADF;
+    }
+
+  /* In order to setup the send, we need to have at least
+   * one free IOB to initialize the write buffer head.
+   */
+
+#if CONFIG_NET_SEND_BUFSIZE > 0
+  conn = psock->s_conn;
+#endif
+
+  if (can_iob_navail() <= 0
+#if CONFIG_NET_SEND_BUFSIZE > 0
+      || iob_get_queue_size(&conn->write_q) >= conn->sndbufs
+#endif
+     )
+    {
+      return -EWOULDBLOCK;
+    }
+
+  return OK;
+}
+
 #endif
 
 /****************************************************************************
@@ -1473,4 +1895,39 @@ static int can_close(FAR struct socket *psock)
   return ret;
 }
 
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN_WRITE_BUFFERS
+/****************************************************************************
+ * Name: can_sendbuffer_notify
+ *
+ * Description:
+ *   Notify the send buffer semaphore
+ *
+ * Input Parameters:
+ *   conn - The CAN connection of interest
+ *
+ * Assumptions:
+ *   Called from user logic with the network locked.
+ *
+ ****************************************************************************/
+
+#if CONFIG_NET_SEND_BUFSIZE > 0
+void can_sendbuffer_notify(FAR struct can_conn_s *conn)
+{
+  int val = 0;
+
+  nxsem_get_value(&conn->sndsem, &val);
+  if (val < 1)
+    {
+      nxsem_post(&conn->sndsem);
+    }
+}
+
+#endif /* CONFIG_NET_SEND_BUFSIZE */
+
+#endif
+
 #endif /* CONFIG_NET_CAN */
diff --git a/net/can/can_sendmsg_buffered.c b/net/can/can_sendmsg_buffered.c
deleted file mode 100644
index bc631aedb06..00000000000
--- a/net/can/can_sendmsg_buffered.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/****************************************************************************
- * net/can/can_sendmsg_buffered.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>
-#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) && \
-    defined(CONFIG_NET_CAN_WRITE_BUFFERS)
-
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <nuttx/debug.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <arch/irq.h>
-
-#include <nuttx/net/can.h>
-#include <nuttx/net/ip.h>
-#include <nuttx/net/net.h>
-#include <nuttx/net/netdev.h>
-#include <nuttx/semaphore.h>
-
-#include "can/can.h"
-#include "devif/devif.h"
-#include "netdev/netdev.h"
-#include "socket/socket.h"
-#include "utils/utils.h"
-
-#include <sys/time.h>
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: psock_send_eventhandler
- ****************************************************************************/
-
-static uint32_t psock_send_eventhandler(FAR struct net_driver_s *dev,
-                                        FAR void *pvpriv, uint32_t flags)
-{
-  FAR struct can_conn_s *conn = pvpriv;
-
-  DEBUGASSERT(dev != NULL && conn != NULL);
-
-  /* Check if the outgoing packet is available. It may have been claimed
-   * by a send event handler serving a different thread -OR- if the
-   * output buffer currently contains unprocessed incoming data. In
-   * these cases we will just have to wait for the next polling cycle.
-   */
-
-  if (dev->d_sndlen > 0 || (flags & CAN_NEWDATA) != 0)
-    {
-      /* Another thread has beat us sending data or the buffer is busy,
-       * Check for a timeout. If not timed out, wait for the next
-       * polling cycle and check again.
-       */
-
-      /* No timeout. Just wait for the next polling cycle */
-
-      return flags;
-    }
-
-  /* It looks like we are good to send the data */
-
-  else
-    {
-      uint32_t write_q_len;
-      FAR struct iob_s *wrb_iob;
-
-      /* Copy the packet data into the device packet buffer and send it */
-
-      write_q_len = iob_get_queue_entry_count(&conn->write_q);
-
-      if (write_q_len == 0)
-        {
-          return flags;
-        }
-
-      /* Peek at the head of the write queue (but don't remove anything
-       * from the write queue yet).  We know from the above test that
-       * the write_q is not empty.
-       */
-
-      wrb_iob = (FAR struct iob_s *)iob_remove_queue(&conn->write_q);
-      DEBUGASSERT(wrb_iob != NULL);
-
-      /* Then set-up to send that amount of data with the offset
-       * corresponding to the size of the IP-dependent address structure.
-       */
-
-      netdev_iob_replace(dev, wrb_iob);
-
-      /* Get the amount of data that we can send in the next packet.
-       * We will send either the remaining data in the buffer I/O
-       * buffer chain, or as much as will fit given the MSS and current
-       * window size.
-       */
-
-      dev->d_sndlen = wrb_iob->io_pktlen;
-      ninfo("wrb=%p sndlen=%d\n", wrb_iob, dev->d_sndlen);
-
-      if (write_q_len > 1)
-        {
-          /* Set up for the next packet transfer
-           * next packet now at the header of the write buffer queue.
-           */
-
-          /* Notify the device driver that new TX data is available. */
-
-          netdev_txnotify_dev(dev, CAN_POLL);
-        }
-      else
-        {
-          /* stifle any further callbacks until more write data is
-           * enqueued.
-           */
-
-          conn->sndcb->flags = 0;
-          conn->sndcb->priv = NULL;
-          conn->sndcb->event = NULL;
-        }
-
-      /* Only one data can be sent by low level driver at once,
-       * tell the caller stop polling the other connections.
-       */
-
-      flags &= ~CAN_POLL;
-
-#if CONFIG_NET_SEND_BUFSIZE > 0
-      can_sendbuffer_notify(conn);
-#endif
-    }
-
-  return flags;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: can_sendmsg
- *
- * Description:
- *   The can_sendmsg() call may be used only when the packet socket is
- *   in a connected state (so that the intended recipient is known).
- *
- * Input Parameters:
- *   psock    An instance of the internal socket structure.
- *   msg      CAN frame and optional CMSG
- *   flags    Send flags (ignored)
- *
- * Returned Value:
- *   On success, returns the number of characters sent.  On  error,
- *   a negated errno value is retruend.  See sendmsg() for the complete list
- *   of return values.
- *
- ****************************************************************************/
-
-ssize_t can_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg,
-                    int flags)
-{
-  FAR struct net_driver_s *dev;
-  FAR struct can_conn_s *conn;
-  FAR struct iob_s *wb_iob;
-  size_t total_len = 0;
-  size_t i;
-  bool empty;
-  bool nonblock;
-  int ret = OK;
-
-  /* Only SOCK_RAW is supported */
-
-  if (psock->s_type != SOCK_RAW)
-    {
-      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
-       * no peer address is set.
-       */
-
-      return -EDESTADDRREQ;
-    }
-
-  conn = psock->s_conn;
-
-  /* Get the device driver that will service this transfer */
-
-  dev = conn->dev;
-  if (dev == NULL)
-    {
-      return -ENODEV;
-    }
-
-  if (msg->msg_iovlen == 0)
-    {
-      return -EMSGSIZE;
-    }
-
-  for (i = 0; i < msg->msg_iovlen; i++)
-    {
-      if (msg->msg_iov[i].iov_len > CANFD_MTU - total_len)
-        {
-          return -EINVAL;
-        }
-
-      total_len += msg->msg_iov[i].iov_len;
-    }
-
-#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
-  if (_SO_GETOPT(conn->sconn.s_options, CAN_RAW_FD_FRAMES))
-    {
-      if (total_len != CANFD_MTU && total_len != CAN_MTU)
-        {
-          return -EINVAL;
-        }
-    }
-  else
-#endif
-    {
-      if (total_len != CAN_MTU)
-        {
-          return -EINVAL;
-        }
-    }
-
-  nonblock =
-      _SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0;
-
-  /* Perform the send operation */
-
-  /* Initialize the state structure. This is done with the network locked
-   * because we don't want anything to happen until we are ready.
-   */
-
-  conn_dev_lock(&conn->sconn, dev);
-
-#if CONFIG_NET_SEND_BUFSIZE > 0
-  /* Wait until the frame fits.  The semaphore can be posted while there is
-   * still no room, so check again after every wake-up.  A frame is always
-   * accepted into an empty queue, even if it is larger than sndbufs.
-   */
-
-  while (!IOB_QEMPTY(&conn->write_q) &&
-         (iob_get_queue_size(&conn->write_q) + total_len) >
-         conn->sndbufs)
-    {
-      /* send buffer size exceeds the send limit */
-
-      if (nonblock)
-        {
-          nerr("ERROR: Buffer overflow\n");
-          ret = -EAGAIN;
-          goto errout_with_lock;
-        }
-
-      ret = conn_dev_sem_timedwait(&conn->sndsem, false,
-                                   _SO_TIMEOUT(conn->sconn.s_sndtimeo),
-                                   &conn->sconn, dev);
-      if (ret < 0)
-        {
-          goto errout_with_lock;
-        }
-    }
-#endif
-
-  if (nonblock)
-    {
-      wb_iob = can_iob_timedalloc(0);
-    }
-  else
-    {
-      wb_iob = can_iob_timedalloc(_SO_TIMEOUT(conn->sconn.s_sndtimeo));
-    }
-
-  if (wb_iob == NULL)
-    {
-      /* A buffer allocation error occurred */
-
-      nerr("ERROR: Failed to allocate write buffer\n");
-
-      if (nonblock)
-        {
-          ret = -EAGAIN;
-        }
-      else
-        {
-          ret = -ENOMEM;
-        }
-
-      goto errout_with_lock;
-    }
-
-  iob_reserve(wb_iob, CONFIG_NET_LL_GUARDSIZE);
-  iob_update_pktlen(wb_iob, 0, false);
-
-  wb_iob->io_conn = &conn->sconn;
-
-  /* Copy the user data into the write buffer.  We cannot wait for
-   * buffer space if the socket was opened non-blocking.
-   */
-
-  if (nonblock)
-    {
-      ret = iob_trycopyin_iov(wb_iob, msg->msg_iov, msg->msg_iovlen, 0,
-                              false);
-    }
-  else
-    {
-      /* iob_copyin might wait for buffers to be freed, but if
-       * network is locked this might never happen, since network
-       * driver is also locked, therefore we need to break the lock
-       */
-
-      conn_dev_unlock(&conn->sconn, dev);
-      ret = iob_copyin_iov(wb_iob, msg->msg_iov, msg->msg_iovlen, 0, false);
-      conn_dev_lock(&conn->sconn, dev);
-    }
-
-  if (ret < 0 || ret != total_len)
-    {
-      nerr("ERROR: Failed to copy data into write buffer\n");
-      if (ret >= 0)
-        {
-          ret = -ENOMEM;
-        }
-
-      goto errout_with_wrb;
-    }
-
-  /* Check if the write queue is empty */
-
-  empty = (iob_get_queue_entry_count(&conn->write_q) == 0);
-
-  /* Add the write buffer to the write queue */
-
-  if (nonblock)
-    {
-      ret = iob_tryadd_queue(wb_iob, &conn->write_q);
-    }
-  else
-    {
-      ret = iob_add_queue(wb_iob, &conn->write_q);
-    }
-
-  if (ret < 0)
-    {
-      nerr("ERROR: Failed to add buffer to w_queue\n");
-      goto errout_with_wrb;
-    }
-
-  /* The new write buffer lies at the head of the write queue.
-   * Set up for the next packet transfer.
-   */
-
-  if (empty)
-    {
-      /* Allocate resource to receive a callback */
-
-      if (conn->sndcb == NULL)
-        {
-          conn->sndcb = can_callback_alloc(dev, conn);
-        }
-
-      /* Test if the callback has been allocated */
-
-      if (conn->sndcb == NULL)
-        {
-          /* A buffer allocation error occurred */
-
-          nerr("ERROR: Failed to allocate callback\n");
-          ret = -ENOMEM;
-          goto errout_with_wq;
-        }
-
-      /* Set up the callback in the connection */
-
-      conn->sndcb->flags = CAN_POLL;
-      conn->sndcb->priv  = (FAR void *)conn;
-      conn->sndcb->event = psock_send_eventhandler;
-
-      /* Notify the device driver that new TX data is available. */
-
-      netdev_txnotify_dev(dev, CAN_POLL);
-    }
-
-  /* unlock */
-
-  conn_dev_unlock(&conn->sconn, dev);
-
-  return total_len;
-
-errout_with_wrb:
-  iob_free_chain(wb_iob);
-
-errout_with_wq:
-  iob_free_queue(&conn->write_q);
-
-errout_with_lock:
-  conn_dev_unlock(&conn->sconn, dev);
-  return ret;
-}
-
-/****************************************************************************
- * Name: psock_can_cansend
- *
- * Description:
- *   psock_can_cansend() returns a value indicating if a write to the socket
- *   would block.  No space in the buffer is actually reserved, so it is
- *   possible that the write may still block if the buffer is filled by
- *   another means.
- *
- * Input Parameters:
- *   psock    An instance of the internal socket structure.
- *
- * Returned Value:
- *   OK
- *     At least one byte of data could be successfully written.
- *   -EWOULDBLOCK
- *     There is no room in the output buffer.
- *   -EBADF
- *     An invalid descriptor was specified.
- *
- ****************************************************************************/
-
-int psock_can_cansend(FAR struct socket *psock)
-{
-#if CONFIG_NET_SEND_BUFSIZE > 0
-  FAR struct can_conn_s *conn;
-#endif
-
-  /* Verify that we received a valid socket */
-
-  if (psock == NULL || psock->s_conn == NULL)
-    {
-      nerr("ERROR: Invalid socket\n");
-      return -EBADF;
-    }
-
-  /* In order to setup the send, we need to have at least
-   * one free IOB to initialize the write buffer head.
-   */
-
-#if CONFIG_NET_SEND_BUFSIZE > 0
-  conn = psock->s_conn;
-#endif
-
-  if (can_iob_navail() <= 0
-#if CONFIG_NET_SEND_BUFSIZE > 0
-      || iob_get_queue_size(&conn->write_q) >= conn->sndbufs
-#endif
-     )
-    {
-      return -EWOULDBLOCK;
-    }
-
-  return OK;
-}
-
-/****************************************************************************
- * Name: can_sendbuffer_notify
- *
- * Description:
- *   Notify the send buffer semaphore
- *
- * Input Parameters:
- *   conn - The CAN connection of interest
- *
- * Assumptions:
- *   Called from user logic with the network locked.
- *
- ****************************************************************************/
-
-#if CONFIG_NET_SEND_BUFSIZE > 0
-void can_sendbuffer_notify(FAR struct can_conn_s *conn)
-{
-  int val = 0;
-
-  nxsem_get_value(&conn->sndsem, &val);
-  if (val < 1)
-    {
-      nxsem_post(&conn->sndsem);
-    }
-}
-
-#endif /* CONFIG_NET_SEND_BUFSIZE */
-
-#endif /* CONFIG_NET && CONFIG_NET_CAN */

Reply via email to