]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-ldp.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-ldp.c
index fc5ff42e67fbaac08f4fde465dcc5844a047519d..bdf9a13843f88feae2c5b54dd95a027d4403b290 100644 (file)
  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * FOR A PARTICULAR PURPOSE.
  *
  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * FOR A PARTICULAR PURPOSE.
  *
- * Original code by Hannes Gredler (hannes@juniper.net)
+ * Original code by Hannes Gredler (hannes@gredler.at)
  *  and Steinar Haug ([email protected])
  */
 
  *  and Steinar Haug ([email protected])
  */
 
-#define NETDISSECT_REWORKED
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+/* \summary: Label Distribution Protocol (LDP) printer */
 
 
-#include <tcpdump-stdinc.h>
+#include <config.h>
 
 
-#include "interface.h"
+#include "netdissect-stdinc.h"
+
+#include "netdissect.h"
 #include "extract.h"
 #include "addrtoname.h"
 
 #include "extract.h"
 #include "addrtoname.h"
 
  */
 
 struct ldp_common_header {
  */
 
 struct ldp_common_header {
-    uint8_t version[2];
-    uint8_t pdu_length[2];
-    uint8_t lsr_id[4];
-    uint8_t label_space[2];
+    nd_uint16_t version;
+    nd_uint16_t pdu_length;
+    nd_ipv4     lsr_id;
+    nd_uint16_t label_space;
 };
 
 #define LDP_VERSION 1
 };
 
 #define LDP_VERSION 1
