]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-l2tp.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-l2tp.c
index f0708ddb8233459f624f633019bf49adbbe41b20..a320873444f1a7b7b841c8f417633f7c8754ad01 100644 (file)
  * L2TP support contributed by Motonori Shindo ([email protected])
  */
 
  * L2TP support contributed by Motonori Shindo ([email protected])
  */
 
-#ifndef lint
-static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-l2tp.c,v 1.20 2006-06-23 02:03:09 hannes Exp $";
-#endif
+/* \summary: Layer Two Tunneling Protocol (L2TP) printer */
 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+/* specification: RFC 2661 */
 
 
-#include <tcpdump-stdinc.h>
+#include <config.h>
 
 
-#include <stdio.h>
+#include "netdissect-stdinc.h"
 
 
-#include "interface.h"
+#define ND_LONGJMP_FROM_TCHECK
+#include "netdissect.h"
 #include "extract.h"
 
 #define L2TP_FLAG_TYPE         0x8000  /* Type (0=Data, 1=Control) */
 #include "extract.h"
 
 #define L2TP_FLAG_TYPE         0x8000  /* Type (0=Data, 1=Control) */
@@ -73,7 +69,6 @@ static const char rcsid[] _U_ =
 
 #define L2TP_PROXY_AUTH_ID_MASK                0x00ff
 
 
 #define L2TP_PROXY_AUTH_ID_MASK                0x00ff
 
-static const char tstr[] = " [|l2tp]";
 
 #define        L2TP_MSGTYPE_SCCRQ      1  /* Start-Control-Connection-Request */
 #define        L2TP_MSGTYPE_SCCRP      2  /* Start-Control-Connection-Reply */
 
 #define        L2TP_MSGTYPE_SCCRQ      1  /* Start-Control-Connection-Request */
 #define        L2TP_MSGTYPE_SCCRP      2  /* Start-Control-Connection-Reply */
