diff --git a/Documentation/components/drivers/character/can.rst b/Documentation/components/drivers/character/can.rst index d17643be2acc8..d5351c475bdef 100644 --- a/Documentation/components/drivers/character/can.rst +++ b/Documentation/components/drivers/character/can.rst @@ -2,8 +2,9 @@ CAN Drivers =========== -NuttX supports only a very low-level CAN driver. This driver -supports only the data exchange and does not include any +NuttX supports character device CAN a very low-level CAN driver and +SocketCAN as a more high level (and more overhead) option. +This driver supports only the data exchange and does not include any high-level CAN protocol. The NuttX CAN driver is split into two parts: diff --git a/Documentation/components/net/socketcan.rst b/Documentation/components/net/socketcan.rst index 6ca7ae759c9a6..4b2ec8521af95 100644 --- a/Documentation/components/net/socketcan.rst +++ b/Documentation/components/net/socketcan.rst @@ -1,4 +1,7 @@ -======================== +========= +SocketCAN +========= + SocketCAN Device Drivers ======================== @@ -7,7 +10,12 @@ SocketCAN Device Drivers The structure struct net_driver_s defines the interface and is passed to the network via ``netdev_register()``. -- ``include/nuttx/can.h``. CAN & CAN FD frame data structures. +- ``include/nuttx/can.h``. CAN & CAN FD frame data structures and dlc to len size + + .. code-block:: c + + uint8_t can_bytes2dlc(uint8_t nbytes); + uint8_t can_dlc2bytes(uint8_t dlc); - ``int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)'``. Each driver registers itself by calling ``netdev_register()``. @@ -15,11 +23,6 @@ SocketCAN Device Drivers - ``Include/nuttx/net/can.h``. contains lookup tables for CAN dlc to CAN FD len sizes named - .. code-block:: c - - extern const uint8_t g_can_dlc_to_len[16]; - extern const uint8_t g_len_to_can_dlc[65]; - - **Initialization sequence is as follows**. #. ``xxx_netinitialize(void)`` is called on startup of NuttX in this @@ -59,3 +62,87 @@ SocketCAN Device Drivers matches the size of a ``struct can_frame`` or ``struct canfd_frame`` then you cast the content of the ``net_driver_s.d_buf`` pointer to the correct CAN frame struct + +SocketCAN protocol stack +======================== + +SocketCAN is a CAN protocol stack implementation based on the BSD socket API, +providing a more standardized and flexible CAN communication interface. +SocketCAN uses the network protocol stack framework, allowing applications +to use standard socket system calls (such as ``socket()``, ``bind()``, +``send()``, ``recv()``, etc.) for CAN communication. + +Architecture +------------ + +The SocketCAN implementation follows the standard network layer hierarchy: + +#. **Application Layer Interface**: Uses standard socket API + (AF_CAN address family) +#. **Protocol Layer**: CAN protocol processing (located in ``net/can/``) +#. **Device Layer**: CAN network device drivers + +File Locations +-------------- + +Files supporting SocketCAN can be found in the following locations: + +- **Protocol Implementation**: The SocketCAN protocol stack is located in + the ``net/can/`` directory +- **Header File**: ``include/nuttx/net/can.h`` +- **Main Modules**: + + - ``can_conn.c`` - Connection management + - ``can_sockif.c`` - Socket interface implementation + - ``can_sendmsg.c`` - Message transmission + - ``can_sendmsg_buffered.c`` - Message transmission with buffering + - ``can_recvmsg.c`` - Message reception + - ``can_poll.c`` - Polling support + - ``can_callback.c`` - Callback handling + +Configuration Options +--------------------- + +To enable SocketCAN, configure the following options: + +- ``CONFIG_NET_CAN`` - Enable SocketCAN support +- ``CONFIG_NET_CAN_NOTIFIER`` - Enable CAN notifier (optional) +- ``CONFIG_NET_CAN_NBUFFERS`` - Number of CAN buffers +- ``CONFIG_NET_RECV_BUFSIZE`` - Receive buffer size + +Usage Notes +----------- + +SocketCAN uses the standard socket programming model: + +.. code-block:: c + + /* Create CAN socket */ + int sock = socket(AF_CAN, SOCK_RAW, CAN_RAW); + + /* Bind to CAN interface */ + struct sockaddr_can addr; + addr.can_family = AF_CAN; + addr.can_ifindex = if_nametoindex("can0"); + bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + + /* Send CAN frame */ + struct can_frame frame; + frame.can_id = 0x123; + frame.can_dlc = 8; + /* Fill data */ + send(sock, &frame, sizeof(frame), 0); + + /* Receive CAN frame */ + recv(sock, &frame, sizeof(frame), 0); + +Features +-------- + +- **Standard Socket API**: Uses familiar socket programming interface +- **Filtering Support**: Set CAN ID filters via socket options +- **Non-blocking I/O**: Supports non-blocking mode and polling +- **Multiple Connections**: Supports multiple sockets accessing the same CAN bus simultaneously +- **Read Buffering**: Supports data read buffering to prevent data loss +- **CAN FD Support**: Supports CAN FD frames if enabled in configuration +- **Extensible**: Easy to extend for additional CAN protocols diff --git a/net/Kconfig b/net/Kconfig index 1e158c9db4061..285078eab13bc 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -170,7 +170,7 @@ config NET_MAX_RECV_BUFSIZE config NET_SEND_BUFSIZE int "Net Default Send buffer size" - depends on NET_TCP_WRITE_BUFFERS || NET_UDP_WRITE_BUFFERS + depends on NET_TCP_WRITE_BUFFERS || NET_UDP_WRITE_BUFFERS || NET_CAN_WRITE_BUFFERS default 0 ---help--- This is the default value for send buffer size. diff --git a/net/can/CMakeLists.txt b/net/can/CMakeLists.txt index 1c02c53f88bdc..90f8d2fe23baf 100644 --- a/net/can/CMakeLists.txt +++ b/net/can/CMakeLists.txt @@ -23,7 +23,13 @@ if(CONFIG_NET_CAN) set(SRCS) # Socket layer - list(APPEND SRCS can_sockif.c can_sendmsg.c can_recvmsg.c) + list(APPEND SRCS can_sockif.c can_recvmsg.c) + + if(CONFIG_NET_CAN_WRITE_BUFFERS) + list(APPEND SRCS can_sendmsg_buffered.c) + else() + list(APPEND SRCS can_sendmsg.c) + endif() if(CONFIG_NET_CAN_NOTIFIER) list(APPEND SRCS can_notifier.c) diff --git a/net/can/Kconfig b/net/can/Kconfig index b24895fd1430a..49a8911d915aa 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -30,6 +30,17 @@ config NET_CAN_HAVE_ERRORS bool default n +config NET_CAN_WRITE_BUFFERS + bool "Enable CAN write buffering" + default n + select NTE_WRITE_BUFFERS + ---help--- + Write buffers allows buffering of ongoing CAN packets, providing + for higher performance, nonblocking output. + + You might want to disable CAN write buffering on a highly memory + memory constrained system where there are no performance issues. + config CAN_PREALLOC_CONNS int "Preallocated CAN socket connections" default 4 diff --git a/net/can/Make.defs b/net/can/Make.defs index 50dd7c9c9ea3e..f6f3ae61901e2 100644 --- a/net/can/Make.defs +++ b/net/can/Make.defs @@ -27,7 +27,12 @@ ifeq ($(CONFIG_NET_CAN),y) # Socket layer SOCK_CSRCS += can_sockif.c +ifeq ($(CONFIG_NET_CAN_WRITE_BUFFERS),y) +SOCK_CSRCS += can_sendmsg_buffered.c +else SOCK_CSRCS += can_sendmsg.c +endif + SOCK_CSRCS += can_recvmsg.c ifeq ($(CONFIG_NET_CAN_NOTIFIER),y) diff --git a/net/can/can.h b/net/can/can.h index df3d15c239151..feaec373a03bf 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -93,6 +93,25 @@ struct can_conn_s int32_t recv_buffnum; /* Recv buffer number */ #endif +#if CONFIG_NET_SEND_BUFSIZE > 0 + int32_t sndbufs; /* Maximum amount of bytes queued in send */ + sem_t sndsem; /* Semaphore signals send completion */ +#endif + +#ifdef CONFIG_NET_CAN_WRITE_BUFFERS + /* Write buffering + * + * write_q - The queue of unsent I/O buffers. The head of this + * list may be partially sent. FIFO ordering. + */ + + struct iob_queue_s write_q; /* Write buffering for can messages */ + + /* Callback instance for can send */ + + FAR struct devif_callback_s *sndcb; +#endif + /* CAN-specific content follows */ int16_t crefs; /* Reference count */ @@ -356,6 +375,24 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, void can_readahead_signal(FAR struct can_conn_s *conn); #endif +/**************************************************************************** + * 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); +#endif /* CONFIG_NET_SEND_BUFSIZE */ + /**************************************************************************** * Name: can_setsockopt * diff --git a/net/can/can_conn.c b/net/can/can_conn.c index fec70b616e041..3d0fe2f1fe5ae 100644 --- a/net/can/can_conn.c +++ b/net/can/can_conn.c @@ -152,6 +152,27 @@ void can_free(FAR struct can_conn_s *conn) dq_rem(&conn->sconn.node, &g_active_can_connections); +#ifdef CONFIG_NET_CAN_WRITE_BUFFERS + /* Free the write queue */ + + iob_free_queue(&conn->write_q); + +# if CONFIG_NET_SEND_BUFSIZE > 0 + /* Notify the send buffer available */ + + can_sendbuffer_notify(conn); +# endif /* CONFIG_NET_SEND_BUFSIZE */ + +#endif + +#if CONFIG_NET_SEND_BUFSIZE > 0 + nxsem_destroy(&conn->sndsem); +#endif + + /* Free the readahead queue */ + + iob_free_queue(&conn->readahead); + /* Free the connection. */ NET_BUFPOOL_FREE(g_can_connections, conn); @@ -203,7 +224,8 @@ FAR struct can_conn_s *can_active(FAR struct net_driver_s *dev, { while ((conn = can_nextconn(conn)) != NULL) { - if (conn->dev == NULL || conn->dev == dev) + if ((conn->dev == NULL && _SS_ISBOUND(conn->sconn.s_flags)) || + conn->dev == dev) { break; } diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c index 6d9f66c019dc4..6b2a1ae444ba0 100644 --- a/net/can/can_getsockopt.c +++ b/net/can/can_getsockopt.c @@ -185,6 +185,21 @@ int can_getsockopt(FAR struct socket *psock, int level, int option, break; #endif +#if CONFIG_NET_SEND_BUFSIZE > 0 + case SO_SNDBUF: + /* Verify that option is the size of an 'int'. Should also check + * that 'value' is properly aligned for an 'int' + */ + + if (*value_len < sizeof(int)) + { + return -EINVAL; + } + + *(FAR int *)value = conn->sndbufs; + break; +#endif + default: nerr("ERROR: Unrecognized RAW CAN socket option: %d\n", option); ret = -ENOPROTOOPT; diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index 9ec9dddbeece9..0ef861fd43ffb 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -564,6 +564,11 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, /* 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; diff --git a/net/can/can_sendmsg_buffered.c b/net/can/can_sendmsg_buffered.c new file mode 100644 index 0000000000000..8b2381f7b1862 --- /dev/null +++ b/net/can/can_sendmsg_buffered.c @@ -0,0 +1,481 @@ +/**************************************************************************** + * 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 +#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) && \ + defined(CONFIG_NET_CAN_WRITE_BUFFERS) + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "can/can.h" +#include "devif/devif.h" +#include "netdev/netdev.h" +#include "socket/socket.h" +#include "utils/utils.h" + +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_send_eventhandler + ****************************************************************************/ + +static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvpriv, uint16_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); + } + 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 struct msghdr *msg, + int flags) +{ + FAR struct net_driver_s *dev; + FAR struct can_conn_s *conn; + FAR struct iob_s *wb_iob; + bool empty; + bool nonblock; + int ret = OK; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (psock == NULL || psock->s_conn == NULL) + { + return -EBADF; + } + + /* 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 defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD) + if (_SO_GETOPT(conn->sconn.s_options, CAN_RAW_FD_FRAMES)) + { + if (msg->msg_iov->iov_len != CANFD_MTU && + msg->msg_iov->iov_len != CAN_MTU) + { + return -EINVAL; + } + } + else +#endif + { + if (msg->msg_iov->iov_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. + */ + + net_lock(); + +#if CONFIG_NET_SEND_BUFSIZE > 0 + if ((iob_get_queue_size(&conn->write_q) + msg->msg_iov->iov_len) > + conn->sndbufs) + { + /* send buffer size exceeds the send limit */ + + if (nonblock) + { + nerr("ERROR: Buffer overflow\n"); + ret = -EAGAIN; + goto errout_with_lock; + } + + ret = net_sem_timedwait_uninterruptible(&conn->sndsem, + _SO_TIMEOUT(conn->sconn.s_sndtimeo)); + if (ret < 0) + { + goto errout_with_lock; + } + } +#endif + + if (nonblock) + { + wb_iob = iob_tryalloc(false); + } + else + { + wb_iob = net_iobtimedalloc(true, _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); + + /* 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(wb_iob, (FAR uint8_t *)msg->msg_iov->iov_base, + msg->msg_iov->iov_len, 0, false); + } + else + { + unsigned int count; + int blresult; + + /* 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 + */ + + blresult = net_breaklock(&count); + ret = iob_copyin(wb_iob, (FAR uint8_t *)msg->msg_iov->iov_base, + msg->msg_iov->iov_len, 0, false); + if (blresult >= 0) + { + net_restorelock(count); + } + } + + if (ret < 0) + { + nerr("ERROR: Failed to copy data into write buffer\n"); + 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"); + return -ENOMEM; + } + + /* 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); + } + + net_unlock(); + + return msg->msg_iov->iov_len; + +errout_with_wrb: + iob_free_chain(wb_iob); + +errout_with_lock: + net_unlock(); + 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) +{ + /* 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 (iob_navail(false) <= 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 < 0) + { + nxsem_post(&conn->sndsem); + } +} + +#endif /* CONFIG_NET_SEND_BUFSIZE */ + +#endif /* CONFIG_NET && CONFIG_NET_CAN */ diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c index 66b4f8924c549..ffd203400015c 100644 --- a/net/can/can_setsockopt.c +++ b/net/can/can_setsockopt.c @@ -207,6 +207,35 @@ int can_setsockopt(FAR struct socket *psock, int level, int option, } #endif +#if CONFIG_NET_SEND_BUFSIZE > 0 + case SO_SNDBUF: + { + int buffersize; + + /* Verify options */ + + if (value_len != sizeof(int)) + { + return -EINVAL; + } + + buffersize = *(FAR int *)value; + if (buffersize < 0) + { + return -EINVAL; + } + +# if CONFIG_NET_MAX_SEND_BUFSIZE > 0 + /* Limit the size of the send buffer */ + + buffersize = MIN(buffersize, CONFIG_NET_MAX_SEND_BUFSIZE); +# endif + + conn->sndbufs = buffersize; + break; + } +#endif + default: nerr("ERROR: Unrecognized CAN option: %d\n", option); ret = -ENOPROTOOPT; diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c index ea050de375420..aebd83985ca9e 100644 --- a/net/can/can_sockif.c +++ b/net/can/can_sockif.c @@ -232,6 +232,11 @@ static int can_setup(FAR struct socket *psock) / CONFIG_IOB_BUFSIZE; #endif +#if CONFIG_NET_SEND_BUFSIZE > 0 + conn->sndbufs = CONFIG_NET_SEND_BUFSIZE; + nxsem_init(&conn->sndsem, 0, 0); +#endif + /* Attach the connection instance to the socket */ psock->s_conn = conn; @@ -340,7 +345,7 @@ static int can_bind(FAR struct socket *psock, conn->dev = netdev_findbyname((const char *)&netdev_name); #endif - return OK; + return conn->dev == NULL && canaddr->can_ifindex != 0 ? -ENODEV : OK; } /**************************************************************************** @@ -503,7 +508,15 @@ static int can_close(FAR struct socket *psock) { /* Yes... inform user-space daemon of socket close. */ - /* #warning Missing logic */ +#ifdef CONFIG_NET_CAN_WRITE_BUFFERS + /* Free write buffer callback. */ + + if (conn->sndcb != NULL) + { + can_callback_free(conn->dev, conn, conn->sndcb); + conn->sndcb = NULL; + } +#endif /* Free the connection structure */ diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index 6bccd8741a8ae..926a97db36cd9 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -887,6 +887,10 @@ void tcp_free(FAR struct tcp_conn_s *conn) #endif +#if CONFIG_NET_SEND_BUFSIZE > 0 + nxsem_destroy(&conn->snd_sem); +#endif + #ifdef CONFIG_NET_TCPBACKLOG /* Remove any backlog attached to this connection */ diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index e4c253e46e7a7..2b1d8fc51ae06 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -647,6 +647,10 @@ void udp_free(FAR struct udp_conn_s *conn) udp_sendbuffer_notify(conn); #endif /* CONFIG_NET_SEND_BUFSIZE */ +#endif + +#if CONFIG_NET_SEND_BUFSIZE > 0 + nxsem_destroy(&conn->sndsem); #endif /* Free the connection. */