This commit is contained in:
Jerry Ma 2026-08-01 14:10:47 +00:00 committed by GitHub
commit 68a7423da2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 112 additions and 33 deletions

View file

@ -84,6 +84,7 @@
#include <sys/ioctl.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/debug.h>
#include <string.h>
@ -166,6 +167,34 @@ static int ipv4_check_opt(FAR struct ipv4_hdr_s *ipv4)
}
#endif
/****************************************************************************
* Name: ipv4_fragin_or_drop
*
* Description:
* Reassemble an incoming IPv4 fragment for local processing or drop it if
* fragment reassembly is not available.
*
****************************************************************************/
static int ipv4_fragin_or_drop(FAR struct net_driver_s *dev)
{
#ifdef CONFIG_NET_IPFRAG
if (ipv4_fragin(dev) == OK)
{
return OK;
}
#endif
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv4.drop++;
g_netstats.ipv4.fragerr++;
#endif
nwarn("WARNING: IP fragment dropped\n");
dev->d_len = 0;
return OK;
}
/****************************************************************************
* Name: ipv4_in
*
@ -199,6 +228,7 @@ static int ipv4_in(FAR struct net_driver_s *dev)
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
in_addr_t destipaddr;
uint16_t totlen;
bool isfrag;
int ret = OK;
/* Handle ARP on input then give the IPv4 packet to the network layer */
@ -273,22 +303,7 @@ static int ipv4_in(FAR struct net_driver_s *dev)
/* Check the fragment flag. */
if ((ipv4->ipoffset[0] & 0x3f) != 0 || ipv4->ipoffset[1] != 0)
{
#ifdef CONFIG_NET_IPFRAG
if (ipv4_fragin(dev) == OK)
{
return OK;
}
#endif
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv4.drop++;
g_netstats.ipv4.fragerr++;
#endif
nwarn("WARNING: IP fragment dropped\n");
goto drop;
}
isfrag = (ipv4->ipoffset[0] & 0x3f) != 0 || ipv4->ipoffset[1] != 0;
#ifdef CONFIG_DEBUG_FEATURES
if (ipv4_check_opt(ipv4) != OK)
@ -301,6 +316,13 @@ static int ipv4_in(FAR struct net_driver_s *dev)
}
#endif
#if defined(CONFIG_NET_NAT44) || defined(CONFIG_NET_IPFILTER)
if (isfrag)
{
return ipv4_fragin_or_drop(dev);
}
#endif
#ifdef CONFIG_NET_NAT44
/* Try NAT inbound, rule matching will be performed in NAT module. */
@ -334,6 +356,11 @@ static int ipv4_in(FAR struct net_driver_s *dev)
ipv4_forward_broadcast(dev, ipv4);
#endif
if (isfrag)
{
return ipv4_fragin_or_drop(dev);
}
#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
if (ipv4->proto == IP_PROTO_UDP)
{
@ -406,6 +433,16 @@ static int ipv4_in(FAR struct net_driver_s *dev)
}
}
/* Forwarding has already had a chance to consume non-local unicast
* fragments. Any remaining fragments are for local input and must be
* reassembled before the transport layer sees them.
*/
if (isfrag)
{
return ipv4_fragin_or_drop(dev);
}
#ifdef CONFIG_NET_IPV4_CHECKSUMS
if (((dev->d_features & NETDEV_RX_CSUM) == 0)
&& (ipv4_chksum(IPv4BUF) != 0xffff))

View file

