Home | History | Annotate | Line # | Download | only in dist
print-ldp.c revision 1.11
      1 /*
      2  * Redistribution and use in source and binary forms, with or without
      3  * modification, are permitted provided that: (1) source code
      4  * distributions retain the above copyright notice and this paragraph
      5  * in its entirety, and (2) distributions including binary code include
      6  * the above copyright notice and this paragraph in its entirety in
      7  * the documentation or other materials provided with the distribution.
      8  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
      9  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     10  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     11  * FOR A PARTICULAR PURPOSE.
     12  *
     13  * Original code by Hannes Gredler (hannes (at) gredler.at)
     14  *  and Steinar Haug (sthaug (at) nethelp.no)
     15  */
     16 
     17 #include <sys/cdefs.h>
     18 #ifndef lint
     19 __RCSID("$NetBSD: print-ldp.c,v 1.11 2023/08/17 20:19:40 christos Exp $");
     20 #endif
     21 
     22 /* \summary: Label Distribution Protocol (LDP) printer */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 
     28 #include "netdissect-stdinc.h"
     29 
     30 #include "netdissect.h"
     31 #include "extract.h"
     32 #include "addrtoname.h"
     33 
     34 #include "l2vpn.h"
     35 #include "af.h"
     36 
     37 
     38 /*
     39  * ldp common header
     40  *
     41  *  0                   1                   2                   3
     42  *  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
     43  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     44  * |  Version                      |         PDU Length            |
     45  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     46  * |                         LDP Identifier                        |
     47  * +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     48  * |                               |
     49  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     50  *
     51  */
     52 
     53 struct ldp_common_header {
     54     nd_uint16_t version;
     55     nd_uint16_t pdu_length;
     56     nd_ipv4     lsr_id;
     57     nd_uint16_t label_space;
     58 };
     59 
     60 #define LDP_VERSION 1
     61 
     62 /*
     63  * ldp message header
     64  *
     65  *  0                   1                   2                   3
     66  *  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
     67  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     68  * |U|   Message Type              |      Message Length           |
     69  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     70  * |                     Message ID                                |
     71  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     72  * |                                                               |
     73  * +                                                               +
     74  * |                     Mandatory Parameters                      |
     75  * +                                                               +
     76  * |                                                               |
     77  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     78  * |                                                               |
     79  * +                                                               +
     80  * |                     Optional Parameters                       |
     81  * +                                                               +
     82  * |                                                               |
     83  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     84  */
     85 
     86 struct ldp_msg_header {
     87     nd_uint16_t type;
     88     nd_uint16_t length;
     89     nd_uint32_t id;
     90 };
     91 
     92 #define	LDP_MASK_MSG_TYPE(x)  ((x)&0x7fff)
     93 #define	LDP_MASK_U_BIT(x)     ((x)&0x8000)
     94 
     95 #define	LDP_MSG_NOTIF                0x0001
     96 #define	LDP_MSG_HELLO                0x0100
     97 #define	LDP_MSG_INIT                 0x0200
     98 #define	LDP_MSG_KEEPALIVE            0x0201
     99 #define	LDP_MSG_ADDRESS              0x0300
    100 #define	LDP_MSG_ADDRESS_WITHDRAW     0x0301
    101 #define	LDP_MSG_LABEL_MAPPING        0x0400
    102 #define	LDP_MSG_LABEL_REQUEST        0x0401
    103 #define	LDP_MSG_LABEL_WITHDRAW       0x0402
    104 #define	LDP_MSG_LABEL_RELEASE        0x0403
    105 #define	LDP_MSG_LABEL_ABORT_REQUEST  0x0404
    106 
    107 #define	LDP_VENDOR_PRIVATE_MIN       0x3e00
    108 #define	LDP_VENDOR_PRIVATE_MAX       0x3eff
    109 #define	LDP_EXPERIMENTAL_MIN         0x3f00
    110 #define	LDP_EXPERIMENTAL_MAX         0x3fff
    111 
    112 static const struct tok ldp_msg_values[] = {
    113     { LDP_MSG_NOTIF,	             "Notification" },
    114     { LDP_MSG_HELLO,	             "Hello" },
    115     { LDP_MSG_INIT,	             "Initialization" },
    116     { LDP_MSG_KEEPALIVE,             "Keepalive" },
    117     { LDP_MSG_ADDRESS,	             "Address" },
    118     { LDP_MSG_ADDRESS_WITHDRAW,	     "Address Withdraw" },
    119     { LDP_MSG_LABEL_MAPPING,	     "Label Mapping" },
    120     { LDP_MSG_LABEL_REQUEST,	     "Label Request" },
    121     { LDP_MSG_LABEL_WITHDRAW,	     "Label Withdraw" },
    122     { LDP_MSG_LABEL_RELEASE,	     "Label Release" },
    123     { LDP_MSG_LABEL_ABORT_REQUEST,   "Label Abort Request" },
    124     { 0, NULL}
    125 };
    126 
    127 #define	LDP_MASK_TLV_TYPE(x)  ((x)&0x3fff)
    128 #define	LDP_MASK_F_BIT(x) ((x)&0x4000)
    129 
    130 #define	LDP_TLV_FEC                  0x0100
    131 #define	LDP_TLV_ADDRESS_LIST         0x0101
    132 #define LDP_TLV_ADDRESS_LIST_AFNUM_LEN 2
    133 #define	LDP_TLV_HOP_COUNT            0x0103
    134 #define	LDP_TLV_PATH_VECTOR          0x0104
    135 #define	LDP_TLV_GENERIC_LABEL        0x0200
    136 #define	LDP_TLV_ATM_LABEL            0x0201
    137 #define	LDP_TLV_FR_LABEL             0x0202
    138 #define	LDP_TLV_STATUS               0x0300
    139 #define	LDP_TLV_EXTD_STATUS          0x0301
    140 #define	LDP_TLV_RETURNED_PDU         0x0302
    141 #define	LDP_TLV_RETURNED_MSG         0x0303
    142 #define	LDP_TLV_COMMON_HELLO         0x0400
    143 #define	LDP_TLV_IPV4_TRANSPORT_ADDR  0x0401
    144 #define	LDP_TLV_CONFIG_SEQ_NUMBER    0x0402
    145 #define	LDP_TLV_IPV6_TRANSPORT_ADDR  0x0403
    146 #define	LDP_TLV_COMMON_SESSION       0x0500
    147 #define	LDP_TLV_ATM_SESSION_PARM     0x0501
    148 #define	LDP_TLV_FR_SESSION_PARM      0x0502
    149 #define LDP_TLV_FT_SESSION	     0x0503
    150 #define	LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
    151 #define LDP_TLV_MTU                  0x0601 /* rfc 3988 */
    152 
    153 static const struct tok ldp_tlv_values[] = {
    154     { LDP_TLV_FEC,	             "FEC" },
    155     { LDP_TLV_ADDRESS_LIST,          "Address List" },
    156     { LDP_TLV_HOP_COUNT,             "Hop Count" },
    157     { LDP_TLV_PATH_VECTOR,           "Path Vector" },
    158     { LDP_TLV_GENERIC_LABEL,         "Generic Label" },
    159     { LDP_TLV_ATM_LABEL,             "ATM Label" },
    160     { LDP_TLV_FR_LABEL,              "Frame-Relay Label" },
    161     { LDP_TLV_STATUS,                "Status" },
    162     { LDP_TLV_EXTD_STATUS,           "Extended Status" },
    163     { LDP_TLV_RETURNED_PDU,          "Returned PDU" },
    164     { LDP_TLV_RETURNED_MSG,          "Returned Message" },
    165     { LDP_TLV_COMMON_HELLO,          "Common Hello Parameters" },
    166     { LDP_TLV_IPV4_TRANSPORT_ADDR,   "IPv4 Transport Address" },
    167     { LDP_TLV_CONFIG_SEQ_NUMBER,     "Configuration Sequence Number" },
    168     { LDP_TLV_IPV6_TRANSPORT_ADDR,   "IPv6 Transport Address" },
    169     { LDP_TLV_COMMON_SESSION,        "Common Session Parameters" },
    170     { LDP_TLV_ATM_SESSION_PARM,      "ATM Session Parameters" },
    171     { LDP_TLV_FR_SESSION_PARM,       "Frame-Relay Session Parameters" },
    172     { LDP_TLV_FT_SESSION,            "Fault-Tolerant Session Parameters" },
    173     { LDP_TLV_LABEL_REQUEST_MSG_ID,  "Label Request Message ID" },
    174     { LDP_TLV_MTU,                   "MTU" },
    175     { 0, NULL}
    176 };
    177 
    178 #define LDP_FEC_WILDCARD	0x01
    179 #define LDP_FEC_PREFIX		0x02
    180 #define LDP_FEC_HOSTADDRESS	0x03
    181 /* From RFC 4906; should probably be updated to RFC 4447 (e.g., VC -> PW) */
    182 #define LDP_FEC_MARTINI_VC	0x80
    183 
    184 static const struct tok ldp_fec_values[] = {
    185     { LDP_FEC_WILDCARD,		"Wildcard" },
    186     { LDP_FEC_PREFIX,		"Prefix" },
    187     { LDP_FEC_HOSTADDRESS,	"Host address" },
    188     { LDP_FEC_MARTINI_VC,	"Martini VC" },
    189     { 0, NULL}
    190 };
    191 
    192 #define LDP_FEC_MARTINI_IFPARM_MTU  0x01
    193 #define LDP_FEC_MARTINI_IFPARM_DESC 0x03
    194 #define LDP_FEC_MARTINI_IFPARM_VCCV 0x0c
    195 
    196 static const struct tok ldp_fec_martini_ifparm_values[] = {
    197     { LDP_FEC_MARTINI_IFPARM_MTU, "MTU" },
    198     { LDP_FEC_MARTINI_IFPARM_DESC, "Description" },
    199     { LDP_FEC_MARTINI_IFPARM_VCCV, "VCCV" },
    200     { 0, NULL}
    201 };
    202 
    203 /* draft-ietf-pwe3-vccv-04.txt */
    204 static const struct tok ldp_fec_martini_ifparm_vccv_cc_values[] = {
    205     { 0x01, "PWE3 control word" },
    206     { 0x02, "MPLS Router Alert Label" },
    207     { 0x04, "MPLS inner label TTL = 1" },
    208     { 0, NULL}
    209 };
    210 
    211 /* draft-ietf-pwe3-vccv-04.txt */
    212 static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = {
    213     { 0x01, "ICMP Ping" },
    214     { 0x02, "LSP Ping" },
    215     { 0x04, "BFD" },
    216     { 0, NULL}
    217 };
    218 
    219 static u_int ldp_pdu_print(netdissect_options *, const u_char *);
    220 
    221 /*
    222  * ldp tlv header
    223  *
    224  *  0                   1                   2                   3
    225  *  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
    226  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    227  * |U|F|        Type               |            Length             |
    228  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    229  * |                                                               |
    230  * |                             Value                             |
    231  * ~                                                               ~
    232  * |                                                               |
    233  * |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    234  * |                               |
    235  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    236  */
    237 
    238 #define TLV_TCHECK(minlen) \
    239     if (tlv_tlen < minlen) { \
    240         ND_PRINT(" [tlv length %u < %u]", tlv_tlen, minlen); \
    241         nd_print_invalid(ndo); \
    242         goto invalid; \
    243     }
    244 
    245 static u_int
    246 ldp_tlv_print(netdissect_options *ndo,
    247               const u_char *tptr,
    248               u_int msg_tlen)
    249 {
    250     struct ldp_tlv_header {
    251         nd_uint16_t type;
    252         nd_uint16_t length;
    253     };
    254 
    255     const struct ldp_tlv_header *ldp_tlv_header;
    256     u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags;
    257     u_char fec_type;
    258     u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx;
    259     char buf[100];
    260     int i;
    261 
    262     ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
    263     ND_TCHECK_SIZE(ldp_tlv_header);
    264     tlv_len=GET_BE_U_2(ldp_tlv_header->length);
    265     if (tlv_len + 4U > msg_tlen) {
    266         ND_PRINT("\n\t\t TLV contents go past end of message");
    267         return 0;
    268     }
    269     tlv_tlen=tlv_len;
    270     tlv_type=LDP_MASK_TLV_TYPE(GET_BE_U_2(ldp_tlv_header->type));
    271 
    272     /* FIXME vendor private / experimental check */
    273     ND_PRINT("\n\t    %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
    274            tok2str(ldp_tlv_values,
    275                    "Unknown",
    276                    tlv_type),
    277            tlv_type,
    278            tlv_len,
    279            LDP_MASK_U_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "continue processing" : "ignore",
    280            LDP_MASK_F_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "do" : "don't");
    281 
    282     tptr+=sizeof(struct ldp_tlv_header);
    283 
    284     switch(tlv_type) {
    285 
    286     case LDP_TLV_COMMON_HELLO:
    287         TLV_TCHECK(4);
    288         ND_PRINT("\n\t      Hold Time: %us, Flags: [%s Hello%s]",
    289                GET_BE_U_2(tptr),
    290                (GET_BE_U_2(tptr + 2)&0x8000) ? "Targeted" : "Link",
    291                (GET_BE_U_2(tptr + 2)&0x4000) ? ", Request for targeted Hellos" : "");
    292         break;
    293 
    294     case LDP_TLV_IPV4_TRANSPORT_ADDR:
    295         TLV_TCHECK(4);
    296         ND_PRINT("\n\t      IPv4 Transport Address: %s", GET_IPADDR_STRING(tptr));
    297         break;
    298     case LDP_TLV_IPV6_TRANSPORT_ADDR:
    299         TLV_TCHECK(16);
    300         ND_PRINT("\n\t      IPv6 Transport Address: %s", GET_IP6ADDR_STRING(tptr));
    301         break;
    302     case LDP_TLV_CONFIG_SEQ_NUMBER:
    303         TLV_TCHECK(4);
    304         ND_PRINT("\n\t      Sequence Number: %u", GET_BE_U_4(tptr));
    305         break;
    306 
    307     case LDP_TLV_ADDRESS_LIST:
    308         TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
    309 	af = GET_BE_U_2(tptr);
    310 	tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
    311         tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
    312 	ND_PRINT("\n\t      Address Family: %s, addresses",
    313                tok2str(af_values, "Unknown (%u)", af));
    314         switch (af) {
    315         case AFNUM_INET:
    316 	    while(tlv_tlen >= sizeof(nd_ipv4)) {
    317 		ND_PRINT(" %s", GET_IPADDR_STRING(tptr));
    318 		tlv_tlen-=sizeof(nd_ipv4);
    319 		tptr+=sizeof(nd_ipv4);
    320 	    }
    321             break;
    322         case AFNUM_INET6:
    323 	    while(tlv_tlen >= sizeof(nd_ipv6)) {
    324 		ND_PRINT(" %s", GET_IP6ADDR_STRING(tptr));
    325 		tlv_tlen-=sizeof(nd_ipv6);
    326 		tptr+=sizeof(nd_ipv6);
    327 	    }
    328             break;
    329         default:
    330             /* unknown AF */
    331             break;
    332         }
    333 	break;
    334 
    335     case LDP_TLV_COMMON_SESSION:
    336 	TLV_TCHECK(8);
    337 	ND_PRINT("\n\t      Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]",
    338 	       GET_BE_U_2(tptr), GET_BE_U_2(tptr + 2),
    339 	       (GET_BE_U_2(tptr + 6)&0x8000) ? "On Demand" : "Unsolicited",
    340 	       (GET_BE_U_2(tptr + 6)&0x4000) ? "Enabled" : "Disabled"
    341 	       );
    342 	break;
    343 
    344     case LDP_TLV_FEC:
    345         TLV_TCHECK(1);
    346         fec_type = GET_U_1(tptr);
    347 	ND_PRINT("\n\t      %s FEC (0x%02x)",
    348 	       tok2str(ldp_fec_values, "Unknown", fec_type),
    349 	       fec_type);
    350 
    351 	tptr+=1;
    352 	tlv_tlen-=1;
    353 	switch(fec_type) {
    354 
    355 	case LDP_FEC_WILDCARD:
    356 	    break;
    357 	case LDP_FEC_PREFIX:
    358 	    TLV_TCHECK(2);
    359 	    af = GET_BE_U_2(tptr);
    360 	    tptr+=2;
    361 	    tlv_tlen-=2;
    362 	    if (af == AFNUM_INET) {
    363 		i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf));
    364 		if (i == -2)
    365 		    goto trunc;
    366 		if (i == -3)
    367 		    ND_PRINT(": IPv4 prefix (goes past end of TLV)");
    368 		else if (i == -1)
    369 		    ND_PRINT(": IPv4 prefix (invalid length)");
    370 		else
    371 		    ND_PRINT(": IPv4 prefix %s", buf);
    372 	    }
    373 	    else if (af == AFNUM_INET6) {
    374 		i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf));
    375 		if (i == -2)
    376 		    goto trunc;
    377 		if (i == -3)
    378 		    ND_PRINT(": IPv4 prefix (goes past end of TLV)");
    379 		else if (i == -1)
    380 		    ND_PRINT(": IPv6 prefix (invalid length)");
    381 		else
    382 		    ND_PRINT(": IPv6 prefix %s", buf);
    383 	    }
    384 	    else
    385 		ND_PRINT(": Address family %u prefix", af);
    386 	    break;
    387 	case LDP_FEC_HOSTADDRESS:
    388 	    break;
    389 	case LDP_FEC_MARTINI_VC:
    390             /*
    391              * We assume the type was supposed to be one of the MPLS
    392              * Pseudowire Types.
    393              */
    394             TLV_TCHECK(7);
    395             vc_info_len = GET_U_1(tptr + 2);
    396 
    397             /*
    398 	     * According to RFC 4908, the VC info Length field can be zero,
    399 	     * in which case not only are there no interface parameters,
    400 	     * there's no VC ID.
    401 	     */
    402             if (vc_info_len == 0) {
    403                 ND_PRINT(": %s, %scontrol word, group-ID %u, VC-info-length: %u",
    404                        tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
    405                        GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
    406                        GET_BE_U_4(tptr + 3),
    407                        vc_info_len);
    408                 break;
    409             }
    410 
    411             /* Make sure we have the VC ID as well */
    412             TLV_TCHECK(11);
    413 	    ND_PRINT(": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u",
    414 		   tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
    415 		   GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
    416 		   GET_BE_U_4(tptr + 3),
    417 		   GET_BE_U_4(tptr + 7),
    418 		   vc_info_len);
    419             if (vc_info_len < 4) {
    420                 /* minimum 4, for the VC ID */
    421                 ND_PRINT(" (invalid, < 4");
    422                 return(tlv_len+4); /* Type & Length fields not included */
    423 	    }
    424             vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */
    425 
    426             /* Skip past the fixed information and the VC ID */
    427             tptr+=11;
    428             tlv_tlen-=11;
    429             TLV_TCHECK(vc_info_len);
    430 
    431             while (vc_info_len > 2) {
    432                 vc_info_tlv_type = GET_U_1(tptr);
    433                 vc_info_tlv_len = GET_U_1(tptr + 1);
    434                 if (vc_info_tlv_len < 2)
    435                     break;
    436                 if (vc_info_len < vc_info_tlv_len)
    437                     break;
    438 
    439                 ND_PRINT("\n\t\tInterface Parameter: %s (0x%02x), len %u",
    440                        tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
    441                        vc_info_tlv_type,
    442                        vc_info_tlv_len);
    443 
    444                 switch(vc_info_tlv_type) {
    445                 case LDP_FEC_MARTINI_IFPARM_MTU:
    446                     ND_PRINT(": %u", GET_BE_U_2(tptr + 2));
    447                     break;
    448 
    449                 case LDP_FEC_MARTINI_IFPARM_DESC:
    450                     ND_PRINT(": ");
    451                     for (idx = 2; idx < vc_info_tlv_len; idx++)
    452                         fn_print_char(ndo, GET_U_1(tptr + idx));
    453                     break;
    454 
    455                 case LDP_FEC_MARTINI_IFPARM_VCCV:
    456                     ND_PRINT("\n\t\t  Control Channels (0x%02x) = [%s]",
    457                            GET_U_1((tptr + 2)),
    458                            bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", GET_U_1((tptr + 2))));
    459                     ND_PRINT("\n\t\t  CV Types (0x%02x) = [%s]",
    460                            GET_U_1((tptr + 3)),
    461                            bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", GET_U_1((tptr + 3))));
    462                     break;
    463 
    464                 default:
    465                     print_unknown_data(ndo, tptr+2, "\n\t\t  ", vc_info_tlv_len-2);
    466                     break;
    467                 }
    468 
    469                 vc_info_len -= vc_info_tlv_len;
    470                 tptr += vc_info_tlv_len;
    471             }
    472 	    break;
    473 	}
    474 
    475 	break;
    476 
    477     case LDP_TLV_GENERIC_LABEL:
    478 	TLV_TCHECK(4);
    479 	ND_PRINT("\n\t      Label: %u", GET_BE_U_4(tptr) & 0xfffff);
    480 	break;
    481 
    482     case LDP_TLV_STATUS:
    483 	TLV_TCHECK(8);
    484 	ui = GET_BE_U_4(tptr);
    485 	tptr+=4;
    486 	ND_PRINT("\n\t      Status: 0x%02x, Flags: [%s and %s forward]",
    487 	       ui&0x3fffffff,
    488 	       ui&0x80000000 ? "Fatal error" : "Advisory Notification",
    489 	       ui&0x40000000 ? "do" : "don't");
    490 	ui = GET_BE_U_4(tptr);
    491 	tptr+=4;
    492 	if (ui)
    493 	    ND_PRINT(", causing Message ID: 0x%08x", ui);
    494 	break;
    495 
    496     case LDP_TLV_FT_SESSION:
    497 	TLV_TCHECK(12);
    498 	ft_flags = GET_BE_U_2(tptr);
    499 	ND_PRINT("\n\t      Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]",
    500 	       ft_flags&0x8000 ? "" : "No ",
    501 	       ft_flags&0x8 ? "" : "Don't ",
    502 	       ft_flags&0x4 ? "" : "No ",
    503 	       ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels",
    504 	       ft_flags&0x1 ? "" : "Don't ");
    505 	/* 16 bits (FT Flags) + 16 bits (Reserved) */
    506 	tptr+=4;
    507 	ui = GET_BE_U_4(tptr);
    508 	if (ui)
    509 	    ND_PRINT(", Reconnect Timeout: %ums", ui);
    510 	tptr+=4;
    511 	ui = GET_BE_U_4(tptr);
    512 	if (ui)
    513 	    ND_PRINT(", Recovery Time: %ums", ui);
    514 	break;
    515 
    516     case LDP_TLV_MTU:
    517 	TLV_TCHECK(2);
    518 	ND_PRINT("\n\t      MTU: %u", GET_BE_U_2(tptr));
    519 	break;
    520 
    521 
    522     /*
    523      *  FIXME those are the defined TLVs that lack a decoder
    524      *  you are welcome to contribute code ;-)
    525      */
    526 
    527     case LDP_TLV_HOP_COUNT:
    528     case LDP_TLV_PATH_VECTOR:
    529     case LDP_TLV_ATM_LABEL:
    530     case LDP_TLV_FR_LABEL:
    531     case LDP_TLV_EXTD_STATUS:
    532     case LDP_TLV_RETURNED_PDU:
    533     case LDP_TLV_RETURNED_MSG:
    534     case LDP_TLV_ATM_SESSION_PARM:
    535     case LDP_TLV_FR_SESSION_PARM:
    536     case LDP_TLV_LABEL_REQUEST_MSG_ID:
    537 
    538     default:
    539         if (ndo->ndo_vflag <= 1)
    540             print_unknown_data(ndo, tptr, "\n\t      ", tlv_tlen);
    541         break;
    542     }
    543     return(tlv_len+4); /* Type & Length fields not included */
    544 
    545 trunc:
    546     nd_trunc_longjmp(ndo);
    547 
    548 invalid:
    549     return(tlv_len+4); /* Type & Length fields not included */
    550 }
    551 
    552 void
    553 ldp_print(netdissect_options *ndo,
    554           const u_char *pptr, u_int len)
    555 {
    556     u_int processed;
    557 
    558     ndo->ndo_protocol = "ldp";
    559     while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
    560         processed = ldp_pdu_print(ndo, pptr);
    561         if (processed == 0)
    562             return;
    563         if (len < processed) {
    564             ND_PRINT(" [remaining length %u < %u]", len, processed);
    565             nd_print_invalid(ndo);
    566             break;
    567         }
    568         len -= processed;
    569         pptr += processed;
    570     }
    571 }
    572 
    573 static u_int
    574 ldp_pdu_print(netdissect_options *ndo,
    575               const u_char *pptr)
    576 {
    577     const struct ldp_common_header *ldp_com_header;
    578     const struct ldp_msg_header *ldp_msg_header;
    579     const u_char *tptr,*msg_tptr;
    580     u_short tlen;
    581     u_short pdu_len,msg_len,msg_type;
    582     u_int msg_tlen;
    583     int hexdump,processed;
    584 
    585     ldp_com_header = (const struct ldp_common_header *)pptr;
    586     ND_TCHECK_SIZE(ldp_com_header);
    587 
    588     /*
    589      * Sanity checking of the header.
    590      */
    591     if (GET_BE_U_2(ldp_com_header->version) != LDP_VERSION) {
    592 	ND_PRINT("%sLDP version %u packet not supported",
    593                (ndo->ndo_vflag < 1) ? "" : "\n\t",
    594                GET_BE_U_2(ldp_com_header->version));
    595 	return 0;
    596     }
    597 
    598     pdu_len = GET_BE_U_2(ldp_com_header->pdu_length);
    599     if (pdu_len < sizeof(struct ldp_common_header)-4) {
    600         /* length too short */
    601         ND_PRINT("%sLDP, pdu-length: %u (too short, < %zu)",
    602                  (ndo->ndo_vflag < 1) ? "" : "\n\t",
    603                  pdu_len,
    604                  sizeof(struct ldp_common_header)-4);
    605         return 0;
    606     }
    607 
    608     /* print the LSR-ID, label-space & length */
    609     ND_PRINT("%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
    610            (ndo->ndo_vflag < 1) ? "" : "\n\t",
    611            GET_IPADDR_STRING(ldp_com_header->lsr_id),
    612            GET_BE_U_2(ldp_com_header->label_space),
    613            pdu_len);
    614 
    615     /* bail out if non-verbose */
    616     if (ndo->ndo_vflag < 1)
    617         return 0;
    618 
    619     /* ok they seem to want to know everything - lets fully decode it */
    620     tptr = pptr + sizeof(struct ldp_common_header);
    621     tlen = pdu_len - (sizeof(struct ldp_common_header)-4);	/* Type & Length fields not included */
    622 
    623     while(tlen>0) {
    624         /* did we capture enough for fully decoding the msg header ? */
    625         ND_TCHECK_LEN(tptr, sizeof(struct ldp_msg_header));
    626 
    627         ldp_msg_header = (const struct ldp_msg_header *)tptr;
    628         msg_len=GET_BE_U_2(ldp_msg_header->length);
    629         msg_type=LDP_MASK_MSG_TYPE(GET_BE_U_2(ldp_msg_header->type));
    630 
    631         if (msg_len < sizeof(struct ldp_msg_header)-4) {
    632             /* length too short */
    633             /* FIXME vendor private / experimental check */
    634             ND_PRINT("\n\t  %s Message (0x%04x), length: %u (too short, < %zu)",
    635                      tok2str(ldp_msg_values,
    636                              "Unknown",
    637                              msg_type),
    638                      msg_type,
    639                      msg_len,
    640                      sizeof(struct ldp_msg_header)-4);
    641             return 0;
    642         }
    643 
    644         /* FIXME vendor private / experimental check */
    645         ND_PRINT("\n\t  %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
    646                tok2str(ldp_msg_values,
    647                        "Unknown",
    648                        msg_type),
    649                msg_type,
    650                msg_len,
    651                GET_BE_U_4(ldp_msg_header->id),
    652                LDP_MASK_U_BIT(GET_BE_U_2(ldp_msg_header->type)) ? "continue processing" : "ignore");
    653 
    654         msg_tptr=tptr+sizeof(struct ldp_msg_header);
    655         msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */
    656 
    657         /* did we capture enough for fully decoding the message ? */
    658         ND_TCHECK_LEN(tptr, msg_len);
    659         hexdump=FALSE;
    660 
    661         switch(msg_type) {
    662 
    663         case LDP_MSG_NOTIF:
    664         case LDP_MSG_HELLO:
    665         case LDP_MSG_INIT:
    666         case LDP_MSG_KEEPALIVE:
    667         case LDP_MSG_ADDRESS:
    668         case LDP_MSG_LABEL_MAPPING:
    669         case LDP_MSG_ADDRESS_WITHDRAW:
    670         case LDP_MSG_LABEL_WITHDRAW:
    671             while(msg_tlen >= 4) {
    672                 processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen);
    673                 if (processed == 0)
    674                     break;
    675                 msg_tlen-=processed;
    676                 msg_tptr+=processed;
    677             }
    678             break;
    679 
    680         /*
    681          *  FIXME those are the defined messages that lack a decoder
    682          *  you are welcome to contribute code ;-)
    683          */
    684 
    685         case LDP_MSG_LABEL_REQUEST:
    686         case LDP_MSG_LABEL_RELEASE:
    687         case LDP_MSG_LABEL_ABORT_REQUEST:
    688 
    689         default:
    690             if (ndo->ndo_vflag <= 1)
    691                 print_unknown_data(ndo, msg_tptr, "\n\t  ", msg_tlen);
    692             break;
    693         }
    694         /* do we want to see an additionally hexdump ? */
    695         if (ndo->ndo_vflag > 1 || hexdump==TRUE)
    696             print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t  ",
    697                                msg_len);
    698 
    699         tptr += msg_len+4;
    700         tlen -= msg_len+4;
    701     }
    702     return pdu_len+4;
    703 trunc:
    704     nd_trunc_longjmp(ndo);
    705 }
    706