From 61c67fc2295e522c7a12175581d6928c3951c0bf Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 30 Jan 2020 23:02:16 +0100 Subject: [PATCH] ip_forward: fix IPv4 forwarding with multiple netifs/offloading When we have multiple netifs where at least one has checksum offloading capabilities, IP forwarding needs to set various checksum fields to 0 to prevent HW algorithms on calculating an invalid checksum. -> set checksum fields of IP/UDP/TCP/ICMP to 0 in ip4_forward(). See bug #56288 Signed-off-by: Simon Goldschmidt --- src/core/ipv4/ip4.c | 31 +++++++++++++++++++++++++++++++ src/include/lwip/netif.h | 4 +++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 60d4042d..19144c92 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -336,6 +336,37 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100))); } + /* Take care of setting checksums to 0 for checksum offload netifs */ + if (CHECKSUM_GEN_IP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP)) { + IPH_CHKSUM_SET(iphdr, 0); + } + switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP +#if LWIP_UDPLITE + case IP_PROTO_UDPLITE: +#endif + case IP_PROTO_UDP: + if (CHECKSUM_GEN_UDP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_UDP)) { + ((struct udp_hdr *)((const u8_t *)iphdr + IPH_HL_BYTES(iphdr)))->chksum = 0; + } + break; +#endif +#if LWIP_TCP + case IP_PROTO_TCP: + if (CHECKSUM_GEN_TCP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_TCP)) { + ((struct tcp_hdr *)((const u8_t *)iphdr + IPH_HL_BYTES(iphdr)))->chksum = 0; + } + break; +#endif +#if LWIP_ICMP + case IP_PROTO_ICMP: + if (CHECKSUM_GEN_ICMP || NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP)) { + ((struct icmp_hdr *)((const u8_t *)iphdr + IPH_HL_BYTES(iphdr)))->chksum = 0; + } + break; +#endif + } + LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()), ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr()))); diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 1bdb14ee..900029e2 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -404,8 +404,10 @@ struct netif { #if LWIP_CHECKSUM_CTRL_PER_NETIF #define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ (netif)->chksum_flags = chksumflags; } while(0) -#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#define NETIF_CHECKSUM_ENABLED(netif, chksumflag) (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if NETIF_CHECKSUM_ENABLED(netif, chksumflag) #else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define NETIF_CHECKSUM_ENABLED(netif, chksumflag) 0 #define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) #define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */