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 c2863382003530b8e90364cd7612b0cc95ad7951
Author: raiden00pl <[email protected]>
AuthorDate: Mon Oct 26 13:12:37 2026 +0100

    net/sixlowpan: send packets from the IOB chain of the device
    
    The conversion of a packet in the IOB chain of the device read it as one
    flat buffer, so a payload longer than the first IOB was read past it.
    sixlowpan_queue_frames() now copies the payload from an IOB chain with
    iob_copyout(), the socket send paths put the data in the device IOB with
    devif_send() as the UDP and TCP send paths do, and the reply to a
    received packet is converted in the netdev_input() callback while it is
    in the IOB, before the reassembly buffer is freed.
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <[email protected]>
---
 net/sixlowpan/sixlowpan_framelist.c  |  20 +--
 net/sixlowpan/sixlowpan_icmpv6send.c |   8 +-
 net/sixlowpan/sixlowpan_input.c      | 234 +++++++++++++++++++----------------
 net/sixlowpan/sixlowpan_internal.h   |  12 +-
 net/sixlowpan/sixlowpan_send.c       |  19 ++-
 net/sixlowpan/sixlowpan_tcpsend.c    |  26 ++--
 net/sixlowpan/sixlowpan_udpsend.c    |   8 +-
 7 files changed, 184 insertions(+), 143 deletions(-)

diff --git a/net/sixlowpan/sixlowpan_framelist.c 
b/net/sixlowpan/sixlowpan_framelist.c
index ef28c50f6db..1c6cde5c91f 100644
--- a/net/sixlowpan/sixlowpan_framelist.c
+++ b/net/sixlowpan/sixlowpan_framelist.c
@@ -347,7 +347,8 @@ static int sixlowpan_pktradio_metadata(FAR struct 
radio_driver_s *radio,
  *   called from send event handler when a TX poll is received.  It
  *   formats the list of frames to be sent by the IEEE802.15.4 MAC driver.
  *
- *   The payload data is in the caller 'buf' and is of length 'buflen'.
+ *   The payload data is in the IOB chain 'pkt' at 'offset' and is of
+ *   length 'buflen'.
  *   Compressed headers will be added and if necessary the packet is
  *   fragmented. The resulting packet/fragments are submitted to the MAC
  *   where they are queue for transfer.
@@ -355,9 +356,9 @@ static int sixlowpan_pktradio_metadata(FAR struct 
radio_driver_s *radio,
  * Input Parameters:
  *   radio   - The radio network driver instance
  *   ipv6    - IPv6 header followed by TCP, UDP, or ICMPv6 header.
- *   buf     - Beginning of the packet packet to send (with IPv6 + protocol
- *             headers)
- *   buflen  - Length of data to send (includes IPv6 and protocol headers)
+ *   pkt     - The IOB chain holding the payload
+ *   offset  - The offset of the payload in pkt
+ *   buflen  - Length of the payload
  *   destmac - The IEEE802.15.4 MAC address of the destination
  *
  * Returned Value:
@@ -373,7 +374,8 @@ static int sixlowpan_pktradio_metadata(FAR struct 
radio_driver_s *radio,
 
 int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
                            FAR const struct ipv6_hdr_s *ipv6,
-                           FAR const void *buf, size_t buflen,
+                           FAR struct iob_s *pkt, unsigned int offset,
+                           size_t buflen,
                            FAR const struct netdev_varaddr_s *destmac)
 {
   union sixlowpan_metadata_u meta;
@@ -588,7 +590,8 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
        */
 
       paysize = (framelen - g_frame_hdrlen) & ~7;
-      memcpy(fptr + g_frame_hdrlen + protosize, buf, paysize - protosize);
+      iob_copyout(fptr + g_frame_hdrlen + protosize, pkt,
+                  paysize - protosize, offset);
 
       /* Set outlen to what we already sent from the IP payload */
 
@@ -666,7 +669,8 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
               paysize = buflen - outlen + protosize;
             }
 
-          memcpy(fptr + fragn_hdrlen, buf + outlen - protosize, paysize);
+          iob_copyout(fptr + fragn_hdrlen, pkt, paysize,
+                      offset + outlen - protosize);
 
           /* Set outlen to what we already sent from the IP payload */
 
@@ -738,7 +742,7 @@ int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
 
       /* Copy the payload into the frame. */
 
-      memcpy(fptr + g_frame_hdrlen + protosize, buf, buflen);
+      iob_copyout(fptr + g_frame_hdrlen + protosize, pkt, buflen, offset);
       iob->io_len    = buflen + g_frame_hdrlen + protosize;
       iob->io_pktlen = iob->io_len;
 
diff --git a/net/sixlowpan/sixlowpan_icmpv6send.c 
b/net/sixlowpan/sixlowpan_icmpv6send.c
index e6dd187202b..0a6c4cc4e9c 100644
--- a/net/sixlowpan/sixlowpan_icmpv6send.c
+++ b/net/sixlowpan/sixlowpan_icmpv6send.c
@@ -82,7 +82,8 @@ void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
   if (dev != NULL && dev->d_len > 0)
     {
       sixlowpan_dumpbuffer("Outgoing ICMPv6 packet",
-                           (FAR const uint8_t *)ipv6icmpv6, dev->d_len);
+                           (FAR const uint8_t *)ipv6icmpv6,
+                           dev->d_iob->io_len);
 
       /* The ICMPv6 data payload should follow the IPv6 header plus the
        * protocol header.
@@ -96,7 +97,6 @@ void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
       else
         {
           struct netdev_varaddr_s destmac;
-          FAR uint8_t *buf;
           uint16_t hdrlen;
           uint16_t buflen;
           int ret;
@@ -129,12 +129,12 @@ void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
             {
               /* Convert the outgoing packet into a frame list. */
 
-              buf    = (FAR uint8_t *)ipv6 + hdrlen;
               buflen = dev->d_len - hdrlen;
 
               sixlowpan_queue_frames(
                       (FAR struct radio_driver_s *)fwddev,
-                      &ipv6icmpv6->ipv6, buf, buflen, &destmac);
+                      &ipv6icmpv6->ipv6, dev->d_iob, hdrlen, buflen,
+                      &destmac);
             }
         }
     }
diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c
index c99723d353a..c6eb5cd0921 100644
--- a/net/sixlowpan/sixlowpan_input.c
+++ b/net/sixlowpan/sixlowpan_input.c
@@ -68,6 +68,7 @@
 #  include "pkt/pkt.h"
 #endif
 
+#include "devif/devif.h"
 #include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
@@ -652,6 +653,124 @@ errout_with_reass:
   return ret;
 }
 
+/****************************************************************************
+ * Name: sixlowpan_ipv6_input
+ *
+ * Description:
+ *   Give the IPv6 packet in d_iob to the network and convert the reply to
+ *   it, if any, into frames.  Called from netdev_input().
+ *
+ * Input Parameters:
+ *   dev - The IEEE802.15.4 MAC network driver interface.
+ *
+ * Returned Value:
+ *   The result of ipv6_input(), zero if a reply was handled.
+ *
+ ****************************************************************************/
+
+static int sixlowpan_ipv6_input(FAR struct net_driver_s *dev)
+{
+  FAR struct radio_driver_s *radio = (FAR struct radio_driver_s *)dev;
+  FAR struct ipv6_hdr_s *ipv6hdr;
+  struct netdev_varaddr_s destmac;
+  size_t hdrlen;
+  int ret;
+
+  /* Give the IPv6 packet to the network layer.  NOTE:  If there is a
+   * problem with IPv6 header, it will be silently dropped and d_len will
+   * be set to zero.  Oddly, ipv6_input() will return OK in this case.
+   */
+
+  ret = ipv6_input(dev);
+
+  /* Check if this resulted in a request to send an outgoing packet. */
+
+  if (ret < 0 || dev->d_len == 0)
+    {
+      return ret;
+    }
+
+  /* The IPv6 header followed by TCP or UDP headers should lie at the
+   * beginning of d_buf since there is no link layer protocol header.
+   * ipv6_input() may have replaced d_iob.
+   */
+
+  dev->d_buf = NETLLBUF;
+  ipv6hdr    = IPv6BUF;
+
+  /* Get the IEEE 802.15.4 MAC address of the destination.  This assumes an
+   * encoding of the MAC address in the IPv6 address.
+   */
+
+  ret = sixlowpan_nexthopaddr(radio, ipv6hdr->destipaddr, &destmac);
+  if (ret < 0)
+    {
+      nerr("ERROR: Failed to get dest MAC address: %d\n", ret);
+      goto drop;
+    }
+
+  /* The data payload should follow the IPv6 header plus the protocol
+   * header.
+   */
+
+  switch (ipv6hdr->proto)
+    {
+#ifdef CONFIG_NET_TCP
+      case IP_PROTO_TCP:
+        {
+          FAR struct tcp_hdr_s *tcp = TCPBUF(dev);
+          uint16_t tcplen;
+
+          /* The TCP header length is encoded in the top 4 bits of the
+           * tcpoffset field (in units of 32-bit words).
+           */
+
+          tcplen = ((uint16_t)tcp->tcpoffset >> 4) << 2;
+          hdrlen = IPv6_HDRLEN + tcplen;
+        }
+        break;
+#endif
+#ifdef CONFIG_NET_UDP
+      case IP_PROTO_UDP:
+        {
+          hdrlen = IPv6_HDRLEN + UDP_HDRLEN;
+        }
+        break;
+#endif
+#ifdef CONFIG_NET_ICMPv6
+      case IP_PROTO_ICMP6:
+        {
+          hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN;
+        }
+        break;
+#endif
+      default:
+        {
+          nwarn("WARNING: Unsupported prototype: %u\n", ipv6hdr->proto);
+          goto drop;
+        }
+    }
+
+  if (hdrlen > dev->d_len)
+    {
+      nwarn("WARNING: Packet too small: Have %u need >%zu\n",
+            dev->d_len, hdrlen);
+      goto drop;
+    }
+
+  /* Convert the outgoing packet into a frame list. */
+
+  sixlowpan_queue_frames(radio, ipv6hdr, dev->d_iob, hdrlen,
+                         dev->d_len - hdrlen, &destmac);
+
+drop:
+  dev->d_len = 0;
+
+  /* We consumed the frame, so we must return 0. */
+
+  return 0;
+}
+
 /****************************************************************************
  * Name: sixlowpan_dispatch
  *
@@ -692,16 +811,16 @@ static int sixlowpan_dispatch(FAR struct radio_driver_s 
*radio)
   ninfo("IPv6 packet dispatch\n");
   NETDEV_RXIPV6(&radio->r_dev);
 
-  /* Give the IPv6 packet to the network layer.  NOTE:  If there is a
-   * problem with IPv6 header, it will be silently dropped and d_len will
-   * be set to zero.  Oddly, ipv6_input() will return OK in this case.
-   */
+  /* Give the IPv6 packet to the network layer in an IOB chain */
 