@@ -77,9 +76,9 @@ struct ldp_common_header {
  */
 
 struct ldp_msg_header {
  */
 
 struct ldp_msg_header {
-    uint8_t type[2];
-    uint8_t length[2];
-    uint8_t id[4];
+    nd_uint16_t type;
+    nd_uint16_t length;
+    nd_uint32_t id;
 };
 
 #define        LDP_MASK_MSG_TYPE(x)  ((x)&0x7fff)
 };
 
 #define        LDP_MASK_MSG_TYPE(x)  ((x)&0x7fff)
@@ -140,8 +139,10 @@ static const struct tok ldp_msg_values[] = {
 #define        LDP_TLV_ATM_SESSION_PARM     0x0501
 #define        LDP_TLV_FR_SESSION_PARM      0x0502
 #define LDP_TLV_FT_SESSION          0x0503
 #define        LDP_TLV_ATM_SESSION_PARM     0x0501
 #define        LDP_TLV_FR_SESSION_PARM      0x0502
 #define LDP_TLV_FT_SESSION          0x0503
+#define LDP_TLV_TYPED_WC_FEC_CAP     0x050b /* rfc 5918 */
 #define        LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
 #define LDP_TLV_MTU                  0x0601 /* rfc 3988 */
 #define        LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
 #define LDP_TLV_MTU                  0x0601 /* rfc 3988 */
+#define LDP_TLV_DUAL_STACK_CAP       0x0701 /* rfc 7552 */
 
 static const struct tok ldp_tlv_values[] = {
     { LDP_TLV_FEC,                  "FEC" },
 
 static const struct tok ldp_tlv_values[] = {
     { LDP_TLV_FEC,                  "FEC" },
@@ -163,8 +164,41 @@ static const struct tok ldp_tlv_values[] = {
     { 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_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_TYPED_WC_FEC_CAP,      "Typed Wildcard FEC Capability" },
     { LDP_TLV_LABEL_REQUEST_MSG_ID,  "Label Request Message ID" },
     { LDP_TLV_MTU,                   "MTU" },
     { LDP_TLV_LABEL_REQUEST_MSG_ID,  "Label Request Message ID" },
     { LDP_TLV_MTU,                   "MTU" },
+    { LDP_TLV_DUAL_STACK_CAP,        "Dual-Stack Capability" },
+    { 0, NULL}
+};
+
+static const struct tok ldp_status_code_values[] = {
+    /* rfc 5036 */
+    { 0x00000000, "Success" },
+    { 0x00000001, "Bad LDP Identifier" },
+    { 0x00000002, "Bad Protocol Version" },
+    { 0x00000003, "Bad PDU Length" },
+    { 0x00000004, "Unknown Message Type" },
+    { 0x00000005, "Bad Message Length" },
+    { 0x00000006, "Unknown TLV" },
+    { 0x00000007, "Bad TLV Length" },
+    { 0x00000008, "Malformted TLV Value" },
+    { 0x00000009, "Hold Timer Expired" },
+    { 0x0000000A, "Shutdown" },
+    { 0x0000000B, "Loop Detected" },
+    { 0x0000000C, "Unknown FEC" },
+    { 0x0000000D, "No Route" },
+    { 0x0000000E, "No Label Resources" },
+    { 0x0000000F, "Label Resources/Available" },
+    { 0x00000010, "Session Rejected/No Hello" },
+    { 0x00000011, "Session Rejected/Parameters Advertisement Mode" },
+    { 0x00000012, "Session Rejected/Parameters Max PDU Length" },
+    { 0x00000013, "Session Rejected/Parameters Label Range" },
+    { 0x00000014, "KeepAlive Timer Expired" },
+    { 0x00000015, "Label Request Aborted" },
+    { 0x00000016, "Missing Message Parameters" },
+    { 0x00000017, "Unsupported Address Family" },
+    { 0x00000018, "Session Rejected/Bad KeepAlive Time" },
+    { 0x00000019, "Internal Error" },
     { 0, NULL}
 };
 
     { 0, NULL}
 };
 
@@ -209,7 +243,17 @@ static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = {
     { 0, NULL}
 };
 
     { 0, NULL}
 };
 
-static int ldp_msg_print(netdissect_options *, register const u_char *);
+/* rfc 7552 */
+#define LDP_DUAL_STACK_TRANSPORT_PREF_IPV4  0x40
+#define LDP_DUAL_STACK_TRANSPORT_PREF_IPV6  0x60
+
+static const struct tok ldp_dual_stack_transport_pref_values[] = {
+    { LDP_DUAL_STACK_TRANSPORT_PREF_IPV4, "IPv4" },
+    { LDP_DUAL_STACK_TRANSPORT_PREF_IPV6, "IPv6" },
+    { 0, NULL}
+};
+
+static u_int ldp_pdu_print(netdissect_options *, const u_char *);
 
 /*
  * ldp tlv header
 
 /*
  * ldp tlv header
@@ -228,114 +272,135 @@ static int ldp_msg_print(netdissect_options *, register const u_char *);
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
-#define TLV_TCHECK(minlen) \
-    ND_TCHECK2(*tptr, minlen); if (tlv_tlen < minlen) goto badtlv;
-
-static int
+static u_int
 ldp_tlv_print(netdissect_options *ndo,
 ldp_tlv_print(netdissect_options *ndo,
-              register const u_char *tptr) {
-
+              const u_char *tptr,
+              u_int msg_tlen)
+{
     struct ldp_tlv_header {
     struct ldp_tlv_header {
-        uint8_t type[2];
-        uint8_t length[2];
+        nd_uint16_t type;
+        nd_uint16_t length;
     };
 
     const struct ldp_tlv_header *ldp_tlv_header;
     u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags;
     };
 
     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;
+    u_char fec_type, transport_pref;
+    u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len;
     char buf[100];
     int i;
 
     ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
     char buf[100];
     int i;
 
     ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
-    tlv_len=EXTRACT_16BITS(ldp_tlv_header->length);
+    ND_TCHECK_SIZE(ldp_tlv_header);
+    tlv_len=GET_BE_U_2(ldp_tlv_header->length);
+    if (tlv_len + 4U > msg_tlen) {
+        ND_PRINT("\n\t\t TLV contents go past end of message");
+        return 0;
+    }
     tlv_tlen=tlv_len;
     tlv_tlen=tlv_len;
-    tlv_type=LDP_MASK_TLV_TYPE(EXTRACT_16BITS(ldp_tlv_header->type));
+    tlv_type=LDP_MASK_TLV_TYPE(GET_BE_U_2(ldp_tlv_header->type));
 
     /* FIXME vendor private / experimental check */
 
     /* FIXME vendor private / experimental check */
-    ND_PRINT((ndo, "\n\t    %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
+    ND_PRINT("\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,
            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"));
+           LDP_MASK_U_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "continue processing" : "ignore",
+           LDP_MASK_F_BIT(GET_BE_U_2(ldp_tlv_header->type)) ? "do" : "don't");
 
     tptr+=sizeof(struct ldp_tlv_header);
 
     switch(tlv_type) {
 
     case LDP_TLV_COMMON_HELLO:
 
     tptr+=sizeof(struct ldp_tlv_header);
 
     switch(tlv_type) {
 
     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" : ""));
+        ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 4);
+        ND_PRINT("\n\t      Hold Time: %us, Flags: [%s Hello%s]",
+               GET_BE_U_2(tptr),
+               (GET_BE_U_2(tptr + 2)&0x8000) ? "Targeted" : "Link",
+               (GET_BE_U_2(tptr + 2)&0x4000) ? ", Request for targeted Hellos" : "");
         break;
 
     case LDP_TLV_IPV4_TRANSPORT_ADDR:
         break;
 
     case LDP_TLV_IPV4_TRANSPORT_ADDR:
-        TLV_TCHECK(4);
-        ND_PRINT((ndo, "\n\t      IPv4 Transport Address: %s", ipaddr_string(ndo, tptr)));
+        ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 4);
+        ND_PRINT("\n\t      IPv4 Transport Address: %s", GET_IPADDR_STRING(tptr));
         break;
         break;
-#ifdef INET6
     case LDP_TLV_IPV6_TRANSPORT_ADDR:
     case LDP_TLV_IPV6_TRANSPORT_ADDR:
-        TLV_TCHECK(16);
-        ND_PRINT((ndo, "\n\t      IPv6 Transport Address: %s", ip6addr_string(ndo, tptr)));
+        ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 16);
+        ND_PRINT("\n\t      IPv6 Transport Address: %s", GET_IP6ADDR_STRING(tptr));
         break;
         break;
-#endif
     case LDP_TLV_CONFIG_SEQ_NUMBER:
     case LDP_TLV_CONFIG_SEQ_NUMBER:
-        TLV_TCHECK(4);
-        ND_PRINT((ndo, "\n\t      Sequence Number: %u", EXTRACT_32BITS(tptr)));
+        ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 4);
+        ND_PRINT("\n\t      Sequence Number: %u", GET_BE_U_4(tptr));
         break;
 
     case LDP_TLV_ADDRESS_LIST:
         break;
 
     case LDP_TLV_ADDRESS_LIST:
-        TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
-       af = EXTRACT_16BITS(tptr);
+        ND_ICHECKMSG_U("tlv length", tlv_tlen, <,
+                       LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
+       af = GET_BE_U_2(tptr);
        tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
         tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
        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)));
