X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/b8c56aa09228ee6c59af9bd2565bc66b69ac7943..d7b497cac78b6e22a66a6bae9bdec60a8044f67a:/print-cfm.c diff --git a/print-cfm.c b/print-cfm.c index 43ad438c..2a2485e9 100644 --- a/print-cfm.c +++ b/print-cfm.c @@ -12,7 +12,7 @@ * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * - * Original code by Hannes Gredler (hannes@juniper.net) + * Original code by Hannes Gredler (hannes@gredler.at) */ /* \summary: IEEE 802.1ag Connectivity Fault Management (CFM) protocols printer */ @@ -50,7 +50,7 @@ struct cfm_common_header_t { #define CFM_OPCODE_LTM 5 static const struct tok cfm_opcode_values[] = { - { CFM_OPCODE_CCM, "Continouity Check Message"}, + { CFM_OPCODE_CCM, "Continuity Check Message"}, { CFM_OPCODE_LBR, "Loopback Reply"}, { CFM_OPCODE_LBM, "Loopback Message"}, { CFM_OPCODE_LTR, "Linktrace Reply"}, @@ -217,17 +217,22 @@ static const struct tok cfm_tlv_senderid_chassisid_values[] = { static int cfm_network_addr_print(netdissect_options *ndo, - register const u_char *tptr) + register const u_char *tptr, const u_int length) { u_int network_addr_type; u_int hexdump = FALSE; /* - * Altough AFIs are tpically 2 octects wide, + * Although AFIs are typically 2 octects wide, * 802.1ab specifies that this field width - * is only once octet + * is only one octet. */ - network_addr_type = *tptr; + if (length < 1) { + ND_PRINT((ndo, "\n\t Network Address Type (invalid, no data")); + return hexdump; + } + /* The calling function must make any due ND_TCHECK calls. */ + network_addr_type = EXTRACT_U_1(tptr); ND_PRINT((ndo, "\n\t Network Address Type %s (%u)", tok2str(af_values, "Unknown", network_addr_type), network_addr_type)); @@ -237,10 +242,20 @@ cfm_network_addr_print(netdissect_options *ndo, */ switch(network_addr_type) { case AFNUM_INET: + if (length != 1 + 4) { + ND_PRINT((ndo, "(invalid IPv4 address length %u)", length - 1)); + hexdump = TRUE; + break; + } ND_PRINT((ndo, ", %s", ipaddr_string(ndo, tptr + 1))); break; case AFNUM_INET6: + if (length != 1 + 16) { + ND_PRINT((ndo, "(invalid IPv6 address length %u)", length - 1)); + hexdump = TRUE; + break; + } ND_PRINT((ndo, ", %s", ip6addr_string(ndo, tptr + 1))); break; @@ -305,7 +320,7 @@ cfm_print(netdissect_options *ndo, ND_PRINT((ndo, "\n\tFirst TLV offset %u", cfm_common_header->first_tlv_offset)); - tptr += sizeof(const struct cfm_common_header_t); + tptr += sizeof(struct cfm_common_header_t); tlen = length - sizeof(struct cfm_common_header_t); /* @@ -346,8 +361,8 @@ cfm_print(netdissect_options *ndo, } ND_PRINT((ndo, "\n\t Sequence Number 0x%08x, MA-End-Point-ID 0x%04x", - EXTRACT_32BITS(msg_ptr.cfm_ccm->sequence), - EXTRACT_16BITS(msg_ptr.cfm_ccm->ma_epi))); + EXTRACT_BE_U_4(msg_ptr.cfm_ccm->sequence), + EXTRACT_BE_U_2(msg_ptr.cfm_ccm->ma_epi))); namesp = msg_ptr.cfm_ccm->names; names_data_remaining = sizeof(msg_ptr.cfm_ccm->names); @@ -368,8 +383,11 @@ cfm_print(netdissect_options *ndo, md_nameformat, md_namelength)); - /* -2 for the MA short name format and length */ - if (md_namelength > names_data_remaining - 2) { + /* + * -3 for the MA short name format and length and one byte + * of MA short name. + */ + if (md_namelength > names_data_remaining - 3) { ND_PRINT((ndo, " (too large, must be <= %u)", names_data_remaining - 2)); return; } @@ -459,7 +477,7 @@ cfm_print(netdissect_options *ndo, bittok2str(cfm_ltm_flag_values, "none", cfm_common_header->flags))); ND_PRINT((ndo, "\n\t Transaction-ID 0x%08x, ttl %u", - EXTRACT_32BITS(msg_ptr.cfm_ltm->transaction_id), + EXTRACT_BE_U_4(msg_ptr.cfm_ltm->transaction_id), msg_ptr.cfm_ltm->ttl)); ND_PRINT((ndo, "\n\t Original-MAC %s, Target-MAC %s", @@ -482,7 +500,7 @@ cfm_print(netdissect_options *ndo, bittok2str(cfm_ltr_flag_values, "none", cfm_common_header->flags))); ND_PRINT((ndo, "\n\t Transaction-ID 0x%08x, ttl %u", - EXTRACT_32BITS(msg_ptr.cfm_ltr->transaction_id), + EXTRACT_BE_U_4(msg_ptr.cfm_ltr->transaction_id), msg_ptr.cfm_ltr->ttl)); ND_PRINT((ndo, "\n\t Replay-Action %s (%u)", @@ -511,7 +529,7 @@ cfm_print(netdissect_options *ndo, cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr; /* Enough to read the tlv type ? */ - ND_TCHECK2(*tptr, 1); + ND_TCHECK_1(tptr); cfm_tlv_type=cfm_tlv_header->type; ND_PRINT((ndo, "\n\t%s TLV (0x%02x)", @@ -527,7 +545,7 @@ cfm_print(netdissect_options *ndo, if (tlen < sizeof(struct cfm_tlv_header_t)) goto tooshort; ND_TCHECK2(*tptr, sizeof(struct cfm_tlv_header_t)); - cfm_tlv_len=EXTRACT_16BITS(&cfm_tlv_header->length); + cfm_tlv_len=EXTRACT_BE_U_2(&cfm_tlv_header->length); ND_PRINT((ndo, ", length %u", cfm_tlv_len)); @@ -548,8 +566,8 @@ cfm_print(netdissect_options *ndo, return; } ND_PRINT((ndo, ", Status: %s (%u)", - tok2str(cfm_tlv_port_status_values, "Unknown", *tptr), - *tptr)); + tok2str(cfm_tlv_port_status_values, "Unknown", EXTRACT_U_1(tptr)), + EXTRACT_U_1(tptr))); break; case CFM_TLV_INTERFACE_STATUS: @@ -558,8 +576,8 @@ cfm_print(netdissect_options *ndo, return; } ND_PRINT((ndo, ", Status: %s (%u)", - tok2str(cfm_tlv_interface_status_values, "Unknown", *tptr), - *tptr)); + tok2str(cfm_tlv_interface_status_values, "Unknown", EXTRACT_U_1(tptr)), + EXTRACT_U_1(tptr))); break; case CFM_TLV_PRIVATE: @@ -568,9 +586,9 @@ cfm_print(netdissect_options *ndo, return; } ND_PRINT((ndo, ", Vendor: %s (%u), Sub-Type %u", - tok2str(oui_values,"Unknown", EXTRACT_24BITS(tptr)), - EXTRACT_24BITS(tptr), - *(tptr + 3))); + tok2str(oui_values,"Unknown", EXTRACT_BE_U_3(tptr)), + EXTRACT_BE_U_3(tptr), + EXTRACT_U_1(tptr + 3))); hexdump = TRUE; break; @@ -581,23 +599,29 @@ cfm_print(netdissect_options *ndo, if (cfm_tlv_len < 1) { ND_PRINT((ndo, " (too short, must be >= 1)")); - return; + goto next_tlv; } /* * Get the Chassis ID length and check it. + * IEEE 802.1Q-2014 Section 21.5.3.1 */ - chassis_id_length = *tptr; + chassis_id_length = EXTRACT_U_1(tptr); tptr++; tlen--; cfm_tlv_len--; if (chassis_id_length) { + /* + * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references + * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently + * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype + */ if (cfm_tlv_len < 1) { ND_PRINT((ndo, "\n\t (TLV too short)")); - return; + goto next_tlv; } - chassis_id_type = *tptr; + chassis_id_type = EXTRACT_U_1(tptr); cfm_tlv_len--; ND_PRINT((ndo, "\n\t Chassis-ID Type %s (%u), Chassis-ID length %u", tok2str(cfm_tlv_senderid_chassisid_values, @@ -608,16 +632,22 @@ cfm_print(netdissect_options *ndo, if (cfm_tlv_len < chassis_id_length) { ND_PRINT((ndo, "\n\t (TLV too short)")); - return; + goto next_tlv; } + /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */ switch (chassis_id_type) { case CFM_CHASSIS_ID_MAC_ADDRESS: + if (chassis_id_length != ETHER_ADDR_LEN) { + ND_PRINT((ndo, " (invalid MAC address length)")); + hexdump = TRUE; + break; + } ND_PRINT((ndo, "\n\t MAC %s", etheraddr_string(ndo, tptr + 1))); break; case CFM_CHASSIS_ID_NETWORK_ADDRESS: - hexdump |= cfm_network_addr_print(ndo, tptr); + hexdump |= cfm_network_addr_print(ndo, tptr + 1, chassis_id_length); break; case CFM_CHASSIS_ID_INTERFACE_NAME: /* fall through */ @@ -640,38 +670,53 @@ cfm_print(netdissect_options *ndo, /* * Check if there is a Management Address. + * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length + * This and all subsequent fields are not present if the TLV length + * allows only the above fields. */ if (cfm_tlv_len == 0) { /* No, there isn't; we're done. */ - return; + break; } - mgmt_addr_length = *tptr; + /* Here mgmt_addr_length stands for the management domain length. */ + mgmt_addr_length = EXTRACT_U_1(tptr); tptr++; tlen--; cfm_tlv_len--; + ND_PRINT((ndo, "\n\t Management Address Domain Length %u", mgmt_addr_length)); if (mgmt_addr_length) { + /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */ if (cfm_tlv_len < mgmt_addr_length) { ND_PRINT((ndo, "\n\t (TLV too short)")); - return; + goto next_tlv; } cfm_tlv_len -= mgmt_addr_length; /* * XXX - this is an OID; print it as such. */ + hex_print(ndo, "\n\t Management Address Domain: ", tptr, mgmt_addr_length); tptr += mgmt_addr_length; tlen -= mgmt_addr_length; + /* + * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length + * This field is present if Management Address Domain Length is not 0. + */ if (cfm_tlv_len < 1) { - ND_PRINT((ndo, "\n\t (TLV too short)")); - return; + ND_PRINT((ndo, " (Management Address Length is missing)")); + hexdump = TRUE; + break; } - - mgmt_addr_length = *tptr; + + /* Here mgmt_addr_length stands for the management address length. */ + mgmt_addr_length = EXTRACT_U_1(tptr); tptr++; tlen--; cfm_tlv_len--; + ND_PRINT((ndo, "\n\t Management Address Length %u", mgmt_addr_length)); if (mgmt_addr_length) { + /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */ if (cfm_tlv_len < mgmt_addr_length) { ND_PRINT((ndo, "\n\t (TLV too short)")); return; @@ -680,6 +725,7 @@ cfm_print(netdissect_options *ndo, /* * XXX - this is a TransportDomain; print it as such. */ + hex_print(ndo, "\n\t Management Address: ", tptr, mgmt_addr_length); tptr += mgmt_addr_length; tlen -= mgmt_addr_length; } @@ -703,6 +749,7 @@ cfm_print(netdissect_options *ndo, if (hexdump || ndo->ndo_vflag > 1) print_unknown_data(ndo, tlv_ptr, "\n\t ", cfm_tlv_len); +next_tlv: tptr+=cfm_tlv_len; tlen-=cfm_tlv_len; }