This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit e2525f61b1e7635e4d660c5624ccf2e3f849ea56 Author: zhanghongyu <[email protected]> AuthorDate: Thu Apr 24 16:58:35 2025 +0800 net/pkt: add nonblock mode and send buffered support Supports more flexible configuration of sending methods Signed-off-by: zhanghongyu <[email protected]> --- net/pkt/CMakeLists.txt | 37 +- net/pkt/Kconfig | 12 + net/pkt/Make.defs | 9 +- net/pkt/pkt.h | 82 ++++ net/pkt/pkt_conn.c | 6 + net/pkt/pkt_getsockopt.c | 125 +++++++ net/pkt/pkt_netpoll.c | 9 + net/pkt/pkt_sendmsg_buffered.c | 412 +++++++++++++++++++++ .../{pkt_sendmsg.c => pkt_sendmsg_unbuffered.c} | 2 +- net/pkt/pkt_setsockopt.c | 133 +++++++ net/pkt/pkt_sockif.c | 40 +- net/socket/Kconfig | 6 + 12 files changed, 857 insertions(+), 16 deletions(-) diff --git a/net/pkt/CMakeLists.txt b/net/pkt/CMakeLists.txt index da3fac7dbe7..1481c6d76d3 100644 --- a/net/pkt/CMakeLists.txt +++ b/net/pkt/CMakeLists.txt @@ -23,17 +23,28 @@ # Packet socket support if(CONFIG_NET_PKT) - target_sources( - net - PRIVATE # Socket layer - pkt_sockif.c - pkt_sendmsg.c - pkt_recvmsg.c - # Transport layer - pkt_conn.c - pkt_input.c - pkt_callback.c - pkt_poll.c - pkt_netpoll.c - pkt_finddev.c) + + set(SRCS # Socket layer + pkt_sockif.c + pkt_recvmsg.c + # Transport layer + pkt_conn.c + pkt_input.c + pkt_callback.c + pkt_poll.c + pkt_netpoll.c + pkt_finddev.c) + + if(CONFIG_NET_PKT_WRITE_BUFFERS) + list(APPEND SRCS pkt_sendmsg_buffered.c) # Socket layer + else() + list(APPEND SRCS pkt_sendmsg_unbuffered.c) # Socket layer + + endif() + + if(CONFIG_NET_PKTPROTO_OPTIONS) + list(APPEND SRCS pkt_setsockopt.c pkt_getsockopt.c) # Socket layer + endif() + + target_sources(net PRIVATE ${SRCS}) endif() diff --git a/net/pkt/Kconfig b/net/pkt/Kconfig index 9e012c7bc12..acecd593f29 100644 --- a/net/pkt/Kconfig +++ b/net/pkt/Kconfig @@ -20,6 +20,18 @@ config NET_PKT if NET_PKT +config NET_PKT_WRITE_BUFFERS + bool "Enable PKT write buffering" + default n + select NET_WRITE_BUFFERS + select NET_PKTPROTO_OPTIONS + ---help--- + Write buffers allows buffering of ongoing PKT packets, providing + for higher performance, nonblocking output. + + You might want to disable PKT write buffering on a highly memory + memory constrained system where there are no performance issues. + config NET_PKT_PREALLOC_CONNS int "Preallocated packet sockets" default 1 diff --git a/net/pkt/Make.defs b/net/pkt/Make.defs index 6d846c2489b..f9d9c215d91 100644 --- a/net/pkt/Make.defs +++ b/net/pkt/Make.defs @@ -27,8 +27,15 @@ ifeq ($(CONFIG_NET_PKT),y) # Socket layer SOCK_CSRCS += pkt_sockif.c -SOCK_CSRCS += pkt_sendmsg.c +ifeq ($(CONFIG_NET_PKT_WRITE_BUFFERS),y) +SOCK_CSRCS += pkt_sendmsg_buffered.c +else +SOCK_CSRCS += pkt_sendmsg_unbuffered.c +endif SOCK_CSRCS += pkt_recvmsg.c +ifeq ($(CONFIG_NET_PKTPROTO_OPTIONS),y) +SOCK_CSRCS += pkt_setsockopt.c pkt_getsockopt.c +endif # Transport layer diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h index ab866c21336..999358b067b 100644 --- a/net/pkt/pkt.h +++ b/net/pkt/pkt.h @@ -76,6 +76,25 @@ struct pkt_conn_s uint8_t crefs; /* Reference counts on this instance */ uint16_t type; /* The Ethernet type of the packet */ +#ifdef CONFIG_NET_PKT_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 pkt messages */ + + /* Callback instance for pkt send */ + + FAR struct devif_callback_s *sndcb; +# if CONFIG_NET_SEND_BUFSIZE > 0 + int32_t sndbufs; /* Maximum amount of bytes queued in send */ + sem_t sndsem; /* Semaphore signals send completion */ +# endif + +#endif + /* Read-ahead buffering. * * readahead - A singly linked list of type struct iob_qentry_s @@ -347,6 +366,69 @@ int pkt_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds); ssize_t pkt_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, int flags); +#ifdef CONFIG_NET_PKTPROTO_OPTIONS +/**************************************************************************** + * Name: pkt_getsockopt + * + * Description: + * pkt_getsockopt() retrieves the value for the option specified by the + * 'option' argument for the socket specified by the 'psock' argument. If + * the size of the option value is greater than 'value_len', the value + * stored in the object pointed to by the 'value' argument will be silently + * truncated. Otherwise, the length pointed to by the 'value_len' argument + * will be modified to indicate the actual length of the 'value'. + * + * See <sys/socket.h> a complete list of values for the socket-level + * 'option' argument. Protocol-specific options are are protocol specific + * header files (such as nuttx/pkt.h for the case of the PKT protocol). + * + * Input Parameters: + * psock Socket structure of the socket to query + * level Protocol level to set the option + * option identifies the option to get + * value Points to the argument value + * value_len The length of the argument value + * + * Returned Value: + * Returns zero (OK) on success. On failure, it returns a negated errno + * value to indicate the nature of the error. See psock_getsockopt() for + * the complete list of appropriate return error codes. + * + ****************************************************************************/ + +int pkt_getsockopt(FAR struct socket *psock, int level, int option, + FAR void *value, FAR socklen_t *value_len); + +/**************************************************************************** + * Name: pkt_setsockopt + * + * Description: + * pkt_setsockopt() sets the PKT-protocol option specified by the + * 'option' argument to the value pointed to by the 'value' argument for + * the socket specified by the 'psock' argument. + * + * See <nuttx/pkt.h> for the a complete list of values of PKT protocol + * options. + * + * Input Parameters: + * psock Socket structure of socket to operate on + * level Protocol level to set the option + * option identifies the option to set + * value Points to the argument value + * value_len The length of the argument value + * + * Returned Value: + * Returns zero (OK) on success. On failure, it returns a negated errno + * value to indicate the nature of the error. See psock_setcockopt() for + * the list of possible error values. + * + ****************************************************************************/ + +int pkt_setsockopt(FAR struct socket *psock, int level, int option, + FAR const void *value, socklen_t value_len); + +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/net/pkt/pkt_conn.c b/net/pkt/pkt_conn.c index 9387cd961f5..168080cfdc1 100644 --- a/net/pkt/pkt_conn.c +++ b/net/pkt/pkt_conn.c @@ -139,6 +139,12 @@ void pkt_free(FAR struct pkt_conn_s *conn) dq_rem(&conn->sconn.node, &g_active_pkt_connections); +#ifdef CONFIG_NET_CAN_WRITE_BUFFERS + /* Free the write queue */ + + iob_free_queue(&conn->write_q); +#endif + /* Free the connection. */ NET_BUFPOOL_FREE(g_pkt_connections, conn); diff --git a/net/pkt/pkt_getsockopt.c b/net/pkt/pkt_getsockopt.c new file mode 100644 index 00000000000..3ca9265adff --- /dev/null +++ b/net/pkt/pkt_getsockopt.c @@ -0,0 +1,125 @@ +/**************************************************************************** + * net/pkt/pkt_getsockopt.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> + +#include <sys/time.h> +#include <stdint.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/net/net.h> +#include <nuttx/net/pkt.h> + +#include "socket/socket.h" +#include "utils/utils.h" +#include "pkt/pkt.h" + +#ifdef CONFIG_NET_PKTPROTO_OPTIONS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pkt_getsockopt + * + * Description: + * pkt_getsockopt() retrieves the value for the option specified by the + * 'option' argument for the socket specified by the 'psock' argument. If + * the size of the option value is greater than 'value_len', the value + * stored in the object pointed to by the 'value' argument will be silently + * truncated. Otherwise, the length pointed to by the 'value_len' argument + * will be modified to indicate the actual length of the 'value'. + * + * See <sys/socket.h> a complete list of values for the socket-level + * 'option' argument. Protocol-specific options are are protocol specific + * header files (such as nuttx/pkt.h for the case of the PKT protocol). + * + * Input Parameters: + * psock Socket structure of the socket to query + * level Protocol level to set the option + * option identifies the option to get + * value Points to the argument value + * value_len The length of the argument value + * + * Returned Value: + * Returns zero (OK) on success. On failure, it returns a negated errno + * value to indicate the nature of the error. See psock_getsockopt() for + * the complete list of appropriate return error codes. + * + ****************************************************************************/ + +int pkt_getsockopt(FAR struct socket *psock, int level, int option, + FAR void *value, FAR socklen_t *value_len) +{ + int ret = OK; + + DEBUGASSERT(value != NULL && value_len != NULL); + + if (level != SOL_PACKET) + { + return -ENOPROTOOPT; + } + + if (psock->s_type != SOCK_RAW) + { + nerr("ERROR: Not a RAW PKT socket\n"); + return -ENOTCONN; + } + + switch (option) + { +#if CONFIG_NET_SEND_BUFSIZE > 0 + case SO_SNDBUF: + { + FAR struct pkt_conn_s *conn; + conn = psock->s_conn; + /* 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 PKT socket option: %d\n", option); + ret = -ENOPROTOOPT; + break; + } + + return ret; +} + +#endif /* CONFIG_NET_PKTPROTO_OPTIONS */ diff --git a/net/pkt/pkt_netpoll.c b/net/pkt/pkt_netpoll.c index 114a40184c1..652848acea4 100644 --- a/net/pkt/pkt_netpoll.c +++ b/net/pkt/pkt_netpoll.c @@ -65,6 +65,15 @@ static int psock_pkt_cansend(FAR struct pkt_conn_s *conn) { + if (iob_navail(false) <= 0 +#if defined(CONFIG_NET_PKT_WRITE_BUFFERS) && CONFIG_NET_SEND_BUFSIZE > 0 + || iob_get_queue_size(&conn->write_q) >= conn->sndbufs +#endif + ) + { + return -EWOULDBLOCK; + } + return OK; } diff --git a/net/pkt/pkt_sendmsg_buffered.c b/net/pkt/pkt_sendmsg_buffered.c new file mode 100644 index 00000000000..4a84d6feee3 --- /dev/null +++ b/net/pkt/pkt_sendmsg_buffered.c @@ -0,0 +1,412 @@ +/**************************************************************************** + * net/pkt/pkt_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> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <arch/irq.h> + +#include <nuttx/semaphore.h> +#include <nuttx/net/netdev.h> +#include <nuttx/net/net.h> +#include <nuttx/net/ip.h> + +#include "devif/devif.h" +#include "netdev/netdev.h" +#include "socket/socket.h" +#include "utils/utils.h" +#include "pkt/pkt.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pkt_sendbuffer_notify + * + * Description: + * Notify the send buffer semaphore + * + * Input Parameters: + * conn - The PKT connection of interest + * + * Assumptions: + * Called from user logic with the network locked. + * + ****************************************************************************/ + +#if CONFIG_NET_SEND_BUFSIZE > 0 +static void pkt_sendbuffer_notify(FAR struct pkt_conn_s *conn) +{ + int val = 0; + + nxsem_get_value(&conn->sndsem, &val); + if (val < 0) + { + nxsem_post(&conn->sndsem); + } +} +#endif + +/**************************************************************************** + * Name: psock_send_eventhandler + ****************************************************************************/ + +static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct pkt_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 & PKT_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 *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. + */ + + iob = iob_remove_queue(&conn->write_q); + DEBUGASSERT(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, iob); + conn->pendiob = 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 = iob->io_pktlen; + ninfo("wrb=%p sndlen=%d\n", 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 &= ~PKT_POLL; + +#if CONFIG_NET_SEND_BUFSIZE > 0 + pkt_sendbuffer_notify(conn); +#endif + } + + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pkt_sendmsg + * + * Description: + * The pkt_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 Message to send + * flags Send flags + * + * Returned Value: + * On success, returns the number of characters sent. On error, a negated + * errno value is returned (see sendmsg() for the complete list of return + * values. + * + ****************************************************************************/ + +ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, + int flags) +{ + FAR const void *buf = msg->msg_iov->iov_base; + size_t len = msg->msg_iov->iov_len; + FAR struct net_driver_s *dev; + FAR struct pkt_conn_s *conn; + FAR struct iob_s *iob; + bool nonblock; + int ret = OK; + + /* Validity check, only single iov supported */ + + if (msg->msg_iovlen != 1) + { + return -ENOTSUP; + } + + if (msg->msg_name != NULL) + { + /* pkt_sendto */ + + nerr("ERROR: sendto() not supported for raw packet sockets\n"); + return -EAFNOSUPPORT; + } + + /* 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; + } + + if (len <= 0) + { + return 0; + } + + net_lock(); + + /* Get the device driver that will service this transfer */ + + dev = pkt_find_device(psock->s_conn); + if (dev == NULL) + { + ret = -ENODEV; + goto errout_with_lock; + } + + conn = psock->s_conn; + nonblock = _SS_ISNONBLOCK(conn->sconn.s_flags) || + (flags & MSG_DONTWAIT) != 0; + +#if CONFIG_NET_SEND_BUFSIZE > 0 + if ((iob_get_queue_size(&conn->write_q) + 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) + { + iob = iob_tryalloc(false); + } + else + { + iob = net_iobtimedalloc(true, _SO_TIMEOUT(conn->sconn.s_sndtimeo)); + } + + if (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(iob, CONFIG_NET_LL_GUARDSIZE); + iob_update_pktlen(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(iob, buf, len, -NET_LL_HDRLEN(dev), 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(iob, buf, len, -NET_LL_HDRLEN(dev), false); + if (blresult >= 0) + { + net_restorelock(count); + } + } + + if (ret < 0) + { + nerr("ERROR: Failed to copy data into write buffer\n"); + goto errout_with_iob; + } + + if (nonblock) + { + ret = iob_tryadd_queue(iob, &conn->write_q); + } + else + { + ret = iob_add_queue(iob, &conn->write_q); + } + + if (ret < 0) + { + nerr("ERROR: Failed to add buffer to w_queue\n"); + goto errout_with_iob; + } + + /* Allocate resource to receive a callback */ + + if (conn->sndcb == NULL) + { + conn->sndcb = pkt_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_iob; + } + else + { + /* Set up the callback in the connection */ + + conn->sndcb->flags = PKT_POLL; + conn->sndcb->priv = conn; + conn->sndcb->event = psock_send_eventhandler; + + /* Notify the device driver that new TX data is available. */ + + netdev_txnotify_dev(dev); + } + + net_unlock(); + + return len; + +errout_with_iob: + iob_free_chain(iob); + +errout_with_lock: + net_unlock(); + + return ret; +} diff --git a/net/pkt/pkt_sendmsg.c b/net/pkt/pkt_sendmsg_unbuffered.c similarity index 99% rename from net/pkt/pkt_sendmsg.c rename to net/pkt/pkt_sendmsg_unbuffered.c index 7d153d67cf8..b7d7bb510b4 100644 --- a/net/pkt/pkt_sendmsg.c +++ b/net/pkt/pkt_sendmsg_unbuffered.c @@ -1,5 +1,5 @@ /**************************************************************************** - * net/pkt/pkt_sendmsg.c + * net/pkt/pkt_sendmsg_unbuffered.c * * SPDX-License-Identifier: Apache-2.0 * diff --git a/net/pkt/pkt_setsockopt.c b/net/pkt/pkt_setsockopt.c new file mode 100644 index 00000000000..9c340117404 --- /dev/null +++ b/net/pkt/pkt_setsockopt.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * net/pkt/pkt_setsockopt.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> + +#include <sys/time.h> +#include <stdint.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/net/net.h> +#include <nuttx/net/pkt.h> + +#include "socket/socket.h" +#include "utils/utils.h" +#include "pkt/pkt.h" + +#ifdef CONFIG_NET_PKTPROTO_OPTIONS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pkt_setsockopt + * + * Description: + * pkt_setsockopt() sets the PKT-protocol option specified by the + * 'option' argument to the value pointed to by the 'value' argument for + * the socket specified by the 'psock' argument. + * + * See <nuttx/pkt.h> for the a complete list of values of PKT protocol + * options. + * + * Input Parameters: + * psock Socket structure of socket to operate on + * level Protocol level to set the option + * option identifies the option to set + * value Points to the argument value + * value_len The length of the argument value + * + * Returned Value: + * Returns zero (OK) on success. On failure, it returns a negated errno + * value to indicate the nature of the error. See psock_setcockopt() for + * the list of possible error values. + * + ****************************************************************************/ + +int pkt_setsockopt(FAR struct socket *psock, int level, int option, + FAR const void *value, socklen_t value_len) +{ + int ret = OK; + + DEBUGASSERT(value_len == 0 || value != NULL); + + if (level != SOL_PACKET) + { + return -ENOPROTOOPT; + } + + if (psock->s_type != SOCK_RAW) + { + nerr("ERROR: Not a RAW PKT socket\n"); + return -ENOTCONN; + } + + switch (option) + { +#if CONFIG_NET_SEND_BUFSIZE > 0 + case SO_SNDBUF: + { + FAR struct pkt_conn_s *conn; + conn = psock->s_conn; + 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 PKT option: %d\n", option); + ret = -ENOPROTOOPT; + break; + } + + return ret; +} + +#endif /* CONFIG_NET_PKTPROTO_OPTIONS */ diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index be401da804f..fef6470296d 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -39,6 +39,7 @@ #include <nuttx/net/net.h> #include <nuttx/net/netdev.h> +#include "devif/devif.h" #include "netdev/netdev.h" #include <socket/socket.h> #include "pkt/pkt.h" @@ -77,7 +78,14 @@ const struct sock_intf_s g_pkt_sockif = pkt_netpoll, /* si_poll */ pkt_sendmsg, /* si_sendmsg */ pkt_recvmsg, /* si_recvmsg */ - pkt_close /* si_close */ + pkt_close, /* si_close */ + NULL, /* si_ioctl */ + NULL, /* si_socketpair */ + NULL /* si_shutdown */ +#if defined(CONFIG_NET_SOCKOPTS) && defined(CONFIG_NET_PKTPROTO_OPTIONS) + , pkt_getsockopt /* si_getsockopt */ + , pkt_setsockopt /* si_setsockopt */ +#endif }; /**************************************************************************** @@ -117,6 +125,11 @@ static int pkt_sockif_alloc(FAR struct socket *psock) conn->type = psock->s_proto; +#if defined(CONFIG_NET_PKT_WRITE_BUFFERS) && CONFIG_NET_SEND_BUFSIZE > 0 + conn->sndbufs = CONFIG_NET_SEND_BUFSIZE; + nxsem_init(&conn->sndsem, 0, 0); +#endif + /* Save the pre-allocated connection in the socket structure */ psock->s_conn = conn; @@ -347,6 +360,31 @@ static int pkt_close(FAR struct socket *psock) iob_free_queue(&conn->readahead); +#ifdef CONFIG_NET_PKT_WRITE_BUFFERS + /* Free write buffer callback. */ + + if (conn->sndcb != NULL) + { + FAR struct net_driver_s *dev; + int ret; + + while (iob_get_queue_entry_count(&conn->write_q) != 0) + { + ret = net_sem_timedwait_uninterruptible(&conn->sndsem, + _SO_TIMEOUT(conn->sconn.s_sndtimeo)); + if (ret < 0) + { + break; + } + } + + dev = pkt_find_device(conn); + + pkt_callback_free(dev, conn, conn->sndcb); + conn->sndcb = NULL; + } +#endif + /* Then free the connection structure */ conn->crefs = 0; /* No more references on the connection */ diff --git a/net/socket/Kconfig b/net/socket/Kconfig index c05b90ad1cb..fb62b24eb9c 100644 --- a/net/socket/Kconfig +++ b/net/socket/Kconfig @@ -60,6 +60,12 @@ config NET_CANPROTO_OPTIONS ---help--- Enable or disable support for CAN protocol level socket option +config NET_PKTPROTO_OPTIONS + bool + default n + ---help--- + Enable or disable support for PKT protocol level socket option + if NET_SOCKOPTS config NET_SOLINGER
