diff options
-rw-r--r-- | lib/checksum.c | 46 | ||||
-rw-r--r-- | lib/checksum.h | 1 | ||||
-rw-r--r-- | ospf6d/ospf6_flood.c | 4 | ||||
-rw-r--r-- | ospf6d/ospf6_lsa.c | 54 | ||||
-rw-r--r-- | ospf6d/ospf6_lsa.h | 1 | ||||
-rw-r--r-- | ospfd/ospf_lsa.c | 12 | ||||
-rw-r--r-- | ospfd/ospf_packet.c | 2 |
7 files changed, 66 insertions, 54 deletions
diff --git a/lib/checksum.c b/lib/checksum.c index 3ddde8152..43940b715 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -51,6 +51,8 @@ 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 */ +/* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum + without modifying the buffer; a valid checksum returns 0 */ u_int16_t fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) { @@ -62,13 +64,14 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) checksum = 0; - assert (offset < len); - /* - * Zero the csum in the packet. - */ - csum = (u_int16_t *) (buffer + offset); - *(csum) = 0; + if (offset != FLETCHER_CHECKSUM_VALIDATE) + /* Zero the csum in the packet. */ + { + assert (offset < (len - 1)); /* account for two bytes of checksum */ + csum = (u_int16_t *) (buffer + offset); + *(csum) = 0; + } p = buffer; c0 = 0; @@ -89,7 +92,7 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) 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; @@ -98,17 +101,24 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) y = 510 - c0 - x; if (y > 255) y -= 255; - - /* - * 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)); + + if (offset == FLETCHER_CHECKSUM_VALIDATE) + { + checksum = (c1 << 8) + c0; + } + else + { + /* + * 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 da1d3cbad..b310f744c 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,2 +1,3 @@ extern int in_cksum(void *, int); +#define FLETCHER_CHECKSUM_VALIDATE 0xffff extern u_int16_t fletcher_checksum(u_char *, const size_t len, const uint16_t offset); diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 670c5d1d1..b81597290 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -733,7 +733,6 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, { struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL; int ismore_recent; - unsigned short cksum; int is_debug = 0; ismore_recent = 1; @@ -751,8 +750,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, } /* (1) LSA Checksum */ - cksum = ntohs (new->header->checksum); - if (ntohs (ospf6_lsa_checksum (new->header)) != cksum) + if (! ospf6_lsa_checksum_valid (new->header)) { if (is_debug) zlog_debug ("Wrong LSA Checksum, discard"); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index e65752d8c..ff061dfb1 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -29,6 +29,7 @@ #include "command.h" #include "memory.h" #include "thread.h" +#include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -672,47 +673,36 @@ ospf6_lsa_refresh (struct thread *thread) -/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */ -#define MODX 4102 -#define LSA_CHECKSUM_OFFSET 15 +/* Fletcher Checksum -- Refer to RFC1008. */ +/* All the offsets are zero-based. The offsets in the RFC1008 are + one-based. */ unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) { - u_char *sp, *ep, *p, *q; - int c0 = 0, c1 = 0; - int x, y; - u_int16_t length; + u_char *buffer = (u_char *) &lsa_header->type; + int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ - lsa_header->checksum = 0; - length = ntohs (lsa_header->length) - 2; - sp = (u_char *) &lsa_header->type; + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa_header->length) - type_offset; - for (ep = sp + length; sp < ep; sp = q) - { - q = sp + MODX; - if (q > ep) - q = ep; - for (p = sp; p < q; p++) - { - c0 += *p; - c1 += c0; - } - c0 %= 255; - c1 %= 255; - } + /* Checksum offset starts from "type" field, not the beginning of the + lsa_header struct. The offset is 14, rather than 16. */ + int checksum_offset = (u_char *) &lsa_header->checksum - buffer; + + return (unsigned short)fletcher_checksum(buffer, len, checksum_offset); +} - /* r = (c1 << 8) + c0; */ - x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; - if (x <= 0) - x += 255; - y = 510 - c0 - x; - if (y > 255) - y -= 255; +int +ospf6_lsa_checksum_valid (struct ospf6_lsa_header *lsa_header) +{ + u_char *buffer = (u_char *) &lsa_header->type; + int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ - lsa_header->checksum = htons ((x << 8) + y); + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa_header->length) - type_offset; - return (lsa_header->checksum); + return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); } void diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 7d93f5cba..263411fc7 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -237,6 +237,7 @@ extern int ospf6_lsa_expire (struct thread *); extern int ospf6_lsa_refresh (struct thread *); extern unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *); +extern int ospf6_lsa_checksum_valid (struct ospf6_lsa_header *); extern int ospf6_lsa_prohibited_duration (u_int16_t type, u_int32_t id, u_int32_t adv_router, void *scope); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 493209a0b..5579d8efd 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -192,6 +192,18 @@ ospf_lsa_checksum (struct lsa_header *lsa) return fletcher_checksum(buffer, len, checksum_offset); } +int +ospf_lsa_checksum_valid (struct lsa_header *lsa) +{ + u_char *buffer = (u_char *) &lsa->options; + int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ + + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa->length) - options_offset; + + return(fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); +} + /* Create OSPF LSA. */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 351fb210b..ede59088c 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1590,7 +1590,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, /* Validate the LSA's LS checksum. */ sum = lsah->checksum; - if (sum != ospf_lsa_checksum (lsah)) + if (! ospf_lsa_checksum_valid (lsah)) { /* (bug #685) more details in a one-line message make it possible * to identify problem source on the one hand and to have a better |