xref: /dflybsd-src/contrib/tcpdump/print-cfm.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
1ea7b4bf5SPeter Avalos /*
2ea7b4bf5SPeter Avalos  * Copyright (c) 1998-2006 The TCPDUMP project
3ea7b4bf5SPeter Avalos  *
4ea7b4bf5SPeter Avalos  * Redistribution and use in source and binary forms, with or without
5ea7b4bf5SPeter Avalos  * modification, are permitted provided that: (1) source code
6ea7b4bf5SPeter Avalos  * distributions retain the above copyright notice and this paragraph
7ea7b4bf5SPeter Avalos  * in its entirety, and (2) distributions including binary code include
8ea7b4bf5SPeter Avalos  * the above copyright notice and this paragraph in its entirety in
9ea7b4bf5SPeter Avalos  * the documentation or other materials provided with the distribution.
10ea7b4bf5SPeter Avalos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11ea7b4bf5SPeter Avalos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12ea7b4bf5SPeter Avalos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13ea7b4bf5SPeter Avalos  * FOR A PARTICULAR PURPOSE.
14ea7b4bf5SPeter Avalos  *
15411677aeSAaron LI  * Original code by Hannes Gredler (hannes@gredler.at)
16ea7b4bf5SPeter Avalos  */
17ea7b4bf5SPeter Avalos 
18411677aeSAaron LI /* \summary: IEEE 802.1ag Connectivity Fault Management (CFM) protocols printer */
19ea7b4bf5SPeter Avalos 
20ea7b4bf5SPeter Avalos #ifdef HAVE_CONFIG_H
21*ed775ee7SAntonio Huete Jimenez #include <config.h>
22ea7b4bf5SPeter Avalos #endif
23ea7b4bf5SPeter Avalos 
24*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
25ea7b4bf5SPeter Avalos 
26411677aeSAaron LI #include "netdissect.h"
27ea7b4bf5SPeter Avalos #include "extract.h"
28ea7b4bf5SPeter Avalos #include "addrtoname.h"
29ea7b4bf5SPeter Avalos #include "oui.h"
30ea7b4bf5SPeter Avalos #include "af.h"
31ea7b4bf5SPeter Avalos 
32*ed775ee7SAntonio Huete Jimenez 
33ea7b4bf5SPeter Avalos struct cfm_common_header_t {
34*ed775ee7SAntonio Huete Jimenez     nd_uint8_t mdlevel_version;
35*ed775ee7SAntonio Huete Jimenez     nd_uint8_t opcode;
36*ed775ee7SAntonio Huete Jimenez     nd_uint8_t flags;
37*ed775ee7SAntonio Huete Jimenez     nd_uint8_t first_tlv_offset;
38ea7b4bf5SPeter Avalos };
39ea7b4bf5SPeter Avalos 
40ea7b4bf5SPeter Avalos #define	CFM_VERSION 0
41*ed775ee7SAntonio Huete Jimenez #define CFM_EXTRACT_VERSION(x) ((x)&0x1f)
42ea7b4bf5SPeter Avalos #define CFM_EXTRACT_MD_LEVEL(x) (((x)&0xe0)>>5)
43ea7b4bf5SPeter Avalos 
44ea7b4bf5SPeter Avalos #define	CFM_OPCODE_CCM 1
45ea7b4bf5SPeter Avalos #define	CFM_OPCODE_LBR 2
46ea7b4bf5SPeter Avalos #define	CFM_OPCODE_LBM 3
47ea7b4bf5SPeter Avalos #define	CFM_OPCODE_LTR 4
48ea7b4bf5SPeter Avalos #define	CFM_OPCODE_LTM 5
49ea7b4bf5SPeter Avalos 
50ea7b4bf5SPeter Avalos static const struct tok cfm_opcode_values[] = {
51*ed775ee7SAntonio Huete Jimenez     { CFM_OPCODE_CCM, "Continuity Check Message"},
52ea7b4bf5SPeter Avalos     { CFM_OPCODE_LBR, "Loopback Reply"},
53ea7b4bf5SPeter Avalos     { CFM_OPCODE_LBM, "Loopback Message"},
54ea7b4bf5SPeter Avalos     { CFM_OPCODE_LTR, "Linktrace Reply"},
55ea7b4bf5SPeter Avalos     { CFM_OPCODE_LTM, "Linktrace Message"},
56ea7b4bf5SPeter Avalos     { 0, NULL}
57ea7b4bf5SPeter Avalos };
58ea7b4bf5SPeter Avalos 
59ea7b4bf5SPeter Avalos /*
60ea7b4bf5SPeter Avalos  * Message Formats.
61ea7b4bf5SPeter Avalos  */
62ea7b4bf5SPeter Avalos struct cfm_ccm_t {
63*ed775ee7SAntonio Huete Jimenez     nd_uint32_t sequence;
64*ed775ee7SAntonio Huete Jimenez     nd_uint16_t ma_epi;
65*ed775ee7SAntonio Huete Jimenez     nd_byte     names[48];
66*ed775ee7SAntonio Huete Jimenez     nd_byte     itu_t_y_1731[16];
67ea7b4bf5SPeter Avalos };
68ea7b4bf5SPeter Avalos 
69ea7b4bf5SPeter Avalos /*
70ea7b4bf5SPeter Avalos  * Timer Bases for the CCM Interval field.
71ea7b4bf5SPeter Avalos  * Expressed in units of seconds.
72ea7b4bf5SPeter Avalos  */
73*ed775ee7SAntonio Huete Jimenez static const float ccm_interval_base[8] = {0.0f, 0.003333f, 0.01f, 0.1f, 1.0f, 10.0f, 60.0f, 600.0f};
74ea7b4bf5SPeter Avalos #define CCM_INTERVAL_MIN_MULTIPLIER 3.25
75ea7b4bf5SPeter Avalos #define CCM_INTERVAL_MAX_MULTIPLIER 3.5
76ea7b4bf5SPeter Avalos 
77ea7b4bf5SPeter Avalos #define CFM_CCM_RDI_FLAG 0x80
78*ed775ee7SAntonio Huete Jimenez #define CFM_EXTRACT_CCM_INTERVAL(x) ((x)&0x07)
79ea7b4bf5SPeter Avalos 
80ea7b4bf5SPeter Avalos #define CFM_CCM_MD_FORMAT_8021 0
81ea7b4bf5SPeter Avalos #define CFM_CCM_MD_FORMAT_NONE 1
82ea7b4bf5SPeter Avalos #define CFM_CCM_MD_FORMAT_DNS  2
83ea7b4bf5SPeter Avalos #define CFM_CCM_MD_FORMAT_MAC  3
84ea7b4bf5SPeter Avalos #define CFM_CCM_MD_FORMAT_CHAR 4
85ea7b4bf5SPeter Avalos 
86ea7b4bf5SPeter Avalos static const struct tok cfm_md_nameformat_values[] = {
87ea7b4bf5SPeter Avalos     { CFM_CCM_MD_FORMAT_8021, "IEEE 802.1"},
88ea7b4bf5SPeter Avalos     { CFM_CCM_MD_FORMAT_NONE, "No MD Name present"},
89ea7b4bf5SPeter Avalos     { CFM_CCM_MD_FORMAT_DNS, "DNS string"},
90ea7b4bf5SPeter Avalos     { CFM_CCM_MD_FORMAT_MAC, "MAC + 16Bit Integer"},
91ea7b4bf5SPeter Avalos     { CFM_CCM_MD_FORMAT_CHAR, "Character string"},
92ea7b4bf5SPeter Avalos     { 0, NULL}
93ea7b4bf5SPeter Avalos };
94ea7b4bf5SPeter Avalos 
95ea7b4bf5SPeter Avalos #define CFM_CCM_MA_FORMAT_8021 0
96ea7b4bf5SPeter Avalos #define CFM_CCM_MA_FORMAT_VID  1
97ea7b4bf5SPeter Avalos #define CFM_CCM_MA_FORMAT_CHAR 2
98ea7b4bf5SPeter Avalos #define CFM_CCM_MA_FORMAT_INT  3
99ea7b4bf5SPeter Avalos #define CFM_CCM_MA_FORMAT_VPN  4
100ea7b4bf5SPeter Avalos 
101ea7b4bf5SPeter Avalos static const struct tok cfm_ma_nameformat_values[] = {
102ea7b4bf5SPeter Avalos     { CFM_CCM_MA_FORMAT_8021, "IEEE 802.1"},
103ea7b4bf5SPeter Avalos     { CFM_CCM_MA_FORMAT_VID, "Primary VID"},
104ea7b4bf5SPeter Avalos     { CFM_CCM_MA_FORMAT_CHAR, "Character string"},
105ea7b4bf5SPeter Avalos     { CFM_CCM_MA_FORMAT_INT, "16Bit Integer"},
106ea7b4bf5SPeter Avalos     { CFM_CCM_MA_FORMAT_VPN, "RFC2685 VPN-ID"},
107ea7b4bf5SPeter Avalos     { 0, NULL}
108ea7b4bf5SPeter Avalos };
109ea7b4bf5SPeter Avalos 
110ea7b4bf5SPeter Avalos struct cfm_lbm_t {
111*ed775ee7SAntonio Huete Jimenez     nd_uint32_t transaction_id;
112ea7b4bf5SPeter Avalos };
113ea7b4bf5SPeter Avalos 
114ea7b4bf5SPeter Avalos struct cfm_ltm_t {
115*ed775ee7SAntonio Huete Jimenez     nd_uint32_t transaction_id;
116*ed775ee7SAntonio Huete Jimenez     nd_uint8_t  ttl;
117*ed775ee7SAntonio Huete Jimenez     nd_mac_addr original_mac;
118*ed775ee7SAntonio Huete Jimenez     nd_mac_addr target_mac;
119ea7b4bf5SPeter Avalos };
120ea7b4bf5SPeter Avalos 
121ea7b4bf5SPeter Avalos static const struct tok cfm_ltm_flag_values[] = {
122ea7b4bf5SPeter Avalos     { 0x80, "Use Forwarding-DB only"},
123ea7b4bf5SPeter Avalos     { 0, NULL}
124ea7b4bf5SPeter Avalos };
125ea7b4bf5SPeter Avalos 
126ea7b4bf5SPeter Avalos struct cfm_ltr_t {
127*ed775ee7SAntonio Huete Jimenez     nd_uint32_t transaction_id;
128*ed775ee7SAntonio Huete Jimenez     nd_uint8_t  ttl;
129*ed775ee7SAntonio Huete Jimenez     nd_uint8_t  replay_action;
130ea7b4bf5SPeter Avalos };
131ea7b4bf5SPeter Avalos 
132ea7b4bf5SPeter Avalos static const struct tok cfm_ltr_flag_values[] = {
133411677aeSAaron LI     { 0x80, "UseFDB Only"},
134411677aeSAaron LI     { 0x40, "FwdYes"},
135411677aeSAaron LI     { 0x20, "Terminal MEP"},
136ea7b4bf5SPeter Avalos     { 0, NULL}
137ea7b4bf5SPeter Avalos };
138ea7b4bf5SPeter Avalos 
139ea7b4bf5SPeter Avalos static const struct tok cfm_ltr_replay_action_values[] = {
140ea7b4bf5SPeter Avalos     { 1, "Exact Match"},
141ea7b4bf5SPeter Avalos     { 2, "Filtering DB"},
142ea7b4bf5SPeter Avalos     { 3, "MIP CCM DB"},
143ea7b4bf5SPeter Avalos     { 0, NULL}
144ea7b4bf5SPeter Avalos };
145ea7b4bf5SPeter Avalos 
146ea7b4bf5SPeter Avalos 
147ea7b4bf5SPeter Avalos #define CFM_TLV_END 0
148ea7b4bf5SPeter Avalos #define CFM_TLV_SENDER_ID 1
149ea7b4bf5SPeter Avalos #define CFM_TLV_PORT_STATUS 2
150ea7b4bf5SPeter Avalos #define CFM_TLV_INTERFACE_STATUS 3
151ea7b4bf5SPeter Avalos #define CFM_TLV_DATA 4
152ea7b4bf5SPeter Avalos #define CFM_TLV_REPLY_INGRESS 5
153ea7b4bf5SPeter Avalos #define CFM_TLV_REPLY_EGRESS 6
154ea7b4bf5SPeter Avalos #define CFM_TLV_PRIVATE 31
155ea7b4bf5SPeter Avalos 
156ea7b4bf5SPeter Avalos static const struct tok cfm_tlv_values[] = {
157ea7b4bf5SPeter Avalos     { CFM_TLV_END, "End"},
158ea7b4bf5SPeter Avalos     { CFM_TLV_SENDER_ID, "Sender ID"},
159ea7b4bf5SPeter Avalos     { CFM_TLV_PORT_STATUS, "Port status"},
160ea7b4bf5SPeter Avalos     { CFM_TLV_INTERFACE_STATUS, "Interface status"},
161ea7b4bf5SPeter Avalos     { CFM_TLV_DATA, "Data"},
162ea7b4bf5SPeter Avalos     { CFM_TLV_REPLY_INGRESS, "Reply Ingress"},
163ea7b4bf5SPeter Avalos     { CFM_TLV_REPLY_EGRESS, "Reply Egress"},
164ea7b4bf5SPeter Avalos     { CFM_TLV_PRIVATE, "Organization Specific"},
165ea7b4bf5SPeter Avalos     { 0, NULL}
166ea7b4bf5SPeter Avalos };
167ea7b4bf5SPeter Avalos 
168ea7b4bf5SPeter Avalos /*
169ea7b4bf5SPeter Avalos  * TLVs
170ea7b4bf5SPeter Avalos  */
171ea7b4bf5SPeter Avalos 
172ea7b4bf5SPeter Avalos struct cfm_tlv_header_t {
173*ed775ee7SAntonio Huete Jimenez     nd_uint8_t  type;
174*ed775ee7SAntonio Huete Jimenez     nd_uint16_t length;
175ea7b4bf5SPeter Avalos };
176ea7b4bf5SPeter Avalos 
177ea7b4bf5SPeter Avalos /* FIXME define TLV formats */
178ea7b4bf5SPeter Avalos 
179ea7b4bf5SPeter Avalos static const struct tok cfm_tlv_port_status_values[] = {
180ea7b4bf5SPeter Avalos     { 1, "Blocked"},
181ea7b4bf5SPeter Avalos     { 2, "Up"},
182ea7b4bf5SPeter Avalos     { 0, NULL}
183ea7b4bf5SPeter Avalos };
184ea7b4bf5SPeter Avalos 
185ea7b4bf5SPeter Avalos static const struct tok cfm_tlv_interface_status_values[] = {
186ea7b4bf5SPeter Avalos     { 1, "Up"},
187ea7b4bf5SPeter Avalos     { 2, "Down"},
188ea7b4bf5SPeter Avalos     { 3, "Testing"},
189ea7b4bf5SPeter Avalos     { 5, "Dormant"},
190ea7b4bf5SPeter Avalos     { 6, "not present"},
191ea7b4bf5SPeter Avalos     { 7, "lower Layer down"},
192ea7b4bf5SPeter Avalos     { 0, NULL}
193ea7b4bf5SPeter Avalos };
194ea7b4bf5SPeter Avalos 
195ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_CHASSIS_COMPONENT 1
196ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_INTERFACE_ALIAS 2
197ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_PORT_COMPONENT 3
198ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_MAC_ADDRESS 4
199ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_NETWORK_ADDRESS 5
200ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_INTERFACE_NAME 6
201ea7b4bf5SPeter Avalos #define CFM_CHASSIS_ID_LOCAL 7
202ea7b4bf5SPeter Avalos 
203ea7b4bf5SPeter Avalos static const struct tok cfm_tlv_senderid_chassisid_values[] = {
204ea7b4bf5SPeter Avalos     { 0, "Reserved"},
205ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_CHASSIS_COMPONENT, "Chassis component"},
206ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_INTERFACE_ALIAS, "Interface alias"},
207ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_PORT_COMPONENT, "Port component"},
208ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_MAC_ADDRESS, "MAC address"},
209ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_NETWORK_ADDRESS, "Network address"},
210ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_INTERFACE_NAME, "Interface name"},
211ea7b4bf5SPeter Avalos     { CFM_CHASSIS_ID_LOCAL, "Locally assigned"},
212ea7b4bf5SPeter Avalos     { 0, NULL}
213ea7b4bf5SPeter Avalos };
214ea7b4bf5SPeter Avalos 
215ea7b4bf5SPeter Avalos 
216411677aeSAaron LI static int
cfm_network_addr_print(netdissect_options * ndo,const u_char * tptr,const u_int length)217411677aeSAaron LI cfm_network_addr_print(netdissect_options *ndo,
218*ed775ee7SAntonio Huete Jimenez                        const u_char *tptr, const u_int length)
219411677aeSAaron LI {
220411677aeSAaron LI     u_int network_addr_type;
221ea7b4bf5SPeter Avalos     u_int hexdump =  FALSE;
222ea7b4bf5SPeter Avalos 
223ea7b4bf5SPeter Avalos     /*
224*ed775ee7SAntonio Huete Jimenez      * Although AFIs are typically 2 octets wide,
225ea7b4bf5SPeter Avalos      * 802.1ab specifies that this field width
226*ed775ee7SAntonio Huete Jimenez      * is only one octet.
227ea7b4bf5SPeter Avalos      */
228411677aeSAaron LI     if (length < 1) {
229*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  Network Address Type (invalid, no data");
230411677aeSAaron LI         return hexdump;
231411677aeSAaron LI     }
232411677aeSAaron LI     /* The calling function must make any due ND_TCHECK calls. */
233*ed775ee7SAntonio Huete Jimenez     network_addr_type = GET_U_1(tptr);
234*ed775ee7SAntonio Huete Jimenez     ND_PRINT("\n\t  Network Address Type %s (%u)",
235411677aeSAaron LI            tok2str(af_values, "Unknown", network_addr_type),
236*ed775ee7SAntonio Huete Jimenez            network_addr_type);
237ea7b4bf5SPeter Avalos 
238ea7b4bf5SPeter Avalos     /*
239ea7b4bf5SPeter Avalos      * Resolve the passed in Address.
240ea7b4bf5SPeter Avalos      */
241411677aeSAaron LI     switch(network_addr_type) {
242ea7b4bf5SPeter Avalos     case AFNUM_INET:
243411677aeSAaron LI         if (length != 1 + 4) {
244*ed775ee7SAntonio Huete Jimenez             ND_PRINT("(invalid IPv4 address length %u)", length - 1);
245411677aeSAaron LI             hexdump = TRUE;
246411677aeSAaron LI             break;
247411677aeSAaron LI         }
248*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", %s", GET_IPADDR_STRING(tptr + 1));
249ea7b4bf5SPeter Avalos         break;
250ea7b4bf5SPeter Avalos 
251ea7b4bf5SPeter Avalos     case AFNUM_INET6:
252411677aeSAaron LI         if (length != 1 + 16) {
253*ed775ee7SAntonio Huete Jimenez             ND_PRINT("(invalid IPv6 address length %u)", length - 1);
254411677aeSAaron LI             hexdump = TRUE;
255ea7b4bf5SPeter Avalos             break;
256411677aeSAaron LI         }
257*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", %s", GET_IP6ADDR_STRING(tptr + 1));
258411677aeSAaron LI         break;
259ea7b4bf5SPeter Avalos 
260ea7b4bf5SPeter Avalos     default:
261ea7b4bf5SPeter Avalos         hexdump = TRUE;
262ea7b4bf5SPeter Avalos         break;
263ea7b4bf5SPeter Avalos     }
264ea7b4bf5SPeter Avalos 
265ea7b4bf5SPeter Avalos     return hexdump;
266ea7b4bf5SPeter Avalos }
267ea7b4bf5SPeter Avalos 
268ea7b4bf5SPeter Avalos void
cfm_print(netdissect_options * ndo,const u_char * pptr,u_int length)269411677aeSAaron LI cfm_print(netdissect_options *ndo,
270*ed775ee7SAntonio Huete Jimenez           const u_char *pptr, u_int length)
271411677aeSAaron LI {
272ea7b4bf5SPeter Avalos     const struct cfm_common_header_t *cfm_common_header;
273*ed775ee7SAntonio Huete Jimenez     uint8_t mdlevel_version, opcode, flags, first_tlv_offset;
274ea7b4bf5SPeter Avalos     const struct cfm_tlv_header_t *cfm_tlv_header;
275411677aeSAaron LI     const uint8_t *tptr, *tlv_ptr;
276411677aeSAaron LI     const uint8_t *namesp;
277411677aeSAaron LI     u_int names_data_remaining;
278411677aeSAaron LI     uint8_t md_nameformat, md_namelength;
279411677aeSAaron LI     const uint8_t *md_name;
280411677aeSAaron LI     uint8_t ma_nameformat, ma_namelength;
281411677aeSAaron LI     const uint8_t *ma_name;
282ea7b4bf5SPeter Avalos     u_int hexdump, tlen, cfm_tlv_len, cfm_tlv_type, ccm_interval;
283ea7b4bf5SPeter Avalos 
284ea7b4bf5SPeter Avalos 
285ea7b4bf5SPeter Avalos     union {
286ea7b4bf5SPeter Avalos         const struct cfm_ccm_t *cfm_ccm;
287ea7b4bf5SPeter Avalos         const struct cfm_lbm_t *cfm_lbm;
288ea7b4bf5SPeter Avalos         const struct cfm_ltm_t *cfm_ltm;
289ea7b4bf5SPeter Avalos         const struct cfm_ltr_t *cfm_ltr;
290ea7b4bf5SPeter Avalos     } msg_ptr;
291ea7b4bf5SPeter Avalos 
292*ed775ee7SAntonio Huete Jimenez     ndo->ndo_protocol = "cfm";
293ea7b4bf5SPeter Avalos     tptr=pptr;
294ea7b4bf5SPeter Avalos     cfm_common_header = (const struct cfm_common_header_t *)pptr;
295411677aeSAaron LI     if (length < sizeof(*cfm_common_header))
296411677aeSAaron LI         goto tooshort;
297*ed775ee7SAntonio Huete Jimenez     ND_TCHECK_SIZE(cfm_common_header);
298ea7b4bf5SPeter Avalos 
299ea7b4bf5SPeter Avalos     /*
300ea7b4bf5SPeter Avalos      * Sanity checking of the header.
301ea7b4bf5SPeter Avalos      */
302*ed775ee7SAntonio Huete Jimenez     mdlevel_version = GET_U_1(cfm_common_header->mdlevel_version);
303*ed775ee7SAntonio Huete Jimenez     if (CFM_EXTRACT_VERSION(mdlevel_version) != CFM_VERSION) {
304*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("CFMv%u not supported, length %u",
305*ed775ee7SAntonio Huete Jimenez                CFM_EXTRACT_VERSION(mdlevel_version), length);
306ea7b4bf5SPeter Avalos 	return;
307ea7b4bf5SPeter Avalos     }
308ea7b4bf5SPeter Avalos 
309*ed775ee7SAntonio Huete Jimenez     opcode = GET_U_1(cfm_common_header->opcode);
310*ed775ee7SAntonio Huete Jimenez     ND_PRINT("CFMv%u %s, MD Level %u, length %u",
311*ed775ee7SAntonio Huete Jimenez            CFM_EXTRACT_VERSION(mdlevel_version),
312*ed775ee7SAntonio Huete Jimenez            tok2str(cfm_opcode_values, "unknown (%u)", opcode),
313*ed775ee7SAntonio Huete Jimenez            CFM_EXTRACT_MD_LEVEL(mdlevel_version),
314*ed775ee7SAntonio Huete Jimenez            length);
315ea7b4bf5SPeter Avalos 
316ea7b4bf5SPeter Avalos     /*
317ea7b4bf5SPeter Avalos      * In non-verbose mode just print the opcode and md-level.
318ea7b4bf5SPeter Avalos      */
319411677aeSAaron LI     if (ndo->ndo_vflag < 1) {
320ea7b4bf5SPeter Avalos         return;
321ea7b4bf5SPeter Avalos     }
322ea7b4bf5SPeter Avalos 
323*ed775ee7SAntonio Huete Jimenez     flags = GET_U_1(cfm_common_header->flags);
324*ed775ee7SAntonio Huete Jimenez     first_tlv_offset = GET_U_1(cfm_common_header->first_tlv_offset);
325*ed775ee7SAntonio Huete Jimenez     ND_PRINT("\n\tFirst TLV offset %u", first_tlv_offset);
326ea7b4bf5SPeter Avalos 
327*ed775ee7SAntonio Huete Jimenez     tptr += sizeof(struct cfm_common_header_t);
328ea7b4bf5SPeter Avalos     tlen = length - sizeof(struct cfm_common_header_t);
329ea7b4bf5SPeter Avalos 
330411677aeSAaron LI     /*
331411677aeSAaron LI      * Sanity check the first TLV offset.
332411677aeSAaron LI      */
333*ed775ee7SAntonio Huete Jimenez     if (first_tlv_offset > tlen) {
334*ed775ee7SAntonio Huete Jimenez         ND_PRINT(" (too large, must be <= %u)", tlen);
335411677aeSAaron LI         return;
336411677aeSAaron LI     }
337411677aeSAaron LI 
338*ed775ee7SAntonio Huete Jimenez     switch (opcode) {
339ea7b4bf5SPeter Avalos     case CFM_OPCODE_CCM:
340ea7b4bf5SPeter Avalos         msg_ptr.cfm_ccm = (const struct cfm_ccm_t *)tptr;
341*ed775ee7SAntonio Huete Jimenez         if (first_tlv_offset < sizeof(*msg_ptr.cfm_ccm)) {
342*ed775ee7SAntonio Huete Jimenez             ND_PRINT(" (too small 1, must be >= %zu)",
343*ed775ee7SAntonio Huete Jimenez                      sizeof(*msg_ptr.cfm_ccm));
344411677aeSAaron LI             return;
345411677aeSAaron LI         }
346411677aeSAaron LI         if (tlen < sizeof(*msg_ptr.cfm_ccm))
347411677aeSAaron LI             goto tooshort;
348*ed775ee7SAntonio Huete Jimenez         ND_TCHECK_SIZE(msg_ptr.cfm_ccm);
349ea7b4bf5SPeter Avalos 
350*ed775ee7SAntonio Huete Jimenez         ccm_interval = CFM_EXTRACT_CCM_INTERVAL(flags);
351*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", Flags [CCM Interval %u%s]",
352ea7b4bf5SPeter Avalos                ccm_interval,
353*ed775ee7SAntonio Huete Jimenez                flags & CFM_CCM_RDI_FLAG ?
354*ed775ee7SAntonio Huete Jimenez                ", RDI" : "");
355ea7b4bf5SPeter Avalos 
356ea7b4bf5SPeter Avalos         /*
357ea7b4bf5SPeter Avalos          * Resolve the CCM interval field.
358ea7b4bf5SPeter Avalos          */
359ea7b4bf5SPeter Avalos         if (ccm_interval) {
360*ed775ee7SAntonio Huete Jimenez             ND_PRINT("\n\t  CCM Interval %.3fs"
361ea7b4bf5SPeter Avalos                    ", min CCM Lifetime %.3fs, max CCM Lifetime %.3fs",
362ea7b4bf5SPeter Avalos                    ccm_interval_base[ccm_interval],
363ea7b4bf5SPeter Avalos                    ccm_interval_base[ccm_interval] * CCM_INTERVAL_MIN_MULTIPLIER,
364*ed775ee7SAntonio Huete Jimenez                    ccm_interval_base[ccm_interval] * CCM_INTERVAL_MAX_MULTIPLIER);
365ea7b4bf5SPeter Avalos         }
366ea7b4bf5SPeter Avalos 
367*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  Sequence Number 0x%08x, MA-End-Point-ID 0x%04x",
368*ed775ee7SAntonio Huete Jimenez                GET_BE_U_4(msg_ptr.cfm_ccm->sequence),
369*ed775ee7SAntonio Huete Jimenez                GET_BE_U_2(msg_ptr.cfm_ccm->ma_epi));
370ea7b4bf5SPeter Avalos 
371411677aeSAaron LI         namesp = msg_ptr.cfm_ccm->names;
372411677aeSAaron LI         names_data_remaining = sizeof(msg_ptr.cfm_ccm->names);
373ea7b4bf5SPeter Avalos 
374ea7b4bf5SPeter Avalos         /*
375ea7b4bf5SPeter Avalos          * Resolve the MD fields.
376ea7b4bf5SPeter Avalos          */
377*ed775ee7SAntonio Huete Jimenez         md_nameformat = GET_U_1(namesp);
378411677aeSAaron LI         namesp++;
379411677aeSAaron LI         names_data_remaining--;  /* We know this is != 0 */
380411677aeSAaron LI         if (md_nameformat != CFM_CCM_MD_FORMAT_NONE) {
381*ed775ee7SAntonio Huete Jimenez             md_namelength = GET_U_1(namesp);
382411677aeSAaron LI             namesp++;
383411677aeSAaron LI             names_data_remaining--; /* We know this is !=0 */
384*ed775ee7SAntonio Huete Jimenez             ND_PRINT("\n\t  MD Name Format %s (%u), MD Name length %u",
385ea7b4bf5SPeter Avalos                    tok2str(cfm_md_nameformat_values, "Unknown",
386411677aeSAaron LI                            md_nameformat),
387411677aeSAaron LI                    md_nameformat,
388*ed775ee7SAntonio Huete Jimenez                    md_namelength);
389ea7b4bf5SPeter Avalos 
390411677aeSAaron LI             /*
391411677aeSAaron LI              * -3 for the MA short name format and length and one byte
392411677aeSAaron LI              * of MA short name.
393411677aeSAaron LI              */
394411677aeSAaron LI             if (md_namelength > names_data_remaining - 3) {
395*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(" (too large, must be <= %u)", names_data_remaining - 2);
396411677aeSAaron LI                 return;
397411677aeSAaron LI             }
398411677aeSAaron LI 
399411677aeSAaron LI             md_name = namesp;
400*ed775ee7SAntonio Huete Jimenez             ND_PRINT("\n\t  MD Name: ");
401411677aeSAaron LI             switch (md_nameformat) {
402ea7b4bf5SPeter Avalos             case CFM_CCM_MD_FORMAT_DNS:
403ea7b4bf5SPeter Avalos             case CFM_CCM_MD_FORMAT_CHAR:
404*ed775ee7SAntonio Huete Jimenez                 nd_printjnp(ndo, md_name, md_namelength);
405ea7b4bf5SPeter Avalos                 break;
406ea7b4bf5SPeter Avalos 
407ea7b4bf5SPeter Avalos             case CFM_CCM_MD_FORMAT_MAC:
408*ed775ee7SAntonio Huete Jimenez                 if (md_namelength == MAC_ADDR_LEN) {
409*ed775ee7SAntonio Huete Jimenez                     ND_PRINT("\n\t  MAC %s", GET_ETHERADDR_STRING(md_name));
410411677aeSAaron LI                 } else {
411*ed775ee7SAntonio Huete Jimenez                     ND_PRINT("\n\t  MAC (length invalid)");
412411677aeSAaron LI                 }
413ea7b4bf5SPeter Avalos                 break;
414ea7b4bf5SPeter Avalos 
415ea7b4bf5SPeter Avalos                 /* FIXME add printers for those MD formats - hexdump for now */
416ea7b4bf5SPeter Avalos             case CFM_CCM_MA_FORMAT_8021:
417ea7b4bf5SPeter Avalos             default:
418411677aeSAaron LI                 print_unknown_data(ndo, md_name, "\n\t    ",
419411677aeSAaron LI                                    md_namelength);
420ea7b4bf5SPeter Avalos             }
421411677aeSAaron LI             namesp += md_namelength;
422411677aeSAaron LI             names_data_remaining -= md_namelength;
423411677aeSAaron LI         } else {
424*ed775ee7SAntonio Huete Jimenez             ND_PRINT("\n\t  MD Name Format %s (%u)",
425411677aeSAaron LI                    tok2str(cfm_md_nameformat_values, "Unknown",
426411677aeSAaron LI                            md_nameformat),
427*ed775ee7SAntonio Huete Jimenez                    md_nameformat);
428ea7b4bf5SPeter Avalos         }
429ea7b4bf5SPeter Avalos 
430ea7b4bf5SPeter Avalos 
431ea7b4bf5SPeter Avalos         /*
432ea7b4bf5SPeter Avalos          * Resolve the MA fields.
433ea7b4bf5SPeter Avalos          */
434*ed775ee7SAntonio Huete Jimenez         ma_nameformat = GET_U_1(namesp);
435411677aeSAaron LI         namesp++;
436411677aeSAaron LI         names_data_remaining--; /* We know this is != 0 */
437*ed775ee7SAntonio Huete Jimenez         ma_namelength = GET_U_1(namesp);
438411677aeSAaron LI         namesp++;
439411677aeSAaron LI         names_data_remaining--; /* We know this is != 0 */
440*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  MA Name-Format %s (%u), MA name length %u",
441ea7b4bf5SPeter Avalos                tok2str(cfm_ma_nameformat_values, "Unknown",
442411677aeSAaron LI                        ma_nameformat),
443411677aeSAaron LI                ma_nameformat,
444*ed775ee7SAntonio Huete Jimenez                ma_namelength);
445ea7b4bf5SPeter Avalos 
446411677aeSAaron LI         if (ma_namelength > names_data_remaining) {
447*ed775ee7SAntonio Huete Jimenez             ND_PRINT(" (too large, must be <= %u)", names_data_remaining);
448411677aeSAaron LI             return;
449411677aeSAaron LI         }
450411677aeSAaron LI 
451411677aeSAaron LI         ma_name = namesp;
452*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  MA Name: ");
453411677aeSAaron LI         switch (ma_nameformat) {
454ea7b4bf5SPeter Avalos         case CFM_CCM_MA_FORMAT_CHAR:
455*ed775ee7SAntonio Huete Jimenez             nd_printjnp(ndo, ma_name, ma_namelength);
456ea7b4bf5SPeter Avalos             break;
457ea7b4bf5SPeter Avalos 
458ea7b4bf5SPeter Avalos             /* FIXME add printers for those MA formats - hexdump for now */
459ea7b4bf5SPeter Avalos         case CFM_CCM_MA_FORMAT_8021:
460ea7b4bf5SPeter Avalos         case CFM_CCM_MA_FORMAT_VID:
461ea7b4bf5SPeter Avalos         case CFM_CCM_MA_FORMAT_INT:
462ea7b4bf5SPeter Avalos         case CFM_CCM_MA_FORMAT_VPN:
463ea7b4bf5SPeter Avalos         default:
464411677aeSAaron LI             print_unknown_data(ndo, ma_name, "\n\t    ", ma_namelength);
465ea7b4bf5SPeter Avalos         }
466ea7b4bf5SPeter Avalos         break;
467ea7b4bf5SPeter Avalos 
468ea7b4bf5SPeter Avalos     case CFM_OPCODE_LTM:
46927bfbee1SPeter Avalos         msg_ptr.cfm_ltm = (const struct cfm_ltm_t *)tptr;
470*ed775ee7SAntonio Huete Jimenez         if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltm)) {
471*ed775ee7SAntonio Huete Jimenez             ND_PRINT(" (too small 4, must be >= %zu)",
472*ed775ee7SAntonio Huete Jimenez                      sizeof(*msg_ptr.cfm_ltm));
473411677aeSAaron LI             return;
474411677aeSAaron LI         }
475411677aeSAaron LI         if (tlen < sizeof(*msg_ptr.cfm_ltm))
476411677aeSAaron LI             goto tooshort;
477*ed775ee7SAntonio Huete Jimenez         ND_TCHECK_SIZE(msg_ptr.cfm_ltm);
47827bfbee1SPeter Avalos 
479*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", Flags [%s]",
480*ed775ee7SAntonio Huete Jimenez                bittok2str(cfm_ltm_flag_values, "none", flags));
481ea7b4bf5SPeter Avalos 
482*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  Transaction-ID 0x%08x, ttl %u",
483*ed775ee7SAntonio Huete Jimenez                GET_BE_U_4(msg_ptr.cfm_ltm->transaction_id),
484*ed775ee7SAntonio Huete Jimenez                GET_U_1(msg_ptr.cfm_ltm->ttl));
485ea7b4bf5SPeter Avalos 
486*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  Original-MAC %s, Target-MAC %s",
487*ed775ee7SAntonio Huete Jimenez                GET_ETHERADDR_STRING(msg_ptr.cfm_ltm->original_mac),
488*ed775ee7SAntonio Huete Jimenez                GET_ETHERADDR_STRING(msg_ptr.cfm_ltm->target_mac));
489ea7b4bf5SPeter Avalos         break;
490ea7b4bf5SPeter Avalos 
491ea7b4bf5SPeter Avalos     case CFM_OPCODE_LTR:
49227bfbee1SPeter Avalos         msg_ptr.cfm_ltr = (const struct cfm_ltr_t *)tptr;
493*ed775ee7SAntonio Huete Jimenez         if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltr)) {
494*ed775ee7SAntonio Huete Jimenez             ND_PRINT(" (too small 5, must be >= %zu)",
495*ed775ee7SAntonio Huete Jimenez                      sizeof(*msg_ptr.cfm_ltr));
496411677aeSAaron LI             return;
497411677aeSAaron LI         }
498411677aeSAaron LI         if (tlen < sizeof(*msg_ptr.cfm_ltr))
499411677aeSAaron LI             goto tooshort;
500*ed775ee7SAntonio Huete Jimenez         ND_TCHECK_SIZE(msg_ptr.cfm_ltr);
50127bfbee1SPeter Avalos 
502*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", Flags [%s]",
503*ed775ee7SAntonio Huete Jimenez                bittok2str(cfm_ltr_flag_values, "none", flags));
504ea7b4bf5SPeter Avalos 
505*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  Transaction-ID 0x%08x, ttl %u",
506*ed775ee7SAntonio Huete Jimenez                GET_BE_U_4(msg_ptr.cfm_ltr->transaction_id),
507*ed775ee7SAntonio Huete Jimenez                GET_U_1(msg_ptr.cfm_ltr->ttl));
508ea7b4bf5SPeter Avalos 
509*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t  Replay-Action %s (%u)",
510ea7b4bf5SPeter Avalos                tok2str(cfm_ltr_replay_action_values,
511ea7b4bf5SPeter Avalos                        "Unknown",
512*ed775ee7SAntonio Huete Jimenez                        GET_U_1(msg_ptr.cfm_ltr->replay_action)),
513*ed775ee7SAntonio Huete Jimenez                GET_U_1(msg_ptr.cfm_ltr->replay_action));
514ea7b4bf5SPeter Avalos         break;
515ea7b4bf5SPeter Avalos 
516ea7b4bf5SPeter Avalos         /*
517ea7b4bf5SPeter Avalos          * No message decoder yet.
518ea7b4bf5SPeter Avalos          * Hexdump everything up until the start of the TLVs
519ea7b4bf5SPeter Avalos          */
520ea7b4bf5SPeter Avalos     case CFM_OPCODE_LBR:
521ea7b4bf5SPeter Avalos     case CFM_OPCODE_LBM:
522ea7b4bf5SPeter Avalos     default:
523411677aeSAaron LI         print_unknown_data(ndo, tptr, "\n\t  ",
524*ed775ee7SAntonio Huete Jimenez                            tlen -  first_tlv_offset);
525ea7b4bf5SPeter Avalos         break;
526ea7b4bf5SPeter Avalos     }
527ea7b4bf5SPeter Avalos 
528*ed775ee7SAntonio Huete Jimenez     tptr += first_tlv_offset;
529*ed775ee7SAntonio Huete Jimenez     tlen -= first_tlv_offset;
530ea7b4bf5SPeter Avalos 
531ea7b4bf5SPeter Avalos     while (tlen > 0) {
532ea7b4bf5SPeter Avalos         cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr;
533ea7b4bf5SPeter Avalos 
534ea7b4bf5SPeter Avalos         /* Enough to read the tlv type ? */
535*ed775ee7SAntonio Huete Jimenez         cfm_tlv_type = GET_U_1(cfm_tlv_header->type);
536ea7b4bf5SPeter Avalos 
537*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t%s TLV (0x%02x)",
538ea7b4bf5SPeter Avalos                tok2str(cfm_tlv_values, "Unknown", cfm_tlv_type),
539*ed775ee7SAntonio Huete Jimenez                cfm_tlv_type);
540ea7b4bf5SPeter Avalos 
541411677aeSAaron LI         if (cfm_tlv_type == CFM_TLV_END) {
542411677aeSAaron LI             /* Length is "Not present if the Type field is 0." */
543ea7b4bf5SPeter Avalos             return;
544ea7b4bf5SPeter Avalos         }
545ea7b4bf5SPeter Avalos 
546411677aeSAaron LI         /* do we have the full tlv header ? */
547411677aeSAaron LI         if (tlen < sizeof(struct cfm_tlv_header_t))
548411677aeSAaron LI             goto tooshort;
549*ed775ee7SAntonio Huete Jimenez         ND_TCHECK_LEN(tptr, sizeof(struct cfm_tlv_header_t));
550*ed775ee7SAntonio Huete Jimenez         cfm_tlv_len=GET_BE_U_2(cfm_tlv_header->length);
551411677aeSAaron LI 
552*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", length %u", cfm_tlv_len);
553411677aeSAaron LI 
554ea7b4bf5SPeter Avalos         tptr += sizeof(struct cfm_tlv_header_t);
555ea7b4bf5SPeter Avalos         tlen -= sizeof(struct cfm_tlv_header_t);
556ea7b4bf5SPeter Avalos         tlv_ptr = tptr;
557ea7b4bf5SPeter Avalos 
558411677aeSAaron LI         /* do we have the full tlv ? */
559411677aeSAaron LI         if (tlen < cfm_tlv_len)
560411677aeSAaron LI             goto tooshort;
561*ed775ee7SAntonio Huete Jimenez         ND_TCHECK_LEN(tptr, cfm_tlv_len);
562ea7b4bf5SPeter Avalos         hexdump = FALSE;
563ea7b4bf5SPeter Avalos 
564ea7b4bf5SPeter Avalos         switch(cfm_tlv_type) {
565ea7b4bf5SPeter Avalos         case CFM_TLV_PORT_STATUS:
566411677aeSAaron LI             if (cfm_tlv_len < 1) {
567*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(" (too short, must be >= 1)");
568411677aeSAaron LI                 return;
569411677aeSAaron LI             }
570*ed775ee7SAntonio Huete Jimenez             ND_PRINT(", Status: %s (%u)",
571*ed775ee7SAntonio Huete Jimenez                    tok2str(cfm_tlv_port_status_values, "Unknown", GET_U_1(tptr)),
572*ed775ee7SAntonio Huete Jimenez                    GET_U_1(tptr));
573ea7b4bf5SPeter Avalos             break;
574ea7b4bf5SPeter Avalos 
575ea7b4bf5SPeter Avalos         case CFM_TLV_INTERFACE_STATUS:
576411677aeSAaron LI             if (cfm_tlv_len < 1) {
577*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(" (too short, must be >= 1)");
578411677aeSAaron LI                 return;
579411677aeSAaron LI             }
580*ed775ee7SAntonio Huete Jimenez             ND_PRINT(", Status: %s (%u)",
581*ed775ee7SAntonio Huete Jimenez                    tok2str(cfm_tlv_interface_status_values, "Unknown", GET_U_1(tptr)),
582*ed775ee7SAntonio Huete Jimenez                    GET_U_1(tptr));
583ea7b4bf5SPeter Avalos             break;
584ea7b4bf5SPeter Avalos 
585ea7b4bf5SPeter Avalos         case CFM_TLV_PRIVATE:
586411677aeSAaron LI             if (cfm_tlv_len < 4) {
587*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(" (too short, must be >= 4)");
588411677aeSAaron LI                 return;
589411677aeSAaron LI             }
590*ed775ee7SAntonio Huete Jimenez             ND_PRINT(", Vendor: %s (%u), Sub-Type %u",
591*ed775ee7SAntonio Huete Jimenez                    tok2str(oui_values,"Unknown", GET_BE_U_3(tptr)),
592*ed775ee7SAntonio Huete Jimenez                    GET_BE_U_3(tptr),
593*ed775ee7SAntonio Huete Jimenez                    GET_U_1(tptr + 3));
594ea7b4bf5SPeter Avalos             hexdump = TRUE;
595ea7b4bf5SPeter Avalos             break;
596ea7b4bf5SPeter Avalos 
597ea7b4bf5SPeter Avalos         case CFM_TLV_SENDER_ID:
598ea7b4bf5SPeter Avalos         {
599ea7b4bf5SPeter Avalos             u_int chassis_id_type, chassis_id_length;
600ea7b4bf5SPeter Avalos             u_int mgmt_addr_length;
601ea7b4bf5SPeter Avalos 
602411677aeSAaron LI             if (cfm_tlv_len < 1) {
603*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(" (too short, must be >= 1)");
604411677aeSAaron LI                 goto next_tlv;
605ea7b4bf5SPeter Avalos             }
606ea7b4bf5SPeter Avalos 
607411677aeSAaron LI             /*
608411677aeSAaron LI              * Get the Chassis ID length and check it.
609411677aeSAaron LI              * IEEE 802.1Q-2014 Section 21.5.3.1
610411677aeSAaron LI              */
611*ed775ee7SAntonio Huete Jimenez             chassis_id_length = GET_U_1(tptr);
612ea7b4bf5SPeter Avalos             tptr++;
613ea7b4bf5SPeter Avalos             tlen--;
614411677aeSAaron LI             cfm_tlv_len--;
615ea7b4bf5SPeter Avalos 
616ea7b4bf5SPeter Avalos             if (chassis_id_length) {
617411677aeSAaron LI                 /*
618411677aeSAaron LI                  * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references
619411677aeSAaron LI                  * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently
620411677aeSAaron LI                  * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype
621411677aeSAaron LI                  */
622411677aeSAaron LI                 if (cfm_tlv_len < 1) {
623*ed775ee7SAntonio Huete Jimenez                     ND_PRINT("\n\t  (TLV too short)");
624411677aeSAaron LI                     goto next_tlv;
625411677aeSAaron LI                 }
626*ed775ee7SAntonio Huete Jimenez                 chassis_id_type = GET_U_1(tptr);
627411677aeSAaron LI                 cfm_tlv_len--;
628*ed775ee7SAntonio Huete Jimenez                 ND_PRINT("\n\t  Chassis-ID Type %s (%u), Chassis-ID length %u",
629ea7b4bf5SPeter Avalos                        tok2str(cfm_tlv_senderid_chassisid_values,
630ea7b4bf5SPeter Avalos                                "Unknown",
631ea7b4bf5SPeter Avalos                                chassis_id_type),
632ea7b4bf5SPeter Avalos                        chassis_id_type,
633*ed775ee7SAntonio Huete Jimenez                        chassis_id_length);
634ea7b4bf5SPeter Avalos 
635411677aeSAaron LI                 if (cfm_tlv_len < chassis_id_length) {
636*ed775ee7SAntonio Huete Jimenez                     ND_PRINT("\n\t  (TLV too short)");
637411677aeSAaron LI                     goto next_tlv;
638411677aeSAaron LI                 }
639411677aeSAaron LI 
640411677aeSAaron LI                 /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */
641ea7b4bf5SPeter Avalos                 switch (chassis_id_type) {
642ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_MAC_ADDRESS:
643*ed775ee7SAntonio Huete Jimenez                     if (chassis_id_length != MAC_ADDR_LEN) {
644*ed775ee7SAntonio Huete Jimenez                         ND_PRINT(" (invalid MAC address length)");
645411677aeSAaron LI                         hexdump = TRUE;
646411677aeSAaron LI                         break;
647411677aeSAaron LI                     }
648*ed775ee7SAntonio Huete Jimenez                     ND_PRINT("\n\t  MAC %s", GET_ETHERADDR_STRING(tptr + 1));
649ea7b4bf5SPeter Avalos                     break;
650ea7b4bf5SPeter Avalos 
651ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_NETWORK_ADDRESS:
652411677aeSAaron LI                     hexdump |= cfm_network_addr_print(ndo, tptr + 1, chassis_id_length);
653ea7b4bf5SPeter Avalos                     break;
654ea7b4bf5SPeter Avalos 
655ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_INTERFACE_NAME: /* fall through */
656ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_INTERFACE_ALIAS:
657ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_LOCAL:
658ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_CHASSIS_COMPONENT:
659ea7b4bf5SPeter Avalos                 case CFM_CHASSIS_ID_PORT_COMPONENT:
660*ed775ee7SAntonio Huete Jimenez                     nd_printjnp(ndo, tptr + 1, chassis_id_length);
661ea7b4bf5SPeter Avalos                     break;
662ea7b4bf5SPeter Avalos 
663ea7b4bf5SPeter Avalos                 default:
664ea7b4bf5SPeter Avalos                     hexdump = TRUE;
665ea7b4bf5SPeter Avalos                     break;
666ea7b4bf5SPeter Avalos                 }
667411677aeSAaron LI                 cfm_tlv_len -= chassis_id_length;
668ea7b4bf5SPeter Avalos 
669411677aeSAaron LI                 tptr += 1 + chassis_id_length;
670411677aeSAaron LI                 tlen -= 1 + chassis_id_length;
671411677aeSAaron LI             }
672ea7b4bf5SPeter Avalos 
673ea7b4bf5SPeter Avalos             /*
674ea7b4bf5SPeter Avalos              * Check if there is a Management Address.
675411677aeSAaron LI              * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length
676411677aeSAaron LI              * This and all subsequent fields are not present if the TLV length
677411677aeSAaron LI              * allows only the above fields.
678ea7b4bf5SPeter Avalos              */
679411677aeSAaron LI             if (cfm_tlv_len == 0) {
680411677aeSAaron LI                 /* No, there isn't; we're done. */
681411677aeSAaron LI                 break;
682411677aeSAaron LI             }
683411677aeSAaron LI 
684411677aeSAaron LI             /* Here mgmt_addr_length stands for the management domain length. */
685*ed775ee7SAntonio Huete Jimenez             mgmt_addr_length = GET_U_1(tptr);
686411677aeSAaron LI             tptr++;
687411677aeSAaron LI             tlen--;
688411677aeSAaron LI             cfm_tlv_len--;
689*ed775ee7SAntonio Huete Jimenez             ND_PRINT("\n\t  Management Address Domain Length %u", mgmt_addr_length);
690411677aeSAaron LI             if (mgmt_addr_length) {
691411677aeSAaron LI                 /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */
692411677aeSAaron LI                 if (cfm_tlv_len < mgmt_addr_length) {
693*ed775ee7SAntonio Huete Jimenez                     ND_PRINT("\n\t  (TLV too short)");
694411677aeSAaron LI                     goto next_tlv;
695411677aeSAaron LI                 }
696411677aeSAaron LI                 cfm_tlv_len -= mgmt_addr_length;
697411677aeSAaron LI                 /*
698411677aeSAaron LI                  * XXX - this is an OID; print it as such.
699411677aeSAaron LI                  */
700411677aeSAaron LI                 hex_print(ndo, "\n\t  Management Address Domain: ", tptr, mgmt_addr_length);
701411677aeSAaron LI                 tptr += mgmt_addr_length;
702411677aeSAaron LI                 tlen -= mgmt_addr_length;
703411677aeSAaron LI 
704411677aeSAaron LI                 /*
705411677aeSAaron LI                  * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length
706411677aeSAaron LI                  * This field is present if Management Address Domain Length is not 0.
707411677aeSAaron LI                  */
708411677aeSAaron LI                 if (cfm_tlv_len < 1) {
709*ed775ee7SAntonio Huete Jimenez                     ND_PRINT(" (Management Address Length is missing)");
710ea7b4bf5SPeter Avalos                     hexdump = TRUE;
711ea7b4bf5SPeter Avalos                     break;
712ea7b4bf5SPeter Avalos                 }
713ea7b4bf5SPeter Avalos 
714411677aeSAaron LI                 /* Here mgmt_addr_length stands for the management address length. */
715*ed775ee7SAntonio Huete Jimenez                 mgmt_addr_length = GET_U_1(tptr);
716ea7b4bf5SPeter Avalos                 tptr++;
717ea7b4bf5SPeter Avalos                 tlen--;
718411677aeSAaron LI                 cfm_tlv_len--;
719*ed775ee7SAntonio Huete Jimenez                 ND_PRINT("\n\t  Management Address Length %u", mgmt_addr_length);
720ea7b4bf5SPeter Avalos                 if (mgmt_addr_length) {
721411677aeSAaron LI                     /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */
722411677aeSAaron LI                     if (cfm_tlv_len < mgmt_addr_length) {
723*ed775ee7SAntonio Huete Jimenez                         ND_PRINT("\n\t  (TLV too short)");
724411677aeSAaron LI                         return;
725ea7b4bf5SPeter Avalos                     }
726411677aeSAaron LI                     cfm_tlv_len -= mgmt_addr_length;
727411677aeSAaron LI                     /*
728411677aeSAaron LI                      * XXX - this is a TransportDomain; print it as such.
729411677aeSAaron LI                      */
730411677aeSAaron LI                     hex_print(ndo, "\n\t  Management Address: ", tptr, mgmt_addr_length);
731ea7b4bf5SPeter Avalos                     tptr += mgmt_addr_length;
732ea7b4bf5SPeter Avalos                     tlen -= mgmt_addr_length;
733411677aeSAaron LI                 }
734ea7b4bf5SPeter Avalos             }
735ea7b4bf5SPeter Avalos             break;
736411677aeSAaron LI         }
737ea7b4bf5SPeter Avalos 
738ea7b4bf5SPeter Avalos             /*
739ea7b4bf5SPeter Avalos              * FIXME those are the defined TLVs that lack a decoder
740ea7b4bf5SPeter Avalos              * you are welcome to contribute code ;-)
741ea7b4bf5SPeter Avalos              */
742ea7b4bf5SPeter Avalos 
743ea7b4bf5SPeter Avalos         case CFM_TLV_DATA:
744ea7b4bf5SPeter Avalos         case CFM_TLV_REPLY_INGRESS:
745ea7b4bf5SPeter Avalos         case CFM_TLV_REPLY_EGRESS:
746ea7b4bf5SPeter Avalos         default:
747ea7b4bf5SPeter Avalos             hexdump = TRUE;
748ea7b4bf5SPeter Avalos             break;
749ea7b4bf5SPeter Avalos         }
750ea7b4bf5SPeter Avalos         /* do we want to see an additional hexdump ? */
751411677aeSAaron LI         if (hexdump || ndo->ndo_vflag > 1)
752411677aeSAaron LI             print_unknown_data(ndo, tlv_ptr, "\n\t  ", cfm_tlv_len);
753ea7b4bf5SPeter Avalos 
754411677aeSAaron LI next_tlv:
755ea7b4bf5SPeter Avalos         tptr+=cfm_tlv_len;
756ea7b4bf5SPeter Avalos         tlen-=cfm_tlv_len;
757ea7b4bf5SPeter Avalos     }
758ea7b4bf5SPeter Avalos     return;
759411677aeSAaron LI 
760411677aeSAaron LI tooshort:
761*ed775ee7SAntonio Huete Jimenez     ND_PRINT("\n\t\t packet is too short");
762411677aeSAaron LI     return;
763411677aeSAaron LI 
764ea7b4bf5SPeter Avalos trunc:
765*ed775ee7SAntonio Huete Jimenez     nd_print_trunc(ndo);
766ea7b4bf5SPeter Avalos }
767