@@ -91,7 +86,7 @@ static const char tstr[] = " [|l2tp]";
 #define        L2TP_MSGTYPE_SLI        16 /* Set-Link-Info */
 
 static const struct tok l2tp_msgtype2str[] = {
 #define        L2TP_MSGTYPE_SLI        16 /* Set-Link-Info */
 
 static const struct tok l2tp_msgtype2str[] = {
-       { L2TP_MSGTYPE_SCCRQ,   "SCCRQ" },
+       { L2TP_MSGTYPE_SCCRQ,   "SCCRQ" },
        { L2TP_MSGTYPE_SCCRP,   "SCCRP" },
        { L2TP_MSGTYPE_SCCCN,   "SCCCN" },
        { L2TP_MSGTYPE_STOPCCN, "StopCCN" },
        { L2TP_MSGTYPE_SCCRP,   "SCCRP" },
        { L2TP_MSGTYPE_SCCCN,   "SCCCN" },
        { L2TP_MSGTYPE_STOPCCN, "StopCCN" },
@@ -117,17 +112,17 @@ static const struct tok l2tp_msgtype2str[] = {
 #define L2TP_AVP_FIRM_VER              6  /* Firmware Revision */
 #define L2TP_AVP_HOST_NAME             7  /* Host Name */
 #define L2TP_AVP_VENDOR_NAME           8  /* Vendor Name */
 #define L2TP_AVP_FIRM_VER              6  /* Firmware Revision */
 #define L2TP_AVP_HOST_NAME             7  /* Host Name */
 #define L2TP_AVP_VENDOR_NAME           8  /* Vendor Name */
-#define L2TP_AVP_ASSND_TUN_ID          9  /* Assigned Tunnel ID */
+#define L2TP_AVP_ASSND_TUN_ID          9  /* Assigned Tunnel ID */
 #define L2TP_AVP_RECV_WIN_SIZE         10 /* Receive Window Size */
 #define L2TP_AVP_CHALLENGE             11 /* Challenge */
 #define L2TP_AVP_Q931_CC               12 /* Q.931 Cause Code */
 #define L2TP_AVP_CHALLENGE_RESP                13 /* Challenge Response */
 #define L2TP_AVP_RECV_WIN_SIZE         10 /* Receive Window Size */
 #define L2TP_AVP_CHALLENGE             11 /* Challenge */
 #define L2TP_AVP_Q931_CC               12 /* Q.931 Cause Code */
 #define L2TP_AVP_CHALLENGE_RESP                13 /* Challenge Response */
-#define L2TP_AVP_ASSND_SESS_ID         14 /* Assigned Session ID */
-#define L2TP_AVP_CALL_SER_NUM          15 /* Call Serial Number */
+#define L2TP_AVP_ASSND_SESS_ID         14 /* Assigned Session ID */
+#define L2TP_AVP_CALL_SER_NUM          15 /* Call Serial Number */
 #define L2TP_AVP_MINIMUM_BPS           16 /* Minimum BPS */
 #define L2TP_AVP_MAXIMUM_BPS           17 /* Maximum BPS */
 #define L2TP_AVP_BEARER_TYPE           18 /* Bearer Type */
 #define L2TP_AVP_MINIMUM_BPS           16 /* Minimum BPS */
 #define L2TP_AVP_MAXIMUM_BPS           17 /* Maximum BPS */
 #define L2TP_AVP_BEARER_TYPE           18 /* Bearer Type */
-#define L2TP_AVP_FRAMING_TYPE          19 /* Framing Type */
+#define L2TP_AVP_FRAMING_TYPE          19 /* Framing Type */
 #define L2TP_AVP_PACKET_PROC_DELAY     20 /* Packet Processing Delay (OBSOLETE) */
 #define L2TP_AVP_CALLED_NUMBER         21 /* Called Number */
 #define L2TP_AVP_CALLING_NUMBER                22 /* Calling Number */
 #define L2TP_AVP_PACKET_PROC_DELAY     20 /* Packet Processing Delay (OBSOLETE) */
 #define L2TP_AVP_CALLED_NUMBER         21 /* Called Number */
 #define L2TP_AVP_CALLING_NUMBER                22 /* Calling Number */
@@ -147,8 +142,8 @@ static const struct tok l2tp_msgtype2str[] = {
 #define L2TP_AVP_RANDOM_VECTOR         36 /* Random Vector */
 #define L2TP_AVP_PRIVATE_GRP_ID                37 /* Private Group ID */
 #define L2TP_AVP_RX_CONN_SPEED         38 /* (Rx) Connect Speed */
 #define L2TP_AVP_RANDOM_VECTOR         36 /* Random Vector */
 #define L2TP_AVP_PRIVATE_GRP_ID                37 /* Private Group ID */
 #define L2TP_AVP_RX_CONN_SPEED         38 /* (Rx) Connect Speed */
-#define L2TP_AVP_SEQ_REQUIRED          39 /* Sequencing Required */
-#define L2TP_AVP_PPP_DISCON_CC         46 /* PPP Disconnect Cause Code */
+#define L2TP_AVP_SEQ_REQUIRED          39 /* Sequencing Required */
+#define L2TP_AVP_PPP_DISCON_CC         46 /* PPP Disconnect Cause Code - RFC 3145 */
 
 static const struct tok l2tp_avp2str[] = {
        { L2TP_AVP_MSGTYPE,             "MSGTYPE" },
 
 static const struct tok l2tp_avp2str[] = {
        { L2TP_AVP_MSGTYPE,             "MSGTYPE" },
@@ -236,9 +231,9 @@ static char *l2tp_result_code_CDN[] = {
        "Call disconnected due to loss of carrier",
        "Call disconnected for the reason indicated in error code",
        "Call disconnected for administrative reasons",
        "Call disconnected due to loss of carrier",
        "Call disconnected for the reason indicated in error code",
        "Call disconnected for administrative reasons",
-       "Call failed due to lack of appropriate facilities being " \
+       "Call failed due to lack of appropriate facilities being "
        "available (temporary condition)",
        "available (temporary condition)",
-       "Call failed due to lack of appropriate facilities being " \
+       "Call failed due to lack of appropriate facilities being "
        "available (permanent condition)",
        "Invalid destination",
        "Call failed due to no carrier detected",
        "available (permanent condition)",
        "Invalid destination",
        "Call failed due to no carrier detected",
@@ -255,7 +250,7 @@ static char *l2tp_error_code_general[] = {
        "No general error",
        "No control connection exists yet for this LAC-LNS pair",
        "Length is wrong",
        "No general error",
        "No control connection exists yet for this LAC-LNS pair",
        "Length is wrong",
-       "One of the field values was out of range or " \
+       "One of the field values was out of range or "
        "reserved field was non-zero"
        "Insufficient resources to handle this operation now",
        "The Session ID is invalid in this context",
        "reserved field was non-zero"
        "Insufficient resources to handle this operation now",
        "The Session ID is invalid in this context",
@@ -269,301 +264,383 @@ static char *l2tp_error_code_general[] = {
 /* generic print out routines */
 /******************************/
 static void
 /* generic print out routines */
 /******************************/
 static void
-print_string(const u_char *dat, u_int length)
-{
-       u_int i;
-       for (i=0; i<length; i++) {
-               printf("%c", *dat++);
-       }
-}
-
-static void
-print_octets(const u_char *dat, u_int length)
+print_octets(netdissect_options *ndo, const u_char *dat, u_int length)
 {
        u_int i;
        for (i=0; i<length; i++) {
 {
        u_int i;
        for (i=0; i<length; i++) {
-               printf("%02x", *dat++);
+               ND_PRINT("%02x", GET_U_1(dat));
+               dat++;
        }
 }
 
 static void
        }
 }
 
 static void
-print_16bits_val(const u_int16_t *dat)
+print_16bits_val(netdissect_options *ndo, const uint8_t *dat)
 {
 {
-       printf("%u", EXTRACT_16BITS(dat));
+       ND_PRINT("%u", GET_BE_U_2(dat));
 }
 
 static void
 }
 
 static void
-print_32bits_val(const u_int32_t *dat)
+print_32bits_val(netdissect_options *ndo, const uint8_t *dat)
 {
 {
-       printf("%lu", (u_long)EXTRACT_32BITS(dat));
+       ND_PRINT("%u", GET_BE_U_4(dat));
 }
 
 /***********************************/
 /* AVP-specific print out routines */
 /***********************************/
 static void
 }
 
 /***********************************/
 /* AVP-specific print out routines */
 /***********************************/
 static void
-l2tp_msgtype_print(const u_char *dat)
+l2tp_msgtype_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t*)dat;
-
-       printf("%s", tok2str(l2tp_msgtype2str, "MSGTYPE-#%u",
-           EXTRACT_16BITS(ptr)));
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       ND_PRINT("%s", tok2str(l2tp_msgtype2str, "MSGTYPE-#%u",
+           GET_BE_U_2(dat)));
 }
 
 static void
 }
 
 static void
-l2tp_result_code_print(const u_char *dat, u_int length)
+l2tp_result_code_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t *)dat;
-
-       printf("%u", EXTRACT_16BITS(ptr)); ptr++;       /* Result Code */
-       if (length > 2) {                               /* Error Code (opt) */
-               printf("/%u", EXTRACT_16BITS(ptr)); ptr++;
+       /* Result Code */
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
        }
        }
-       if (length > 4) {                               /* Error Message (opt) */
-               printf(" ");
-               print_string((u_char *)ptr, length - 4);
+       ND_PRINT("%u", GET_BE_U_2(dat));
+       dat += 2;
+       length -= 2;
+
+       /* Error Code (opt) */
+       if (length == 0)
+               return;
+       if (length < 2) {
+               ND_PRINT(" AVP too short");
+               return;
        }
        }
+       ND_PRINT("/%u", GET_BE_U_2(dat));
+       dat += 2;
+       length -= 2;
+
+       /* Error Message (opt) */
+       if (length == 0)
+               return;
+       ND_PRINT(" ");
+       nd_printjn(ndo, dat, length);
 }
 
 static void
 }
 
 static void
-l2tp_proto_ver_print(const u_int16_t *dat)
+l2tp_proto_ver_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       printf("%u.%u", (EXTRACT_16BITS(dat) >> 8),
-           (EXTRACT_16BITS(dat) & 0xff));
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       ND_PRINT("%u.%u", (GET_BE_U_2(dat) >> 8),
+                 (GET_BE_U_2(dat) & 0xff));
 }
 
 static void
 }
 
 static void
