From c44ba9f6684946b156335da6a6d55f0b8cf7cb72 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 23 Jun 2009 21:22:58 +0200 Subject: lib/checksum.c: use 32-bit arithmetic consistently The use of 'unsigned long' variables in the 32-bit part of do_csum() is confusing at best, and potentially broken for long input on 64-bit machines. This changes the code to use 'unsigned int' instead, which makes the code behave in the same (correct) way on both 32 and 64 bit machines. Reported-by: Linus Torvalds Signed-off-by: Arnd Bergmann --- lib/checksum.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/checksum.c b/lib/checksum.c index b2e2fd468461..886b48db4f28 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -37,7 +37,7 @@ #include -static inline unsigned short from32to16(unsigned long x) +static inline unsigned short from32to16(unsigned int x) { /* add up 16-bit and 16-bit for 16+c bit */ x = (x & 0xffff) + (x >> 16); @@ -49,7 +49,7 @@ static inline unsigned short from32to16(unsigned long x) static unsigned int do_csum(const unsigned char *buff, int len) { int odd, count; - unsigned long result = 0; + unsigned int result = 0; if (len <= 0) goto out; @@ -73,9 +73,9 @@ static unsigned int do_csum(const unsigned char *buff, int len) } count >>= 1; /* nr of 32-bit words.. */ if (count) { - unsigned long carry = 0; + unsigned int carry = 0; do { - unsigned long w = *(unsigned int *) buff; + unsigned int w = *(unsigned int *) buff; count--; buff += 4; result += carry; -- cgit v1.2.3-59-g8ed1b From 20c1f641bb80fb272dec959a5caabed92e5a422e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 23 Jun 2009 21:37:26 +0200 Subject: lib/checksum.c: make do_csum optional Mike Frysinger suggested that do_csum should be optional so that an architecture can use the generic checksum code but still provide an optimized fast-path for the most critical function. This can mean an implementation using inline assembly, or in case of Alpha one using 64-bit arithmetic in C. Cc: Mike Frysinger Signed-off-by: Arnd Bergmann --- lib/checksum.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/checksum.c b/lib/checksum.c index 886b48db4f28..b08c2d059024 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -37,6 +37,7 @@ #include +#ifndef do_csum static inline unsigned short from32to16(unsigned int x) { /* add up 16-bit and 16-bit for 16+c bit */ @@ -102,6 +103,7 @@ static unsigned int do_csum(const unsigned char *buff, int len) out: return result; } +#endif /* * This is a version of ip_compute_csum() optimized for IP headers, -- cgit v1.2.3-59-g8ed1b From 0a5549ed163520787f76b7515dfe9d9aa1c7ae37 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 23 Jun 2009 22:52:51 +0200 Subject: lib/checksum: fix one more thinko When do_csum gets unaligned data, we really need to treat the first byte as an even byte, not an odd byte, because we swap the two halves later. Found by Mike's checksum-selftest module. Reported-by: Mike Frysinger Signed-off-by: Arnd Bergmann --- lib/checksum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/checksum.c b/lib/checksum.c index b08c2d059024..097508732f34 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -57,9 +57,9 @@ static unsigned int do_csum(const unsigned char *buff, int len) odd = 1 & (unsigned long) buff; if (odd) { #ifdef __LITTLE_ENDIAN - result = *buff; -#else result += (*buff << 8); +#else + result = *buff; #endif len--; buff++; -- cgit v1.2.3-59-g8ed1b