From a28ba05b526038c52068ea183b00cb45ccc3dd67 Mon Sep 17 00:00:00 2001 From: OceanfromXiaomi Date: Tue, 14 Oct 2025 17:10:00 +0800 Subject: [PATCH 01/10] net: move rx timestamp from d_rxtime to iob_s.io_time Move RX timestamp storage from net_driver_s.d_rxtime into iob_s.io_time so each IOB carries its own timestamp through the stack. Remove old iob_trycopyin/iob_copyout timestamp packing in CAN/PKT/UDP paths. Fix iob_clone_partial to copy io_time before source pointer advances to NULL. Signed-off-by: OceanfromXiaomi Signed-off-by: wenquan1 --- .../arm/imx9/imx95-evk/configs/can/defconfig | 1 - include/nuttx/mm/iob.h | 14 +++++++++ include/nuttx/net/netdev.h | 5 ++-- mm/iob/iob_clone.c | 4 +++ net/Kconfig | 1 - net/can/can_bufpool.c | 8 ----- net/can/can_callback.c | 29 ------------------- net/can/can_input.c | 6 ++++ net/can/can_recvmsg.c | 22 +++++++------- net/devif/ipv4_input.c | 12 ++++---- net/devif/ipv6_input.c | 12 ++++---- net/netdev/netdev_input.c | 4 +++ net/pkt/pkt_input.c | 18 +----------- net/pkt/pkt_recvmsg.c | 10 ++----- net/udp/udp_callback.c | 16 ---------- net/udp/udp_recvfrom.c | 11 ++----- 16 files changed, 58 insertions(+), 115 deletions(-) diff --git a/boards/arm/imx9/imx95-evk/configs/can/defconfig b/boards/arm/imx9/imx95-evk/configs/can/defconfig index fb147108d64f1..6b14202f5b98a 100644 --- a/boards/arm/imx9/imx95-evk/configs/can/defconfig +++ b/boards/arm/imx9/imx95-evk/configs/can/defconfig @@ -62,7 +62,6 @@ CONFIG_NET_CAN_EXTID=y CONFIG_NET_CAN_NOTIFIER=y CONFIG_NET_CAN_RAW_TX_DEADLINE=y CONFIG_NET_CAN_SOCK_OPTS=y -CONFIG_NET_LL_GUARDSIZE=14 CONFIG_NET_TIMESTAMP=y CONFIG_NSH_BUILTIN_APPS=y CONFIG_NSH_FILEIOSIZE=512 diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h index 4c3c2710264ae..a32c5090bcae9 100644 --- a/include/nuttx/mm/iob.h +++ b/include/nuttx/mm/iob.h @@ -37,6 +37,10 @@ # include #endif +#ifdef CONFIG_NET_TIMESTAMP +# include +#endif + #ifdef CONFIG_MM_IOB /**************************************************************************** @@ -126,6 +130,16 @@ struct iob_s #endif unsigned int io_pktlen; /* Total length of the packet */ +#ifdef CONFIG_NET_TIMESTAMP + /* timestamp of the packet. + * If CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP is true, the timestamp is provided + * by hardware driver. Otherwise it is filled in by kernel when the packet + * is passed into respective protocol layer. The timestamp is in + * CLOCK_REALTIME. + */ + + struct timespec io_time; +#endif #ifdef CONFIG_IOB_ALLOC iob_free_cb_t io_free; /* Custom free callback */ FAR uint8_t *io_data; diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 23a3f2f5e5d8a..ca68c30eaaf92 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -527,9 +527,10 @@ struct net_driver_s /* Reception timestamp of packet being currently processed. * If CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP is true, the timestamp is provided * by hardware driver. Otherwise it is filled in by kernel when packet - * enters ipv4_input or ipv6_input. + * enters ipv4_input or ipv6_input. The timestamp is in CLOCK_REALTIME. * - * The timestamp is in CLOCK_REALTIME. + * d_rxtime is serviced for older netdev driver. + * d_rxtime will be replaced by iob->io_tstamp in net stack. */ struct timespec d_rxtime; diff --git a/mm/iob/iob_clone.c b/mm/iob/iob_clone.c index 3438a1b1097b5..86316bc4519a6 100644 --- a/mm/iob/iob_clone.c +++ b/mm/iob/iob_clone.c @@ -127,6 +127,10 @@ int iob_clone_partial(FAR struct iob_s *iob1, unsigned int len, iob2->io_pktlen = len + offset2; +#ifdef CONFIG_NET_TIMESTAMP + iob2->io_time = iob1->io_time; +#endif + /* Handle special case where there are empty buffers at the head * the list, Skip I/O buffer containing the data offset. */ diff --git a/net/Kconfig b/net/Kconfig index b561b3f8fcc5b..26d55b7a87eb2 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -139,7 +139,6 @@ config NET_LL_GUARDSIZE int "Data Link Layer(L2) Guard size of Network buffer(IOB)" default 50 if RNDIS default 18 if NET_VLAN - default 16 if NET_CAN && NET_TIMESTAMP default 14 if NET_ETHERNET default 0 ---help--- diff --git a/net/can/can_bufpool.c b/net/can/can_bufpool.c index a6b2b47f909d3..a5140a7d80bff 100644 --- a/net/can/can_bufpool.c +++ b/net/can/can_bufpool.c @@ -36,14 +36,9 @@ * Pre-processor Definitions ****************************************************************************/ -#ifdef CONFIG_NET_TIMESTAMP # define CAN_BUFFER_SIZE ALIGN_UP(sizeof(struct iob_s) + NET_CAN_PKTSIZE + \ CONFIG_NET_LL_GUARDSIZE + IOB_ALIGNMENT - \ 1, IOB_ALIGNMENT) -#else -# define CAN_BUFFER_SIZE ALIGN_UP(sizeof(struct iob_s) + NET_CAN_PKTSIZE + \ - IOB_ALIGNMENT - 1, IOB_ALIGNMENT) -#endif /**************************************************************************** * Private Data @@ -117,10 +112,7 @@ FAR struct iob_s *can_iob_clone(FAR struct net_driver_s *dev) return NULL; } -#ifdef CONFIG_NET_TIMESTAMP iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE); -#endif - /* CAN data length is fixed, So when we use iob_clone_partial to copy * data, we don't have to worry about distributing other iob. */ diff --git a/net/can/can_callback.c b/net/can/can_callback.c index b06302e0e6c14..c5c072d143ab7 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -70,10 +70,6 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn, int recvlen; uint32_t ret; -#ifdef CONFIG_NET_TIMESTAMP - buflen -= sizeof(struct timeval); -#endif - ret = (flags & ~CAN_NEWDATA); /* Save as the packet data as in the read-ahead buffer. NOTE that @@ -126,31 +122,6 @@ uint32_t can_callback(FAR struct net_driver_s *dev, if (conn) { -#ifdef CONFIG_NET_TIMESTAMP - /* TIMESTAMP sockopt is activated, - * create timestamp and copy to iob - */ - - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && - (dev->d_iob != NULL)) - { - struct timeval tv; - FAR struct timespec *ts = (FAR struct timespec *)&tv; - int len; - - clock_systime_timespec(ts); - tv.tv_usec = ts->tv_nsec / 1000; - - len = iob_trycopyin(dev->d_iob, (FAR uint8_t *)&tv, - sizeof(struct timeval), - -CONFIG_NET_LL_GUARDSIZE, false); - if (len == sizeof(struct timeval)) - { - dev->d_len += len; - } - } -#endif - conn_lock(&conn->sconn); flags = devif_conn_event(dev, flags, conn->sconn.list); diff --git a/net/can/can_input.c b/net/can/can_input.c index a2c2b497f1760..f1cd561df6646 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -229,6 +229,12 @@ static int can_in(FAR struct net_driver_s *dev) return OK; } + /* Store reception timestamp if enabled and not provided by hardware. */ + +#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); +#endif + can_conn_list_lock(); /* Do we have second connection that can hold this packet? */ diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index 0a26ea283449d..82fdb3a1f5192 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -135,8 +135,11 @@ static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev, if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && pstate->pr_msglen == sizeof(struct timeval)) { - iob_copyout(pstate->pr_msgbuf, dev->d_iob, sizeof(struct timeval), - -CONFIG_NET_LL_GUARDSIZE); + struct timeval tv; + + tv.tv_sec = dev->d_iob->io_time.tv_sec; + tv.tv_usec = dev->d_iob->io_time.tv_nsec / 1000; + memcpy(pstate->pr_msgbuf, &tv, sizeof(struct timeval)); } #endif @@ -249,8 +252,11 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && pstate->pr_msglen == sizeof(struct timeval)) { - iob_copyout(pstate->pr_msgbuf, iob, sizeof(struct timeval), - -CONFIG_NET_LL_GUARDSIZE); + struct timeval tv; + + tv.tv_sec = iob->io_time.tv_sec; + tv.tv_usec = iob->io_time.tv_nsec / 1000; + memcpy(pstate->pr_msgbuf, &tv, sizeof(struct timeval)); } #endif @@ -309,15 +315,7 @@ static uint32_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev, if (!_SO_GETOPT(conn->sconn.s_options, CAN_RAW_FD_FRAMES)) #endif { -#ifdef CONFIG_NET_TIMESTAMP - if ((_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && - dev->d_len > sizeof(struct can_frame) + - sizeof(struct timeval)) || - (!_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && - dev->d_len > sizeof(struct can_frame))) -#else if (dev->d_len > sizeof(struct can_frame)) -#endif { /* DO WE NEED TO CLEAR FLAGS?? */ diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index eb880ad2e901c..b94c4c53ba4a9 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -231,6 +231,12 @@ static int ipv4_in(FAR struct net_driver_s *dev) bool isfrag; int ret = OK; + /* Store reception timestamp if enabled and not provided by hardware. */ + +#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); +#endif + /* Handle ARP on input then give the IPv4 packet to the network layer */ arp_ipin(dev); @@ -573,12 +579,6 @@ int ipv4_input(FAR struct net_driver_s *dev) netdev_lock(dev); - /* Store reception timestamp if enabled and not provided by hardware. */ - -#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - clock_gettime(CLOCK_REALTIME, &dev->d_rxtime); -#endif - if (dev->d_iob != NULL) { buf = dev->d_buf; diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 3400fdebd7906..065c5873341a3 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -229,6 +229,12 @@ static int ipv6_in(FAR struct net_driver_s *dev) bool isfrag = false; #endif + /* Store reception timestamp if enabled and not provided by hardware. */ + +#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); +#endif + /* This is where the input processing starts. */ #ifdef CONFIG_NET_STATISTICS @@ -706,12 +712,6 @@ int ipv6_input(FAR struct net_driver_s *dev) netdev_lock(dev); - /* Store reception timestamp if enabled and not provided by hardware. */ - -#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - clock_gettime(CLOCK_REALTIME, &dev->d_rxtime); -#endif - if (dev->d_iob != NULL) { buf = dev->d_buf; diff --git a/net/netdev/netdev_input.c b/net/netdev/netdev_input.c index 6554e11520d8b..05882f5d9d79d 100644 --- a/net/netdev/netdev_input.c +++ b/net/netdev/netdev_input.c @@ -80,6 +80,10 @@ int netdev_input(FAR struct net_driver_s *dev, return ret; } +#if defined(CONFIG_NET_TIMESTAMP) && defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) + dev->d_iob->io_time = dev->d_rxtime; +#endif + /* Copy data to iob entry */ ret = iob_trycopyin(dev->d_iob, buf, dev->d_len, -llhdrlen, false); diff --git a/net/pkt/pkt_input.c b/net/pkt/pkt_input.c index 5840d246a700e..07e4b274f01f4 100644 --- a/net/pkt/pkt_input.c +++ b/net/pkt/pkt_input.c @@ -70,22 +70,6 @@ static uint16_t pkt_datahandler(FAR struct net_driver_s *dev, return 0; } -#ifdef CONFIG_NET_TIMESTAMP - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || - _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS)) - { - ret = iob_trycopyin(iob, (FAR const uint8_t *)&dev->d_rxtime, - sizeof(struct timespec), 0, true); - if (ret != sizeof(struct timespec)) - { - nerr("ERROR: Failed to write timestamp: %d\n", ret); - goto errout; - } - - iob_reserve(iob, sizeof(struct timespec)); - } -#endif - /* Clone an I/O buffer chain of the L2 data, use throttled IOB to avoid * overconsumption. * TODO: Optimize IOB clone after we support shared IOB. @@ -177,7 +161,7 @@ static int pkt_in(FAR struct net_driver_s *dev) if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS)) { - clock_gettime(CLOCK_REALTIME, &dev->d_rxtime); + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); } #endif /* CONFIG_NET_TIMESTAMP */ diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index 531e48e9183d4..79489a9ca496d 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -163,7 +163,7 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev, if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMP) || _SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS)) { - pkt_store_cmsg_timestamp(pstate, &dev->d_rxtime); + pkt_store_cmsg_timestamp(pstate, &dev->d_iob->io_time); } #endif @@ -392,13 +392,7 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS)) { - struct timespec ts; - recvlen = iob_copyout((FAR uint8_t *)&ts, iob, - sizeof(struct timespec), - -sizeof(struct timespec)); - DEBUGASSERT(recvlen == sizeof(struct timespec)); - - pkt_store_cmsg_timestamp(pstate, &ts); + pkt_store_cmsg_timestamp(pstate, &iob->io_time); } #endif diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c index 1eae4b81d10c0..58f872cf4f9b2 100644 --- a/net/udp/udp_callback.c +++ b/net/udp/udp_callback.c @@ -159,22 +159,6 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev, */ offset = (dev->d_appdata - iob->io_data) - iob->io_offset; - -#ifdef CONFIG_NET_TIMESTAMP - /* Store timestamp while packet is being queued. - * This is done unconditionally to avoid race condition when SO_TIMESTAMP - * gets enabled after packet is received but before it is read. - */ - - offset -= sizeof(struct timespec); - ret = iob_trycopyin(iob, (FAR const uint8_t *)&dev->d_rxtime, - sizeof(struct timespec), offset, true); - if (ret < 0) - { - goto errout; - } -#endif - offset -= src_addr_size; ret = iob_trycopyin(iob, src_addr, src_addr_size, offset, true); if (ret < 0) diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c index 66a4d8810faf6..3514069fd07b2 100644 --- a/net/udp/udp_recvfrom.c +++ b/net/udp/udp_recvfrom.c @@ -224,15 +224,8 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate) if (conn->timestamp) { - struct timespec timestamp; - recvlen = iob_copyout((FAR uint8_t *)×tamp, iob, - sizeof(struct timespec), offset); - DEBUGASSERT(recvlen == sizeof(struct timespec)); - - udp_store_cmsg_timestamp(pstate, ×tamp); + udp_store_cmsg_timestamp(pstate, &iob->io_time); } - - offset += sizeof(struct timespec); #endif /* Copy to user */ @@ -472,7 +465,7 @@ static uint32_t udp_eventhandler(FAR struct net_driver_s *dev, #ifdef CONFIG_NET_TIMESTAMP if (pstate->ir_conn->timestamp) { - udp_store_cmsg_timestamp(pstate, &dev->d_rxtime); + udp_store_cmsg_timestamp(pstate, &dev->d_iob->io_time); } #endif From 10713c018d4b7bad71787fdf5078203d4166bb89 Mon Sep 17 00:00:00 2001 From: OceanfromXiaomi Date: Thu, 27 Nov 2025 12:03:31 +0800 Subject: [PATCH 02/10] net/utils: extract cmsg_store_timestamp helper Extract a common cmsg_store_timestamp() helper that checks SO_TIMESTAMP/SO_TIMESTAMPNS via s_options and appends the appropriate cmsg. Replaces per-protocol timestamp formatting in CAN, PKT, and UDP receive paths. Signed-off-by: OceanfromXiaomi --- net/can/can_recvmsg.c | 106 +++++++++++++++++++---------------------- net/pkt/pkt_recvmsg.c | 60 ++--------------------- net/udp/udp_recvfrom.c | 19 ++------ net/utils/net_cmsg.c | 37 +++++++++++++- net/utils/utils.h | 22 ++++++++- 5 files changed, 114 insertions(+), 130 deletions(-) diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index 82fdb3a1f5192..8dd4879ab3c14 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -63,12 +63,9 @@ struct can_recvfrom_s { FAR struct can_conn_s *pr_conn; /* Connection associated with the socket */ FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */ + FAR struct msghdr *pr_msg; /* Pointer to receive buffer */ sem_t pr_sem; /* Semaphore signals recv completion */ - size_t pr_buflen; /* Length of receive buffer */ - FAR uint8_t *pr_buffer; /* Pointer to receive buffer */ ssize_t pr_recvlen; /* The received length */ - size_t pr_msglen; /* Length of msg buffer */ - FAR uint8_t *pr_msgbuf; /* Pointer to msg buffer */ int pr_result; /* Success:OK, failure:negated errno */ }; @@ -76,6 +73,37 @@ struct can_recvfrom_s * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: can_recvfrom_initialize + * + * Description: + * Initialize the state structure + * + * Input Parameters: + * conn The CAN connection of interest + * msg Receive info and buffer for receive data + * pstate A pointer to the state structure to be initialized + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void can_recvfrom_initialize(FAR struct can_conn_s *conn, + FAR struct msghdr *msg, + FAR struct can_recvfrom_s *pstate) +{ + /* Initialize the state structure. */ + + memset(pstate, 0, sizeof(struct can_recvfrom_s)); + nxsem_init(&pstate->pr_sem, 0, 0); + + pstate->pr_conn = conn; + pstate->pr_msg = msg; +} + /**************************************************************************** * Name: can_add_recvlen * @@ -102,8 +130,6 @@ static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate, } pstate->pr_recvlen += recvlen; - pstate->pr_buffer += recvlen; - pstate->pr_buflen -= recvlen; } /**************************************************************************** @@ -129,34 +155,20 @@ static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev, { unsigned int offset; size_t recvlen; -#ifdef CONFIG_NET_TIMESTAMP - FAR struct can_conn_s *conn = pstate->pr_conn; - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && - pstate->pr_msglen == sizeof(struct timeval)) - { - struct timeval tv; - - tv.tv_sec = dev->d_iob->io_time.tv_sec; - tv.tv_usec = dev->d_iob->io_time.tv_nsec / 1000; - memcpy(pstate->pr_msgbuf, &tv, sizeof(struct timeval)); - } +#ifdef CONFIG_NET_TIMESTAMP + cmsg_store_timestamp(pstate->pr_msg, &dev->d_iob->io_time, + pstate->pr_conn->sconn.s_options); #endif - if (dev->d_len > pstate->pr_buflen) - { - recvlen = pstate->pr_buflen; - } - else - { - recvlen = dev->d_len; - } + recvlen = MIN(pstate->pr_msg->msg_iov->iov_len, dev->d_len); /* Copy the new packet data into the user buffer */ offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset; - recvlen = iob_copyout(pstate->pr_buffer, dev->d_iob, recvlen, offset); + recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, + dev->d_iob, recvlen, offset); /* Trim the copied buffers */ @@ -241,30 +253,28 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) * buffer. */ - pstate->pr_recvlen = -1; + pstate->pr_recvlen = -ENODATA; - if (pstate->pr_buflen > 0 && + if (pstate->pr_msg->msg_iov->iov_len > 0 && (iob = iob_remove_queue(&conn->readahead)) != NULL) { DEBUGASSERT(iob->io_pktlen > 0); #ifdef CONFIG_NET_TIMESTAMP - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) && - pstate->pr_msglen == sizeof(struct timeval)) - { - struct timeval tv; - - tv.tv_sec = iob->io_time.tv_sec; - tv.tv_usec = iob->io_time.tv_nsec / 1000; - memcpy(pstate->pr_msgbuf, &tv, sizeof(struct timeval)); - } + cmsg_store_timestamp(pstate->pr_msg, &iob->io_time, + conn->sconn.s_options); #endif /* Transfer that buffered data from the I/O buffer chain into * the user buffer. */ - recvlen = iob_copyout(pstate->pr_buffer, iob, pstate->pr_buflen, 0); + recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, + iob, pstate->pr_msg->msg_iov->iov_len, 0); + + /* Update the accumulated size of the data read */ + + pstate->pr_recvlen = recvlen; /* We should have taken all of the data from the I/O buffer chain, * so release it. There is no trimming needed, since One CAN/CANFD @@ -440,25 +450,7 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, /* Initialize the state structure. */ - memset(&state, 0, sizeof(struct can_recvfrom_s)); - nxsem_init(&state.pr_sem, 0, 0); /* Doesn't really fail */ - - state.pr_buflen = msg->msg_iov->iov_len; - state.pr_buffer = msg->msg_iov->iov_base; - -#ifdef CONFIG_NET_TIMESTAMP - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP)) - { - state.pr_msgbuf = cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, - NULL, sizeof(struct timeval)); - if (state.pr_msgbuf != NULL) - { - state.pr_msglen = sizeof(struct timeval); - } - } -#endif - - state.pr_conn = conn; + can_recvfrom_initialize(conn, msg, &state); /* Handle any any CAN data already buffered in a read-ahead buffer. NOTE * that there may be read-ahead data to be retrieved even after the diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index 79489a9ca496d..f3f675eddbe15 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -65,46 +65,6 @@ struct pkt_recvfrom_s uint8_t pr_type; /* Protocol type */ }; -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pkt_store_cmsg_timestamp - * - * Description: - * Store the timestamp in the cmsg - * - * Input Parameters: - * pstate Recicve state information - * timestamp Timestamp information - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_NET_TIMESTAMP -static void pkt_store_cmsg_timestamp(FAR struct pkt_recvfrom_s *pstate, - FAR struct timespec *timestamp) -{ - FAR struct msghdr *msg = pstate->pr_msg; - struct timeval tv; - - if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS)) - { - cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMPNS, timestamp, - sizeof(struct timespec)); - } - else - { - TIMESPEC_TO_TIMEVAL(&tv, timestamp); - cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, &tv, - sizeof(struct timeval)); - } -} -#endif - /**************************************************************************** * Name: pkt_add_recvlen * @@ -158,13 +118,8 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev, size_t recvlen; #ifdef CONFIG_NET_TIMESTAMP - /* Unpack stored timestamp if SO_TIMESTAMP socket option is enabled */ - - if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMP) || - _SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS)) - { - pkt_store_cmsg_timestamp(pstate, &dev->d_iob->io_time); - } + cmsg_store_timestamp(pstate->pr_msg, &dev->d_iob->io_time, + pstate->pr_conn->sconn.s_options); #endif recvlen = MIN(pstate->pr_msg->msg_iov->iov_len, dev->d_len); @@ -385,15 +340,8 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) DEBUGASSERT(iob->io_pktlen > 0); #ifdef CONFIG_NET_TIMESTAMP - /* Unpack stored timestamp if SO_TIMESTAMP/SO_TIMESTAMPNS socket option - * is enabled - */ - - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || - _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS)) - { - pkt_store_cmsg_timestamp(pstate, &iob->io_time); - } + cmsg_store_timestamp(pstate->pr_msg, &iob->io_time, + conn->sconn.s_options); #endif /* Copy to user */ diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c index 3514069fd07b2..a7357d78b87ce 100644 --- a/net/udp/udp_recvfrom.c +++ b/net/udp/udp_recvfrom.c @@ -67,19 +67,6 @@ struct udp_recvfrom_s * Private Functions ****************************************************************************/ -#ifdef CONFIG_NET_TIMESTAMP -static void udp_store_cmsg_timestamp(FAR struct udp_recvfrom_s *pstate, - FAR struct timespec *timestamp) -{ - FAR struct msghdr *msg = pstate->ir_msg; - struct timeval tv; - - TIMESPEC_TO_TIMEVAL(&tv, timestamp); - cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, - &tv, sizeof(struct timeval)); -} -#endif - #ifdef CONFIG_NET_SOCKOPTS static void udp_recvpktinfo(FAR struct udp_recvfrom_s *pstate, FAR void *srcaddr, uint8_t ifindex) @@ -224,7 +211,8 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate) if (conn->timestamp) { - udp_store_cmsg_timestamp(pstate, &iob->io_time); + cmsg_store_timestamp(pstate->ir_msg, &iob->io_time, + conn->sconn.s_options); } #endif @@ -465,7 +453,8 @@ static uint32_t udp_eventhandler(FAR struct net_driver_s *dev, #ifdef CONFIG_NET_TIMESTAMP if (pstate->ir_conn->timestamp) { - udp_store_cmsg_timestamp(pstate, &dev->d_iob->io_time); + cmsg_store_timestamp(pstate->ir_msg, &dev->d_iob->io_time, + pstate->ir_conn->sconn.s_options); } #endif diff --git a/net/utils/net_cmsg.c b/net/utils/net_cmsg.c index c36c989c3ce19..0cbfb41bc2ef6 100644 --- a/net/utils/net_cmsg.c +++ b/net/utils/net_cmsg.c @@ -28,6 +28,7 @@ #include +#include "socket/socket.h" #include "utils/utils.h" /**************************************************************************** @@ -60,7 +61,7 @@ ****************************************************************************/ FAR void *cmsg_append(FAR struct msghdr *msg, int level, int type, - FAR void *value, int value_len) + FAR const void *value, int value_len) { FAR struct cmsghdr *cmsg; unsigned long cmsgspace = CMSG_SPACE(value_len); @@ -86,3 +87,37 @@ FAR void *cmsg_append(FAR struct msghdr *msg, int level, int type, return cmsgdata; } + +/**************************************************************************** + * Name: cmsg_store_timestamp + * + * Description: + * Store the timestamp in the cmsg + * + * Input Parameters: + * msg - Pointer to the msghdr containing ancillary data (CMSG). + * tstamp - Timestamp information. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TIMESTAMP +void cmsg_store_timestamp(FAR struct msghdr *msg, + FAR const struct timespec *tstamp, sockopt_t opt) +{ + if (_SO_GETOPT(opt, SO_TIMESTAMP)) + { + struct timeval tv; + TIMESPEC_TO_TIMEVAL(&tv, tstamp); + cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, &tv, + sizeof(struct timeval)); + } + else if (_SO_GETOPT(opt, SO_TIMESTAMPNS)) + { + cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMPNS, tstamp, + sizeof(struct timespec)); + } +} +#endif /* CONFIG_NET_TIMESTAMP */ diff --git a/net/utils/utils.h b/net/utils/utils.h index 03fe8d15d2c17..5b34ae2976c77 100644 --- a/net/utils/utils.h +++ b/net/utils/utils.h @@ -668,7 +668,27 @@ uint16_t icmpv6_chksum(FAR struct net_driver_s *dev, unsigned int iplen); ****************************************************************************/ FAR void *cmsg_append(FAR struct msghdr *msg, int level, int type, - FAR void *value, int value_len); + FAR const void *value, int value_len); + +/**************************************************************************** + * Name: cmsg_store_timestamp + * + * Description: + * Store the timestamp in the cmsg + * + * Input Parameters: + * msg - Pointer to the msghdr containing ancillary data (CMSG). + * tstamp - Timestamp information. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TIMESTAMP +void cmsg_store_timestamp(FAR struct msghdr *msg, + FAR const struct timespec *tstamp, sockopt_t opt); +#endif /* CONFIG_NET_TIMESTAMP */ #undef EXTERN #ifdef __cplusplus From 9a1eba14789933e71684b13362629e58d43d203f Mon Sep 17 00:00:00 2001 From: OceanfromXiaomi Date: Tue, 25 Nov 2025 17:14:35 +0800 Subject: [PATCH 03/10] net: add NETDEV_RX_STAMP flag in d_features Replace compile-time CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP with a runtime NETDEV_RX_STAMP bit in net_driver_s.d_features. Drivers providing hardware RX timestamps set the flag at probe time; the stack checks it at runtime. Signed-off-by: OceanfromXiaomi --- arch/arm/src/common/stm32/Kconfig.eth | 1 - arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c | 4 ++++ include/nuttx/mm/iob.h | 8 ++++---- include/nuttx/net/netdev.h | 1 + net/Kconfig | 4 ---- net/can/can_input.c | 13 +++++++++---- net/devif/ipv4_input.c | 13 +++++++++---- net/devif/ipv6_input.c | 13 +++++++++---- net/netdev/netdev_input.c | 7 +++++-- net/pkt/pkt_input.c | 13 ++++++++----- 10 files changed, 49 insertions(+), 28 deletions(-) diff --git a/arch/arm/src/common/stm32/Kconfig.eth b/arch/arm/src/common/stm32/Kconfig.eth index d682b5d345906..7a028c19fd855 100644 --- a/arch/arm/src/common/stm32/Kconfig.eth +++ b/arch/arm/src/common/stm32/Kconfig.eth @@ -188,7 +188,6 @@ config STM32_ETH_PTP_RTC_HIRES config STM32_ETH_TIMESTAMP_RX bool "Hardware timestamping of received packets" depends on STM32_COMMON_LEGACY && STM32_ETH_PTP && NET_TIMESTAMP && STM32_ETH_ENHANCEDDESC - select ARCH_HAVE_NETDEV_TIMESTAMP default n ---help--- Timestamp all received Ethernet packets. diff --git a/arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c b/arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c index a33b15a6bc791..b151bf6e9ced8 100644 --- a/arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c +++ b/arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c @@ -4234,6 +4234,10 @@ int stm32_ethinitialize(int intf) return ret; } +#ifdef CONFIG_STM32_ETH_TIMESTAMP_RX + priv->dev.d_features |= NETDEV_RX_STAMP; +#endif + /* Register the device with the OS so that socket IOCTLs can be performed */ netdev_register(&priv->dev, NET_LL_ETHERNET); diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h index a32c5090bcae9..6985cc3dcf2b3 100644 --- a/include/nuttx/mm/iob.h +++ b/include/nuttx/mm/iob.h @@ -132,10 +132,10 @@ struct iob_s #ifdef CONFIG_NET_TIMESTAMP /* timestamp of the packet. - * If CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP is true, the timestamp is provided - * by hardware driver. Otherwise it is filled in by kernel when the packet - * is passed into respective protocol layer. The timestamp is in - * CLOCK_REALTIME. + * d_features is the member of net_driver_s struct, if the NETDEV_RX_STAMP + * bit of d_features is set, the timestamp is provided by hardware driver. + * Otherwise it is filled in by kernel when the packet is passed into + * respective protocol layer. The timestamp is in CLOCK_REALTIME. */ struct timespec io_time; diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index ca68c30eaaf92..c5395ba67cdc9 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -84,6 +84,7 @@ #define NETDEV_TX_CSUM (1 << 1) /* Netdev support hardware tx checksum */ #define NETDEV_RX_CSUM (1 << 2) /* Netdev support hardware rx checksum */ +#define NETDEV_RX_STAMP (1 << 3) /* Netdev support hardware timestamp */ /* Determine the largest possible address */ diff --git a/net/Kconfig b/net/Kconfig index 26d55b7a87eb2..7ca3c46763778 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -23,10 +23,6 @@ config ARCH_HAVE_NETDEV_STATISTICS bool default n -config ARCH_HAVE_NETDEV_TIMESTAMP - bool - default n - config NET_WRITE_BUFFERS bool default n diff --git a/net/can/can_input.c b/net/can/can_input.c index f1cd561df6646..d84f4b247c71d 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -229,11 +229,16 @@ static int can_in(FAR struct net_driver_s *dev) return OK; } - /* Store reception timestamp if enabled and not provided by hardware. */ + /* Storing reception timestamp provided by realtime + * if timestamp no provided by hardware. + */ -#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); -#endif +#ifdef CONFIG_NET_TIMESTAMP + if ((dev->d_features & NETDEV_RX_STAMP) == 0) + { + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); + } +#endif /* CONFIG_NET_TIMESTAMP */ can_conn_list_lock(); diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index b94c4c53ba4a9..233e3105fce89 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -231,11 +231,16 @@ static int ipv4_in(FAR struct net_driver_s *dev) bool isfrag; int ret = OK; - /* Store reception timestamp if enabled and not provided by hardware. */ + /* Storing reception timestamp provided by realtime + * if timestamp no provided by hardware. + */ -#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); -#endif +#ifdef CONFIG_NET_TIMESTAMP + if ((dev->d_features & NETDEV_RX_STAMP) == 0) + { + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); + } +#endif /* CONFIG_NET_TIMESTAMP */ /* Handle ARP on input then give the IPv4 packet to the network layer */ diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 065c5873341a3..87067bcf367fa 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -229,11 +229,16 @@ static int ipv6_in(FAR struct net_driver_s *dev) bool isfrag = false; #endif - /* Store reception timestamp if enabled and not provided by hardware. */ + /* Storing reception timestamp provided by realtime + * if timestamp no provided by hardware. + */ -#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); -#endif +#ifdef CONFIG_NET_TIMESTAMP + if ((dev->d_features & NETDEV_RX_STAMP) == 0) + { + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); + } +#endif /* CONFIG_NET_TIMESTAMP */ /* This is where the input processing starts. */ diff --git a/net/netdev/netdev_input.c b/net/netdev/netdev_input.c index 05882f5d9d79d..36333d27bc840 100644 --- a/net/netdev/netdev_input.c +++ b/net/netdev/netdev_input.c @@ -80,8 +80,11 @@ int netdev_input(FAR struct net_driver_s *dev, return ret; } -#if defined(CONFIG_NET_TIMESTAMP) && defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - dev->d_iob->io_time = dev->d_rxtime; +#if defined(CONFIG_NET_TIMESTAMP) + if ((dev->d_features & NETDEV_RX_STAMP) != 0) + { + dev->d_iob->io_time = dev->d_rxtime; + } #endif /* Copy data to iob entry */ diff --git a/net/pkt/pkt_input.c b/net/pkt/pkt_input.c index 07e4b274f01f4..34ca6b2bff3cd 100644 --- a/net/pkt/pkt_input.c +++ b/net/pkt/pkt_input.c @@ -155,12 +155,15 @@ static int pkt_in(FAR struct net_driver_s *dev) return OK; } -#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP) - /* Get system as timestamp if no hardware timestamp */ - - if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || - _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS)) +#ifdef CONFIG_NET_TIMESTAMP + if ((dev->d_features & NETDEV_RX_STAMP) == 0 && + (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || + _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))) { + /* Storing reception timestamp provided by realtime + * if timestamp no provided by hardware. + */ + clock_gettime(CLOCK_REALTIME, &dev->d_iob->io_time); } #endif /* CONFIG_NET_TIMESTAMP */ From 360f791a9fa9f8e4f369503ab34cf255aa19f3f7 Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Wed, 26 Nov 2025 09:20:13 +0800 Subject: [PATCH 04/10] net/pkt: support SO_TIMESTAMPING and MSG_ERRQUEUE Add SO_TIMESTAMPING TX path for PKT sockets. Tagged TX packets loop back through the driver with io_conn set, are routed into conn->errahead, and delivered to userspace via recvmsg(MSG_ERRQUEUE) with SO_TIMESTAMPING cmsg. Add poll(POLLPRI) notification when errahead is non-empty. Signed-off-by: wenquan1 --- include/nuttx/mm/iob.h | 8 ++- include/sys/socket.h | 20 +++++-- mm/iob/iob_alloc.c | 22 ++++---- net/pkt/pkt.h | 4 ++ net/pkt/pkt_input.c | 36 ++++++++++--- net/pkt/pkt_netpoll.c | 18 ++++++- net/pkt/pkt_recvmsg.c | 92 +++++++++++++++++++++++++------- net/pkt/pkt_sendmsg_buffered.c | 7 +++ net/pkt/pkt_sendmsg_unbuffered.c | 8 +++ net/pkt/pkt_sockif.c | 4 ++ net/socket/Kconfig | 8 ++- net/socket/getsockopt.c | 3 ++ net/socket/setsockopt.c | 3 ++ 13 files changed, 187 insertions(+), 46 deletions(-) diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h index 6985cc3dcf2b3..9a1265835e5ae 100644 --- a/include/nuttx/mm/iob.h +++ b/include/nuttx/mm/iob.h @@ -37,7 +37,7 @@ # include #endif -#ifdef CONFIG_NET_TIMESTAMP +#if defined(CONFIG_NET_TIMESTAMP) || defined(CONFIG_NET_TIMESTAMPING) # include #endif @@ -130,7 +130,7 @@ struct iob_s #endif unsigned int io_pktlen; /* Total length of the packet */ -#ifdef CONFIG_NET_TIMESTAMP +#if defined(CONFIG_NET_TIMESTAMP) || defined(CONFIG_NET_TIMESTAMPING) /* timestamp of the packet. * d_features is the member of net_driver_s struct, if the NETDEV_RX_STAMP * bit of d_features is set, the timestamp is provided by hardware driver. @@ -140,6 +140,10 @@ struct iob_s struct timespec io_time; #endif +#endif +#ifdef CONFIG_NET_TIMESTAMPING + FAR struct socket_conn_s *io_conn; +#endif #ifdef CONFIG_IOB_ALLOC iob_free_cb_t io_free; /* Custom free callback */ FAR uint8_t *io_data; diff --git a/include/sys/socket.h b/include/sys/socket.h index 3cdb3ce75b819..fddc049959f8f 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -223,6 +223,22 @@ #define SO_TIMESTAMPNS 20 /* Generates a timestamp in ns for each incoming packet * arg: integer value */ +#define SO_TIMESTAMPING 21 /* Generates timestamp for each output packet + */ + +/* Protocol-level socket options may begin with this value */ + +#define __SO_PROTOCOL 16 + +/* Timestamp generation */ + +#define SOF_TIMESTAMPING_TX_HARDWARE (1 << SO_TIMESTAMPING) +#define SOF_TIMESTAMPING_TX_SOFTWARE SOF_TIMESTAMPING_TX_HARDWARE + +/* Timestamp reporting */ + +#define SOF_TIMESTAMPING_SOFTWARE SOF_TIMESTAMPING_TX_SOFTWARE +#define SOF_TIMESTAMPING_RAW_HARDWARE SOF_TIMESTAMPING_TX_HARDWARE /* The options are unsupported but included for compatibility * and portability @@ -249,10 +265,6 @@ #define SOL_PACKET 19 -/* Protocol-level socket options may begin with this value */ - -#define __SO_PROTOCOL 16 - /* Values for the 'how' argument of shutdown() */ #define SHUT_RD 1 /* Bit 0: Disables further receive operations */ diff --git a/mm/iob/iob_alloc.c b/mm/iob/iob_alloc.c index 27575084c039e..9eb822b986728 100644 --- a/mm/iob/iob_alloc.c +++ b/mm/iob/iob_alloc.c @@ -96,6 +96,9 @@ static FAR struct iob_s *iob_alloc_committed(void) iob->io_len = 0; /* Length of the data in the entry */ iob->io_offset = 0; /* Offset to the beginning of data */ iob->io_pktlen = 0; /* Total length of the packet */ +#ifdef CONFIG_NET_TIMESTAMPING + iob->io_conn = NULL; +#endif } spin_unlock_irqrestore(&g_iob_lock, flags); @@ -135,6 +138,9 @@ static FAR struct iob_s *iob_tryalloc_internal(bool throttled) iob->io_len = 0; /* Length of the data in the entry */ iob->io_offset = 0; /* Offset to the beginning of data */ iob->io_pktlen = 0; /* Total length of the packet */ +#ifdef CONFIG_NET_TIMESTAMPING + iob->io_conn = NULL; +#endif return iob; } } @@ -340,11 +346,8 @@ FAR struct iob_s *iob_alloc_dynamic(uint16_t size) iob = kmm_memalign(IOB_ALIGNMENT, alignsize); if (iob) { - iob->io_flink = NULL; /* Not in a chain */ - iob->io_len = 0; /* Length of the data in the entry */ - iob->io_offset = 0; /* Offset to the beginning of data */ + memset(iob, 0, offsetof(struct iob_s, io_data)); iob->io_bufsize = size; /* Total length of the iob buffer */ - iob->io_pktlen = 0; /* Total length of the packet */ iob->io_free = iob_free_dynamic; /* Customer free callback */ iob->io_data = (FAR uint8_t *)ALIGN_UP((uintptr_t)(iob + 1), IOB_ALIGNMENT); @@ -383,14 +386,10 @@ FAR struct iob_s *iob_alloc_with_data(FAR void *data, uint16_t size, DEBUGASSERT(free_cb != NULL); - iob = kmm_malloc(sizeof(struct iob_s)); + iob = kmm_zalloc(sizeof(struct iob_s)); if (iob) { - iob->io_flink = NULL; /* Not in a chain */ - iob->io_len = 0; /* Length of the data in the entry */ - iob->io_offset = 0; /* Offset to the beginning of data */ iob->io_bufsize = size; /* Total length of the iob buffer */ - iob->io_pktlen = 0; /* Total length of the packet */ iob->io_free = free_cb; /* Customer free callback */ iob->io_data = data; } @@ -426,10 +425,7 @@ FAR struct iob_s *iob_init_with_data(FAR void *data, uint16_t size, { FAR struct iob_s *iob = (FAR struct iob_s *)data; - iob->io_flink = NULL; /* Not in a chain */ - iob->io_len = 0; /* Length of the data in the entry */ - iob->io_offset = 0; /* Offset to the beginning of data */ - iob->io_pktlen = 0; /* Total length of the packet */ + memset(iob, 0, offsetof(struct iob_s, io_data)); iob->io_free = free_cb; /* Customer free callback */ iob->io_data = (FAR uint8_t *)ALIGN_UP((uintptr_t)(iob + 1), IOB_ALIGNMENT); diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h index 63d946dafa284..2b2a368533452 100644 --- a/net/pkt/pkt.h +++ b/net/pkt/pkt.h @@ -104,6 +104,10 @@ struct pkt_conn_s struct iob_queue_s readahead; /* Read-ahead buffering */ +#ifdef CONFIG_NET_TIMESTAMPING + struct iob_queue_s errahead; /* Error-ahead buffering */ +#endif + FAR struct iob_s *pendiob; /* The iob currently being sent */ /* The following is a list of poll structures of threads waiting for diff --git a/net/pkt/pkt_input.c b/net/pkt/pkt_input.c index 34ca6b2bff3cd..99d46586d8fb3 100644 --- a/net/pkt/pkt_input.c +++ b/net/pkt/pkt_input.c @@ -52,6 +52,7 @@ * Input Parameters: * dev - Device instance only the input packet in d_buf, length = d_len; * conn - A pointer to the PKT connection structure + * iobq - A pointer to the buffer queue * * Returned Value: * The number of bytes actually buffered is returned. This will be either @@ -60,7 +61,8 @@ ****************************************************************************/ static uint16_t pkt_datahandler(FAR struct net_driver_s *dev, - FAR struct pkt_conn_s *conn) + FAR struct pkt_conn_s *conn, + FAR struct iob_queue_s *iobq) { FAR struct iob_s *iob = iob_tryalloc(true); int ret; @@ -88,7 +90,7 @@ static uint16_t pkt_datahandler(FAR struct net_driver_s *dev, */ conn_lock(&conn->sconn); - ret = iob_tryadd_queue(iob, &conn->readahead); + ret = iob_tryadd_queue(iob, iobq); conn_unlock(&conn->sconn); if (ret < 0) @@ -155,10 +157,32 @@ static int pkt_in(FAR struct net_driver_s *dev) return OK; } +#ifdef CONFIG_NET_TIMESTAMPING + + /* Handle hardware timestamp */ + + if (dev->d_iob->io_conn == &conn->sconn) + { + if (pkt_datahandler(dev, conn, &conn->errahead) > 0) + { + pkt_callback(dev, conn, PKT_NEWDATA); + } + + pkt_conn_list_unlock(); + return OK; + } + + if (dev->d_iob->io_conn != NULL) + { + /* Skip no related pkt conn */ + + pkt_conn_list_unlock(); + return OK; + } +#endif + #ifdef CONFIG_NET_TIMESTAMP - if ((dev->d_features & NETDEV_RX_STAMP) == 0 && - (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) || - _SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))) + if ((dev->d_features & NETDEV_RX_STAMP) == 0) { /* Storing reception timestamp provided by realtime * if timestamp no provided by hardware. @@ -185,7 +209,7 @@ static int pkt_in(FAR struct net_driver_s *dev) { /* Add the PKT to the socket read-ahead buffer. */ - if (pkt_datahandler(dev, conn) == 0) + if (pkt_datahandler(dev, conn, &conn->readahead) == 0) { /* No.. the packet was not processed now. Return -EAGAIN so * that the driver may retry again later. diff --git a/net/pkt/pkt_netpoll.c b/net/pkt/pkt_netpoll.c index 991db490aa50d..e04e74b23f005 100644 --- a/net/pkt/pkt_netpoll.c +++ b/net/pkt/pkt_netpoll.c @@ -124,7 +124,7 @@ static uint32_t pkt_poll_eventhandler(FAR struct net_driver_s *dev, if ((flags & NETDEV_DOWN) != 0) { - eventset |= (POLLHUP | POLLERR); + eventset |= POLLHUP | POLLERR; } /* A poll is a sign that we are free to send data. */ @@ -134,6 +134,15 @@ static uint32_t pkt_poll_eventhandler(FAR struct net_driver_s *dev, eventset |= POLLOUT; } +#ifdef CONFIG_NET_TIMESTAMPING + /* Check for timestamping data */ + + if (!IOB_QEMPTY(&info->conn->errahead)) + { + eventset |= POLLPRI | POLLERR; + } +#endif + /* Awaken the caller of poll() is requested event occurred. */ poll_notify(&info->fds, 1, eventset); @@ -237,6 +246,13 @@ int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) cb->flags |= PKT_NEWDATA; } +#ifdef CONFIG_NET_TIMESTAMPING + if ((fds->events & POLLPRI) != 0) + { + cb->flags |= PKT_NEWDATA; + } +#endif + /* Save the reference in the poll info structure as fds private as well * for use during poll teardown as well. */ diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index f3f675eddbe15..c2c0bf02d77f5 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -185,6 +185,18 @@ static uint32_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev, { /* If a new packet is available, then complete the read action. */ +#ifdef CONFIG_NET_TIMESTAMPING + if ((flags & PKT_NEWDATA) != 0 && dev->d_iob->io_conn != NULL) + { + pstate->pr_cb->flags = 0; + pstate->pr_cb->priv = NULL; + pstate->pr_cb->event = NULL; + pstate->pr_result = -EAGAIN; + nxsem_post(&pstate->pr_sem); + } + else +#endif + if ((flags & PKT_NEWDATA) != 0) { /* Copy the packet */ @@ -197,9 +209,9 @@ static uint32_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev, /* Don't allow any further call backs. */ - pstate->pr_cb->flags = 0; - pstate->pr_cb->priv = NULL; - pstate->pr_cb->event = NULL; + pstate->pr_cb->flags = 0; + pstate->pr_cb->priv = NULL; + pstate->pr_cb->event = NULL; /* Save the sender's address in the caller's 'from' location */ @@ -308,23 +320,56 @@ static ssize_t pkt_recvfrom_result(int result, } /**************************************************************************** - * Name: pkt_readahead + * Name: pkt_readdata * * Description: - * Copy the buffered read-ahead data to the user buffer. + * Copy the buffered data to the user buffer based on the flag errmsg. * * Input Parameters: * pstate The state structure of the recv operation * * Returned Value: - * None + * copy length or -ENODATA * * Assumptions: * The network is locked. * ****************************************************************************/ -static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) +static void append_timestamp(FAR struct pkt_recvfrom_s *pstate, + FAR struct iob_s *iob) +{ +#ifdef CONFIG_NET_TIMESTAMP + FAR struct pkt_conn_s *conn = pstate->pr_conn; + cmsg_store_timestamp(pstate->pr_msg, &iob->io_time, + conn->sconn.s_options); +#endif +} + +#ifdef CONFIG_NET_TIMESTAMPING +static void append_timestamping(FAR struct pkt_recvfrom_s *pstate, + FAR struct iob_s *iob) +{ + FAR struct pkt_conn_s *conn = pstate->pr_conn; + struct timespec ts[3]; + + memset(&ts, 0, sizeof(ts)); + + ts[0].tv_sec = iob->io_time.tv_sec; + ts[0].tv_nsec = iob->io_time.tv_nsec; + ts[2].tv_sec = iob->io_time.tv_sec; + ts[2].tv_nsec = iob->io_time.tv_nsec; + + cmsg_append(pstate->pr_msg, SOL_SOCKET, SO_TIMESTAMPING, &ts, + sizeof(ts)); + pstate->pr_msg->msg_flags |= MSG_ERRQUEUE; +} +#endif + +static inline int pkt_readdata(FAR struct pkt_recvfrom_s *pstate, + FAR struct iob_queue_s *iobq, + CODE void (*tsfunc)(FAR struct pkt_recvfrom_s *, + FAR struct iob_s *)) { FAR struct pkt_conn_s *conn = pstate->pr_conn; FAR struct iob_s *iob; @@ -335,14 +380,11 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) pstate->pr_recvlen = -ENODATA; - if ((iob = iob_peek_queue(&conn->readahead)) != NULL) + if ((iob = iob_remove_queue(iobq)) != NULL) { DEBUGASSERT(iob->io_pktlen > 0); -#ifdef CONFIG_NET_TIMESTAMP - cmsg_store_timestamp(pstate->pr_msg, &iob->io_time, - conn->sconn.s_options); -#endif + /* Copy to user */ @@ -370,16 +412,14 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) ninfo("Received %d bytes (of %u)\n", recvlen, iob->io_pktlen); - /* Remove the I/O buffer chain from the head of the read-ahead - * buffer queue. - */ - - iob_remove_queue(&conn->readahead); + tsfunc(pstate, iob); /* And free the I/O buffer chain */ iob_free_chain(iob); } + + return pstate->pr_recvlen; } /**************************************************************************** @@ -462,14 +502,28 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, conn_dev_lock(&conn->sconn, dev); +#ifdef CONFIG_NET_TIMESTAMPING + if (flags & MSG_ERRQUEUE) + { + if (!IOB_QEMPTY(&conn->errahead)) + { + ret = pkt_readdata(&state, &conn->errahead, append_timestamping); + } + else + { + ret = -EAGAIN; + } + } + else +#endif + /* Check if there is buffered read-ahead data for this socket. We may have * already received the response to previous command. */ if (!IOB_QEMPTY(&conn->readahead)) { - pkt_readahead(&state); - ret = pkt_recvfrom_result(ret, &state); + ret = pkt_readdata(&state, &conn->readahead, append_timestamp); } else if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0) diff --git a/net/pkt/pkt_sendmsg_buffered.c b/net/pkt/pkt_sendmsg_buffered.c index 5a237e11f74a0..3743f7ffda1d2 100644 --- a/net/pkt/pkt_sendmsg_buffered.c +++ b/net/pkt/pkt_sendmsg_buffered.c @@ -294,6 +294,13 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE); iob_update_pktlen(iob, 0, false); +#ifdef CONFIG_NET_TIMESTAMPING + if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPING)) + { + iob->io_conn = &conn->sconn; + } +#endif + /* Copy the user data into the write buffer. We cannot wait for * buffer space if the socket was opened non-blocking. */ diff --git a/net/pkt/pkt_sendmsg_unbuffered.c b/net/pkt/pkt_sendmsg_unbuffered.c index 349440e5d4b92..62d35e8af92e4 100644 --- a/net/pkt/pkt_sendmsg_unbuffered.c +++ b/net/pkt/pkt_sendmsg_unbuffered.c @@ -131,6 +131,14 @@ static uint32_t psock_send_eventhandler(FAR struct net_driver_s *dev, pstate->snd_sent = pstate->snd_buflen; pstate->snd_conn->pendiob = dev->d_iob; +#ifdef CONFIG_NET_TIMESTAMPING + if (_SO_GETOPT(pstate->snd_conn->sconn.s_options, + SO_TIMESTAMPING)) + { + dev->d_iob->io_conn = &pstate->snd_conn->sconn; + } +#endif + if (pstate->snd_sock->s_type == SOCK_DGRAM) { FAR struct eth_hdr_s *ethhdr = NETLLBUF; diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index 1efca0a898c7b..7da08a0dd85e2 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -368,6 +368,10 @@ static int pkt_close(FAR struct socket *psock) iob_free_queue(&conn->readahead); +#ifdef CONFIG_NET_TIMESTAMPING + iob_free_queue(&conn->errahead); +#endif + #ifdef CONFIG_NET_PKT_WRITE_BUFFERS /* Free write buffer callback. */ diff --git a/net/socket/Kconfig b/net/socket/Kconfig index eb438e91e87a5..663860b923a6f 100644 --- a/net/socket/Kconfig +++ b/net/socket/Kconfig @@ -80,11 +80,17 @@ config NET_SOLINGER config NET_TIMESTAMP bool "SO_TIMESTAMP socket option" default n - depends on NET_CAN || NET_ETHERNET ---help--- Enable or disable support for the SO_TIMESTAMP socket option. Supported on SocketCAN and Ethernet/UDP. +config NET_TIMESTAMPING + bool "SO_TIMESTAMPING socket option" + default n + ---help--- + Enable or disable support for the SO_TIMESTAMPING socket option. + Supported on Ethernet/PKT. + config NET_BINDTODEVICE bool "SO_BINDTODEVICE socket option Bind-to-device support" default n diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c index 8f258ae1be441..e2d5bdd85a71c 100644 --- a/net/socket/getsockopt.c +++ b/net/socket/getsockopt.c @@ -150,6 +150,9 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #ifdef CONFIG_NET_TIMESTAMP case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */ case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */ +#endif +#ifdef CONFIG_NET_TIMESTAMPING + case SO_TIMESTAMPING: /* Timestamping options */ #endif { sockopt_t optionset; diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c index a5368be6b922f..c22efce8f3bb1 100644 --- a/net/socket/setsockopt.c +++ b/net/socket/setsockopt.c @@ -140,6 +140,9 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #ifdef CONFIG_NET_TIMESTAMP case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */ case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */ +#endif +#ifdef CONFIG_NET_TIMESTAMPING + case SO_TIMESTAMPING: /* Timestamp all packets */ #endif { int setting; From 0d069c04d03f56a91886c3ccde3b0e84b9777c6f Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Thu, 25 Dec 2025 21:37:02 +0800 Subject: [PATCH 05/10] net/pkt: fix scheduling when receiving MSG_ERRQUEUE Fix a scheduling issue where MSG_ERRQUEUE readiness was not properly waking poll waiters in pkt_netpoll.c. Signed-off-by: wenquan1 --- net/pkt/pkt_netpoll.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/pkt/pkt_netpoll.c b/net/pkt/pkt_netpoll.c index e04e74b23f005..4adf8eaff2deb 100644 --- a/net/pkt/pkt_netpoll.c +++ b/net/pkt/pkt_netpoll.c @@ -277,6 +277,15 @@ int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) eventset |= POLLWRNORM; } + /* Check for timestamping data */ + +#ifdef CONFIG_NET_TIMESTAMPING + if (!IOB_QEMPTY(&conn->errahead)) + { + eventset |= POLLPRI | POLLERR; + } +#endif + /* Check if any requested events are already in effect */ poll_notify(&fds, 1, eventset); From 4336263e34ecbe2384bd192957644c769966ae4a Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Wed, 11 Mar 2026 15:19:15 +0800 Subject: [PATCH 06/10] net/socket: use s_options for SO_TIMESTAMP instead of per-conn field Remove the redundant `timestamp` field from `udp_conn_s` and use the existing `s_options` bitmask to track SO_TIMESTAMP/SO_TIMESTAMPNS state. The socket-level setsockopt/getsockopt already handles SO_TIMESTAMP via _SO_SETOPT/_SO_GETOPT on s_options. The protocol-level handlers in inet_sockif.c were intercepting the option before the socket layer, causing s_options to never be set. This also meant SO_TIMESTAMPNS was broken since inet_sockif.c only handled SO_TIMESTAMP. Changes: - Remove udp_conn_s.timestamp field from udp.h - Remove SO_TIMESTAMP get/set handlers from inet_sockif.c, letting them fall through to the socket-level handler - Simplify udp_recvfrom.c to call cmsg_store_timestamp() directly, which already checks s_options internally - Align pkt_input.c software timestamp generation with ipv4/can by removing per-socket SO_TIMESTAMP option check, only checking hardware timestamp capability Signed-off-by: wenquan1 --- net/inet/inet_sockif.c | 55 ------------------------------------------ net/pkt/pkt_input.c | 4 +++ net/udp/udp.h | 3 --- net/udp/udp_recvfrom.c | 16 +++--------- 4 files changed, 8 insertions(+), 70 deletions(-) diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index b8012b4fc6ca1..61962a9b459e2 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -713,29 +713,6 @@ static int inet_get_socketlevel_option(FAR struct socket *psock, int option, } #endif -#ifdef CONFIG_NET_TIMESTAMP - case SO_TIMESTAMP: - { - if (*value_len != sizeof(int)) - { - return -EINVAL; - } - -# ifdef NET_UDP_HAVE_STACK - if (psock->s_type == SOCK_DGRAM) - { - FAR struct udp_conn_s *conn = psock->s_conn; - *(FAR int *)value = (conn->timestamp != 0); - } - else -# endif - { - return -ENOPROTOOPT; - } - } - break; -#endif - default: return -ENOPROTOOPT; } @@ -1017,38 +994,6 @@ static int inet_set_socketlevel_option(FAR struct socket *psock, int option, break; #endif -#ifdef CONFIG_NET_TIMESTAMP - case SO_TIMESTAMP: /* Report receive timestamps as cmsg */ - { - if (value_len < sizeof(int)) - { - return -EINVAL; - } - -# ifdef NET_UDP_HAVE_STACK - if (psock->s_type == SOCK_DGRAM) - { - conn_lock(psock->s_conn); - - /* For now the timestamp enable is just boolean. - * If SO_TIMESTAMPING support is added in future, it can be - * expanded to flags field for rx/tx timestamps. - */ - - FAR struct udp_conn_s *conn = psock->s_conn; - conn->timestamp = (*((FAR int *)value) != 0); - - conn_unlock(psock->s_conn); - } - else -# endif - { - return -ENOPROTOOPT; - } - } - break; - #endif - default: return -ENOPROTOOPT; } diff --git a/net/pkt/pkt_input.c b/net/pkt/pkt_input.c index 99d46586d8fb3..d3e1c12ae06d5 100644 --- a/net/pkt/pkt_input.c +++ b/net/pkt/pkt_input.c @@ -182,6 +182,10 @@ static int pkt_in(FAR struct net_driver_s *dev) #endif #ifdef CONFIG_NET_TIMESTAMP + /* Storing reception timestamp provided by realtime + * if timestamp no provided by hardware. + */ + if ((dev->d_features & NETDEV_RX_STAMP) == 0) { /* Storing reception timestamp provided by realtime diff --git a/net/udp/udp.h b/net/udp/udp.h index 68850022f6571..b95a2c57eeaad 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -159,9 +159,6 @@ struct udp_conn_s struct udp_poll_s pollinfo[CONFIG_NET_UDP_NPOLLWAITERS]; -#ifdef CONFIG_NET_TIMESTAMP - int timestamp; /* Nonzero when SO_TIMESTAMP is enabled */ -#endif FAR sem_t *txdrain_sem; }; diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c index a7357d78b87ce..120eba315489b 100644 --- a/net/udp/udp_recvfrom.c +++ b/net/udp/udp_recvfrom.c @@ -207,13 +207,8 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate) DEBUGASSERT(recvlen == src_addr_size); #ifdef CONFIG_NET_TIMESTAMP - /* Unpack stored timestamp if SO_TIMESTAMP socket option is enabled */ - - if (conn->timestamp) - { - cmsg_store_timestamp(pstate->ir_msg, &iob->io_time, - conn->sconn.s_options); - } + cmsg_store_timestamp(pstate->ir_msg, &iob->io_time, + conn->sconn.s_options); #endif /* Copy to user */ @@ -451,11 +446,8 @@ static uint32_t udp_eventhandler(FAR struct net_driver_s *dev, /* Save packet timestamp, if requested */ #ifdef CONFIG_NET_TIMESTAMP - if (pstate->ir_conn->timestamp) - { - cmsg_store_timestamp(pstate->ir_msg, &dev->d_iob->io_time, - pstate->ir_conn->sconn.s_options); - } + cmsg_store_timestamp(pstate->ir_msg, &dev->d_iob->io_time, + pstate->ir_conn->sconn.s_options); #endif /* Save the sender's address in the caller's 'from' location */ From e1a1c031df18c0a68d40642f45c3f16a8990299e Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Wed, 11 Mar 2026 16:07:19 +0800 Subject: [PATCH 07/10] net/socket: merge CONFIG_NET_TIMESTAMPING into CONFIG_NET_TIMESTAMP Consolidate the two separate timestamp Kconfig options into a single CONFIG_NET_TIMESTAMP option that covers SO_TIMESTAMP, SO_TIMESTAMPNS and SO_TIMESTAMPING socket options. Previously CONFIG_NET_TIMESTAMPING was a separate option only used by PKT sockets for hardware TX/RX timestamps and error queue support. Since both options guard the same io_time field in iob_s and share the s_options bitmask, merging them simplifies configuration without functional impact. Changes: - Replace all CONFIG_NET_TIMESTAMPING with CONFIG_NET_TIMESTAMP in pkt_input.c, pkt_recvmsg.c, pkt_sendmsg_buffered.c, pkt_sendmsg_unbuffered.c, pkt_sockif.c, pkt_netpoll.c, pkt.h, setsockopt.c, getsockopt.c - Simplify iob.h conditional from OR of both to single option - Remove NET_TIMESTAMPING Kconfig entry, update NET_TIMESTAMP description to cover all three socket options Signed-off-by: wenquan1 --- include/nuttx/mm/iob.h | 10 ++++------ net/pkt/pkt.h | 2 +- net/pkt/pkt_input.c | 2 +- net/pkt/pkt_netpoll.c | 6 +++--- net/pkt/pkt_recvmsg.c | 6 +++--- net/pkt/pkt_sendmsg_buffered.c | 2 +- net/pkt/pkt_sendmsg_unbuffered.c | 2 +- net/pkt/pkt_sockif.c | 2 +- net/socket/Kconfig | 14 ++++---------- net/socket/getsockopt.c | 2 -- net/socket/setsockopt.c | 2 -- 11 files changed, 19 insertions(+), 31 deletions(-) diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h index 9a1265835e5ae..125dd2627ea5d 100644 --- a/include/nuttx/mm/iob.h +++ b/include/nuttx/mm/iob.h @@ -37,7 +37,7 @@ # include #endif -#if defined(CONFIG_NET_TIMESTAMP) || defined(CONFIG_NET_TIMESTAMPING) +#ifdef CONFIG_NET_TIMESTAMP # include #endif @@ -130,7 +130,9 @@ struct iob_s #endif unsigned int io_pktlen; /* Total length of the packet */ -#if defined(CONFIG_NET_TIMESTAMP) || defined(CONFIG_NET_TIMESTAMPING) + FAR struct socket_conn_s *io_conn; + +#ifdef CONFIG_NET_TIMESTAMP /* timestamp of the packet. * d_features is the member of net_driver_s struct, if the NETDEV_RX_STAMP * bit of d_features is set, the timestamp is provided by hardware driver. @@ -140,10 +142,6 @@ struct iob_s struct timespec io_time; #endif -#endif -#ifdef CONFIG_NET_TIMESTAMPING - FAR struct socket_conn_s *io_conn; -#endif #ifdef CONFIG_IOB_ALLOC iob_free_cb_t io_free; /* Custom free callback */ FAR uint8_t *io_data; diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h index 2b2a368533452..2aaa52f6258ef 100644 --- a/net/pkt/pkt.h +++ b/net/pkt/pkt.h @@ -104,7 +104,7 @@ struct pkt_conn_s struct iob_queue_s readahead; /* Read-ahead buffering */ -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP struct iob_queue_s errahead; /* Error-ahead buffering */ #endif diff --git a/net/pkt/pkt_input.c b/net/pkt/pkt_input.c index d3e1c12ae06d5..a287f114d8b74 100644 --- a/net/pkt/pkt_input.c +++ b/net/pkt/pkt_input.c @@ -157,7 +157,7 @@ static int pkt_in(FAR struct net_driver_s *dev) return OK; } -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP /* Handle hardware timestamp */ diff --git a/net/pkt/pkt_netpoll.c b/net/pkt/pkt_netpoll.c index 4adf8eaff2deb..5e07cd9bf03b5 100644 --- a/net/pkt/pkt_netpoll.c +++ b/net/pkt/pkt_netpoll.c @@ -134,7 +134,7 @@ static uint32_t pkt_poll_eventhandler(FAR struct net_driver_s *dev, eventset |= POLLOUT; } -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP /* Check for timestamping data */ if (!IOB_QEMPTY(&info->conn->errahead)) @@ -246,7 +246,7 @@ int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) cb->flags |= PKT_NEWDATA; } -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP if ((fds->events & POLLPRI) != 0) { cb->flags |= PKT_NEWDATA; @@ -279,7 +279,7 @@ int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) /* Check for timestamping data */ -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP if (!IOB_QEMPTY(&conn->errahead)) { eventset |= POLLPRI | POLLERR; diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index c2c0bf02d77f5..ad488064ec7e9 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -185,7 +185,7 @@ static uint32_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev, { /* If a new packet is available, then complete the read action. */ -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP if ((flags & PKT_NEWDATA) != 0 && dev->d_iob->io_conn != NULL) { pstate->pr_cb->flags = 0; @@ -346,7 +346,7 @@ static void append_timestamp(FAR struct pkt_recvfrom_s *pstate, #endif } -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP static void append_timestamping(FAR struct pkt_recvfrom_s *pstate, FAR struct iob_s *iob) { @@ -502,7 +502,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, conn_dev_lock(&conn->sconn, dev); -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP if (flags & MSG_ERRQUEUE) { if (!IOB_QEMPTY(&conn->errahead)) diff --git a/net/pkt/pkt_sendmsg_buffered.c b/net/pkt/pkt_sendmsg_buffered.c index 3743f7ffda1d2..cb2d9f05b83e6 100644 --- a/net/pkt/pkt_sendmsg_buffered.c +++ b/net/pkt/pkt_sendmsg_buffered.c @@ -294,7 +294,7 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE); iob_update_pktlen(iob, 0, false); -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPING)) { iob->io_conn = &conn->sconn; diff --git a/net/pkt/pkt_sendmsg_unbuffered.c b/net/pkt/pkt_sendmsg_unbuffered.c index 62d35e8af92e4..ac4be4c91d57a 100644 --- a/net/pkt/pkt_sendmsg_unbuffered.c +++ b/net/pkt/pkt_sendmsg_unbuffered.c @@ -131,7 +131,7 @@ static uint32_t psock_send_eventhandler(FAR struct net_driver_s *dev, pstate->snd_sent = pstate->snd_buflen; pstate->snd_conn->pendiob = dev->d_iob; -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP if (_SO_GETOPT(pstate->snd_conn->sconn.s_options, SO_TIMESTAMPING)) { diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index 7da08a0dd85e2..b2a3c2ced3c15 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -368,7 +368,7 @@ static int pkt_close(FAR struct socket *psock) iob_free_queue(&conn->readahead); -#ifdef CONFIG_NET_TIMESTAMPING +#ifdef CONFIG_NET_TIMESTAMP iob_free_queue(&conn->errahead); #endif diff --git a/net/socket/Kconfig b/net/socket/Kconfig index 663860b923a6f..2ceaa2c88fa90 100644 --- a/net/socket/Kconfig +++ b/net/socket/Kconfig @@ -78,18 +78,12 @@ config NET_SOLINGER write buffer support. config NET_TIMESTAMP - bool "SO_TIMESTAMP socket option" + bool "SO_TIMESTAMP/SO_TIMESTAMPING socket option" default n ---help--- - Enable or disable support for the SO_TIMESTAMP socket option. - Supported on SocketCAN and Ethernet/UDP. - -config NET_TIMESTAMPING - bool "SO_TIMESTAMPING socket option" - default n - ---help--- - Enable or disable support for the SO_TIMESTAMPING socket option. - Supported on Ethernet/PKT. + Enable or disable support for the SO_TIMESTAMP, + SO_TIMESTAMPNS and SO_TIMESTAMPING socket options. + Supported on SocketCAN, Ethernet/UDP and Ethernet/PKT. config NET_BINDTODEVICE bool "SO_BINDTODEVICE socket option Bind-to-device support" diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c index e2d5bdd85a71c..2d0d876986ea9 100644 --- a/net/socket/getsockopt.c +++ b/net/socket/getsockopt.c @@ -150,8 +150,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #ifdef CONFIG_NET_TIMESTAMP case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */ case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */ -#endif -#ifdef CONFIG_NET_TIMESTAMPING case SO_TIMESTAMPING: /* Timestamping options */ #endif { diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c index c22efce8f3bb1..ca0bcb8bd6636 100644 --- a/net/socket/setsockopt.c +++ b/net/socket/setsockopt.c @@ -140,8 +140,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #ifdef CONFIG_NET_TIMESTAMP case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */ case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */ -#endif -#ifdef CONFIG_NET_TIMESTAMPING case SO_TIMESTAMPING: /* Timestamp all packets */ #endif { From efb39feb7a524e164e09b4a75b4a831538ceaaa8 Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Wed, 11 Mar 2026 16:47:44 +0800 Subject: [PATCH 08/10] include/sys/socket.h: add SCM_TIMESTAMPNS and SCM_TIMESTAMPING macros Add missing SCM_TIMESTAMPNS and SCM_TIMESTAMPING control message type definitions mapped to their corresponding SO_TIMESTAMPNS and SO_TIMESTAMPING socket options. Also align whitespace of existing SCM_* definitions for consistency. Signed-off-by: wenquan1 --- include/sys/socket.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/sys/socket.h b/include/sys/socket.h index fddc049959f8f..50424bff924e8 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -309,10 +309,12 @@ /* "Socket"-level control message types: */ -#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ -#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ -#define SCM_SECURITY 0x03 /* rw: security label */ -#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ +#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ +#define SCM_SECURITY 0x03 /* rw: security label */ +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SCM_TIMESTAMPING SO_TIMESTAMPING /* Desired design of maximum size and alignment (see RFC2553) */ From f9604e7fc2ceae64ecd150b8827aac21ab39d220 Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Thu, 12 Mar 2026 14:05:53 +0800 Subject: [PATCH 09/10] arch/sim: support SO_TIMESTAMPING TX in sim netdriver Add TX timestamp loopback support to the simulator network driver. When a packet tagged with io_conn (SO_TIMESTAMPING TX) is sent, the driver clones the packet, generates a software timestamp, and queues it for loopback through the RX path. The protocol layer (UDP/PKT) then delivers the timestamp via MSG_ERRQUEUE. - Add tstampq IOB queue to sim_netdev_s for loopback packets. - In netdriver_send(), clone timestamped packets with realtime clock and notify RX ready. - In netdriver_recv(), return loopback packets before reading from the tap device. Signed-off-by: wenquan1 --- arch/sim/src/sim/sim_netdriver.c | 72 ++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/arch/sim/src/sim/sim_netdriver.c b/arch/sim/src/sim/sim_netdriver.c index b41ae87e7ea2e..2266128f9fd31 100644 --- a/arch/sim/src/sim/sim_netdriver.c +++ b/arch/sim/src/sim/sim_netdriver.c @@ -63,6 +63,7 @@ #include #include +#include #include #include @@ -109,6 +110,9 @@ struct sim_netdev_s #endif uint8_t buf[SIM_NETDEV_BUFSIZE]; /* Used when packet buffer is fragmented */ struct work_s work; +#ifdef CONFIG_NET_TIMESTAMP + netpkt_queue_t tstampq; /* TX timestamp loopback queue */ +#endif }; /**************************************************************************** @@ -163,6 +167,25 @@ static int netdriver_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt) sim_netdev_send(DEVIDX(dev), netpkt_getdata(dev, pkt), len); } +#ifdef CONFIG_NET_TIMESTAMP + /* If the packet is tagged for TX timestamping, generate a + * software timestamp and loop it back through the RX path + * so the protocol layer can deliver it via MSG_ERRQUEUE. + * Reuse the original pkt directly to avoid clone overhead. + */ + + if (pkt->io_conn != NULL) + { + FAR struct sim_netdev_s *priv = (FAR struct sim_netdev_s *)dev; + + clock_gettime(CLOCK_REALTIME, &pkt->io_time); + iob_add_queue(pkt, &priv->tstampq); + atomic_add(&dev->quota_ptr[NETPKT_TX], 1); + netdev_lower_rxready(dev); + return OK; + } +#endif + netpkt_free(dev, pkt, NETPKT_TX); return OK; } @@ -172,6 +195,26 @@ static netpkt_t *netdriver_recv(struct netdev_lowerhalf_s *dev) netpkt_t *pkt = NULL; unsigned int len; +#ifdef CONFIG_NET_TIMESTAMP + /* Return any TX timestamp loopback packets first. + * Fast-path: skip locking when the queue is empty. + */ + + FAR struct sim_netdev_s *priv = (FAR struct sim_netdev_s *)dev; + + if (!IOB_QEMPTY(&priv->tstampq)) + { + netdev_lock(&dev->netdev); + pkt = iob_remove_queue(&priv->tstampq); + netdev_unlock(&dev->netdev); + if (pkt != NULL) + { + atomic_sub(&dev->quota_ptr[NETPKT_RX], 1); + return pkt; + } + } +#endif + if (sim_netdev_avail(DEVIDX(dev))) { pkt = netpkt_alloc(dev, NETPKT_RX); @@ -237,8 +280,23 @@ static int netdriver_ifup(struct netdev_lowerhalf_s *dev) static int netdriver_ifdown(struct netdev_lowerhalf_s *dev) { +#ifdef CONFIG_NET_TIMESTAMP + /* Drain any pending TX timestamp loopback packets. + * Detach the entire queue under lock, then free outside. + */ + + FAR struct sim_netdev_s *priv = (FAR struct sim_netdev_s *)dev; + FAR netpkt_t *pkt; + + while ((pkt = iob_remove_queue(&priv->tstampq)) != NULL) + { + netpkt_free(dev, pkt, NETPKT_TX); + } +#endif + netdev_lower_carrier_off(dev); sim_netdev_ifdown(DEVIDX(dev)); + return OK; } @@ -273,7 +331,11 @@ static void sim_netdev_work(void *arg) struct sim_netdev_s *priv = (struct sim_netdev_s *)arg; struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)&priv->dev; - if (sim_netdev_avail(DEVIDX(dev))) + if (sim_netdev_avail(DEVIDX(dev)) +#ifdef CONFIG_NET_TIMESTAMP + || !IOB_QEMPTY(&priv->tstampq) +#endif + ) { netdev_lower_rxready(dev); } @@ -347,7 +409,7 @@ void sim_netdriver_setmacaddr(int devidx, unsigned char *macaddr) void sim_netdriver_setmtu(int devidx, int mtu) { IDXDEV(devidx)->netdev.d_pktsize = MIN(SIM_NETDEV_BUFSIZE, - mtu + ETH_HDRLEN); + mtu + ETH_HDRLEN); } void sim_netdriver_loop(void) @@ -355,7 +417,11 @@ void sim_netdriver_loop(void) int devidx; for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++) { - if (sim_netdev_avail(devidx)) + if (sim_netdev_avail(devidx) +#ifdef CONFIG_NET_TIMESTAMP + || !IOB_QEMPTY(&g_sim_dev[devidx].tstampq) +#endif + ) { netdev_lower_rxready(IDXDEV(devidx)); } From 17d71a991b7a548e0ea659d35cae61bbe907e395 Mon Sep 17 00:00:00 2001 From: wenquan1 Date: Wed, 16 Sep 2026 20:17:48 +0800 Subject: [PATCH 10/10] net: fix pre-existing coding style issues in timestamp-related files Fix coding style issues flagged by nxstyle in files touched by the SO_TIMESTAMPING series. These are pre-existing issues, not introduced by the SO_TIMESTAMPING patches: - inet_sockif.c: missing blank lines after declarations - ipv4_input.c: missing blank line after declaration, bad comment alignment - can_input.c: bad indentation inside #ifdef block - getsockopt.c: bad comment block alignment, bad brace alignment - setsockopt.c: wrong column position of comment - sim_netdriver.c: missing blank lines after declarations Signed-off-by: wenquan1 --- arch/sim/src/sim/sim_netdriver.c | 3 + net/can/can_input.c | 2 +- net/can/can_recvmsg.c | 3 +- net/devif/ipv4_input.c | 5 +- net/inet/inet_sockif.c | 252 +++++++++++++++++-------------- net/pkt/pkt_recvmsg.c | 2 - net/pkt/pkt_sendmsg_buffered.c | 1 + net/pkt/pkt_sendmsg_unbuffered.c | 1 + net/pkt/pkt_sockif.c | 1 + net/socket/getsockopt.c | 8 +- net/socket/setsockopt.c | 2 +- net/udp/udp_callback.c | 2 +- net/utils/net_cmsg.c | 1 + 13 files changed, 157 insertions(+), 126 deletions(-) diff --git a/arch/sim/src/sim/sim_netdriver.c b/arch/sim/src/sim/sim_netdriver.c index 2266128f9fd31..ee8310c7f02bb 100644 --- a/arch/sim/src/sim/sim_netdriver.c +++ b/arch/sim/src/sim/sim_netdriver.c @@ -317,12 +317,14 @@ static int netdriver_rmmac(struct netdev_lowerhalf_s *dev, static void netdriver_txdone_interrupt(void *priv) { struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)priv; + netdev_lower_txdone(dev); } static void netdriver_rxready_interrupt(void *priv) { struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)priv; + netdev_lower_rxready(dev); } @@ -415,6 +417,7 @@ void sim_netdriver_setmtu(int devidx, int mtu) void sim_netdriver_loop(void) { int devidx; + for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++) { if (sim_netdev_avail(devidx) diff --git a/net/can/can_input.c b/net/can/can_input.c index d84f4b247c71d..315186c5852ee 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -322,7 +322,7 @@ int can_input(FAR struct net_driver_s *dev) if (ret < 0) { #ifdef CONFIG_NET_STATISTICS - g_netstats.can.drop++; + g_netstats.can.drop++; #endif } diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index 8dd4879ab3c14..d69fbbc52d91b 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -313,8 +313,7 @@ static uint32_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev, if (pstate) { -#if (defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)) \ - || defined(CONFIG_NET_TIMESTAMP) +#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD) struct can_conn_s *conn = pstate->pr_conn; #endif diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index 233e3105fce89..15f1b62a84253 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -149,6 +149,7 @@ static int ipv4_check_opt(FAR struct ipv4_hdr_s *ipv4) else if (optlen > 1) { int len = opt[1]; + if (len > optlen) { return -EINVAL; @@ -494,7 +495,7 @@ static int ipv4_in(FAR struct net_driver_s *dev) #endif #ifdef NET_ICMP_HAVE_STACK - /* Check for ICMP input */ + /* Check for ICMP input */ case IP_PROTO_ICMP: /* ICMP input */ icmp_input(dev); @@ -502,7 +503,7 @@ static int ipv4_in(FAR struct net_driver_s *dev) #endif #ifdef CONFIG_NET_IGMP - /* Check for IGMP input */ + /* Check for IGMP input */ case IP_PROTO_IGMP: /* IGMP input */ igmp_input(dev); diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index 61962a9b459e2..db3fccbe4c3fe 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -72,48 +72,62 @@ static void inet_addref(FAR struct socket *psock); static int inet_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); + static int inet_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen); + static int inet_getpeername(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen); + static int inet_listen(FAR struct socket *psock, int backlog); static int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); + static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR struct socket *newsock, int flags); + static int inet_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup); + static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); + static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen); + static ssize_t inet_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, int flags); + static ssize_t inet_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, int flags); + static int inet_ioctl(FAR struct socket *psock, int cmd, unsigned long arg); + static int inet_socketpair(FAR struct socket *psocks[2]); static int inet_shutdown(FAR struct socket *psock, int how); #ifdef CONFIG_NET_SOCKOPTS static int inet_getsockopt(FAR struct socket *psock, int level, int option, FAR void *value, FAR socklen_t *value_len); + static int inet_setsockopt(FAR struct socket *psock, int level, int option, FAR const void *value, socklen_t value_len); + #endif #ifdef CONFIG_NET_SENDFILE static ssize_t inet_sendfile(FAR struct socket *psock, FAR struct file *infile, FAR off_t *offset, size_t count); + #endif /**************************************************************************** @@ -165,6 +179,7 @@ static int inet_tcp_alloc(FAR struct socket *psock) /* Allocate the TCP connection structure */ FAR struct tcp_conn_s *conn = tcp_alloc(psock->s_domain); + if (conn == NULL) { /* Failed to reserve a connection structure */ @@ -207,6 +222,7 @@ static int inet_udp_alloc(FAR struct socket *psock) /* Allocate the UDP connection structure */ FAR struct udp_conn_s *conn = udp_alloc(psock->s_domain); + if (conn == NULL) { /* Failed to reserve a connection structure */ @@ -362,6 +378,7 @@ static void inet_addref(FAR struct socket *psock) if (psock->s_type == SOCK_STREAM) { FAR struct tcp_conn_s *conn = psock->s_conn; + DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255); conn->crefs++; } @@ -371,6 +388,7 @@ static void inet_addref(FAR struct socket *psock) if (psock->s_type == SOCK_DGRAM) { FAR struct udp_conn_s *conn = psock->s_conn; + DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255); conn->crefs++; } @@ -412,20 +430,20 @@ static int inet_bind(FAR struct socket *psock, switch (addr->sa_family) { #ifdef CONFIG_NET_IPv4 - case AF_INET: - minlen = sizeof(struct sockaddr_in); - break; + case AF_INET: + minlen = sizeof(struct sockaddr_in); + break; #endif #ifdef CONFIG_NET_IPv6 - case AF_INET6: - minlen = sizeof(struct sockaddr_in6); - break; + case AF_INET6: + minlen = sizeof(struct sockaddr_in6); + break; #endif - default: - nerr("ERROR: Unrecognized address family: %d\n", addr->sa_family); - return -EAFNOSUPPORT; + default: + nerr("ERROR: Unrecognized address family: %d\n", addr->sa_family); + return -EAFNOSUPPORT; } if (addrlen < minlen) @@ -517,17 +535,17 @@ static int inet_getsockname(FAR struct socket *psock, switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 - case PF_INET: - return ipv4_getsockname(psock, addr, addrlen); + case PF_INET: + return ipv4_getsockname(psock, addr, addrlen); #endif #ifdef CONFIG_NET_IPv6 - case PF_INET6: - return ipv6_getsockname(psock, addr, addrlen); + case PF_INET6: + return ipv6_getsockname(psock, addr, addrlen); #endif - default: - return -EAFNOSUPPORT; + default: + return -EAFNOSUPPORT; } } @@ -568,17 +586,17 @@ static int inet_getpeername(FAR struct socket *psock, switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 - case PF_INET: - return ipv4_getpeername(psock, addr, addrlen); + case PF_INET: + return ipv4_getpeername(psock, addr, addrlen); #endif #ifdef CONFIG_NET_IPv6 - case PF_INET6: - return ipv6_getpeername(psock, addr, addrlen); + case PF_INET6: + return ipv6_getpeername(psock, addr, addrlen); #endif - default: - return -EAFNOSUPPORT; + default: + return -EAFNOSUPPORT; } } @@ -637,6 +655,7 @@ static int inet_get_socketlevel_option(FAR struct socket *psock, int option, if (psock->s_type == SOCK_STREAM) { FAR struct tcp_conn_s *tcp = psock->s_conn; + *(FAR int *)value = tcp->rcv_bufs; } else @@ -645,6 +664,7 @@ static int inet_get_socketlevel_option(FAR struct socket *psock, int option, if (psock->s_type == SOCK_DGRAM) { FAR struct udp_conn_s *udp = psock->s_conn; + *(FAR int *)value = udp->rcvbufs; } else @@ -668,6 +688,7 @@ static int inet_get_socketlevel_option(FAR struct socket *psock, int option, if (psock->s_type == SOCK_STREAM) { FAR struct tcp_conn_s *tcp = psock->s_conn; + *(FAR int *)value = tcp->snd_bufs; } else @@ -767,7 +788,7 @@ static int inet_getsockopt(FAR struct socket *psock, int level, int option, #ifdef CONFIG_NET_IPv6 case IPPROTO_IPV6:/* IPv6 protocol socket options (see include/netinet/in.h) */ - return ipv6_getsockopt(psock, option, value, value_len); + return ipv6_getsockopt(psock, option, value, value_len); #endif default: @@ -1088,6 +1109,7 @@ static int inet_listen(FAR struct socket *psock, int backlog) #if defined(CONFIG_NET_TCP) && defined(NET_TCP_HAVE_STACK) FAR struct tcp_conn_s *conn; int ret; + #endif /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ @@ -1212,33 +1234,33 @@ static int inet_connect(FAR struct socket *psock, switch (inaddr->sin_family) { #ifdef CONFIG_NET_IPv4 - case AF_INET: - { - if (addrlen < sizeof(struct sockaddr_in)) - { - return -EINVAL; - } - } - break; + case AF_INET: + { + if (addrlen < sizeof(struct sockaddr_in)) + { + return -EINVAL; + } + } + break; #endif #ifdef CONFIG_NET_IPv6 - case AF_INET6: - { - if (addrlen < sizeof(struct sockaddr_in6)) - { - return -EINVAL; - } - } - break; + case AF_INET6: + { + if (addrlen < sizeof(struct sockaddr_in6)) + { + return -EINVAL; + } + } + break; #endif - case AF_UNSPEC: - break; + case AF_UNSPEC: + break; - default: - DEBUGPANIC(); - return -EAFNOSUPPORT; + default: + DEBUGPANIC(); + return -EAFNOSUPPORT; } /* Perform the connection depending on the protocol type */ @@ -1373,6 +1395,7 @@ static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, { #if defined(CONFIG_NET_TCP) && defined(NET_TCP_HAVE_STACK) int ret; + #endif /* Is the socket a stream? */ @@ -1398,30 +1421,30 @@ static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 - case PF_INET: - { - if (*addrlen < sizeof(struct sockaddr_in)) - { - return -EINVAL; - } - } - break; + case PF_INET: + { + if (*addrlen < sizeof(struct sockaddr_in)) + { + return -EINVAL; + } + } + break; #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 - case PF_INET6: - { - if (*addrlen < sizeof(struct sockaddr_in6)) - { - return -EINVAL; - } - } - break; + case PF_INET6: + { + if (*addrlen < sizeof(struct sockaddr_in6)) + { + return -EINVAL; + } + } + break; #endif /* CONFIG_NET_IPv6 */ - default: - DEBUGPANIC(); - return -EINVAL; + default: + DEBUGPANIC(); + return -EINVAL; } } @@ -1446,9 +1469,9 @@ static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, return ret; } - /* Begin monitoring for TCP connection events on the newly connected - * socket - */ + /* Begin monitoring for TCP connection events on the newly connected + * socket + */ ret = tcp_start_monitor(newsock); if (ret < 0) @@ -1592,9 +1615,9 @@ static int inet_poll(FAR struct socket *psock, FAR struct pollfd *fds, return inet_pollteardown(psock, fds); } #else - { - return -ENOSYS; - } + { + return -ENOSYS; + } #endif /* NET_TCP_HAVE_STACK || !NET_UDP_HAVE_STACK */ } @@ -1623,6 +1646,7 @@ static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, { #ifdef NET_UDP_HAVE_STACK FAR struct socket_conn_s *conn = psock->s_conn; + #endif ssize_t ret; @@ -1658,9 +1682,9 @@ static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, case SOCK_DGRAM: { #if defined(CONFIG_NET_6LOWPAN) - /* Try 6LoWPAN UDP packet send */ + /* Try 6LoWPAN UDP packet send */ - ret = psock_6lowpan_udp_send(psock, buf, len); + ret = psock_6lowpan_udp_send(psock, buf, len); #ifdef NET_UDP_HAVE_STACK if (ret < 0) @@ -1733,20 +1757,20 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, switch (to->sa_family) { #ifdef CONFIG_NET_IPv4 - case AF_INET: - minlen = sizeof(struct sockaddr_in); - break; + case AF_INET: + minlen = sizeof(struct sockaddr_in); + break; #endif #ifdef CONFIG_NET_IPv6 - case AF_INET6: - minlen = sizeof(struct sockaddr_in6); - break; + case AF_INET6: + minlen = sizeof(struct sockaddr_in6); + break; #endif - default: - nerr("ERROR: Unrecognized address family: %d\n", to->sa_family); - return -EAFNOSUPPORT; + default: + nerr("ERROR: Unrecognized address family: %d\n", to->sa_family); + return -EAFNOSUPPORT; } if (tolen < minlen) @@ -1913,8 +1937,10 @@ static int inet_socketpair(FAR struct socket *psocks[2]) { #if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) FAR struct socket *pserver = psocks[1]; + #if defined(CONFIG_NET_TCP) FAR struct socket server; + #endif union sockaddr_u addr[2]; socklen_t len; @@ -2153,24 +2179,24 @@ static ssize_t inet_recvmsg(FAR struct socket *psock, switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 - case PF_INET: - { - minlen = sizeof(struct sockaddr_in); - } - break; + case PF_INET: + { + minlen = sizeof(struct sockaddr_in); + } + break; #endif #ifdef CONFIG_NET_IPv6 - case PF_INET6: - { - minlen = sizeof(struct sockaddr_in6); - } - break; + case PF_INET6: + { + minlen = sizeof(struct sockaddr_in6); + } + break; #endif - default: - DEBUGPANIC(); - return -EINVAL; + default: + DEBUGPANIC(); + return -EINVAL; } if (msg->msg_namelen < minlen) @@ -2186,35 +2212,35 @@ static ssize_t inet_recvmsg(FAR struct socket *psock, switch (psock->s_type) { #ifdef CONFIG_NET_TCP - case SOCK_STREAM: - { + case SOCK_STREAM: + { #ifdef NET_TCP_HAVE_STACK - ret = psock_tcp_recvfrom(psock, msg, flags); + ret = psock_tcp_recvfrom(psock, msg, flags); #else - ret = -ENOSYS; + ret = -ENOSYS; #endif - } - break; + } + break; #endif /* CONFIG_NET_TCP */ #ifdef CONFIG_NET_UDP - case SOCK_DGRAM: - { + case SOCK_DGRAM: + { #ifdef NET_UDP_HAVE_STACK - ret = psock_udp_recvfrom(psock, msg, flags); + ret = psock_udp_recvfrom(psock, msg, flags); #else - ret = -ENOSYS; + ret = -ENOSYS; #endif - } - break; + } + break; #endif /* CONFIG_NET_UDP */ - default: - { - nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); - ret = -ENOSYS; - } - break; + default: + { + nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); + ret = -ENOSYS; + } + break; } return ret; @@ -2382,9 +2408,9 @@ inet_sockif(sa_family_t family, int type, int protocol) return &g_inet_sockif; } #else - { - return NULL; - } + { + return NULL; + } #endif } diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index ad488064ec7e9..df1e4eea3842c 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -384,8 +384,6 @@ static inline int pkt_readdata(FAR struct pkt_recvfrom_s *pstate, { DEBUGASSERT(iob->io_pktlen > 0); - - /* Copy to user */ if (pstate->pr_type == SOCK_DGRAM) diff --git a/net/pkt/pkt_sendmsg_buffered.c b/net/pkt/pkt_sendmsg_buffered.c index cb2d9f05b83e6..40b46051dbc78 100644 --- a/net/pkt/pkt_sendmsg_buffered.c +++ b/net/pkt/pkt_sendmsg_buffered.c @@ -336,6 +336,7 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, { FAR struct eth_hdr_s *ethhdr = (FAR struct eth_hdr_s *)(IOB_DATA(iob) - NET_LL_HDRLEN(dev)); + memcpy(ethhdr->dest, addr->sll_addr, ETHER_ADDR_LEN); memcpy(ethhdr->src, &dev->d_mac.ether, ETHER_ADDR_LEN); ethhdr->type = addr->sll_protocol; diff --git a/net/pkt/pkt_sendmsg_unbuffered.c b/net/pkt/pkt_sendmsg_unbuffered.c index ac4be4c91d57a..5e9982c9bbb33 100644 --- a/net/pkt/pkt_sendmsg_unbuffered.c +++ b/net/pkt/pkt_sendmsg_unbuffered.c @@ -142,6 +142,7 @@ static uint32_t psock_send_eventhandler(FAR struct net_driver_s *dev, if (pstate->snd_sock->s_type == SOCK_DGRAM) { FAR struct eth_hdr_s *ethhdr = NETLLBUF; + memcpy(ethhdr->dest, pstate->addr->sll_addr, ETHER_ADDR_LEN); memcpy(ethhdr->src, &dev->d_mac.ether, ETHER_ADDR_LEN); ethhdr->type = pstate->addr->sll_protocol; diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index b2a3c2ced3c15..1a3b386efdd94 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -108,6 +108,7 @@ static int pkt_sockif_alloc(FAR struct socket *psock) */ FAR struct pkt_conn_s *conn = pkt_alloc(); + if (conn == NULL) { /* Failed to reserve a connection structure */ diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c index 2d0d876986ea9..99b64f6f84309 100644 --- a/net/socket/getsockopt.c +++ b/net/socket/getsockopt.c @@ -104,8 +104,8 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, } /* Get the timeout value. This is a atomic operation and should - * require no special operation. - */ + * require no special operation. + */ if (option == SO_RCVTIMEO) { @@ -150,7 +150,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #ifdef CONFIG_NET_TIMESTAMP case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */ case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */ - case SO_TIMESTAMPING: /* Timestamping options */ + case SO_TIMESTAMPING:/* Timestamping options */ #endif { sockopt_t optionset; @@ -162,7 +162,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, if (*value_len < sizeof(int)) { return -EINVAL; - } + } /* Sample the current options. This is atomic operation and so * should not require any special steps for thread safety. We diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c index ca0bcb8bd6636..7a3de8f0edea0 100644 --- a/net/socket/setsockopt.c +++ b/net/socket/setsockopt.c @@ -140,7 +140,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, #ifdef CONFIG_NET_TIMESTAMP case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */ case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */ - case SO_TIMESTAMPING: /* Timestamp all packets */ + case SO_TIMESTAMPING:/* Timestamp all packets */ #endif { int setting; diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c index 58f872cf4f9b2..462910cd85f0b 100644 --- a/net/udp/udp_callback.c +++ b/net/udp/udp_callback.c @@ -259,7 +259,7 @@ net_dataevent(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn, * read-ahead buffers to retain the data -- drop the packet. */ - ninfo("Dropped %d bytes\n", dev->d_len); + ninfo("Dropped %d bytes\n", dev->d_len); #ifdef CONFIG_NET_STATISTICS g_netstats.udp.drop++; diff --git a/net/utils/net_cmsg.c b/net/utils/net_cmsg.c index 0cbfb41bc2ef6..935e9fb6e2758 100644 --- a/net/utils/net_cmsg.c +++ b/net/utils/net_cmsg.c @@ -110,6 +110,7 @@ void cmsg_store_timestamp(FAR struct msghdr *msg, if (_SO_GETOPT(opt, SO_TIMESTAMP)) { struct timeval tv; + TIMESPEC_TO_TIMEVAL(&tv, tstamp); cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, &tv, sizeof(struct timeval));