/* 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)
{
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;
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;
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;
}
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);
{
struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL;
int ismore_recent;
- unsigned short cksum;
int is_debug = 0;
ismore_recent = 1;
}
/* (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");
#include "command.h"
#include "memory.h"
#include "thread.h"
+#include "checksum.h"
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
\f
-/* 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
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);
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);
+}
+
\f
/* Create OSPF LSA. */
/* 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