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