summaryrefslogtreecommitdiffstats
path: root/lib/checksum.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/checksum.c')
-rw-r--r--lib/checksum.c96
1 files changed, 43 insertions, 53 deletions
diff --git a/lib/checksum.c b/lib/checksum.c
index c9a590b9..f6d74d31 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -14,20 +14,27 @@ 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;
- count = nbytes >> 1; /* div by 2 */
- for(ptr--; count; --count)
- sum += *++ptr;
- if (nbytes & 1) /* Odd */
- sum += *(u_char *)(++ptr); /* one byte only */
+ 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;
+ }
/*
* Add back carry outs from top 16 bits to low 16 bits.
@@ -45,80 +52,63 @@ in_cksum(void *parg, int nbytes)
/* To be consistent, offset is 0-based index, rather than the 1-based
index required in the specification ISO 8473, Annex C.1 */
u_int16_t
-fletcher_checksum(u_char * buffer, int len, u_int16_t offset)
+fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset)
{
u_int8_t *p;
- int x;
- int y;
-#ifdef UNSIGNED_FLETCHER
- u_int32_t mul;
- u_int32_t c0, c1;
-#else
- int32_t c0, c1;
-#endif
+ int x, y, c0, c1;
+ u_int16_t checksum;
u_int16_t *csum;
- int init_len, partial_len;
+ size_t partial_len, i, left = len;
+
+ checksum = 0;
+
+ assert (offset < len);
/*
* Zero the csum in the packet.
*/
csum = (u_int16_t *) (buffer + offset);
- *csum = 0;
+ *(csum) = 0;
- p = buffer - 1;
+ p = buffer;
c0 = 0;
c1 = 0;
- init_len = len;
- while (len != 0)
+ while (left != 0)
{
- partial_len = MIN(len, MODX);
- len -= partial_len;
+ partial_len = MIN(left, MODX);
- do
+ for (i = 0; i < partial_len; i++)
{
- c0 = c0 + *(++p);
+ c0 = c0 + *(p++);
c1 += c0;
- } while (--partial_len);
+ }
c0 = c0 % 255;
c1 = c1 % 255;
- }
-#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--;
+ left -= partial_len;
+ }
+
+ /* The cast is important, to ensure the mod is taken as a signed value. */
+ x = ((int)(len - offset - 1) * c0 - c1) % 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)
+ 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.
*/
- *csum = htons((x << 8) | (y & 0xFF));
- return *csum;
+ buffer[offset] = x;
+ buffer[offset + 1] = y;
+
+ /* Take care of the endian issue */
+ checksum = htons((x << 8) | (y & 0xFF));
+
+ return checksum;
}