Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20db778e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ipv4-ipv6-csums'



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: default avatarDavid S. Miller <davem@davemloft.net>
parents fbd40ea0 08334824
Loading
Loading
Loading
Loading
+4 −8
Original line number Diff line number Diff line
@@ -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,
@@ -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
+2 −6
Original line number Diff line number Diff line
@@ -42,9 +42,7 @@ 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 +
@@ -52,9 +50,7 @@ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
}

__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;

+2 −2
Original line number Diff line number Diff line
@@ -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"
+7 −7
Original line number Diff line number Diff line
@@ -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"
@@ -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));
}
@@ -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));
+4 −6
Original line number Diff line number Diff line
@@ -111,8 +111,7 @@ static inline __sum16 csum_fold(__wsum sum)
}

static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
					       unsigned short len,
					       unsigned short proto,
					__u32 len, __u8 proto,
					__wsum sum)
{
	asm("	add	%0, %1\n"
@@ -132,8 +131,7 @@ 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,
					__u32 len, __u8 proto,
					__wsum sum)
{
	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
Loading