+       ND_PRINT("\n\t      Address Family: %s, addresses",
+               tok2str(af_values, "Unknown (%u)", af));
         switch (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);
+        case AFNUM_IP:
+           while(tlv_tlen >= sizeof(nd_ipv4)) {
+               ND_PRINT(" %s", GET_IPADDR_STRING(tptr));
+               tlv_tlen-=sizeof(nd_ipv4);
+               tptr+=sizeof(nd_ipv4);
            }
             break;
            }
             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);
+        case AFNUM_IP6:
+           while(tlv_tlen >= sizeof(nd_ipv6)) {
+               ND_PRINT(" %s", GET_IP6ADDR_STRING(tptr));
+               tlv_tlen-=sizeof(nd_ipv6);
+               tptr+=sizeof(nd_ipv6);
            }
             break;
            }
             break;
-#endif
         default:
             /* unknown AF */
             break;
         }
        break;
 
         default:
             /* unknown AF */
             break;
         }
        break;
 
+    case LDP_TLV_HOP_COUNT:
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 1);
+       ND_PRINT("\n\t      Hop Count: %u", GET_U_1(tptr));
+       break;
+
+    case LDP_TLV_PATH_VECTOR:
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 4);
+       ND_PRINT("\n\t      Path Vector: %s", GET_IPADDR_STRING(tptr));
+       tptr += 4;
+       tlv_tlen -= 4;
+       while (tlv_tlen >= 4) {
+           ND_PRINT(", %s", GET_IPADDR_STRING(tptr));
+           tptr += 4;
+           tlv_tlen -= 4;
+       }
+       break;
+
     case LDP_TLV_COMMON_SESSION:
     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"
