]> 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 8ee0db94ec7690af1ba8d4ec44c945462e475e00..a320873444f1a7b7b841c8f417633f7c8754ad01 100644 (file)
  * L2TP support contributed by Motonori Shindo ([email protected])
  */
 
-#ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-l2tp.c,v 1.7 2000-07-01 03:48:44 assar Exp $";
-#endif
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "l2tp.h"
-#include "interface.h"
-
-static char tstr[] = " [|l2tp]";
-
-#ifndef TRUE
-#define TRUE 1
-#endif
+/* \summary: Layer Two Tunneling Protocol (L2TP) printer */
+
+/* specification: RFC 2661 */
+
+#include <config.h>
+
+#include "netdissect-stdinc.h"
+
+#define ND_LONGJMP_FROM_TCHECK
+#include "netdissect.h"
+#include "extract.h"
+
+#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_SCCCN      3  /* Start-Control-Connection-Connected */
+#define        L2TP_MSGTYPE_STOPCCN    4  /* Stop-Control-Connection-Notification */
+#define        L2TP_MSGTYPE_HELLO      6  /* Hello */
+#define        L2TP_MSGTYPE_OCRQ       7  /* Outgoing-Call-Request */
+#define        L2TP_MSGTYPE_OCRP       8  /* Outgoing-Call-Reply */
+#define        L2TP_MSGTYPE_OCCN       9  /* Outgoing-Call-Connected */
+#define        L2TP_MSGTYPE_ICRQ       10 /* Incoming-Call-Request */
+#define        L2TP_MSGTYPE_ICRP       11 /* Incoming-Call-Reply */
+#define        L2TP_MSGTYPE_ICCN       12 /* Incoming-Call-Connected */
+#define        L2TP_MSGTYPE_CDN        14 /* Call-Disconnect-Notify */
+#define        L2TP_MSGTYPE_WEN        15 /* WAN-Error-Notify */
+#define        L2TP_MSGTYPE_SLI        16 /* Set-Link-Info */
+
+static const struct tok l2tp_msgtype2str[] = {
+       { L2TP_MSGTYPE_SCCRQ,   "SCCRQ" },
+       { L2TP_MSGTYPE_SCCRP,   "SCCRP" },
+       { L2TP_MSGTYPE_SCCCN,   "SCCCN" },
+       { L2TP_MSGTYPE_STOPCCN, "StopCCN" },
+       { L2TP_MSGTYPE_HELLO,   "HELLO" },
+       { L2TP_MSGTYPE_OCRQ,    "OCRQ" },
+       { L2TP_MSGTYPE_OCRP,    "OCRP" },
+       { L2TP_MSGTYPE_OCCN,    "OCCN" },
+       { L2TP_MSGTYPE_ICRQ,    "ICRQ" },
+       { L2TP_MSGTYPE_ICRP,    "ICRP" },
+       { L2TP_MSGTYPE_ICCN,    "ICCN" },
+       { L2TP_MSGTYPE_CDN,     "CDN" },
+       { L2TP_MSGTYPE_WEN,     "WEN" },
+       { L2TP_MSGTYPE_SLI,     "SLI" },
+       { 0,                    NULL }
+};
 
