This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 95f8c54836e4a41c73d09c68a19fe49e95b21fc6
Author: wenquan1 <[email protected]>
AuthorDate: Thu Mar 12 14:05:53 2026 +0800

    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 <[email protected]>
---
 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 b41ae87e7ea..2266128f9fd 100644
--- a/arch/sim/src/sim/sim_netdriver.c
+++ b/arch/sim/src/sim/sim_netdriver.c
@@ -63,6 +63,7 @@
 
 #include <nuttx/debug.h>
 #include <string.h>
+#include <time.h>
 
 #include <nuttx/compiler.h>
 #include <nuttx/kmalloc.h>
@@ -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));
         }

Reply via email to