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