Skip to content

Commit

Permalink
Merge branch 'ipv4-ipv6-csums'
Browse files Browse the repository at this point in the history
Alexander Duyck says:

====================
Fix differences between IPv4 and IPv6 TCP/UDP checksum calculation

This patch series is meant to address the differences that exist between
IPv4 and IPv6 in terms of checksum calculation.  Specifically the IPv6
function csum_ipv6_magic treated length as a value that could be greater
than 64K, while csum_tcpudp_magic was truncating the length at 16 bits.
After looking over the code and giving it some thought I decided it would
be best to update the IPv4 function so that it worked the same way the IPv6
one did.  This allows us to get the same results given the same inputs for
both functions.  As a result we can use the same processes to reverse the
calculation in the event we need to do something like remove the length of
the pseudo-header checksum.

I also took the opportunity to standardize things so that the parameters
for these functions all use the correct types.  IPv4 addresses are __be32,
length should always be __u32, and protocol is a __u8.

With this change in place it corrects an issue with UDP tunnels in which we
were getting a checksum that was off by 1 when performing fragmentation on
inner UDP packets.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 14, 2016
2 parents fbd40ea + 0833482 commit 20db778
Show file tree
Hide file tree
Showing 40 changed files with 137 additions and 184 deletions.
12 changes: 4 additions & 8 deletions arch/alpha/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
* computes the checksum of the TCP/UDP pseudo-header
* returns a 16-bit checksum, already complemented
*/
extern __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum);
__sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum);

__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
unsigned short len, unsigned short proto,
__wsum sum);
__u32 len, __u8 proto, __wsum sum);

/*
* computes the checksum of a memory block at buff, length len,
Expand Down Expand Up @@ -70,6 +67,5 @@ static inline __sum16 csum_fold(__wsum csum)
#define _HAVE_ARCH_IPV6_CSUM
extern __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr,
__u32 len, unsigned short proto,
__wsum sum);
__u32 len, __u8 proto, __wsum sum);
#endif
8 changes: 2 additions & 6 deletions arch/alpha/lib/checksum.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,15 @@ static inline unsigned short from64to16(unsigned long x)
* returns a 16-bit checksum, already complemented.
*/
__sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto, __wsum sum)
{
return (__force __sum16)~from64to16(
(__force u64)saddr + (__force u64)daddr +
(__force u64)sum + ((len + proto) << 8));
}

__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto, __wsum sum)
{
unsigned long result;

Expand Down
4 changes: 2 additions & 2 deletions arch/arc/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ ip_fast_csum(const void *iph, unsigned int ihl)
* SA [4], DA [4], zeroes [1], Proto[1], TCP Seg(hdr+data) Len [2]
*/
static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
__asm__ __volatile__(
" add.f %0, %0, %1 \n"
Expand Down
14 changes: 7 additions & 7 deletions arch/arm/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ ip_fast_csum(const void *iph, unsigned int ihl)
}

static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
u32 lenprot = len | proto << 16;
u32 lenprot = len + proto;
if (__builtin_constant_p(sum) && sum == 0) {
__asm__(
"adds %0, %1, %2 @ csum_tcpudp_nofold0 \n\t"
Expand Down Expand Up @@ -121,8 +121,8 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
* returns a 16-bit checksum, already complemented
*/
static inline __sum16
csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
}
Expand All @@ -144,8 +144,8 @@ __csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr, __
__be32 proto, __wsum sum);

static inline __sum16
csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr, __u32 len,
unsigned short proto, __wsum sum)
csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
__u32 len, __u8 proto, __wsum sum)
{
return csum_fold(__csum_ipv6_magic(saddr, daddr, htonl(len),
htonl(proto), sum));
Expand Down
10 changes: 4 additions & 6 deletions arch/avr32/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,8 @@ static inline __sum16 csum_fold(__wsum sum)
}

static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto,
__wsum sum)
{
asm(" add %0, %1\n"
" adc %0, %0, %2\n"
Expand All @@ -132,9 +131,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
* returns a 16-bit checksum, already complemented
*/
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto,
__wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
}
Expand Down
4 changes: 2 additions & 2 deletions arch/blackfin/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
*/

static inline __wsum
__csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
__csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
unsigned int carry;

Expand Down
4 changes: 2 additions & 2 deletions arch/c6x/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#define _ASM_C6X_CHECKSUM_H

static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
unsigned long long tmp;

Expand Down
4 changes: 2 additions & 2 deletions arch/cris/include/arch-v10/arch/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
*/

static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
__wsum res;
__asm__ ("add.d %2, %0\n\t"
Expand Down
2 changes: 1 addition & 1 deletion arch/cris/include/arch-v32/arch/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/
static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
unsigned short len, unsigned short proto, __wsum sum)
__u32 len, __u8 proto, __wsum sum)
{
__wsum res;

Expand Down
5 changes: 2 additions & 3 deletions arch/cris/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
*/

static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto,
__wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
}
Expand Down
10 changes: 5 additions & 5 deletions arch/frv/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ static inline __sum16 csum_fold(__wsum sum)
* returns a 16-bit checksum, already complemented
*/
static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
asm(" addcc %1,%0,%0,icc0 \n"
" addxcc %2,%0,%0,icc0 \n"
Expand All @@ -120,8 +120,8 @@ csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
}