-#ifndef FALSE
-#define FALSE 0
-#endif
+#define L2TP_AVP_MSGTYPE               0  /* Message Type */
+#define L2TP_AVP_RESULT_CODE           1  /* Result Code */
+#define L2TP_AVP_PROTO_VER             2  /* Protocol Version */
+#define L2TP_AVP_FRAMING_CAP           3  /* Framing Capabilities */
+#define L2TP_AVP_BEARER_CAP            4  /* Bearer Capabilities */
+#define L2TP_AVP_TIE_BREAKER           5  /* Tie Breaker */
+#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_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_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_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_SUB_ADDRESS           23 /* Sub-Address */
+#define L2TP_AVP_TX_CONN_SPEED         24 /* (Tx) Connect Speed */
+#define L2TP_AVP_PHY_CHANNEL_ID                25 /* Physical Channel ID */
+#define L2TP_AVP_INI_RECV_LCP          26 /* Initial Received LCP CONFREQ */
+#define L2TP_AVP_LAST_SENT_LCP         27 /* Last Sent LCP CONFREQ */
+#define L2TP_AVP_LAST_RECV_LCP         28 /* Last Received LCP CONFREQ */
+#define L2TP_AVP_PROXY_AUTH_TYPE       29 /* Proxy Authen Type */
+#define L2TP_AVP_PROXY_AUTH_NAME       30 /* Proxy Authen Name */
+#define L2TP_AVP_PROXY_AUTH_CHAL       31 /* Proxy Authen Challenge */
+#define L2TP_AVP_PROXY_AUTH_ID         32 /* Proxy Authen ID */
+#define L2TP_AVP_PROXY_AUTH_RESP       33 /* Proxy Authen Response */
+#define L2TP_AVP_CALL_ERRORS           34 /* Call Errors */
+#define L2TP_AVP_ACCM                  35 /* ACCM */
+#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 - RFC 3145 */
+
+static const struct tok l2tp_avp2str[] = {
+       { L2TP_AVP_MSGTYPE,             "MSGTYPE" },
+       { L2TP_AVP_RESULT_CODE,         "RESULT_CODE" },
+       { L2TP_AVP_PROTO_VER,           "PROTO_VER" },
+       { L2TP_AVP_FRAMING_CAP,         "FRAMING_CAP" },
+       { L2TP_AVP_BEARER_CAP,          "BEARER_CAP" },
+       { L2TP_AVP_TIE_BREAKER,         "TIE_BREAKER" },
+       { L2TP_AVP_FIRM_VER,            "FIRM_VER" },
+       { L2TP_AVP_HOST_NAME,           "HOST_NAME" },
+       { L2TP_AVP_VENDOR_NAME,         "VENDOR_NAME" },
+       { L2TP_AVP_ASSND_TUN_ID,        "ASSND_TUN_ID" },
+       { L2TP_AVP_RECV_WIN_SIZE,       "RECV_WIN_SIZE" },
+       { L2TP_AVP_CHALLENGE,           "CHALLENGE" },
+       { L2TP_AVP_Q931_CC,             "Q931_CC", },
+       { L2TP_AVP_CHALLENGE_RESP,      "CHALLENGE_RESP" },
+       { L2TP_AVP_ASSND_SESS_ID,       "ASSND_SESS_ID" },
+       { L2TP_AVP_CALL_SER_NUM,        "CALL_SER_NUM" },
+       { L2TP_AVP_MINIMUM_BPS,         "MINIMUM_BPS" },
+       { L2TP_AVP_MAXIMUM_BPS,         "MAXIMUM_BPS" },
+       { L2TP_AVP_BEARER_TYPE,         "BEARER_TYPE" },
+       { L2TP_AVP_FRAMING_TYPE,        "FRAMING_TYPE" },
+       { L2TP_AVP_PACKET_PROC_DELAY,   "PACKET_PROC_DELAY" },
+       { L2TP_AVP_CALLED_NUMBER,       "CALLED_NUMBER" },
+       { L2TP_AVP_CALLING_NUMBER,      "CALLING_NUMBER" },
+       { L2TP_AVP_SUB_ADDRESS,         "SUB_ADDRESS" },
+       { L2TP_AVP_TX_CONN_SPEED,       "TX_CONN_SPEED" },
+       { L2TP_AVP_PHY_CHANNEL_ID,      "PHY_CHANNEL_ID" },
+       { L2TP_AVP_INI_RECV_LCP,        "INI_RECV_LCP" },
+       { L2TP_AVP_LAST_SENT_LCP,       "LAST_SENT_LCP" },
+       { L2TP_AVP_LAST_RECV_LCP,       "LAST_RECV_LCP" },
+       { L2TP_AVP_PROXY_AUTH_TYPE,     "PROXY_AUTH_TYPE" },
+       { L2TP_AVP_PROXY_AUTH_NAME,     "PROXY_AUTH_NAME" },
+       { L2TP_AVP_PROXY_AUTH_CHAL,     "PROXY_AUTH_CHAL" },
+       { L2TP_AVP_PROXY_AUTH_ID,       "PROXY_AUTH_ID" },
+       { L2TP_AVP_PROXY_AUTH_RESP,     "PROXY_AUTH_RESP" },
+       { L2TP_AVP_CALL_ERRORS,         "CALL_ERRORS" },
+       { L2TP_AVP_ACCM,                "ACCM" },
+       { L2TP_AVP_RANDOM_VECTOR,       "RANDOM_VECTOR" },
+       { L2TP_AVP_PRIVATE_GRP_ID,      "PRIVATE_GRP_ID" },
+       { L2TP_AVP_RX_CONN_SPEED,       "RX_CONN_SPEED" },
+       { L2TP_AVP_SEQ_REQUIRED,        "SEQ_REQUIRED" },
+       { L2TP_AVP_PPP_DISCON_CC,       "PPP_DISCON_CC" },
+       { 0,                            NULL }
+};
 