-l2tp_framing_cap_print(const u_char *dat)
+l2tp_framing_cap_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int32_t *ptr = (u_int32_t *)dat;
-
-       if (EXTRACT_32BITS(ptr) &  L2TP_FRAMING_CAP_ASYNC_MASK) {
-               printf("A");
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
        }
        }
-       if (EXTRACT_32BITS(ptr) &  L2TP_FRAMING_CAP_SYNC_MASK) {
-               printf("S");
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_CAP_ASYNC_MASK) {
+               ND_PRINT("A");
+       }
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_CAP_SYNC_MASK) {
+               ND_PRINT("S");
        }
 }
 
 static void
        }
 }
 
 static void
-l2tp_bearer_cap_print(const u_char *dat)
+l2tp_bearer_cap_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int32_t *ptr = (u_int32_t *)dat;
-
-       if (EXTRACT_32BITS(ptr) &  L2TP_BEARER_CAP_ANALOG_MASK) {
-               printf("A");
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_CAP_ANALOG_MASK) {
+               ND_PRINT("A");
        }
        }
-       if (EXTRACT_32BITS(ptr) &  L2TP_BEARER_CAP_DIGITAL_MASK) {
-               printf("D");
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_CAP_DIGITAL_MASK) {
+               ND_PRINT("D");
        }
 }
 
 static void
        }
 }
 
 static void
-l2tp_q931_cc_print(const u_char *dat, u_int length)
+l2tp_q931_cc_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       print_16bits_val((u_int16_t *)dat);
-       printf(", %02x", dat[2]);
-       if (length > 3) {
-               printf(" ");
-               print_string(dat+3, length-3);
+       if (length < 3) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       print_16bits_val(ndo, dat);
+       ND_PRINT(", %02x", GET_U_1(dat + 2));
+       dat += 3;
+       length -= 3;
+       if (length != 0) {
+               ND_PRINT(" ");
+               nd_printjn(ndo, dat, length);
        }
 }
 
 static void
        }
 }
 
 static void