@ -151,6 +151,36 @@ static bool check_destipaddr(FAR struct net_driver_s *dev,
return false;
}
#if defined(CONFIG_NET_IPFRAG) || defined(CONFIG_NET_NAT66) || defined(CONFIG_NET_IPFILTER)
/****************************************************************************
* Name: ipv6_fragin_or_drop
*
* Description:
* Reassemble an incoming IPv6 fragment for NAT or local processing or drop
* it if fragment reassembly is not available.
*
****************************************************************************/
static int ipv6_fragin_or_drop(FAR struct net_driver_s *dev)
{
#ifdef CONFIG_NET_IPFRAG
if (ipv6_fragin(dev) == OK)
{
return OK;
}
#endif
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv6.drop++;
g_netstats.ipv6.fragerr++;
#endif
nwarn("WARNING: IPv6 fragment dropped\n");
dev->d_len = 0;
return OK;
}
#endif
/****************************************************************************
* Name: ipv6_in
*
@ -195,7 +225,7 @@ static int ipv6_in(FAR struct net_driver_s *dev)
#ifdef CONFIG_NET_IPFORWARD
int ret;
#endif
#ifdef CONFIG_NET_IPFRAG
#if defined(CONFIG_NET_IPFRAG) || defined(CONFIG_NET_NAT66) || defined(CONFIG_NET_IPFILTER)
bool isfrag = false;
#endif
@ -287,7 +317,7 @@ static int ipv6_in(FAR struct net_driver_s *dev)
if (nxthdr == NEXT_FRAGMENT_EH)
{
extlen = EXTHDR_FRAG_LEN;
#ifdef CONFIG_NET_IPFRAG
#if defined(CONFIG_NET_IPFRAG) || defined(CONFIG_NET_NAT66) || defined(CONFIG_NET_IPFILTER)
isfrag = true;
#endif
}
@ -301,6 +331,13 @@ static int ipv6_in(FAR struct net_driver_s *dev)
nxthdr = exthdr->nxthdr;
}
#if defined(CONFIG_NET_NAT66) || defined(CONFIG_NET_IPFILTER)
if (isfrag)
{
return ipv6_fragin_or_drop(dev);
}
#endif
#ifdef CONFIG_NET_NAT66
/* Try NAT inbound, rule matching will be performed in NAT module. */
@ -410,17 +447,7 @@ static int ipv6_in(FAR struct net_driver_s *dev)
#ifdef CONFIG_NET_IPFRAG
if (isfrag)
{
if (ipv6_fragin(dev) == OK)
{
return OK;
}
else
{
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv6.fragerr++;
#endif
goto drop;
}
return ipv6_fragin_or_drop(dev);
}
#endif

View file

@ -77,6 +77,11 @@ static int ipv4_hdrsize(FAR struct ipv4_hdr_s *ipv4)
iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
if ((ipv4->ipoffset[0] & 0x3f) != 0 || ipv4->ipoffset[1] != 0)
{
return iphdrlen;
}
/* Size is also determined by the following protocol header, */
switch (ipv4->proto)

View file

@ -360,6 +360,8 @@ int32_t ipv4_fragout(FAR struct net_driver_s *dev, uint16_t mtu)
uint32_t iter;
uint32_t nfrags;
uint16_t offset = 0;
uint16_t fragoff;
uint16_t morefrags;
uint16_t hdrlen;
FAR struct iob_s *frag = NULL;
FAR struct ipv4_hdr_s *ref = NULL;
@ -374,6 +376,14 @@ int32_t ipv4_fragout(FAR struct net_driver_s *dev, uint16_t mtu)
hdrlen = (IPv4BUF->vhl & IPv4_HLMASK) << 2;
/* Preserve the original fragment offset when splitting an
* already-fragmented packet for a smaller egress MTU.
*/
fragoff = (IPv4BUF->ipoffset[0] << 8) + IPv4BUF->ipoffset[1];
morefrags = fragoff & IP_FLAG_MOREFRAGS;
fragoff &= 0x1fff;
/* Reconstruct I/O Buffer according to MTU, which will reserve
* the space for the L3 header
*/
@ -401,13 +411,13 @@ int32_t ipv4_fragout(FAR struct net_driver_s *dev, uint16_t mtu)
/* Update the IPv4 header of the first fragment */
ipv4_fragout_buildipv4header(ref, ref, frag->io_pktlen,
IP_FLAG_MOREFRAGS);
fragoff | IP_FLAG_MOREFRAGS);
}
else
{
uint16_t ipoff = (offset - iter * hdrlen) >> 3;
uint16_t ipoff = fragoff + ((offset - iter * hdrlen) >> 3);
if (iter < nfrags - 1)
if (iter < nfrags - 1 || morefrags)
{
ipoff |= IP_FLAG_MOREFRAGS;
}

View file

@ -540,7 +540,7 @@ ipv6_nat_inbound_internal(FAR struct ipv6_hdr_s *ipv6,
uint8_t proto;
FAR void *l4hdr = net_ipv6_payload(ipv6, &proto);
switch (ipv6->proto)
switch (proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP: