]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-ldp.c
Add CAP_FCNTL and use cap_fcntls_limit().
[tcpdump] / print-ldp.c
index 25ea95817151a523e57146405011266e753f70f6..f387affd4b016049d94dcad9229a399938088e08 100644 (file)
  * FOR A PARTICULAR PURPOSE.
  *
  * Original code by Hannes Gredler ([email protected])
+ *  and Steinar Haug ([email protected])
  */
 
-#ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-ldp.c,v 1.1 2002-12-13 00:40:35 hannes Exp $";
-#endif
-
+#define NETDISSECT_REWORKED
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include <tcpdump-stdinc.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "interface.h"
 #include "extract.h"
 #include "addrtoname.h"
-#include "ethertype.h"
+
+#include "l2vpn.h"
+#include "af.h"
 
 /*
  * ldp common header
@@ -49,15 +44,174 @@ static const char rcsid[] =
  */
 
 struct ldp_common_header {
-    u_int8_t version[2];
-    u_int8_t pdu_length[2];
-    u_int8_t lsr_id[4];
-    u_int8_t label_space[2];
+    uint8_t version[2];
+    uint8_t pdu_length[2];
+    uint8_t lsr_id[4];
+    uint8_t label_space[2];
 };
 
 #define LDP_VERSION 1
 