-              ));
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 14);
+       ND_PRINT("\n\t      Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]",
+              GET_BE_U_2(tptr), GET_BE_U_2(tptr + 2),
+              (GET_BE_U_2(tptr + 4)&0x8000) ? "On Demand" : "Unsolicited",
+              (GET_BE_U_2(tptr + 4)&0x4000) ? "Enabled" : "Disabled"
+              );
+       ND_PRINT("\n\t      Path Vector Limit %u, Max-PDU length: %u, Receiver Label-Space-ID %s:%u",
+              GET_U_1(tptr+5),
+              GET_BE_U_2(tptr+6),
+              GET_IPADDR_STRING(tptr+8),
+              GET_BE_U_2(tptr+12)
+              );
        break;
 
     case LDP_TLV_FEC:
        break;
 
     case LDP_TLV_FEC:
-        TLV_TCHECK(1);
-        fec_type = *tptr;
-       ND_PRINT((ndo, "\n\t      %s FEC (0x%02x)",
+        ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 1);
+        fec_type = GET_U_1(tptr);
+       ND_PRINT("\n\t      %s FEC (0x%02x)",
               tok2str(ldp_fec_values, "Unknown", fec_type),
               tok2str(ldp_fec_values, "Unknown", fec_type),
-              fec_type));
+              fec_type);
 
        tptr+=1;
        tlv_tlen-=1;
 
        tptr+=1;
        tlv_tlen-=1;
@@ -344,105 +409,107 @@ ldp_tlv_print(netdissect_options *ndo,
        case LDP_FEC_WILDCARD:
            break;
        case LDP_FEC_PREFIX:
        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) {
+           ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 2);
+           af = GET_BE_U_2(tptr);
+           tptr+=2;
+           tlv_tlen-=2;
+           if (af == AFNUM_IP) {
                i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf));
                if (i == -2)
                    goto trunc;
                if (i == -3)
                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)"));
+                   ND_PRINT(": IPv4 prefix (goes past end of TLV)");
                else if (i == -1)
                else if (i == -1)
-                   ND_PRINT((ndo, ": IPv4 prefix (invalid length)"));
+                   ND_PRINT(": IPv4 prefix (invalid length)");
                else
                else
-                   ND_PRINT((ndo, ": IPv4 prefix %s", buf));
-           }
-#ifdef INET6
-           else if (af == AFNUM_INET6) {
+                   ND_PRINT(": IPv4 prefix %s", buf);
+           } else if (af == AFNUM_IP6) {
                i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf));
                if (i == -2)
                    goto trunc;
                if (i == -3)
                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)"));
+                   ND_PRINT(": IPv4 prefix (goes past end of TLV)");
                else if (i == -1)
                else if (i == -1)
-                   ND_PRINT((ndo, ": IPv6 prefix (invalid length)"));
+                   ND_PRINT(": IPv6 prefix (invalid length)");
                else
                else
-                   ND_PRINT((ndo, ": IPv6 prefix %s", buf));
-           }
-#endif
-           else
-               ND_PRINT((ndo, ": Address family %u prefix", af));
+                   ND_PRINT(": IPv6 prefix %s", buf);
+           } else
+               ND_PRINT(": Address family %u prefix", af);
            break;
        case LDP_FEC_HOSTADDRESS:
            break;
        case LDP_FEC_MARTINI_VC:
            break;
        case LDP_FEC_HOSTADDRESS:
            break;
        case LDP_FEC_MARTINI_VC:
+            /*
+             * We assume the type was supposed to be one of the MPLS
+             * Pseudowire Types.
+             */
+            ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 7);
+            vc_info_len = GET_U_1(tptr + 2);
+
             /*
             * 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.
             */
             /*
             * 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) {
             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));
+                ND_PRINT(": %s, %scontrol word, group-ID %u, VC-info-length: %u",
+                       tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
+                       GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
+                       GET_BE_U_4(tptr + 3),
+                       vc_info_len);
                 break;
             }
 
             /* Make sure we have the VC ID as well */
                 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)