-  ret = ipv6_input(&radio->r_dev);
+  reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
+
+  netdev_lock(&radio->r_dev);
+  ret = netdev_input(&radio->r_dev, sixlowpan_ipv6_input, false);
+  netdev_unlock(&radio->r_dev);
 
   /* Free the reassemby buffer */
 
-  reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
   DEBUGASSERT(reass != NULL);
   sixlowpan_reass_free(reass);
 
@@ -751,7 +870,7 @@ static int sixlowpan_dispatch(FAR struct radio_driver_s 
*radio)
  *
  *   After the network processes the packet, d_len will be set to zero.
  *   Network logic may also decide to send a response to the packet.  In
- *   that case, the outgoing network packet will be placed in d_buf and
+ *   that case, the outgoing network packet will be left in d_iob and
  *   d_len will be set to a non-zero value.  That case is handled by this
  *   function.
  *
@@ -833,107 +952,6 @@ int sixlowpan_input(FAR struct radio_driver_s *radio,
           /* Inject the uncompressed, reassembled packet into the network */
 
           ret = sixlowpan_dispatch(radio);
-          if (ret >= 0)
-            {
-              /* Check if this resulted in a request to send an outgoing
-               * packet.
-               */
-
-              if (dev->d_len > 0)
-                {
-                  FAR struct ipv6_hdr_s *ipv6hdr;
-                  FAR uint8_t *buffer;
-                  struct netdev_varaddr_s destmac;
-                  size_t hdrlen;
-                  size_t buflen;
-
-                  /* The IPv6 header followed by TCP or UDP headers should
-                   * lie at the beginning of d_buf since there is no link
-                   * layer protocol header.
-                   */
-
-                  ipv6hdr = IPv6BUF;
-
-                  /* Get the IEEE 802.15.4 MAC address of the destination.
-                   * This assumes an encoding of the MAC address in the IPv6
-                   * address.
-                   */
-
-                  ret = sixlowpan_nexthopaddr(radio, ipv6hdr->destipaddr,
-                                              &destmac);
-                  if (ret < 0)
-                    {
-                      nerr("ERROR: Failed to get dest MAC address: %d\n",
-                           ret);
-                      goto drop;
-                    }
-
-                  /* The data payload should follow the IPv6 header plus
-                   * the protocol header.
-                   */
-
-                  switch (ipv6hdr->proto)
-                    {
-#ifdef CONFIG_NET_TCP
-                      case IP_PROTO_TCP:
-                        {
-                          FAR struct tcp_hdr_s *tcp = TCPBUF(dev);
-                          uint16_t tcplen;
-
-                          /* The TCP header length is encoded in the top 4
-                           * bits of the tcpoffset field (in units of 32-bit
-                           * words).
-                           */
-
-                          tcplen = ((uint16_t)tcp->tcpoffset >> 4) << 2;
-                          hdrlen = IPv6_HDRLEN + tcplen;
-                        }
-                        break;
-#endif
-#ifdef CONFIG_NET_UDP
-                      case IP_PROTO_UDP:
-                        {
-                          hdrlen = IPv6_HDRLEN + UDP_HDRLEN;
-                        }
-                        break;
-#endif
-#ifdef CONFIG_NET_ICMPv6
-                      case IP_PROTO_ICMP6:
-                        {
-                          hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN;
-                        }
-                        break;
-#endif
-                      default:
-                        {
-                          nwarn("WARNING: Unsupported prototype: %u\n",
-                                ipv6hdr->proto);
-                          goto drop;
-                        }
-                    }
-
-                  if (hdrlen > dev->d_len)
-                    {
-                      nwarn("WARNING: Packet too small: Have %u need >%zu\n",
-                            dev->d_len, hdrlen);
-                      goto drop;
-                    }
-
-                  /* Convert the outgoing packet into a frame list. */
-
-                  buffer = dev->d_buf + hdrlen;
-                  buflen = dev->d_len - hdrlen;
-
-                  ret = sixlowpan_queue_frames(radio, ipv6hdr, buffer,
-                                               buflen, &destmac);
-drop:
-                  dev->d_len = 0;
-
-                  /* We consumed the frame, so we must return 0. */
-
-                  ret = 0;
-                }
-            }
         }
     }
 
