This is a much simpler and efficent impl. of the IP checksum. It is a dry port from Quagga and I have not tested it. --- lib/checksum.c | 44 +++++++++++--------------------------------- 1 files changed, 11 insertions(+), 33 deletions(-)
diff --git a/lib/checksum.c b/lib/checksum.c index 33cb386..b836bdb 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -15,25 +15,10 @@ #include "nest/bird.h" #include "checksum.h" -static u16 /* One-complement addition */ -add16(u16 sum, u16 x) -{ - u16 z = sum + x; - return z + (z < sum); -} - -static u32 -add32(u32 sum, u32 x) -{ - u32 z = sum + x; - return z + (z < sum); -} - static u16 ipsum_calc_block(u16 *x, unsigned len, u16 sum) { - int rest; - u32 tmp, *xx; + u32 tmp; /* * A few simple facts about the IP checksum (see RFC 1071 for detailed @@ -51,23 +36,16 @@ ipsum_calc_block(u16 *x, unsigned len, u16 sum) if (!len) return sum; len >>= 1; - if ((unsigned long) x & 2) /* Align to 32-bit boundary */ - { - sum = add16(sum, *x++); - len--; - } - rest = len & 1; - len >>= 1; - tmp = 0; - xx = (u32 *) x; - while (len) - { - tmp = add32(tmp, *xx++); - len--; - } - sum = add16(sum, add16(tmp & 0xffff, tmp >> 16U)); - if (rest) - sum = add16(sum, *(u16 *) xx); + tmp = sum; + for(x--; len; --len) + tmp += *++x; + /* + * Add back carry outs from top 16 bits to low 16 bits. + */ + tmp = (tmp >> 16) + (tmp & 0xffff); /* add high-16 to low-16 */ + tmp += (tmp >> 16); /* add carry */ + sum = ~tmp; /* ones-complement, then truncate to 16 bits */ + return sum; } -- 1.6.4.4