diff --git a/net/Kconfig b/net/Kconfig index 1e2abd5c3a..3acaaf63a0 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -260,6 +260,39 @@ config NET_IPv4 ---help--- Build in support for IPv4. +config NET_IPv4_REASSEMBLY + bool "IPv4 reassembly" + default n + depends on NET_IPv4 && EXPERIMENTAL && NET_ETHERNET + ---help--- + Enable support for IP packet reassembly of fragmented IP packets. + + This features requires an additional amount of RAM to hold a single + reassembly buffer. The reassembly buffer is of the same size as the + MTU of the selected device. + + REVISIT: There are multiple issues with the current implementation: + 1. IPv4 reassembly in its current form is untested (and, hence, + depends on CONFIG_EXPERIMENTAL). + 2. Currently this feature can only work with Ethernet due to internal + definitions that depend on Ethernet configuration settings (and, + hence, depends on CONFIG_NET_ETHERNET). + 3. Since there is only a single reassembly buffer, IPv4 reassembly + cannot be used in a context where multiple network devices may be + concurrently re-assemblying packets. + +if NET_IPv4_REASSEMBLY + +config NET_IPv4_REASS_MAXAGE + int "IP fragment timeout" + default 200 + ---help--- + The maximum time an IP fragment should wait in the reassembly buffer + before it is dropped. Units are deci-seconds, the range of the timer + is 8-bits. Default: 20 seconds. + +endif # NET_IPv4_REASSEMBLY + config NET_IPv6 bool "IPv6" default n diff --git a/net/devif/devif.h b/net/devif/devif.h index c53288ac63..affb0d2dd2 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -289,7 +289,7 @@ extern "C" #define EXTERN extern #endif -#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_TCP_REASSEMBLY) +#ifdef CONFIG_NET_IPv4_REASSEMBLY /* Reassembly timer (units: deci-seconds) */ EXTERN uint8_t g_reassembly_timer; diff --git a/net/devif/devif_initialize.c b/net/devif/devif_initialize.c index c345877b1b..40a1433260 100644 --- a/net/devif/devif_initialize.c +++ b/net/devif/devif_initialize.c @@ -66,7 +66,7 @@ struct net_stats_s g_netstats; #endif -#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_TCP_REASSEMBLY) +#ifdef CONFIG_NET_IPv4_REASSEMBLY /* Reassembly timer (units: deci-seconds) */ uint8_t g_reassembly_timer; diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 0d636dcdcc..b0d79ac9ae 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -737,11 +737,11 @@ int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback) /* Perform periodic activitives that depend on hsec > 0 */ -#if defined(CONFIG_NET_TCP_REASSEMBLY) && defined(CONFIG_NET_IPv4) +#ifdef CONFIG_NET_IPv4_REASSEMBLY /* Increment the timer used by the IP reassembly logic */ if (g_reassembly_timer != 0 && - g_reassembly_timer < CONFIG_NET_TCP_REASS_MAXAGE) + g_reassembly_timer < CONFIG_NET_IPv4_REASS_MAXAGE) { g_reassembly_timer += hsec; } diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c index 3e7a659a0e..ea16ae3947 100644 --- a/net/devif/ipv4_input.c +++ b/net/devif/ipv4_input.c @@ -2,7 +2,8 @@ * net/devif/ipv4_input.c * Device driver IPv4 packet receipt interface * - * Copyright (C) 2007-2009, 2013-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013-2015, 2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: @@ -112,20 +113,29 @@ #define BUF ((FAR struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) #define FBUF ((FAR struct ipv4_hdr_s *)&g_reassembly_buffer[0]) -/* IP fragment re-assembly */ +/* IP fragment re-assembly. + * + * REVISIT: There are multiple issues with the current implementation: + * 1. IPv4 reassembly is untested. + * 2. Currently can only work with Ethernet due to the definition of + * IPv4_REASS_BUFSIZE. + * 3. Since there is only a single reassembly buffer, IPv4 reassembly cannot + * be used in a context where multiple network devices may be concurrently + * re-assemblying packets. + */ #define IP_MF 0x20 /* See IP_FLAG_MOREFRAGS */ -#define TCP_REASS_BUFSIZE (NET_DEV_MTU(dev) - NET_LL_HDRLEN(dev)) -#define TCP_REASS_LASTFRAG 0x01 +#define IPv4_REASS_BUFSIZE (CONFIG_NET_ETH_MTU - ETH_HDRLEN) +#define IPv4_REASS_LASTFRAG 0x01 /**************************************************************************** * Private Data ****************************************************************************/ -#if defined(CONFIG_NET_TCP_REASSEMBLY) && !defined(CONFIG_NET_IPv6) +#ifdef CONFIG_NET_IPv4_REASSEMBLY -static uint8_t g_reassembly_buffer[TCP_REASS_BUFSIZE]; -static uint8_t g_reassembly_bitmap[TCP_REASS_BUFSIZE / (8 * 8)]; +static uint8_t g_reassembly_buffer[IPv4_REASS_BUFSIZE]; +static uint8_t g_reassembly_bitmap[IPv4_REASS_BUFSIZE / (8 * 8)]; static const uint8_t g_bitmap_bits[8] = { @@ -135,7 +145,7 @@ static const uint8_t g_bitmap_bits[8] = static uint16_t g_reassembly_len; static uint8_t g_reassembly_flags; -#endif /* CONFIG_NET_TCP_REASSEMBLY */ +#endif /* CONFIG_NET_IPv4_REASSEMBLY */ /**************************************************************************** * Private Functions @@ -151,8 +161,8 @@ static uint8_t g_reassembly_flags; * ****************************************************************************/ -#if defined(CONFIG_NET_TCP_REASSEMBLY) && !defined(CONFIG_NET_IPv6) -static uint8_t devif_reassembly(void) +#ifdef CONFIG_NET_IPv4_REASSEMBLY +static uint8_t devif_reassembly(FAR struct net_driver_s *dev) { FAR struct ipv4_hdr_s *ipv4 = BUF; FAR struct ipv4_hdr_s *fipv4 = FBUF; @@ -168,7 +178,7 @@ static uint8_t devif_reassembly(void) if (!g_reassembly_timer) { memcpy(g_reassembly_buffer, &ipv4->vhl, IPv4_HDRLEN); - g_reassembly_timer = CONFIG_NET_TCP_REASS_MAXAGE; + g_reassembly_timer = CONFIG_NET_IPv4_REASS_MAXAGE; g_reassembly_flags = 0; /* Clear the bitmap. */ @@ -183,16 +193,17 @@ static uint8_t devif_reassembly(void) if (net_ipv4addr_hdrcmp(ipv4->srcipaddr, fipv4->srcipaddr) && net_ipv4addr_hdrcmp(ipv4->destipaddr, fipv4->destipaddr) && - ipv4->g_ipid[0] == fipv4->g_ipid[0] && ipv4->g_ipid[1] == fipv4->g_ipid[1]) + ipv4->ipid[0] == fipv4->ipid[0] && ipv4->ipid[1] == fipv4->ipid[1]) { - len = (ipv4->len[0] << 8) + ipv4->len[1] - (ipv4->vhl & 0x0f) * 4; + len = ((uint16_t)ipv4->len[0] << 8) + (uint16_t)ipv4->len[1] - + (uint16_t)(ipv4->vhl & 0x0f) * 4; offset = (((ipv4->ipoffset[0] & 0x3f) << 8) + ipv4->ipoffset[1]) * 8; /* If the offset or the offset + fragment length overflows the * reassembly buffer, we discard the entire packet. */ - if (offset > TCP_REASS_BUFSIZE || offset + len > TCP_REASS_BUFSIZE) + if (offset > IPv4_REASS_BUFSIZE || offset + len > IPv4_REASS_BUFSIZE) { g_reassembly_timer = 0; goto nullreturn; @@ -240,7 +251,7 @@ static uint8_t devif_reassembly(void) if ((ipv4->ipoffset[0] & IP_MF) == 0) { - g_reassembly_flags |= TCP_REASS_LASTFRAG; + g_reassembly_flags |= IPv4_REASS_LASTFRAG; g_reassembly_len = offset + len; } @@ -249,7 +260,7 @@ static uint8_t devif_reassembly(void) * are set. */ - if (g_reassembly_flags & TCP_REASS_LASTFRAG) + if (g_reassembly_flags & IPv4_REASS_LASTFRAG) { /* Check all bytes up to and including all but the last byte in * the bitmap. @@ -298,7 +309,7 @@ static uint8_t devif_reassembly(void) nullreturn: return 0; } -#endif /* CONFIG_NET_TCP_REASSEMBLY */ +#endif /* CONFIG_NET_IPv4_REASSEMBLY */ /**************************************************************************** * Public Functions @@ -380,20 +391,18 @@ int ipv4_input(FAR struct net_driver_s *dev) if ((ipv4->ipoffset[0] & 0x3f) != 0 || ipv4->ipoffset[1] != 0) { -#if defined(CONFIG_NET_TCP_REASSEMBLY) - dev->d_len = devif_reassembly(); +#ifdef CONFIG_NET_IPv4_REASSEMBLY + dev->d_len = devif_reassembly(dev); if (dev->d_len == 0) +#endif { +#ifdef CONFIG_NET_STATISTICS + g_netstats.ipv4.drop++; + g_netstats.ipv4.fragerr++; +#endif + nwarn("WARNING: IP fragment dropped\n"); goto drop; } -#else /* CONFIG_NET_TCP_REASSEMBLY */ -#ifdef CONFIG_NET_STATISTICS - g_netstats.ipv4.drop++; - g_netstats.ipv4.fragerr++; -#endif - nwarn("WARNING: IP fragment dropped\n"); - goto drop; -#endif /* CONFIG_NET_TCP_REASSEMBLY */ } /* Get the destination IP address in a friendlier form */ diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index 306fbd1bc2..4b7b7059f5 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -35,33 +35,6 @@ config NET_TCPURGDATA compiled in. Urgent data (out-of-band data) is a rarely used TCP feature that is very seldom would be required. -config NET_TCP_REASSEMBLY - bool "TCP reassembly" - default n - depends on EXPERIMENTAL - ---help--- - Enable support for IP packet reassembly of fragmented IP packets. - - This features requires an additional amount of RAM to hold the - reassembly buffer and the reassembly code size is approximately 700 - bytes. The reassembly buffer is of the same size as the d_buf buffer - (configured by CONFIG_NET_xxx_MTU). - - Note: IP packet reassembly is not heavily tested (and, hence, - EXPERIMENTAL). - -if NET_TCP_REASSEMBLY - -config NET_TCP_REASS_MAXAGE - int "IP fragment timeout" - default 200 - ---help--- - The maximum time an IP fragment should wait in the reassembly buffer - before it is dropped. Units are deci-seconds, the range of the timer - is 8-bits. Default: 20 seconds. - -endif # NET_TCP_REASSEMBLY - config NET_TCP_CONNS int "Number of TCP/IP connections" default 8 diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index 8eaa3adbe7..5e1b5f9346 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -111,7 +111,13 @@ static void tcp_input(FAR struct net_driver_s *dev, uint8_t domain, tcp = (FAR struct tcp_hdr_s *)&dev->d_buf[iplen + NET_LL_HDRLEN(dev)]; - /* Get the size of the IP header and the TCP header */ + /* Get the size of the IP header and the TCP header. + * + * REVISIT: TCP header is *not* a constant! It can be larger if the + * TCP header includes options. The constand TCP_HDRLEN should be + * replaced with the macro TCP_OPT_HDRLEN(n) which will calculate the + * correct header length in all cases. + */ tcpiplen = iplen + TCP_HDRLEN;