diff --git a/net/sixlowpan/sixlowpan_internal.h 
b/net/sixlowpan/sixlowpan_internal.h
index b74e4cd7eff..7593bf4e7a8 100644
--- a/net/sixlowpan/sixlowpan_internal.h
+++ b/net/sixlowpan/sixlowpan_internal.h
@@ -368,7 +368,8 @@ int sixlowpan_frame_submit(FAR struct radio_driver_s *radio,
  *   the send event handler when a TX poll is received.  It formats the
  *   list of frames to be sent by the IEEE802.15.4 MAC driver.
  *
- *   The payload data is in the caller 'buf' and is of length 'buflen'.
+ *   The payload data is in the IOB chain 'pkt' at 'offset' and is of
+ *   length 'buflen'.
  *   Compressed headers will be added and if necessary the packet is
  *   fragmented. The resulting packet/fragments are submitted to the MAC
  *   via the network driver r_req_data method.
@@ -376,9 +377,9 @@ int sixlowpan_frame_submit(FAR struct radio_driver_s *radio,
  * Input Parameters:
  *   radio   - Reference to a radio network driver state instance.
  *   ipv6    - IPv6 header followed by TCP or UDP header.
- *   buf     - Beginning of the packet packet to send (with IPv6 + protocol
- *             headers)
- *   buflen  - Length of data to send (includes IPv6 and protocol headers)
+ *   pkt     - The IOB chain holding the payload
+ *   offset  - The offset of the payload in pkt
+ *   buflen  - Length of the payload
  *   destmac - The IEEE802.15.4 MAC address of the destination
  *
  * Returned Value:
@@ -394,7 +395,8 @@ int sixlowpan_frame_submit(FAR struct radio_driver_s *radio,
 
 int sixlowpan_queue_frames(FAR struct radio_driver_s *radio,
                            FAR const struct ipv6_hdr_s *ipv6,
-                           FAR const void *buf,  size_t buflen,
+                           FAR struct iob_s *pkt, unsigned int offset,
+                           size_t buflen,
                            FAR const struct netdev_varaddr_s *destmac);
 
 /****************************************************************************
diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c
index 242cafd2b5c..9b72939899d 100644
--- a/net/sixlowpan/sixlowpan_send.c
+++ b/net/sixlowpan/sixlowpan_send.c
@@ -138,12 +138,21 @@ static uint32_t send_eventhandler(FAR struct net_driver_s 
*dev,
     {
       DEBUGASSERT((flags & UDP_POLL) != 0);
 
-      /* Transfer the frame list to the IEEE802.15.4 MAC device */
+      /* Copy the data to the device IOB and transfer the frame list to
+       * the IEEE802.15.4 MAC device.
+       */
 
-      sinfo->s_result =
-        sixlowpan_queue_frames((FAR struct radio_driver_s *)dev,
-                               sinfo->s_ipv6hdr, sinfo->s_buf, sinfo->s_len,
-                               sinfo->s_destmac);
+      sinfo->s_result = devif_send(dev, sinfo->s_buf, sinfo->s_len,
+                                   IPv6_HDRLEN + UDP_HDRLEN);
+      if (sinfo->s_result > 0)
+        {
+          sinfo->s_result =
+            sixlowpan_queue_frames((FAR struct radio_driver_s *)dev,
+                                   sinfo->s_ipv6hdr, dev->d_iob,
+                                   IPv6_HDRLEN + UDP_HDRLEN, sinfo->s_len,
+                                   sinfo->s_destmac);
+          dev->d_sndlen = 0;
+        }
 
       flags &= ~UDP_POLL;
       neighbor_reachable(dev);
diff --git a/net/sixlowpan/sixlowpan_tcpsend.c 
b/net/sixlowpan/sixlowpan_tcpsend.c
index 75a367cc83a..2570ddb1383 100644
--- a/net/sixlowpan/sixlowpan_tcpsend.c
+++ b/net/sixlowpan/sixlowpan_tcpsend.c
@@ -458,12 +458,20 @@ static uint32_t tcp_send_eventhandler(FAR struct 
net_driver_s *dev,
               goto end_wait;
             }
 
-          /* Transfer the frame list to the IEEE802.15.4 MAC device */
+          /* Copy the data to the device IOB and transfer the frame list
+           * to the IEEE802.15.4 MAC device.
+           */
 
-          ret = sixlowpan_queue_frames((FAR struct radio_driver_s *)dev,
-                                       &ipv6tcp.ipv6,
-                                       &sinfo->s_buf[sinfo->s_sent], sndlen,
-                                       sinfo->s_destmac);
+          ret = devif_send(dev, &sinfo->s_buf[sinfo->s_sent], sndlen,
+                           tcpip_hdrsize(conn));
+          if (ret > 0)
+            {
+              ret = sixlowpan_queue_frames((FAR struct radio_driver_s *)dev,
+                                           &ipv6tcp.ipv6, dev->d_iob,
+                                           tcpip_hdrsize(conn), sndlen,
+                                           sinfo->s_destmac);
+              dev->d_sndlen = 0;
+            }
 
           /* Without IOBs the segment is lost like on the air, the
            * retransmission timer sends it again.
@@ -832,7 +840,8 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev,
 
   ninfo("d_len %u\n", dev->d_len);
   sixlowpan_dumpbuffer("Outgoing TCP packet",
-                       (FAR const uint8_t *)ipv6, dev->d_len);
+                       (FAR const uint8_t *)ipv6,
+                       dev->d_iob->io_len);
 
   if (dev != NULL && dev->d_len > 0 && fwddev != NULL)
     {
@@ -857,7 +866,6 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev,
       else
         {
           struct netdev_varaddr_s destmac;
-          FAR uint8_t *buf;
           uint16_t hdrlen;
           uint16_t buflen;
           int ret;
@@ -891,12 +899,12 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev,
             {
               /* Convert the outgoing packet into a frame list. */
 
-              buf    = (FAR uint8_t *)ipv6 + hdrlen;
               buflen = dev->d_len - hdrlen;
 
               sixlowpan_queue_frames(
                       (FAR struct radio_driver_s *)fwddev,
-                      &ipv6hdr->ipv6, buf, buflen, &destmac);
+                      &ipv6hdr->ipv6, dev->d_iob, hdrlen, buflen,
+                      &destmac);
             }
         }
     }
diff --git a/net/sixlowpan/sixlowpan_udpsend.c 
b/net/sixlowpan/sixlowpan_udpsend.c
index 6c3dec7e7e6..80de3071973 100644
--- a/net/sixlowpan/sixlowpan_udpsend.c
+++ b/net/sixlowpan/sixlowpan_udpsend.c
@@ -419,7 +419,8 @@ void sixlowpan_udp_send(FAR struct net_driver_s *dev,
   if (dev != NULL && dev->d_len > 0 && fwddev != NULL)
     {
       sixlowpan_dumpbuffer("Outgoing UDP packet",
-                           (FAR const uint8_t *)ipv6udp, dev->d_len);
+                           (FAR const uint8_t *)ipv6udp,
+                           dev->d_iob->io_len);
 
       /* The UDP data payload should follow the IPv6 header plus the
        * protocol header.
@@ -433,7 +434,6 @@ void sixlowpan_udp_send(FAR struct net_driver_s *dev,
       else
         {
           struct netdev_varaddr_s destmac;
-          FAR uint8_t *buf;
           uint16_t hdrlen;
           uint16_t buflen;
           int ret;
@@ -463,12 +463,12 @@ void sixlowpan_udp_send(FAR struct net_driver_s *dev,
             {
               /* Convert the outgoing packet into a frame list. */
 
-              buf    = (FAR uint8_t *)ipv6 + hdrlen;
               buflen = dev->d_len - hdrlen;
 
               sixlowpan_queue_frames(
                       (FAR struct radio_driver_s *)fwddev,
-                      &ipv6udp->ipv6, buf, buflen, &destmac);
+                      &ipv6udp->ipv6, dev->d_iob, hdrlen, buflen,
+                      &destmac);
             }
         }
     }

Reply via email to