-static char *l2tp_message_type_string[] = {
-       "RESERVED_0",           /* 0  Reserved */
-       "SCCRQ",                /* 1  Start-Control-Connection-Request */
-       "SCCRP",                /* 2  Start-Control-Connection-Reply */
-       "SCCCN",                /* 3  Start-Control-Connection-Connected */
-       "StopCCN",              /* 4  Stop-Control-Connection-Notification */
-       "RESERVED_5",           /* 5  Reserved */
-       "HELLO",                /* 6  Hello */
-       "OCRQ",                 /* 7  Outgoing-Call-Request */
-       "OCRP",                 /* 8  Outgoing-Call-Reply */
-       "OCCN",                 /* 9  Outgoing-Call-Connected */
-       "ICRQ",                 /* 10 Incoming-Call-Request */
-       "ICRP",                 /* 11 Incoming-Call-Reply */
-       "ICCN",                 /* 12 Incoming-Call-Connected */
-       "RESERVED_13",          /* 13 Reserved */
-       "CDN",                  /* 14 Call-Disconnect-Notify */
-       "WEN",                  /* 15 WAN-Error-Notify */
-       "SLI"                   /* 16 Set-Link-Info */
-#define L2TP_MAX_MSGTYPE_INDEX 17
+static const struct tok l2tp_authentype2str[] = {
+       { L2TP_AUTHEN_TYPE_RESERVED,    "Reserved" },
+       { L2TP_AUTHEN_TYPE_TEXTUAL,     "Textual" },
+       { L2TP_AUTHEN_TYPE_CHAP,        "CHAP" },
+       { L2TP_AUTHEN_TYPE_PAP,         "PAP" },
+       { L2TP_AUTHEN_TYPE_NO_AUTH,     "No Auth" },
+       { L2TP_AUTHEN_TYPE_MSCHAPv1,    "MS-CHAPv1" },
+       { 0,                            NULL }
 };
 
-static void l2tp_msgtype_print(const u_char *dat, u_int length);
-static void l2tp_result_code_print(const u_char *dat, u_int length);
-static void l2tp_proto_ver_print(const u_char *dat, u_int length);
-static void l2tp_framing_cap_print(const u_char *dat, u_int length);
-static void l2tp_bearer_cap_print(const u_char *dat, u_int length);
-static void l2tp_tie_breaker_print(const u_char *dat, u_int length);
-static void l2tp_firm_ver_print(const u_char *dat, u_int length);
-static void l2tp_host_name_print(const u_char *dat, u_int length);
-static void l2tp_vendor_name_print(const u_char *dat, u_int length);
-static void l2tp_assnd_tun_id_print(const u_char *dat, u_int length);
-static void l2tp_recv_win_size_print(const u_char *dat, u_int length);
-static void l2tp_challenge_print(const u_char *dat, u_int length);
-static void l2tp_q931_cc_print(const u_char *dat, u_int length);
-static void l2tp_challenge_resp_print(const u_char *dat, u_int length);
-static void l2tp_assnd_sess_id_print(const u_char *dat, u_int length);
-static void l2tp_call_ser_num_print(const u_char *dat, u_int length);
-static void l2tp_minimum_bps_print(const u_char *dat, u_int length);
-static void l2tp_maximum_bps_print(const u_char *dat, u_int length);
-static void l2tp_bearer_type_print(const u_char *dat, u_int length);
-static void l2tp_framing_type_print(const u_char *dat, u_int length);
-static void l2tp_packet_proc_delay_print(const u_char *dat, u_int length);
-static void l2tp_called_number_print(const u_char *dat, u_int length);
-static void l2tp_calling_number_print(const u_char *dat, u_int length);
-static void l2tp_sub_address_print(const u_char *dat, u_int length);
-static void l2tp_tx_conn_speed_print(const u_char *dat, u_int length);
-static void l2tp_phy_channel_id_print(const u_char *dat, u_int length);
-static void l2tp_ini_recv_lcp_print(const u_char *dat, u_int length);
-static void l2tp_last_sent_lcp_print(const u_char *dat, u_int length);
-static void l2tp_last_recv_lcp_print(const u_char *dat, u_int length);
-static void l2tp_proxy_auth_type_print(const u_char *dat, u_int length);
-static void l2tp_proxy_auth_name_print(const u_char *dat, u_int length);
-static void l2tp_proxy_auth_chal_print(const u_char *dat, u_int length);
-static void l2tp_proxy_auth_id_print(const u_char *dat, u_int length);
-static void l2tp_proxy_auth_resp_print(const u_char *dat, u_int length);
-static void l2tp_call_errors_print(const u_char *dat, u_int length);
-static void l2tp_accm_print(const u_char *dat, u_int length);
-static void l2tp_random_vector_print(const u_char *dat, u_int length);
-static void l2tp_private_grp_id_print(const u_char *dat, u_int length);
-static void l2tp_rx_conn_speed_print(const u_char *dat, u_int length);
-static void l2tp_seq_required_print(const u_char *dat, u_int length);
-static void l2tp_avp_print(const u_char *dat, u_int length);
-
-static struct l2tp_avp_vec l2tp_avp[] = {
-  {"MSGTYPE", l2tp_msgtype_print},             /* 0  Message Type */
-  {"RESULT_CODE", l2tp_result_code_print},     /* 1  Result Code */
-  {"PROTO_VER", l2tp_proto_ver_print},         /* 2  Protocol Version */
-  {"FRAMING_CAP", l2tp_framing_cap_print},     /* 3  Framing Capabilities */
-  {"BEARER_CAP", l2tp_bearer_cap_print},       /* 4  Bearer Capabilities */
-  {"TIE_BREAKER", l2tp_tie_breaker_print},     /* 5  Tie Breaker */
-  {"FIRM_VER", l2tp_firm_ver_print},           /* 6  Firmware Revision */
-  {"HOST_NAME", l2tp_host_name_print},         /* 7  Host Name */
-  {"VENDOR_NAME", l2tp_vendor_name_print},     /* 8  Vendor Name */
-  {"ASSND_TUN_ID", l2tp_assnd_tun_id_print},   /* 9  Assigned Tunnel ID */
-  {"RECV_WIN_SIZE", l2tp_recv_win_size_print}, /* 10 Receive Window Size */
-  {"CHALLENGE", l2tp_challenge_print},         /* 11 Challenge */
-  {"Q931_CC", l2tp_q931_cc_print},             /* 12 Q.931 Cause Code */
-  {"CHALLENGE_RESP", l2tp_challenge_resp_print},/* 13 Challenge Response */
-  {"ASSND_SESS_ID", l2tp_assnd_sess_id_print},  /* 14 Assigned Session ID */
-  {"CALL_SER_NUM", l2tp_call_ser_num_print},   /* 15 Call Serial Number */
-  {"MINIMUM_BPS",      l2tp_minimum_bps_print},/* 16 Minimum BPS */
-  {"MAXIMUM_BPS", l2tp_maximum_bps_print},     /* 17 Maximum BPS */
-  {"BEARER_TYPE",      l2tp_bearer_type_print},/* 18 Bearer Type */
-  {"FRAMING_TYPE", l2tp_framing_type_print},   /* 19 Framing Type */
-  {"PACKET_PROC_DELAY", l2tp_packet_proc_delay_print}, /* 20 Packet Processing Delay (OBSOLETE) */
-  {"CALLED_NUMBER", l2tp_called_number_print}, /* 21 Called Number */
-  {"CALLING_NUMBER", l2tp_calling_number_print},/* 22 Calling Number */
-  {"SUB_ADDRESS",      l2tp_sub_address_print},/* 23 Sub-Address */
-  {"TX_CONN_SPEED", l2tp_tx_conn_speed_print}, /* 24 (Tx) Connect Speed */
-  {"PHY_CHANNEL_ID", l2tp_phy_channel_id_print},/* 25 Physical Channel ID */
-  {"INI_RECV_LCP", l2tp_ini_recv_lcp_print},   /* 26 Initial Received LCP CONFREQ */
-  {"LAST_SENT_LCP", l2tp_last_sent_lcp_print}, /* 27 Last Sent LCP CONFREQ */
-  {"LAST_RECV_LCP", l2tp_last_recv_lcp_print}, /* 28 Last Received LCP CONFREQ */
-  {"PROXY_AUTH_TYPE", l2tp_proxy_auth_type_print},/* 29 Proxy Authen Type */
-  {"PROXY_AUTH_NAME", l2tp_proxy_auth_name_print},/* 30 Proxy Authen Name */
-  {"PROXY_AUTH_CHAL", l2tp_proxy_auth_chal_print},/* 31 Proxy Authen Challenge */
-  {"PROXY_AUTH_ID", l2tp_proxy_auth_id_print}, /* 32 Proxy Authen ID */
-  {"PROXY_AUTH_RESP", l2tp_proxy_auth_resp_print},/* 33 Proxy Authen Response */
-  {"CALL_ERRORS", l2tp_call_errors_print},     /* 34 Call Errors */
-  {"ACCM", l2tp_accm_print},                   /* 35 ACCM */
-  {"RANDOM_VECTOR", l2tp_random_vector_print}, /* 36 Random Vector */
-  {"PRIVATE_GRP_ID", l2tp_private_grp_id_print},/* 37 Private Group ID */
-  {"RX_CONN_SPEED", l2tp_rx_conn_speed_print}, /* 38 (Rx) Connect Speed */
-  {"SEQ_REQUIRED", l2tp_seq_required_print},   /* 39 Sequencing Required */
-#define L2TP_MAX_AVP_INDEX     40
+#define L2TP_PPP_DISCON_CC_DIRECTION_GLOBAL    0
+#define L2TP_PPP_DISCON_CC_DIRECTION_AT_PEER   1
+#define L2TP_PPP_DISCON_CC_DIRECTION_AT_LOCAL  2
+
+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" },
+       { 0,                                    NULL }
 };
 
 #if 0
@@ -176,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 failed due to lack of appropriate facilities being " \
+       "Call failed due to lack of appropriate facilities being "
        "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",
@@ -195,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",
-       "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",
@@ -208,516 +263,583 @@ static char *l2tp_error_code_general[] = {
 /******************************/
 /* generic print out routines */
 /******************************/
-static void 
-print_string(const u_char *dat, u_int length)
-{
-       int i;
-       for (i=0; i<length; i++) {
-               printf("%c", *dat++);
-       }
-}
-
-static void 
-print_octets(const u_char *dat, u_int length)
+static void
+print_octets(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       int i;
+       u_int i;
        for (i=0; i<length; i++) {
-               printf("%02x", *dat++);
+               ND_PRINT("%02x", GET_U_1(dat));
+               dat++;
        }
 }
 
 static void
-print_short(const u_short *dat)
+print_16bits_val(netdissect_options *ndo, const uint8_t *dat)
 {
-       printf("%u", ntohs(*dat));
+       ND_PRINT("%u", GET_BE_U_2(dat));
 }
 
 static void
-print_int(const u_int *dat)
+print_32bits_val(netdissect_options *ndo, const uint8_t *dat)
 {
-       printf("%lu", (u_long)ntohl(*dat));
+       ND_PRINT("%u", GET_BE_U_4(dat));
 }
 
-/**********************************/
-/* AVP-specific print out routines*/
-/**********************************/
+/***********************************/
+/* AVP-specific print out routines */
+/***********************************/
 static void
-l2tp_msgtype_print(const u_char *dat, u_int length)
+l2tp_msgtype_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       u_short *ptr = (u_short *)dat;
-
-       if (ntohs(*ptr) < L2TP_MAX_MSGTYPE_INDEX) {
-               printf("%s", l2tp_message_type_string[ntohs(*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
-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)
 {
-       /* we just print out the result and error code number */
-       u_short *ptr = (u_short *)dat;
-       
-       if (length == 2) {              /* result code */
-               printf("%u", ntohs(*ptr));      
-       } else if (length == 4) {       /* result & error code */
-               printf("%u/%u", ntohs(*ptr), ntohs(*(ptr+1)));
-       } else if (length > 4) {        /* result & error code & msg */
-               printf("%u/%u ", ntohs(*ptr), ntohs(*(ptr+1)));
-               print_string((u_char *)(ptr+2), length - 4);
+       /* Result Code */
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
        }
-}
+       ND_PRINT("%u", GET_BE_U_2(dat));
+       dat += 2;
+       length -= 2;
 
-static void
-l2tp_proto_ver_print(const u_char *dat, u_int length)
-{
-       printf("%d.%d", *dat, *(dat+1));
-}
+       /* 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
-l2tp_framing_cap_print(const u_char *dat, u_int length)
+l2tp_proto_ver_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       u_int *ptr = (u_int *)dat;
-
-       if (ntohl(*ptr) &  L2TP_FRAMING_CAP_ASYNC_MASK) {
-               printf("A");
-       }
-       if (ntohl(*ptr) &  L2TP_FRAMING_CAP_SYNC_MASK) {
-               printf("S");
+       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
-l2tp_bearer_cap_print(const u_char *dat, u_int length)
+l2tp_framing_cap_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       u_int *ptr = (u_int *)dat;
-
-       if (ntohl(*ptr) &  L2TP_BEARER_CAP_ANALOG_MASK) {
-               printf("A");
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
        }
-       if (ntohl(*ptr) &  L2TP_BEARER_CAP_DIGITAL_MASK) {
-               printf("D");
+       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
-l2tp_tie_breaker_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, 8);   /* Tie Break Value is 64bits long */
-}
-
-static void
-l2tp_firm_ver_print(const u_char *dat, u_int length)
-{
-       print_short((u_short *)dat);
-}
-
-static void
-l2tp_host_name_print(const u_char *dat, u_int length)
-{
-       print_string(dat, length);
-}
-
-static void
-l2tp_vendor_name_print(const u_char *dat, u_int length)
-{
-       print_string(dat, length);
-}
-
-static void
-l2tp_assnd_tun_id_print(const u_char *dat, u_int length)
-{
-       print_short((u_short *)dat);
-}
-
-static void
-l2tp_recv_win_size_print(const u_char *dat, u_int length)
-{
-       print_short((u_short *)dat); 
-}
-
-static void
-l2tp_challenge_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
-}
-
-static void
-l2tp_q931_cc_print(const u_char *dat, u_int length)
-{
-       print_short((u_short *)dat);
-       printf(", %02x", dat[2]);
-       if (length > 3) {
-               printf(" ");
-               print_string(dat+3, length-3);
-       } 
-}
-
-static void
-l2tp_challenge_resp_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, 16);          /* XXX length should be 16? */
-}
-
-static void
-l2tp_assnd_sess_id_print(const u_char *dat, u_int length)
-{
-       print_short((u_short *)dat);
-}
-
-static void
-l2tp_call_ser_num_print(const u_char *dat, u_int length)
-{
-       print_int((u_int *)dat);
-}
-
-static void
-l2tp_minimum_bps_print(const u_char *dat, u_int length)
+l2tp_bearer_cap_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       print_int((u_int *)dat);
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_CAP_ANALOG_MASK) {
+               ND_PRINT("A");
+       }
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_CAP_DIGITAL_MASK) {
+               ND_PRINT("D");
+       }
 }
 
 static void
