From e5dad7b476552065c24324db5b641a81275c6996 Mon Sep 17 00:00:00 2001 From: shichunma Date: Sun, 2 Aug 2026 10:38:03 +0800 Subject: [PATCH] net/ipv6: Forward reassembled fragments through fragout NAT66 and IPFILTER may reassemble IPv6 fragments before forwarding so they can inspect the full packet. If the reassembled transit packet is larger than the egress MTU, ipv6_dev_forward() currently drops it before the existing egress ip_fragout() path can split it again. Track packets produced by IPv6 reassembly and allow only those packets to bypass the forwarding MTU drop when CONFIG_NET_IPFRAG is enabled. Normal oversized IPv6 forwarded packets still take the Packet Too Big path. Signed-off-by: shichunma --- include/nuttx/net/netdev.h | 1 + net/ipforward/ipv6_forward.c | 12 +++++++++--- net/ipfrag/ipv6_frag.c | 9 ++++++++- net/netdev/netdev_register.c | 4 ++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 23a3f2f5e5d8a..f4a08cf6eeca6 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -442,6 +442,7 @@ struct net_driver_s /* Remember the outgoing fragments waiting to be sent */ #ifdef CONFIG_NET_IPFRAG + uint8_t d_ipfrag_reassembled; /* Current packet is reassembled by IPFRAG */ struct iob_queue_s d_fragout; #endif diff --git a/net/ipforward/ipv6_forward.c b/net/ipforward/ipv6_forward.c index 18d7a941ad763..f8b53eaef2807 100644 --- a/net/ipforward/ipv6_forward.c +++ b/net/ipforward/ipv6_forward.c @@ -390,11 +390,17 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, } else if (ret == PACKET_NOT_FORWARDED) { - /* Verify that the full packet will fit within the forwarding devices - * MTU. We provide no support for fragmenting forwarded packets. + /* Verify that the full packet will fit within the forwarding device's + * MTU. Normal IPv6 forwarding does not fragment oversized packets, + * but packets reassembled locally for NAT66/IPFILTER may be split + * again by the egress IPFRAG path. */ - if (NET_LL_HDRLEN(fwddev) + dev->d_len > NETDEV_PKTSIZE(fwddev)) + if (NET_LL_HDRLEN(fwddev) + dev->d_len > NETDEV_PKTSIZE(fwddev) +#ifdef CONFIG_NET_IPFRAG + && !dev->d_ipfrag_reassembled +#endif + ) { nwarn("WARNING: Packet > MTU... Dropping\n"); ret = -EFBIG; diff --git a/net/ipfrag/ipv6_frag.c b/net/ipfrag/ipv6_frag.c index 5ae861cd9a1a4..c27f731bb0214 100644 --- a/net/ipfrag/ipv6_frag.c +++ b/net/ipfrag/ipv6_frag.c @@ -469,6 +469,8 @@ int32_t ipv6_fragin(FAR struct net_driver_s *dev) FAR struct ip_fragsnode_s *node = NULL; FAR struct ip_fraglink_s *fraginfo = NULL; bool restartwdog; + uint8_t reassembled; + int32_t ret; if (dev->d_len != dev->d_iob->io_pktlen) { @@ -521,7 +523,12 @@ int32_t ipv6_fragin(FAR struct net_driver_s *dev) kmm_free(node); - return ipv6_input(dev); + reassembled = dev->d_ipfrag_reassembled; + dev->d_ipfrag_reassembled = true; + ret = ipv6_input(dev); + dev->d_ipfrag_reassembled = reassembled; + + return ret; } nxmutex_unlock(&g_ipfrag_lock); diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c index e92e0d992b1f3..3bbe6f10bbbee 100644 --- a/net/netdev/netdev_register.c +++ b/net/netdev/netdev_register.c @@ -427,6 +427,10 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype) dev->d_polltype = 0; +#ifdef CONFIG_NET_IPFRAG + dev->d_ipfrag_reassembled = false; +#endif + nxrmutex_init(&dev->d_lock); /* We need exclusive access for the following operations */