diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/checksum.c | 79 | ||||
-rw-r--r-- | lib/checksum.h | 1 |
2 files changed, 80 insertions, 0 deletions
diff --git a/lib/checksum.c b/lib/checksum.c index 201da59f..88ec72a8 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -45,3 +45,82 @@ in_cksum(void *parg, int nbytes) answer = ~sum; /* ones-complement, then truncate to 16 bits */ return(answer); } + +/* Fletcher Checksum -- Refer to RFC1008. */ +#define MODX 4102 /* 5802 should be fine */ + +/* 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) +{ + u_int8_t *p; + int x; + int y; + u_int32_t mul; + u_int32_t c0; + u_int32_t c1; + u_int16_t checksum; + u_int16_t *csum; + int i, init_len, partial_len; + + checksum = 0; + + /* + * Zero the csum in the packet. + */ + csum = (u_int16_t *) (buffer + offset); + *(csum) = checksum; + + p = buffer; + c0 = 0; + c1 = 0; + init_len = len; + + while (len != 0) + { + partial_len = MIN(len, MODX); + + for (i = 0; i < partial_len; i++) + { + c0 = c0 + *(p++); + c1 += c0; + } + + c0 = c0 % 255; + c1 = c1 % 255; + + len -= partial_len; + } + + mul = (init_len - offset)*(c0); + + x = mul - c0 - c1; + y = c1 - mul - 1; + + if (y > 0) + y++; + if (x < 0) + x--; + + x %= 255; + y %= 255; + + if (x == 0) + x = 255; + if (y == 0) + y = 1; + + /* + * 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. + */ + buffer[offset] = x; + buffer[offset + 1] = y; + + /* Take care of the endian issue */ + checksum = htons((x << 8) | (y & 0xFF)); + + return checksum; +} diff --git a/lib/checksum.h b/lib/checksum.h index ccc4da03..d3ce9302 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1 +1,2 @@ extern int in_cksum(void *, int); +extern u_int16_t fletcher_checksum(u_char * buffer, int len, u_int16_t offset); |