static inline __sum16
csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
}
Expand All @@ -135,7 +135,7 @@ extern __sum16 ip_compute_csum(const void *buff, int len);
#define _HAVE_ARCH_IPV6_CSUM
static inline __sum16
csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
__u32 len, unsigned short proto, __wsum sum)
__u32 len, __u8 proto, __wsum sum)
{
unsigned long tmp, tmp2;

Expand Down
8 changes: 4 additions & 4 deletions arch/hexagon/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst,
* returns a 16-bit checksum, already complemented
*/
#define csum_tcpudp_nofold csum_tcpudp_nofold
__wsum csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
unsigned short len, unsigned short proto, __wsum sum);
__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum);

#define csum_tcpudp_magic csum_tcpudp_magic
__sum16 csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
unsigned short len, unsigned short proto, __wsum sum);
__sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum);

#include <asm-generic/checksum.h>

Expand Down
10 changes: 4 additions & 6 deletions arch/hexagon/lib/checksum.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,16 @@ static inline unsigned short from64to16(u64 x)
* computes the checksum of the TCP/UDP pseudo-header
* returns a 16-bit checksum, already complemented.
*/
__sum16 csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
unsigned short len, unsigned short proto,
__wsum sum)
__sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum)
{
return (__force __sum16)~from64to16(
(__force u64)saddr + (__force u64)daddr +
(__force u64)sum + ((len + proto) << 8));
}

__wsum csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
unsigned short len, unsigned short proto,
__wsum sum)
__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum)
{
u64 result;

Expand Down
16 changes: 6 additions & 10 deletions arch/ia64/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,11 @@ extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
* Computes the checksum of the TCP/UDP pseudo-header returns a 16-bit
* checksum, already complemented
*/
extern __sum16 csum_tcpudp_magic (__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum);
extern __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum);

extern __wsum csum_tcpudp_nofold (__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum);
extern __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto, __wsum sum);

/*
* Computes the checksum of a memory block at buff, length len,
Expand Down Expand Up @@ -73,7 +69,7 @@ static inline __sum16 csum_fold(__wsum csum)
#define _HAVE_ARCH_IPV6_CSUM 1
struct in6_addr;
extern __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr, __u32 len, unsigned short proto,
__wsum csum);
const struct in6_addr *daddr,
__u32 len, __u8 proto, __wsum csum);

#endif /* _ASM_IA64_CHECKSUM_H */
8 changes: 4 additions & 4 deletions arch/ia64/lib/checksum.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ from64to16 (unsigned long x)
* returns a 16-bit checksum, already complemented.
*/
__sum16
csum_tcpudp_magic (__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
return (__force __sum16)~from64to16(
(__force u64)saddr + (__force u64)daddr +
Expand All @@ -45,8 +45,8 @@ csum_tcpudp_magic (__be32 saddr, __be32 daddr, unsigned short len,
EXPORT_SYMBOL(csum_tcpudp_magic);

__wsum
csum_tcpudp_nofold (__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
unsigned long result;

Expand Down
10 changes: 4 additions & 6 deletions arch/m32r/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,8 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
}

static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto,
__wsum sum)
{
#if defined(__LITTLE_ENDIAN)
unsigned long len_proto = (proto + len) << 8;
Expand Down Expand Up @@ -145,9 +144,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
* returns a 16-bit checksum, already complemented
*/
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__wsum sum)
__u32 len, __u8 proto,
__wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
}
Expand Down
2 changes: 1 addition & 1 deletion arch/m68k/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static inline __sum16 ip_compute_csum(const void *buff, int len)
#define _HAVE_ARCH_IPV6_CSUM
static __inline__ __sum16
csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
__u32 len, unsigned short proto, __wsum sum)
__u32 len, __u8 proto, __wsum sum)
{
register unsigned long tmp;
__asm__("addl %2@,%0\n\t"
Expand Down
7 changes: 3 additions & 4 deletions arch/metag/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
* returns a 16-bit checksum, already complemented
*/
static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
unsigned short len,
unsigned short proto,
__u32 len, __u8 proto,
__wsum sum)
{
unsigned long len_proto = (proto + len) << 8;
Expand All @@ -78,8 +77,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
}

static inline __sum16
csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
}
Expand Down
4 changes: 2 additions & 2 deletions arch/microblaze/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/
#define csum_tcpudp_nofold csum_tcpudp_nofold
static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
__asm__("add %0, %0, %1\n\t"
"addc %0, %0, %2\n\t"
Expand Down
8 changes: 4 additions & 4 deletions arch/mips/include/asm/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
}
#define ip_fast_csum ip_fast_csum

static inline __wsum csum_tcpudp_nofold(__be32 saddr,
__be32 daddr, unsigned short len, unsigned short proto,
__wsum sum)
static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto,
__wsum sum)
{
__asm__(
" .set push # csum_tcpudp_nofold\n"
Expand Down Expand Up @@ -215,7 +215,7 @@ static inline __sum16 ip_compute_csum(const void *buff, int len)
#define _HAVE_ARCH_IPV6_CSUM
static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr,
__u32 len, unsigned short proto,
__u32 len, __u8 proto,
__wsum sum)
{
__wsum tmp;
Expand Down
Loading

0 comments on commit 20db778

Please sign in to comment.