-l2tp_bearer_type_print(const u_char *dat)
+l2tp_bearer_type_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int32_t *ptr = (u_int32_t *)dat;
-
-       if (EXTRACT_32BITS(ptr) &  L2TP_BEARER_TYPE_ANALOG_MASK) {
-               printf("A");
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_TYPE_ANALOG_MASK) {
+               ND_PRINT("A");
        }
        }
-       if (EXTRACT_32BITS(ptr) &  L2TP_BEARER_TYPE_DIGITAL_MASK) {
-               printf("D");
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_TYPE_DIGITAL_MASK) {
+               ND_PRINT("D");
        }
 }
 
 static void
        }
 }
 
 static void
-l2tp_framing_type_print(const u_char *dat)
+l2tp_framing_type_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int32_t *ptr = (u_int32_t *)dat;
-
-       if (EXTRACT_32BITS(ptr) &  L2TP_FRAMING_TYPE_ASYNC_MASK) {
-               printf("A");
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_TYPE_ASYNC_MASK) {
+               ND_PRINT("A");
        }
        }
-       if (EXTRACT_32BITS(ptr) &  L2TP_FRAMING_TYPE_SYNC_MASK) {
-               printf("S");
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_TYPE_SYNC_MASK) {
+               ND_PRINT("S");
        }
 }
 
 static void
        }
 }
 
 static void
-l2tp_packet_proc_delay_print(void)
+l2tp_packet_proc_delay_print(netdissect_options *ndo)
 {
 {
-       printf("obsolete");
+       ND_PRINT("obsolete");
 }
 
 static void
 }
 
 static void
-l2tp_proxy_auth_type_print(const u_char *dat)
+l2tp_proxy_auth_type_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t *)dat;
-
-       printf("%s", tok2str(l2tp_authentype2str,
-                            "AuthType-#%u", EXTRACT_16BITS(ptr)));
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       ND_PRINT("%s", tok2str(l2tp_authentype2str,
+                            "AuthType-#%u", GET_BE_U_2(dat)));
 }
 
 static void
 }
 
 static void
-l2tp_proxy_auth_id_print(const u_char *dat)
+l2tp_proxy_auth_id_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t *)dat;
-
-       printf("%u", EXTRACT_16BITS(ptr) & L2TP_PROXY_AUTH_ID_MASK);
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       ND_PRINT("%u", GET_BE_U_2(dat) & L2TP_PROXY_AUTH_ID_MASK);
 }
 
 static void
 }
 
 static void
-l2tp_call_errors_print(const u_char *dat)
+l2tp_call_errors_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t *)dat;
-       u_int16_t val_h, val_l;
+       uint32_t val;
 
 
-       ptr++;          /* skip "Reserved" */
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       dat += 2;       /* skip "Reserved" */
+       length -= 2;
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("CRCErr=%u ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("CRCErr=%u ", val);
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("FrameErr=%u ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("FrameErr=%u ", val);
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("HardOver=%u ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("HardOver=%u ", val);
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("BufOver=%u ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("BufOver=%u ", val);
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("Timeout=%u ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("Timeout=%u ", val);
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("AlignErr=%u ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("AlignErr=%u ", val);
 }
 
 static void
 }
 
 static void
-l2tp_accm_print(const u_char *dat)
+l2tp_accm_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t *)dat;
-       u_int16_t val_h, val_l;
+       uint32_t val;
 
 
-       ptr++;          /* skip "Reserved" */
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       dat += 2;       /* skip "Reserved" */
+       length -= 2;
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("send=%08x ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("send=%08x ", val);
 
 
-       val_h = EXTRACT_16BITS(ptr); ptr++;
-       val_l = EXTRACT_16BITS(ptr); ptr++;
-       printf("recv=%08x ", (val_h<<16) + val_l);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("recv=%08x ", val);
 }
 
 static void
 }
 
 static void
-l2tp_ppp_discon_cc_print(const u_char *dat, u_int length)
+l2tp_ppp_discon_cc_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       u_int16_t *ptr = (u_int16_t *)dat;
-
-       printf("%04x, ", EXTRACT_16BITS(ptr)); ptr++;   /* Disconnect Code */
-       printf("%04x ",  EXTRACT_16BITS(ptr)); ptr++;   /* Control Protocol Number */
-       printf("%s", tok2str(l2tp_cc_direction2str,
-                            "Direction-#%u", *((u_char *)ptr++)));
-
-       if (length > 5) {
-               printf(" ");
-               print_string((const u_char *)ptr, length-5);
+       if (length < 5) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       /* Disconnect Code */
+       ND_PRINT("%04x, ", GET_BE_U_2(dat));
+       dat += 2;
+       length -= 2;
+       /* Control Protocol Number */
+       ND_PRINT("%04x ",  GET_BE_U_2(dat));
+       dat += 2;
+       length -= 2;
+       /* Direction */
+       ND_PRINT("%s", tok2str(l2tp_cc_direction2str,
+                            "Direction-#%u", GET_U_1(dat)));
+       dat++;
+       length--;
+
+       if (length != 0) {
+               ND_PRINT(" ");
+               nd_printjn(ndo, (const u_char *)dat, length);
        }
 }
 
        }
 }
 
