]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-l2tp.c
CI: Introduce and use TCPDUMP_CMAKE_TAINTED
[tcpdump] / print-l2tp.c
index 8ee0db94ec7690af1ba8d4ec44c945462e475e00..940aa2b662f24715756a11180f7398f3db702a80 100644 (file)
  * L2TP support contributed by Motonori Shindo ([email protected])
  */
 
  * 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
+/* \summary: Layer Two Tunneling Protocol (L2TP) printer */
+
+/* specification: RFC 2661 */
 
 #ifdef HAVE_CONFIG_H
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
 #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
+#include "netdissect-stdinc.h"
+
+#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
 };
 
 #if 0
@@ -176,9 +232,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",
@@ -195,7 +251,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",
@@ -208,516 +264,596 @@ static char *l2tp_error_code_general[] = {
 /******************************/
 /* generic print out routines */
 /******************************/
 /******************************/
 /* generic print out routines */
 /******************************/
-static void 
-print_string(const u_char *dat, u_int length)
+static void
+print_string(netdissect_options *ndo, const u_char *dat, u_int length)
 {
 {
-       int i;
+       u_int i;
        for (i=0; i<length; i++) {
        for (i=0; i<length; i++) {
-               printf("%c", *dat++);
+               fn_print_char(ndo, GET_U_1(dat));
+               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++) {
        for (i=0; i<length; i++) {
-               printf("%02x", *dat++);
+               ND_PRINT("%02x", GET_U_1(dat));
+               dat++;
        }
 }
 
 static void
        }
 }
 
 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
 }
 
 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
 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
 }
 
 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(" ");
+       print_string(ndo, dat, length);
+}
 
 static void
 
 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
 }
 
 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
        }
 }
 
 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
 }
 
 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(" ");
+               print_string(ndo, dat, length);
+       }
 }
 
 static void
 }
 
 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 (ntohl(*ptr) &  L2TP_BEARER_TYPE_DIGITAL_MASK) {
-               printf("D");
+       if (GET_BE_U_4(dat) &  L2TP_BEARER_TYPE_ANALOG_MASK) {
+               ND_PRINT("A");
+       }
+       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, 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 (ntohl(*ptr) &  L2TP_FRAMING_TYPE_SYNC_MASK) {
-               printf("S");
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_TYPE_ASYNC_MASK) {
+               ND_PRINT("A");
+       }
+       if (GET_BE_U_4(dat) &  L2TP_FRAMING_TYPE_SYNC_MASK) {
+               ND_PRINT("S");
        }
 }
 
 static void
        }
 }
 
 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
 }
 
 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
 }
 
 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
 }
 
 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
 }
 
 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
 }
 
 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(" ");
+               print_string(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;
+       u_int len;
+       uint16_t attr_type;
+       int hidden = FALSE;
 
 
-       printf("send=%x recv=%x", ptr->send_accm, ptr->recv_accm);
-}
+       ND_PRINT(" ");
+       /* Flags & Length */
+       len = GET_BE_U_2(dat) & L2TP_AVP_HDR_LEN_MASK;
 
 
-static void
-l2tp_random_vector_print(const u_char *dat, u_int length)
-{
-       print_octets(dat, length);
-}
+       /* If it is not long enough to contain the header, we'll give up. */
+       if (len < 6)
+               goto trunc;
 
 
-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 goes past the end of the remaining length of the packet,
+          we'll give up. */
+       if (len > (u_int)length)
+               goto trunc;
 
 
-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 captured
+          data, we'll give up. */
+       ND_TCHECK_LEN(dat, len);
 
 
-static void
-l2tp_seq_required_print(const u_char *dat, u_int length)
-{
-       return;
-}
+       /*
+        * 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.
+        */
 
 
-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;
-
-       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 {
                } 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:
+                               print_string(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);
+
+ trunc:
+       nd_print_trunc(ndo);
+       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_short *ptr = (u_short *)dat;
+       const u_char *ptr = dat;
        u_int cnt = 0;                  /* total octets consumed */
        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;
-
-       flag_t = flag_l = flag_s = flag_o = flag_p = FALSE;
+       uint16_t pad;
+       int flag_t, flag_l, flag_s, flag_o;
+       uint16_t l2tp_len;
 
 
-       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 {
                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 (ntohs(*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 (ntohs(*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 (ntohs(*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 (ntohs(*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 (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;
        cnt += 2;
-       
+
        if (flag_l) {
        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;
        }
                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) {
 
        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);
        }
 
                cnt += (2 + pad);
        }
 
+       if (flag_l) {
+               if (length < l2tp_len) {
+                       ND_PRINT(" Length %u larger than packet", l2tp_len);
+                       return;
+               }
+               length = l2tp_len;
+       }
+       if (length < cnt) {
+               ND_PRINT(" Length %u smaller than header length", length);
+               return;
+       }
        if (flag_t) {
        if (flag_t) {
+               if (!flag_l) {
+                       ND_PRINT(" No length");
+                       return;
+               }
                if (length - cnt == 0) {
                if (length - cnt == 0) {
-                       printf(" ZLB");
+                       ND_PRINT(" ZLB");
                } else {
                } 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) {
+                                       /*
+                                        * Truncated.
+                                        */
+                                       break;
+                               }
+                               cnt += avp_length;
+                               ptr += avp_length;
+                       }
                }
        } else {
                }
        } 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;
+trunc:
+       nd_print_trunc(ndo);
+}