-/* 
+/*
+ * ldp message header
+ *
+ *  0                   1                   2                   3
+ *  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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |U|   Message Type              |      Message Length           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     Message ID                                |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                     Mandatory Parameters                      |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * +                                                               +
+ * |                     Optional Parameters                       |
+ * +                                                               +
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+struct ldp_msg_header {
+    uint8_t type[2];
+    uint8_t length[2];
+    uint8_t id[4];
+};
+
+#define        LDP_MASK_MSG_TYPE(x)  ((x)&0x7fff)
+#define        LDP_MASK_U_BIT(x)     ((x)&0x8000)
+
+#define        LDP_MSG_NOTIF                0x0001
+#define        LDP_MSG_HELLO                0x0100
+#define        LDP_MSG_INIT                 0x0200
+#define        LDP_MSG_KEEPALIVE            0x0201
+#define        LDP_MSG_ADDRESS              0x0300
+#define        LDP_MSG_ADDRESS_WITHDRAW     0x0301
+#define        LDP_MSG_LABEL_MAPPING        0x0400
+#define        LDP_MSG_LABEL_REQUEST        0x0401
+#define        LDP_MSG_LABEL_WITHDRAW       0x0402
+#define        LDP_MSG_LABEL_RELEASE        0x0403
+#define        LDP_MSG_LABEL_ABORT_REQUEST  0x0404
+
+#define        LDP_VENDOR_PRIVATE_MIN       0x3e00
+#define        LDP_VENDOR_PRIVATE_MAX       0x3eff
+#define        LDP_EXPERIMENTAL_MIN         0x3f00
+#define        LDP_EXPERIMENTAL_MAX         0x3fff
+
+static const struct tok ldp_msg_values[] = {
+    { LDP_MSG_NOTIF,                "Notification" },
+    { LDP_MSG_HELLO,                "Hello" },
+    { LDP_MSG_INIT,                 "Initialization" },
+    { LDP_MSG_KEEPALIVE,             "Keepalive" },
+    { LDP_MSG_ADDRESS,              "Address" },
+    { LDP_MSG_ADDRESS_WITHDRAW,             "Address Withdraw" },
+    { LDP_MSG_LABEL_MAPPING,        "Label Mapping" },
+    { LDP_MSG_LABEL_REQUEST,        "Label Request" },
+    { LDP_MSG_LABEL_WITHDRAW,       "Label Withdraw" },
+    { LDP_MSG_LABEL_RELEASE,        "Label Release" },
+    { LDP_MSG_LABEL_ABORT_REQUEST,   "Label Abort Request" },
+    { 0, NULL}
+};
+
+#define        LDP_MASK_TLV_TYPE(x)  ((x)&0x3fff)
+#define        LDP_MASK_F_BIT(x) ((x)&0x4000)
+
+#define        LDP_TLV_FEC                  0x0100
+#define        LDP_TLV_ADDRESS_LIST         0x0101
+#define LDP_TLV_ADDRESS_LIST_AFNUM_LEN 2
+#define        LDP_TLV_HOP_COUNT            0x0103
+#define        LDP_TLV_PATH_VECTOR          0x0104
+#define        LDP_TLV_GENERIC_LABEL        0x0200
+#define        LDP_TLV_ATM_LABEL            0x0201
+#define        LDP_TLV_FR_LABEL             0x0202
+#define        LDP_TLV_STATUS               0x0300
+#define        LDP_TLV_EXTD_STATUS          0x0301
+#define        LDP_TLV_RETURNED_PDU         0x0302
+#define        LDP_TLV_RETURNED_MSG         0x0303
+#define        LDP_TLV_COMMON_HELLO         0x0400
+#define        LDP_TLV_IPV4_TRANSPORT_ADDR  0x0401
+#define        LDP_TLV_CONFIG_SEQ_NUMBER    0x0402
+#define        LDP_TLV_IPV6_TRANSPORT_ADDR  0x0403
+#define        LDP_TLV_COMMON_SESSION       0x0500
+#define        LDP_TLV_ATM_SESSION_PARM     0x0501
+#define        LDP_TLV_FR_SESSION_PARM      0x0502
+#define LDP_TLV_FT_SESSION          0x0503
+#define        LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
+#define LDP_TLV_MTU                  0x0601 /* rfc 3988 */
+
+static const struct tok ldp_tlv_values[] = {
+    { LDP_TLV_FEC,                  "FEC" },
+    { LDP_TLV_ADDRESS_LIST,          "Address List" },
+    { LDP_TLV_HOP_COUNT,             "Hop Count" },
+    { LDP_TLV_PATH_VECTOR,           "Path Vector" },
+    { LDP_TLV_GENERIC_LABEL,         "Generic Label" },
+    { LDP_TLV_ATM_LABEL,             "ATM Label" },
+    { LDP_TLV_FR_LABEL,              "Frame-Relay Label" },
+    { LDP_TLV_STATUS,                "Status" },
+    { LDP_TLV_EXTD_STATUS,           "Extended Status" },
+    { LDP_TLV_RETURNED_PDU,          "Returned PDU" },
+    { LDP_TLV_RETURNED_MSG,          "Returned Message" },
+    { LDP_TLV_COMMON_HELLO,          "Common Hello Parameters" },
+    { LDP_TLV_IPV4_TRANSPORT_ADDR,   "IPv4 Transport Address" },
+    { LDP_TLV_CONFIG_SEQ_NUMBER,     "Configuration Sequence Number" },
+    { LDP_TLV_IPV6_TRANSPORT_ADDR,   "IPv6 Transport Address" },
+    { LDP_TLV_COMMON_SESSION,        "Common Session Parameters" },
+    { LDP_TLV_ATM_SESSION_PARM,      "ATM Session Parameters" },
+    { LDP_TLV_FR_SESSION_PARM,       "Frame-Relay Session Parameters" },
+    { LDP_TLV_FT_SESSION,            "Fault-Tolerant Session Parameters" },
+    { LDP_TLV_LABEL_REQUEST_MSG_ID,  "Label Request Message ID" },
+    { LDP_TLV_MTU,                   "MTU" },
+    { 0, NULL}
+};
+
+#define LDP_FEC_WILDCARD       0x01
+#define LDP_FEC_PREFIX         0x02
+#define LDP_FEC_HOSTADDRESS    0x03
+/* From RFC 4906; should probably be updated to RFC 4447 (e.g., VC -> PW) */
+#define LDP_FEC_MARTINI_VC     0x80
+
+static const struct tok ldp_fec_values[] = {
+    { LDP_FEC_WILDCARD,                "Wildcard" },
+    { LDP_FEC_PREFIX,          "Prefix" },
+    { LDP_FEC_HOSTADDRESS,     "Host address" },
+    { LDP_FEC_MARTINI_VC,      "Martini VC" },
+    { 0, NULL}
+};
+
+#define LDP_FEC_MARTINI_IFPARM_MTU  0x01
+#define LDP_FEC_MARTINI_IFPARM_DESC 0x03
+#define LDP_FEC_MARTINI_IFPARM_VCCV 0x0c
+
+static const struct tok ldp_fec_martini_ifparm_values[] = {
+    { LDP_FEC_MARTINI_IFPARM_MTU, "MTU" },
+    { LDP_FEC_MARTINI_IFPARM_DESC, "Description" },
+    { LDP_FEC_MARTINI_IFPARM_VCCV, "VCCV" },
+    { 0, NULL}
+};
+
+/* draft-ietf-pwe3-vccv-04.txt */
+static const struct tok ldp_fec_martini_ifparm_vccv_cc_values[] = {
+    { 0x01, "PWE3 control word" },
+    { 0x02, "MPLS Router Alert Label" },
+    { 0x04, "MPLS inner label TTL = 1" },
+    { 0, NULL}
+};
+
+/* draft-ietf-pwe3-vccv-04.txt */
+static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = {
+    { 0x01, "ICMP Ping" },
+    { 0x02, "LSP Ping" },
+    { 0x04, "BFD" },
+    { 0, NULL}
+};
+
+static int ldp_pdu_print(netdissect_options *, register const u_char *);
+
+/*
  * ldp tlv header
  *
  *  0                   1                   2                   3
@@ -74,134 +228,472 @@ struct ldp_common_header {
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
-struct ldp_tlv_header {
-    u_int8_t type[2];
-    u_int8_t length[2];
-};
+#define TLV_TCHECK(minlen) \
+    ND_TCHECK2(*tptr, minlen); if (tlv_tlen < minlen) goto badtlv;
 
-#define        LDP_MASK_TLV_TYPE(x)  ((x)&0x3fff) 
-#define        LDP_MASK_TLV_U_BIT(x) ((x)&0x8000) 
-#define        LDP_MASK_TLV_F_BIT(x) ((x)&0x4000) 
+static int
+ldp_tlv_print(netdissect_options *ndo,
+              register const u_char *tptr,
+              u_short msg_tlen) {
 
-#define        LDP_TLV_FEC            0x0100
-#define        LDP_TLV_ADDRESS_LIST   0x0101
-#define        LDP_TLV_HOP_COUNT      0x0103
-#define        LDP_TLV_PATH_VECTOR    0x0104
-#define        LDP_TLV_GENERIC_LABEL  0x0200
-#define        LDP_TLV_ATM_LABEL      0x0201
-#define        LDP_TLV_FR_LABEL       0x0202
-#define        LDP_TLV_STATUS         0x0300
+    struct ldp_tlv_header {
+        uint8_t type[2];
+        uint8_t length[2];
+    };
 
-static const struct tok ldp_tlv_values[] = {
-    { LDP_TLV_FEC,            "FEC" },
-    { LDP_TLV_ADDRESS_LIST,    "Address List" },
-    { LDP_TLV_HOP_COUNT,       "Hop Count" },
-    { LDP_TLV_HOP_COUNT,       "Path Vector" },
-    { LDP_TLV_GENERIC_LABEL,   "Generic Label" },
-    { LDP_TLV_ATM_LABEL,       "ATM Label" },
-    { LDP_TLV_FR_LABEL,        "Frame-Relay Label" },
-    { LDP_TLV_STATUS,          "Status" },
-    { 0, NULL}
-};
+    const struct ldp_tlv_header *ldp_tlv_header;
+    u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags;
+    u_char fec_type;
+    u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx;
+    char buf[100];
+    int i;
+
+    ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
+    ND_TCHECK(*ldp_tlv_header);
+    tlv_len=EXTRACT_16BITS(ldp_tlv_header->length);
+    if (tlv_len + 4 > msg_tlen) {
+        ND_PRINT((ndo, "\n\t\t TLV contents go past end of message"));
+        return 0;
+    }
+    tlv_tlen=tlv_len;
+    tlv_type=LDP_MASK_TLV_TYPE(EXTRACT_16BITS(ldp_tlv_header->type));
+
+    /* FIXME vendor private / experimental check */
+    ND_PRINT((ndo, "\n\t    %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
+           tok2str(ldp_tlv_values,
+                   "Unknown",
+                   tlv_type),
+           tlv_type,
+           tlv_len,
+           LDP_MASK_U_BIT(EXTRACT_16BITS(&ldp_tlv_header->type)) ? "continue processing" : "ignore",
+           LDP_MASK_F_BIT(EXTRACT_16BITS(&ldp_tlv_header->type)) ? "do" : "don't"));
+
+    tptr+=sizeof(struct ldp_tlv_header);
+
+    switch(tlv_type) {
 
-#define FALSE 0
-#define TRUE  1
+    case LDP_TLV_COMMON_HELLO:
+        TLV_TCHECK(4);
+        ND_PRINT((ndo, "\n\t      Hold Time: %us, Flags: [%s Hello%s]",
+               EXTRACT_16BITS(tptr),
+               (EXTRACT_16BITS(tptr+2)&0x8000) ? "Targeted" : "Link",
+               (EXTRACT_16BITS(tptr+2)&0x4000) ? ", Request for targeted Hellos" : ""));
+        break;
+
+    case LDP_TLV_IPV4_TRANSPORT_ADDR:
+        TLV_TCHECK(4);
+        ND_PRINT((ndo, "\n\t      IPv4 Transport Address: %s", ipaddr_string(ndo, tptr)));
+        break;
+#ifdef INET6
+    case LDP_TLV_IPV6_TRANSPORT_ADDR:
+        TLV_TCHECK(16);
+        ND_PRINT((ndo, "\n\t      IPv6 Transport Address: %s", ip6addr_string(ndo, tptr)));
+        break;
+#endif
+    case LDP_TLV_CONFIG_SEQ_NUMBER:
+        TLV_TCHECK(4);
+        ND_PRINT((ndo, "\n\t      Sequence Number: %u", EXTRACT_32BITS(tptr)));
+        break;
+
+    case LDP_TLV_ADDRESS_LIST:
+        TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
+       af = EXTRACT_16BITS(tptr);
+       tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
+        tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
+       ND_PRINT((ndo, "\n\t      Address Family: %s, addresses",
+               tok2str(af_values, "Unknown (%u)", af)));
+        switch (af) {
+        case AFNUM_INET:
+           while(tlv_tlen >= sizeof(struct in_addr)) {
+               ND_TCHECK2(*tptr, sizeof(struct in_addr));
+               ND_PRINT((ndo, " %s", ipaddr_string(ndo, tptr)));
+               tlv_tlen-=sizeof(struct in_addr);
+               tptr+=sizeof(struct in_addr);
+           }
+            break;
+#ifdef INET6
+        case AFNUM_INET6:
+           while(tlv_tlen >= sizeof(struct in6_addr)) {
+               ND_TCHECK2(*tptr, sizeof(struct in6_addr));
+               ND_PRINT((ndo, " %s", ip6addr_string(ndo, tptr)));
+               tlv_tlen-=sizeof(struct in6_addr);
+               tptr+=sizeof(struct in6_addr);
+           }
+            break;
+#endif
+        default:
+            /* unknown AF */
+            break;
+        }
+       break;
+
+    case LDP_TLV_COMMON_SESSION:
+       TLV_TCHECK(8);
+       ND_PRINT((ndo, "\n\t      Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]",
+              EXTRACT_16BITS(tptr), EXTRACT_16BITS(tptr+2),
+              (EXTRACT_16BITS(tptr+6)&0x8000) ? "On Demand" : "Unsolicited",
+              (EXTRACT_16BITS(tptr+6)&0x4000) ? "Enabled" : "Disabled"
+              ));
+       break;
+
+    case LDP_TLV_FEC:
+        TLV_TCHECK(1);
+        fec_type = *tptr;
+       ND_PRINT((ndo, "\n\t      %s FEC (0x%02x)",
+              tok2str(ldp_fec_values, "Unknown", fec_type),
+              fec_type));
+
+       tptr+=1;
+       tlv_tlen-=1;
+       switch(fec_type) {
+
+       case LDP_FEC_WILDCARD:
+           break;
+       case LDP_FEC_PREFIX:
+           TLV_TCHECK(2);
+           af = EXTRACT_16BITS(tptr);
+           tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
+           tlv_tlen-=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
+           if (af == AFNUM_INET) {
+               i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf));
+               if (i == -2)
+                   goto trunc;
+               if (i == -3)
+                   ND_PRINT((ndo, ": IPv4 prefix (goes past end of TLV)"));
+               else if (i == -1)
+                   ND_PRINT((ndo, ": IPv4 prefix (invalid length)"));
+               else
+                   ND_PRINT((ndo, ": IPv4 prefix %s", buf));
+           }
+#ifdef INET6
+           else if (af == AFNUM_INET6) {
+               i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf));
+               if (i == -2)
+                   goto trunc;
+               if (i == -3)
+                   ND_PRINT((ndo, ": IPv4 prefix (goes past end of TLV)"));
+               else if (i == -1)
+                   ND_PRINT((ndo, ": IPv6 prefix (invalid length)"));
+               else
+                   ND_PRINT((ndo, ": IPv6 prefix %s", buf));
+           }
+#endif
+           else
+               ND_PRINT((ndo, ": Address family %u prefix", af));
+           break;
+       case LDP_FEC_HOSTADDRESS:
+           break;
+       case LDP_FEC_MARTINI_VC:
+            /*
+            * According to RFC 4908, the VC info Length field can be zero,
+            * in which case not only are there no interface parameters,
+            * there's no VC ID.
+            */
+            TLV_TCHECK(7);
+            vc_info_len = *(tptr+2);
+
+            if (vc_info_len == 0) {
+                ND_PRINT((ndo, ": %s, %scontrol word, group-ID %u, VC-info-length: %u",
+                       tok2str(l2vpn_encaps_values, "Unknown", EXTRACT_16BITS(tptr)&0x7fff),
+                       EXTRACT_16BITS(tptr)&0x8000 ? "" : "no ",
+                       EXTRACT_32BITS(tptr+3),
+                       vc_info_len));
+                break;
+            }
+
+            /* Make sure we have the VC ID as well */
+            TLV_TCHECK(11);
+           ND_PRINT((ndo, ": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u",
+                  tok2str(l2vpn_encaps_values, "Unknown", EXTRACT_16BITS(tptr)&0x7fff),
+                  EXTRACT_16BITS(tptr)&0x8000 ? "" : "no ",
+                   EXTRACT_32BITS(tptr+3),
+                  EXTRACT_32BITS(tptr+7),
+                   vc_info_len));
+            if (vc_info_len < 4) {
+                /* minimum 4, for the VC ID */
+                ND_PRINT((ndo, " (invalid, < 4"));
+                return(tlv_len+4); /* Type & Length fields not included */
+           }
+            vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */
+
+            /* Skip past the fixed information and the VC ID */
+            tptr+=11;
+            tlv_tlen-=11;
+            TLV_TCHECK(vc_info_len);
+
+            while (vc_info_len > 2) {
+                vc_info_tlv_type = *tptr;
+                vc_info_tlv_len = *(tptr+1);
+                if (vc_info_tlv_len < 2)
+                    break;
+                if (vc_info_len < vc_info_tlv_len)
+                    break;
+
+                ND_PRINT((ndo, "\n\t\tInterface Parameter: %s (0x%02x), len %u",
+                       tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
+                       vc_info_tlv_type,
+                       vc_info_tlv_len));
+
+                switch(vc_info_tlv_type) {
+                case LDP_FEC_MARTINI_IFPARM_MTU:
+                    ND_PRINT((ndo, ": %u", EXTRACT_16BITS(tptr+2)));
+                    break;
+
+                case LDP_FEC_MARTINI_IFPARM_DESC:
+                    ND_PRINT((ndo, ": "));
+                    for (idx = 2; idx < vc_info_tlv_len; idx++)
+                        safeputchar(ndo, *(tptr + idx));
+                    break;
+
+                case LDP_FEC_MARTINI_IFPARM_VCCV:
+                    ND_PRINT((ndo, "\n\t\t  Control Channels (0x%02x) = [%s]",
+                           *(tptr+2),
+                           bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", *(tptr+2))));
+                    ND_PRINT((ndo, "\n\t\t  CV Types (0x%02x) = [%s]",
+                           *(tptr+3),
+                           bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", *(tptr+3))));
+                    break;
+
+                default:
+                    print_unknown_data(ndo, tptr+2, "\n\t\t  ", vc_info_tlv_len-2);
+                    break;
+                }
+
+                vc_info_len -= vc_info_tlv_len;
+                tptr += vc_info_tlv_len;
+            }
+           break;
+       }
+
+       break;
+
+    case LDP_TLV_GENERIC_LABEL:
+       TLV_TCHECK(4);
+       ND_PRINT((ndo, "\n\t      Label: %u", EXTRACT_32BITS(tptr) & 0xfffff));
+       break;
+
+    case LDP_TLV_STATUS:
+       TLV_TCHECK(8);
+       ui = EXTRACT_32BITS(tptr);
+       tptr+=4;
+       ND_PRINT((ndo, "\n\t      Status: 0x%02x, Flags: [%s and %s forward]",
+              ui&0x3fffffff,
+              ui&0x80000000 ? "Fatal error" : "Advisory Notification",
+              ui&0x40000000 ? "do" : "don't"));
+       ui = EXTRACT_32BITS(tptr);
+       tptr+=4;
+       if (ui)
+           ND_PRINT((ndo, ", causing Message ID: 0x%08x", ui));
+       break;
+
+    case LDP_TLV_FT_SESSION:
+       TLV_TCHECK(8);
+       ft_flags = EXTRACT_16BITS(tptr);
+       ND_PRINT((ndo, "\n\t      Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]",
+              ft_flags&0x8000 ? "" : "No ",
+              ft_flags&0x8 ? "" : "Don't ",
+              ft_flags&0x4 ? "" : "No ",
+              ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels",
+              ft_flags&0x1 ? "" : "Don't "));
+       tptr+=4;
+       ui = EXTRACT_32BITS(tptr);
+       if (ui)
+           ND_PRINT((ndo, ", Reconnect Timeout: %ums", ui));
+       tptr+=4;
+       ui = EXTRACT_32BITS(tptr);
+       if (ui)
+           ND_PRINT((ndo, ", Recovery Time: %ums", ui));
+       break;
+
+    case LDP_TLV_MTU:
+       TLV_TCHECK(2);
+       ND_PRINT((ndo, "\n\t      MTU: %u", EXTRACT_16BITS(tptr)));
+       break;
+
+
+    /*
+     *  FIXME those are the defined TLVs that lack a decoder
+     *  you are welcome to contribute code ;-)
+     */
+
+    case LDP_TLV_HOP_COUNT:
+    case LDP_TLV_PATH_VECTOR:
+    case LDP_TLV_ATM_LABEL:
+    case LDP_TLV_FR_LABEL:
+    case LDP_TLV_EXTD_STATUS:
+    case LDP_TLV_RETURNED_PDU:
+    case LDP_TLV_RETURNED_MSG:
+    case LDP_TLV_ATM_SESSION_PARM:
+    case LDP_TLV_FR_SESSION_PARM:
+    case LDP_TLV_LABEL_REQUEST_MSG_ID:
+
+    default:
+        if (ndo->ndo_vflag <= 1)
+            print_unknown_data(ndo, tptr, "\n\t      ", tlv_tlen);
+        break;
+    }
+    return(tlv_len+4); /* Type & Length fields not included */
+
+trunc:
+    ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
+    return 0;
+
+badtlv:
+    ND_PRINT((ndo, "\n\t\t TLV contents go past end of TLV"));
+    return(tlv_len+4); /* Type & Length fields not included */
+}
 
 void
-ldp_print(register const u_char *pptr, register u_int len) {
+ldp_print(netdissect_options *ndo,
+          register const u_char *pptr, register u_int len) {
+
+    int processed;
+    while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
+        processed = ldp_pdu_print(ndo, pptr);
+        if (processed == 0)
+            return;
+        len -= processed;
+        pptr += processed;
+    }
+}
+
+static int
+ldp_pdu_print(netdissect_options *ndo,
+              register const u_char *pptr) {
 
     const struct ldp_common_header *ldp_com_header;
-    const struct ldp_tlv_header *ldp_tlv_header;
-    const u_char *tptr,*tlv_tptr;
-    u_short tlen,tlv_len,tlv_type,tlv_tlen;
-    int hexdump;
+    const struct ldp_msg_header *ldp_msg_header;
+    const u_char *tptr,*msg_tptr;
+    u_short tlen;
+    u_short pdu_len,msg_len,msg_type,msg_tlen;
+    int hexdump,processed;
 
-    tptr=pptr;
     ldp_com_header = (const struct ldp_common_header *)pptr;
-    TCHECK(*ldp_com_header);
+    ND_TCHECK(*ldp_com_header);
 
     /*
      * Sanity checking of the header.
      */
     if (EXTRACT_16BITS(&ldp_com_header->version) != LDP_VERSION) {
-       printf("LDP version %u packet not supported",
-               EXTRACT_16BITS(&ldp_com_header->version));
-       return;
+       ND_PRINT((ndo, "%sLDP version %u packet not supported",
+               (ndo->ndo_vflag < 1) ? "" : "\n\t",
+               EXTRACT_16BITS(&ldp_com_header->version)));
+       return 0;
+    }
+
+    pdu_len = EXTRACT_16BITS(&ldp_com_header->pdu_length);
+    if (pdu_len < sizeof(const struct ldp_common_header)-4) {
+        /* length too short */
+        ND_PRINT((ndo, "%sLDP, pdu-length: %u (too short, < %u)",
+               (ndo->ndo_vflag < 1) ? "" : "\n\t",
+               pdu_len,
+               (u_int)(sizeof(const struct ldp_common_header)-4)));
+        return 0;
     }
 
     /* print the LSR-ID, label-space & length */
-    printf("%sLDP, Label-Space-ID: %s:%u, length: %u",
-           (vflag < 1) ? "" : "\n\t",
-           ipaddr_string(&ldp_com_header->lsr_id),
+    ND_PRINT((ndo, "%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
+           (ndo->ndo_vflag < 1) ? "" : "\n\t",
+           ipaddr_string(ndo, &ldp_com_header->lsr_id),
            EXTRACT_16BITS(&ldp_com_header->label_space),
-           len);
+           pdu_len));
 
-    /* bail out if non-verbose */ 
-    if (vflag < 1)
-        return;
+    /* bail out if non-verbose */
+    if (ndo->ndo_vflag < 1)
+        return 0;
 
     /* ok they seem to want to know everything - lets fully decode it */
-    tlen=EXTRACT_16BITS(ldp_com_header->pdu_length);
-
-    tptr+=sizeof(const struct ldp_common_header);
-    tlen-=sizeof(const struct ldp_common_header);
+    tptr = pptr + sizeof(const struct ldp_common_header);
+    tlen = pdu_len - (sizeof(const struct ldp_common_header)-4);       /* Type & Length fields not included */
 
     while(tlen>0) {
-        /* did we capture enough for fully decoding the tlv header ? */
-        if (!TTEST2(*tptr, sizeof(struct ldp_tlv_header)))
-            goto trunc;
+        /* did we capture enough for fully decoding the msg header ? */
+        ND_TCHECK2(*tptr, sizeof(struct ldp_msg_header));
 
-        ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
-        tlv_len=EXTRACT_16BITS(ldp_tlv_header->length);
-        tlv_type=LDP_MASK_TLV_TYPE(EXTRACT_16BITS(ldp_tlv_header->type));
+        ldp_msg_header = (const struct ldp_msg_header *)tptr;
+        msg_len=EXTRACT_16BITS(ldp_msg_header->length);
+        msg_type=LDP_MASK_MSG_TYPE(EXTRACT_16BITS(ldp_msg_header->type));
 
-        printf("\n\t  %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
-               tok2str(ldp_tlv_values,
+        if (msg_len < sizeof(struct ldp_msg_header)-4) {
+            /* length too short */
+            /* FIXME vendor private / experimental check */
+            ND_PRINT((ndo, "\n\t  %s Message (0x%04x), length: %u (too short, < %u)",
+                   tok2str(ldp_msg_values,
+                           "Unknown",
+                           msg_type),
+                   msg_type,
+                   msg_len,
+                   (u_int)(sizeof(struct ldp_msg_header)-4)));
+            return 0;
+        }
+
+        /* FIXME vendor private / experimental check */
+        ND_PRINT((ndo, "\n\t  %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
+               tok2str(ldp_msg_values,
                        "Unknown",
-                       tlv_type),
-               tlv_type,
-               tlv_len,
-               LDP_MASK_TLV_U_BIT(EXTRACT_16BITS(&ldp_tlv_header->type)) ? "continue processing" : "ignore all, notify",
-               LDP_MASK_TLV_F_BIT(EXTRACT_16BITS(&ldp_tlv_header->type)) ? "do" : "don't");
-
-        tlv_tptr=tptr+sizeof(struct ldp_tlv_header);
-        tlv_tlen=tlv_len-sizeof(struct ldp_tlv_header);
-
-        /* did we capture enough for fully decoding the object ? */
-        if (!TTEST2(*tptr, tlv_len))
-            goto trunc;
+                       msg_type),
+               msg_type,
+               msg_len,
+               EXTRACT_32BITS(&ldp_msg_header->id),
+               LDP_MASK_U_BIT(EXTRACT_16BITS(&ldp_msg_header->type)) ? "continue processing" : "ignore"));
+
+        msg_tptr=tptr+sizeof(struct ldp_msg_header);
+        msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */
+
+        /* did we capture enough for fully decoding the message ? */
+        ND_TCHECK2(*tptr, msg_len);
         hexdump=FALSE;
 
-        switch(tlv_type) {
+        switch(msg_type) {
+
+        case LDP_MSG_NOTIF:
+        case LDP_MSG_HELLO:
+        case LDP_MSG_INIT:
+        case LDP_MSG_KEEPALIVE:
+        case LDP_MSG_ADDRESS:
+        case LDP_MSG_LABEL_MAPPING:
+        case LDP_MSG_ADDRESS_WITHDRAW:
+        case LDP_MSG_LABEL_WITHDRAW:
+            while(msg_tlen >= 4) {
+                processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen);
+                if (processed == 0)
+                    break;
+                msg_tlen-=processed;
+                msg_tptr+=processed;
+            }
+            break;
+
         /*
-         *  FIXME those are the defined objects that lack a decoder
+         *  FIXME those are the defined messages that lack a decoder
          *  you are welcome to contribute code ;-)
          */
 
-        case LDP_TLV_FEC:
-        case LDP_TLV_ADDRESS_LIST:
-        case LDP_TLV_HOP_COUNT:
-        case LDP_TLV_PATH_VECTOR:
-        case LDP_TLV_GENERIC_LABEL:
-        case LDP_TLV_ATM_LABEL:
-        case LDP_TLV_FR_LABEL:
-        case LDP_TLV_STATUS:
+        case LDP_MSG_LABEL_REQUEST:
+        case LDP_MSG_LABEL_RELEASE:
+        case LDP_MSG_LABEL_ABORT_REQUEST:
+
         default:
-            if (vflag <= 1)
-                print_unknown_data(tlv_tptr,"\n\t    ",tlv_tlen);
+            if (ndo->ndo_vflag <= 1)
+                print_unknown_data(ndo, msg_tptr, "\n\t  ", msg_tlen);
             break;
         }
         /* do we want to see an additionally hexdump ? */
-        if (vflag > 1 || hexdump==TRUE)
-            print_unknown_data(tptr+sizeof(sizeof(struct ldp_tlv_header)),"\n\t    ",
-                               tlv_len-sizeof(struct ldp_tlv_header));
+        if (ndo->ndo_vflag > 1 || hexdump==TRUE)
+            print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t  ",
+                               msg_len);
 
-        tptr+=tlv_len;
-        tlen-=tlv_len;
+        tptr += msg_len+4;
+        tlen -= msg_len+4;
     }
-    return;
+    return pdu_len+4;
 trunc:
-    printf("\n\t\t packet exceeded snapshot");
+    ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
+    return 0;
 }
 
+/*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 8
+ * End:
+ */