summaryrefslogtreecommitdiff
path: root/lib/csum.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2010-03-08 13:33:13 -0800
committerBen Pfaff <blp@nicira.com>2010-03-08 13:33:13 -0800
commit4787d6d7df196ff7463517423dfbdfd41bdceffe (patch)
tree606adb1b02b7acdd60c0616dbfb10654ae6513b9 /lib/csum.c
parentee402caec46c116a862b716cb4851ff5be371c9f (diff)
downloadopenvswitch-4787d6d7df196ff7463517423dfbdfd41bdceffe.tar.gz
csum: Fix rare error cases in checksum computation.
Occasionally the checksum test on "make check" would fail. This commit fixes the problem, which was that the partial checksum may need more than one reduction step to obtain a final checksum. Now running checksum tests in a continuous loop yields no failures.
Diffstat (limited to 'lib/csum.c')
-rw-r--r--lib/csum.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/lib/csum.c b/lib/csum.c
index 6f044473e..922f68625 100644
--- a/lib/csum.c
+++ b/lib/csum.c
@@ -76,7 +76,10 @@ csum_continue(uint32_t partial, const void *data_, size_t n)
uint16_t
csum_finish(uint32_t partial)
{
- return ~((partial & 0xffff) + (partial >> 16));
+ while (partial >> 16) {
+ partial = (partial & 0xffff) + (partial >> 16);
+ }
+ return ~partial;
}
/* Returns the new checksum for a packet in which the checksum field previously
@@ -93,8 +96,7 @@ recalc_csum16(uint16_t old_csum, uint16_t old_u16, uint16_t new_u16)
uint16_t m_complement = ~old_u16;
uint16_t m_prime = new_u16;
uint32_t sum = hc_complement + m_complement + m_prime;
- uint16_t hc_prime_complement = sum + (sum >> 16);
- return ~hc_prime_complement;
+ return csum_finish(sum);
}
/* Returns the new checksum for a packet in which the checksum field previously