1a5779b6eSRui Paulo /* 2a5779b6eSRui Paulo * Copyright (c) 1998-2006 The TCPDUMP project 3a5779b6eSRui Paulo * 4a5779b6eSRui Paulo * Redistribution and use in source and binary forms, with or without 5a5779b6eSRui Paulo * modification, are permitted provided that: (1) source code 6a5779b6eSRui Paulo * distributions retain the above copyright notice and this paragraph 7a5779b6eSRui Paulo * in its entirety, and (2) distributions including binary code include 8a5779b6eSRui Paulo * the above copyright notice and this paragraph in its entirety in 9a5779b6eSRui Paulo * the documentation or other materials provided with the distribution. 10a5779b6eSRui Paulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 11a5779b6eSRui Paulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 12a5779b6eSRui Paulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13a5779b6eSRui Paulo * FOR A PARTICULAR PURPOSE. 14a5779b6eSRui Paulo * 150bff6a5aSEd Maste * Original code by Hannes Gredler (hannes@gredler.at) 16a5779b6eSRui Paulo */ 17a5779b6eSRui Paulo 183340d773SGleb Smirnoff /* \summary: IEEE 802.1ag Connectivity Fault Management (CFM) protocols printer */ 193340d773SGleb Smirnoff 20*ee67461eSJoseph Mingrone #include <config.h> 21a5779b6eSRui Paulo 22*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 23a5779b6eSRui Paulo 243340d773SGleb Smirnoff #include "netdissect.h" 25a5779b6eSRui Paulo #include "extract.h" 26a5779b6eSRui Paulo #include "addrtoname.h" 27a5779b6eSRui Paulo #include "oui.h" 28a5779b6eSRui Paulo #include "af.h" 29a5779b6eSRui Paulo 30*ee67461eSJoseph Mingrone 31a5779b6eSRui Paulo struct cfm_common_header_t { 32*ee67461eSJoseph Mingrone nd_uint8_t mdlevel_version; 33*ee67461eSJoseph Mingrone nd_uint8_t opcode; 34*ee67461eSJoseph Mingrone nd_uint8_t flags; 35*ee67461eSJoseph Mingrone nd_uint8_t first_tlv_offset; 36a5779b6eSRui Paulo }; 37a5779b6eSRui Paulo 38a5779b6eSRui Paulo #define CFM_VERSION 0 39*ee67461eSJoseph Mingrone #define CFM_EXTRACT_VERSION(x) ((x)&0x1f) 40a5779b6eSRui Paulo #define CFM_EXTRACT_MD_LEVEL(x) (((x)&0xe0)>>5) 41a5779b6eSRui Paulo 42a5779b6eSRui Paulo #define CFM_OPCODE_CCM 1 43a5779b6eSRui Paulo #define CFM_OPCODE_LBR 2 44a5779b6eSRui Paulo #define CFM_OPCODE_LBM 3 45a5779b6eSRui Paulo #define CFM_OPCODE_LTR 4 46a5779b6eSRui Paulo #define CFM_OPCODE_LTM 5 47a5779b6eSRui Paulo 48a5779b6eSRui Paulo static const struct tok cfm_opcode_values[] = { 49*ee67461eSJoseph Mingrone { CFM_OPCODE_CCM, "Continuity Check Message"}, 50a5779b6eSRui Paulo { CFM_OPCODE_LBR, "Loopback Reply"}, 51a5779b6eSRui Paulo { CFM_OPCODE_LBM, "Loopback Message"}, 52a5779b6eSRui Paulo { CFM_OPCODE_LTR, "Linktrace Reply"}, 53a5779b6eSRui Paulo { CFM_OPCODE_LTM, "Linktrace Message"}, 54a5779b6eSRui Paulo { 0, NULL} 55a5779b6eSRui Paulo }; 56a5779b6eSRui Paulo 57a5779b6eSRui Paulo /* 58a5779b6eSRui Paulo * Message Formats. 59a5779b6eSRui Paulo */ 60a5779b6eSRui Paulo struct cfm_ccm_t { 61*ee67461eSJoseph Mingrone nd_uint32_t sequence; 62*ee67461eSJoseph Mingrone nd_uint16_t ma_epi; 63*ee67461eSJoseph Mingrone nd_byte names[48]; 64*ee67461eSJoseph Mingrone nd_byte itu_t_y_1731[16]; 65a5779b6eSRui Paulo }; 66a5779b6eSRui Paulo 67a5779b6eSRui Paulo /* 68a5779b6eSRui Paulo * Timer Bases for the CCM Interval field. 69a5779b6eSRui Paulo * Expressed in units of seconds. 70a5779b6eSRui Paulo */ 71*ee67461eSJoseph Mingrone static const float ccm_interval_base[8] = {0.0f, 0.003333f, 0.01f, 0.1f, 1.0f, 10.0f, 60.0f, 600.0f}; 72a5779b6eSRui Paulo #define CCM_INTERVAL_MIN_MULTIPLIER 3.25 73a5779b6eSRui Paulo #define CCM_INTERVAL_MAX_MULTIPLIER 3.5 74a5779b6eSRui Paulo 75a5779b6eSRui Paulo #define CFM_CCM_RDI_FLAG 0x80 76*ee67461eSJoseph Mingrone #define CFM_EXTRACT_CCM_INTERVAL(x) ((x)&0x07) 77a5779b6eSRui Paulo 78a5779b6eSRui Paulo #define CFM_CCM_MD_FORMAT_8021 0 79a5779b6eSRui Paulo #define CFM_CCM_MD_FORMAT_NONE 1 80a5779b6eSRui Paulo #define CFM_CCM_MD_FORMAT_DNS 2 81a5779b6eSRui Paulo #define CFM_CCM_MD_FORMAT_MAC 3 82a5779b6eSRui Paulo #define CFM_CCM_MD_FORMAT_CHAR 4 83a5779b6eSRui Paulo 84a5779b6eSRui Paulo static const struct tok cfm_md_nameformat_values[] = { 85a5779b6eSRui Paulo { CFM_CCM_MD_FORMAT_8021, "IEEE 802.1"}, 86a5779b6eSRui Paulo { CFM_CCM_MD_FORMAT_NONE, "No MD Name present"}, 87a5779b6eSRui Paulo { CFM_CCM_MD_FORMAT_DNS, "DNS string"}, 88a5779b6eSRui Paulo { CFM_CCM_MD_FORMAT_MAC, "MAC + 16Bit Integer"}, 89a5779b6eSRui Paulo { CFM_CCM_MD_FORMAT_CHAR, "Character string"}, 90a5779b6eSRui Paulo { 0, NULL} 91a5779b6eSRui Paulo }; 92a5779b6eSRui Paulo 93a5779b6eSRui Paulo #define CFM_CCM_MA_FORMAT_8021 0 94a5779b6eSRui Paulo #define CFM_CCM_MA_FORMAT_VID 1 95a5779b6eSRui Paulo #define CFM_CCM_MA_FORMAT_CHAR 2 96a5779b6eSRui Paulo #define CFM_CCM_MA_FORMAT_INT 3 97a5779b6eSRui Paulo #define CFM_CCM_MA_FORMAT_VPN 4 98a5779b6eSRui Paulo 99a5779b6eSRui Paulo static const struct tok cfm_ma_nameformat_values[] = { 100a5779b6eSRui Paulo { CFM_CCM_MA_FORMAT_8021, "IEEE 802.1"}, 101a5779b6eSRui Paulo { CFM_CCM_MA_FORMAT_VID, "Primary VID"}, 102a5779b6eSRui Paulo { CFM_CCM_MA_FORMAT_CHAR, "Character string"}, 103a5779b6eSRui Paulo { CFM_CCM_MA_FORMAT_INT, "16Bit Integer"}, 104a5779b6eSRui Paulo { CFM_CCM_MA_FORMAT_VPN, "RFC2685 VPN-ID"}, 105a5779b6eSRui Paulo { 0, NULL} 106a5779b6eSRui Paulo }; 107a5779b6eSRui Paulo 108a5779b6eSRui Paulo struct cfm_lbm_t { 109*ee67461eSJoseph Mingrone nd_uint32_t transaction_id; 110a5779b6eSRui Paulo }; 111a5779b6eSRui Paulo 112a5779b6eSRui Paulo struct cfm_ltm_t { 113*ee67461eSJoseph Mingrone nd_uint32_t transaction_id; 114*ee67461eSJoseph Mingrone nd_uint8_t ttl; 115*ee67461eSJoseph Mingrone nd_mac_addr original_mac; 116*ee67461eSJoseph Mingrone nd_mac_addr target_mac; 117a5779b6eSRui Paulo }; 118a5779b6eSRui Paulo 119a5779b6eSRui Paulo static const struct tok cfm_ltm_flag_values[] = { 120a5779b6eSRui Paulo { 0x80, "Use Forwarding-DB only"}, 121a5779b6eSRui Paulo { 0, NULL} 122a5779b6eSRui Paulo }; 123a5779b6eSRui Paulo 124a5779b6eSRui Paulo struct cfm_ltr_t { 125*ee67461eSJoseph Mingrone nd_uint32_t transaction_id; 126*ee67461eSJoseph Mingrone nd_uint8_t ttl; 127*ee67461eSJoseph Mingrone nd_uint8_t replay_action; 128a5779b6eSRui Paulo }; 129a5779b6eSRui Paulo 130a5779b6eSRui Paulo static const struct tok cfm_ltr_flag_values[] = { 1313c602fabSXin LI { 0x80, "UseFDB Only"}, 1323c602fabSXin LI { 0x40, "FwdYes"}, 1333c602fabSXin LI { 0x20, "Terminal MEP"}, 134a5779b6eSRui Paulo { 0, NULL} 135a5779b6eSRui Paulo }; 136a5779b6eSRui Paulo 137a5779b6eSRui Paulo static const struct tok cfm_ltr_replay_action_values[] = { 138a5779b6eSRui Paulo { 1, "Exact Match"}, 139a5779b6eSRui Paulo { 2, "Filtering DB"}, 140a5779b6eSRui Paulo { 3, "MIP CCM DB"}, 141a5779b6eSRui Paulo { 0, NULL} 142a5779b6eSRui Paulo }; 143a5779b6eSRui Paulo 144a5779b6eSRui Paulo 145a5779b6eSRui Paulo #define CFM_TLV_END 0 146a5779b6eSRui Paulo #define CFM_TLV_SENDER_ID 1 147a5779b6eSRui Paulo #define CFM_TLV_PORT_STATUS 2 148a5779b6eSRui Paulo #define CFM_TLV_INTERFACE_STATUS 3 149a5779b6eSRui Paulo #define CFM_TLV_DATA 4 150a5779b6eSRui Paulo #define CFM_TLV_REPLY_INGRESS 5 151a5779b6eSRui Paulo #define CFM_TLV_REPLY_EGRESS 6 152a5779b6eSRui Paulo #define CFM_TLV_PRIVATE 31 153a5779b6eSRui Paulo 154a5779b6eSRui Paulo static const struct tok cfm_tlv_values[] = { 155a5779b6eSRui Paulo { CFM_TLV_END, "End"}, 156a5779b6eSRui Paulo { CFM_TLV_SENDER_ID, "Sender ID"}, 157a5779b6eSRui Paulo { CFM_TLV_PORT_STATUS, "Port status"}, 158a5779b6eSRui Paulo { CFM_TLV_INTERFACE_STATUS, "Interface status"}, 159a5779b6eSRui Paulo { CFM_TLV_DATA, "Data"}, 160a5779b6eSRui Paulo { CFM_TLV_REPLY_INGRESS, "Reply Ingress"}, 161a5779b6eSRui Paulo { CFM_TLV_REPLY_EGRESS, "Reply Egress"}, 162a5779b6eSRui Paulo { CFM_TLV_PRIVATE, "Organization Specific"}, 163a5779b6eSRui Paulo { 0, NULL} 164a5779b6eSRui Paulo }; 165a5779b6eSRui Paulo 166a5779b6eSRui Paulo /* 167a5779b6eSRui Paulo * TLVs 168a5779b6eSRui Paulo */ 169a5779b6eSRui Paulo 170a5779b6eSRui Paulo struct cfm_tlv_header_t { 171*ee67461eSJoseph Mingrone nd_uint8_t type; 172*ee67461eSJoseph Mingrone nd_uint16_t length; 173a5779b6eSRui Paulo }; 174a5779b6eSRui Paulo 175a5779b6eSRui Paulo /* FIXME define TLV formats */ 176a5779b6eSRui Paulo 177a5779b6eSRui Paulo static const struct tok cfm_tlv_port_status_values[] = { 178a5779b6eSRui Paulo { 1, "Blocked"}, 179a5779b6eSRui Paulo { 2, "Up"}, 180a5779b6eSRui Paulo { 0, NULL} 181a5779b6eSRui Paulo }; 182a5779b6eSRui Paulo 183a5779b6eSRui Paulo static const struct tok cfm_tlv_interface_status_values[] = { 184a5779b6eSRui Paulo { 1, "Up"}, 185a5779b6eSRui Paulo { 2, "Down"}, 186a5779b6eSRui Paulo { 3, "Testing"}, 187a5779b6eSRui Paulo { 5, "Dormant"}, 188a5779b6eSRui Paulo { 6, "not present"}, 189a5779b6eSRui Paulo { 7, "lower Layer down"}, 190a5779b6eSRui Paulo { 0, NULL} 191a5779b6eSRui Paulo }; 192a5779b6eSRui Paulo 193a5779b6eSRui Paulo #define CFM_CHASSIS_ID_CHASSIS_COMPONENT 1 194a5779b6eSRui Paulo #define CFM_CHASSIS_ID_INTERFACE_ALIAS 2 195a5779b6eSRui Paulo #define CFM_CHASSIS_ID_PORT_COMPONENT 3 196a5779b6eSRui Paulo #define CFM_CHASSIS_ID_MAC_ADDRESS 4 197a5779b6eSRui Paulo #define CFM_CHASSIS_ID_NETWORK_ADDRESS 5 198a5779b6eSRui Paulo #define CFM_CHASSIS_ID_INTERFACE_NAME 6 199a5779b6eSRui Paulo #define CFM_CHASSIS_ID_LOCAL 7 200a5779b6eSRui Paulo 201a5779b6eSRui Paulo static const struct tok cfm_tlv_senderid_chassisid_values[] = { 202a5779b6eSRui Paulo { 0, "Reserved"}, 203a5779b6eSRui Paulo { CFM_CHASSIS_ID_CHASSIS_COMPONENT, "Chassis component"}, 204a5779b6eSRui Paulo { CFM_CHASSIS_ID_INTERFACE_ALIAS, "Interface alias"}, 205a5779b6eSRui Paulo { CFM_CHASSIS_ID_PORT_COMPONENT, "Port component"}, 206a5779b6eSRui Paulo { CFM_CHASSIS_ID_MAC_ADDRESS, "MAC address"}, 207a5779b6eSRui Paulo { CFM_CHASSIS_ID_NETWORK_ADDRESS, "Network address"}, 208a5779b6eSRui Paulo { CFM_CHASSIS_ID_INTERFACE_NAME, "Interface name"}, 209a5779b6eSRui Paulo { CFM_CHASSIS_ID_LOCAL, "Locally assigned"}, 210a5779b6eSRui Paulo { 0, NULL} 211a5779b6eSRui Paulo }; 212a5779b6eSRui Paulo 213a5779b6eSRui Paulo 2143c602fabSXin LI static int 2153340d773SGleb Smirnoff cfm_network_addr_print(netdissect_options *ndo, 216*ee67461eSJoseph Mingrone const u_char *tptr, const u_int length) 2178bdc5a62SPatrick Kelsey { 2183340d773SGleb Smirnoff u_int network_addr_type; 219a5779b6eSRui Paulo u_int hexdump = FALSE; 220a5779b6eSRui Paulo 221a5779b6eSRui Paulo /* 222*ee67461eSJoseph Mingrone * Although AFIs are typically 2 octets wide, 223a5779b6eSRui Paulo * 802.1ab specifies that this field width 224*ee67461eSJoseph Mingrone * is only one octet. 225a5779b6eSRui Paulo */ 2260bff6a5aSEd Maste if (length < 1) { 227*ee67461eSJoseph Mingrone ND_PRINT("\n\t Network Address Type (invalid, no data"); 2280bff6a5aSEd Maste return hexdump; 2290bff6a5aSEd Maste } 2300bff6a5aSEd Maste /* The calling function must make any due ND_TCHECK calls. */ 231*ee67461eSJoseph Mingrone network_addr_type = GET_U_1(tptr); 232*ee67461eSJoseph Mingrone ND_PRINT("\n\t Network Address Type %s (%u)", 2333340d773SGleb Smirnoff tok2str(af_values, "Unknown", network_addr_type), 234*ee67461eSJoseph Mingrone network_addr_type); 235a5779b6eSRui Paulo 236a5779b6eSRui Paulo /* 237a5779b6eSRui Paulo * Resolve the passed in Address. 238a5779b6eSRui Paulo */ 2393340d773SGleb Smirnoff switch(network_addr_type) { 240a5779b6eSRui Paulo case AFNUM_INET: 2410bff6a5aSEd Maste if (length != 1 + 4) { 242*ee67461eSJoseph Mingrone ND_PRINT("(invalid IPv4 address length %u)", length - 1); 2430bff6a5aSEd Maste hexdump = TRUE; 2440bff6a5aSEd Maste break; 2450bff6a5aSEd Maste } 246*ee67461eSJoseph Mingrone ND_PRINT(", %s", GET_IPADDR_STRING(tptr + 1)); 247a5779b6eSRui Paulo break; 248a5779b6eSRui Paulo 249a5779b6eSRui Paulo case AFNUM_INET6: 2500bff6a5aSEd Maste if (length != 1 + 16) { 251*ee67461eSJoseph Mingrone ND_PRINT("(invalid IPv6 address length %u)", length - 1); 2520bff6a5aSEd Maste hexdump = TRUE; 2530bff6a5aSEd Maste break; 2540bff6a5aSEd Maste } 255*ee67461eSJoseph Mingrone ND_PRINT(", %s", GET_IP6ADDR_STRING(tptr + 1)); 256a5779b6eSRui Paulo break; 257a5779b6eSRui Paulo 258a5779b6eSRui Paulo default: 259a5779b6eSRui Paulo hexdump = TRUE; 260a5779b6eSRui Paulo break; 261a5779b6eSRui Paulo } 262a5779b6eSRui Paulo 263a5779b6eSRui Paulo return hexdump; 264a5779b6eSRui Paulo } 265a5779b6eSRui Paulo 266a5779b6eSRui Paulo void 2673c602fabSXin LI cfm_print(netdissect_options *ndo, 268*ee67461eSJoseph Mingrone const u_char *pptr, u_int length) 2698bdc5a62SPatrick Kelsey { 270a5779b6eSRui Paulo const struct cfm_common_header_t *cfm_common_header; 271*ee67461eSJoseph Mingrone uint8_t mdlevel_version, opcode, flags, first_tlv_offset; 272a5779b6eSRui Paulo const struct cfm_tlv_header_t *cfm_tlv_header; 2733340d773SGleb Smirnoff const uint8_t *tptr, *tlv_ptr; 2743340d773SGleb Smirnoff const uint8_t *namesp; 2753340d773SGleb Smirnoff u_int names_data_remaining; 2763340d773SGleb Smirnoff uint8_t md_nameformat, md_namelength; 2773340d773SGleb Smirnoff const uint8_t *md_name; 2783340d773SGleb Smirnoff uint8_t ma_nameformat, ma_namelength; 2793340d773SGleb Smirnoff const uint8_t *ma_name; 280a5779b6eSRui Paulo u_int hexdump, tlen, cfm_tlv_len, cfm_tlv_type, ccm_interval; 281a5779b6eSRui Paulo 282a5779b6eSRui Paulo 283a5779b6eSRui Paulo union { 284a5779b6eSRui Paulo const struct cfm_ccm_t *cfm_ccm; 285a5779b6eSRui Paulo const struct cfm_lbm_t *cfm_lbm; 286a5779b6eSRui Paulo const struct cfm_ltm_t *cfm_ltm; 287a5779b6eSRui Paulo const struct cfm_ltr_t *cfm_ltr; 288a5779b6eSRui Paulo } msg_ptr; 289a5779b6eSRui Paulo 290*ee67461eSJoseph Mingrone ndo->ndo_protocol = "cfm"; 291a5779b6eSRui Paulo tptr=pptr; 292a5779b6eSRui Paulo cfm_common_header = (const struct cfm_common_header_t *)pptr; 2933340d773SGleb Smirnoff if (length < sizeof(*cfm_common_header)) 2943340d773SGleb Smirnoff goto tooshort; 295*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(cfm_common_header); 296a5779b6eSRui Paulo 297a5779b6eSRui Paulo /* 298a5779b6eSRui Paulo * Sanity checking of the header. 299a5779b6eSRui Paulo */ 300*ee67461eSJoseph Mingrone mdlevel_version = GET_U_1(cfm_common_header->mdlevel_version); 301*ee67461eSJoseph Mingrone if (CFM_EXTRACT_VERSION(mdlevel_version) != CFM_VERSION) { 302*ee67461eSJoseph Mingrone ND_PRINT("CFMv%u not supported, length %u", 303*ee67461eSJoseph Mingrone CFM_EXTRACT_VERSION(mdlevel_version), length); 304a5779b6eSRui Paulo return; 305a5779b6eSRui Paulo } 306a5779b6eSRui Paulo 307*ee67461eSJoseph Mingrone opcode = GET_U_1(cfm_common_header->opcode); 308*ee67461eSJoseph Mingrone ND_PRINT("CFMv%u %s, MD Level %u, length %u", 309*ee67461eSJoseph Mingrone CFM_EXTRACT_VERSION(mdlevel_version), 310*ee67461eSJoseph Mingrone tok2str(cfm_opcode_values, "unknown (%u)", opcode), 311*ee67461eSJoseph Mingrone CFM_EXTRACT_MD_LEVEL(mdlevel_version), 312*ee67461eSJoseph Mingrone length); 313a5779b6eSRui Paulo 314a5779b6eSRui Paulo /* 315a5779b6eSRui Paulo * In non-verbose mode just print the opcode and md-level. 316a5779b6eSRui Paulo */ 3173c602fabSXin LI if (ndo->ndo_vflag < 1) { 318a5779b6eSRui Paulo return; 319a5779b6eSRui Paulo } 320a5779b6eSRui Paulo 321*ee67461eSJoseph Mingrone flags = GET_U_1(cfm_common_header->flags); 322*ee67461eSJoseph Mingrone first_tlv_offset = GET_U_1(cfm_common_header->first_tlv_offset); 323*ee67461eSJoseph Mingrone ND_PRINT("\n\tFirst TLV offset %u", first_tlv_offset); 324a5779b6eSRui Paulo 325*ee67461eSJoseph Mingrone tptr += sizeof(struct cfm_common_header_t); 326a5779b6eSRui Paulo tlen = length - sizeof(struct cfm_common_header_t); 327a5779b6eSRui Paulo 3283340d773SGleb Smirnoff /* 3293340d773SGleb Smirnoff * Sanity check the first TLV offset. 3303340d773SGleb Smirnoff */ 331*ee67461eSJoseph Mingrone if (first_tlv_offset > tlen) { 332*ee67461eSJoseph Mingrone ND_PRINT(" (too large, must be <= %u)", tlen); 3333340d773SGleb Smirnoff return; 3343340d773SGleb Smirnoff } 3353340d773SGleb Smirnoff 336*ee67461eSJoseph Mingrone switch (opcode) { 337a5779b6eSRui Paulo case CFM_OPCODE_CCM: 338a5779b6eSRui Paulo msg_ptr.cfm_ccm = (const struct cfm_ccm_t *)tptr; 339*ee67461eSJoseph Mingrone if (first_tlv_offset < sizeof(*msg_ptr.cfm_ccm)) { 340*ee67461eSJoseph Mingrone ND_PRINT(" (too small 1, must be >= %zu)", 341*ee67461eSJoseph Mingrone sizeof(*msg_ptr.cfm_ccm)); 3423340d773SGleb Smirnoff return; 3433340d773SGleb Smirnoff } 3443340d773SGleb Smirnoff if (tlen < sizeof(*msg_ptr.cfm_ccm)) 3453340d773SGleb Smirnoff goto tooshort; 346*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(msg_ptr.cfm_ccm); 347a5779b6eSRui Paulo 348*ee67461eSJoseph Mingrone ccm_interval = CFM_EXTRACT_CCM_INTERVAL(flags); 349*ee67461eSJoseph Mingrone ND_PRINT(", Flags [CCM Interval %u%s]", 350a5779b6eSRui Paulo ccm_interval, 351*ee67461eSJoseph Mingrone flags & CFM_CCM_RDI_FLAG ? 352*ee67461eSJoseph Mingrone ", RDI" : ""); 353a5779b6eSRui Paulo 354a5779b6eSRui Paulo /* 355a5779b6eSRui Paulo * Resolve the CCM interval field. 356a5779b6eSRui Paulo */ 357a5779b6eSRui Paulo if (ccm_interval) { 358*ee67461eSJoseph Mingrone ND_PRINT("\n\t CCM Interval %.3fs" 359a5779b6eSRui Paulo ", min CCM Lifetime %.3fs, max CCM Lifetime %.3fs", 360a5779b6eSRui Paulo ccm_interval_base[ccm_interval], 361a5779b6eSRui Paulo ccm_interval_base[ccm_interval] * CCM_INTERVAL_MIN_MULTIPLIER, 362*ee67461eSJoseph Mingrone ccm_interval_base[ccm_interval] * CCM_INTERVAL_MAX_MULTIPLIER); 363a5779b6eSRui Paulo } 364a5779b6eSRui Paulo 365*ee67461eSJoseph Mingrone ND_PRINT("\n\t Sequence Number 0x%08x, MA-End-Point-ID 0x%04x", 366*ee67461eSJoseph Mingrone GET_BE_U_4(msg_ptr.cfm_ccm->sequence), 367*ee67461eSJoseph Mingrone GET_BE_U_2(msg_ptr.cfm_ccm->ma_epi)); 368a5779b6eSRui Paulo 3693340d773SGleb Smirnoff namesp = msg_ptr.cfm_ccm->names; 3703340d773SGleb Smirnoff names_data_remaining = sizeof(msg_ptr.cfm_ccm->names); 371a5779b6eSRui Paulo 372a5779b6eSRui Paulo /* 373a5779b6eSRui Paulo * Resolve the MD fields. 374a5779b6eSRui Paulo */ 375*ee67461eSJoseph Mingrone md_nameformat = GET_U_1(namesp); 3763340d773SGleb Smirnoff namesp++; 3773340d773SGleb Smirnoff names_data_remaining--; /* We know this is != 0 */ 3783340d773SGleb Smirnoff if (md_nameformat != CFM_CCM_MD_FORMAT_NONE) { 379*ee67461eSJoseph Mingrone md_namelength = GET_U_1(namesp); 3803340d773SGleb Smirnoff namesp++; 3813340d773SGleb Smirnoff names_data_remaining--; /* We know this is !=0 */ 382*ee67461eSJoseph Mingrone ND_PRINT("\n\t MD Name Format %s (%u), MD Name length %u", 383a5779b6eSRui Paulo tok2str(cfm_md_nameformat_values, "Unknown", 3843340d773SGleb Smirnoff md_nameformat), 3853340d773SGleb Smirnoff md_nameformat, 386*ee67461eSJoseph Mingrone md_namelength); 387a5779b6eSRui Paulo 3880bff6a5aSEd Maste /* 3890bff6a5aSEd Maste * -3 for the MA short name format and length and one byte 3900bff6a5aSEd Maste * of MA short name. 3910bff6a5aSEd Maste */ 3920bff6a5aSEd Maste if (md_namelength > names_data_remaining - 3) { 393*ee67461eSJoseph Mingrone ND_PRINT(" (too large, must be <= %u)", names_data_remaining - 2); 3943340d773SGleb Smirnoff return; 3953340d773SGleb Smirnoff } 3963340d773SGleb Smirnoff 3973340d773SGleb Smirnoff md_name = namesp; 398*ee67461eSJoseph Mingrone ND_PRINT("\n\t MD Name: "); 3993340d773SGleb Smirnoff switch (md_nameformat) { 400a5779b6eSRui Paulo case CFM_CCM_MD_FORMAT_DNS: 401a5779b6eSRui Paulo case CFM_CCM_MD_FORMAT_CHAR: 402*ee67461eSJoseph Mingrone nd_printjnp(ndo, md_name, md_namelength); 403a5779b6eSRui Paulo break; 404a5779b6eSRui Paulo 405a5779b6eSRui Paulo case CFM_CCM_MD_FORMAT_MAC: 406*ee67461eSJoseph Mingrone if (md_namelength == MAC_ADDR_LEN) { 407*ee67461eSJoseph Mingrone ND_PRINT("\n\t MAC %s", GET_ETHERADDR_STRING(md_name)); 4083340d773SGleb Smirnoff } else { 409*ee67461eSJoseph Mingrone ND_PRINT("\n\t MAC (length invalid)"); 4103340d773SGleb Smirnoff } 411a5779b6eSRui Paulo break; 412a5779b6eSRui Paulo 413a5779b6eSRui Paulo /* FIXME add printers for those MD formats - hexdump for now */ 414a5779b6eSRui Paulo case CFM_CCM_MA_FORMAT_8021: 415a5779b6eSRui Paulo default: 4163340d773SGleb Smirnoff print_unknown_data(ndo, md_name, "\n\t ", 4173340d773SGleb Smirnoff md_namelength); 418a5779b6eSRui Paulo } 4193340d773SGleb Smirnoff namesp += md_namelength; 4203340d773SGleb Smirnoff names_data_remaining -= md_namelength; 4213340d773SGleb Smirnoff } else { 422*ee67461eSJoseph Mingrone ND_PRINT("\n\t MD Name Format %s (%u)", 4233340d773SGleb Smirnoff tok2str(cfm_md_nameformat_values, "Unknown", 4243340d773SGleb Smirnoff md_nameformat), 425*ee67461eSJoseph Mingrone md_nameformat); 426a5779b6eSRui Paulo } 427a5779b6eSRui Paulo 428a5779b6eSRui Paulo 429a5779b6eSRui Paulo /* 430a5779b6eSRui Paulo * Resolve the MA fields. 431a5779b6eSRui Paulo */ 432*ee67461eSJoseph Mingrone ma_nameformat = GET_U_1(namesp); 4333340d773SGleb Smirnoff namesp++; 4343340d773SGleb Smirnoff names_data_remaining--; /* We know this is != 0 */ 435*ee67461eSJoseph Mingrone ma_namelength = GET_U_1(namesp); 4363340d773SGleb Smirnoff namesp++; 4373340d773SGleb Smirnoff names_data_remaining--; /* We know this is != 0 */ 438*ee67461eSJoseph Mingrone ND_PRINT("\n\t MA Name-Format %s (%u), MA name length %u", 439a5779b6eSRui Paulo tok2str(cfm_ma_nameformat_values, "Unknown", 4403340d773SGleb Smirnoff ma_nameformat), 4413340d773SGleb Smirnoff ma_nameformat, 442*ee67461eSJoseph Mingrone ma_namelength); 443a5779b6eSRui Paulo 4443340d773SGleb Smirnoff if (ma_namelength > names_data_remaining) { 445*ee67461eSJoseph Mingrone ND_PRINT(" (too large, must be <= %u)", names_data_remaining); 4463340d773SGleb Smirnoff return; 4473340d773SGleb Smirnoff } 4483340d773SGleb Smirnoff 4493340d773SGleb Smirnoff ma_name = namesp; 450*ee67461eSJoseph Mingrone ND_PRINT("\n\t MA Name: "); 4513340d773SGleb Smirnoff switch (ma_nameformat) { 452a5779b6eSRui Paulo case CFM_CCM_MA_FORMAT_CHAR: 453*ee67461eSJoseph Mingrone nd_printjnp(ndo, ma_name, ma_namelength); 454a5779b6eSRui Paulo break; 455a5779b6eSRui Paulo 456a5779b6eSRui Paulo /* FIXME add printers for those MA formats - hexdump for now */ 457a5779b6eSRui Paulo case CFM_CCM_MA_FORMAT_8021: 458a5779b6eSRui Paulo case CFM_CCM_MA_FORMAT_VID: 459a5779b6eSRui Paulo case CFM_CCM_MA_FORMAT_INT: 460a5779b6eSRui Paulo case CFM_CCM_MA_FORMAT_VPN: 461a5779b6eSRui Paulo default: 4623340d773SGleb Smirnoff print_unknown_data(ndo, ma_name, "\n\t ", ma_namelength); 463a5779b6eSRui Paulo } 464a5779b6eSRui Paulo break; 465a5779b6eSRui Paulo 466a5779b6eSRui Paulo case CFM_OPCODE_LTM: 46727df3f5dSRui Paulo msg_ptr.cfm_ltm = (const struct cfm_ltm_t *)tptr; 468*ee67461eSJoseph Mingrone if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltm)) { 469*ee67461eSJoseph Mingrone ND_PRINT(" (too small 4, must be >= %zu)", 470*ee67461eSJoseph Mingrone sizeof(*msg_ptr.cfm_ltm)); 4713340d773SGleb Smirnoff return; 4723340d773SGleb Smirnoff } 4733340d773SGleb Smirnoff if (tlen < sizeof(*msg_ptr.cfm_ltm)) 4743340d773SGleb Smirnoff goto tooshort; 475*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(msg_ptr.cfm_ltm); 47627df3f5dSRui Paulo 477*ee67461eSJoseph Mingrone ND_PRINT(", Flags [%s]", 478*ee67461eSJoseph Mingrone bittok2str(cfm_ltm_flag_values, "none", flags)); 479a5779b6eSRui Paulo 480*ee67461eSJoseph Mingrone ND_PRINT("\n\t Transaction-ID 0x%08x, ttl %u", 481*ee67461eSJoseph Mingrone GET_BE_U_4(msg_ptr.cfm_ltm->transaction_id), 482*ee67461eSJoseph Mingrone GET_U_1(msg_ptr.cfm_ltm->ttl)); 483a5779b6eSRui Paulo 484*ee67461eSJoseph Mingrone ND_PRINT("\n\t Original-MAC %s, Target-MAC %s", 485*ee67461eSJoseph Mingrone GET_ETHERADDR_STRING(msg_ptr.cfm_ltm->original_mac), 486*ee67461eSJoseph Mingrone GET_ETHERADDR_STRING(msg_ptr.cfm_ltm->target_mac)); 487a5779b6eSRui Paulo break; 488a5779b6eSRui Paulo 489a5779b6eSRui Paulo case CFM_OPCODE_LTR: 49027df3f5dSRui Paulo msg_ptr.cfm_ltr = (const struct cfm_ltr_t *)tptr; 491*ee67461eSJoseph Mingrone if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltr)) { 492*ee67461eSJoseph Mingrone ND_PRINT(" (too small 5, must be >= %zu)", 493*ee67461eSJoseph Mingrone sizeof(*msg_ptr.cfm_ltr)); 4943340d773SGleb Smirnoff return; 4953340d773SGleb Smirnoff } 4963340d773SGleb Smirnoff if (tlen < sizeof(*msg_ptr.cfm_ltr)) 4973340d773SGleb Smirnoff goto tooshort; 498*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(msg_ptr.cfm_ltr); 49927df3f5dSRui Paulo 500*ee67461eSJoseph Mingrone ND_PRINT(", Flags [%s]", 501*ee67461eSJoseph Mingrone bittok2str(cfm_ltr_flag_values, "none", flags)); 502a5779b6eSRui Paulo 503*ee67461eSJoseph Mingrone ND_PRINT("\n\t Transaction-ID 0x%08x, ttl %u", 504*ee67461eSJoseph Mingrone GET_BE_U_4(msg_ptr.cfm_ltr->transaction_id), 505*ee67461eSJoseph Mingrone GET_U_1(msg_ptr.cfm_ltr->ttl)); 506a5779b6eSRui Paulo 507*ee67461eSJoseph Mingrone ND_PRINT("\n\t Replay-Action %s (%u)", 508a5779b6eSRui Paulo tok2str(cfm_ltr_replay_action_values, 509a5779b6eSRui Paulo "Unknown", 510*ee67461eSJoseph Mingrone GET_U_1(msg_ptr.cfm_ltr->replay_action)), 511*ee67461eSJoseph Mingrone GET_U_1(msg_ptr.cfm_ltr->replay_action)); 512a5779b6eSRui Paulo break; 513a5779b6eSRui Paulo 514a5779b6eSRui Paulo /* 515a5779b6eSRui Paulo * No message decoder yet. 516a5779b6eSRui Paulo * Hexdump everything up until the start of the TLVs 517a5779b6eSRui Paulo */ 518a5779b6eSRui Paulo case CFM_OPCODE_LBR: 519a5779b6eSRui Paulo case CFM_OPCODE_LBM: 520a5779b6eSRui Paulo default: 5213c602fabSXin LI print_unknown_data(ndo, tptr, "\n\t ", 522*ee67461eSJoseph Mingrone tlen - first_tlv_offset); 523a5779b6eSRui Paulo break; 524a5779b6eSRui Paulo } 525a5779b6eSRui Paulo 526*ee67461eSJoseph Mingrone tptr += first_tlv_offset; 527*ee67461eSJoseph Mingrone tlen -= first_tlv_offset; 528a5779b6eSRui Paulo 529a5779b6eSRui Paulo while (tlen > 0) { 530a5779b6eSRui Paulo cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr; 531a5779b6eSRui Paulo 532a5779b6eSRui Paulo /* Enough to read the tlv type ? */ 533*ee67461eSJoseph Mingrone cfm_tlv_type = GET_U_1(cfm_tlv_header->type); 534a5779b6eSRui Paulo 535*ee67461eSJoseph Mingrone ND_PRINT("\n\t%s TLV (0x%02x)", 536a5779b6eSRui Paulo tok2str(cfm_tlv_values, "Unknown", cfm_tlv_type), 537*ee67461eSJoseph Mingrone cfm_tlv_type); 538a5779b6eSRui Paulo 5393340d773SGleb Smirnoff if (cfm_tlv_type == CFM_TLV_END) { 5403340d773SGleb Smirnoff /* Length is "Not present if the Type field is 0." */ 541a5779b6eSRui Paulo return; 542a5779b6eSRui Paulo } 543a5779b6eSRui Paulo 5443340d773SGleb Smirnoff /* do we have the full tlv header ? */ 5453340d773SGleb Smirnoff if (tlen < sizeof(struct cfm_tlv_header_t)) 5463340d773SGleb Smirnoff goto tooshort; 547*ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, sizeof(struct cfm_tlv_header_t)); 548*ee67461eSJoseph Mingrone cfm_tlv_len=GET_BE_U_2(cfm_tlv_header->length); 5493340d773SGleb Smirnoff 550*ee67461eSJoseph Mingrone ND_PRINT(", length %u", cfm_tlv_len); 5513340d773SGleb Smirnoff 552a5779b6eSRui Paulo tptr += sizeof(struct cfm_tlv_header_t); 553a5779b6eSRui Paulo tlen -= sizeof(struct cfm_tlv_header_t); 554a5779b6eSRui Paulo tlv_ptr = tptr; 555a5779b6eSRui Paulo 5563340d773SGleb Smirnoff /* do we have the full tlv ? */ 5573340d773SGleb Smirnoff if (tlen < cfm_tlv_len) 5583340d773SGleb Smirnoff goto tooshort; 559*ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, cfm_tlv_len); 560a5779b6eSRui Paulo hexdump = FALSE; 561a5779b6eSRui Paulo 562a5779b6eSRui Paulo switch(cfm_tlv_type) { 563a5779b6eSRui Paulo case CFM_TLV_PORT_STATUS: 5643340d773SGleb Smirnoff if (cfm_tlv_len < 1) { 565*ee67461eSJoseph Mingrone ND_PRINT(" (too short, must be >= 1)"); 5663340d773SGleb Smirnoff return; 5673340d773SGleb Smirnoff } 568*ee67461eSJoseph Mingrone ND_PRINT(", Status: %s (%u)", 569*ee67461eSJoseph Mingrone tok2str(cfm_tlv_port_status_values, "Unknown", GET_U_1(tptr)), 570*ee67461eSJoseph Mingrone GET_U_1(tptr)); 571a5779b6eSRui Paulo break; 572a5779b6eSRui Paulo 573a5779b6eSRui Paulo case CFM_TLV_INTERFACE_STATUS: 5743340d773SGleb Smirnoff if (cfm_tlv_len < 1) { 575*ee67461eSJoseph Mingrone ND_PRINT(" (too short, must be >= 1)"); 5763340d773SGleb Smirnoff return; 5773340d773SGleb Smirnoff } 578*ee67461eSJoseph Mingrone ND_PRINT(", Status: %s (%u)", 579*ee67461eSJoseph Mingrone tok2str(cfm_tlv_interface_status_values, "Unknown", GET_U_1(tptr)), 580*ee67461eSJoseph Mingrone GET_U_1(tptr)); 581a5779b6eSRui Paulo break; 582a5779b6eSRui Paulo 583a5779b6eSRui Paulo case CFM_TLV_PRIVATE: 5843340d773SGleb Smirnoff if (cfm_tlv_len < 4) { 585*ee67461eSJoseph Mingrone ND_PRINT(" (too short, must be >= 4)"); 5863340d773SGleb Smirnoff return; 5873340d773SGleb Smirnoff } 588*ee67461eSJoseph Mingrone ND_PRINT(", Vendor: %s (%u), Sub-Type %u", 589*ee67461eSJoseph Mingrone tok2str(oui_values,"Unknown", GET_BE_U_3(tptr)), 590*ee67461eSJoseph Mingrone GET_BE_U_3(tptr), 591*ee67461eSJoseph Mingrone GET_U_1(tptr + 3)); 592a5779b6eSRui Paulo hexdump = TRUE; 593a5779b6eSRui Paulo break; 594a5779b6eSRui Paulo 595a5779b6eSRui Paulo case CFM_TLV_SENDER_ID: 596a5779b6eSRui Paulo { 597a5779b6eSRui Paulo u_int chassis_id_type, chassis_id_length; 598a5779b6eSRui Paulo u_int mgmt_addr_length; 599a5779b6eSRui Paulo 6003340d773SGleb Smirnoff if (cfm_tlv_len < 1) { 601*ee67461eSJoseph Mingrone ND_PRINT(" (too short, must be >= 1)"); 6020bff6a5aSEd Maste goto next_tlv; 603a5779b6eSRui Paulo } 604a5779b6eSRui Paulo 6053340d773SGleb Smirnoff /* 6063340d773SGleb Smirnoff * Get the Chassis ID length and check it. 6070bff6a5aSEd Maste * IEEE 802.1Q-2014 Section 21.5.3.1 6083340d773SGleb Smirnoff */ 609*ee67461eSJoseph Mingrone chassis_id_length = GET_U_1(tptr); 610a5779b6eSRui Paulo tptr++; 611a5779b6eSRui Paulo tlen--; 6123340d773SGleb Smirnoff cfm_tlv_len--; 613a5779b6eSRui Paulo 614a5779b6eSRui Paulo if (chassis_id_length) { 6150bff6a5aSEd Maste /* 6160bff6a5aSEd Maste * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references 6170bff6a5aSEd Maste * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently 6180bff6a5aSEd Maste * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype 6190bff6a5aSEd Maste */ 6203340d773SGleb Smirnoff if (cfm_tlv_len < 1) { 621*ee67461eSJoseph Mingrone ND_PRINT("\n\t (TLV too short)"); 6220bff6a5aSEd Maste goto next_tlv; 6233340d773SGleb Smirnoff } 624*ee67461eSJoseph Mingrone chassis_id_type = GET_U_1(tptr); 6253340d773SGleb Smirnoff cfm_tlv_len--; 626*ee67461eSJoseph Mingrone ND_PRINT("\n\t Chassis-ID Type %s (%u), Chassis-ID length %u", 627a5779b6eSRui Paulo tok2str(cfm_tlv_senderid_chassisid_values, 628a5779b6eSRui Paulo "Unknown", 629a5779b6eSRui Paulo chassis_id_type), 630a5779b6eSRui Paulo chassis_id_type, 631*ee67461eSJoseph Mingrone chassis_id_length); 632a5779b6eSRui Paulo 6333340d773SGleb Smirnoff if (cfm_tlv_len < chassis_id_length) { 634*ee67461eSJoseph Mingrone ND_PRINT("\n\t (TLV too short)"); 6350bff6a5aSEd Maste goto next_tlv; 6363340d773SGleb Smirnoff } 6373340d773SGleb Smirnoff 6380bff6a5aSEd Maste /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */ 639a5779b6eSRui Paulo switch (chassis_id_type) { 640a5779b6eSRui Paulo case CFM_CHASSIS_ID_MAC_ADDRESS: 641*ee67461eSJoseph Mingrone if (chassis_id_length != MAC_ADDR_LEN) { 642*ee67461eSJoseph Mingrone ND_PRINT(" (invalid MAC address length)"); 6430bff6a5aSEd Maste hexdump = TRUE; 6440bff6a5aSEd Maste break; 6450bff6a5aSEd Maste } 646*ee67461eSJoseph Mingrone ND_PRINT("\n\t MAC %s", GET_ETHERADDR_STRING(tptr + 1)); 647a5779b6eSRui Paulo break; 648a5779b6eSRui Paulo 649a5779b6eSRui Paulo case CFM_CHASSIS_ID_NETWORK_ADDRESS: 6500bff6a5aSEd Maste hexdump |= cfm_network_addr_print(ndo, tptr + 1, chassis_id_length); 651a5779b6eSRui Paulo break; 652a5779b6eSRui Paulo 653a5779b6eSRui Paulo case CFM_CHASSIS_ID_INTERFACE_NAME: /* fall through */ 654a5779b6eSRui Paulo case CFM_CHASSIS_ID_INTERFACE_ALIAS: 655a5779b6eSRui Paulo case CFM_CHASSIS_ID_LOCAL: 656a5779b6eSRui Paulo case CFM_CHASSIS_ID_CHASSIS_COMPONENT: 657a5779b6eSRui Paulo case CFM_CHASSIS_ID_PORT_COMPONENT: 658*ee67461eSJoseph Mingrone nd_printjnp(ndo, tptr + 1, chassis_id_length); 659a5779b6eSRui Paulo break; 660a5779b6eSRui Paulo 661a5779b6eSRui Paulo default: 662a5779b6eSRui Paulo hexdump = TRUE; 663a5779b6eSRui Paulo break; 664a5779b6eSRui Paulo } 6653340d773SGleb Smirnoff cfm_tlv_len -= chassis_id_length; 666a5779b6eSRui Paulo 6673340d773SGleb Smirnoff tptr += 1 + chassis_id_length; 6683340d773SGleb Smirnoff tlen -= 1 + chassis_id_length; 6693340d773SGleb Smirnoff } 670a5779b6eSRui Paulo 671a5779b6eSRui Paulo /* 672a5779b6eSRui Paulo * Check if there is a Management Address. 6730bff6a5aSEd Maste * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length 6740bff6a5aSEd Maste * This and all subsequent fields are not present if the TLV length 6750bff6a5aSEd Maste * allows only the above fields. 676a5779b6eSRui Paulo */ 6773340d773SGleb Smirnoff if (cfm_tlv_len == 0) { 6783340d773SGleb Smirnoff /* No, there isn't; we're done. */ 6790bff6a5aSEd Maste break; 680a5779b6eSRui Paulo } 681a5779b6eSRui Paulo 6820bff6a5aSEd Maste /* Here mgmt_addr_length stands for the management domain length. */ 683*ee67461eSJoseph Mingrone mgmt_addr_length = GET_U_1(tptr); 684a5779b6eSRui Paulo tptr++; 685a5779b6eSRui Paulo tlen--; 6863340d773SGleb Smirnoff cfm_tlv_len--; 687*ee67461eSJoseph Mingrone ND_PRINT("\n\t Management Address Domain Length %u", mgmt_addr_length); 688a5779b6eSRui Paulo if (mgmt_addr_length) { 6890bff6a5aSEd Maste /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */ 6903340d773SGleb Smirnoff if (cfm_tlv_len < mgmt_addr_length) { 691*ee67461eSJoseph Mingrone ND_PRINT("\n\t (TLV too short)"); 6920bff6a5aSEd Maste goto next_tlv; 693a5779b6eSRui Paulo } 6943340d773SGleb Smirnoff cfm_tlv_len -= mgmt_addr_length; 6953340d773SGleb Smirnoff /* 6963340d773SGleb Smirnoff * XXX - this is an OID; print it as such. 6973340d773SGleb Smirnoff */ 6980bff6a5aSEd Maste hex_print(ndo, "\n\t Management Address Domain: ", tptr, mgmt_addr_length); 699a5779b6eSRui Paulo tptr += mgmt_addr_length; 700a5779b6eSRui Paulo tlen -= mgmt_addr_length; 701a5779b6eSRui Paulo 7020bff6a5aSEd Maste /* 7030bff6a5aSEd Maste * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length 7040bff6a5aSEd Maste * This field is present if Management Address Domain Length is not 0. 7050bff6a5aSEd Maste */ 7063340d773SGleb Smirnoff if (cfm_tlv_len < 1) { 707*ee67461eSJoseph Mingrone ND_PRINT(" (Management Address Length is missing)"); 7080bff6a5aSEd Maste hexdump = TRUE; 7090bff6a5aSEd Maste break; 7103340d773SGleb Smirnoff } 7113340d773SGleb Smirnoff 7120bff6a5aSEd Maste /* Here mgmt_addr_length stands for the management address length. */ 713*ee67461eSJoseph Mingrone mgmt_addr_length = GET_U_1(tptr); 7143340d773SGleb Smirnoff tptr++; 7153340d773SGleb Smirnoff tlen--; 7163340d773SGleb Smirnoff cfm_tlv_len--; 717*ee67461eSJoseph Mingrone ND_PRINT("\n\t Management Address Length %u", mgmt_addr_length); 7183340d773SGleb Smirnoff if (mgmt_addr_length) { 7190bff6a5aSEd Maste /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */ 7203340d773SGleb Smirnoff if (cfm_tlv_len < mgmt_addr_length) { 721*ee67461eSJoseph Mingrone ND_PRINT("\n\t (TLV too short)"); 7223340d773SGleb Smirnoff return; 7233340d773SGleb Smirnoff } 7243340d773SGleb Smirnoff cfm_tlv_len -= mgmt_addr_length; 7253340d773SGleb Smirnoff /* 7263340d773SGleb Smirnoff * XXX - this is a TransportDomain; print it as such. 7273340d773SGleb Smirnoff */ 7280bff6a5aSEd Maste hex_print(ndo, "\n\t Management Address: ", tptr, mgmt_addr_length); 7293340d773SGleb Smirnoff tptr += mgmt_addr_length; 7303340d773SGleb Smirnoff tlen -= mgmt_addr_length; 7313340d773SGleb Smirnoff } 732a5779b6eSRui Paulo } 733a5779b6eSRui Paulo break; 7343340d773SGleb Smirnoff } 735a5779b6eSRui Paulo 736a5779b6eSRui Paulo /* 737a5779b6eSRui Paulo * FIXME those are the defined TLVs that lack a decoder 738a5779b6eSRui Paulo * you are welcome to contribute code ;-) 739a5779b6eSRui Paulo */ 740a5779b6eSRui Paulo 741a5779b6eSRui Paulo case CFM_TLV_DATA: 742a5779b6eSRui Paulo case CFM_TLV_REPLY_INGRESS: 743a5779b6eSRui Paulo case CFM_TLV_REPLY_EGRESS: 744a5779b6eSRui Paulo default: 745a5779b6eSRui Paulo hexdump = TRUE; 746a5779b6eSRui Paulo break; 747a5779b6eSRui Paulo } 748a5779b6eSRui Paulo /* do we want to see an additional hexdump ? */ 7493c602fabSXin LI if (hexdump || ndo->ndo_vflag > 1) 7503c602fabSXin LI print_unknown_data(ndo, tlv_ptr, "\n\t ", cfm_tlv_len); 751a5779b6eSRui Paulo 7520bff6a5aSEd Maste next_tlv: 753a5779b6eSRui Paulo tptr+=cfm_tlv_len; 754a5779b6eSRui Paulo tlen-=cfm_tlv_len; 755a5779b6eSRui Paulo } 756a5779b6eSRui Paulo return; 7573340d773SGleb Smirnoff 7583340d773SGleb Smirnoff tooshort: 759*ee67461eSJoseph Mingrone ND_PRINT("\n\t\t packet is too short"); 7603340d773SGleb Smirnoff return; 7613340d773SGleb Smirnoff 762a5779b6eSRui Paulo trunc: 763*ee67461eSJoseph Mingrone nd_print_trunc(ndo); 764a5779b6eSRui Paulo } 765