-                goto trunc; /* minimum 4, for the VC ID */
+            ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 11);
+           ND_PRINT(": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u",
+                  tok2str(mpls_pw_types_values, "Unknown", GET_BE_U_2(tptr)&0x7fff),
+                  GET_BE_U_2(tptr)&0x8000 ? "" : "no ",
+                  GET_BE_U_4(tptr + 3),
+                  GET_BE_U_4(tptr + 7),
+                  vc_info_len);
+            if (vc_info_len < 4) {
+                /* minimum 4, for the VC ID */
+                ND_PRINT(" (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;
             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);
+            ND_ICHECKMSG_U("tlv length", tlv_tlen, <, vc_info_len);
 
             while (vc_info_len > 2) {
 
             while (vc_info_len > 2) {
-                vc_info_tlv_type = *tptr;
-                vc_info_tlv_len = *(tptr+1);
+                vc_info_tlv_type = GET_U_1(tptr);
+                vc_info_tlv_len = GET_U_1(tptr + 1);
                 if (vc_info_tlv_len < 2)
                     break;
                 if (vc_info_len < vc_info_tlv_len)
                     break;
 
                 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",
+                ND_PRINT("\n\t\tInterface Parameter: %s (0x%02x), len %u",
                        tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
                        vc_info_tlv_type,
                        tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
                        vc_info_tlv_type,
-                       vc_info_tlv_len));
+                       vc_info_tlv_len);
 
                 switch(vc_info_tlv_type) {
                 case LDP_FEC_MARTINI_IFPARM_MTU:
 
                 switch(vc_info_tlv_type) {
                 case LDP_FEC_MARTINI_IFPARM_MTU:
-                    ND_PRINT((ndo, ": %u", EXTRACT_16BITS(tptr+2)));
+                    ND_PRINT(": %u", GET_BE_U_2(tptr + 2));
                     break;
 
                 case LDP_FEC_MARTINI_IFPARM_DESC:
                     break;
 
                 case LDP_FEC_MARTINI_IFPARM_DESC:
-                    ND_PRINT((ndo, ": "));
-                    for (idx = 2; idx < vc_info_tlv_len; idx++)
-                        safeputchar(ndo, *(tptr + idx));
+                    ND_PRINT(": ");
+                    nd_printjn(ndo, tptr + 2, vc_info_tlv_len - 2);
                     break;
 
                 case LDP_FEC_MARTINI_IFPARM_VCCV:
                     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))));
+                    ND_PRINT("\n\t\t  Control Channels (0x%02x) = [%s]",
+                           GET_U_1((tptr + 2)),
+                           bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", GET_U_1((tptr + 2))));
+                    ND_PRINT("\n\t\t  CV Types (0x%02x) = [%s]",
+                           GET_U_1((tptr + 3)),
+                           bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", GET_U_1((tptr + 3))));
                     break;
 
                 default:
                     break;
 
                 default:
@@ -459,56 +526,71 @@ ldp_tlv_print(netdissect_options *ndo,
        break;
 
     case LDP_TLV_GENERIC_LABEL:
        break;
 
     case LDP_TLV_GENERIC_LABEL:
-       TLV_TCHECK(4);
-       ND_PRINT((ndo, "\n\t      Label: %u", EXTRACT_32BITS(tptr) & 0xfffff));
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 4);
+       ND_PRINT("\n\t      Label: %u", GET_BE_U_4(tptr) & 0xfffff);
        break;
 
     case LDP_TLV_STATUS:
        break;
 
     case LDP_TLV_STATUS:
-       TLV_TCHECK(8);
-       ui = EXTRACT_32BITS(tptr);
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 10);
+       ui = GET_BE_U_4(tptr);
        tptr+=4;
        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);
+       ND_PRINT("\n\t      Status Code: %s, Flags: [%s and %s forward]",
+                tok2str(ldp_status_code_values, "Unknown", ui&0x3fffffff),
+                ui&0x80000000 ? "Fatal error" : "Advisory Notification",
+                ui&0x40000000 ? "do" : "don't");
+       ui = GET_BE_U_4(tptr);
        tptr+=4;
        if (ui)
        tptr+=4;
        if (ui)
