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"
31 #include "addrtoname.h"
35 struct cfm_common_header_t
{
36 uint8_t mdlevel_version
;
39 uint8_t first_tlv_offset
;
43 #define CFM_EXTRACT_VERSION(x) (((x)&0x1f))
44 #define CFM_EXTRACT_MD_LEVEL(x) (((x)&0xe0)>>5)
46 #define CFM_OPCODE_CCM 1
47 #define CFM_OPCODE_LBR 2
48 #define CFM_OPCODE_LBM 3
49 #define CFM_OPCODE_LTR 4
50 #define CFM_OPCODE_LTM 5
52 static const struct tok cfm_opcode_values
[] = {
53 { CFM_OPCODE_CCM
, "Continouity Check Message"},
54 { CFM_OPCODE_LBR
, "Loopback Reply"},
55 { CFM_OPCODE_LBM
, "Loopback Message"},
56 { CFM_OPCODE_LTR
, "Linktrace Reply"},
57 { CFM_OPCODE_LTM
, "Linktrace Message"},
68 uint8_t itu_t_y_1731
[16];
72 * Timer Bases for the CCM Interval field.
73 * Expressed in units of seconds.
75 static const float ccm_interval_base
[8] = {0, 0.003333, 0.01, 0.1, 1, 10, 60, 600};
76 #define CCM_INTERVAL_MIN_MULTIPLIER 3.25
77 #define CCM_INTERVAL_MAX_MULTIPLIER 3.5
79 #define CFM_CCM_RDI_FLAG 0x80
80 #define CFM_EXTRACT_CCM_INTERVAL(x) (((x)&0x07))
82 #define CFM_CCM_MD_FORMAT_8021 0
83 #define CFM_CCM_MD_FORMAT_NONE 1
84 #define CFM_CCM_MD_FORMAT_DNS 2
85 #define CFM_CCM_MD_FORMAT_MAC 3
86 #define CFM_CCM_MD_FORMAT_CHAR 4
88 static const struct tok cfm_md_nameformat_values
[] = {
89 { CFM_CCM_MD_FORMAT_8021
, "IEEE 802.1"},
90 { CFM_CCM_MD_FORMAT_NONE
, "No MD Name present"},
91 { CFM_CCM_MD_FORMAT_DNS
, "DNS string"},
92 { CFM_CCM_MD_FORMAT_MAC
, "MAC + 16Bit Integer"},
93 { CFM_CCM_MD_FORMAT_CHAR
, "Character string"},
97 #define CFM_CCM_MA_FORMAT_8021 0
98 #define CFM_CCM_MA_FORMAT_VID 1
99 #define CFM_CCM_MA_FORMAT_CHAR 2
100 #define CFM_CCM_MA_FORMAT_INT 3
101 #define CFM_CCM_MA_FORMAT_VPN 4
103 static const struct tok cfm_ma_nameformat_values
[] = {
104 { CFM_CCM_MA_FORMAT_8021
, "IEEE 802.1"},
105 { CFM_CCM_MA_FORMAT_VID
, "Primary VID"},
106 { CFM_CCM_MA_FORMAT_CHAR
, "Character string"},
107 { CFM_CCM_MA_FORMAT_INT
, "16Bit Integer"},
108 { CFM_CCM_MA_FORMAT_VPN
, "RFC2685 VPN-ID"},
113 uint8_t transaction_id
[4];
117 uint8_t transaction_id
[4];
119 uint8_t original_mac
[ETHER_ADDR_LEN
];
120 uint8_t target_mac
[ETHER_ADDR_LEN
];
123 static const struct tok cfm_ltm_flag_values
[] = {
124 { 0x80, "Use Forwarding-DB only"},
129 uint8_t transaction_id
[4];
131 uint8_t replay_action
;
134 static const struct tok cfm_ltr_flag_values
[] = {
135 { 0x80, "UseFDB Only"},
137 { 0x20, "Terminal MEP"},
141 static const struct tok cfm_ltr_replay_action_values
[] = {
143 { 2, "Filtering DB"},
149 #define CFM_TLV_END 0
150 #define CFM_TLV_SENDER_ID 1
151 #define CFM_TLV_PORT_STATUS 2
152 #define CFM_TLV_INTERFACE_STATUS 3
153 #define CFM_TLV_DATA 4
154 #define CFM_TLV_REPLY_INGRESS 5
155 #define CFM_TLV_REPLY_EGRESS 6
156 #define CFM_TLV_PRIVATE 31
158 static const struct tok cfm_tlv_values
[] = {
159 { CFM_TLV_END
, "End"},
160 { CFM_TLV_SENDER_ID
, "Sender ID"},
161 { CFM_TLV_PORT_STATUS
, "Port status"},
162 { CFM_TLV_INTERFACE_STATUS
, "Interface status"},
163 { CFM_TLV_DATA
, "Data"},
164 { CFM_TLV_REPLY_INGRESS
, "Reply Ingress"},
165 { CFM_TLV_REPLY_EGRESS
, "Reply Egress"},
166 { CFM_TLV_PRIVATE
, "Organization Specific"},
174 struct cfm_tlv_header_t
{
179 /* FIXME define TLV formats */
181 static const struct tok cfm_tlv_port_status_values
[] = {
187 static const struct tok cfm_tlv_interface_status_values
[] = {
193 { 7, "lower Layer down"},
197 #define CFM_CHASSIS_ID_CHASSIS_COMPONENT 1
198 #define CFM_CHASSIS_ID_INTERFACE_ALIAS 2
199 #define CFM_CHASSIS_ID_PORT_COMPONENT 3
200 #define CFM_CHASSIS_ID_MAC_ADDRESS 4
201 #define CFM_CHASSIS_ID_NETWORK_ADDRESS 5
202 #define CFM_CHASSIS_ID_INTERFACE_NAME 6
203 #define CFM_CHASSIS_ID_LOCAL 7
205 static const struct tok cfm_tlv_senderid_chassisid_values
[] = {
207 { CFM_CHASSIS_ID_CHASSIS_COMPONENT
, "Chassis component"},
208 { CFM_CHASSIS_ID_INTERFACE_ALIAS
, "Interface alias"},
209 { CFM_CHASSIS_ID_PORT_COMPONENT
, "Port component"},
210 { CFM_CHASSIS_ID_MAC_ADDRESS
, "MAC address"},
211 { CFM_CHASSIS_ID_NETWORK_ADDRESS
, "Network address"},
212 { CFM_CHASSIS_ID_INTERFACE_NAME
, "Interface name"},
213 { CFM_CHASSIS_ID_LOCAL
, "Locally assigned"},
219 cfm_network_addr_print(netdissect_options
*ndo
,
220 register const u_char
*tptr
, const u_int length
)
222 u_int network_addr_type
;
223 u_int hexdump
= FALSE
;
226 * Altough AFIs are tpically 2 octects wide,
227 * 802.1ab specifies that this field width
231 ND_PRINT((ndo
, "\n\t Network Address Type (invalid, no data"));
234 /* The calling function must make any due ND_TCHECK calls. */
235 network_addr_type
= *tptr
;
236 ND_PRINT((ndo
, "\n\t Network Address Type %s (%u)",
237 tok2str(af_values
, "Unknown", network_addr_type
),
241 * Resolve the passed in Address.
243 switch(network_addr_type
) {
245 if (length
!= 1 + 4) {
246 ND_PRINT((ndo
, "(invalid IPv4 address length %u)", length
- 1));
250 ND_PRINT((ndo
, ", %s", ipaddr_string(ndo
, tptr
+ 1)));
254 if (length
!= 1 + 16) {
255 ND_PRINT((ndo
, "(invalid IPv6 address length %u)", length
- 1));
259 ND_PRINT((ndo
, ", %s", ip6addr_string(ndo
, tptr
+ 1)));
271 cfm_print(netdissect_options
*ndo
,
272 register const u_char
*pptr
, register u_int length
)
274 const struct cfm_common_header_t
*cfm_common_header
;
275 const struct cfm_tlv_header_t
*cfm_tlv_header
;
276 const uint8_t *tptr
, *tlv_ptr
;
277 const uint8_t *namesp
;
278 u_int names_data_remaining
;
279 uint8_t md_nameformat
, md_namelength
;
280 const uint8_t *md_name
;
281 uint8_t ma_nameformat
, ma_namelength
;
282 const uint8_t *ma_name
;
283 u_int hexdump
, tlen
, cfm_tlv_len
, cfm_tlv_type
, ccm_interval
;
287 const struct cfm_ccm_t
*cfm_ccm
;
288 const struct cfm_lbm_t
*cfm_lbm
;
289 const struct cfm_ltm_t
*cfm_ltm
;
290 const struct cfm_ltr_t
*cfm_ltr
;
294 cfm_common_header
= (const struct cfm_common_header_t
*)pptr
;
295 if (length
< sizeof(*cfm_common_header
))
297 ND_TCHECK(*cfm_common_header
);
300 * Sanity checking of the header.
302 if (CFM_EXTRACT_VERSION(cfm_common_header
->mdlevel_version
) != CFM_VERSION
) {
303 ND_PRINT((ndo
, "CFMv%u not supported, length %u",
304 CFM_EXTRACT_VERSION(cfm_common_header
->mdlevel_version
), length
));
308 ND_PRINT((ndo
, "CFMv%u %s, MD Level %u, length %u",
309 CFM_EXTRACT_VERSION(cfm_common_header
->mdlevel_version
),
310 tok2str(cfm_opcode_values
, "unknown (%u)", cfm_common_header
->opcode
),
311 CFM_EXTRACT_MD_LEVEL(cfm_common_header
->mdlevel_version
),
315 * In non-verbose mode just print the opcode and md-level.
317 if (ndo
->ndo_vflag
< 1) {
321 ND_PRINT((ndo
, "\n\tFirst TLV offset %u", cfm_common_header
->first_tlv_offset
));
323 tptr
+= sizeof(const struct cfm_common_header_t
);
324 tlen
= length
- sizeof(struct cfm_common_header_t
);
327 * Sanity check the first TLV offset.
329 if (cfm_common_header
->first_tlv_offset
> tlen
) {
330 ND_PRINT((ndo
, " (too large, must be <= %u)", tlen
));
334 switch (cfm_common_header
->opcode
) {
336 msg_ptr
.cfm_ccm
= (const struct cfm_ccm_t
*)tptr
;
337 if (cfm_common_header
->first_tlv_offset
< sizeof(*msg_ptr
.cfm_ccm
)) {
338 ND_PRINT((ndo
, " (too small 1, must be >= %lu)",
339 (unsigned long) sizeof(*msg_ptr
.cfm_ccm
)));
342 if (tlen
< sizeof(*msg_ptr
.cfm_ccm
))
344 ND_TCHECK(*msg_ptr
.cfm_ccm
);
346 ccm_interval
= CFM_EXTRACT_CCM_INTERVAL(cfm_common_header
->flags
);
347 ND_PRINT((ndo
, ", Flags [CCM Interval %u%s]",
349 cfm_common_header
->flags
& CFM_CCM_RDI_FLAG
?
353 * Resolve the CCM interval field.
356 ND_PRINT((ndo
, "\n\t CCM Interval %.3fs"
357 ", min CCM Lifetime %.3fs, max CCM Lifetime %.3fs",
358 ccm_interval_base
[ccm_interval
],
359 ccm_interval_base
[ccm_interval
] * CCM_INTERVAL_MIN_MULTIPLIER
,
360 ccm_interval_base
[ccm_interval
] * CCM_INTERVAL_MAX_MULTIPLIER
));
363 ND_PRINT((ndo
, "\n\t Sequence Number 0x%08x, MA-End-Point-ID 0x%04x",
364 EXTRACT_32BITS(msg_ptr
.cfm_ccm
->sequence
),
365 EXTRACT_16BITS(msg_ptr
.cfm_ccm
->ma_epi
)));
367 namesp
= msg_ptr
.cfm_ccm
->names
;
368 names_data_remaining
= sizeof(msg_ptr
.cfm_ccm
->names
);
371 * Resolve the MD fields.
373 md_nameformat
= *namesp
;
375 names_data_remaining
--; /* We know this is != 0 */
376 if (md_nameformat
!= CFM_CCM_MD_FORMAT_NONE
) {
377 md_namelength
= *namesp
;
379 names_data_remaining
--; /* We know this is !=0 */
380 ND_PRINT((ndo
, "\n\t MD Name Format %s (%u), MD Name length %u",
381 tok2str(cfm_md_nameformat_values
, "Unknown",
387 * -3 for the MA short name format and length and one byte
390 if (md_namelength
> names_data_remaining
- 3) {
391 ND_PRINT((ndo
, " (too large, must be <= %u)", names_data_remaining
- 2));
396 ND_PRINT((ndo
, "\n\t MD Name: "));
397 switch (md_nameformat
) {
398 case CFM_CCM_MD_FORMAT_DNS
:
399 case CFM_CCM_MD_FORMAT_CHAR
:
400 safeputs(ndo
, md_name
, md_namelength
);
403 case CFM_CCM_MD_FORMAT_MAC
:
404 if (md_namelength
== 6) {
405 ND_PRINT((ndo
, "\n\t MAC %s", etheraddr_string(ndo
,
408 ND_PRINT((ndo
, "\n\t MAC (length invalid)"));
412 /* FIXME add printers for those MD formats - hexdump for now */
413 case CFM_CCM_MA_FORMAT_8021
:
415 print_unknown_data(ndo
, md_name
, "\n\t ",
418 namesp
+= md_namelength
;
419 names_data_remaining
-= md_namelength
;
421 ND_PRINT((ndo
, "\n\t MD Name Format %s (%u)",
422 tok2str(cfm_md_nameformat_values
, "Unknown",
429 * Resolve the MA fields.
431 ma_nameformat
= *namesp
;
433 names_data_remaining
--; /* We know this is != 0 */
434 ma_namelength
= *namesp
;
436 names_data_remaining
--; /* We know this is != 0 */
437 ND_PRINT((ndo
, "\n\t MA Name-Format %s (%u), MA name length %u",
438 tok2str(cfm_ma_nameformat_values
, "Unknown",
443 if (ma_namelength
> names_data_remaining
) {
444 ND_PRINT((ndo
, " (too large, must be <= %u)", names_data_remaining
));
449 ND_PRINT((ndo
, "\n\t MA Name: "));
450 switch (ma_nameformat
) {
451 case CFM_CCM_MA_FORMAT_CHAR
:
452 safeputs(ndo
, ma_name
, ma_namelength
);
455 /* FIXME add printers for those MA formats - hexdump for now */
456 case CFM_CCM_MA_FORMAT_8021
:
457 case CFM_CCM_MA_FORMAT_VID
:
458 case CFM_CCM_MA_FORMAT_INT
:
459 case CFM_CCM_MA_FORMAT_VPN
:
461 print_unknown_data(ndo
, ma_name
, "\n\t ", ma_namelength
);
466 msg_ptr
.cfm_ltm
= (const struct cfm_ltm_t
*)tptr
;
467 if (cfm_common_header
->first_tlv_offset
< sizeof(*msg_ptr
.cfm_ltm
)) {
468 ND_PRINT((ndo
, " (too small 4, must be >= %lu)",
469 (unsigned long) sizeof(*msg_ptr
.cfm_ltm
)));
472 if (tlen
< sizeof(*msg_ptr
.cfm_ltm
))
474 ND_TCHECK(*msg_ptr
.cfm_ltm
);
476 ND_PRINT((ndo
, ", Flags [%s]",
477 bittok2str(cfm_ltm_flag_values
, "none", cfm_common_header
->flags
)));
479 ND_PRINT((ndo
, "\n\t Transaction-ID 0x%08x, ttl %u",
480 EXTRACT_32BITS(msg_ptr
.cfm_ltm
->transaction_id
),
481 msg_ptr
.cfm_ltm
->ttl
));
483 ND_PRINT((ndo
, "\n\t Original-MAC %s, Target-MAC %s",
484 etheraddr_string(ndo
, msg_ptr
.cfm_ltm
->original_mac
),
485 etheraddr_string(ndo
, msg_ptr
.cfm_ltm
->target_mac
)));
489 msg_ptr
.cfm_ltr
= (const struct cfm_ltr_t
*)tptr
;
490 if (cfm_common_header
->first_tlv_offset
< sizeof(*msg_ptr
.cfm_ltr
)) {
491 ND_PRINT((ndo
, " (too small 5, must be >= %lu)",
492 (unsigned long) sizeof(*msg_ptr
.cfm_ltr
)));
495 if (tlen
< sizeof(*msg_ptr
.cfm_ltr
))
497 ND_TCHECK(*msg_ptr
.cfm_ltr
);
499 ND_PRINT((ndo
, ", Flags [%s]",
500 bittok2str(cfm_ltr_flag_values
, "none", cfm_common_header
->flags
)));
502 ND_PRINT((ndo
, "\n\t Transaction-ID 0x%08x, ttl %u",
503 EXTRACT_32BITS(msg_ptr
.cfm_ltr
->transaction_id
),
504 msg_ptr
.cfm_ltr
->ttl
));
506 ND_PRINT((ndo
, "\n\t Replay-Action %s (%u)",
507 tok2str(cfm_ltr_replay_action_values
,
509 msg_ptr
.cfm_ltr
->replay_action
),
510 msg_ptr
.cfm_ltr
->replay_action
));
514 * No message decoder yet.
515 * Hexdump everything up until the start of the TLVs
520 print_unknown_data(ndo
, tptr
, "\n\t ",
521 tlen
- cfm_common_header
->first_tlv_offset
);
525 tptr
+= cfm_common_header
->first_tlv_offset
;
526 tlen
-= cfm_common_header
->first_tlv_offset
;
529 cfm_tlv_header
= (const struct cfm_tlv_header_t
*)tptr
;
531 /* Enough to read the tlv type ? */
532 ND_TCHECK2(*tptr
, 1);
533 cfm_tlv_type
=cfm_tlv_header
->type
;
535 ND_PRINT((ndo
, "\n\t%s TLV (0x%02x)",
536 tok2str(cfm_tlv_values
, "Unknown", cfm_tlv_type
),
539 if (cfm_tlv_type
== CFM_TLV_END
) {
540 /* Length is "Not present if the Type field is 0." */
544 /* do we have the full tlv header ? */
545 if (tlen
< sizeof(struct cfm_tlv_header_t
))
547 ND_TCHECK2(*tptr
, sizeof(struct cfm_tlv_header_t
));
548 cfm_tlv_len
=EXTRACT_16BITS(&cfm_tlv_header
->length
);
550 ND_PRINT((ndo
, ", length %u", cfm_tlv_len
));
552 tptr
+= sizeof(struct cfm_tlv_header_t
);
553 tlen
-= sizeof(struct cfm_tlv_header_t
);
556 /* do we have the full tlv ? */
557 if (tlen
< cfm_tlv_len
)
559 ND_TCHECK2(*tptr
, cfm_tlv_len
);
562 switch(cfm_tlv_type
) {
563 case CFM_TLV_PORT_STATUS
:
564 if (cfm_tlv_len
< 1) {
565 ND_PRINT((ndo
, " (too short, must be >= 1)"));
568 ND_PRINT((ndo
, ", Status: %s (%u)",
569 tok2str(cfm_tlv_port_status_values
, "Unknown", *tptr
),
573 case CFM_TLV_INTERFACE_STATUS
:
574 if (cfm_tlv_len
< 1) {
575 ND_PRINT((ndo
, " (too short, must be >= 1)"));
578 ND_PRINT((ndo
, ", Status: %s (%u)",
579 tok2str(cfm_tlv_interface_status_values
, "Unknown", *tptr
),
583 case CFM_TLV_PRIVATE
:
584 if (cfm_tlv_len
< 4) {
585 ND_PRINT((ndo
, " (too short, must be >= 4)"));
588 ND_PRINT((ndo
, ", Vendor: %s (%u), Sub-Type %u",
589 tok2str(oui_values
,"Unknown", EXTRACT_24BITS(tptr
)),
590 EXTRACT_24BITS(tptr
),
595 case CFM_TLV_SENDER_ID
:
597 u_int chassis_id_type
, chassis_id_length
;
598 u_int mgmt_addr_length
;
600 if (cfm_tlv_len
< 1) {
601 ND_PRINT((ndo
, " (too short, must be >= 1)"));
606 * Get the Chassis ID length and check it.
607 * IEEE 802.1Q-2014 Section 21.5.3.1
609 chassis_id_length
= *tptr
;
614 if (chassis_id_length
) {
616 * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references
617 * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently
618 * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype
620 if (cfm_tlv_len
< 1) {
621 ND_PRINT((ndo
, "\n\t (TLV too short)"));
624 chassis_id_type
= *tptr
;
626 ND_PRINT((ndo
, "\n\t Chassis-ID Type %s (%u), Chassis-ID length %u",
627 tok2str(cfm_tlv_senderid_chassisid_values
,
633 if (cfm_tlv_len
< chassis_id_length
) {
634 ND_PRINT((ndo
, "\n\t (TLV too short)"));
638 /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */
639 switch (chassis_id_type
) {
640 case CFM_CHASSIS_ID_MAC_ADDRESS
:
641 if (chassis_id_length
!= ETHER_ADDR_LEN
) {
642 ND_PRINT((ndo
, " (invalid MAC address length)"));
646 ND_PRINT((ndo
, "\n\t MAC %s", etheraddr_string(ndo
, tptr
+ 1)));
649 case CFM_CHASSIS_ID_NETWORK_ADDRESS
:
650 hexdump
|= cfm_network_addr_print(ndo
, tptr
+ 1, chassis_id_length
);
653 case CFM_CHASSIS_ID_INTERFACE_NAME
: /* fall through */
654 case CFM_CHASSIS_ID_INTERFACE_ALIAS
:
655 case CFM_CHASSIS_ID_LOCAL
:
656 case CFM_CHASSIS_ID_CHASSIS_COMPONENT
:
657 case CFM_CHASSIS_ID_PORT_COMPONENT
:
658 safeputs(ndo
, tptr
+ 1, chassis_id_length
);
665 cfm_tlv_len
-= chassis_id_length
;
667 tptr
+= 1 + chassis_id_length
;
668 tlen
-= 1 + chassis_id_length
;
672 * Check if there is a Management Address.
673 * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length
674 * This and all subsequent fields are not present if the TLV length
675 * allows only the above fields.
677 if (cfm_tlv_len
== 0) {
678 /* No, there isn't; we're done. */
682 /* Here mgmt_addr_length stands for the management domain length. */
683 mgmt_addr_length
= *tptr
;
687 ND_PRINT((ndo
, "\n\t Management Address Domain Length %u", mgmt_addr_length
));
688 if (mgmt_addr_length
) {
689 /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */
690 if (cfm_tlv_len
< mgmt_addr_length
) {
691 ND_PRINT((ndo
, "\n\t (TLV too short)"));
694 cfm_tlv_len
-= mgmt_addr_length
;
696 * XXX - this is an OID; print it as such.
698 hex_print(ndo
, "\n\t Management Address Domain: ", tptr
, mgmt_addr_length
);
699 tptr
+= mgmt_addr_length
;
700 tlen
-= mgmt_addr_length
;
703 * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length
704 * This field is present if Management Address Domain Length is not 0.
706 if (cfm_tlv_len
< 1) {
707 ND_PRINT((ndo
, " (Management Address Length is missing)"));
712 /* Here mgmt_addr_length stands for the management address length. */
713 mgmt_addr_length
= *tptr
;
717 ND_PRINT((ndo
, "\n\t Management Address Length %u", mgmt_addr_length
));
718 if (mgmt_addr_length
) {
719 /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */
720 if (cfm_tlv_len
< mgmt_addr_length
) {
721 ND_PRINT((ndo
, "\n\t (TLV too short)"));
724 cfm_tlv_len
-= mgmt_addr_length
;
726 * XXX - this is a TransportDomain; print it as such.
728 hex_print(ndo
, "\n\t Management Address: ", tptr
, mgmt_addr_length
);
729 tptr
+= mgmt_addr_length
;
730 tlen
-= mgmt_addr_length
;
737 * FIXME those are the defined TLVs that lack a decoder
738 * you are welcome to contribute code ;-)
742 case CFM_TLV_REPLY_INGRESS
:
743 case CFM_TLV_REPLY_EGRESS
:
748 /* do we want to see an additional hexdump ? */
749 if (hexdump
|| ndo
->ndo_vflag
> 1)
750 print_unknown_data(ndo
, tlv_ptr
, "\n\t ", cfm_tlv_len
);
759 ND_PRINT((ndo
, "\n\t\t packet is too short"));
763 ND_PRINT((ndo
, "\n\t\t packet exceeded snapshot"));