X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/d17c56a6f65369c5b406d77a6cf039cc40b49ff4..a890c4489fa1bcee9f455ee28d772bb1ccf590bf:/print-pim.c diff --git a/print-pim.c b/print-pim.c index 9fc94394..788af214 100644 --- a/print-pim.c +++ b/print-pim.c @@ -31,6 +31,7 @@ #include "extract.h" #include "ip.h" +#include "ip6.h" #define PIMV1_TYPE_QUERY 0 #define PIMV1_TYPE_REGISTER 1 @@ -121,7 +122,7 @@ static const struct tok pimv2_register_flag_values[] = { */ struct pim { - u_int8_t pim_typever; + uint8_t pim_typever; /* upper 4bit: PIM version number; 2 for PIMv2 */ /* lower 4bit: the PIM message type, currently they are: * Hello, Register, Register-Stop, Join/Prune, @@ -134,7 +135,7 @@ struct pim { u_short pim_cksum; /* IP style check sum */ }; -static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, u_int cksum); +static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, const u_char *); static void pimv1_join_prune_print(netdissect_options *ndo, @@ -415,7 +416,7 @@ trunc: void pim_print(netdissect_options *ndo, - register const u_char *bp, register u_int len, u_int cksum) + register const u_char *bp, register u_int len, const u_char *bp2) { register const u_char *ep; register struct pim *pim = (struct pim *)bp; @@ -440,7 +441,7 @@ pim_print(netdissect_options *ndo, PIM_VER(pim->pim_typever), len, tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)))); - pimv2_print(ndo, bp, len, cksum); + pimv2_print(ndo, bp, len, bp2); } break; default: @@ -620,13 +621,47 @@ trunc: return -1; } +enum checksum_status { + CORRECT, + INCORRECT, + UNVERIFIED +}; + +static enum checksum_status +pimv2_check_checksum(const u_char *bp, const u_char *bp2, u_int len) +{ + const struct ip *ip; + u_int cksum; + + ip = (const struct ip *)bp2; + if (IP_V(ip) == 4) { + struct cksum_vec vec[1]; + + vec[0].ptr = bp; + vec[0].len = len; + cksum = in_cksum(vec, 1); + return (cksum ? INCORRECT : CORRECT); +#ifdef INET6 + } else if (IP_V(ip) == 6) { + const struct ip6_hdr *ip6; + + ip6 = (const struct ip6_hdr *)bp2; + cksum = nextproto6_cksum(ip6, bp, len, len, IPPROTO_PIM); + return (cksum ? INCORRECT : CORRECT); +#endif + } else { + return (UNVERIFIED); + } +} + static void pimv2_print(netdissect_options *ndo, - register const u_char *bp, register u_int len, u_int cksum) + register const u_char *bp, register u_int len, const u_char *bp2) { register const u_char *ep; register struct pim *pim = (struct pim *)bp; int advance; + enum checksum_status cksum_status; ep = (const u_char *)ndo->ndo_snapend; if (bp >= ep) @@ -642,13 +677,47 @@ pimv2_print(netdissect_options *ndo, if (EXTRACT_16BITS(&pim->pim_cksum) == 0) { ND_PRINT((ndo, "(unverified)")); } else { - ND_PRINT((ndo, "(%scorrect)", ND_TTEST2(bp[0], len) && cksum ? "in" : "" )); + if (PIM_TYPE(pim->pim_typever) == PIMV2_TYPE_REGISTER) { + /* + * The checksum only covers the packet header, + * not the encapsulated packet. + */ + cksum_status = pimv2_check_checksum(bp, bp2, 8); + if (cksum_status == INCORRECT) { + /* + * To quote RFC 4601, "For interoperability + * reasons, a message carrying a checksum + * calculated over the entire PIM Register + * message should also be accepted." + */ + cksum_status = pimv2_check_checksum(bp, bp2, len); + } + } else { + /* + * The checksum covers the entire packet. + */ + cksum_status = pimv2_check_checksum(bp, bp2, len); + } + switch (cksum_status) { + + case CORRECT: + ND_PRINT((ndo, "(correct)")); + break; + + case INCORRECT: + ND_PRINT((ndo, "(incorrect)")); + break; + + case UNVERIFIED: + ND_PRINT((ndo, "(unverified)")); + break; + } } switch (PIM_TYPE(pim->pim_typever)) { case PIMV2_TYPE_HELLO: { - u_int16_t otype, olen; + uint16_t otype, olen; bp += 4; while (bp < ep) { ND_TCHECK2(bp[0], 4); @@ -671,7 +740,7 @@ pimv2_print(netdissect_options *ndo, ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen)); } else { char t_bit; - u_int16_t lan_delay, override_interval; + uint16_t lan_delay, override_interval; lan_delay = EXTRACT_16BITS(bp); override_interval = EXTRACT_16BITS(bp+2); t_bit = (lan_delay & 0x8000)? 1 : 0; @@ -748,8 +817,7 @@ pimv2_print(netdissect_options *ndo, { struct ip *ip; - if (!ND_TTEST2(*(bp+4), PIMV2_REGISTER_FLAG_LEN)) - goto trunc; + ND_TCHECK2(*(bp + 4), PIMV2_REGISTER_FLAG_LEN); ND_PRINT((ndo, ", Flags [ %s ]\n\t", tok2str(pimv2_register_flag_values, @@ -769,11 +837,11 @@ pimv2_print(netdissect_options *ndo, case 4: /* IPv4 */ ip_print(ndo, bp, len); break; -#ifdef INET6 + case 6: /* IPv6 */ ip6_print(ndo, bp, len); break; -#endif + default: ND_PRINT((ndo, "IP ver %d", IP_V(ip))); break; @@ -842,10 +910,10 @@ pimv2_print(netdissect_options *ndo, */ { - u_int8_t ngroup; - u_int16_t holdtime; - u_int16_t njoin; - u_int16_t nprune; + uint8_t ngroup; + uint16_t holdtime; + uint16_t njoin; + uint16_t nprune; int i, j; bp += 4; len -= 4; @@ -916,9 +984,9 @@ pimv2_print(netdissect_options *ndo, bp += 4; /* Fragment Tag, Hash Mask len, and BSR-priority */ - if (bp + sizeof(u_int16_t) >= ep) break; + if (bp + sizeof(uint16_t) >= ep) break; ND_PRINT((ndo, " tag=%x", EXTRACT_16BITS(bp))); - bp += sizeof(u_int16_t); + bp += sizeof(uint16_t); if (bp >= ep) break; ND_PRINT((ndo, " hashmlen=%d", bp[0])); if (bp + 1 >= ep) break;