diff options
-rw-r--r-- | lib/checksum.c | 76 |
1 files changed, 37 insertions, 39 deletions
diff --git a/lib/checksum.c b/lib/checksum.c index 88ec72a8..c9a590b9 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -14,27 +14,20 @@ in_cksum(void *parg, int nbytes) { u_short *ptr = parg; register long sum; /* assumes long == 32 bits */ - u_short oddbyte; register u_short answer; /* assumes u_short == 16 bits */ - + register int count; /* * Our algorithm is simple, using a 32-bit accumulator (sum), * we add sequential 16-bit words to it, and at the end, fold back * all the carry bits from the top 16 bits into the lower 16 bits. */ - sum = 0; - while (nbytes > 1) { - sum += *ptr++; - nbytes -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nbytes == 1) { - oddbyte = 0; /* make sure top half is zero */ - *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ - sum += oddbyte; - } + count = nbytes >> 1; /* div by 2 */ + for(ptr--; count; --count) + sum += *++ptr; + + if (nbytes & 1) /* Odd */ + sum += *(u_char *)(++ptr); /* one byte only */ /* * Add back carry outs from top 16 bits to low 16 bits. @@ -57,22 +50,22 @@ fletcher_checksum(u_char * buffer, int len, u_int16_t offset) u_int8_t *p; int x; int y; +#ifdef UNSIGNED_FLETCHER u_int32_t mul; - u_int32_t c0; - u_int32_t c1; - u_int16_t checksum; + u_int32_t c0, c1; +#else + int32_t c0, c1; +#endif u_int16_t *csum; - int i, init_len, partial_len; - - checksum = 0; + int init_len, partial_len; /* * Zero the csum in the packet. */ csum = (u_int16_t *) (buffer + offset); - *(csum) = checksum; + *csum = 0; - p = buffer; + p = buffer - 1; c0 = 0; c1 = 0; init_len = len; @@ -80,47 +73,52 @@ fletcher_checksum(u_char * buffer, int len, u_int16_t offset) while (len != 0) { partial_len = MIN(len, MODX); + len -= partial_len; - for (i = 0; i < partial_len; i++) + do { - c0 = c0 + *(p++); + c0 = c0 + *(++p); c1 += c0; - } + } while (--partial_len); c0 = c0 % 255; c1 = c1 % 255; - - len -= partial_len; } - +#ifdef UNSIGNED_FLETCHER + /* This can do both unsigned and signed c0, c1 and MODX=5802 + * but costs more instructions. + */ mul = (init_len - offset)*(c0); x = mul - c0 - c1; y = c1 - mul - 1; + x %= 255; + y %= 255; + if (y > 0) y++; if (x < 0) x--; - x %= 255; - y %= 255; - if (x == 0) x = 255; if (y == 0) y = 1; - +#else + x = ((init_len - offset - 1) * c0 - c1) % 255; + if (x <= 0) + x += 255; + y = 510 - c0 - x; + if (y > 255) + y -= 255; +#endif /* * Now we write this to the packet. * We could skip this step too, since the checksum returned would * be stored into the checksum field by the caller. + * Checksum is always big endian. */ - buffer[offset] = x; - buffer[offset + 1] = y; - - /* Take care of the endian issue */ - checksum = htons((x << 8) | (y & 0xFF)); - - return checksum; + *csum = htons((x << 8) | (y & 0xFF)); + return *csum; } |