From 6a270cd93d02a88709e7292684db47552b630abf Mon Sep 17 00:00:00 2001 From: Jingjing Duan Date: Wed, 13 Aug 2008 19:09:10 +0100 Subject: [ospfd/isisd] Switch to lib/ Fletcher checksum, fixing bug in isisd 2008-08-13 Jingjing Duan * ospfd/: Remove the old checksum implementation and use the consolidated version. * isisd/: ditto, thus fixing isisd checksuming on big-endian. Signed-off-by: Paul Jakma --- isisd/isis_lsp.c | 8 ++-- isisd/isis_pdu.c | 5 +- isisd/iso_checksum.c | 128 +++------------------------------------------------ isisd/iso_checksum.h | 1 - ospfd/ospf_lsa.c | 44 +++++------------- 5 files changed, 24 insertions(+), 162 deletions(-) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 1a4deb1b..48e3147d 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -33,6 +33,7 @@ #include "command.h" #include "hash.h" #include "if.h" +#include "checksum.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -45,7 +46,6 @@ #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_flags.h" -#include "isisd/iso_checksum.h" #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" @@ -314,7 +314,7 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num) newseq = seq_num++; lsp->lsp_header->seq_num = htonl (newseq); - iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); return; @@ -1803,7 +1803,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu); lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); - iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); list_delete (adj_list); @@ -2071,7 +2071,7 @@ lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level) lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); lsp->purged = 0; - iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); ISIS_FLAGS_SET_ALL (lsp->SRMflags); } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 6fcc5ed5..4311a905 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -32,6 +32,7 @@ #include "hash.c" #include "prefix.h" #include "if.h" +#include "checksum.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" @@ -1121,7 +1122,7 @@ dontcheckadj: if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("LSP LEN: %d", ntohs (lsp->lsp_header->pdu_len)); - iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); ISIS_FLAGS_SET_ALL (lsp->SRMflags); if (isis->debugs & DEBUG_UPDATE_PACKETS) @@ -1164,7 +1165,7 @@ dontcheckadj: /* 7.3.16.1 */ lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1); - iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); ISIS_FLAGS_SET_ALL (lsp->SRMflags); diff --git a/isisd/iso_checksum.c b/isisd/iso_checksum.c index 16f18e50..294fe994 100644 --- a/isisd/iso_checksum.c +++ b/isisd/iso_checksum.c @@ -23,6 +23,7 @@ #include #include "iso_checksum.h" +#include "checksum.h" /* * Calculations of the OSI checksum. @@ -47,14 +48,10 @@ int iso_csum_verify (u_char * buffer, int len, uint16_t * csum) { - u_int8_t *p; + u_int16_t checksum; u_int32_t c0; u_int32_t c1; - u_int16_t checksum; - int i, partial_len; - p = buffer; - checksum = 0; c0 = *csum & 0xff00; c1 = *csum & 0x00ff; @@ -70,124 +67,11 @@ iso_csum_verify (u_char * buffer, int len, uint16_t * csum) if (c0 == 0 || c1 == 0) return 1; - /* - * Otherwise initialize to zero and calculate... - */ - c0 = 0; - c1 = 0; - - while (len) - { - partial_len = MIN(len, 5803); - - for (i = 0; i < partial_len; i++) - { - c0 = c0 + *(p++); - c1 += c0; - } + /* Offset of checksum from the start of the buffer */ + int offset = (u_char *) csum - buffer; - c0 = c0 % 255; - c1 = c1 % 255; - - len -= partial_len; - } - - if (c0 == 0 && c1 == 0) + checksum = fletcher_checksum(buffer, len, offset); + if (checksum == *csum) return 0; - return 1; } - -/* - * Creates the checksum. *csum points to the position of the checksum in the - * PDU. - * Based on Annex C.4 of ISO/IEC 8473 - */ -#define FIXED_CODE -u_int16_t -iso_csum_create (u_char * buffer, int len, u_int16_t n) -{ - - 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 + n); - *(csum) = checksum; - - p = buffer; - c0 = 0; - c1 = 0; - init_len = len; - - while (len != 0) - { - partial_len = MIN(len, 5803); - - for (i = 0; i < partial_len; i++) - { - c0 = c0 + *(p++); - c1 += c0; - } - - c0 = c0 % 255; - c1 = c1 % 255; - - len -= partial_len; - } - - mul = (init_len - n)*(c0); - -#ifdef FIXED_CODE - 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; - - checksum = (y << 8) | (x & 0xFF); - -#else - x = mul - c0 - c1; - x %= 255; - - y = c1 - mul - 1; - y %= 255; - - if (x == 0) - x = 255; - if (y == 0) - y = 255; - - checksum = ((y << 8) | x); -#endif - - /* - * Now we write this to the packet - */ - *(csum) = checksum; - - /* return the checksum for user usage */ - return checksum; -} diff --git a/isisd/iso_checksum.h b/isisd/iso_checksum.h index ba0d1983..5f8d41f9 100644 --- a/isisd/iso_checksum.h +++ b/isisd/iso_checksum.h @@ -24,6 +24,5 @@ #define _ZEBRA_ISO_CSUM_H int iso_csum_verify (u_char * buffer, int len, uint16_t * csum); -u_int16_t iso_csum_create (u_char * buffer, int len, u_int16_t n); #endif /* _ZEBRA_ISO_CSUM_H */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 243928f4..f453353d 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -32,6 +32,7 @@ #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ +#include "checksum.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -172,46 +173,23 @@ get_age (struct ospf_lsa *lsa) /* Fletcher Checksum -- Refer to RFC1008. */ -#define MODX 4102 -#define LSA_CHECKSUM_OFFSET 15 +/* All the offsets are zero-based. The offsets in the RFC1008 are + one-based. */ u_int16_t ospf_lsa_checksum (struct lsa_header *lsa) { - u_char *sp, *ep, *p, *q; - int c0 = 0, c1 = 0; - int x, y; - u_int16_t length; - - lsa->checksum = 0; - length = ntohs (lsa->length) - 2; - sp = (u_char *) &lsa->options; - - 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; - } + u_char *buffer = (u_char *) &lsa->options; + int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ - x = (((int)length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255; - if (x <= 0) - x += 255; - y = 510 - c0 - x; - if (y > 255) - y -= 255; + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa->length) - options_offset; - /* take care endian issue. */ - lsa->checksum = htons ((x << 8) + y); + /* Checksum offset starts from "options" field, not the beginning of the + lsa_header struct. The offset is 14, rather than 16. */ + int checksum_offset = (u_char *) &lsa->checksum - buffer; - return (lsa->checksum); + return fletcher_checksum(buffer, len, checksum_offset); } -- cgit v1.2.1