-           ND_PRINT((ndo, ", causing Message ID: 0x%08x", ui));
+           ND_PRINT(", causing Message ID: 0x%08x", ui);
+       ui = GET_BE_U_2(tptr);
+       if (ui)
+           ND_PRINT(", Message Type: %s", tok2str(ldp_msg_values, "Unknown", ui));
        break;
 
     case LDP_TLV_FT_SESSION:
        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]",
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 12);
+       ft_flags = GET_BE_U_2(tptr);
+       ND_PRINT("\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&0x8000 ? "" : "No ",
               ft_flags&0x8 ? "" : "Don't ",
               ft_flags&0x4 ? "" : "No ",
               ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels",
-              ft_flags&0x1 ? "" : "Don't "));
+              ft_flags&0x1 ? "" : "Don't ");
+       /* 16 bits (FT Flags) + 16 bits (Reserved) */
        tptr+=4;
        tptr+=4;
-       ui = EXTRACT_32BITS(tptr);
+       ui = GET_BE_U_4(tptr);
        if (ui)
        if (ui)
-           ND_PRINT((ndo, ", Reconnect Timeout: %ums", ui));
+           ND_PRINT(", Reconnect Timeout: %ums", ui);
        tptr+=4;
        tptr+=4;
-       ui = EXTRACT_32BITS(tptr);
+       ui = GET_BE_U_4(tptr);
        if (ui)
        if (ui)
-           ND_PRINT((ndo, ", Recovery Time: %ums", ui));
+           ND_PRINT(", Recovery Time: %ums", ui);
+       break;
+
+    case LDP_TLV_TYPED_WC_FEC_CAP:
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 1);
+       ND_PRINT("\n\t      %s", GET_U_1(tptr)&0x80 ? "Support" : "No Support");
        break;
 
     case LDP_TLV_MTU:
        break;
 
     case LDP_TLV_MTU:
-       TLV_TCHECK(2);
-       ND_PRINT((ndo, "\n\t      MTU: %u", EXTRACT_16BITS(tptr)));
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 2);
+       ND_PRINT("\n\t      MTU: %u", GET_BE_U_2(tptr));
        break;
 
        break;
 
+    case LDP_TLV_DUAL_STACK_CAP:
+       ND_ICHECKMSG_U("tlv length", tlv_tlen, <, 4);
+       transport_pref = GET_U_1(tptr);
+       ND_PRINT("\n\t      Transport Connection Preference: %s",
+                tok2str(ldp_dual_stack_transport_pref_values,
+                        "Unknown",
+                        transport_pref));
+       break;
 
     /*
      *  FIXME those are the defined TLVs that lack a decoder
      *  you are welcome to contribute code ;-)
      */
 
 
     /*
      *  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_ATM_LABEL:
     case LDP_TLV_FR_LABEL:
     case LDP_TLV_EXTD_STATUS:
@@ -526,97 +608,120 @@ ldp_tlv_print(netdissect_options *ndo,
     return(tlv_len+4); /* Type & Length fields not included */
 
 trunc:
     return(tlv_len+4); /* Type & Length fields not included */
 
 trunc:
-    ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
-    return 0;
+    nd_trunc_longjmp(ndo);
 
 
-badtlv:
-    ND_PRINT((ndo, "\n\t\t TLV contents go past end of TLV"));
+invalid:
+    nd_print_invalid(ndo);
     return(tlv_len+4); /* Type & Length fields not included */
 }
 
 void
 ldp_print(netdissect_options *ndo,
     return(tlv_len+4); /* Type & Length fields not included */
 }
 
 void
 ldp_print(netdissect_options *ndo,
-          register const u_char *pptr, register u_int len) {
+          const u_char *pptr, u_int len)
+{
+    u_int processed;
 
 
-    int processed;
+    ndo->ndo_protocol = "ldp";
     while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
     while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
-        processed = ldp_msg_print(ndo, pptr);
+        processed = ldp_pdu_print(ndo, pptr);
         if (processed == 0)
             return;
         if (processed == 0)
             return;
+        if (len < processed) {
+            ND_PRINT(" [remaining length %u < %u]", len, processed);
+            nd_print_invalid(ndo);
+            break;
+        }
         len -= processed;
         pptr += processed;
     }
 }
 
         len -= processed;
         pptr += processed;
     }
 }
 
