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