-l2tp_maximum_bps_print(const u_char *dat, u_int length)
+l2tp_q931_cc_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       print_int((u_int *)dat);
+       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
-l2tp_bearer_type_print(const u_char *dat, u_int length)
+l2tp_bearer_type_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       u_int *ptr = (u_int *)dat;
-
-       if (ntohl(*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 (ntohl(*ptr) &  L2TP_BEARER_TYPE_DIGITAL_MASK) {
-               printf("D");
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_TYPE_DIGITAL_MASK) {
+               ND_PRINT("D");
        }
 }
 
 static void
-l2tp_framing_type_print(const u_char *dat, u_int length)
+l2tp_framing_type_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       u_int *ptr = (u_int *)dat;
-
-       if (ntohl(*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 (ntohl(*ptr) &  L2TP_FRAMING_TYPE_SYNC_MASK) {
-               printf("S");
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_TYPE_SYNC_MASK) {
+               ND_PRINT("S");
        }
 }
 
 static void
-l2tp_packet_proc_delay_print(const u_char *dat, u_int length)
+l2tp_packet_proc_delay_print(netdissect_options *ndo)
 {
-       printf("obsolete");
+       ND_PRINT("obsolete");
 }
 
 static void
-l2tp_called_number_print(const u_char *dat, u_int length)
+l2tp_proxy_auth_type_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       print_string(dat, length);
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       ND_PRINT("%s", tok2str(l2tp_authentype2str,
+                            "AuthType-#%u", GET_BE_U_2(dat)));
 }
 
 static void
-l2tp_calling_number_print(const u_char *dat, u_int length)
+l2tp_proxy_auth_id_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       print_string(dat, length);
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       ND_PRINT("%u", GET_BE_U_2(dat) & L2TP_PROXY_AUTH_ID_MASK);
 }
 
 static void
