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