]> 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 2f726574e4ee3757b493bbdbd9707de6e5855d07..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 "l2tp.h"
-#include "interface.h"
+#define ND_LONGJMP_FROM_TCHECK
+#include "netdissect.h"
 #include "extract.h"
 
 #include "extract.h"
 
-static char tstr[] = " [|l2tp]";
+#define L2TP_FLAG_TYPE         0x8000  /* Type (0=Data, 1=Control) */
+#define L2TP_FLAG_LENGTH       0x4000  /* Length */
+#define L2TP_FLAG_SEQUENCE     0x0800  /* Sequence */
+#define L2TP_FLAG_OFFSET       0x0200  /* Offset */
+#define L2TP_FLAG_PRIORITY     0x0100  /* Priority */
+
+#define L2TP_VERSION_MASK      0x000f  /* Version Mask */
+#define L2TP_VERSION_L2F       0x0001  /* L2F */
+#define L2TP_VERSION_L2TP      0x0002  /* L2TP */
+
+#define L2TP_AVP_HDR_FLAG_MANDATORY    0x8000  /* Mandatory Flag */
+#define L2TP_AVP_HDR_FLAG_HIDDEN       0x4000  /* Hidden Flag */
+#define L2TP_AVP_HDR_LEN_MASK          0x03ff  /* Length Mask */
+
+#define L2TP_FRAMING_CAP_SYNC_MASK     0x00000001      /* Synchronous */
+#define L2TP_FRAMING_CAP_ASYNC_MASK    0x00000002      /* Asynchronous */
+
+#define L2TP_FRAMING_TYPE_SYNC_MASK    0x00000001      /* Synchronous */
+#define L2TP_FRAMING_TYPE_ASYNC_MASK   0x00000002      /* Asynchronous */
+
+#define L2TP_BEARER_CAP_DIGITAL_MASK   0x00000001      /* Digital */
+#define L2TP_BEARER_CAP_ANALOG_MASK    0x00000002      /* Analog */
+
+#define L2TP_BEARER_TYPE_DIGITAL_MASK  0x00000001      /* Digital */
+#define L2TP_BEARER_TYPE_ANALOG_MASK   0x00000002      /* Analog */
+
+/* Authen Type */
+#define L2TP_AUTHEN_TYPE_RESERVED      0x0000  /* Reserved */
+#define L2TP_AUTHEN_TYPE_TEXTUAL       0x0001  /* Textual username/password exchange */
+#define L2TP_AUTHEN_TYPE_CHAP          0x0002  /* PPP CHAP */
+#define L2TP_AUTHEN_TYPE_PAP           0x0003  /* PPP PAP */
+#define L2TP_AUTHEN_TYPE_NO_AUTH       0x0004  /* No Authentication */
+#define L2TP_AUTHEN_TYPE_MSCHAPv1      0x0005  /* MSCHAPv1 */
+
+#define L2TP_PROXY_AUTH_ID_MASK                0x00ff
+
 
 #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 */
@@ -55,8 +85,8 @@ static char tstr[] = " [|l2tp]";
 #define        L2TP_MSGTYPE_WEN        15 /* WAN-Error-Notify */
 #define        L2TP_MSGTYPE_SLI        16 /* Set-Link-Info */
 
 #define        L2TP_MSGTYPE_WEN        15 /* WAN-Error-Notify */
 #define        L2TP_MSGTYPE_SLI        16 /* Set-Link-Info */
 
