diff options
author | Jingjing Duan <Jingjing.Duan@sun.com> | 2008-08-13 19:02:03 +0100 |
---|---|---|
committer | Paul Jakma <paul@quagga.net> | 2008-08-22 19:52:57 +0100 |
commit | efda3bb8e548fee84928ff23329c11de8e742ecd (patch) | |
tree | d49dd2cdcf1d995be81c9cf56ddda6a25d3aba22 /lib | |
parent | 40da22166ff29753a65b7947ed5fa7261fee1d80 (diff) |
[lib] Add fletcher checksum implementation
2008-08-13 Jingjing Duan <Jingjing.Duan@sun.com>
* lib/checksum.?: (fletcher_checksum) implementation of
Fletcher checksum, as per RFC1008.
Signed-off-by: Paul Jakma <paul@quagga.net>
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); |