xref: /netbsd-src/external/bsd/tcpdump/dist/print-ldp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Redistribution and use in source and binary forms, with or without
30f74e101Schristos  * modification, are permitted provided that: (1) source code
40f74e101Schristos  * distributions retain the above copyright notice and this paragraph
50f74e101Schristos  * in its entirety, and (2) distributions including binary code include
60f74e101Schristos  * the above copyright notice and this paragraph in its entirety in
70f74e101Schristos  * the documentation or other materials provided with the distribution.
80f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
90f74e101Schristos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
100f74e101Schristos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
110f74e101Schristos  * FOR A PARTICULAR PURPOSE.
120f74e101Schristos  *
1372c96ff3Schristos  * Original code by Hannes Gredler (hannes@gredler.at)
140f74e101Schristos  *  and Steinar Haug (sthaug@nethelp.no)
150f74e101Schristos  */
160f74e101Schristos 
1711b3aaa1Schristos #include <sys/cdefs.h>
180f74e101Schristos #ifndef lint
19*26ba0b50Schristos __RCSID("$NetBSD: print-ldp.c,v 1.12 2024/09/02 16:15:31 christos Exp $");
200f74e101Schristos #endif
210f74e101Schristos 
22dc860a36Sspz /* \summary: Label Distribution Protocol (LDP) printer */
23dc860a36Sspz 
24c74ad251Schristos #include <config.h>
250f74e101Schristos 
26c74ad251Schristos #include "netdissect-stdinc.h"
270f74e101Schristos 
28fdccd7e4Schristos #include "netdissect.h"
290f74e101Schristos #include "extract.h"
300f74e101Schristos #include "addrtoname.h"
310f74e101Schristos 
320f74e101Schristos #include "l2vpn.h"
330f74e101Schristos #include "af.h"
340f74e101Schristos 
35817e9a7eSchristos 
360f74e101Schristos /*
370f74e101Schristos  * ldp common header
380f74e101Schristos  *
390f74e101Schristos  *  0                   1                   2                   3
400f74e101Schristos  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
410f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
420f74e101Schristos  * |  Version                      |         PDU Length            |
430f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
440f74e101Schristos  * |                         LDP Identifier                        |
450f74e101Schristos  * +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460f74e101Schristos  * |                               |
470f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
480f74e101Schristos  *
490f74e101Schristos  */
500f74e101Schristos 
510f74e101Schristos struct ldp_common_header {
52c74ad251Schristos     nd_uint16_t version;
53c74ad251Schristos     nd_uint16_t pdu_length;
54c74ad251Schristos     nd_ipv4     lsr_id;
55c74ad251Schristos     nd_uint16_t label_space;
560f74e101Schristos };
570f74e101Schristos 
580f74e101Schristos #define LDP_VERSION 1
590f74e101Schristos 
600f74e101Schristos /*
610f74e101Schristos  * ldp message header
620f74e101Schristos  *
630f74e101Schristos  *  0                   1                   2                   3
640f74e101Schristos  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
650f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
660f74e101Schristos  * |U|   Message Type              |      Message Length           |
670f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
680f74e101Schristos  * |                     Message ID                                |
690f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
700f74e101Schristos  * |                                                               |
710f74e101Schristos  * +                                                               +
720f74e101Schristos  * |                     Mandatory Parameters                      |
730f74e101Schristos  * +                                                               +
740f74e101Schristos  * |                                                               |
750f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
760f74e101Schristos  * |                                                               |
770f74e101Schristos  * +                                                               +
780f74e101Schristos  * |                     Optional Parameters                       |
790f74e101Schristos  * +                                                               +
800f74e101Schristos  * |                                                               |
810f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
820f74e101Schristos  */
830f74e101Schristos 
840f74e101Schristos struct ldp_msg_header {
85c74ad251Schristos     nd_uint16_t type;
86c74ad251Schristos     nd_uint16_t length;
87c74ad251Schristos     nd_uint32_t id;
880f74e101Schristos };
890f74e101Schristos 
900f74e101Schristos #define	LDP_MASK_MSG_TYPE(x)  ((x)&0x7fff)
910f74e101Schristos #define	LDP_MASK_U_BIT(x)     ((x)&0x8000)
920f74e101Schristos 
930f74e101Schristos #define	LDP_MSG_NOTIF                0x0001
940f74e101Schristos #define	LDP_MSG_HELLO                0x0100
950f74e101Schristos #define	LDP_MSG_INIT                 0x0200
960f74e101Schristos #define	LDP_MSG_KEEPALIVE            0x0201
970f74e101Schristos #define	LDP_MSG_ADDRESS              0x0300
980f74e101Schristos #define	LDP_MSG_ADDRESS_WITHDRAW     0x0301
990f74e101Schristos #define	LDP_MSG_LABEL_MAPPING        0x0400
1000f74e101Schristos #define	LDP_MSG_LABEL_REQUEST        0x0401
1010f74e101Schristos #define	LDP_MSG_LABEL_WITHDRAW       0x0402
1020f74e101Schristos #define	LDP_MSG_LABEL_RELEASE        0x0403
1030f74e101Schristos #define	LDP_MSG_LABEL_ABORT_REQUEST  0x0404
1040f74e101Schristos 
1050f74e101Schristos #define	LDP_VENDOR_PRIVATE_MIN       0x3e00
1060f74e101Schristos #define	LDP_VENDOR_PRIVATE_MAX       0x3eff
1070f74e101Schristos #define	LDP_EXPERIMENTAL_MIN         0x3f00
1080f74e101Schristos #define	LDP_EXPERIMENTAL_MAX         0x3fff
1090f74e101Schristos 
1100f74e101Schristos static const struct tok ldp_msg_values[] = {
1110f74e101Schristos     { LDP_MSG_NOTIF,	             "Notification" },
1120f74e101Schristos     { LDP_MSG_HELLO,	             "Hello" },
1130f74e101Schristos     { LDP_MSG_INIT,	             "Initialization" },
1140f74e101Schristos     { LDP_MSG_KEEPALIVE,             "Keepalive" },
1150f74e101Schristos     { LDP_MSG_ADDRESS,	             "Address" },
1160f74e101Schristos     { LDP_MSG_ADDRESS_WITHDRAW,	     "Address Withdraw" },
1170f74e101Schristos     { LDP_MSG_LABEL_MAPPING,	     "Label Mapping" },
1180f74e101Schristos     { LDP_MSG_LABEL_REQUEST,	     "Label Request" },
1190f74e101Schristos     { LDP_MSG_LABEL_WITHDRAW,	     "Label Withdraw" },
1200f74e101Schristos     { LDP_MSG_LABEL_RELEASE,	     "Label Release" },
1210f74e101Schristos     { LDP_MSG_LABEL_ABORT_REQUEST,   "Label Abort Request" },
1220f74e101Schristos     { 0, NULL}
1230f74e101Schristos };
1240f74e101Schristos 
1250f74e101Schristos #define	LDP_MASK_TLV_TYPE(x)  ((x)&0x3fff)
1260f74e101Schristos #define	LDP_MASK_F_BIT(x) ((x)&0x4000)
1270f74e101Schristos 
1280f74e101Schristos #define	LDP_TLV_FEC                  0x0100
1290f74e101Schristos #define	LDP_TLV_ADDRESS_LIST         0x0101
1300f74e101Schristos #define LDP_TLV_ADDRESS_LIST_AFNUM_LEN 2
1310f74e101Schristos #define	LDP_TLV_HOP_COUNT            0x0103
1320f74e101Schristos #define	LDP_TLV_PATH_VECTOR          0x0104
1330f74e101Schristos #define	LDP_TLV_GENERIC_LABEL        0x0200
1340f74e101Schristos #define	LDP_TLV_ATM_LABEL            0x0201
1350f74e101Schristos #define	LDP_TLV_FR_LABEL             0x0202
1360f74e101Schristos #define	LDP_TLV_STATUS               0x0300
1370f74e101Schristos #define	LDP_TLV_EXTD_STATUS          0x0301
1380f74e101Schristos #define	LDP_TLV_RETURNED_PDU         0x0302
1390f74e101Schristos #define	LDP_TLV_RETURNED_MSG         0x0303
1400f74e101Schristos #define	LDP_TLV_COMMON_HELLO         0x0400
1410f74e101Schristos #define	LDP_TLV_IPV4_TRANSPORT_ADDR  0x0401
1420f74e101Schristos #define	LDP_TLV_CONFIG_SEQ_NUMBER    0x0402
1430f74e101Schristos #define	LDP_TLV_IPV6_TRANSPORT_ADDR  0x0403
1440f74e101Schristos #define	LDP_TLV_COMMON_SESSION       0x0500
1450f74e101Schristos #define	LDP_TLV_ATM_SESSION_PARM     0x0501
1460f74e101Schristos #define	LDP_TLV_FR_SESSION_PARM      0x0502
1470f74e101Schristos #define LDP_TLV_FT_SESSION	     0x0503
1480f74e101Schristos #define	LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
1490f74e101Schristos #define LDP_TLV_MTU                  0x0601 /* rfc 3988 */
1500f74e101Schristos 
1510f74e101Schristos static const struct tok ldp_tlv_values[] = {
1520f74e101Schristos     { LDP_TLV_FEC,	             "FEC" },
1530f74e101Schristos     { LDP_TLV_ADDRESS_LIST,          "Address List" },
1540f74e101Schristos     { LDP_TLV_HOP_COUNT,             "Hop Count" },
1550f74e101Schristos     { LDP_TLV_PATH_VECTOR,           "Path Vector" },
1560f74e101Schristos     { LDP_TLV_GENERIC_LABEL,         "Generic Label" },
1570f74e101Schristos     { LDP_TLV_ATM_LABEL,             "ATM Label" },
1580f74e101Schristos     { LDP_TLV_FR_LABEL,              "Frame-Relay Label" },
1590f74e101Schristos     { LDP_TLV_STATUS,                "Status" },
1600f74e101Schristos     { LDP_TLV_EXTD_STATUS,           "Extended Status" },
1610f74e101Schristos     { LDP_TLV_RETURNED_PDU,          "Returned PDU" },
1620f74e101Schristos     { LDP_TLV_RETURNED_MSG,          "Returned Message" },
1630f74e101Schristos     { LDP_TLV_COMMON_HELLO,          "Common Hello Parameters" },
1640f74e101Schristos     { LDP_TLV_IPV4_TRANSPORT_ADDR,   "IPv4 Transport Address" },
1650f74e101Schristos     { LDP_TLV_CONFIG_SEQ_NUMBER,     "Configuration Sequence Number" },
1660f74e101Schristos     { LDP_TLV_IPV6_TRANSPORT_ADDR,   "IPv6 Transport Address" },
1670f74e101Schristos     { LDP_TLV_COMMON_SESSION,        "Common Session Parameters" },
1680f74e101Schristos     { LDP_TLV_ATM_SESSION_PARM,      "ATM Session Parameters" },
1690f74e101Schristos     { LDP_TLV_FR_SESSION_PARM,       "Frame-Relay Session Parameters" },
1700f74e101Schristos     { LDP_TLV_FT_SESSION,            "Fault-Tolerant Session Parameters" },
1710f74e101Schristos     { LDP_TLV_LABEL_REQUEST_MSG_ID,  "Label Request Message ID" },
1720f74e101Schristos     { LDP_TLV_MTU,                   "MTU" },
1730f74e101Schristos     { 0, NULL}
1740f74e101Schristos };
1750f74e101Schristos 
1760f74e101Schristos #define LDP_FEC_WILDCARD	0x01
1770f74e101Schristos #define LDP_FEC_PREFIX		0x02
1780f74e101Schristos #define LDP_FEC_HOSTADDRESS	0x03
1790e9868baSchristos /* From RFC 4906; should probably be updated to RFC 4447 (e.g., VC -> PW) */
1800f74e101Schristos #define LDP_FEC_MARTINI_VC	0x80
1810f74e101Schristos 
1820f74e101Schristos static const struct tok ldp_fec_values[] = {
1830f74e101Schristos     { LDP_FEC_WILDCARD,		"Wildcard" },
1840f74e101Schristos     { LDP_FEC_PREFIX,		"Prefix" },
1850f74e101Schristos     { LDP_FEC_HOSTADDRESS,	"Host address" },
1860f74e101Schristos     { LDP_FEC_MARTINI_VC,	"Martini VC" },
1870f74e101Schristos     { 0, NULL}
1880f74e101Schristos };
1890f74e101Schristos 
1900f74e101Schristos #define LDP_FEC_MARTINI_IFPARM_MTU  0x01
1910f74e101Schristos #define LDP_FEC_MARTINI_IFPARM_DESC 0x03
1920f74e101Schristos #define LDP_FEC_MARTINI_IFPARM_VCCV 0x0c
1930f74e101Schristos 
1940f74e101Schristos static const struct tok ldp_fec_martini_ifparm_values[] = {
1950f74e101Schristos     { LDP_FEC_MARTINI_IFPARM_MTU, "MTU" },
1960f74e101Schristos     { LDP_FEC_MARTINI_IFPARM_DESC, "Description" },
1970f74e101Schristos     { LDP_FEC_MARTINI_IFPARM_VCCV, "VCCV" },
1980f74e101Schristos     { 0, NULL}
1990f74e101Schristos };
2000f74e101Schristos 
2010f74e101Schristos /* draft-ietf-pwe3-vccv-04.txt */
2020f74e101Schristos static const struct tok ldp_fec_martini_ifparm_vccv_cc_values[] = {
2030f74e101Schristos     { 0x01, "PWE3 control word" },
2040f74e101Schristos     { 0x02, "MPLS Router Alert Label" },
2050f74e101Schristos     { 0x04, "MPLS inner label TTL = 1" },
2060f74e101Schristos     { 0, NULL}
2070f74e101Schristos };
2080f74e101Schristos 
2090f74e101Schristos /* draft-ietf-pwe3-vccv-04.txt */
2100f74e101Schristos static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = {
2110f74e101Schristos     { 0x01, "ICMP Ping" },
2120f74e101Schristos     { 0x02, "LSP Ping" },
2130f74e101Schristos     { 0x04, "BFD" },
2140f74e101Schristos     { 0, NULL}
2150f74e101Schristos };
2160f74e101Schristos 
217c74ad251Schristos static u_int ldp_pdu_print(netdissect_options *, const u_char *);
2180f74e101Schristos 
2190f74e101Schristos /*
2200f74e101Schristos  * ldp tlv header
2210f74e101Schristos  *
2220f74e101Schristos  *  0                   1                   2                   3
2230f74e101Schristos  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2240f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2250f74e101Schristos  * |U|F|        Type               |            Length             |
2260f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2270f74e101Schristos  * |                                                               |
2280f74e101Schristos  * |                             Value                             |
2290f74e101Schristos  * ~                                                               ~
2300f74e101Schristos  * |                                                               |
2310f74e101Schristos  * |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2320f74e101Schristos  * |                               |
2330f74e101Schristos  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2340f74e101Schristos  */
2350f74e101Schristos 
2360e9868baSchristos #define TLV_TCHECK(minlen) \
237c74ad251Schristos     if (tlv_tlen < minlen) { \
238c74ad251Schristos         ND_PRINT(" [tlv length %u < %u]", tlv_tlen, minlen); \
239c74ad251Schristos         nd_print_invalid(ndo); \
240c74ad251Schristos         goto invalid; \
241c74ad251Schristos     }
2420e9868baSchristos 
243c74ad251Schristos static u_int
244b3a00663Schristos ldp_tlv_print(netdissect_options *ndo,
245c74ad251Schristos               const u_char *tptr,
246c74ad251Schristos               u_int msg_tlen)
247ba2ff121Schristos {
2480f74e101Schristos     struct ldp_tlv_header {
249c74ad251Schristos         nd_uint16_t type;
250c74ad251Schristos         nd_uint16_t length;
2510f74e101Schristos     };
2520f74e101Schristos 
2530f74e101Schristos     const struct ldp_tlv_header *ldp_tlv_header;
2540f74e101Schristos     u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags;
2550f74e101Schristos     u_char fec_type;
2560f74e101Schristos     u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx;
2570f74e101Schristos     char buf[100];
2580f74e101Schristos     int i;
2590f74e101Schristos 
2600f74e101Schristos     ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
261c74ad251Schristos     ND_TCHECK_SIZE(ldp_tlv_header);
262c74ad251Schristos     tlv_len=GET_BE_U_2(ldp_tlv_header->length);
263c74ad251Schristos     if (tlv_len + 4U > msg_tlen) {
264c74ad251Schristos         ND_PRINT("\n\t\t TLV contents go past end of message");
265ba2ff121Schristos         return 0;
266ba2ff121Schristos     }
2670f74e101Schristos     tlv_tlen=tlv_len;
268c74ad251Schristos     tlv_type=LDP_MASK_TLV_TYPE(GET_BE_U_2(ldp_tlv_header->type));
2690f74e101Schristos 
2700f74e101Schristos     /* FIXME vendor private / experimental check */
271c74ad251Schristos     ND_PRINT("\n\t    %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
2720f74e101Schristos            tok2str(ldp_tlv_values,
2730f74e101Schristos                    "Unknown",
2740f74e101Schristos                    tlv_type),
2750f74e101Schristos            tlv_type,
2760f74e101Schristos            tlv_len,
277c74ad251Schristos            LDP_MASK_U_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "continue processing" : "ignore",
278c74ad251Schristos            LDP_MASK_F_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "do" : "don't");
2790f74e101Schristos 
2800f74e101Schristos     tptr+=sizeof(struct ldp_tlv_header);
2810f74e101Schristos 
2820f74e101Schristos     switch(tlv_type) {
2830f74e101Schristos 
2840f74e101Schristos     case LDP_TLV_COMMON_HELLO:
2850e9868baSchristos         TLV_TCHECK(4);
286c74ad251Schristos         ND_PRINT("\n\t      Hold Time: %us, Flags: [%s Hello%s]",
287c74ad251Schristos                GET_BE_U_2(tptr),
288c74ad251Schristos                (GET_BE_U_2(tptr + 2)&0x8000) ? "Targeted" : "Link",
289c74ad251Schristos                (GET_BE_U_2(tptr + 2)&0x4000) ? ", Request for targeted Hellos" : "");
2900f74e101Schristos         break;
2910f74e101Schristos 
2920f74e101Schristos     case LDP_TLV_IPV4_TRANSPORT_ADDR:
2930e9868baSchristos         TLV_TCHECK(4);
294c74ad251Schristos         ND_PRINT("\n\t      IPv4 Transport Address: %s", GET_IPADDR_STRING(tptr));
2950f74e101Schristos         break;
2960f74e101Schristos     case LDP_TLV_IPV6_TRANSPORT_ADDR:
2970e9868baSchristos         TLV_TCHECK(16);
298c74ad251Schristos         ND_PRINT("\n\t      IPv6 Transport Address: %s", GET_IP6ADDR_STRING(tptr));
2990f74e101Schristos         break;
3000f74e101Schristos     case LDP_TLV_CONFIG_SEQ_NUMBER:
3010e9868baSchristos         TLV_TCHECK(4);
302c74ad251Schristos         ND_PRINT("\n\t      Sequence Number: %u", GET_BE_U_4(tptr));
3030f74e101Schristos         break;
3040f74e101Schristos 
3050f74e101Schristos     case LDP_TLV_ADDRESS_LIST:
3060e9868baSchristos         TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
307c74ad251Schristos 	af = GET_BE_U_2(tptr);
3080f74e101Schristos 	tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
3090f74e101Schristos         tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
310c74ad251Schristos 	ND_PRINT("\n\t      Address Family: %s, addresses",
311c74ad251Schristos                tok2str(af_values, "Unknown (%u)", af));
3120f74e101Schristos         switch (af) {
3130f74e101Schristos         case AFNUM_INET:
314c74ad251Schristos 	    while(tlv_tlen >= sizeof(nd_ipv4)) {
315c74ad251Schristos 		ND_PRINT(" %s", GET_IPADDR_STRING(tptr));
316c74ad251Schristos 		tlv_tlen-=sizeof(nd_ipv4);
317c74ad251Schristos 		tptr+=sizeof(nd_ipv4);
3180f74e101Schristos 	    }
3190f74e101Schristos             break;
3200f74e101Schristos         case AFNUM_INET6:
321c74ad251Schristos 	    while(tlv_tlen >= sizeof(nd_ipv6)) {
322c74ad251Schristos 		ND_PRINT(" %s", GET_IP6ADDR_STRING(tptr));
323c74ad251Schristos 		tlv_tlen-=sizeof(nd_ipv6);
324c74ad251Schristos 		tptr+=sizeof(nd_ipv6);
3250f74e101Schristos 	    }
3260f74e101Schristos             break;
3270f74e101Schristos         default:
3280f74e101Schristos             /* unknown AF */
3290f74e101Schristos             break;
3300f74e101Schristos         }
3310f74e101Schristos 	break;
3320f74e101Schristos 
3330f74e101Schristos     case LDP_TLV_COMMON_SESSION:
334*26ba0b50Schristos 	TLV_TCHECK(14);
335c74ad251Schristos 	ND_PRINT("\n\t      Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]",
336c74ad251Schristos 	       GET_BE_U_2(tptr), GET_BE_U_2(tptr + 2),
337*26ba0b50Schristos 	       (GET_BE_U_2(tptr + 4)&0x8000) ? "On Demand" : "Unsolicited",
338*26ba0b50Schristos 	       (GET_BE_U_2(tptr + 4)&0x4000) ? "Enabled" : "Disabled"
339*26ba0b50Schristos 	       );
340*26ba0b50Schristos 	ND_PRINT("\n\t      Path Vector Limit %u, Max-PDU length: %u, Receiver Label-Space-ID %s:%u",
341*26ba0b50Schristos 	       GET_U_1(tptr+5),
342*26ba0b50Schristos 	       GET_BE_U_2(tptr+6),
343*26ba0b50Schristos 	       GET_IPADDR_STRING(tptr+8),
344*26ba0b50Schristos 	       GET_BE_U_2(tptr+12)
345c74ad251Schristos 	       );
3460f74e101Schristos 	break;
3470f74e101Schristos 
3480f74e101Schristos     case LDP_TLV_FEC:
3490e9868baSchristos         TLV_TCHECK(1);
350c74ad251Schristos         fec_type = GET_U_1(tptr);
351c74ad251Schristos 	ND_PRINT("\n\t      %s FEC (0x%02x)",
3520f74e101Schristos 	       tok2str(ldp_fec_values, "Unknown", fec_type),
353c74ad251Schristos 	       fec_type);
3540f74e101Schristos 
3550f74e101Schristos 	tptr+=1;
3560e9868baSchristos 	tlv_tlen-=1;
3570f74e101Schristos 	switch(fec_type) {
3580f74e101Schristos 
3590f74e101Schristos 	case LDP_FEC_WILDCARD:
3600f74e101Schristos 	    break;
3610f74e101Schristos 	case LDP_FEC_PREFIX:
3620e9868baSchristos 	    TLV_TCHECK(2);
363c74ad251Schristos 	    af = GET_BE_U_2(tptr);
364c74ad251Schristos 	    tptr+=2;
365c74ad251Schristos 	    tlv_tlen-=2;
3660f74e101Schristos 	    if (af == AFNUM_INET) {
367b3a00663Schristos 		i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf));
3680e9868baSchristos 		if (i == -2)
3690e9868baSchristos 		    goto trunc;
3700e9868baSchristos 		if (i == -3)
371c74ad251Schristos 		    ND_PRINT(": IPv4 prefix (goes past end of TLV)");
3720e9868baSchristos 		else if (i == -1)
373c74ad251Schristos 		    ND_PRINT(": IPv4 prefix (invalid length)");
3740e9868baSchristos 		else
375c74ad251Schristos 		    ND_PRINT(": IPv4 prefix %s", buf);
376*26ba0b50Schristos 	    } else if (af == AFNUM_INET6) {
377b3a00663Schristos 		i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf));
3780e9868baSchristos 		if (i == -2)
3790e9868baSchristos 		    goto trunc;
3800e9868baSchristos 		if (i == -3)
381c74ad251Schristos 		    ND_PRINT(": IPv4 prefix (goes past end of TLV)");
3820e9868baSchristos 		else if (i == -1)
383c74ad251Schristos 		    ND_PRINT(": IPv6 prefix (invalid length)");
3840e9868baSchristos 		else
385c74ad251Schristos 		    ND_PRINT(": IPv6 prefix %s", buf);
386*26ba0b50Schristos 	    } else
387c74ad251Schristos 		ND_PRINT(": Address family %u prefix", af);
3880f74e101Schristos 	    break;
3890f74e101Schristos 	case LDP_FEC_HOSTADDRESS:
3900f74e101Schristos 	    break;
3910f74e101Schristos 	case LDP_FEC_MARTINI_VC:
3920e9868baSchristos             /*
393dc860a36Sspz              * We assume the type was supposed to be one of the MPLS
394dc860a36Sspz              * Pseudowire Types.
3950e9868baSchristos              */
3960e9868baSchristos             TLV_TCHECK(7);
397c74ad251Schristos             vc_info_len = GET_U_1(tptr + 2);
3980f74e101Schristos 
399dc860a36Sspz             /*
400dc860a36Sspz 	     * According to RFC 4908, the VC info Length field can be zero,
401dc860a36Sspz 	     * in which case not only are there no interface parameters,
402dc860a36Sspz 	     * there's no VC ID.
403dc860a36Sspz 	     */
4040e9868baSchristos             if (vc_info_len == 0) {
405c74ad251Schristos                 ND_PRINT(": %s, %scontrol word, group-ID %u, VC-info-length: %u",
406c74ad251Schristos                        tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
407c74ad251Schristos                        GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
408c74ad251Schristos                        GET_BE_U_4(tptr + 3),
409c74ad251Schristos                        vc_info_len);
4100e9868baSchristos                 break;
4110e9868baSchristos             }
4120e9868baSchristos 
4130e9868baSchristos             /* Make sure we have the VC ID as well */
4140e9868baSchristos             TLV_TCHECK(11);
415c74ad251Schristos 	    ND_PRINT(": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u",
416c74ad251Schristos 		   tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
417c74ad251Schristos 		   GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
418c74ad251Schristos 		   GET_BE_U_4(tptr + 3),
419c74ad251Schristos 		   GET_BE_U_4(tptr + 7),
420c74ad251Schristos 		   vc_info_len);
421ba2ff121Schristos             if (vc_info_len < 4) {
422ba2ff121Schristos                 /* minimum 4, for the VC ID */
423c74ad251Schristos                 ND_PRINT(" (invalid, < 4");
424ba2ff121Schristos                 return(tlv_len+4); /* Type & Length fields not included */
425ba2ff121Schristos 	    }
4260e9868baSchristos             vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */
4270f74e101Schristos 
4280e9868baSchristos             /* Skip past the fixed information and the VC ID */
4290f74e101Schristos             tptr+=11;
4300e9868baSchristos             tlv_tlen-=11;
4310e9868baSchristos             TLV_TCHECK(vc_info_len);
4320f74e101Schristos 
4330f74e101Schristos             while (vc_info_len > 2) {
434c74ad251Schristos                 vc_info_tlv_type = GET_U_1(tptr);
435c74ad251Schristos                 vc_info_tlv_len = GET_U_1(tptr + 1);
4360f74e101Schristos                 if (vc_info_tlv_len < 2)
4370f74e101Schristos                     break;
4380f74e101Schristos                 if (vc_info_len < vc_info_tlv_len)
4390f74e101Schristos                     break;
4400f74e101Schristos 
441c74ad251Schristos                 ND_PRINT("\n\t\tInterface Parameter: %s (0x%02x), len %u",
4420f74e101Schristos                        tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
4430f74e101Schristos                        vc_info_tlv_type,
444c74ad251Schristos                        vc_info_tlv_len);
4450f74e101Schristos 
4460f74e101Schristos                 switch(vc_info_tlv_type) {
4470f74e101Schristos                 case LDP_FEC_MARTINI_IFPARM_MTU:
448c74ad251Schristos                     ND_PRINT(": %u", GET_BE_U_2(tptr + 2));
4490f74e101Schristos                     break;
4500f74e101Schristos 
4510f74e101Schristos                 case LDP_FEC_MARTINI_IFPARM_DESC:
452c74ad251Schristos                     ND_PRINT(": ");
453c74ad251Schristos                     for (idx = 2; idx < vc_info_tlv_len; idx++)
454c74ad251Schristos                         fn_print_char(ndo, GET_U_1(tptr + idx));
4550f74e101Schristos                     break;
4560f74e101Schristos 
4570f74e101Schristos                 case LDP_FEC_MARTINI_IFPARM_VCCV:
458c74ad251Schristos                     ND_PRINT("\n\t\t  Control Channels (0x%02x) = [%s]",
459c74ad251Schristos                            GET_U_1((tptr + 2)),
460c74ad251Schristos                            bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", GET_U_1((tptr + 2))));
461c74ad251Schristos                     ND_PRINT("\n\t\t  CV Types (0x%02x) = [%s]",
462c74ad251Schristos                            GET_U_1((tptr + 3)),
463c74ad251Schristos                            bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", GET_U_1((tptr + 3))));
4640f74e101Schristos                     break;
4650f74e101Schristos 
4660f74e101Schristos                 default:
467b3a00663Schristos                     print_unknown_data(ndo, tptr+2, "\n\t\t  ", vc_info_tlv_len-2);
4680f74e101Schristos                     break;
4690f74e101Schristos                 }
4700f74e101Schristos 
4710f74e101Schristos                 vc_info_len -= vc_info_tlv_len;
4720f74e101Schristos                 tptr += vc_info_tlv_len;
4730f74e101Schristos             }
4740f74e101Schristos 	    break;
4750f74e101Schristos 	}
4760f74e101Schristos 
4770f74e101Schristos 	break;
4780f74e101Schristos 
4790f74e101Schristos     case LDP_TLV_GENERIC_LABEL:
4800e9868baSchristos 	TLV_TCHECK(4);
481c74ad251Schristos 	ND_PRINT("\n\t      Label: %u", GET_BE_U_4(tptr) & 0xfffff);
4820f74e101Schristos 	break;
4830f74e101Schristos 
4840f74e101Schristos     case LDP_TLV_STATUS:
4850e9868baSchristos 	TLV_TCHECK(8);
486c74ad251Schristos 	ui = GET_BE_U_4(tptr);
4870f74e101Schristos 	tptr+=4;
488c74ad251Schristos 	ND_PRINT("\n\t      Status: 0x%02x, Flags: [%s and %s forward]",
4890f74e101Schristos 	       ui&0x3fffffff,
4900f74e101Schristos 	       ui&0x80000000 ? "Fatal error" : "Advisory Notification",
491c74ad251Schristos 	       ui&0x40000000 ? "do" : "don't");
492c74ad251Schristos 	ui = GET_BE_U_4(tptr);
4930f74e101Schristos 	tptr+=4;
4940f74e101Schristos 	if (ui)
495c74ad251Schristos 	    ND_PRINT(", causing Message ID: 0x%08x", ui);
4960f74e101Schristos 	break;
4970f74e101Schristos 
4980f74e101Schristos     case LDP_TLV_FT_SESSION:
499817e9a7eSchristos 	TLV_TCHECK(12);
500c74ad251Schristos 	ft_flags = GET_BE_U_2(tptr);
501c74ad251Schristos 	ND_PRINT("\n\t      Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]",
5020f74e101Schristos 	       ft_flags&0x8000 ? "" : "No ",
5030f74e101Schristos 	       ft_flags&0x8 ? "" : "Don't ",
5040f74e101Schristos 	       ft_flags&0x4 ? "" : "No ",
5050f74e101Schristos 	       ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels",
506c74ad251Schristos 	       ft_flags&0x1 ? "" : "Don't ");
507817e9a7eSchristos 	/* 16 bits (FT Flags) + 16 bits (Reserved) */
5080f74e101Schristos 	tptr+=4;
509c74ad251Schristos 	ui = GET_BE_U_4(tptr);
5100f74e101Schristos 	if (ui)
511c74ad251Schristos 	    ND_PRINT(", Reconnect Timeout: %ums", ui);
5120f74e101Schristos 	tptr+=4;
513c74ad251Schristos 	ui = GET_BE_U_4(tptr);
5140f74e101Schristos 	if (ui)
515c74ad251Schristos 	    ND_PRINT(", Recovery Time: %ums", ui);
5160f74e101Schristos 	break;
5170f74e101Schristos 
5180f74e101Schristos     case LDP_TLV_MTU:
5190e9868baSchristos 	TLV_TCHECK(2);
520c74ad251Schristos 	ND_PRINT("\n\t      MTU: %u", GET_BE_U_2(tptr));
5210f74e101Schristos 	break;
5220f74e101Schristos 
5230f74e101Schristos 
5240f74e101Schristos     /*
5250f74e101Schristos      *  FIXME those are the defined TLVs that lack a decoder
5260f74e101Schristos      *  you are welcome to contribute code ;-)
5270f74e101Schristos      */
5280f74e101Schristos 
5290f74e101Schristos     case LDP_TLV_HOP_COUNT:
5300f74e101Schristos     case LDP_TLV_PATH_VECTOR:
5310f74e101Schristos     case LDP_TLV_ATM_LABEL:
5320f74e101Schristos     case LDP_TLV_FR_LABEL:
5330f74e101Schristos     case LDP_TLV_EXTD_STATUS:
5340f74e101Schristos     case LDP_TLV_RETURNED_PDU:
5350f74e101Schristos     case LDP_TLV_RETURNED_MSG:
5360f74e101Schristos     case LDP_TLV_ATM_SESSION_PARM:
5370f74e101Schristos     case LDP_TLV_FR_SESSION_PARM:
5380f74e101Schristos     case LDP_TLV_LABEL_REQUEST_MSG_ID:
5390f74e101Schristos 
5400f74e101Schristos     default:
541b3a00663Schristos         if (ndo->ndo_vflag <= 1)
542b3a00663Schristos             print_unknown_data(ndo, tptr, "\n\t      ", tlv_tlen);
5430f74e101Schristos         break;
5440f74e101Schristos     }
5450f74e101Schristos     return(tlv_len+4); /* Type & Length fields not included */
5460f74e101Schristos 
5470f74e101Schristos trunc:
548c74ad251Schristos     nd_trunc_longjmp(ndo);
5490e9868baSchristos 
550c74ad251Schristos invalid:
5510e9868baSchristos     return(tlv_len+4); /* Type & Length fields not included */
5520f74e101Schristos }
5530f74e101Schristos 
5540f74e101Schristos void
555b3a00663Schristos ldp_print(netdissect_options *ndo,
556c74ad251Schristos           const u_char *pptr, u_int len)
557ba2ff121Schristos {
558817e9a7eSchristos     u_int processed;
559c74ad251Schristos 
560c74ad251Schristos     ndo->ndo_protocol = "ldp";
5610f74e101Schristos     while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
562ba2ff121Schristos         processed = ldp_pdu_print(ndo, pptr);
5630f74e101Schristos         if (processed == 0)
5640f74e101Schristos             return;
565817e9a7eSchristos         if (len < processed) {
566c74ad251Schristos             ND_PRINT(" [remaining length %u < %u]", len, processed);
567c74ad251Schristos             nd_print_invalid(ndo);
568817e9a7eSchristos             break;
569817e9a7eSchristos         }
5700f74e101Schristos         len -= processed;
5710f74e101Schristos         pptr += processed;
5720f74e101Schristos     }
5730f74e101Schristos }
5740f74e101Schristos 
575817e9a7eSchristos static u_int
576ba2ff121Schristos ldp_pdu_print(netdissect_options *ndo,
577c74ad251Schristos               const u_char *pptr)
578ba2ff121Schristos {
5790f74e101Schristos     const struct ldp_common_header *ldp_com_header;
5800f74e101Schristos     const struct ldp_msg_header *ldp_msg_header;
5810f74e101Schristos     const u_char *tptr,*msg_tptr;
5820f74e101Schristos     u_short tlen;
583c74ad251Schristos     u_short pdu_len,msg_len,msg_type;
584c74ad251Schristos     u_int msg_tlen;
5850f74e101Schristos     int hexdump,processed;
5860f74e101Schristos 
5870f74e101Schristos     ldp_com_header = (const struct ldp_common_header *)pptr;
588c74ad251Schristos     ND_TCHECK_SIZE(ldp_com_header);
5890f74e101Schristos 
5900f74e101Schristos     /*
5910f74e101Schristos      * Sanity checking of the header.
5920f74e101Schristos      */
593c74ad251Schristos     if (GET_BE_U_2(ldp_com_header->version) != LDP_VERSION) {
594c74ad251Schristos 	ND_PRINT("%sLDP version %u packet not supported",
595b3a00663Schristos                (ndo->ndo_vflag < 1) ? "" : "\n\t",
596c74ad251Schristos                GET_BE_U_2(ldp_com_header->version));
5970f74e101Schristos 	return 0;
5980f74e101Schristos     }
5990f74e101Schristos 
600c74ad251Schristos     pdu_len = GET_BE_U_2(ldp_com_header->pdu_length);
601c74ad251Schristos     if (pdu_len < sizeof(struct ldp_common_header)-4) {
602ba2ff121Schristos         /* length too short */
603c74ad251Schristos         ND_PRINT("%sLDP, pdu-length: %u (too short, < %zu)",
604ba2ff121Schristos                  (ndo->ndo_vflag < 1) ? "" : "\n\t",
605ba2ff121Schristos                  pdu_len,
606c74ad251Schristos                  sizeof(struct ldp_common_header)-4);
607ba2ff121Schristos         return 0;
608ba2ff121Schristos     }
609ba2ff121Schristos 
610ba2ff121Schristos     /* print the LSR-ID, label-space & length */
611c74ad251Schristos     ND_PRINT("%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
612b3a00663Schristos            (ndo->ndo_vflag < 1) ? "" : "\n\t",
613c74ad251Schristos            GET_IPADDR_STRING(ldp_com_header->lsr_id),
614c74ad251Schristos            GET_BE_U_2(ldp_com_header->label_space),
615c74ad251Schristos            pdu_len);
6160f74e101Schristos 
6170f74e101Schristos     /* bail out if non-verbose */
618b3a00663Schristos     if (ndo->ndo_vflag < 1)
6190f74e101Schristos         return 0;
6200f74e101Schristos 
6210f74e101Schristos     /* ok they seem to want to know everything - lets fully decode it */
622c74ad251Schristos     tptr = pptr + sizeof(struct ldp_common_header);
623c74ad251Schristos     tlen = pdu_len - (sizeof(struct ldp_common_header)-4);	/* Type & Length fields not included */
6240f74e101Schristos 
6250f74e101Schristos     while(tlen>0) {
6260f74e101Schristos         /* did we capture enough for fully decoding the msg header ? */
627c74ad251Schristos         ND_TCHECK_LEN(tptr, sizeof(struct ldp_msg_header));
6280f74e101Schristos 
6290f74e101Schristos         ldp_msg_header = (const struct ldp_msg_header *)tptr;
630c74ad251Schristos         msg_len=GET_BE_U_2(ldp_msg_header->length);
631c74ad251Schristos         msg_type=LDP_MASK_MSG_TYPE(GET_BE_U_2(ldp_msg_header->type));
6320f74e101Schristos 
633ba2ff121Schristos         if (msg_len < sizeof(struct ldp_msg_header)-4) {
634ba2ff121Schristos             /* length too short */
635ba2ff121Schristos             /* FIXME vendor private / experimental check */
636c74ad251Schristos             ND_PRINT("\n\t  %s Message (0x%04x), length: %u (too short, < %zu)",
637ba2ff121Schristos                      tok2str(ldp_msg_values,
638ba2ff121Schristos                              "Unknown",
639ba2ff121Schristos                              msg_type),
640ba2ff121Schristos                      msg_type,
641ba2ff121Schristos                      msg_len,
642c74ad251Schristos                      sizeof(struct ldp_msg_header)-4);
643ba2ff121Schristos             return 0;
644ba2ff121Schristos         }
645ba2ff121Schristos 
6460f74e101Schristos         /* FIXME vendor private / experimental check */
647c74ad251Schristos         ND_PRINT("\n\t  %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
6480f74e101Schristos                tok2str(ldp_msg_values,
6490f74e101Schristos                        "Unknown",
6500f74e101Schristos                        msg_type),
6510f74e101Schristos                msg_type,
6520f74e101Schristos                msg_len,
653c74ad251Schristos                GET_BE_U_4(ldp_msg_header->id),
654c74ad251Schristos                LDP_MASK_U_BIT(GET_BE_U_2(ldp_msg_header->type)) ? "continue processing" : "ignore");
6550f74e101Schristos 
6560f74e101Schristos         msg_tptr=tptr+sizeof(struct ldp_msg_header);
657ba2ff121Schristos         msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */
6580f74e101Schristos 
6590f74e101Schristos         /* did we capture enough for fully decoding the message ? */
660c74ad251Schristos         ND_TCHECK_LEN(tptr, msg_len);
6610f74e101Schristos         hexdump=FALSE;
6620f74e101Schristos 
6630f74e101Schristos         switch(msg_type) {
6640f74e101Schristos 
6650f74e101Schristos         case LDP_MSG_NOTIF:
6660f74e101Schristos         case LDP_MSG_HELLO:
6670f74e101Schristos         case LDP_MSG_INIT:
6680f74e101Schristos         case LDP_MSG_KEEPALIVE:
6690f74e101Schristos         case LDP_MSG_ADDRESS:
6700f74e101Schristos         case LDP_MSG_LABEL_MAPPING:
6710f74e101Schristos         case LDP_MSG_ADDRESS_WITHDRAW:
6720f74e101Schristos         case LDP_MSG_LABEL_WITHDRAW:
6730f74e101Schristos             while(msg_tlen >= 4) {
674ba2ff121Schristos                 processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen);
6750f74e101Schristos                 if (processed == 0)
6760f74e101Schristos                     break;
6770f74e101Schristos                 msg_tlen-=processed;
6780f74e101Schristos                 msg_tptr+=processed;
6790f74e101Schristos             }
6800f74e101Schristos             break;
6810f74e101Schristos 
6820f74e101Schristos         /*
6830f74e101Schristos          *  FIXME those are the defined messages that lack a decoder
6840f74e101Schristos          *  you are welcome to contribute code ;-)
6850f74e101Schristos          */
6860f74e101Schristos 
6870f74e101Schristos         case LDP_MSG_LABEL_REQUEST:
6880f74e101Schristos         case LDP_MSG_LABEL_RELEASE:
6890f74e101Schristos         case LDP_MSG_LABEL_ABORT_REQUEST:
6900f74e101Schristos 
6910f74e101Schristos         default:
692b3a00663Schristos             if (ndo->ndo_vflag <= 1)
693b3a00663Schristos                 print_unknown_data(ndo, msg_tptr, "\n\t  ", msg_tlen);
6940f74e101Schristos             break;
6950f74e101Schristos         }
6960f74e101Schristos         /* do we want to see an additionally hexdump ? */
697b3a00663Schristos         if (ndo->ndo_vflag > 1 || hexdump==TRUE)
698b3a00663Schristos             print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t  ",
6990f74e101Schristos                                msg_len);
7000f74e101Schristos 
7010f74e101Schristos         tptr += msg_len+4;
7020f74e101Schristos         tlen -= msg_len+4;
7030f74e101Schristos     }
7040f74e101Schristos     return pdu_len+4;
7050f74e101Schristos trunc:
706c74ad251Schristos     nd_trunc_longjmp(ndo);
7070f74e101Schristos }
708