csum: Fix rare error cases in checksum computation.
authorBen Pfaff <blp@nicira.com>
Mon, 8 Mar 2010 21:33:13 +0000 (13:33 -0800)
committerBen Pfaff <blp@nicira.com>
Mon, 8 Mar 2010 21:33:13 +0000 (13:33 -0800)
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.

lib/csum.c

index 6f044473e2f87607ccdd071e87f28540b25a048d..922f686257594caf2e7f7af3d03b0d9c485b8c02 100644 (file)
@@ -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