diff options
-rw-r--r-- | checksum.c | 61 | ||||
-rw-r--r-- | interface.h | 3 | ||||
-rw-r--r-- | print-isoclns.c | 68 |
3 files changed, 90 insertions, 42 deletions
@@ -19,7 +19,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/tcpdump/checksum.c,v 1.3 2006-02-09 21:34:38 hannes Exp $"; + "@(#) $Header: /tcpdump/master/tcpdump/checksum.c,v 1.4 2006-09-25 09:23:32 hannes Exp $"; #endif #ifdef HAVE_CONFIG_H @@ -76,3 +76,62 @@ init_checksum(void) { init_crc10_table(); } + +/* + * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3. + * The checksum field of the passed PDU does not need to be reset to zero. + */ +u_int16_t +create_osi_cksum (const u_int8_t *pptr, int checksum_offset, int length) +{ + + int x; + int y; + u_int32_t mul; + u_int32_t c0; + u_int32_t c1; + u_int16_t checksum; + int index; + + checksum = 0; + + c0 = 0; + c1 = 0; + + for (index = 0; index < length; index++) { + /* + * Ignore the contents of the checksum field. + */ + if (index == checksum_offset || + index == checksum_offset+1) { + c1 += c0; + pptr++; + } else { + c0 = c0 + *(pptr++); + c1 += c0; + } + } + + c0 = c0 % 255; + c1 = c1 % 255; + + mul = (length - checksum_offset)*(c0); + + 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 = 255; + + y &= 0x00FF; + checksum = ((x << 8) | y); + + return checksum; +} diff --git a/interface.h b/interface.h index 8f347b07..4204063d 100644 --- a/interface.h +++ b/interface.h @@ -18,7 +18,7 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * @(#) $Header: /tcpdump/master/tcpdump/interface.h,v 1.270 2006-05-05 23:13:00 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/tcpdump/interface.h,v 1.271 2006-09-25 09:23:32 hannes Exp $ (LBL) */ #ifndef tcpdump_interface_h @@ -163,6 +163,7 @@ extern const char *dnnum_string(u_short); /* checksum routines */ extern void init_checksum(void); extern u_int16_t verify_crc10_cksum(u_int16_t, const u_char *, int); +extern u_int16_t create_osi_cksum(const u_int8_t *, int, int); /* The printer routines. */ diff --git a/print-isoclns.c b/print-isoclns.c index 394e46da..f11ec8ec 100644 --- a/print-isoclns.c +++ b/print-isoclns.c @@ -26,7 +26,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.160 2006-06-16 18:08:35 hannes Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.161 2006-09-25 09:23:32 hannes Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -508,7 +508,8 @@ struct isis_tlv_ptp_adj { u_int8_t neighbor_extd_local_circuit_id[4]; }; -static int osi_cksum(const u_int8_t *, u_int); +static void osi_print_cksum(const u_int8_t *pptr, u_int16_t checksum, + u_int checksum_offset, u_int length); static int clnp_print(const u_int8_t *, u_int); static void esis_print(const u_int8_t *, u_int); static int isis_print(const u_int8_t *, u_int); @@ -771,7 +772,7 @@ static int clnp_print (const u_int8_t *pptr, u_int length) } printf("%slength %u",eflag ? "" : ", ",length); - printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x ", + printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x", tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type), clnp_header->length_indicator, clnp_header->version, @@ -780,10 +781,8 @@ static int clnp_print (const u_int8_t *pptr, u_int length) EXTRACT_16BITS(clnp_header->segment_length), EXTRACT_16BITS(clnp_header->cksum)); - /* do not attempt to verify the checksum if it is zero */ - if (EXTRACT_16BITS(clnp_header->cksum) == 0) - printf("(unverified)"); - else printf("(%s)", osi_cksum(optr, clnp_header->length_indicator) ? "incorrect" : "correct"); + osi_print_cksum(optr, EXTRACT_16BITS(clnp_header->cksum), 7, + clnp_header->length_indicator); printf("\n\tFlags [%s]", bittok2str(clnp_flag_values,"none",clnp_flags)); @@ -1037,12 +1036,9 @@ esis_print(const u_int8_t *pptr, u_int length) esis_pdu_type); printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" ); - printf(", checksum: 0x%04x ", EXTRACT_16BITS(esis_header->cksum)); - /* do not attempt to verify the checksum if it is zero */ - if (EXTRACT_16BITS(esis_header->cksum) == 0) - printf("(unverified)"); - else - printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct"); + printf(", checksum: 0x%04x", EXTRACT_16BITS(esis_header->cksum)); + + osi_print_cksum(pptr, EXTRACT_16BITS(esis_header->cksum), 7, li); printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li); @@ -2013,15 +2009,9 @@ static int isis_print (const u_int8_t *p, u_int length) EXTRACT_16BITS(header_lsp->remaining_lifetime), EXTRACT_16BITS(header_lsp->checksum)); - /* if this is a purge do not attempt to verify the checksum */ - if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 && - EXTRACT_16BITS(header_lsp->checksum) == 0) - printf(" (purged)"); - else - /* verify the checksum - - * checking starts at the lsp-id field at byte position [12] - * hence the length needs to be reduced by 12 bytes */ - printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct"); + + osi_print_cksum((u_int8_t *)header_lsp->lsp_id, + EXTRACT_16BITS(header_lsp->checksum), 12, length-12); printf(", PDU length: %u, Flags: [ %s", pdu_len, @@ -2522,9 +2512,7 @@ static int isis_print (const u_int8_t *p, u_int length) * to avoid conflicts the checksum TLV is zeroed. * see rfc3358 for details */ - if (EXTRACT_16BITS(tptr) == 0) - printf("(unverified)"); - else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct"); + osi_print_cksum(optr, EXTRACT_16BITS(tptr), tptr-optr, length); break; case ISIS_TLV_MT_SUPPORTED: @@ -2716,25 +2704,25 @@ static int isis_print (const u_int8_t *p, u_int length) return(1); } -/* - * Verify the checksum. See 8473-1, Appendix C, section C.4. - */ - -static int -osi_cksum(const u_int8_t *tptr, u_int len) +static void +osi_print_cksum (const u_int8_t *pptr, u_int16_t checksum, + u_int checksum_offset, u_int length) { - int32_t c0 = 0, c1 = 0; + u_int16_t calculated_checksum; - while ((int)--len >= 0) { - c0 += *tptr++; - c0 %= 255; - c1 += c0; - c1 %= 255; - } - return (c0 | c1); + /* do not attempt to verify the checksum if it is zero */ + if (!checksum) { + printf("(unverified)"); + } else { + calculated_checksum = create_osi_cksum(pptr, checksum_offset, length); + if (checksum == calculated_checksum) { + printf(" (correct)"); + } else { + printf(" (incorrect should be 0x%04x)", calculated_checksum); + } + } } - /* * Local Variables: * c-style: whitesmith |