diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/ospf/lsalib.c | 28 | ||||
-rw-r--r-- | proto/ospf/lsalib.h | 2 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 2 |
3 files changed, 25 insertions, 7 deletions
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index 579d13e8..ce6fb178 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -205,7 +205,7 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body) buf_dump("CALC", buf, length); */ - (void) lsasum_check(h, body); + (void) lsasum_check(h, body, 1); // log(L_WARN "Checksum result %4x", h->checksum); @@ -214,11 +214,21 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body) } /* - * Note, that this function expects that LSA is in big endianity - * It also returns value in big endian + * Calculates the Fletcher checksum of an OSPF LSA. + * + * If 'update' is non-zero, the checkbytes (X and Y in RFC905) are calculated + * and the checksum field in the header is updated. The return value is the + * checksum as placed in the header (in network byte order). + * + * If 'update' is zero, only C0 and C1 are calculated and the header is kept + * intact. The return value is a combination of C0 and C1; if the return value + * is exactly zero the checksum is considered valid, any non-zero value is + * invalid. + * + * Note that this function expects the input LSA to be in network byte order. */ u16 -lsasum_check(struct ospf_lsa_header *h, void *body) +lsasum_check(struct ospf_lsa_header *h, void *body, int update) { u8 *sp, *ep, *p, *q, *b; int c0 = 0, c1 = 0; @@ -229,7 +239,7 @@ lsasum_check(struct ospf_lsa_header *h, void *body) sp = (char *) h; sp += 2; /* Skip Age field */ length = ntohs(h->length) - 2; - h->checksum = 0; + if (update) h->checksum = 0; for (ep = sp + length; sp < ep; sp = q) { /* Actually MODX is very large, do we need the for-cyclus? */ @@ -259,6 +269,14 @@ lsasum_check(struct ospf_lsa_header *h, void *body) c1 %= 255; } + if (!update) { + /* + * When testing the checksum, we don't need to calculate x and y. The + * checksum passes if c0 and c1 are both 0. + */ + return (c0 << 8) | (c1 & 0xff); + } + x = (int)((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; if (x <= 0) x += 255; diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h index d9e1a610..4ad770e8 100644 --- a/proto/ospf/lsalib.h +++ b/proto/ospf/lsalib.h @@ -48,7 +48,7 @@ static inline u32 lsa_get_etype(struct ospf_lsa_header *h, struct ospf_proto *p) int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa); void lsasum_calculate(struct ospf_lsa_header *header, void *body); -u16 lsasum_check(struct ospf_lsa_header *h, void *body); +u16 lsasum_check(struct ospf_lsa_header *h, void *body, int update); #define CMP_NEWER 1 #define CMP_SAME 0 #define CMP_OLDER -1 diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index ea32923a..6e7dce26 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -531,7 +531,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa, lsa_type, lsa.id, lsa.rt, lsa.sn, lsa.age, lsa.checksum); /* RFC 2328 13. (1) - validate LSA checksum */ - if (lsa_n->checksum != lsasum_check(lsa_n, NULL)) + if ((lsa_n->checksum == 0) || (lsasum_check(lsa_n, NULL, 0) != 0)) SKIP("invalid checksum"); /* RFC 2328 13. (2) */ |