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