2 * Copyright (c) 1998-2006 The TCPDUMP project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
15 * Original code by Hannes Gredler (hannes@gredler.at)
18 /* \summary: IEEE 802.1ag Connectivity Fault Management (CFM) protocols printer */
24 #include "netdissect-stdinc.h"
28 #include "netdissect.h"
30 #include "addrtoname.h"
34 static const char tstr
[] = " [|cfm]";
36 struct cfm_common_header_t
{
37 nd_uint8_t mdlevel_version
;
40 nd_uint8_t first_tlv_offset
;
44 #define CFM_EXTRACT_VERSION(x) (((x)&0x1f))
45 #define CFM_EXTRACT_MD_LEVEL(x) (((x)&0xe0)>>5)
47 #define CFM_OPCODE_CCM 1
48 #define CFM_OPCODE_LBR 2
49 #define CFM_OPCODE_LBM 3
50 #define CFM_OPCODE_LTR 4
51 #define CFM_OPCODE_LTM 5
53 static const struct tok cfm_opcode_values
[] = {
54 { CFM_OPCODE_CCM
, "Continuity Check Message"},
55 { CFM_OPCODE_LBR
, "Loopback Reply"},
56 { CFM_OPCODE_LBM
, "Loopback Message"},
57 { CFM_OPCODE_LTR
, "Linktrace Reply"},
58 { CFM_OPCODE_LTM
, "Linktrace Message"},
69 nd_byte itu_t_y_1731
[16];
73 * Timer Bases for the CCM Interval field.
74 * Expressed in units of seconds.
76 static const float ccm_interval_base
[8] = {0.0f
, 0.003333f
, 0.01f
, 0.1f
, 1.0f
, 10.0f
, 60.0f
, 600.0f
};
77 #define CCM_INTERVAL_MIN_MULTIPLIER 3.25
78 #define CCM_INTERVAL_MAX_MULTIPLIER 3.5
80 #define CFM_CCM_RDI_FLAG 0x80
81 #define CFM_EXTRACT_CCM_INTERVAL(x) (((x)&0x07))
83 #define CFM_CCM_MD_FORMAT_8021 0
84 #define CFM_CCM_MD_FORMAT_NONE 1
85 #define CFM_CCM_MD_FORMAT_DNS 2
86 #define CFM_CCM_MD_FORMAT_MAC 3
87 #define CFM_CCM_MD_FORMAT_CHAR 4
89 static const struct tok cfm_md_nameformat_values
[] = {
90 { CFM_CCM_MD_FORMAT_8021
, "IEEE 802.1"},
91 { CFM_CCM_MD_FORMAT_NONE
, "No MD Name present"},
92 { CFM_CCM_MD_FORMAT_DNS
, "DNS string"},
93 { CFM_CCM_MD_FORMAT_MAC
, "MAC + 16Bit Integer"},
94 { CFM_CCM_MD_FORMAT_CHAR
, "Character string"},
98 #define CFM_CCM_MA_FORMAT_8021 0
99 #define CFM_CCM_MA_FORMAT_VID 1
100 #define CFM_CCM_MA_FORMAT_CHAR 2
101 #define CFM_CCM_MA_FORMAT_INT 3
102 #define CFM_CCM_MA_FORMAT_VPN 4
104 static const struct tok cfm_ma_nameformat_values
[] = {
105 { CFM_CCM_MA_FORMAT_8021
, "IEEE 802.1"},
106 { CFM_CCM_MA_FORMAT_VID
, "Primary VID"},
107 { CFM_CCM_MA_FORMAT_CHAR
, "Character string"},
108 { CFM_CCM_MA_FORMAT_INT
, "16Bit Integer"},
109 { CFM_CCM_MA_FORMAT_VPN
, "RFC2685 VPN-ID"},
114 nd_uint32_t transaction_id
;
118 nd_uint32_t transaction_id
;
120 nd_mac_addr original_mac
;
121 nd_mac_addr target_mac
;
124 static const struct tok cfm_ltm_flag_values
[] = {
125 { 0x80, "Use Forwarding-DB only"},
130 nd_uint32_t transaction_id
;
132 nd_uint8_t replay_action
;
135 static const struct tok cfm_ltr_flag_values
[] = {
136 { 0x80, "UseFDB Only"},
138 { 0x20, "Terminal MEP"},
142 static const struct tok cfm_ltr_replay_action_values
[] = {
144 { 2, "Filtering DB"},
150 #define CFM_TLV_END 0
151 #define CFM_TLV_SENDER_ID 1
152 #define CFM_TLV_PORT_STATUS 2
153 #define CFM_TLV_INTERFACE_STATUS 3
154 #define CFM_TLV_DATA 4
155 #define CFM_TLV_REPLY_INGRESS 5
156 #define CFM_TLV_REPLY_EGRESS 6
157 #define CFM_TLV_PRIVATE 31
159 static const struct tok cfm_tlv_values
[] = {
160 { CFM_TLV_END
, "End"},
161 { CFM_TLV_SENDER_ID
, "Sender ID"},
162 { CFM_TLV_PORT_STATUS
, "Port status"},
163 { CFM_TLV_INTERFACE_STATUS
, "Interface status"},
164 { CFM_TLV_DATA
, "Data"},
165 { CFM_TLV_REPLY_INGRESS
, "Reply Ingress"},
166 { CFM_TLV_REPLY_EGRESS
, "Reply Egress"},
167 { CFM_TLV_PRIVATE
, "Organization Specific"},
175 struct cfm_tlv_header_t
{
180 /* FIXME define TLV formats */
182 static const struct tok cfm_tlv_port_status_values
[] = {
188 static const struct tok cfm_tlv_interface_status_values
[] = {
194 { 7, "lower Layer down"},
198 #define CFM_CHASSIS_ID_CHASSIS_COMPONENT 1
199 #define CFM_CHASSIS_ID_INTERFACE_ALIAS 2
200 #define CFM_CHASSIS_ID_PORT_COMPONENT 3
201 #define CFM_CHASSIS_ID_MAC_ADDRESS 4
202 #define CFM_CHASSIS_ID_NETWORK_ADDRESS 5
203 #define CFM_CHASSIS_ID_INTERFACE_NAME 6
204 #define CFM_CHASSIS_ID_LOCAL 7
206 static const struct tok cfm_tlv_senderid_chassisid_values
[] = {
208 { CFM_CHASSIS_ID_CHASSIS_COMPONENT
, "Chassis component"},
209 { CFM_CHASSIS_ID_INTERFACE_ALIAS
, "Interface alias"},
210 { CFM_CHASSIS_ID_PORT_COMPONENT
, "Port component"},
211 { CFM_CHASSIS_ID_MAC_ADDRESS
, "MAC address"},
212 { CFM_CHASSIS_ID_NETWORK_ADDRESS
, "Network address"},
213 { CFM_CHASSIS_ID_INTERFACE_NAME
, "Interface name"},
214 { CFM_CHASSIS_ID_LOCAL
, "Locally assigned"},
220 cfm_network_addr_print(netdissect_options
*ndo
,
221 const u_char
*tptr
, const u_int length
)
223 u_int network_addr_type
;
224 u_int hexdump
= FALSE
;
227 * Although AFIs are typically 2 octects wide,
228 * 802.1ab specifies that this field width
232 ND_PRINT("\n\t Network Address Type (invalid, no data");
235 /* The calling function must make any due ND_TCHECK calls. */
236 network_addr_type
= EXTRACT_U_1(tptr
);
237 ND_PRINT("\n\t Network Address Type %s (%u)",
238 tok2str(af_values
, "Unknown", network_addr_type
),
242 * Resolve the passed in Address.
244 switch(network_addr_type
) {
246 if (length
!= 1 + 4) {
247 ND_PRINT("(invalid IPv4 address length %u)", length
- 1);
251 ND_PRINT(", %s", ipaddr_string(ndo
, tptr
+ 1));
255 if (length
!= 1 + 16) {
256 ND_PRINT("(invalid IPv6 address length %u)", length
- 1);
260 ND_PRINT(", %s", ip6addr_string(ndo
, tptr
+ 1));
272 cfm_print(netdissect_options
*ndo
,
273 const u_char
*pptr
, u_int length
)
275 const struct cfm_common_header_t
*cfm_common_header
;
276 uint8_t mdlevel_version
, opcode
, flags
, first_tlv_offset
;
277 const struct cfm_tlv_header_t
*cfm_tlv_header
;
278 const uint8_t *tptr
, *tlv_ptr
;
279 const uint8_t *namesp
;
280 u_int names_data_remaining
;
281 uint8_t md_nameformat
, md_namelength
;
282 const uint8_t *md_name
;
283 uint8_t ma_nameformat
, ma_namelength
;
284 const uint8_t *ma_name
;
285 u_int hexdump
, tlen
, cfm_tlv_len
, cfm_tlv_type
, ccm_interval
;
289 const struct cfm_ccm_t
*cfm_ccm
;
290 const struct cfm_lbm_t
*cfm_lbm
;
291 const struct cfm_ltm_t
*cfm_ltm
;
292 const struct cfm_ltr_t
*cfm_ltr
;
295 ndo
->ndo_protocol
= "cfm";
297 cfm_common_header
= (const struct cfm_common_header_t
*)pptr
;
298 if (length
< sizeof(*cfm_common_header
))
300 ND_TCHECK_SIZE(cfm_common_header
);
303 * Sanity checking of the header.
305 mdlevel_version
= EXTRACT_U_1(cfm_common_header
->mdlevel_version
);
306 if (CFM_EXTRACT_VERSION(mdlevel_version
) != CFM_VERSION
) {
307 ND_PRINT("CFMv%u not supported, length %u",
308 CFM_EXTRACT_VERSION(mdlevel_version
), length
);
312 opcode
= EXTRACT_U_1(cfm_common_header
->opcode
);
313 ND_PRINT("CFMv%u %s, MD Level %u, length %u",
314 CFM_EXTRACT_VERSION(mdlevel_version
),
315 tok2str(cfm_opcode_values
, "unknown (%u)", opcode
),
316 CFM_EXTRACT_MD_LEVEL(mdlevel_version
),
320 * In non-verbose mode just print the opcode and md-level.
322 if (ndo
->ndo_vflag
< 1) {
326 flags
= EXTRACT_U_1(cfm_common_header
->flags
);
327 first_tlv_offset
= EXTRACT_U_1(cfm_common_header
->first_tlv_offset
);
328 ND_PRINT("\n\tFirst TLV offset %u", first_tlv_offset
);
330 tptr
+= sizeof(struct cfm_common_header_t
);
331 tlen
= length
- sizeof(struct cfm_common_header_t
);
334 * Sanity check the first TLV offset.
336 if (first_tlv_offset
> tlen
) {
337 ND_PRINT(" (too large, must be <= %u)", tlen
);
343 msg_ptr
.cfm_ccm
= (const struct cfm_ccm_t
*)tptr
;
344 if (first_tlv_offset
< sizeof(*msg_ptr
.cfm_ccm
)) {
345 ND_PRINT(" (too small 1, must be >= %lu)",
346 (unsigned long) sizeof(*msg_ptr
.cfm_ccm
));
349 if (tlen
< sizeof(*msg_ptr
.cfm_ccm
))
351 ND_TCHECK_SIZE(msg_ptr
.cfm_ccm
);
353 ccm_interval
= CFM_EXTRACT_CCM_INTERVAL(flags
);
354 ND_PRINT(", Flags [CCM Interval %u%s]",
356 flags
& CFM_CCM_RDI_FLAG
?
360 * Resolve the CCM interval field.
363 ND_PRINT("\n\t CCM Interval %.3fs"
364 ", min CCM Lifetime %.3fs, max CCM Lifetime %.3fs",
365 ccm_interval_base
[ccm_interval
],
366 ccm_interval_base
[ccm_interval
] * CCM_INTERVAL_MIN_MULTIPLIER
,
367 ccm_interval_base
[ccm_interval
] * CCM_INTERVAL_MAX_MULTIPLIER
);
370 ND_PRINT("\n\t Sequence Number 0x%08x, MA-End-Point-ID 0x%04x",
371 EXTRACT_BE_U_4(msg_ptr
.cfm_ccm
->sequence
),
372 EXTRACT_BE_U_2(msg_ptr
.cfm_ccm
->ma_epi
));
374 namesp
= msg_ptr
.cfm_ccm
->names
;
375 names_data_remaining
= sizeof(msg_ptr
.cfm_ccm
->names
);
378 * Resolve the MD fields.
380 md_nameformat
= EXTRACT_U_1(namesp
);
382 names_data_remaining
--; /* We know this is != 0 */
383 if (md_nameformat
!= CFM_CCM_MD_FORMAT_NONE
) {
384 md_namelength
= EXTRACT_U_1(namesp
);
386 names_data_remaining
--; /* We know this is !=0 */
387 ND_PRINT("\n\t MD Name Format %s (%u), MD Name length %u",
388 tok2str(cfm_md_nameformat_values
, "Unknown",
394 * -3 for the MA short name format and length and one byte
397 if (md_namelength
> names_data_remaining
- 3) {
398 ND_PRINT(" (too large, must be <= %u)", names_data_remaining
- 2);
403 ND_PRINT("\n\t MD Name: ");
404 switch (md_nameformat
) {
405 case CFM_CCM_MD_FORMAT_DNS
:
406 case CFM_CCM_MD_FORMAT_CHAR
:
407 (void)nd_printzp(ndo
, md_name
, md_namelength
, NULL
);
410 case CFM_CCM_MD_FORMAT_MAC
:
411 if (md_namelength
== 6) {
412 ND_PRINT("\n\t MAC %s", etheraddr_string(ndo
,
415 ND_PRINT("\n\t MAC (length invalid)");
419 /* FIXME add printers for those MD formats - hexdump for now */
420 case CFM_CCM_MA_FORMAT_8021
:
422 print_unknown_data(ndo
, md_name
, "\n\t ",
425 namesp
+= md_namelength
;
426 names_data_remaining
-= md_namelength
;
428 ND_PRINT("\n\t MD Name Format %s (%u)",
429 tok2str(cfm_md_nameformat_values
, "Unknown",
436 * Resolve the MA fields.
438 ma_nameformat
= EXTRACT_U_1(namesp
);
440 names_data_remaining
--; /* We know this is != 0 */
441 ma_namelength
= EXTRACT_U_1(namesp
);
443 names_data_remaining
--; /* We know this is != 0 */
444 ND_PRINT("\n\t MA Name-Format %s (%u), MA name length %u",
445 tok2str(cfm_ma_nameformat_values
, "Unknown",
450 if (ma_namelength
> names_data_remaining
) {
451 ND_PRINT(" (too large, must be <= %u)", names_data_remaining
);
456 ND_PRINT("\n\t MA Name: ");
457 switch (ma_nameformat
) {
458 case CFM_CCM_MA_FORMAT_CHAR
:
459 (void)nd_printzp(ndo
, ma_name
, ma_namelength
, NULL
);
462 /* FIXME add printers for those MA formats - hexdump for now */
463 case CFM_CCM_MA_FORMAT_8021
:
464 case CFM_CCM_MA_FORMAT_VID
:
465 case CFM_CCM_MA_FORMAT_INT
:
466 case CFM_CCM_MA_FORMAT_VPN
:
468 print_unknown_data(ndo
, ma_name
, "\n\t ", ma_namelength
);
473 msg_ptr
.cfm_ltm
= (const struct cfm_ltm_t
*)tptr
;
474 if (first_tlv_offset
< sizeof(*msg_ptr
.cfm_ltm
)) {
475 ND_PRINT(" (too small 4, must be >= %lu)",
476 (unsigned long) sizeof(*msg_ptr
.cfm_ltm
));
479 if (tlen
< sizeof(*msg_ptr
.cfm_ltm
))
481 ND_TCHECK_SIZE(msg_ptr
.cfm_ltm
);
483 ND_PRINT(", Flags [%s]",
484 bittok2str(cfm_ltm_flag_values
, "none", flags
));
486 ND_PRINT("\n\t Transaction-ID 0x%08x, ttl %u",
487 EXTRACT_BE_U_4(msg_ptr
.cfm_ltm
->transaction_id
),
488 EXTRACT_U_1(msg_ptr
.cfm_ltm
->ttl
));
490 ND_PRINT("\n\t Original-MAC %s, Target-MAC %s",
491 etheraddr_string(ndo
, msg_ptr
.cfm_ltm
->original_mac
),
492 etheraddr_string(ndo
, msg_ptr
.cfm_ltm
->target_mac
));
496 msg_ptr
.cfm_ltr
= (const struct cfm_ltr_t
*)tptr
;
497 if (first_tlv_offset
< sizeof(*msg_ptr
.cfm_ltr
)) {
498 ND_PRINT(" (too small 5, must be >= %lu)",
499 (unsigned long) sizeof(*msg_ptr
.cfm_ltr
));
502 if (tlen
< sizeof(*msg_ptr
.cfm_ltr
))
504 ND_TCHECK_SIZE(msg_ptr
.cfm_ltr
);
506 ND_PRINT(", Flags [%s]",
507 bittok2str(cfm_ltr_flag_values
, "none", flags
));
509 ND_PRINT("\n\t Transaction-ID 0x%08x, ttl %u",
510 EXTRACT_BE_U_4(msg_ptr
.cfm_ltr
->transaction_id
),
511 EXTRACT_U_1(msg_ptr
.cfm_ltr
->ttl
));
513 ND_PRINT("\n\t Replay-Action %s (%u)",
514 tok2str(cfm_ltr_replay_action_values
,
516 EXTRACT_U_1(msg_ptr
.cfm_ltr
->replay_action
)),
517 EXTRACT_U_1(msg_ptr
.cfm_ltr
->replay_action
));
521 * No message decoder yet.
522 * Hexdump everything up until the start of the TLVs
527 print_unknown_data(ndo
, tptr
, "\n\t ",
528 tlen
- first_tlv_offset
);
532 tptr
+= first_tlv_offset
;
533 tlen
-= first_tlv_offset
;
536 cfm_tlv_header
= (const struct cfm_tlv_header_t
*)tptr
;
538 /* Enough to read the tlv type ? */
539 ND_TCHECK_1(cfm_tlv_header
->type
);
540 cfm_tlv_type
= EXTRACT_U_1(cfm_tlv_header
->type
);
542 ND_PRINT("\n\t%s TLV (0x%02x)",
543 tok2str(cfm_tlv_values
, "Unknown", cfm_tlv_type
),
546 if (cfm_tlv_type
== CFM_TLV_END
) {
547 /* Length is "Not present if the Type field is 0." */
551 /* do we have the full tlv header ? */
552 if (tlen
< sizeof(struct cfm_tlv_header_t
))
554 ND_TCHECK_LEN(tptr
, sizeof(struct cfm_tlv_header_t
));
555 cfm_tlv_len
=EXTRACT_BE_U_2(cfm_tlv_header
->length
);
557 ND_PRINT(", length %u", cfm_tlv_len
);
559 tptr
+= sizeof(struct cfm_tlv_header_t
);
560 tlen
-= sizeof(struct cfm_tlv_header_t
);
563 /* do we have the full tlv ? */
564 if (tlen
< cfm_tlv_len
)
566 ND_TCHECK_LEN(tptr
, cfm_tlv_len
);
569 switch(cfm_tlv_type
) {
570 case CFM_TLV_PORT_STATUS
:
571 if (cfm_tlv_len
< 1) {
572 ND_PRINT(" (too short, must be >= 1)");
575 ND_PRINT(", Status: %s (%u)",
576 tok2str(cfm_tlv_port_status_values
, "Unknown", EXTRACT_U_1(tptr
)),
580 case CFM_TLV_INTERFACE_STATUS
:
581 if (cfm_tlv_len
< 1) {
582 ND_PRINT(" (too short, must be >= 1)");
585 ND_PRINT(", Status: %s (%u)",
586 tok2str(cfm_tlv_interface_status_values
, "Unknown", EXTRACT_U_1(tptr
)),
590 case CFM_TLV_PRIVATE
:
591 if (cfm_tlv_len
< 4) {
592 ND_PRINT(" (too short, must be >= 4)");
595 ND_PRINT(", Vendor: %s (%u), Sub-Type %u",
596 tok2str(oui_values
,"Unknown", EXTRACT_BE_U_3(tptr
)),
597 EXTRACT_BE_U_3(tptr
),
598 EXTRACT_U_1(tptr
+ 3));
602 case CFM_TLV_SENDER_ID
:
604 u_int chassis_id_type
, chassis_id_length
;
605 u_int mgmt_addr_length
;
607 if (cfm_tlv_len
< 1) {
608 ND_PRINT(" (too short, must be >= 1)");
613 * Get the Chassis ID length and check it.
614 * IEEE 802.1Q-2014 Section 21.5.3.1
616 chassis_id_length
= EXTRACT_U_1(tptr
);
621 if (chassis_id_length
) {
623 * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references
624 * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently
625 * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype
627 if (cfm_tlv_len
< 1) {
628 ND_PRINT("\n\t (TLV too short)");
631 chassis_id_type
= EXTRACT_U_1(tptr
);
633 ND_PRINT("\n\t Chassis-ID Type %s (%u), Chassis-ID length %u",
634 tok2str(cfm_tlv_senderid_chassisid_values
,
640 if (cfm_tlv_len
< chassis_id_length
) {
641 ND_PRINT("\n\t (TLV too short)");
645 /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */
646 switch (chassis_id_type
) {
647 case CFM_CHASSIS_ID_MAC_ADDRESS
:
648 if (chassis_id_length
!= MAC_ADDR_LEN
) {
649 ND_PRINT(" (invalid MAC address length)");
653 ND_PRINT("\n\t MAC %s", etheraddr_string(ndo
, tptr
+ 1));
656 case CFM_CHASSIS_ID_NETWORK_ADDRESS
:
657 hexdump
|= cfm_network_addr_print(ndo
, tptr
+ 1, chassis_id_length
);
660 case CFM_CHASSIS_ID_INTERFACE_NAME
: /* fall through */
661 case CFM_CHASSIS_ID_INTERFACE_ALIAS
:
662 case CFM_CHASSIS_ID_LOCAL
:
663 case CFM_CHASSIS_ID_CHASSIS_COMPONENT
:
664 case CFM_CHASSIS_ID_PORT_COMPONENT
:
665 (void)nd_printzp(ndo
, tptr
+ 1, chassis_id_length
, NULL
);
672 cfm_tlv_len
-= chassis_id_length
;
674 tptr
+= 1 + chassis_id_length
;
675 tlen
-= 1 + chassis_id_length
;
679 * Check if there is a Management Address.
680 * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length
681 * This and all subsequent fields are not present if the TLV length
682 * allows only the above fields.
684 if (cfm_tlv_len
== 0) {
685 /* No, there isn't; we're done. */
689 /* Here mgmt_addr_length stands for the management domain length. */
690 mgmt_addr_length
= EXTRACT_U_1(tptr
);
694 ND_PRINT("\n\t Management Address Domain Length %u", mgmt_addr_length
);
695 if (mgmt_addr_length
) {
696 /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */
697 if (cfm_tlv_len
< mgmt_addr_length
) {
698 ND_PRINT("\n\t (TLV too short)");
701 cfm_tlv_len
-= mgmt_addr_length
;
703 * XXX - this is an OID; print it as such.
705 hex_print(ndo
, "\n\t Management Address Domain: ", tptr
, mgmt_addr_length
);
706 tptr
+= mgmt_addr_length
;
707 tlen
-= mgmt_addr_length
;
710 * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length
711 * This field is present if Management Address Domain Length is not 0.
713 if (cfm_tlv_len
< 1) {
714 ND_PRINT(" (Management Address Length is missing)");
719 /* Here mgmt_addr_length stands for the management address length. */
720 mgmt_addr_length
= EXTRACT_U_1(tptr
);
724 ND_PRINT("\n\t Management Address Length %u", mgmt_addr_length
);
725 if (mgmt_addr_length
) {
726 /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */
727 if (cfm_tlv_len
< mgmt_addr_length
) {
728 ND_PRINT("\n\t (TLV too short)");
731 cfm_tlv_len
-= mgmt_addr_length
;
733 * XXX - this is a TransportDomain; print it as such.
735 hex_print(ndo
, "\n\t Management Address: ", tptr
, mgmt_addr_length
);
736 tptr
+= mgmt_addr_length
;
737 tlen
-= mgmt_addr_length
;
744 * FIXME those are the defined TLVs that lack a decoder
745 * you are welcome to contribute code ;-)
749 case CFM_TLV_REPLY_INGRESS
:
750 case CFM_TLV_REPLY_EGRESS
:
755 /* do we want to see an additional hexdump ? */
756 if (hexdump
|| ndo
->ndo_vflag
> 1)
757 print_unknown_data(ndo
, tlv_ptr
, "\n\t ", cfm_tlv_len
);
766 ND_PRINT("\n\t\t packet is too short");
770 ND_PRINT("%s", tstr
);