-static struct tok l2tp_msgtype2str[] = {
-       { L2TP_MSGTYPE_SCCRQ,   "SCCRQ" },
+static const struct tok l2tp_msgtype2str[] = {
+       { 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" },
@@ -82,17 +112,17 @@ static 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 */
@@ -112,10 +142,10 @@ static 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 struct tok l2tp_avp2str[] = {
+static const struct tok l2tp_avp2str[] = {
        { L2TP_AVP_MSGTYPE,             "MSGTYPE" },
        { L2TP_AVP_RESULT_CODE,         "RESULT_CODE" },
        { L2TP_AVP_PROTO_VER,           "PROTO_VER" },
        { L2TP_AVP_MSGTYPE,             "MSGTYPE" },
        { L2TP_AVP_RESULT_CODE,         "RESULT_CODE" },
        { L2TP_AVP_PROTO_VER,           "PROTO_VER" },
@@ -160,7 +190,7 @@ static struct tok l2tp_avp2str[] = {
        { 0,                            NULL }
 };
 
        { 0,                            NULL }
 };
 
-static struct tok l2tp_authentype2str[] = {
+static const struct tok l2tp_authentype2str[] = {
        { L2TP_AUTHEN_TYPE_RESERVED,    "Reserved" },
        { L2TP_AUTHEN_TYPE_TEXTUAL,     "Textual" },
        { L2TP_AUTHEN_TYPE_CHAP,        "CHAP" },
        { L2TP_AUTHEN_TYPE_RESERVED,    "Reserved" },
        { L2TP_AUTHEN_TYPE_TEXTUAL,     "Textual" },
        { L2TP_AUTHEN_TYPE_CHAP,        "CHAP" },
@@ -174,7 +204,7 @@ static struct tok l2tp_authentype2str[] = {
 #define L2TP_PPP_DISCON_CC_DIRECTION_AT_PEER   1
 #define L2TP_PPP_DISCON_CC_DIRECTION_AT_LOCAL  2
 
 #define L2TP_PPP_DISCON_CC_DIRECTION_AT_PEER   1
 #define L2TP_PPP_DISCON_CC_DIRECTION_AT_LOCAL  2
 
-static struct tok l2tp_cc_direction2str[] = {
+static const struct tok l2tp_cc_direction2str[] = {
        { L2TP_PPP_DISCON_CC_DIRECTION_GLOBAL,  "global error" },
        { L2TP_PPP_DISCON_CC_DIRECTION_AT_PEER, "at peer" },
        { L2TP_PPP_DISCON_CC_DIRECTION_AT_LOCAL,"at local" },
        { L2TP_PPP_DISCON_CC_DIRECTION_GLOBAL,  "global error" },
        { L2TP_PPP_DISCON_CC_DIRECTION_AT_PEER, "at peer" },
        { L2TP_PPP_DISCON_CC_DIRECTION_AT_LOCAL,"at local" },
@@ -201,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",
@@ -220,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",
@@ -234,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)
+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("%c", *dat++);
+               ND_PRINT("%02x", GET_U_1(dat));
+               dat++;
        }
 }
 
 static void
        }
 }
 
 static void
-print_octets(const u_char *dat, u_int length)
+print_16bits_val(netdissect_options *ndo, const uint8_t *dat)
 {
 {
-       u_int i;
-       for (i=0; i<length; i++) {
-               printf("%02x", *dat++);
-       }
+       ND_PRINT("%u", GET_BE_U_2(dat));
 }
 
 static void
 }
 
 static void
-print_16bits_val(const u_int16_t *dat)
+print_32bits_val(netdissect_options *ndo, const uint8_t *dat)
 {
 {
-       printf("%u", EXTRACT_16BITS(dat));
-}
-
-static void
-print_32bits_val(const u_int32_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 (GET_BE_U_4(dat) &  L2TP_FRAMING_CAP_ASYNC_MASK) {
+               ND_PRINT("A");
        }
        }
-       if (EXTRACT_32BITS(ptr) &  L2TP_FRAMING_CAP_SYNC_MASK) {
-               printf("S");
+       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);
 
 
-       if (EXTRACT_16BITS(ptr) & L2TP_AVP_HDR_FLAG_MANDATORY) {
-               printf("*");
+       /*
+        * 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 (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:
@@ -537,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:
@@ -546,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:
@@ -560,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);
 }
 }