-static int
-ldp_msg_print(netdissect_options *ndo,
-              register const u_char *pptr) {
-
+static u_int
+ldp_pdu_print(netdissect_options *ndo,
+              const u_char *pptr)
+{
     const struct ldp_common_header *ldp_com_header;
     const struct ldp_msg_header *ldp_msg_header;
     const u_char *tptr,*msg_tptr;
     u_short tlen;
     const struct ldp_common_header *ldp_com_header;
     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;
+    u_short pdu_len,msg_len,msg_type;
+    u_int msg_tlen;
     int hexdump,processed;
 
     int hexdump,processed;
 
-    tptr=pptr;
     ldp_com_header = (const struct ldp_common_header *)pptr;
     ldp_com_header = (const struct ldp_common_header *)pptr;
-    ND_TCHECK(*ldp_com_header);
+    ND_TCHECK_SIZE(ldp_com_header);
 
     /*
      * Sanity checking of the header.
      */
 
     /*
      * Sanity checking of the header.
      */
-    if (EXTRACT_16BITS(&ldp_com_header->version) != LDP_VERSION) {
-       ND_PRINT((ndo, "%sLDP version %u packet not supported",
+    if (GET_BE_U_2(ldp_com_header->version) != LDP_VERSION) {
+       ND_PRINT("%sLDP version %u packet not supported",
                (ndo->ndo_vflag < 1) ? "" : "\n\t",
                (ndo->ndo_vflag < 1) ? "" : "\n\t",
-               EXTRACT_16BITS(&ldp_com_header->version)));
+               GET_BE_U_2(ldp_com_header->version));
        return 0;
     }
 
        return 0;
     }
 
+    pdu_len = GET_BE_U_2(ldp_com_header->pdu_length);
+    if (pdu_len < sizeof(struct ldp_common_header)-4) {
+        /* length too short */
+        ND_PRINT("%sLDP, pdu-length: %u (too short, < %zu)",
+                 (ndo->ndo_vflag < 1) ? "" : "\n\t",
+                 pdu_len,
+                 sizeof(struct ldp_common_header)-4);
+        return 0;
+    }
+
     /* print the LSR-ID, label-space & length */
     /* print the LSR-ID, label-space & length */
-    pdu_len = EXTRACT_16BITS(&ldp_com_header->pdu_length);
-    ND_PRINT((ndo, "%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
+    ND_PRINT("%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
            (ndo->ndo_vflag < 1) ? "" : "\n\t",
            (ndo->ndo_vflag < 1) ? "" : "\n\t",
-           ipaddr_string(ndo, &ldp_com_header->lsr_id),
-           EXTRACT_16BITS(&ldp_com_header->label_space),
-           pdu_len));
+           GET_IPADDR_STRING(ldp_com_header->lsr_id),
+           GET_BE_U_2(ldp_com_header->label_space),
+           pdu_len);
 
     /* bail out if non-verbose */
     if (ndo->ndo_vflag < 1)
         return 0;
 
     /* ok they seem to want to know everything - lets fully decode it */
 
     /* 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=pdu_len;
+    tptr = pptr + sizeof(struct ldp_common_header);
+    tlen = pdu_len - (sizeof(struct ldp_common_header)-4);     /* Type & Length fields not included */
 
 
-    tptr += sizeof(const struct ldp_common_header);
-    tlen -= sizeof(const struct ldp_common_header)-4;  /* Type & Length fields not included */
-
-    while(tlen>0) {
+    while(tlen != 0) {
         /* did we capture enough for fully decoding the msg header ? */
         /* did we capture enough for fully decoding the msg header ? */
-        ND_TCHECK2(*tptr, sizeof(struct ldp_msg_header));
+        ND_TCHECK_LEN(tptr, sizeof(struct ldp_msg_header));
 
         ldp_msg_header = (const struct ldp_msg_header *)tptr;
 
         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));
+        msg_len=GET_BE_U_2(ldp_msg_header->length);
+        msg_type=LDP_MASK_MSG_TYPE(GET_BE_U_2(ldp_msg_header->type));
+
+        if (msg_len < sizeof(struct ldp_msg_header)-4) {
+            /* length too short */
+            /* FIXME vendor private / experimental check */
+            ND_PRINT("\n\t  %s Message (0x%04x), length: %u (too short, < %zu)",
+                     tok2str(ldp_msg_values,
+                             "Unknown",
+                             msg_type),
+                     msg_type,
+                     msg_len,
+                     sizeof(struct ldp_msg_header)-4);
+            return 0;
+        }
 
         /* FIXME vendor private / experimental check */
 
         /* FIXME vendor private / experimental check */
-        ND_PRINT((ndo, "\n\t  %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
+        ND_PRINT("\n\t  %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
                tok2str(ldp_msg_values,
                        "Unknown",
                        msg_type),
                msg_type,
                msg_len,
                tok2str(ldp_msg_values,
                        "Unknown",
                        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"));
-
-        if (msg_len == 0) /* infinite loop protection */
-            return 0;
+               GET_BE_U_4(ldp_msg_header->id),
+               LDP_MASK_U_BIT(GET_BE_U_2(ldp_msg_header->type)) ? "continue processing" : "ignore");
 
         msg_tptr=tptr+sizeof(struct ldp_msg_header);
 
         msg_tptr=tptr+sizeof(struct ldp_msg_header);
-        msg_tlen=msg_len-sizeof(struct ldp_msg_header)+4; /* Type & Length fields not included */
+        msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */
 
         /* did we capture enough for fully decoding the message ? */
 
         /* did we capture enough for fully decoding the message ? */
-        ND_TCHECK2(*tptr, msg_len);
+        ND_TCHECK_LEN(tptr, msg_len);
         hexdump=FALSE;
 
         switch(msg_type) {
         hexdump=FALSE;
 
         switch(msg_type) {
@@ -629,8 +734,11 @@ ldp_msg_print(netdissect_options *ndo,
         case LDP_MSG_LABEL_MAPPING:
         case LDP_MSG_ADDRESS_WITHDRAW:
         case LDP_MSG_LABEL_WITHDRAW:
         case LDP_MSG_LABEL_MAPPING:
         case LDP_MSG_ADDRESS_WITHDRAW:
         case LDP_MSG_LABEL_WITHDRAW:
+        case LDP_MSG_LABEL_REQUEST:
+        case LDP_MSG_LABEL_RELEASE:
+        case LDP_MSG_LABEL_ABORT_REQUEST:
             while(msg_tlen >= 4) {
             while(msg_tlen >= 4) {
-                processed = ldp_tlv_print(ndo, msg_tptr);
+                processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen);
                 if (processed == 0)
                     break;
                 msg_tlen-=processed;
                 if (processed == 0)
                     break;
                 msg_tlen-=processed;
@@ -638,15 +746,6 @@ ldp_msg_print(netdissect_options *ndo,
             }
             break;
 
             }
             break;
 
-        /*
-         *  FIXME those are the defined messages that lack a decoder
-         *  you are welcome to contribute code ;-)
-         */
-
-        case LDP_MSG_LABEL_REQUEST:
-        case LDP_MSG_LABEL_RELEASE:
-        case LDP_MSG_LABEL_ABORT_REQUEST:
-
         default:
             if (ndo->ndo_vflag <= 1)
                 print_unknown_data(ndo, msg_tptr, "\n\t  ", msg_tlen);
         default:
             if (ndo->ndo_vflag <= 1)
                 print_unknown_data(ndo, msg_tptr, "\n\t  ", msg_tlen);
@@ -662,13 +761,5 @@ ldp_msg_print(netdissect_options *ndo,
     }
     return pdu_len+4;
 trunc:
     }
     return pdu_len+4;
 trunc:
-    ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
-    return 0;
+    nd_trunc_longjmp(ndo);
 }
 }
-
-/*
- * Local Variables:
- * c-style: whitesmith
- * c-basic-offset: 8
- * End:
- */