-static void
-l2tp_avp_print(const u_char *dat, int length)
+static u_int
+l2tp_avp_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
        u_int len;
 {
        u_int len;
-       const u_int16_t *ptr = (u_int16_t *)dat;
-       u_int16_t attr_type;
+       uint16_t attr_type;
        int hidden = FALSE;
 
        int hidden = FALSE;
 
-       if (length <= 0) {
-               return;
-       }
-
-       printf(" ");
-
-       TCHECK(*ptr);   /* Flags & Length */
-       len = EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_LEN_MASK;
+       ND_PRINT(" ");
+       /* Flags & Length */
+       len = GET_BE_U_2(dat) & L2TP_AVP_HDR_LEN_MASK;
 
        /* If it is not long enough to contain the header, we'll give up. */
 
        /* If it is not long enough to contain the header, we'll give up. */
-       if (len < 6)
-               goto trunc;
+       ND_ICHECKMSG_U("AVP length", len, <, 6);
 
        /* If it goes past the end of the remaining length of the packet,
           we'll give up. */
 
        /* If it goes past the end of the remaining length of the packet,
           we'll give up. */
-       if (len > (u_int)length)
-               goto trunc;
+       if (len > length) {
+               ND_PRINT(" (len > %u)", length);
+               goto invalid;
+       }
 
        /* If it goes past the end of the remaining length of the captured
           data, we'll give up. */
 
        /* If it goes past the end of the remaining length of the captured
           data, we'll give up. */
-       TCHECK2(*ptr, len);
-       /* After this point, no need to worry about truncation */
+       ND_TCHECK_LEN(dat, len);
+
+       /*
+        * After this point, we don't need to check whether we go past
+        * the length of the captured data; however, we *do* need to
+        * check whether we go past the end of the AVP.
+        */
 
 
-       if (EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_FLAG_MANDATORY) {
-               printf("*");
+       if (GET_BE_U_2(dat) & L2TP_AVP_HDR_FLAG_MANDATORY) {
+               ND_PRINT("*");
        }
        }
-       if (EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_FLAG_HIDDEN) {
+       if (GET_BE_U_2(dat) & L2TP_AVP_HDR_FLAG_HIDDEN) {
                hidden = TRUE;
                hidden = TRUE;
-               printf("?");
+               ND_PRINT("?");
        }
        }
-       ptr++;
+       dat += 2;
 
 
-       if (EXTRACT_16BITS(ptr)) {
+       if (GET_BE_U_2(dat)) {
                /* Vendor Specific Attribute */
                /* Vendor Specific Attribute */
-               printf("VENDOR%04x:", EXTRACT_16BITS(ptr)); ptr++;
-               printf("ATTR%04x", EXTRACT_16BITS(ptr)); ptr++;
-               printf("(");
-               print_octets((u_char *)ptr, len-6);
-               printf(")");
+               ND_PRINT("VENDOR%04x:", GET_BE_U_2(dat)); dat += 2;
+               ND_PRINT("ATTR%04x", GET_BE_U_2(dat)); dat += 2;
+               ND_PRINT("(");
+               print_octets(ndo, dat, len-6);
+               ND_PRINT(")");
        } else {
                /* IETF-defined Attributes */
        } else {
                /* IETF-defined Attributes */
-               ptr++;
-               attr_type = EXTRACT_16BITS(ptr); ptr++;
-               printf("%s", tok2str(l2tp_avp2str, "AVP-#%u", attr_type));
-               printf("(");
+               dat += 2;
+               attr_type = GET_BE_U_2(dat); dat += 2;
+               ND_PRINT("%s", tok2str(l2tp_avp2str, "AVP-#%u", attr_type));
+               ND_PRINT("(");
                if (hidden) {
                if (hidden) {
-                       printf("???");
+                       ND_PRINT("???");
                } else {
                        switch (attr_type) {
                        case L2TP_AVP_MSGTYPE:
                } else {
                        switch (attr_type) {
                        case L2TP_AVP_MSGTYPE:
-                               l2tp_msgtype_print((u_char *)ptr);
+                               l2tp_msgtype_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_RESULT_CODE:
                                break;
                        case L2TP_AVP_RESULT_CODE:
-                               l2tp_result_code_print((u_char *)ptr, len-6);
+                               l2tp_result_code_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_PROTO_VER:
                                break;
                        case L2TP_AVP_PROTO_VER:
-                               l2tp_proto_ver_print(ptr);
+                               l2tp_proto_ver_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_FRAMING_CAP:
                                break;
                        case L2TP_AVP_FRAMING_CAP:
-                               l2tp_framing_cap_print((u_char *)ptr);
+                               l2tp_framing_cap_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_BEARER_CAP:
                                break;
                        case L2TP_AVP_BEARER_CAP:
-                               l2tp_bearer_cap_print((u_char *)ptr);
+                               l2tp_bearer_cap_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_TIE_BREAKER:
                                break;
                        case L2TP_AVP_TIE_BREAKER:
-                               print_octets((u_char *)ptr, 8);
+                               if (len-6 < 8) {
+                                       ND_PRINT("AVP too short");
+                                       break;
+                               }
+                               print_octets(ndo, dat, 8);
                                break;
                        case L2TP_AVP_FIRM_VER:
                        case L2TP_AVP_ASSND_TUN_ID:
                        case L2TP_AVP_RECV_WIN_SIZE:
                        case L2TP_AVP_ASSND_SESS_ID:
                                break;
                        case L2TP_AVP_FIRM_VER:
                        case L2TP_AVP_ASSND_TUN_ID:
                        case L2TP_AVP_RECV_WIN_SIZE:
                        case L2TP_AVP_ASSND_SESS_ID:
-                               print_16bits_val(ptr);
+                               if (len-6 < 2) {
+                                       ND_PRINT("AVP too short");
+                                       break;
+                               }
+                               print_16bits_val(ndo, dat);
                                break;
                        case L2TP_AVP_HOST_NAME:
                        case L2TP_AVP_VENDOR_NAME:
                                break;
                        case L2TP_AVP_HOST_NAME:
                        case L2TP_AVP_VENDOR_NAME:
@@ -572,7 +649,7 @@ l2tp_avp_print(const u_char *dat, int length)
                        case L2TP_AVP_SUB_ADDRESS:
                        case L2TP_AVP_PROXY_AUTH_NAME:
                        case L2TP_AVP_PRIVATE_GRP_ID:
                        case L2TP_AVP_SUB_ADDRESS:
                        case L2TP_AVP_PROXY_AUTH_NAME:
                        case L2TP_AVP_PRIVATE_GRP_ID:
-                               print_string((u_char *)ptr, len-6);
+                               nd_printjn(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_CHALLENGE:
                        case L2TP_AVP_INI_RECV_LCP:
                                break;
                        case L2TP_AVP_CHALLENGE:
                        case L2TP_AVP_INI_RECV_LCP:
@@ -581,13 +658,17 @@ l2tp_avp_print(const u_char *dat, int length)
                        case L2TP_AVP_PROXY_AUTH_CHAL:
                        case L2TP_AVP_PROXY_AUTH_RESP:
                        case L2TP_AVP_RANDOM_VECTOR:
                        case L2TP_AVP_PROXY_AUTH_CHAL:
                        case L2TP_AVP_PROXY_AUTH_RESP:
                        case L2TP_AVP_RANDOM_VECTOR:
-                               print_octets((u_char *)ptr, len-6);
+                               print_octets(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_Q931_CC:
                                break;
                        case L2TP_AVP_Q931_CC:
-                               l2tp_q931_cc_print((u_char *)ptr, len-6);
+                               l2tp_q931_cc_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_CHALLENGE_RESP:
                                break;
                        case L2TP_AVP_CHALLENGE_RESP:
-                               print_octets((u_char *)ptr, 16);
+                               if (len-6 < 16) {
+                                       ND_PRINT("AVP too short");
+                                       break;
+                               }
+                               print_octets(ndo, dat, 16);
                                break;
                        case L2TP_AVP_CALL_SER_NUM:
                        case L2TP_AVP_MINIMUM_BPS:
                                break;
                        case L2TP_AVP_CALL_SER_NUM:
                        case L2TP_AVP_MINIMUM_BPS:
@@ -595,160 +676,170 @@ l2tp_avp_print(const u_char *dat, int length)
                        case L2TP_AVP_TX_CONN_SPEED:
                        case L2TP_AVP_PHY_CHANNEL_ID:
                        case L2TP_AVP_RX_CONN_SPEED:
                        case L2TP_AVP_TX_CONN_SPEED:
                        case L2TP_AVP_PHY_CHANNEL_ID:
                        case L2TP_AVP_RX_CONN_SPEED:
-                               print_32bits_val((u_int32_t *)ptr);
+                               if (len-6 < 4) {
+                                       ND_PRINT("AVP too short");
+                                       break;
+                               }
+                               print_32bits_val(ndo, dat);
                                break;
                        case L2TP_AVP_BEARER_TYPE:
                                break;
                        case L2TP_AVP_BEARER_TYPE:
-                               l2tp_bearer_type_print((u_char *)ptr);
+                               l2tp_bearer_type_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_FRAMING_TYPE:
                                break;
                        case L2TP_AVP_FRAMING_TYPE:
-                               l2tp_framing_type_print((u_char *)ptr);
+                               l2tp_framing_type_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_PACKET_PROC_DELAY:
                                break;
                        case L2TP_AVP_PACKET_PROC_DELAY:
-                               l2tp_packet_proc_delay_print();
+                               l2tp_packet_proc_delay_print(ndo);
                                break;
                        case L2TP_AVP_PROXY_AUTH_TYPE:
                                break;
                        case L2TP_AVP_PROXY_AUTH_TYPE:
-                               l2tp_proxy_auth_type_print((u_char *)ptr);
+                               l2tp_proxy_auth_type_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_PROXY_AUTH_ID:
                                break;
                        case L2TP_AVP_PROXY_AUTH_ID:
-                               l2tp_proxy_auth_id_print((u_char *)ptr);
+                               l2tp_proxy_auth_id_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_CALL_ERRORS:
                                break;
                        case L2TP_AVP_CALL_ERRORS:
-                               l2tp_call_errors_print((u_char *)ptr);
+                               l2tp_call_errors_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_ACCM:
                                break;
                        case L2TP_AVP_ACCM:
-                               l2tp_accm_print((u_char *)ptr);
+                               l2tp_accm_print(ndo, dat, len-6);
                                break;
                        case L2TP_AVP_SEQ_REQUIRED:
                                break;  /* No Attribute Value */
                        case L2TP_AVP_PPP_DISCON_CC:
                                break;
                        case L2TP_AVP_SEQ_REQUIRED:
                                break;  /* No Attribute Value */
                        case L2TP_AVP_PPP_DISCON_CC:
-                               l2tp_ppp_discon_cc_print((u_char *)ptr, len-6);
+                               l2tp_ppp_discon_cc_print(ndo, dat, len-6);
                                break;
                        default:
                                break;
                        }
                }
                                break;
                        default:
                                break;
                        }
                }
-               printf(")");
+               ND_PRINT(")");
        }
 
        }
 
-       l2tp_avp_print(dat+len, length-len);
-       return;
+       return (len);
 
 
- trunc:
-       printf("|...");
+invalid:
+       return (0);
 }
 
 
 void
 }
 
 
 void
-l2tp_print(const u_char *dat, u_int length)
+l2tp_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
        const u_char *ptr = dat;
        u_int cnt = 0;                  /* total octets consumed */
 {
        const u_char *ptr = dat;
        u_int cnt = 0;                  /* total octets consumed */
-       u_int16_t pad;
+       uint16_t pad;
        int flag_t, flag_l, flag_s, flag_o;
        int flag_t, flag_l, flag_s, flag_o;
-       u_int16_t l2tp_len;
+       uint16_t l2tp_len;
 
 
+       ndo->ndo_protocol = "l2tp";
        flag_t = flag_l = flag_s = flag_o = FALSE;
 
        flag_t = flag_l = flag_s = flag_o = FALSE;
 
-       TCHECK2(*ptr, 2);       /* Flags & Version */
-       if ((EXTRACT_16BITS(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2TP) {
-               printf(" l2tp:");
-       } else if ((EXTRACT_16BITS(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2F) {
-               printf(" l2f:");
+       if ((GET_BE_U_2(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2TP) {
+               ND_PRINT(" l2tp:");
+       } else if ((GET_BE_U_2(ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2F) {
+               ND_PRINT(" l2f:");
                return;         /* nothing to do */
        } else {
                return;         /* nothing to do */
        } else {
-               printf(" Unknown Version, neither L2F(1) nor L2TP(2)");
+               ND_PRINT(" Unknown Version, neither L2F(1) nor L2TP(2)");
                return;         /* nothing we can do */
        }
 
                return;         /* nothing we can do */
        }
 
-       printf("[");
-       if (EXTRACT_16BITS(ptr) & L2TP_FLAG_TYPE) {
+       ND_PRINT("[");
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_TYPE) {
                flag_t = TRUE;
                flag_t = TRUE;
-               printf("T");
+               ND_PRINT("T");
        }
        }
-       if (EXTRACT_16BITS(ptr) & L2TP_FLAG_LENGTH) {
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_LENGTH) {
                flag_l = TRUE;
                flag_l = TRUE;
-               printf("L");
+               ND_PRINT("L");
        }
        }
-       if (EXTRACT_16BITS(ptr) & L2TP_FLAG_SEQUENCE) {
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_SEQUENCE) {
                flag_s = TRUE;
                flag_s = TRUE;
-               printf("S");
+               ND_PRINT("S");
        }
        }
-       if (EXTRACT_16BITS(ptr) & L2TP_FLAG_OFFSET) {
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_OFFSET) {
                flag_o = TRUE;
                flag_o = TRUE;
-               printf("O");
+               ND_PRINT("O");
        }
        }
-       if (EXTRACT_16BITS(ptr) & L2TP_FLAG_PRIORITY)
-               printf("P");
-       printf("]");
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_PRIORITY)
+               ND_PRINT("P");
+       ND_PRINT("]");
 
        ptr += 2;
        cnt += 2;
 
        if (flag_l) {
 
        ptr += 2;
        cnt += 2;
 
        if (flag_l) {
-               TCHECK2(*ptr, 2);       /* Length */
-               l2tp_len = EXTRACT_16BITS(ptr);
+               l2tp_len = GET_BE_U_2(ptr);
                ptr += 2;
                cnt += 2;
        } else {
                l2tp_len = 0;
        }
                ptr += 2;
                cnt += 2;
        } else {
                l2tp_len = 0;
        }
-
-       TCHECK2(*ptr, 2);               /* Tunnel ID */
-       printf("(%u/", EXTRACT_16BITS(ptr));
+       /* Tunnel ID */
+       ND_PRINT("(%u/", GET_BE_U_2(ptr));
        ptr += 2;
        cnt += 2;
        ptr += 2;
        cnt += 2;
-       TCHECK2(*ptr, 2);               /* Session ID */
-       printf("%u)",  EXTRACT_16BITS(ptr));
+       /* Session ID */
+       ND_PRINT("%u)",  GET_BE_U_2(ptr));
        ptr += 2;
        cnt += 2;
 
        if (flag_s) {
        ptr += 2;
        cnt += 2;
 
        if (flag_s) {
-               TCHECK2(*ptr, 2);       /* Ns */
-               printf("Ns=%u,", EXTRACT_16BITS(ptr));
+               ND_PRINT("Ns=%u,", GET_BE_U_2(ptr));
                ptr += 2;
                cnt += 2;
                ptr += 2;
                cnt += 2;
-               TCHECK2(*ptr, 2);       /* Nr */
-               printf("Nr=%u",  EXTRACT_16BITS(ptr));
+               ND_PRINT("Nr=%u",  GET_BE_U_2(ptr));
                ptr += 2;
                cnt += 2;
        }
 
                ptr += 2;
                cnt += 2;
        }
 
-       if (flag_o) {
-               TCHECK2(*ptr, 2);       /* Offset Size */
-               pad =  EXTRACT_16BITS(ptr);
+       if (flag_o) {   /* Offset Size */
+               pad =  GET_BE_U_2(ptr);
+               /* Offset padding octets in packet buffer? */
+               ND_TCHECK_LEN(ptr + 2, pad);
                ptr += (2 + pad);
                cnt += (2 + pad);
        }
 
        if (flag_l) {
                if (length < l2tp_len) {
                ptr += (2 + pad);
                cnt += (2 + pad);
        }
 
        if (flag_l) {
                if (length < l2tp_len) {
-                       printf(" Length %u larger than packet", l2tp_len);
-                       return;
+                       ND_PRINT(" Length %u larger than packet", l2tp_len);
+                       goto invalid;
                }
                length = l2tp_len;
        }
        if (length < cnt) {
                }
                length = l2tp_len;
        }
        if (length < cnt) {
-               printf(" Length %u smaller than header length", length);
-               return;
+               ND_PRINT(" Length %u smaller than header length", length);
+               goto invalid;
        }
        if (flag_t) {
                if (!flag_l) {
        }
        if (flag_t) {
                if (!flag_l) {
-                       printf(" No length");
-                       return;
+                       ND_PRINT(" No length");
+                       goto invalid;
                }
                if (length - cnt == 0) {
                }
                if (length - cnt == 0) {
-                       printf(" ZLB");
+                       ND_PRINT(" ZLB");
                } else {
                } else {
-                       l2tp_avp_print(ptr, length - cnt);
+                       /*
+                        * Print AVPs.
+                        */
+                       while (length - cnt != 0) {
+                               u_int avp_length;
+
+                               avp_length = l2tp_avp_print(ndo, ptr, length - cnt);
+                               if (avp_length == 0) {
+                                       goto invalid;
+                               }
+                               cnt += avp_length;
+                               ptr += avp_length;
+                       }
                }
        } else {
                }
        } else {
-               printf(" {");
-               ppp_print(ptr, length - cnt);
-               printf("}");
+               ND_PRINT(" {");
+               ppp_print(ndo, ptr, length - cnt);
+               ND_PRINT("}");
        }
        }
-
        return;
        return;
-
- trunc:
-       printf("%s", tstr);
+invalid:
+       nd_print_invalid(ndo);
 }
 }