* 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 */
#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"},
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));
*/
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;
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);
/*
}
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);
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;
}
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",
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)",
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)",
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));
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:
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:
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;
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,
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 */
/*
* 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;
/*
* 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;
}
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;
}