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); } } }
