Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 53 additions & 16 deletions net/devif/ipv4_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@

#include <sys/ioctl.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/debug.h>
#include <string.h>

Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
Expand All @@ -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. */

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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))
Expand Down
53 changes: 40 additions & 13 deletions net/devif/ipv6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
}
Expand All @@ -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. */

Expand Down Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions net/ipforward/ipv4_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 13 additions & 3 deletions net/ipfrag/ipv4_frag.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
*/
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion net/nat/ipv6_nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading