xref: /aosp_15_r20/external/tcpdump/print-cfm.c (revision 05b00f6010a2396e3db2409989fc67270046269f)
1*05b00f60SXin Li /*
2*05b00f60SXin Li  * Copyright (c) 1998-2006 The TCPDUMP project
3*05b00f60SXin Li  *
4*05b00f60SXin Li  * Redistribution and use in source and binary forms, with or without
5*05b00f60SXin Li  * modification, are permitted provided that: (1) source code
6*05b00f60SXin Li  * distributions retain the above copyright notice and this paragraph
7*05b00f60SXin Li  * in its entirety, and (2) distributions including binary code include
8*05b00f60SXin Li  * the above copyright notice and this paragraph in its entirety in
9*05b00f60SXin Li  * the documentation or other materials provided with the distribution.
10*05b00f60SXin Li  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11*05b00f60SXin Li  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12*05b00f60SXin Li  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13*05b00f60SXin Li  * FOR A PARTICULAR PURPOSE.
14*05b00f60SXin Li  *
15*05b00f60SXin Li  * Original code by Hannes Gredler ([email protected])
16*05b00f60SXin Li  */
17*05b00f60SXin Li 
18*05b00f60SXin Li /* \summary: IEEE 802.1ag Connectivity Fault Management (CFM) protocols printer */
19*05b00f60SXin Li 
20*05b00f60SXin Li #ifdef HAVE_CONFIG_H
21*05b00f60SXin Li #include <config.h>
22*05b00f60SXin Li #endif
23*05b00f60SXin Li 
24*05b00f60SXin Li #include "netdissect-stdinc.h"
25*05b00f60SXin Li 
26*05b00f60SXin Li #include "netdissect.h"
27*05b00f60SXin Li #include "extract.h"
28*05b00f60SXin Li #include "addrtoname.h"
29*05b00f60SXin Li #include "oui.h"
30*05b00f60SXin Li #include "af.h"
31*05b00f60SXin Li 
32*05b00f60SXin Li 
33*05b00f60SXin Li struct cfm_common_header_t {
34*05b00f60SXin Li     nd_uint8_t mdlevel_version;
35*05b00f60SXin Li     nd_uint8_t opcode;
36*05b00f60SXin Li     nd_uint8_t flags;
37*05b00f60SXin Li     nd_uint8_t first_tlv_offset;
38*05b00f60SXin Li };
39*05b00f60SXin Li 
40*05b00f60SXin Li #define	CFM_VERSION 0
41*05b00f60SXin Li #define CFM_EXTRACT_VERSION(x) ((x)&0x1f)
42*05b00f60SXin Li #define CFM_EXTRACT_MD_LEVEL(x) (((x)&0xe0)>>5)
43*05b00f60SXin Li 
44*05b00f60SXin Li #define	CFM_OPCODE_CCM 1
45*05b00f60SXin Li #define	CFM_OPCODE_LBR 2
46*05b00f60SXin Li #define	CFM_OPCODE_LBM 3
47*05b00f60SXin Li #define	CFM_OPCODE_LTR 4
48*05b00f60SXin Li #define	CFM_OPCODE_LTM 5
49*05b00f60SXin Li 
50*05b00f60SXin Li static const struct tok cfm_opcode_values[] = {
51*05b00f60SXin Li     { CFM_OPCODE_CCM, "Continuity Check Message"},
52*05b00f60SXin Li     { CFM_OPCODE_LBR, "Loopback Reply"},
53*05b00f60SXin Li     { CFM_OPCODE_LBM, "Loopback Message"},
54*05b00f60SXin Li     { CFM_OPCODE_LTR, "Linktrace Reply"},
55*05b00f60SXin Li     { CFM_OPCODE_LTM, "Linktrace Message"},
56*05b00f60SXin Li     { 0, NULL}
57*05b00f60SXin Li };
58*05b00f60SXin Li 
59*05b00f60SXin Li /*
60*05b00f60SXin Li  * Message Formats.
61*05b00f60SXin Li  */
62*05b00f60SXin Li struct cfm_ccm_t {
63*05b00f60SXin Li     nd_uint32_t sequence;
64*05b00f60SXin Li     nd_uint16_t ma_epi;
65*05b00f60SXin Li     nd_byte     names[48];
66*05b00f60SXin Li     nd_byte     itu_t_y_1731[16];
67*05b00f60SXin Li };
68*05b00f60SXin Li 
69*05b00f60SXin Li /*
70*05b00f60SXin Li  * Timer Bases for the CCM Interval field.
71*05b00f60SXin Li  * Expressed in units of seconds.
72*05b00f60SXin Li  */
73*05b00f60SXin Li static const float ccm_interval_base[8] = {0.0f, 0.003333f, 0.01f, 0.1f, 1.0f, 10.0f, 60.0f, 600.0f};
74*05b00f60SXin Li #define CCM_INTERVAL_MIN_MULTIPLIER 3.25
75*05b00f60SXin Li #define CCM_INTERVAL_MAX_MULTIPLIER 3.5
76*05b00f60SXin Li 
77*05b00f60SXin Li #define CFM_CCM_RDI_FLAG 0x80
78*05b00f60SXin Li #define CFM_EXTRACT_CCM_INTERVAL(x) ((x)&0x07)
79*05b00f60SXin Li 
80*05b00f60SXin Li #define CFM_CCM_MD_FORMAT_8021 0
81*05b00f60SXin Li #define CFM_CCM_MD_FORMAT_NONE 1
82*05b00f60SXin Li #define CFM_CCM_MD_FORMAT_DNS  2
83*05b00f60SXin Li #define CFM_CCM_MD_FORMAT_MAC  3
84*05b00f60SXin Li #define CFM_CCM_MD_FORMAT_CHAR 4
85*05b00f60SXin Li 
86*05b00f60SXin Li static const struct tok cfm_md_nameformat_values[] = {
87*05b00f60SXin Li     { CFM_CCM_MD_FORMAT_8021, "IEEE 802.1"},
88*05b00f60SXin Li     { CFM_CCM_MD_FORMAT_NONE, "No MD Name present"},
89*05b00f60SXin Li     { CFM_CCM_MD_FORMAT_DNS, "DNS string"},
90*05b00f60SXin Li     { CFM_CCM_MD_FORMAT_MAC, "MAC + 16Bit Integer"},
91*05b00f60SXin Li     { CFM_CCM_MD_FORMAT_CHAR, "Character string"},
92*05b00f60SXin Li     { 0, NULL}
93*05b00f60SXin Li };
94*05b00f60SXin Li 
95*05b00f60SXin Li #define CFM_CCM_MA_FORMAT_8021 0
96*05b00f60SXin Li #define CFM_CCM_MA_FORMAT_VID  1
97*05b00f60SXin Li #define CFM_CCM_MA_FORMAT_CHAR 2
98*05b00f60SXin Li #define CFM_CCM_MA_FORMAT_INT  3
99*05b00f60SXin Li #define CFM_CCM_MA_FORMAT_VPN  4
100*05b00f60SXin Li 
101*05b00f60SXin Li static const struct tok cfm_ma_nameformat_values[] = {
102*05b00f60SXin Li     { CFM_CCM_MA_FORMAT_8021, "IEEE 802.1"},
103*05b00f60SXin Li     { CFM_CCM_MA_FORMAT_VID, "Primary VID"},
104*05b00f60SXin Li     { CFM_CCM_MA_FORMAT_CHAR, "Character string"},
105*05b00f60SXin Li     { CFM_CCM_MA_FORMAT_INT, "16Bit Integer"},
106*05b00f60SXin Li     { CFM_CCM_MA_FORMAT_VPN, "RFC2685 VPN-ID"},
107*05b00f60SXin Li     { 0, NULL}
108*05b00f60SXin Li };
109*05b00f60SXin Li 
110*05b00f60SXin Li struct cfm_lbm_t {
111*05b00f60SXin Li     nd_uint32_t transaction_id;
112*05b00f60SXin Li };
113*05b00f60SXin Li 
114*05b00f60SXin Li struct cfm_ltm_t {
115*05b00f60SXin Li     nd_uint32_t transaction_id;
116*05b00f60SXin Li     nd_uint8_t  ttl;
117*05b00f60SXin Li     nd_mac_addr original_mac;
118*05b00f60SXin Li     nd_mac_addr target_mac;
119*05b00f60SXin Li };
120*05b00f60SXin Li 
121*05b00f60SXin Li static const struct tok cfm_ltm_flag_values[] = {
122*05b00f60SXin Li     { 0x80, "Use Forwarding-DB only"},
123*05b00f60SXin Li     { 0, NULL}
124*05b00f60SXin Li };
125*05b00f60SXin Li 
126*05b00f60SXin Li struct cfm_ltr_t {
127*05b00f60SXin Li     nd_uint32_t transaction_id;
128*05b00f60SXin Li     nd_uint8_t  ttl;
129*05b00f60SXin Li     nd_uint8_t  replay_action;
130*05b00f60SXin Li };
131*05b00f60SXin Li 
132*05b00f60SXin Li static const struct tok cfm_ltr_flag_values[] = {
133*05b00f60SXin Li     { 0x80, "UseFDB Only"},
134*05b00f60SXin Li     { 0x40, "FwdYes"},
135*05b00f60SXin Li     { 0x20, "Terminal MEP"},
136*05b00f60SXin Li     { 0, NULL}
137*05b00f60SXin Li };
138*05b00f60SXin Li 
139*05b00f60SXin Li static const struct tok cfm_ltr_replay_action_values[] = {
140*05b00f60SXin Li     { 1, "Exact Match"},
141*05b00f60SXin Li     { 2, "Filtering DB"},
142*05b00f60SXin Li     { 3, "MIP CCM DB"},
143*05b00f60SXin Li     { 0, NULL}
144*05b00f60SXin Li };
145*05b00f60SXin Li 
146*05b00f60SXin Li 
147*05b00f60SXin Li #define CFM_TLV_END 0
148*05b00f60SXin Li #define CFM_TLV_SENDER_ID 1
149*05b00f60SXin Li #define CFM_TLV_PORT_STATUS 2
150*05b00f60SXin Li #define CFM_TLV_INTERFACE_STATUS 3
151*05b00f60SXin Li #define CFM_TLV_DATA 4
152*05b00f60SXin Li #define CFM_TLV_REPLY_INGRESS 5
153*05b00f60SXin Li #define CFM_TLV_REPLY_EGRESS 6
154*05b00f60SXin Li #define CFM_TLV_PRIVATE 31
155*05b00f60SXin Li 
156*05b00f60SXin Li static const struct tok cfm_tlv_values[] = {
157*05b00f60SXin Li     { CFM_TLV_END, "End"},
158*05b00f60SXin Li     { CFM_TLV_SENDER_ID, "Sender ID"},
159*05b00f60SXin Li     { CFM_TLV_PORT_STATUS, "Port status"},
160*05b00f60SXin Li     { CFM_TLV_INTERFACE_STATUS, "Interface status"},
161*05b00f60SXin Li     { CFM_TLV_DATA, "Data"},
162*05b00f60SXin Li     { CFM_TLV_REPLY_INGRESS, "Reply Ingress"},
163*05b00f60SXin Li     { CFM_TLV_REPLY_EGRESS, "Reply Egress"},
164*05b00f60SXin Li     { CFM_TLV_PRIVATE, "Organization Specific"},
165*05b00f60SXin Li     { 0, NULL}
166*05b00f60SXin Li };
167*05b00f60SXin Li 
168*05b00f60SXin Li /*
169*05b00f60SXin Li  * TLVs
170*05b00f60SXin Li  */
171*05b00f60SXin Li 
172*05b00f60SXin Li struct cfm_tlv_header_t {
173*05b00f60SXin Li     nd_uint8_t  type;
174*05b00f60SXin Li     nd_uint16_t length;
175*05b00f60SXin Li };
176*05b00f60SXin Li 
177*05b00f60SXin Li /* FIXME define TLV formats */
178*05b00f60SXin Li 
179*05b00f60SXin Li static const struct tok cfm_tlv_port_status_values[] = {
180*05b00f60SXin Li     { 1, "Blocked"},
181*05b00f60SXin Li     { 2, "Up"},
182*05b00f60SXin Li     { 0, NULL}
183*05b00f60SXin Li };
184*05b00f60SXin Li 
185*05b00f60SXin Li static const struct tok cfm_tlv_interface_status_values[] = {
186*05b00f60SXin Li     { 1, "Up"},
187*05b00f60SXin Li     { 2, "Down"},
188*05b00f60SXin Li     { 3, "Testing"},
189*05b00f60SXin Li     { 5, "Dormant"},
190*05b00f60SXin Li     { 6, "not present"},
191*05b00f60SXin Li     { 7, "lower Layer down"},
192*05b00f60SXin Li     { 0, NULL}
193*05b00f60SXin Li };
194*05b00f60SXin Li 
195*05b00f60SXin Li #define CFM_CHASSIS_ID_CHASSIS_COMPONENT 1
196*05b00f60SXin Li #define CFM_CHASSIS_ID_INTERFACE_ALIAS 2
197*05b00f60SXin Li #define CFM_CHASSIS_ID_PORT_COMPONENT 3
198*05b00f60SXin Li #define CFM_CHASSIS_ID_MAC_ADDRESS 4
199*05b00f60SXin Li #define CFM_CHASSIS_ID_NETWORK_ADDRESS 5
200*05b00f60SXin Li #define CFM_CHASSIS_ID_INTERFACE_NAME 6
201*05b00f60SXin Li #define CFM_CHASSIS_ID_LOCAL 7
202*05b00f60SXin Li 
203*05b00f60SXin Li static const struct tok cfm_tlv_senderid_chassisid_values[] = {
204*05b00f60SXin Li     { 0, "Reserved"},
205*05b00f60SXin Li     { CFM_CHASSIS_ID_CHASSIS_COMPONENT, "Chassis component"},
206*05b00f60SXin Li     { CFM_CHASSIS_ID_INTERFACE_ALIAS, "Interface alias"},
207*05b00f60SXin Li     { CFM_CHASSIS_ID_PORT_COMPONENT, "Port component"},
208*05b00f60SXin Li     { CFM_CHASSIS_ID_MAC_ADDRESS, "MAC address"},
209*05b00f60SXin Li     { CFM_CHASSIS_ID_NETWORK_ADDRESS, "Network address"},
210*05b00f60SXin Li     { CFM_CHASSIS_ID_INTERFACE_NAME, "Interface name"},
211*05b00f60SXin Li     { CFM_CHASSIS_ID_LOCAL, "Locally assigned"},
212*05b00f60SXin Li     { 0, NULL}
213*05b00f60SXin Li };
214*05b00f60SXin Li 
215*05b00f60SXin Li 
216*05b00f60SXin Li static int
cfm_network_addr_print(netdissect_options * ndo,const u_char * tptr,const u_int length)217*05b00f60SXin Li cfm_network_addr_print(netdissect_options *ndo,
218*05b00f60SXin Li                        const u_char *tptr, const u_int length)
219*05b00f60SXin Li {
220*05b00f60SXin Li     u_int network_addr_type;
221*05b00f60SXin Li     u_int hexdump =  FALSE;
222*05b00f60SXin Li 
223*05b00f60SXin Li     /*
224*05b00f60SXin Li      * Although AFIs are typically 2 octets wide,
225*05b00f60SXin Li      * 802.1ab specifies that this field width
226*05b00f60SXin Li      * is only one octet.
227*05b00f60SXin Li      */
228*05b00f60SXin Li     if (length < 1) {
229*05b00f60SXin Li         ND_PRINT("\n\t  Network Address Type (invalid, no data");
230*05b00f60SXin Li         return hexdump;
231*05b00f60SXin Li     }
232*05b00f60SXin Li     /* The calling function must make any due ND_TCHECK calls. */
233*05b00f60SXin Li     network_addr_type = GET_U_1(tptr);
234*05b00f60SXin Li     ND_PRINT("\n\t  Network Address Type %s (%u)",
235*05b00f60SXin Li            tok2str(af_values, "Unknown", network_addr_type),
236*05b00f60SXin Li            network_addr_type);
237*05b00f60SXin Li 
238*05b00f60SXin Li     /*
239*05b00f60SXin Li      * Resolve the passed in Address.
240*05b00f60SXin Li      */
241*05b00f60SXin Li     switch(network_addr_type) {
242*05b00f60SXin Li     case AFNUM_INET:
243*05b00f60SXin Li         if (length != 1 + 4) {
244*05b00f60SXin Li             ND_PRINT("(invalid IPv4 address length %u)", length - 1);
245*05b00f60SXin Li             hexdump = TRUE;
246*05b00f60SXin Li             break;
247*05b00f60SXin Li         }
248*05b00f60SXin Li         ND_PRINT(", %s", GET_IPADDR_STRING(tptr + 1));
249*05b00f60SXin Li         break;
250*05b00f60SXin Li 
251*05b00f60SXin Li     case AFNUM_INET6:
252*05b00f60SXin Li         if (length != 1 + 16) {
253*05b00f60SXin Li             ND_PRINT("(invalid IPv6 address length %u)", length - 1);
254*05b00f60SXin Li             hexdump = TRUE;
255*05b00f60SXin Li             break;
256*05b00f60SXin Li         }
257*05b00f60SXin Li         ND_PRINT(", %s", GET_IP6ADDR_STRING(tptr + 1));
258*05b00f60SXin Li         break;
259*05b00f60SXin Li 
260*05b00f60SXin Li     default:
261*05b00f60SXin Li         hexdump = TRUE;
262*05b00f60SXin Li         break;
263*05b00f60SXin Li     }
264*05b00f60SXin Li 
265*05b00f60SXin Li     return hexdump;
266*05b00f60SXin Li }
267*05b00f60SXin Li 
268*05b00f60SXin Li void
cfm_print(netdissect_options * ndo,const u_char * pptr,u_int length)269*05b00f60SXin Li cfm_print(netdissect_options *ndo,
270*05b00f60SXin Li           const u_char *pptr, u_int length)
271*05b00f60SXin Li {
272*05b00f60SXin Li     const struct cfm_common_header_t *cfm_common_header;
273*05b00f60SXin Li     uint8_t mdlevel_version, opcode, flags, first_tlv_offset;
274*05b00f60SXin Li     const struct cfm_tlv_header_t *cfm_tlv_header;
275*05b00f60SXin Li     const uint8_t *tptr, *tlv_ptr;
276*05b00f60SXin Li     const uint8_t *namesp;
277*05b00f60SXin Li     u_int names_data_remaining;
278*05b00f60SXin Li     uint8_t md_nameformat, md_namelength;
279*05b00f60SXin Li     const uint8_t *md_name;
280*05b00f60SXin Li     uint8_t ma_nameformat, ma_namelength;
281*05b00f60SXin Li     const uint8_t *ma_name;
282*05b00f60SXin Li     u_int hexdump, tlen, cfm_tlv_len, cfm_tlv_type, ccm_interval;
283*05b00f60SXin Li 
284*05b00f60SXin Li 
285*05b00f60SXin Li     union {
286*05b00f60SXin Li         const struct cfm_ccm_t *cfm_ccm;
287*05b00f60SXin Li         const struct cfm_lbm_t *cfm_lbm;
288*05b00f60SXin Li         const struct cfm_ltm_t *cfm_ltm;
289*05b00f60SXin Li         const struct cfm_ltr_t *cfm_ltr;
290*05b00f60SXin Li     } msg_ptr;
291*05b00f60SXin Li 
292*05b00f60SXin Li     ndo->ndo_protocol = "cfm";
293*05b00f60SXin Li     tptr=pptr;
294*05b00f60SXin Li     cfm_common_header = (const struct cfm_common_header_t *)pptr;
295*05b00f60SXin Li     if (length < sizeof(*cfm_common_header))
296*05b00f60SXin Li         goto tooshort;
297*05b00f60SXin Li     ND_TCHECK_SIZE(cfm_common_header);
298*05b00f60SXin Li 
299*05b00f60SXin Li     /*
300*05b00f60SXin Li      * Sanity checking of the header.
301*05b00f60SXin Li      */
302*05b00f60SXin Li     mdlevel_version = GET_U_1(cfm_common_header->mdlevel_version);
303*05b00f60SXin Li     if (CFM_EXTRACT_VERSION(mdlevel_version) != CFM_VERSION) {
304*05b00f60SXin Li 	ND_PRINT("CFMv%u not supported, length %u",
305*05b00f60SXin Li                CFM_EXTRACT_VERSION(mdlevel_version), length);
306*05b00f60SXin Li 	return;
307*05b00f60SXin Li     }
308*05b00f60SXin Li 
309*05b00f60SXin Li     opcode = GET_U_1(cfm_common_header->opcode);
310*05b00f60SXin Li     ND_PRINT("CFMv%u %s, MD Level %u, length %u",
311*05b00f60SXin Li            CFM_EXTRACT_VERSION(mdlevel_version),
312*05b00f60SXin Li            tok2str(cfm_opcode_values, "unknown (%u)", opcode),
313*05b00f60SXin Li            CFM_EXTRACT_MD_LEVEL(mdlevel_version),
314*05b00f60SXin Li            length);
315*05b00f60SXin Li 
316*05b00f60SXin Li     /*
317*05b00f60SXin Li      * In non-verbose mode just print the opcode and md-level.
318*05b00f60SXin Li      */
319*05b00f60SXin Li     if (ndo->ndo_vflag < 1) {
320*05b00f60SXin Li         return;
321*05b00f60SXin Li     }
322*05b00f60SXin Li 
323*05b00f60SXin Li     flags = GET_U_1(cfm_common_header->flags);
324*05b00f60SXin Li     first_tlv_offset = GET_U_1(cfm_common_header->first_tlv_offset);
325*05b00f60SXin Li     ND_PRINT("\n\tFirst TLV offset %u", first_tlv_offset);
326*05b00f60SXin Li 
327*05b00f60SXin Li     tptr += sizeof(struct cfm_common_header_t);
328*05b00f60SXin Li     tlen = length - sizeof(struct cfm_common_header_t);
329*05b00f60SXin Li 
330*05b00f60SXin Li     /*
331*05b00f60SXin Li      * Sanity check the first TLV offset.
332*05b00f60SXin Li      */
333*05b00f60SXin Li     if (first_tlv_offset > tlen) {
334*05b00f60SXin Li         ND_PRINT(" (too large, must be <= %u)", tlen);
335*05b00f60SXin Li         return;
336*05b00f60SXin Li     }
337*05b00f60SXin Li 
338*05b00f60SXin Li     switch (opcode) {
339*05b00f60SXin Li     case CFM_OPCODE_CCM:
340*05b00f60SXin Li         msg_ptr.cfm_ccm = (const struct cfm_ccm_t *)tptr;
341*05b00f60SXin Li         if (first_tlv_offset < sizeof(*msg_ptr.cfm_ccm)) {
342*05b00f60SXin Li             ND_PRINT(" (too small 1, must be >= %zu)",
343*05b00f60SXin Li                      sizeof(*msg_ptr.cfm_ccm));
344*05b00f60SXin Li             return;
345*05b00f60SXin Li         }
346*05b00f60SXin Li         if (tlen < sizeof(*msg_ptr.cfm_ccm))
347*05b00f60SXin Li             goto tooshort;
348*05b00f60SXin Li         ND_TCHECK_SIZE(msg_ptr.cfm_ccm);
349*05b00f60SXin Li 
350*05b00f60SXin Li         ccm_interval = CFM_EXTRACT_CCM_INTERVAL(flags);
351*05b00f60SXin Li         ND_PRINT(", Flags [CCM Interval %u%s]",
352*05b00f60SXin Li                ccm_interval,
353*05b00f60SXin Li                flags & CFM_CCM_RDI_FLAG ?
354*05b00f60SXin Li                ", RDI" : "");
355*05b00f60SXin Li 
356*05b00f60SXin Li         /*
357*05b00f60SXin Li          * Resolve the CCM interval field.
358*05b00f60SXin Li          */
359*05b00f60SXin Li         if (ccm_interval) {
360*05b00f60SXin Li             ND_PRINT("\n\t  CCM Interval %.3fs"
361*05b00f60SXin Li                    ", min CCM Lifetime %.3fs, max CCM Lifetime %.3fs",
362*05b00f60SXin Li                    ccm_interval_base[ccm_interval],
363*05b00f60SXin Li                    ccm_interval_base[ccm_interval] * CCM_INTERVAL_MIN_MULTIPLIER,
364*05b00f60SXin Li                    ccm_interval_base[ccm_interval] * CCM_INTERVAL_MAX_MULTIPLIER);
365*05b00f60SXin Li         }
366*05b00f60SXin Li 
367*05b00f60SXin Li         ND_PRINT("\n\t  Sequence Number 0x%08x, MA-End-Point-ID 0x%04x",
368*05b00f60SXin Li                GET_BE_U_4(msg_ptr.cfm_ccm->sequence),
369*05b00f60SXin Li                GET_BE_U_2(msg_ptr.cfm_ccm->ma_epi));
370*05b00f60SXin Li 
371*05b00f60SXin Li         namesp = msg_ptr.cfm_ccm->names;
372*05b00f60SXin Li         names_data_remaining = sizeof(msg_ptr.cfm_ccm->names);
373*05b00f60SXin Li 
374*05b00f60SXin Li         /*
375*05b00f60SXin Li          * Resolve the MD fields.
376*05b00f60SXin Li          */
377*05b00f60SXin Li         md_nameformat = GET_U_1(namesp);
378*05b00f60SXin Li         namesp++;
379*05b00f60SXin Li         names_data_remaining--;  /* We know this is != 0 */
380*05b00f60SXin Li         if (md_nameformat != CFM_CCM_MD_FORMAT_NONE) {
381*05b00f60SXin Li             md_namelength = GET_U_1(namesp);
382*05b00f60SXin Li             namesp++;
383*05b00f60SXin Li             names_data_remaining--; /* We know this is !=0 */
384*05b00f60SXin Li             ND_PRINT("\n\t  MD Name Format %s (%u), MD Name length %u",
385*05b00f60SXin Li                    tok2str(cfm_md_nameformat_values, "Unknown",
386*05b00f60SXin Li                            md_nameformat),
387*05b00f60SXin Li                    md_nameformat,
388*05b00f60SXin Li                    md_namelength);
389*05b00f60SXin Li 
390*05b00f60SXin Li             /*
391*05b00f60SXin Li              * -3 for the MA short name format and length and one byte
392*05b00f60SXin Li              * of MA short name.
393*05b00f60SXin Li              */
394*05b00f60SXin Li             if (md_namelength > names_data_remaining - 3) {
395*05b00f60SXin Li                 ND_PRINT(" (too large, must be <= %u)", names_data_remaining - 2);
396*05b00f60SXin Li                 return;
397*05b00f60SXin Li             }
398*05b00f60SXin Li 
399*05b00f60SXin Li             md_name = namesp;
400*05b00f60SXin Li             ND_PRINT("\n\t  MD Name: ");
401*05b00f60SXin Li             switch (md_nameformat) {
402*05b00f60SXin Li             case CFM_CCM_MD_FORMAT_DNS:
403*05b00f60SXin Li             case CFM_CCM_MD_FORMAT_CHAR:
404*05b00f60SXin Li                 nd_printjnp(ndo, md_name, md_namelength);
405*05b00f60SXin Li                 break;
406*05b00f60SXin Li 
407*05b00f60SXin Li             case CFM_CCM_MD_FORMAT_MAC:
408*05b00f60SXin Li                 if (md_namelength == MAC_ADDR_LEN) {
409*05b00f60SXin Li                     ND_PRINT("\n\t  MAC %s", GET_ETHERADDR_STRING(md_name));
410*05b00f60SXin Li                 } else {
411*05b00f60SXin Li                     ND_PRINT("\n\t  MAC (length invalid)");
412*05b00f60SXin Li                 }
413*05b00f60SXin Li                 break;
414*05b00f60SXin Li 
415*05b00f60SXin Li                 /* FIXME add printers for those MD formats - hexdump for now */
416*05b00f60SXin Li             case CFM_CCM_MA_FORMAT_8021:
417*05b00f60SXin Li             default:
418*05b00f60SXin Li                 print_unknown_data(ndo, md_name, "\n\t    ",
419*05b00f60SXin Li                                    md_namelength);
420*05b00f60SXin Li             }
421*05b00f60SXin Li             namesp += md_namelength;
422*05b00f60SXin Li             names_data_remaining -= md_namelength;
423*05b00f60SXin Li         } else {
424*05b00f60SXin Li             ND_PRINT("\n\t  MD Name Format %s (%u)",
425*05b00f60SXin Li                    tok2str(cfm_md_nameformat_values, "Unknown",
426*05b00f60SXin Li                            md_nameformat),
427*05b00f60SXin Li                    md_nameformat);
428*05b00f60SXin Li         }
429*05b00f60SXin Li 
430*05b00f60SXin Li 
431*05b00f60SXin Li         /*
432*05b00f60SXin Li          * Resolve the MA fields.
433*05b00f60SXin Li          */
434*05b00f60SXin Li         ma_nameformat = GET_U_1(namesp);
435*05b00f60SXin Li         namesp++;
436*05b00f60SXin Li         names_data_remaining--; /* We know this is != 0 */
437*05b00f60SXin Li         ma_namelength = GET_U_1(namesp);
438*05b00f60SXin Li         namesp++;
439*05b00f60SXin Li         names_data_remaining--; /* We know this is != 0 */
440*05b00f60SXin Li         ND_PRINT("\n\t  MA Name-Format %s (%u), MA name length %u",
441*05b00f60SXin Li                tok2str(cfm_ma_nameformat_values, "Unknown",
442*05b00f60SXin Li                        ma_nameformat),
443*05b00f60SXin Li                ma_nameformat,
444*05b00f60SXin Li                ma_namelength);
445*05b00f60SXin Li 
446*05b00f60SXin Li         if (ma_namelength > names_data_remaining) {
447*05b00f60SXin Li             ND_PRINT(" (too large, must be <= %u)", names_data_remaining);
448*05b00f60SXin Li             return;
449*05b00f60SXin Li         }
450*05b00f60SXin Li 
451*05b00f60SXin Li         ma_name = namesp;
452*05b00f60SXin Li         ND_PRINT("\n\t  MA Name: ");
453*05b00f60SXin Li         switch (ma_nameformat) {
454*05b00f60SXin Li         case CFM_CCM_MA_FORMAT_CHAR:
455*05b00f60SXin Li             nd_printjnp(ndo, ma_name, ma_namelength);
456*05b00f60SXin Li             break;
457*05b00f60SXin Li 
458*05b00f60SXin Li             /* FIXME add printers for those MA formats - hexdump for now */
459*05b00f60SXin Li         case CFM_CCM_MA_FORMAT_8021:
460*05b00f60SXin Li         case CFM_CCM_MA_FORMAT_VID:
461*05b00f60SXin Li         case CFM_CCM_MA_FORMAT_INT:
462*05b00f60SXin Li         case CFM_CCM_MA_FORMAT_VPN:
463*05b00f60SXin Li         default:
464*05b00f60SXin Li             print_unknown_data(ndo, ma_name, "\n\t    ", ma_namelength);
465*05b00f60SXin Li         }
466*05b00f60SXin Li         break;
467*05b00f60SXin Li 
468*05b00f60SXin Li     case CFM_OPCODE_LTM:
469*05b00f60SXin Li         msg_ptr.cfm_ltm = (const struct cfm_ltm_t *)tptr;
470*05b00f60SXin Li         if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltm)) {
471*05b00f60SXin Li             ND_PRINT(" (too small 4, must be >= %zu)",
472*05b00f60SXin Li                      sizeof(*msg_ptr.cfm_ltm));
473*05b00f60SXin Li             return;
474*05b00f60SXin Li         }
475*05b00f60SXin Li         if (tlen < sizeof(*msg_ptr.cfm_ltm))
476*05b00f60SXin Li             goto tooshort;
477*05b00f60SXin Li         ND_TCHECK_SIZE(msg_ptr.cfm_ltm);
478*05b00f60SXin Li 
479*05b00f60SXin Li         ND_PRINT(", Flags [%s]",
480*05b00f60SXin Li                bittok2str(cfm_ltm_flag_values, "none", flags));
481*05b00f60SXin Li 
482*05b00f60SXin Li         ND_PRINT("\n\t  Transaction-ID 0x%08x, ttl %u",
483*05b00f60SXin Li                GET_BE_U_4(msg_ptr.cfm_ltm->transaction_id),
484*05b00f60SXin Li                GET_U_1(msg_ptr.cfm_ltm->ttl));
485*05b00f60SXin Li 
486*05b00f60SXin Li         ND_PRINT("\n\t  Original-MAC %s, Target-MAC %s",
487*05b00f60SXin Li                GET_ETHERADDR_STRING(msg_ptr.cfm_ltm->original_mac),
488*05b00f60SXin Li                GET_ETHERADDR_STRING(msg_ptr.cfm_ltm->target_mac));
489*05b00f60SXin Li         break;
490*05b00f60SXin Li 
491*05b00f60SXin Li     case CFM_OPCODE_LTR:
492*05b00f60SXin Li         msg_ptr.cfm_ltr = (const struct cfm_ltr_t *)tptr;
493*05b00f60SXin Li         if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltr)) {
494*05b00f60SXin Li             ND_PRINT(" (too small 5, must be >= %zu)",
495*05b00f60SXin Li                      sizeof(*msg_ptr.cfm_ltr));
496*05b00f60SXin Li             return;
497*05b00f60SXin Li         }
498*05b00f60SXin Li         if (tlen < sizeof(*msg_ptr.cfm_ltr))
499*05b00f60SXin Li             goto tooshort;
500*05b00f60SXin Li         ND_TCHECK_SIZE(msg_ptr.cfm_ltr);
501*05b00f60SXin Li 
502*05b00f60SXin Li         ND_PRINT(", Flags [%s]",
503*05b00f60SXin Li                bittok2str(cfm_ltr_flag_values, "none", flags));
504*05b00f60SXin Li 
505*05b00f60SXin Li         ND_PRINT("\n\t  Transaction-ID 0x%08x, ttl %u",
506*05b00f60SXin Li                GET_BE_U_4(msg_ptr.cfm_ltr->transaction_id),
507*05b00f60SXin Li                GET_U_1(msg_ptr.cfm_ltr->ttl));
508*05b00f60SXin Li 
509*05b00f60SXin Li         ND_PRINT("\n\t  Replay-Action %s (%u)",
510*05b00f60SXin Li                tok2str(cfm_ltr_replay_action_values,
511*05b00f60SXin Li                        "Unknown",
512*05b00f60SXin Li                        GET_U_1(msg_ptr.cfm_ltr->replay_action)),
513*05b00f60SXin Li                GET_U_1(msg_ptr.cfm_ltr->replay_action));
514*05b00f60SXin Li         break;
515*05b00f60SXin Li 
516*05b00f60SXin Li         /*
517*05b00f60SXin Li          * No message decoder yet.
518*05b00f60SXin Li          * Hexdump everything up until the start of the TLVs
519*05b00f60SXin Li          */
520*05b00f60SXin Li     case CFM_OPCODE_LBR:
521*05b00f60SXin Li     case CFM_OPCODE_LBM:
522*05b00f60SXin Li     default:
523*05b00f60SXin Li         print_unknown_data(ndo, tptr, "\n\t  ",
524*05b00f60SXin Li                            tlen -  first_tlv_offset);
525*05b00f60SXin Li         break;
526*05b00f60SXin Li     }
527*05b00f60SXin Li 
528*05b00f60SXin Li     tptr += first_tlv_offset;
529*05b00f60SXin Li     tlen -= first_tlv_offset;
530*05b00f60SXin Li 
531*05b00f60SXin Li     while (tlen > 0) {
532*05b00f60SXin Li         cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr;
533*05b00f60SXin Li 
534*05b00f60SXin Li         /* Enough to read the tlv type ? */
535*05b00f60SXin Li         cfm_tlv_type = GET_U_1(cfm_tlv_header->type);
536*05b00f60SXin Li 
537*05b00f60SXin Li         ND_PRINT("\n\t%s TLV (0x%02x)",
538*05b00f60SXin Li                tok2str(cfm_tlv_values, "Unknown", cfm_tlv_type),
539*05b00f60SXin Li                cfm_tlv_type);
540*05b00f60SXin Li 
541*05b00f60SXin Li         if (cfm_tlv_type == CFM_TLV_END) {
542*05b00f60SXin Li             /* Length is "Not present if the Type field is 0." */
543*05b00f60SXin Li             return;
544*05b00f60SXin Li         }
545*05b00f60SXin Li 
546*05b00f60SXin Li         /* do we have the full tlv header ? */
547*05b00f60SXin Li         if (tlen < sizeof(struct cfm_tlv_header_t))
548*05b00f60SXin Li             goto tooshort;
549*05b00f60SXin Li         ND_TCHECK_LEN(tptr, sizeof(struct cfm_tlv_header_t));
550*05b00f60SXin Li         cfm_tlv_len=GET_BE_U_2(cfm_tlv_header->length);
551*05b00f60SXin Li 
552*05b00f60SXin Li         ND_PRINT(", length %u", cfm_tlv_len);
553*05b00f60SXin Li 
554*05b00f60SXin Li         tptr += sizeof(struct cfm_tlv_header_t);
555*05b00f60SXin Li         tlen -= sizeof(struct cfm_tlv_header_t);
556*05b00f60SXin Li         tlv_ptr = tptr;
557*05b00f60SXin Li 
558*05b00f60SXin Li         /* do we have the full tlv ? */
559*05b00f60SXin Li         if (tlen < cfm_tlv_len)
560*05b00f60SXin Li             goto tooshort;
561*05b00f60SXin Li         ND_TCHECK_LEN(tptr, cfm_tlv_len);
562*05b00f60SXin Li         hexdump = FALSE;
563*05b00f60SXin Li 
564*05b00f60SXin Li         switch(cfm_tlv_type) {
565*05b00f60SXin Li         case CFM_TLV_PORT_STATUS:
566*05b00f60SXin Li             if (cfm_tlv_len < 1) {
567*05b00f60SXin Li                 ND_PRINT(" (too short, must be >= 1)");
568*05b00f60SXin Li                 return;
569*05b00f60SXin Li             }
570*05b00f60SXin Li             ND_PRINT(", Status: %s (%u)",
571*05b00f60SXin Li                    tok2str(cfm_tlv_port_status_values, "Unknown", GET_U_1(tptr)),
572*05b00f60SXin Li                    GET_U_1(tptr));
573*05b00f60SXin Li             break;
574*05b00f60SXin Li 
575*05b00f60SXin Li         case CFM_TLV_INTERFACE_STATUS:
576*05b00f60SXin Li             if (cfm_tlv_len < 1) {
577*05b00f60SXin Li                 ND_PRINT(" (too short, must be >= 1)");
578*05b00f60SXin Li                 return;
579*05b00f60SXin Li             }
580*05b00f60SXin Li             ND_PRINT(", Status: %s (%u)",
581*05b00f60SXin Li                    tok2str(cfm_tlv_interface_status_values, "Unknown", GET_U_1(tptr)),
582*05b00f60SXin Li                    GET_U_1(tptr));
583*05b00f60SXin Li             break;
584*05b00f60SXin Li 
585*05b00f60SXin Li         case CFM_TLV_PRIVATE:
586*05b00f60SXin Li             if (cfm_tlv_len < 4) {
587*05b00f60SXin Li                 ND_PRINT(" (too short, must be >= 4)");
588*05b00f60SXin Li                 return;
589*05b00f60SXin Li             }
590*05b00f60SXin Li             ND_PRINT(", Vendor: %s (%u), Sub-Type %u",
591*05b00f60SXin Li                    tok2str(oui_values,"Unknown", GET_BE_U_3(tptr)),
592*05b00f60SXin Li                    GET_BE_U_3(tptr),
593*05b00f60SXin Li                    GET_U_1(tptr + 3));
594*05b00f60SXin Li             hexdump = TRUE;
595*05b00f60SXin Li             break;
596*05b00f60SXin Li 
597*05b00f60SXin Li         case CFM_TLV_SENDER_ID:
598*05b00f60SXin Li         {
599*05b00f60SXin Li             u_int chassis_id_type, chassis_id_length;
600*05b00f60SXin Li             u_int mgmt_addr_length;
601*05b00f60SXin Li 
602*05b00f60SXin Li             if (cfm_tlv_len < 1) {
603*05b00f60SXin Li                 ND_PRINT(" (too short, must be >= 1)");
604*05b00f60SXin Li                 goto next_tlv;
605*05b00f60SXin Li             }
606*05b00f60SXin Li 
607*05b00f60SXin Li             /*
608*05b00f60SXin Li              * Get the Chassis ID length and check it.
609*05b00f60SXin Li              * IEEE 802.1Q-2014 Section 21.5.3.1
610*05b00f60SXin Li              */
611*05b00f60SXin Li             chassis_id_length = GET_U_1(tptr);
612*05b00f60SXin Li             tptr++;
613*05b00f60SXin Li             tlen--;
614*05b00f60SXin Li             cfm_tlv_len--;
615*05b00f60SXin Li 
616*05b00f60SXin Li             if (chassis_id_length) {
617*05b00f60SXin Li                 /*
618*05b00f60SXin Li                  * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references
619*05b00f60SXin Li                  * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently
620*05b00f60SXin Li                  * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype
621*05b00f60SXin Li                  */
622*05b00f60SXin Li                 if (cfm_tlv_len < 1) {
623*05b00f60SXin Li                     ND_PRINT("\n\t  (TLV too short)");
624*05b00f60SXin Li                     goto next_tlv;
625*05b00f60SXin Li                 }
626*05b00f60SXin Li                 chassis_id_type = GET_U_1(tptr);
627*05b00f60SXin Li                 cfm_tlv_len--;
628*05b00f60SXin Li                 ND_PRINT("\n\t  Chassis-ID Type %s (%u), Chassis-ID length %u",
629*05b00f60SXin Li                        tok2str(cfm_tlv_senderid_chassisid_values,
630*05b00f60SXin Li                                "Unknown",
631*05b00f60SXin Li                                chassis_id_type),
632*05b00f60SXin Li                        chassis_id_type,
633*05b00f60SXin Li                        chassis_id_length);
634*05b00f60SXin Li 
635*05b00f60SXin Li                 if (cfm_tlv_len < chassis_id_length) {
636*05b00f60SXin Li                     ND_PRINT("\n\t  (TLV too short)");
637*05b00f60SXin Li                     goto next_tlv;
638*05b00f60SXin Li                 }
639*05b00f60SXin Li 
640*05b00f60SXin Li                 /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */
641*05b00f60SXin Li                 switch (chassis_id_type) {
642*05b00f60SXin Li                 case CFM_CHASSIS_ID_MAC_ADDRESS:
643*05b00f60SXin Li                     if (chassis_id_length != MAC_ADDR_LEN) {
644*05b00f60SXin Li                         ND_PRINT(" (invalid MAC address length)");
645*05b00f60SXin Li                         hexdump = TRUE;
646*05b00f60SXin Li                         break;
647*05b00f60SXin Li                     }
648*05b00f60SXin Li                     ND_PRINT("\n\t  MAC %s", GET_ETHERADDR_STRING(tptr + 1));
649*05b00f60SXin Li                     break;
650*05b00f60SXin Li 
651*05b00f60SXin Li                 case CFM_CHASSIS_ID_NETWORK_ADDRESS:
652*05b00f60SXin Li                     hexdump |= cfm_network_addr_print(ndo, tptr + 1, chassis_id_length);
653*05b00f60SXin Li                     break;
654*05b00f60SXin Li 
655*05b00f60SXin Li                 case CFM_CHASSIS_ID_INTERFACE_NAME: /* fall through */
656*05b00f60SXin Li                 case CFM_CHASSIS_ID_INTERFACE_ALIAS:
657*05b00f60SXin Li                 case CFM_CHASSIS_ID_LOCAL:
658*05b00f60SXin Li                 case CFM_CHASSIS_ID_CHASSIS_COMPONENT:
659*05b00f60SXin Li                 case CFM_CHASSIS_ID_PORT_COMPONENT:
660*05b00f60SXin Li                     nd_printjnp(ndo, tptr + 1, chassis_id_length);
661*05b00f60SXin Li                     break;
662*05b00f60SXin Li 
663*05b00f60SXin Li                 default:
664*05b00f60SXin Li                     hexdump = TRUE;
665*05b00f60SXin Li                     break;
666*05b00f60SXin Li                 }
667*05b00f60SXin Li                 cfm_tlv_len -= chassis_id_length;
668*05b00f60SXin Li 
669*05b00f60SXin Li                 tptr += 1 + chassis_id_length;
670*05b00f60SXin Li                 tlen -= 1 + chassis_id_length;
671*05b00f60SXin Li             }
672*05b00f60SXin Li 
673*05b00f60SXin Li             /*
674*05b00f60SXin Li              * Check if there is a Management Address.
675*05b00f60SXin Li              * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length
676*05b00f60SXin Li              * This and all subsequent fields are not present if the TLV length
677*05b00f60SXin Li              * allows only the above fields.
678*05b00f60SXin Li              */
679*05b00f60SXin Li             if (cfm_tlv_len == 0) {
680*05b00f60SXin Li                 /* No, there isn't; we're done. */
681*05b00f60SXin Li                 break;
682*05b00f60SXin Li             }
683*05b00f60SXin Li 
684*05b00f60SXin Li             /* Here mgmt_addr_length stands for the management domain length. */
685*05b00f60SXin Li             mgmt_addr_length = GET_U_1(tptr);
686*05b00f60SXin Li             tptr++;
687*05b00f60SXin Li             tlen--;
688*05b00f60SXin Li             cfm_tlv_len--;
689*05b00f60SXin Li             ND_PRINT("\n\t  Management Address Domain Length %u", mgmt_addr_length);
690*05b00f60SXin Li             if (mgmt_addr_length) {
691*05b00f60SXin Li                 /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */
692*05b00f60SXin Li                 if (cfm_tlv_len < mgmt_addr_length) {
693*05b00f60SXin Li                     ND_PRINT("\n\t  (TLV too short)");
694*05b00f60SXin Li                     goto next_tlv;
695*05b00f60SXin Li                 }
696*05b00f60SXin Li                 cfm_tlv_len -= mgmt_addr_length;
697*05b00f60SXin Li                 /*
698*05b00f60SXin Li                  * XXX - this is an OID; print it as such.
699*05b00f60SXin Li                  */
700*05b00f60SXin Li                 hex_print(ndo, "\n\t  Management Address Domain: ", tptr, mgmt_addr_length);
701*05b00f60SXin Li                 tptr += mgmt_addr_length;
702*05b00f60SXin Li                 tlen -= mgmt_addr_length;
703*05b00f60SXin Li 
704*05b00f60SXin Li                 /*
705*05b00f60SXin Li                  * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length
706*05b00f60SXin Li                  * This field is present if Management Address Domain Length is not 0.
707*05b00f60SXin Li                  */
708*05b00f60SXin Li                 if (cfm_tlv_len < 1) {
709*05b00f60SXin Li                     ND_PRINT(" (Management Address Length is missing)");
710*05b00f60SXin Li                     hexdump = TRUE;
711*05b00f60SXin Li                     break;
712*05b00f60SXin Li                 }
713*05b00f60SXin Li 
714*05b00f60SXin Li                 /* Here mgmt_addr_length stands for the management address length. */
715*05b00f60SXin Li                 mgmt_addr_length = GET_U_1(tptr);
716*05b00f60SXin Li                 tptr++;
717*05b00f60SXin Li                 tlen--;
718*05b00f60SXin Li                 cfm_tlv_len--;
719*05b00f60SXin Li                 ND_PRINT("\n\t  Management Address Length %u", mgmt_addr_length);
720*05b00f60SXin Li                 if (mgmt_addr_length) {
721*05b00f60SXin Li                     /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */
722*05b00f60SXin Li                     if (cfm_tlv_len < mgmt_addr_length) {
723*05b00f60SXin Li                         ND_PRINT("\n\t  (TLV too short)");
724*05b00f60SXin Li                         return;
725*05b00f60SXin Li                     }
726*05b00f60SXin Li                     cfm_tlv_len -= mgmt_addr_length;
727*05b00f60SXin Li                     /*
728*05b00f60SXin Li                      * XXX - this is a TransportDomain; print it as such.
729*05b00f60SXin Li                      */
730*05b00f60SXin Li                     hex_print(ndo, "\n\t  Management Address: ", tptr, mgmt_addr_length);
731*05b00f60SXin Li                     tptr += mgmt_addr_length;
732*05b00f60SXin Li                     tlen -= mgmt_addr_length;
733*05b00f60SXin Li                 }
734*05b00f60SXin Li             }
735*05b00f60SXin Li             break;
736*05b00f60SXin Li         }
737*05b00f60SXin Li 
738*05b00f60SXin Li             /*
739*05b00f60SXin Li              * FIXME those are the defined TLVs that lack a decoder
740*05b00f60SXin Li              * you are welcome to contribute code ;-)
741*05b00f60SXin Li              */
742*05b00f60SXin Li 
743*05b00f60SXin Li         case CFM_TLV_DATA:
744*05b00f60SXin Li         case CFM_TLV_REPLY_INGRESS:
745*05b00f60SXin Li         case CFM_TLV_REPLY_EGRESS:
746*05b00f60SXin Li         default:
747*05b00f60SXin Li             hexdump = TRUE;
748*05b00f60SXin Li             break;
749*05b00f60SXin Li         }
750*05b00f60SXin Li         /* do we want to see an additional hexdump ? */
751*05b00f60SXin Li         if (hexdump || ndo->ndo_vflag > 1)
752*05b00f60SXin Li             print_unknown_data(ndo, tlv_ptr, "\n\t  ", cfm_tlv_len);
753*05b00f60SXin Li 
754*05b00f60SXin Li next_tlv:
755*05b00f60SXin Li         tptr+=cfm_tlv_len;
756*05b00f60SXin Li         tlen-=cfm_tlv_len;
757*05b00f60SXin Li     }
758*05b00f60SXin Li     return;
759*05b00f60SXin Li 
760*05b00f60SXin Li tooshort:
761*05b00f60SXin Li     ND_PRINT("\n\t\t packet is too short");
762*05b00f60SXin Li     return;
763*05b00f60SXin Li 
764*05b00f60SXin Li trunc:
765*05b00f60SXin Li     nd_print_trunc(ndo);
766*05b00f60SXin Li }
767