-l2tp_sub_address_print(const u_char *dat, u_int length)
+l2tp_call_errors_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       print_string(dat, length);
-}
+       uint32_t val;
 
-static void
-l2tp_tx_conn_speed_print(const u_char *dat, u_int length)
-{
-       print_int((u_int *)dat);
-}
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       dat += 2;       /* skip "Reserved" */
+       length -= 2;
 
-static void
-l2tp_phy_channel_id_print(const u_char *dat, u_int length)
-{
-       print_int((u_int *)dat);
-}
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("CRCErr=%u ", val);
 
-static void
-l2tp_ini_recv_lcp_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
-}
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("FrameErr=%u ", val);
 
-static void
-l2tp_last_sent_lcp_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
-}
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("HardOver=%u ", val);
 
-static void
-l2tp_last_recv_lcp_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
-}
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("BufOver=%u ", val);
 
-static void
-l2tp_proxy_auth_type_print(const u_char *dat, u_int length)
-{
-       u_short *ptr = (u_short *)dat;
-
-       switch (ntohs(*ptr)) {
-       case L2TP_AUTHEN_TYPE_RESERVED:
-               printf("Reserved");
-               break;
-       case L2TP_AUTHEN_TYPE_TEXTUAL:
-               printf("Textual");
-               break;
-       case L2TP_AUTHEN_TYPE_CHAP:
-               printf("CHAP");
-               break;
-       case L2TP_AUTHEN_TYPE_PAP:
-               printf("PAP");
-               break;
-       case L2TP_AUTHEN_TYPE_NO_AUTH:
-               printf("No Auth");
-               break;
-       case L2TP_AUTHEN_TYPE_MSCHAP:
-               printf("MS-CHAP");
-               break;
-       default:
-               printf("unknown");
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
        }
-}
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("Timeout=%u ", val);
 
