summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/checksum.c46
-rw-r--r--lib/checksum.h1
-rw-r--r--ospf6d/ospf6_flood.c4
-rw-r--r--ospf6d/ospf6_lsa.c54
-rw-r--r--ospf6d/ospf6_lsa.h1
-rw-r--r--ospfd/ospf_lsa.c12
-rw-r--r--ospfd/ospf_packet.c2
7 files changed, 66 insertions, 54 deletions
diff --git a/lib/checksum.c b/lib/checksum.c
index 3ddde815..43940b71 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 da1d3cba..b310f744 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 670c5d1d..b8159729 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 e65752d8..ff061dfb 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 7d93f5cb..263411fc 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 493209a0..5579d8ef 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 351fb210..ede59088 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