X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/a6f81d534ddc1026442664d21a2122d64ab571a9..a890c4489fa1bcee9f455ee28d772bb1ccf590bf:/print-pim.c diff --git a/print-pim.c b/print-pim.c index 15f4c513..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 @@ -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,7 +677,41 @@ 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)) {