aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-l2tp.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-l2tp.c')
-rw-r--r--epan/dissectors/packet-l2tp.c1082
1 files changed, 1082 insertions, 0 deletions
diff --git a/epan/dissectors/packet-l2tp.c b/epan/dissectors/packet-l2tp.c
new file mode 100644
index 0000000000..719d8b32d3
--- /dev/null
+++ b/epan/dissectors/packet-l2tp.c
@@ -0,0 +1,1082 @@
+/* packet-l2tp.c
+ * Routines for Layer Two Tunnelling Protocol (L2TP) (RFC 2661) packet
+ * disassembly
+ * John Thomes <john@ensemblecom.com>
+ *
+ * Minor changes by: (2000-01-10)
+ * Laurent Cazalet <laurent.cazalet@mailclub.net>
+ * Thomas Parvais <thomas.parvais@advalvas.be>
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+static int proto_l2tp = -1;
+static int hf_l2tp_type = -1;
+static int hf_l2tp_length_bit = -1;
+static int hf_l2tp_seq_bit = -1;
+static int hf_l2tp_offset_bit = -1;
+static int hf_l2tp_priority = -1;
+static int hf_l2tp_version = -1;
+static int hf_l2tp_length = -1;
+static int hf_l2tp_tunnel = -1;
+static int hf_l2tp_session = -1;
+static int hf_l2tp_Ns = -1;
+static int hf_l2tp_Nr = -1;
+static int hf_l2tp_offset = -1;
+static int hf_l2tp_avp_mandatory = -1;
+static int hf_l2tp_avp_hidden = -1;
+static int hf_l2tp_avp_length = -1;
+static int hf_l2tp_avp_vendor_id = -1;
+static int hf_l2tp_avp_type = -1;
+static int hf_l2tp_tie_breaker = -1;
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <epan/packet.h>
+#include <epan/resolv.h>
+
+#define UDP_PORT_L2TP 1701
+
+#define CONTROL_BIT(msg_info) (msg_info & 0x8000) /* Type bit control = 1 data = 0 */
+#define LENGTH_BIT(msg_info) (msg_info & 0x4000) /* Length bit = 1 */
+#define RESERVE_BITS(msg_info) (msg_info &0x37F8) /* Reserved bit - usused */
+#define SEQUENCE_BIT(msg_info) (msg_info & 0x0800) /* SEQUENCE bit = 1 Ns and Nr fields */
+#define OFFSET_BIT(msg_info) (msg_info & 0x0200) /* Offset */
+#define PRIORITY_BIT(msg_info) (msg_info & 0x0100) /* Priority */
+#define L2TP_VERSION(msg_info) (msg_info & 0x000f) /* Version of l2tp */
+#define MANDATORY_BIT(msg_info) (msg_info & 0x8000) /* Mandatory = 1 */
+#define HIDDEN_BIT(msg_info) (msg_info & 0x4000) /* Hidden = 1 */
+#define AVP_LENGTH(msg_info) (msg_info & 0x03ff) /* AVP Length */
+#define FRAMING_SYNC(msg_info) (msg_info & 0x0001) /* SYNC Framing Type */
+#define FRAMING_ASYNC(msg_info) (msg_info & 0x0002) /* ASYNC Framing Type */
+#define BEARER_DIGITAL(msg_info) (msg_info & 0x0001) /* Digital Bearer Type */
+#define BEARER_ANALOG(msg_info) (msg_info & 0x0002) /* Analog Bearer Type */
+
+static gint ett_l2tp = -1;
+static gint ett_l2tp_ctrl = -1;
+static gint ett_l2tp_avp = -1;
+static gint ett_l2tp_lcp = -1;
+
+#define AVP_SCCRQ 1
+#define AVP_SCCRP 2
+#define AVP_SCCCN 3
+#define AVP_StopCCN 4
+#define AVP_Reserved 5
+#define AVP_HELLO 6
+#define AVP_OCRQ 7
+#define AVP_OCRP 8
+#define AVP_ORCRP 9
+#define AVP_ICRQ 10
+#define AVP_ICRP 11
+#define AVP_ICCN 12
+#define AVP_Reserved1 13
+#define AVP_CDN 14
+
+
+#define NUM_CONTROL_CALL_TYPES 16
+static const char *calltypestr[NUM_CONTROL_CALL_TYPES+1] = {
+ "Unknown Call Type ",
+ "Start_Control_Request ",
+ "Start_Control_Reply ",
+ "Start_Control_Connected ",
+ "Stop_Control_Notification ",
+ "Reserved ",
+ "Hello ",
+ "Outgoing_Call_Request ",
+ "Outgoing_Call_Reply ",
+ "Outgoing_Call_Connected ",
+ "Incoming_Call_Request ",
+ "Incoming_Call_Reply ",
+ "Incoming_Call_Connected ",
+ "Reserved ",
+ "Call_Disconnect_Notification",
+ "WAN_Error_Notify ",
+ "Set_Link_Info ",
+};
+
+static const char *calltype_short_str[NUM_CONTROL_CALL_TYPES+1] = {
+ "Unknown ",
+ "SCCRQ ",
+ "SCCRP ",
+ "SCCCN ",
+ "StopCCN ",
+ "Reserved",
+ "Hello ",
+ "OCRQ ",
+ "OCRP ",
+ "OCCN ",
+ "ICRQ ",
+ "ICRP ",
+ "ICCN ",
+ "Reserved",
+ "CDN ",
+ "WEN ",
+ "SLI ",
+};
+
+
+static const char *control_msg = "Control Message";
+static const char *data_msg = "Data Message";
+static const value_string l2tp_type_vals[] = {
+ { 0, "Data Message" },
+ { 1, "Control Message" },
+ { 0, NULL },
+};
+
+static const value_string cause_code_direction_vals[] = {
+ { 0, "global error" },
+ { 1, "at peer" },
+ { 2, "at local" },
+ { 0, NULL },
+};
+
+static const true_false_string l2tp_length_bit_truth =
+ { "Length field is present", "Length field is not present" };
+
+static const true_false_string l2tp_seq_bit_truth =
+ { "Ns and Nr fields are present", "Ns and Nr fields are not present" };
+
+static const true_false_string l2tp_offset_bit_truth =
+ { "Offset Size field is present", "Offset size field is not present" };
+
+static const true_false_string l2tp_priority_truth =
+ { "This data message has priority", "No priority" };
+
+static const value_string authen_type_vals[] = {
+ { 0, "Reserved" },
+ { 1, "Textual username and password" },
+ { 2, "PPP CHAP" },
+ { 3, "PPP PAP" },
+ { 4, "No Authentication" },
+ { 5, "Microsoft CHAP Version 1" },
+ { 0, NULL }
+};
+
+#define CONTROL_MESSAGE 0
+#define RESULT_ERROR_CODE 1
+#define PROTOCOL_VERSION 2
+#define FRAMING_CAPABILITIES 3
+#define BEARER_CAPABILITIES 4
+#define TIE_BREAKER 5
+#define FIRMWARE_REVISION 6
+#define HOST_NAME 7
+#define VENDOR_NAME 8
+#define ASSIGNED_TUNNEL_ID 9
+#define RECEIVE_WINDOW_SIZE 10
+#define CHALLENGE 11
+#define CAUSE_CODE 12
+#define CHALLENGE_RESPONSE 13
+#define ASSIGNED_SESSION 14
+#define CALL_SERIAL_NUMBER 15
+#define MINIMUM_BPS 16
+#define MAXIMUM_BPS 17
+#define BEARER_TYPE 18
+#define FRAMING_TYPE 19
+#define CALLED_NUMBER 21
+#define CALLING_NUMBER 22
+#define SUB_ADDRESS 23
+#define TX_CONNECT_SPEED 24
+#define PHYSICAL_CHANNEL 25
+#define INITIAL_RECEIVED_LCP_CONFREQ 26
+#define LAST_SENT_LCP_CONFREQ 27
+#define LAST_RECEIVED_LCP_CONFREQ 28
+#define PROXY_AUTHEN_TYPE 29
+#define PROXY_AUTHEN_NAME 30
+#define PROXY_AUTHEN_CHALLENGE 31
+#define PROXY_AUTHEN_ID 32
+#define PROXY_AUTHEN_RESPONSE 33
+#define CALL_STATUS_AVPS 34
+#define ACCM 35
+#define RANDOM_VECTOR 36
+#define PRIVATE_GROUP_ID 37
+#define RX_CONNECT_SPEED 38
+#define SEQUENCING_REQUIRED 39
+#define PPP_DISCONNECT_CAUSE_CODE 46 /* RFC 3145 */
+
+#define NUM_AVP_TYPES 40
+static const value_string avp_type_vals[] = {
+ { CONTROL_MESSAGE, "Control Message" },
+ { RESULT_ERROR_CODE, "Result-Error Code" },
+ { PROTOCOL_VERSION, "Protocol Version" },
+ { FRAMING_CAPABILITIES, "Framing Capabilities" },
+ { BEARER_CAPABILITIES, "Bearer Capabilities" },
+ { TIE_BREAKER, "Tie Breaker" },
+ { FIRMWARE_REVISION, "Firmware Revision" },
+ { HOST_NAME, "Host Name" },
+ { VENDOR_NAME, "Vendor Name" },
+ { ASSIGNED_TUNNEL_ID, "Assigned Tunnel ID" },
+ { RECEIVE_WINDOW_SIZE, "Receive Window Size" },
+ { CHALLENGE, "Challenge" },
+ { CAUSE_CODE, "Cause Code" },
+ { CHALLENGE_RESPONSE, "Challenge Response" },
+ { ASSIGNED_SESSION, "Assigned Session" },
+ { CALL_SERIAL_NUMBER, "Call Serial Number" },
+ { MINIMUM_BPS, "Minimum BPS" },
+ { MAXIMUM_BPS, "Maximum BPS" },
+ { BEARER_TYPE, "Bearer Type" },
+ { FRAMING_TYPE, "Framing Type" },
+ { CALLED_NUMBER, "Called Number" },
+ { CALLING_NUMBER, "Calling Number" },
+ { SUB_ADDRESS, "Sub-Address" },
+ { TX_CONNECT_SPEED, "Connect Speed" },
+ { PHYSICAL_CHANNEL, "Physical Channel" },
+ { INITIAL_RECEIVED_LCP_CONFREQ, "Initial Received LCP CONFREQ" },
+ { LAST_SENT_LCP_CONFREQ, "Last Sent LCP CONFREQ" },
+ { LAST_RECEIVED_LCP_CONFREQ, "Last Received LCP CONFREQ" },
+ { PROXY_AUTHEN_TYPE, "Proxy Authen Type" },
+ { PROXY_AUTHEN_NAME, "Proxy Authen Name" },
+ { PROXY_AUTHEN_CHALLENGE, "Proxy Authen Challenge" },
+ { PROXY_AUTHEN_ID, "Proxy Authen ID" },
+ { PROXY_AUTHEN_RESPONSE, "Proxy Authen Response" },
+ { CALL_STATUS_AVPS, "Call status AVPs" },
+ { ACCM, "ACCM" },
+ { RANDOM_VECTOR, "Random Vector" },
+ { PRIVATE_GROUP_ID, "Private group ID" },
+ { RX_CONNECT_SPEED, "RxConnect Speed" },
+ { SEQUENCING_REQUIRED, "Sequencing Required" },
+ { PPP_DISCONNECT_CAUSE_CODE, "PPP Disconnect Cause Code" },
+ { 0, NULL }
+};
+
+/*
+ * These are SMI Network Management Private Enterprise Codes for
+ * organizations; see
+ *
+ * http://www.iana.org/assignments/enterprise-numbers
+ *
+ * for a list.
+ */
+#define VENDOR_IETF 0
+#define VENDOR_ACC 5
+#define VENDOR_CISCO 9
+#define VENDOR_SHIVA 166
+#define VENDOR_LIVINGSTON 307
+#define VENDOR_3COM 429
+#define VENDOR_ASCEND 529
+#define VENDOR_BAY 1584
+#define VENDOR_REDBACK 2352
+#define VENDOR_JUNIPER 2636
+#define VENDOR_COSINE 3085
+#define VENDOR_UNISPHERE 4874
+
+static const value_string avp_vendor_id_vals[] =
+{{VENDOR_IETF,"IETF"},
+{VENDOR_ACC,"ACC"},
+{VENDOR_CISCO,"Cisco"},
+{VENDOR_SHIVA,"Shiva"},
+{VENDOR_LIVINGSTON,"Livingston"},
+{VENDOR_3COM,"3Com"},
+{VENDOR_ASCEND,"Ascend"},
+{VENDOR_BAY,"Bay Networks"},
+{VENDOR_REDBACK,"Redback"},
+{VENDOR_JUNIPER,"Juniper Networks"},
+{VENDOR_COSINE,"CoSine Communications"},
+{VENDOR_UNISPHERE,"Unisphere Networks"},
+{0,NULL}};
+
+static gchar textbuffer[200];
+
+static dissector_handle_t ppp_hdlc_handle;
+static dissector_handle_t ppp_lcp_options_handle;
+
+static void
+dissect_l2tp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *l2tp_tree=NULL, *l2tp_avp_tree, *l2tp_lcp_avp_tree, *ctrl_tree;
+ proto_item *l2tp_item = NULL, *ti, *tf, *te;
+ int rhcode;
+ int index = 0;
+ int tmp_index;
+ guint16 length = 0; /* Length field */
+ guint16 tid; /* Tunnel ID */
+ guint16 cid; /* Call ID */
+ guint16 offset_size; /* Offset size */
+ guint16 ver_len_hidden;
+ guint16 avp_vendor_id;
+ guint16 avp_type;
+ guint16 msg_type;
+ guint16 avp_len;
+ guint16 result_code;
+ guint16 error_code;
+ guint32 bits;
+ guint16 firmware_rev;
+ guint16 control;
+ tvbuff_t *next_tvb;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL)) /* build output for closed L2tp frame displayed */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "L2TP");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ control = tvb_get_ntohs(tvb, 0);
+
+ if (L2TP_VERSION(control) != 2) {
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "L2TP Version %u", L2TP_VERSION(control) );
+ }
+ return;
+ }
+
+ rhcode= 10;
+
+ if (LENGTH_BIT(control)) { /* length field included ? */
+ index += 2; /* skip ahead */
+ length = tvb_get_ntohs(tvb, index);
+ }
+
+ /* collect the tunnel id & call id */
+ index += 2;
+ tid = tvb_get_ntohs(tvb, index);
+ index += 2;
+ cid = tvb_get_ntohs(tvb, index);
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ if (CONTROL_BIT(control)) {
+ /* CONTROL MESSAGE */
+ tmp_index = index;
+
+ if ((LENGTH_BIT(control))&&(length==12)) /* ZLB Message */
+ sprintf(textbuffer,"%s - ZLB (tunnel id=%d, session id=%d)",
+ control_msg , tid ,cid);
+ else
+ {
+ if (SEQUENCE_BIT(control)) {
+ tmp_index += 4;
+ }
+
+ tmp_index+=4;
+
+ avp_type = tvb_get_ntohs(tvb, (tmp_index+=2));
+
+ if (avp_type == CONTROL_MESSAGE)
+ {
+ /* We print message type */
+ msg_type = tvb_get_ntohs(tvb, (tmp_index+=2));
+ sprintf(textbuffer,"%s - %s (tunnel id=%d, session id=%d)",
+ control_msg ,
+ ((NUM_CONTROL_CALL_TYPES + 1 ) > msg_type) ?
+ calltype_short_str[msg_type] : "Unknown",
+ tid ,cid);
+ }
+ else
+ {
+ /*
+ * This is not a control message.
+ * We never pass here except in case of bad l2tp packet!
+ */
+ sprintf(textbuffer,"%s (tunnel id=%d, session id=%d)",
+ control_msg , tid ,cid);
+
+ }
+ }
+ }
+ else {
+ /* DATA Message */
+ sprintf(textbuffer,"%s (tunnel id=%d, session id=%d)",
+ data_msg, tid ,cid);
+ }
+ col_add_fstr(pinfo->cinfo,COL_INFO,textbuffer);
+ }
+
+ if (LENGTH_BIT(control)) {
+ /*
+ * Set the length of this tvbuff to be no longer than the length
+ * in the header.
+ *
+ * XXX - complain if that length is longer than the length of
+ * the tvbuff? Have "set_actual_length()" return a Boolean
+ * and have its callers check the result?
+ */
+ set_actual_length(tvb, length);
+ }
+
+ if (tree) {
+ l2tp_item = proto_tree_add_item(tree,proto_l2tp, tvb, 0, -1, FALSE);
+ l2tp_tree = proto_item_add_subtree(l2tp_item, ett_l2tp);
+
+ ti = proto_tree_add_text(l2tp_tree, tvb, 0, 2,
+ "Packet Type: %s Tunnel Id=%d Session Id=%d",
+ (CONTROL_BIT(control) ? control_msg : data_msg), tid, cid);
+
+ ctrl_tree = proto_item_add_subtree(ti, ett_l2tp_ctrl);
+ proto_tree_add_uint(ctrl_tree, hf_l2tp_type, tvb, 0, 2, control);
+ proto_tree_add_boolean(ctrl_tree, hf_l2tp_length_bit, tvb, 0, 2, control);
+ proto_tree_add_boolean(ctrl_tree, hf_l2tp_seq_bit, tvb, 0, 2, control);
+ proto_tree_add_boolean(ctrl_tree, hf_l2tp_offset_bit, tvb, 0, 2, control);
+ proto_tree_add_boolean(ctrl_tree, hf_l2tp_priority, tvb, 0, 2, control);
+ proto_tree_add_uint(ctrl_tree, hf_l2tp_version, tvb, 0, 2, control);
+ }
+ index = 2;
+ if (LENGTH_BIT(control)) {
+ if (tree) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_length, tvb, index, 2, FALSE);
+ }
+ index += 2;
+ }
+
+ if (tree) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_tunnel, tvb, index, 2, FALSE);
+ }
+ index += 2;
+ if (tree) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_session, tvb, index, 2, FALSE);
+ }
+ index += 2;
+
+ if (SEQUENCE_BIT(control)) {
+ if (tree) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_Ns, tvb, index, 2, FALSE);
+ }
+ index += 2;
+ if (tree) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_Nr, tvb, index, 2, FALSE);
+ }
+ index += 2;
+ }
+ if (OFFSET_BIT(control)) {
+ offset_size = tvb_get_ntohs(tvb, index);
+ if (tree) {
+ proto_tree_add_uint(l2tp_tree, hf_l2tp_offset, tvb, index, 2,
+ offset_size);
+ }
+ index += 2;
+ if (offset_size != 0) {
+ if (tree) {
+ proto_tree_add_text(l2tp_tree, tvb, index, offset_size, "Offset Padding");
+ }
+ index += offset_size;
+ }
+ }
+ if (tree && (LENGTH_BIT(control))&&(length==12)) {
+ proto_tree_add_text(l2tp_tree, tvb, 0, 0, "Zero Length Bit message");
+ }
+
+ if (!CONTROL_BIT(control)) { /* Data Messages so we are done */
+ if (tree)
+ proto_item_set_len(l2tp_item, index);
+ /* If we have data, signified by having a length bit, dissect it */
+ if (tvb_offset_exists(tvb, index)) {
+ next_tvb = tvb_new_subset(tvb, index, -1, -1);
+ call_dissector(ppp_hdlc_handle, next_tvb, pinfo, tree);
+ }
+ return;
+ }
+
+ if (tree) {
+ if (!LENGTH_BIT(control)) {
+ return;
+ }
+ while (index < length ) { /* Process AVP's */
+ ver_len_hidden = tvb_get_ntohs(tvb, index);
+ avp_len = AVP_LENGTH(ver_len_hidden);
+ avp_vendor_id = tvb_get_ntohs(tvb, index + 2);
+ avp_type = tvb_get_ntohs(tvb, index + 4);
+
+ if (avp_vendor_id == VENDOR_IETF) {
+ tf = proto_tree_add_text(l2tp_tree, tvb, index,
+ avp_len, "%s AVP",
+ val_to_str(avp_type, avp_type_vals, "Unknown (%u)"));
+ } else { /* Vendor-Specific AVP */
+ tf = proto_tree_add_text(l2tp_tree, tvb, index,
+ avp_len, "Vendor %s AVP",
+ val_to_str(avp_vendor_id, avp_vendor_id_vals, "Unknown (%u)"));
+ }
+
+ l2tp_avp_tree = proto_item_add_subtree(tf, ett_l2tp_avp);
+
+ proto_tree_add_boolean_format(l2tp_avp_tree,hf_l2tp_avp_mandatory, tvb, index, 1,
+ rhcode, "Mandatory: %s",
+ (MANDATORY_BIT(ver_len_hidden)) ? "True" : "False" );
+ proto_tree_add_boolean_format(l2tp_avp_tree,hf_l2tp_avp_hidden, tvb, index, 1,
+ rhcode, "Hidden: %s",
+ (HIDDEN_BIT(ver_len_hidden)) ? "True" : "False" );
+ proto_tree_add_uint_format(l2tp_avp_tree,hf_l2tp_avp_length, tvb, index, 2,
+ rhcode, "Length: %u", avp_len);
+ if (HIDDEN_BIT(ver_len_hidden)) { /* don't try do display hidden */
+ index += avp_len;
+ continue;
+ }
+
+ if (avp_len < 6) {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 0,
+ "AVP length must be >= 6");
+ return;
+ }
+ index += 2;
+ avp_len -= 2;
+
+ proto_tree_add_item(l2tp_avp_tree, hf_l2tp_avp_vendor_id,
+ tvb, index, 2, FALSE);
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_vendor_id != VENDOR_IETF) {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Type: %u", avp_type);
+ index += 2;
+ avp_len -= 2;
+
+ /* For the time being, we don't decode any Vendor-
+ specific AVP. */
+ proto_tree_add_text(l2tp_avp_tree, tvb, index,
+ avp_len, "Vendor-Specific AVP");
+
+ index += avp_len;
+ continue;
+ }
+
+ proto_tree_add_uint(l2tp_avp_tree, hf_l2tp_avp_type,
+ tvb, index, 2, avp_type);
+ index += 2;
+ avp_len -= 2;
+
+ switch (avp_type) {
+
+ case CONTROL_MESSAGE:
+ msg_type = tvb_get_ntohs(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree,tvb, index, 2,
+ "Control Message Type: (%u) %s", msg_type,
+ ((NUM_CONTROL_CALL_TYPES + 1 ) > msg_type) ?
+ calltypestr[msg_type] : "Unknown");
+ break;
+
+ case RESULT_ERROR_CODE:
+ if (avp_len < 2)
+ break;
+ result_code = tvb_get_ntohs(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Result code: %u", result_code);
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len < 2)
+ break;
+ error_code = tvb_get_ntohs(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Error code: %u", error_code);
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Error Message: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case PROTOCOL_VERSION:
+ if (avp_len < 1)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 1,
+ "Version: %u", tvb_get_guint8(tvb, index));
+ index += 1;
+ avp_len -= 1;
+
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 1,
+ "Revision: %u", tvb_get_guint8(tvb, index));
+ break;
+
+ case FRAMING_CAPABILITIES:
+ bits = tvb_get_ntohl(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Async Framing Supported: %s",
+ (FRAMING_ASYNC(bits)) ? "True" : "False");
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Sync Framing Supported: %s",
+ (FRAMING_SYNC(bits)) ? "True" : "False");
+ break;
+
+ case BEARER_CAPABILITIES:
+ bits = tvb_get_ntohl(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Analog Access Supported: %s",
+ (BEARER_ANALOG(bits)) ? "True" : "False");
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Digital Access Supported: %s",
+ (BEARER_DIGITAL(bits)) ? "True" : "False");
+ break;
+
+ case TIE_BREAKER:
+ proto_tree_add_item(l2tp_avp_tree, hf_l2tp_tie_breaker, tvb, index, 8, FALSE);
+ break;
+
+ case FIRMWARE_REVISION:
+ firmware_rev = tvb_get_ntohs(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Firmware Revision: %d 0x%x", firmware_rev,firmware_rev );
+ break;
+
+ case HOST_NAME:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Host Name: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case VENDOR_NAME:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Vendor Name: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case ASSIGNED_TUNNEL_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Tunnel ID: %u", tvb_get_ntohs(tvb, index));
+ break;
+
+ case RECEIVE_WINDOW_SIZE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Receive Window Size: %u",
+ tvb_get_ntohs(tvb, index));
+ break;
+
+ case CHALLENGE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "CHAP Challenge: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+
+ case CAUSE_CODE:
+ /*
+ * XXX - export stuff from the Q.931 dissector
+ * to dissect the cause code and cause message,
+ * and use it.
+ */
+ if (avp_len < 2)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Cause Code: %u",
+ tvb_get_ntohs(tvb, index));
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len < 1)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 1,
+ "Cause Msg: %u",
+ tvb_get_guint8(tvb, index));
+ index += 1;
+ avp_len -= 1;
+
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Advisory Msg: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case CHALLENGE_RESPONSE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 16,
+ "CHAP Challenge Response: %s",
+ tvb_bytes_to_str(tvb, index, 16));
+ break;
+
+ case ASSIGNED_SESSION:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Assigned Session: %u",
+ tvb_get_ntohs(tvb, index));
+ break;
+
+ case CALL_SERIAL_NUMBER:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Call Serial Number: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case MINIMUM_BPS:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Minimum BPS: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case MAXIMUM_BPS:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Maximum BPS: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case BEARER_TYPE:
+ bits = tvb_get_ntohl(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Analog Bearer Type: %s",
+ (BEARER_ANALOG(bits)) ? "True" : "False");
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Digital Bearer Type: %s",
+ (BEARER_DIGITAL(bits)) ? "True" : "False");
+ break;
+
+ case FRAMING_TYPE:
+ bits = tvb_get_ntohl(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Async Framing Type: %s",
+ (FRAMING_ASYNC(bits)) ? "True" : "False");
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Sync Framing Type: %s",
+ (FRAMING_SYNC(bits)) ? "True" : "False");
+ break;
+
+ case CALLED_NUMBER:
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Called Number: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case CALLING_NUMBER:
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Calling Number: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case SUB_ADDRESS:
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Sub-Address: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case TX_CONNECT_SPEED:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Connect Speed: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case PHYSICAL_CHANNEL:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Physical Channel: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case INITIAL_RECEIVED_LCP_CONFREQ:
+ te = proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Initial Received LCP CONFREQ: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ l2tp_lcp_avp_tree = proto_item_add_subtree(te, ett_l2tp_lcp);
+ next_tvb = tvb_new_subset(tvb, index, avp_len, avp_len);
+ call_dissector(ppp_lcp_options_handle, next_tvb, pinfo, l2tp_lcp_avp_tree );
+ break;
+
+ case LAST_SENT_LCP_CONFREQ:
+ te = proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Last Sent LCP CONFREQ: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ l2tp_lcp_avp_tree = proto_item_add_subtree(te, ett_l2tp_lcp);
+ next_tvb = tvb_new_subset(tvb, index, avp_len, avp_len);
+ call_dissector(ppp_lcp_options_handle, next_tvb, pinfo, l2tp_lcp_avp_tree );
+ break;
+
+ case LAST_RECEIVED_LCP_CONFREQ:
+ te = proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Last Received LCP CONFREQ: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ l2tp_lcp_avp_tree = proto_item_add_subtree(te, ett_l2tp_lcp);
+ next_tvb = tvb_new_subset(tvb, index, avp_len, avp_len);
+ call_dissector(ppp_lcp_options_handle, next_tvb, pinfo, l2tp_lcp_avp_tree );
+ break;
+
+ case PROXY_AUTHEN_TYPE:
+ msg_type = tvb_get_ntohs(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Proxy Authen Type: %s",
+ val_to_str(msg_type, authen_type_vals, "Unknown (%u)"));
+ break;
+
+ case PROXY_AUTHEN_NAME:
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Proxy Authen Name: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ case PROXY_AUTHEN_CHALLENGE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Proxy Authen Challenge: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+
+ case PROXY_AUTHEN_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index + 1, 1,
+ "Proxy Authen ID: %u",
+ tvb_get_guint8(tvb, index + 1));
+ break;
+
+ case PROXY_AUTHEN_RESPONSE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Proxy Authen Response: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+
+ case CALL_STATUS_AVPS:
+ if (avp_len < 2)
+ break;
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "CRC Errors: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Framing Errors: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Hardware Overruns: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Buffer Overruns: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Time-out Errors: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Alignment Errors: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+ break;
+
+ case ACCM:
+ if (avp_len < 2)
+ break;
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Send ACCM: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+
+ if (avp_len < 4)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Receive ACCM: %u", tvb_get_ntohl(tvb, index));
+ index += 4;
+ avp_len -= 4;
+ break;
+
+ case RANDOM_VECTOR:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Random Vector: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+
+ case PRIVATE_GROUP_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Private Group ID: %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+
+ case RX_CONNECT_SPEED:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Rx Connect Speed: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case PPP_DISCONNECT_CAUSE_CODE:
+ if (avp_len < 2)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Disconnect Code: %u",
+ tvb_get_ntohs(tvb, index));
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len < 2)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Control Protocol Number: %u",
+ tvb_get_ntohs(tvb, index));
+ index += 2;
+ avp_len -= 2;
+
+ if (avp_len < 1)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 1,
+ "Direction: %s",
+ val_to_str(tvb_get_guint8(tvb, index),
+ cause_code_direction_vals,
+ "Reserved (%u)"));
+ index += 1;
+ avp_len -= 1;
+
+ if (avp_len == 0)
+ break;
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Message: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+
+ default:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Unknown AVP");
+ break;
+ }
+
+ /* printf("Avp Decode avp_len= %d index= %d length= %d %x\n ",avp_len,
+ index,length,length); */
+
+ index += avp_len;
+ }
+
+ }
+}
+
+/* registration with the filtering engine */
+void
+proto_register_l2tp(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_l2tp_type,
+ { "Type", "l2tp.type", FT_UINT16, BASE_DEC, VALS(l2tp_type_vals), 0x8000,
+ "Type bit", HFILL }},
+
+ { &hf_l2tp_length_bit,
+ { "Length Bit", "l2tp.length_bit", FT_BOOLEAN, 16, TFS(&l2tp_length_bit_truth), 0x4000,
+ "Length bit", HFILL }},
+
+ { &hf_l2tp_seq_bit,
+ { "Sequence Bit", "l2tp.seq_bit", FT_BOOLEAN, 16, TFS(&l2tp_seq_bit_truth), 0x0800,
+ "Sequence bit", HFILL }},
+
+ { &hf_l2tp_offset_bit,
+ { "Offset bit", "l2tp.offset_bit", FT_BOOLEAN, 16, TFS(&l2tp_offset_bit_truth), 0x0200,
+ "Offset bit", HFILL }},
+
+ { &hf_l2tp_priority,
+ { "Priority", "l2tp.priority", FT_BOOLEAN, 16, TFS(&l2tp_priority_truth), 0x0100,
+ "Priority bit", HFILL }},
+
+ { &hf_l2tp_version,
+ { "Version", "l2tp.version", FT_UINT16, BASE_DEC, NULL, 0x000f,
+ "Version", HFILL }},
+
+ { &hf_l2tp_length,
+ { "Length","l2tp.length", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_l2tp_tunnel,
+ { "Tunnel ID","l2tp.tunnel", FT_UINT16, BASE_DEC, NULL, 0x0, /* Probably should be FT_BYTES */
+ "Tunnel ID", HFILL }},
+
+ { &hf_l2tp_session,
+ { "Session ID","l2tp.session", FT_UINT16, BASE_DEC, NULL, 0x0, /* Probably should be FT_BYTES */
+ "Session ID", HFILL }},
+
+ { &hf_l2tp_Ns,
+ { "Ns","l2tp.Ns", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_l2tp_Nr,
+ { "Nr","l2tp.Nr", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_l2tp_offset,
+ { "Offset","l2tp.offset", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Number of octest past the L2TP header at which the"
+ "payload data starts.", HFILL }},
+
+ { &hf_l2tp_avp_mandatory,
+ { "Mandatory", "l2tp.avp.mandatory", FT_BOOLEAN, BASE_NONE, NULL, 0,
+ "Mandatory AVP", HFILL }},
+
+ { &hf_l2tp_avp_hidden,
+ { "Hidden", "l2tp.avp.hidden", FT_BOOLEAN, BASE_NONE, NULL, 0,
+ "Hidden AVP", HFILL }},
+
+ { &hf_l2tp_avp_length,
+ { "Length", "l2tp.avp.length", FT_UINT16, BASE_DEC, NULL, 0,
+ "AVP Length", HFILL }},
+
+ { &hf_l2tp_avp_vendor_id,
+ { "Vendor ID", "l2tp.avp.vendor_id", FT_UINT16, BASE_DEC, VALS(avp_vendor_id_vals), 0,
+ "AVP Vendor ID", HFILL }},
+
+ { &hf_l2tp_avp_type,
+ { "Type", "l2tp.avp.type", FT_UINT16, BASE_DEC, VALS(avp_type_vals), 0,
+ "AVP Type", HFILL }},
+
+ { &hf_l2tp_tie_breaker,
+ { "Tie Breaker", "l2tp.tie_breaker", FT_UINT64, BASE_HEX, NULL, 0,
+ "Tie Breaker", HFILL }},
+
+ };
+
+ static gint *ett[] = {
+ &ett_l2tp,
+ &ett_l2tp_ctrl,
+ &ett_l2tp_avp,
+ &ett_l2tp_lcp,
+ };
+
+ proto_l2tp = proto_register_protocol(
+ "Layer 2 Tunneling Protocol", "L2TP", "l2tp");
+ proto_register_field_array(proto_l2tp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_l2tp(void)
+{
+ dissector_handle_t l2tp_handle;
+
+ l2tp_handle = create_dissector_handle(dissect_l2tp, proto_l2tp);
+ dissector_add("udp.port", UDP_PORT_L2TP, l2tp_handle);
+
+ /*
+ * Get a handle for the PPP-in-HDLC-like-framing dissector.
+ */
+ ppp_hdlc_handle = find_dissector("ppp_hdlc");
+ ppp_lcp_options_handle = find_dissector("ppp_lcp_options");
+
+}