-static void
-l2tp_proxy_auth_name_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
+       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
-l2tp_proxy_auth_chal_print(const u_char *dat, u_int length)
+l2tp_accm_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       print_octets(dat, length);
-}
+       uint32_t val;
 
-static void
-l2tp_proxy_auth_id_print(const u_char *dat, u_int length)
-{
-       u_short *ptr = (u_short *)dat;
+       if (length < 2) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       dat += 2;       /* skip "Reserved" */
+       length -= 2;
 
-       printf("%u", ntohs(*ptr) & L2TP_PROXY_AUTH_ID_MASK);
-}
+       if (length < 4) {
+               ND_PRINT("AVP too short");
+               return;
+       }
+       val = GET_BE_U_4(dat); dat += 4; length -= 4;
+       ND_PRINT("send=%08x ", val);
 
-static void
-l2tp_proxy_auth_resp_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
+       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
-l2tp_call_errors_print(const u_char *dat, u_int length)
+l2tp_ppp_discon_cc_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       struct l2tp_call_errors *ptr = (struct l2tp_call_errors *)dat;
-
-       printf("CRCErr=%d FrameErr=%d HardOver=%d BufOver=%d ",
-              ptr->crc_errs,
-              ptr->framing_errs,
-              ptr->hardware_overruns,
-              ptr->buffer_overruns);
-       printf("Timeout=%d AlingErr=%d",
-              ptr->timeout_errs,
-              ptr->alignment_errs);
+       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_accm_print(const u_char *dat, u_int length)
+static u_int
+l2tp_avp_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       struct l2tp_accm *ptr = (struct l2tp_accm *)dat;
-
-       printf("send=%x recv=%x", ptr->send_accm, ptr->recv_accm);
-}
+       u_int len;
+       uint16_t attr_type;
+       int hidden = FALSE;
 
-static void
-l2tp_random_vector_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
-}
+       ND_PRINT(" ");
+       /* Flags & Length */
+       len = GET_BE_U_2(dat) & L2TP_AVP_HDR_LEN_MASK;
 
-static void
-l2tp_private_grp_id_print(const u_char *dat, u_int length)
-{
-       print_string(dat, length);      
-       /* XXX print_octets is more appropriate?? */
-}
+       /* If it is not long enough to contain the header, we'll give up. */
+       ND_ICHECKMSG_U("AVP length", len, <, 6);
 
-static void
-l2tp_rx_conn_speed_print(const u_char *dat, u_int length)
-{
-       print_int((u_int *)dat);
-}
+       /* If it goes past the end of the remaining length of the packet,
+          we'll give up. */
+       if (len > length) {
+               ND_PRINT(" (len > %u)", length);
+               goto invalid;
+       }
 
-static void
-l2tp_seq_required_print(const u_char *dat, u_int length)
-{
-       return;
-}
+       /* If it goes past the end of the remaining length of the captured
+          data, we'll give up. */
+       ND_TCHECK_LEN(dat, len);
 
