summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/checksum.c76
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;
}