-static void
-l2tp_avp_print(const u_char *dat, u_int length)
-{
-       u_int len;
-       const u_short *ptr = (u_short *)dat;
-       int hidden = FALSE;
+       /*
+        * 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.
+        */
 
-       printf(" ");
-       if (length > 0 && (snapend - dat) >= 2) {
-               /* there must be at least two octets for the length
-                  to be decoded */
-               if ((len = (ntohs(*ptr) & L2TP_AVP_HDR_LEN_MASK)) <=
-                   (snapend - dat)) {
-                       if (ntohs(*ptr) & L2TP_AVP_HDR_FLAG_MANDATORY) {
-                               printf("*");
-                       }
-                       if (ntohs(*ptr) & L2TP_AVP_HDR_FLAG_HIDDEN) {
-                               hidden = TRUE;
-                               printf("?");
-                       }
-               } else {
-                       printf("|...");
-                       return;
-               }
-               ptr++;
-
-               if (ntohs(*ptr)) {
-                       /* Vendor Specific Attribute */
-                       printf("VENDOR%04x:", ntohs(*ptr));
-                       ptr++;
-                       printf("ATTR%04x", ntohs(*ptr));
-                       printf("(");
-                       print_octets((u_char *)ptr+2, len-6);
-                       printf(")");
+       if (GET_BE_U_2(dat) & L2TP_AVP_HDR_FLAG_MANDATORY) {
+               ND_PRINT("*");
+       }
+       if (GET_BE_U_2(dat) & L2TP_AVP_HDR_FLAG_HIDDEN) {
+               hidden = TRUE;
+               ND_PRINT("?");
+       }
+       dat += 2;
+
+       if (GET_BE_U_2(dat)) {
+               /* Vendor Specific Attribute */
+               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 */
+               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) {
+                       ND_PRINT("???");
                } else {
-                       /* IETF-defined Attribute */ 
-                       ptr++;
-                       if (ntohs(*ptr) < L2TP_MAX_AVP_INDEX) {
-                               printf("%s", l2tp_avp[ntohs(*ptr)].name);
-                               printf("(");
-                               if (!hidden) {
-                                       (l2tp_avp[ntohs(*ptr)].print)
-                                               ((u_char *)ptr+2, len-6);
-                               } else {
-                                       printf("???");
+                       switch (attr_type) {
+                       case L2TP_AVP_MSGTYPE:
+                               l2tp_msgtype_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_RESULT_CODE:
+                               l2tp_result_code_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_PROTO_VER:
+                               l2tp_proto_ver_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_FRAMING_CAP:
+                               l2tp_framing_cap_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_BEARER_CAP:
+                               l2tp_bearer_cap_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_TIE_BREAKER:
+                               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:
+                               if (len-6 < 2) {
+                                       ND_PRINT("AVP too short");
+                                       break;
                                }
-                               printf(")");
-                       } else {
-                               printf(" invalid AVP %u", ntohs(*ptr));
+                               print_16bits_val(ndo, dat);
+                               break;
+                       case L2TP_AVP_HOST_NAME:
+                       case L2TP_AVP_VENDOR_NAME:
+                       case L2TP_AVP_CALLING_NUMBER:
+                       case L2TP_AVP_CALLED_NUMBER:
+                       case L2TP_AVP_SUB_ADDRESS:
+                       case L2TP_AVP_PROXY_AUTH_NAME:
+                       case L2TP_AVP_PRIVATE_GRP_ID:
+                               nd_printjn(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_CHALLENGE:
+                       case L2TP_AVP_INI_RECV_LCP:
+                       case L2TP_AVP_LAST_SENT_LCP:
+                       case L2TP_AVP_LAST_RECV_LCP:
+                       case L2TP_AVP_PROXY_AUTH_CHAL:
+                       case L2TP_AVP_PROXY_AUTH_RESP:
+                       case L2TP_AVP_RANDOM_VECTOR:
+                               print_octets(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_Q931_CC:
+                               l2tp_q931_cc_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_CHALLENGE_RESP:
+                               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:
+                       case L2TP_AVP_MAXIMUM_BPS:
+                       case L2TP_AVP_TX_CONN_SPEED:
+                       case L2TP_AVP_PHY_CHANNEL_ID:
+                       case L2TP_AVP_RX_CONN_SPEED:
+                               if (len-6 < 4) {
+                                       ND_PRINT("AVP too short");
+                                       break;
+                               }
+                               print_32bits_val(ndo, dat);
+                               break;
+                       case L2TP_AVP_BEARER_TYPE:
+                               l2tp_bearer_type_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_FRAMING_TYPE:
+                               l2tp_framing_type_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_PACKET_PROC_DELAY:
+                               l2tp_packet_proc_delay_print(ndo);
+                               break;
+                       case L2TP_AVP_PROXY_AUTH_TYPE:
+                               l2tp_proxy_auth_type_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_PROXY_AUTH_ID:
+                               l2tp_proxy_auth_id_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_CALL_ERRORS:
+                               l2tp_call_errors_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_ACCM:
+                               l2tp_accm_print(ndo, dat, len-6);
+                               break;
+                       case L2TP_AVP_SEQ_REQUIRED:
+                               break;  /* No Attribute Value */
+                       case L2TP_AVP_PPP_DISCON_CC:
+                               l2tp_ppp_discon_cc_print(ndo, dat, len-6);
+                               break;
+                       default:
+                               break;
                        }
                }
-
-               l2tp_avp_print(dat + len, length - len);
-       } else if (length == 0) {
-               return;
-       } else {
-               printf("|...");
+               ND_PRINT(")");
        }
+
+       return (len);
+
+invalid:
+       return (0);
 }
 
 
 void
-l2tp_print(const u_char *dat, u_int length)
+l2tp_print(netdissect_options *ndo, const u_char *dat, u_int length)
 {
-       const u_short *ptr = (u_short *)dat;
+       const u_char *ptr = dat;
        u_int cnt = 0;                  /* total octets consumed */
-       u_short pad;
-       int flag_t, flag_l, flag_s, flag_o, flag_p;
-       u_short l2tp_len;
+       uint16_t pad;
+       int flag_t, flag_l, flag_s, flag_o;
+       uint16_t l2tp_len;
 
-       flag_t = flag_l = flag_s = flag_o = flag_p = FALSE;
-
-       if (min(length, snapend - dat) - 6 < 0) { 
-               /* flag/ver, tunnel_id, session_id must be present for
-                  this packet to be properly decoded */
-               printf("%s", tstr);
-               return;
-       }
+       ndo->ndo_protocol = "l2tp";
+       flag_t = flag_l = flag_s = flag_o = FALSE;
 
-       if ((ntohs(*ptr) & L2TP_VERSION_MASK) == L2TP_VERSION_L2TP) {
-               printf(" l2tp:");
-       } else if ((ntohs(*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 {
-               printf(" Unknown Version, neither L2F(1) nor L2TP(2)");
+               ND_PRINT(" Unknown Version, neither L2F(1) nor L2TP(2)");
                return;         /* nothing we can do */
        }
 
-       printf("[");
-       if (ntohs(*ptr) & L2TP_FLAG_TYPE) {
+       ND_PRINT("[");
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_TYPE) {
                flag_t = TRUE;
-               printf("T");
+               ND_PRINT("T");
        }
-       if (ntohs(*ptr) & L2TP_FLAG_LENGTH) {
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_LENGTH) {
                flag_l = TRUE;
-               printf("L");
+               ND_PRINT("L");
        }
-       if (ntohs(*ptr) & L2TP_FLAG_SEQUENCE) {
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_SEQUENCE) {
                flag_s = TRUE;
-               printf("S");
+               ND_PRINT("S");
        }
-       if (ntohs(*ptr) & L2TP_FLAG_OFFSET) {
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_OFFSET) {
                flag_o = TRUE;
-               printf("O");
+               ND_PRINT("O");
        }
-       if (ntohs(*ptr) & L2TP_FLAG_PRIORITY) {
-               flag_p = TRUE;
-               printf("P");
-       }
-       printf("]");
+       if (GET_BE_U_2(ptr) & L2TP_FLAG_PRIORITY)
+               ND_PRINT("P");
+       ND_PRINT("]");
 
-       ptr++;
+       ptr += 2;
        cnt += 2;
-       
+
        if (flag_l) {
-               l2tp_len = ntohs(*ptr++);       /* XXX need to consider 
-                                                  truncation ?? */
+               l2tp_len = GET_BE_U_2(ptr);
+               ptr += 2;
                cnt += 2;
        } else {
                l2tp_len = 0;
        }
-
-       printf("(%u/", ntohs(*ptr++));          /* Tunnel ID */
-       printf("%u)",  ntohs(*ptr++));          /* Session ID */
-       cnt += 4;
+       /* Tunnel ID */
+       ND_PRINT("(%u/", GET_BE_U_2(ptr));
+       ptr += 2;
+       cnt += 2;
+       /* Session ID */
+       ND_PRINT("%u)",  GET_BE_U_2(ptr));
+       ptr += 2;
+       cnt += 2;
 
        if (flag_s) {
-               printf("Ns=%u,", ntohs(*ptr++));
-               printf("Nr=%u",  ntohs(*ptr++));
-               cnt += 4;
+               ND_PRINT("Ns=%u,", GET_BE_U_2(ptr));
+               ptr += 2;
+               cnt += 2;
+               ND_PRINT("Nr=%u",  GET_BE_U_2(ptr));
+               ptr += 2;
+               cnt += 2;
        }
 
-       if (flag_o) {
-               pad =  ntohs(*ptr++);
-               ptr += pad / sizeof(*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) {
+                       ND_PRINT(" Length %u larger than packet", l2tp_len);
+                       goto invalid;
+               }
+               length = l2tp_len;
+       }
+       if (length < cnt) {
+               ND_PRINT(" Length %u smaller than header length", length);
+               goto invalid;
+       }
        if (flag_t) {
+               if (!flag_l) {
+                       ND_PRINT(" No length");
+                       goto invalid;
+               }
                if (length - cnt == 0) {
-                       printf(" ZLB");
+                       ND_PRINT(" ZLB");
                } else {
-                       l2tp_avp_print((u_char *)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 {
-#if 0
-               printf(" {");
-               ppp_hdlc_print((u_char *)ptr, length - cnt);
-               printf("}");
-#else
-               printf("[hdlc|]");
-#endif
+               ND_PRINT(" {");
+               ppp_print(ndo, ptr, length - cnt);
+               ND_PRINT("}");
        }
-}      
+       return;
+invalid:
+       nd_print_invalid(ndo);
+}