summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2005-01-09 21:42:39 +0000
committerGuy Harris <guy@alum.mit.edu>2005-01-09 21:42:39 +0000
commit7b49d981aeea6e2ffee0c90f5454ffd19ef9d91f (patch)
tree30259e4f159f3b4dfe77b0e19e39f08eb16ae87a
parentd8c21fe77e765c210ae721708d9d5d8a3173dbad (diff)
downloadwireshark-7b49d981aeea6e2ffee0c90f5454ffd19ef9d91f.tar.gz
From Deepak Jain: L2TP v3 (draft 15) support.
Add VENDOR_IETF to <epan/sminmpec.h>, and add an entry for it to sminmpec_values[], so that the L2TP dissector can use them rather than defining its own copy of the private enterprise number values and table - and make it do so. svn path=/trunk/; revision=12999
-rw-r--r--AUTHORS4
-rw-r--r--epan/dissectors/packet-l2tp.c1831
-rw-r--r--epan/sminmpec.c8
-rw-r--r--epan/sminmpec.h3
4 files changed, 1208 insertions, 638 deletions
diff --git a/AUTHORS b/AUTHORS
index d904fa1da8..d4922f70d4 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2273,6 +2273,10 @@ Mike Duigou <bondolo [AT] jxta.org> {
Dissector for JXTA protocol
}
+Deepak Jain <jain1971 [AT] yahoo.com> {
+ L2TP v3 support
+}
+
And assorted fixes and enhancements by the people listed above
and by:
diff --git a/epan/dissectors/packet-l2tp.c b/epan/dissectors/packet-l2tp.c
index 0e82ecf5eb..4f3c93b5dc 100644
--- a/epan/dissectors/packet-l2tp.c
+++ b/epan/dissectors/packet-l2tp.c
@@ -47,6 +47,9 @@ 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;
+static int hf_l2tp_sid = -1;
+static int hf_l2tp_ccid = -1;
+static int hf_l2tp_cisco_avp_type = -1;
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -59,6 +62,8 @@ static int hf_l2tp_tie_breaker = -1;
#include <glib.h>
#include <epan/packet.h>
#include <epan/addr_resolv.h>
+#include <epan/ipproto.h>
+#include <epan/sminmpec.h>
#define UDP_PORT_L2TP 1701
@@ -76,6 +81,8 @@ static int hf_l2tp_tie_breaker = -1;
#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 */
+#define CIRCUIT_STATUS_BIT(msg_info) (msg_info & 0x0001) /* Circuit Status */
+#define CIRCUIT_TYPE_BIT(msg_info) (msg_info & 0x0001) /* Circuit Condition */
static gint ett_l2tp = -1;
static gint ett_l2tp_ctrl = -1;
@@ -97,8 +104,7 @@ static gint ett_l2tp_lcp = -1;
#define AVP_Reserved1 13
#define AVP_CDN 14
-
-#define NUM_CONTROL_CALL_TYPES 16
+#define NUM_CONTROL_CALL_TYPES 20
static const char *calltypestr[NUM_CONTROL_CALL_TYPES+1] = {
"Unknown Call Type ",
"Start_Control_Request ",
@@ -117,6 +123,10 @@ static const char *calltypestr[NUM_CONTROL_CALL_TYPES+1] = {
"Call_Disconnect_Notification",
"WAN_Error_Notify ",
"Set_Link_Info ",
+ "Unknown Call Type ",
+ "Unknown Call Type ",
+ "Unknown Call Type ",
+ "Explicit Acknowledgement ",
};
static const char *calltype_short_str[NUM_CONTROL_CALL_TYPES+1] = {
@@ -137,6 +147,10 @@ static const char *calltype_short_str[NUM_CONTROL_CALL_TYPES+1] = {
"CDN ",
"WEN ",
"SLI ",
+ "Unknown ",
+ "Unknown ",
+ "Unknown ",
+ "ACK ",
};
@@ -177,6 +191,59 @@ static const value_string authen_type_vals[] = {
{ 0, NULL }
};
+static const value_string data_sequencing_vals[] = {
+ { 0, "No incoming data packets require sequencing" },
+ { 1, "Only non-IP data packets require sequencing" },
+ { 2, "All incoming data packets require sequencing" },
+ { 0, NULL }
+};
+
+static const value_string l2_sublayer_vals[] = {
+ { 0, "No L2-Specific Sublayer Present" },
+ { 1, "Default L2-Specific is used" },
+ { 0, NULL }
+};
+
+static const value_string result_code_stopccn_vals[] = {
+ { 0, "Reserved", },
+ { 1, "General request to clear control connection", },
+ { 2, "General error, Error Code indicates the problem", },
+ { 3, "Control connection already exists", },
+ { 4, "Requester is not authorized to establish a control connection", },
+ { 5, "The protocol version of the requester is not supported", },
+ { 6, "Requester is being shut down", },
+ { 7, "Finite state machine error or timeout", },
+ { 0, NULL }
+};
+
+static const value_string result_code_cdn_vals[] = {
+ { 0, "Reserved", },
+ { 1, "Session disconnected due to loss of carrier or circuit disconnect", },
+ { 2, "Session disconnected for the reason indicated in Error Code", },
+ { 3, "Session disconnected for administrative reasons", },
+ { 4, "Appropriate facilities unavailable (temporary condition)", },
+ { 5, "Appropriate facilities unavailable (permanent condition)", },
+ { 13, "Session not established due to losing tie breaker", },
+ { 14, "Session not established due to unsupported PW type", },
+ { 15, "Session not established, sequencing required without valid L2-Specific Sublayer", },
+ { 16, "Finite state machine error or timeout", },
+ { 0, NULL }
+};
+
+static const value_string error_code_vals[] = {
+ { 0, "No General Error", },
+ { 1, "No control connection exists yet for this pair of LCCEs", },
+ { 2, "Length is wrong", },
+ { 3, "One of the field values was out of range", },
+ { 4, "Insufficient resources to handle this operation now", },
+ { 5, "Invalid Session ID", },
+ { 6, "A generic vendor-specific error occurred", },
+ { 7, "Try another", },
+ { 8, "Receipt of an unknown AVP with the M bit set", },
+ { 9, "Try another directed", },
+ { 0, NULL }
+};
+
#define CONTROL_MESSAGE 0
#define RESULT_ERROR_CODE 1
#define PROTOCOL_VERSION 2
@@ -217,8 +284,25 @@ static const value_string authen_type_vals[] = {
#define RX_CONNECT_SPEED 38
#define SEQUENCING_REQUIRED 39
#define PPP_DISCONNECT_CAUSE_CODE 46 /* RFC 3145 */
-
-#define NUM_AVP_TYPES 40
+#define EXTENDED_VENDOR_ID 58
+#define MESSAGE_DIGEST 59
+#define ROUTER_ID 60
+#define ASSIGNED_CONTROL_CONN_ID 61
+#define PW_CAPABILITY_LIST 62
+#define LOCAL_SESSION_ID 63
+#define REMOTE_SESSION_ID 64
+#define ASSIGNED_COOKIE 65
+#define REMOTE_END_ID 66
+#define PW_TYPE 68
+#define L2_SPECIFIC_SUBLAYER 69
+#define DATA_SEQUENCING 70
+#define CIRCUIT_STATUS 71
+#define PREFERRED_LANGUAGE 72
+#define CTL_MSG_AUTH_NONCE 73
+#define TX_CONNECT_SPEED_V3 74
+#define RX_CONNECT_SPEED_V3 75
+
+#define NUM_AVP_TYPES 76
static const value_string avp_type_vals[] = {
{ CONTROL_MESSAGE, "Control Message" },
{ RESULT_ERROR_CODE, "Result-Error Code" },
@@ -260,716 +344,1181 @@ static const value_string avp_type_vals[] = {
{ RX_CONNECT_SPEED, "RxConnect Speed" },
{ SEQUENCING_REQUIRED, "Sequencing Required" },
{ PPP_DISCONNECT_CAUSE_CODE, "PPP Disconnect Cause Code" },
+ { EXTENDED_VENDOR_ID, "Extended Vendor ID" },
+ { MESSAGE_DIGEST, "Message Digest" },
+ { ROUTER_ID, "Router ID" },
+ { ASSIGNED_CONTROL_CONN_ID, "Assigned Control Connection ID" },
+ { PW_CAPABILITY_LIST, "Pseudowire Capability List" },
+ { LOCAL_SESSION_ID, "Local Session ID" },
+ { REMOTE_SESSION_ID, "Remote Session ID" },
+ { ASSIGNED_COOKIE, "Assigned Cookie" },
+ { REMOTE_END_ID, "Remote End ID" },
+ { PW_TYPE, "Pseudowire Type" },
+ { L2_SPECIFIC_SUBLAYER, "Layer2 Specific Sublayer" },
+ { DATA_SEQUENCING, "Data Sequencing" },
+ { CIRCUIT_STATUS, "Circuit Status" },
+ { PREFERRED_LANGUAGE, "Preferred Language" },
+ { CTL_MSG_AUTH_NONCE, "Control Message Authentication Nonce" },
+ { TX_CONNECT_SPEED_V3, "Tx Connect Speed Version 3" },
+ { RX_CONNECT_SPEED_V3, "Rx Connect Speed Version 3" },
{ 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}};
+#define CISCO_ASSIGNED_CONNECTION_ID 1
+#define CISCO_PW_CAPABILITY_LIST 2
+#define CISCO_UNKNOWN_10 10
+
+static const value_string cisco_avp_type_vals[] = {
+ { CISCO_ASSIGNED_CONNECTION_ID, "Assigned Connection ID" },
+ { CISCO_PW_CAPABILITY_LIST, "Pseudowire Capabilities List" },
+ { CISCO_UNKNOWN_10, "Cisco Unknown 10" },
+ { 0, NULL }
+};
+
+#define NUM_PW_TYPES 0x1A
+static const value_string pw_types_vals[NUM_PW_TYPES+1] = {
+ { 0, "End of PW Capability List" },
+ { 1, "Frame Relay DLCI (Martini Mode)" },
+ { 2, "ATM AAL5 SDU VCC transport" },
+ { 3, "ATM transparent cell transport" },
+ { 4, "Ethernet Tagged Mode" },
+ { 5, "Ethernet" },
+ { 6, "HDLC" },
+ { 7, "PPP" },
+ { 8, "SONET/SDH Circuit Emulation Service Over MPLS (CEM) [Note1]" },
+ { 9, "ATM n-to-one VCC cell transport" },
+ { 10, "ATM n-to-one VPC cell transport" },
+ { 11, "IP Layer2 Transport" },
+ { 12, "ATM one-to-one VCC Cell Mode" },
+ { 13, "ATM one-to-one VPC Cell Mode" },
+ { 14, "ATM AAL5 PDU VCC transport" },
+ { 15, "Frame-Relay Port mode" },
+ { 16, "SONET/SDH Circuit Emulation over Packet (CEP)" },
+ { 17, "Structure-agnostic E1 over Packet (SAToP)" },
+ { 18, "Structure-agnostic T1 (DS1) over Packet (SAToP)" },
+ { 19, "Structure-agnostic E3 over Packet (SAToP)" },
+ { 20, "Structure-agnostic T3 (DS3) over Packet (SAToP)" },
+ { 21, "CESoPSN basic mode" },
+ { 22, "TDMoIP basic mode" },
+ { 23, "CESoPSN TDM with CAS" },
+ { 24, "TDMoIP TDM with CAS" },
+ { 25, "Frame Relay DLCI" },
+ { 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)
+static void process_control_avps(tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *l2tp_tree,
+ int index,
+ int length)
{
- 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);
+ proto_tree *l2tp_lcp_avp_tree, *l2tp_avp_tree;
+ proto_item *tf, *te;
+
+ int msg_type;
+ gboolean isStopCcn = FALSE;
+ int avp_type;
+ guint32 avp_vendor_id;
+ guint16 avp_len;
+ guint16 ver_len_hidden;
+ int rhcode = 10;
+ tvbuff_t *next_tvb;
+ guint16 result_code;
+ guint16 error_code;
+ guint32 bits;
+ guint16 firmware_rev;
+
+ if (l2tp_tree) {
+ 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:%s AVP",
+ val_to_str(avp_vendor_id, sminmpec_values, "Unknown (%u)"),
+ val_to_str(avp_type, cisco_avp_type_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;
- if (check_col(pinfo->cinfo, COL_INFO)) {
- if (CONTROL_BIT(control)) {
- /* CONTROL MESSAGE */
- tmp_index = index;
+ /* Special Case for handling Extended Vendor Id */
+ if (avp_type == EXTENDED_VENDOR_ID) {
+ index += 2;
+ avp_len -= 2;
+ proto_tree_add_item(l2tp_avp_tree, hf_l2tp_avp_vendor_id,
+ tvb, index, 4, FALSE);
+
+ avp_vendor_id = tvb_get_ntohl(tvb, index);
+
+ index += 4;
+ avp_len -= 4;
+ continue;
+ }
+ else {
+ 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_uint(l2tp_avp_tree, hf_l2tp_cisco_avp_type,
+ tvb, index, 2, avp_type);
+ /*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. */
+ switch (avp_type) {
+ case CISCO_ASSIGNED_CONNECTION_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Assigned Control Connection ID: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+
+ case CISCO_PW_CAPABILITY_LIST:
+ while (avp_len > 0) {
+ int pw_type = tvb_get_ntohs(tvb, index);
+
+ proto_tree_add_text(l2tp_avp_tree, tvb, index,
+ 2, "\t PW Type: (%u) %s",
+ pw_type,
+ (pw_type < NUM_PW_TYPES) ?
+ pw_types_vals[pw_type].strptr : "Unknown");
+ index += 2;
+ avp_len -= 2;
+ }
+ break;
+
+ default:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index,
+ avp_len, "Vendor-Specific AVP");
+ break;
+ }
+ 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;
- 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;
- }
+ switch (avp_type) {
- tmp_index+=4;
+ 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");
- avp_type = tvb_get_ntohs(tvb, (tmp_index+=2));
+ if (msg_type == AVP_StopCCN) {
+ isStopCcn = TRUE;
+ }
+ break;
- 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);
+ case RESULT_ERROR_CODE:
+ if (avp_len < 2)
+ break;
+ result_code = tvb_get_ntohs(tvb, index);
+ if (isStopCcn) {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Result code: %s",
+ val_to_str(result_code, result_code_stopccn_vals, "Unknown (%u)"));
+ }
+ else {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Result code: %s",
+ val_to_str(result_code, result_code_cdn_vals, "Unknown (%u)"));
+ }
+ 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: %s",
+ val_to_str(error_code, error_code_vals, "Unknown (%u)"));
+ 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;
- }
- }
- }
- else {
- /* DATA Message */
- sprintf(textbuffer,"%s (tunnel id=%d, session id=%d)",
- data_msg, tid ,cid);
- }
- col_add_fstr(pinfo->cinfo,COL_INFO,textbuffer);
- }
+ 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;
- 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);
- }
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 1,
+ "Revision: %u", tvb_get_guint8(tvb, index));
+ break;
- 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");
- }
+ 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;
- 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;
- }
+ 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;
- 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)"));
- }
+ case TIE_BREAKER:
+ proto_tree_add_item(l2tp_avp_tree, hf_l2tp_tie_breaker, tvb, index, 8, FALSE);
+ break;
- 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;
- }
+ 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;
- 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;
+ 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;
- proto_tree_add_item(l2tp_avp_tree, hf_l2tp_avp_vendor_id,
- tvb, index, 2, FALSE);
- index += 2;
- avp_len -= 2;
+ 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;
- 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;
+ case ASSIGNED_TUNNEL_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Tunnel ID: %u", tvb_get_ntohs(tvb, index));
+ break;
- /* 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");
+ case RECEIVE_WINDOW_SIZE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Receive Window Size: %u",
+ tvb_get_ntohs(tvb, index));
+ break;
- index += avp_len;
- continue;
- }
+ 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;
- proto_tree_add_uint(l2tp_avp_tree, hf_l2tp_avp_type,
- tvb, index, 2, avp_type);
- index += 2;
- avp_len -= 2;
+ 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;
- switch (avp_type) {
+ 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 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 ASSIGNED_SESSION:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Assigned Session: %u",
+ tvb_get_ntohs(tvb, index));
+ break;
- case RESULT_ERROR_CODE:
- if (avp_len < 2)
+ case CALL_SERIAL_NUMBER:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Call Serial Number: %u",
+ tvb_get_ntohl(tvb, index));
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)
+ case MINIMUM_BPS:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Minimum BPS: %u",
+ tvb_get_ntohl(tvb, index));
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)
+ case MAXIMUM_BPS:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Maximum BPS: %u",
+ tvb_get_ntohl(tvb, index));
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)
+ 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;
- 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)
+
+ 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;
- 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)
+ 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;
- 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)
+ 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;
- 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)
+
+ 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;
- 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)
+ case TX_CONNECT_SPEED:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Connect Speed: %u",
+ tvb_get_ntohl(tvb, index));
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)
+ case PHYSICAL_CHANNEL:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Physical Channel: %u",
+ tvb_get_ntohl(tvb, index));
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);
+
+ 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;
+ 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);
+ 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;
+ 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);
+ 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;
+ 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_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)
+ 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;
- 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)
+
+ 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;
- index += 2;
- avp_len -= 2;
- if (avp_len < 4)
+ 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;
- 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)
+ 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;
- 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)
+ 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;
- 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)
+ 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;
- 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)
+ 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;
- 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)
+ 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;
- 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)
+
+ case RX_CONNECT_SPEED:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Rx Connect Speed: %u",
+ tvb_get_ntohl(tvb, index));
break;
- index += 2;
- avp_len -= 2;
- if (avp_len < 4)
+ 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;
- 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)
+ case MESSAGE_DIGEST:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Message Digest : %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
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)
+ case ROUTER_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Router ID: %u",
+ tvb_get_ntohl(tvb, index));
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)
+ case ASSIGNED_CONTROL_CONN_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Assigned Control Connection ID: %u",
+ tvb_get_ntohl(tvb, index));
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)
+ case PW_CAPABILITY_LIST:
+ while (avp_len > 0) {
+ int pw_type = tvb_get_ntohs(tvb, index);
+
+ proto_tree_add_text(l2tp_avp_tree, tvb, index,
+ 2, "\t PW Type: (%u) %s",
+ pw_type,
+ (pw_type < NUM_PW_TYPES) ?
+ pw_types_vals[pw_type].strptr : "Unknown");
+ index += 2;
+ avp_len -= 2;
+ }
+ break;
+ case LOCAL_SESSION_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Local Session ID: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+ case REMOTE_SESSION_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 4,
+ "Remote Session ID: %u",
+ tvb_get_ntohl(tvb, index));
+ break;
+ case ASSIGNED_COOKIE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Assigned Cookie : %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+ case REMOTE_END_ID:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Remote End ID : %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
+ break;
+ case PW_TYPE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Pseudowire Type: %s",
+ val_to_str(tvb_get_ntohs(tvb, index),
+ pw_types_vals, "Unknown (%u)"));
+ break;
+ case L2_SPECIFIC_SUBLAYER:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Layer2 Specific Sublayer: %s",
+ val_to_str(tvb_get_ntohs(tvb, index),
+ l2_sublayer_vals, "Invalid (%u)"));
+ break;
+ case DATA_SEQUENCING:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Data Sequencing: %s",
+ val_to_str(tvb_get_ntohs(tvb, index),
+ data_sequencing_vals, "Invalid (%u)"));
+ break;
+ case CIRCUIT_STATUS:
+ bits = tvb_get_ntohs(tvb, index);
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Circuit Status: %s",
+ (CIRCUIT_STATUS_BIT(bits)) ? "Up" : "Down");
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 2,
+ "Circuit Type: %s",
+ (CIRCUIT_TYPE_BIT(bits)) ? "New" : "Existing");
+ break;
+ case PREFERRED_LANGUAGE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Preferred Language: %.*s", avp_len,
+ tvb_get_ptr(tvb, index, avp_len));
+ break;
+ case CTL_MSG_AUTH_NONCE:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Nonce : %s",
+ tvb_bytes_to_str(tvb, index, avp_len));
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)
+ case TX_CONNECT_SPEED_V3:
+ {
+ guint32 l_int, h_int;
+ if (avp_len < 8)
+ break;
+
+ h_int = tvb_get_ntohl(tvb, index);
+ l_int = tvb_get_ntohl(tvb, index+4);
+ if (!h_int && !l_int) {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 8,
+ "Tx Connect Speed v3: indeterminable or no physical p2p link");
+ }
+ else {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 8,
+ "Tx Connect Speed v3: %#x%04x",
+ h_int, l_int);
+ }
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;
+ }
+ case RX_CONNECT_SPEED_V3:
+ {
+ guint32 l_int, h_int;
+ if (avp_len < 8)
+ break;
+
+ h_int = tvb_get_ntohl(tvb, index);
+ l_int = tvb_get_ntohl(tvb, index+4);
+ if (!h_int && !l_int) {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 8,
+ "Rx Connect Speed v3: indeterminable or no physical p2p link");
+ }
+ else {
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, 8,
+ "Rx Connect Speed v3: %#x%04x",
+ h_int, l_int);
+ }
+ break;
+ }
+ default:
+ proto_tree_add_text(l2tp_avp_tree, tvb, index, avp_len,
+ "Unknown AVP");
+ break;
+ }
+
+ index += avp_len;
+ }
+
+ }
+ return;
+}
+
+static void
+process_l2tpv3_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ proto_tree *l2tp_tree, proto_item *l2tp_item, int *pIndex)
+{
+ int index = *pIndex;
+ int sid;
+ tvbuff_t *next_tvb;
+
+ /* Get Session ID */
+ sid = tvb_get_ntohl(tvb, index);
+ index += 4;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ sprintf(textbuffer,"%s (session id=%d)",
+ data_msg, sid);
+ col_add_fstr(pinfo->cinfo,COL_INFO,textbuffer);
+ }
+
+ if (tree) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_sid, tvb, index-4, 4, FALSE);
+ 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;
+}
+
+static void
+process_l2tpv3_data_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *l2tp_tree = NULL, *ctrl_tree;
+ proto_item *l2tp_item = NULL, *ti;
+
+ int index = 0;
+ int control;
+
+ control = tvb_get_ntohs(tvb, index);
+ index += 2; /* skip ahead */
+ index += 2; /* Skip the reserved */
+
+ 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 - version 3",
+ data_msg);
+
+ 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_uint(ctrl_tree, hf_l2tp_version, tvb, 0, 2, control);
+ }
+
+ process_l2tpv3_data(tvb, pinfo, tree, l2tp_tree, l2tp_item, &index);
+
+ return;
+}
+
+static void
+process_l2tpv3_data_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *l2tp_tree = NULL;
+ proto_item *l2tp_item = NULL, *ti;
+
+ int index = 0;
+
+ 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, 4, 2,
+ "Packet Type: %s - version 3",
+ data_msg);
+ }
+
+ process_l2tpv3_data(tvb, pinfo, tree, l2tp_tree, l2tp_item, &index);
+
+ return;
+}
+
+static void
+process_l2tpv3_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int baseIndex)
+{
+ proto_tree *l2tp_tree=NULL, *ctrl_tree;
+ proto_item *l2tp_item = NULL, *ti;
+
+ int index = baseIndex;
+ int tmp_index;
+ guint16 length = 0; /* Length field */
+ guint32 ccid = 0; /* Control Connection ID */
+ guint16 avp_type;
+ guint16 msg_type;
+ guint16 control = 0;
+
+ control = tvb_get_ntohs(tvb, index);
+ index += 2; /* skip ahead */
+ if (LENGTH_BIT(control)) { /* length field included ? */
+ length = tvb_get_ntohs(tvb, index);
+ index += 2;
+ }
+
+ /* Get Control Channel ID */
+ ccid = tvb_get_ntohl(tvb, index);
+ index += 4;
+
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ tmp_index = index;
+
+ if ((LENGTH_BIT(control))&&(length==12)) /* ZLB Message */
+ sprintf(textbuffer,"%s - ZLB (tunnel id=%d)",
+ control_msg , ccid);
+ else
+ {
+ if (SEQUENCE_BIT(control)) {
+ tmp_index += 4;
+ }
+
+ tmp_index+=4;
+
+ avp_type = tvb_get_ntohs(tvb, tmp_index);
+ tmp_index += 2;
+
+ if (avp_type == CONTROL_MESSAGE) {
+ /* We print message type */
+ msg_type = tvb_get_ntohs(tvb, tmp_index);
+ tmp_index += 2;
+ sprintf(textbuffer,"%s - %s (tunnel id=%d)",
+ control_msg ,
+ ((NUM_CONTROL_CALL_TYPES + 1 ) > msg_type) ?
+ calltype_short_str[msg_type] : "Unknown",
+ ccid);
+ }
+ else {
+ /*
+ * This is not a control message.
+ * We never pass here except in case of bad l2tp packet!
+ */
+ sprintf(textbuffer,"%s (tunnel id=%d)",
+ control_msg , ccid);
+ }
+ }
+ 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+baseIndex);
+ }
+
+ 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);
+
+ if (baseIndex) {
+ proto_tree_add_item(l2tp_tree, hf_l2tp_sid, tvb, 0, 4, FALSE);
+ }
+ ti = proto_tree_add_text(l2tp_tree, tvb, baseIndex, 2,
+ "Packet Type: %s Tunnel Id=%d",
+ (CONTROL_BIT(control) ? control_msg : data_msg), ccid);
+
+ 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_uint(ctrl_tree, hf_l2tp_version, tvb, 0, 2, control);
+ }
+ index = baseIndex + 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_ccid, tvb, index, 4, FALSE);
+ }
+ index += 4;
- /* printf("Avp Decode avp_len= %d index= %d length= %d %x\n ",avp_len,
- index,length,length); */
+ 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 (tree && (LENGTH_BIT(control))&&(length==12)) {
+ proto_tree_add_text(l2tp_tree, tvb, 0, 0, "Zero Length Bit message");
+ }
- index += avp_len;
+ if (!LENGTH_BIT(control)) {
+ return;
}
- }
+ process_control_avps(tvb, pinfo, l2tp_tree, index, length+baseIndex);
+
+ return;
+}
+
+static void
+dissect_l2tp_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *l2tp_tree=NULL, *ctrl_tree;
+ proto_item *l2tp_item = NULL, *ti;
+ 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 avp_type;
+ guint16 msg_type;
+ 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) );
+ }
+ if (CONTROL_BIT(control)) {
+ /* Call to process l2tp v3 control message */
+ process_l2tpv3_control(tvb, pinfo, tree, 0);
+ }
+ else {
+ /* Call to process l2tp v3 data message */
+ process_l2tpv3_data_udp(tvb, pinfo, tree);
+ }
+ return;
+ }
+
+ 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;
+ }
+
+ process_control_avps(tvb, pinfo, l2tp_tree, index, length);
+
+ return;
+}
+
+
+static void
+dissect_l2tp_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ int index = 0;
+ guint32 sid; /* Session ID */
+
+ 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);
+ col_add_fstr(pinfo->cinfo, COL_INFO, "L2TP Version 3");
+ }
+
+ sid = tvb_get_ntohl(tvb, index);
+ if (sid == 0) {
+ /* This is control message */
+ /* Call to process l2tp v3 control message */
+ process_l2tpv3_control(tvb, pinfo, tree, 4);
+ }
+ else {
+ /* Call to process l2tp v3 data message */
+ process_l2tpv3_data_ip(tvb, pinfo, tree);
+ }
+
+ return;
}
/* registration with the filtering engine */
@@ -1039,7 +1588,7 @@ proto_register_l2tp(void)
"AVP Length", HFILL }},
{ &hf_l2tp_avp_vendor_id,
- { "Vendor ID", "l2tp.avp.vendor_id", FT_UINT16, BASE_DEC, VALS(avp_vendor_id_vals), 0,
+ { "Vendor ID", "l2tp.avp.vendor_id", FT_UINT16, BASE_DEC, VALS(sminmpec_values), 0,
"AVP Vendor ID", HFILL }},
{ &hf_l2tp_avp_type,
@@ -1050,6 +1599,18 @@ proto_register_l2tp(void)
{ "Tie Breaker", "l2tp.tie_breaker", FT_UINT64, BASE_HEX, NULL, 0,
"Tie Breaker", HFILL }},
+ { &hf_l2tp_sid,
+ { "Session ID","l2tp.sid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Session ID", HFILL }},
+
+ { &hf_l2tp_ccid,
+ { "Control Connection ID","l2tp.ccid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Control Connection ID", HFILL }},
+
+ { &hf_l2tp_cisco_avp_type,
+ { "Type", "l2tp.avp.ciscotype", FT_UINT16, BASE_DEC, VALS(cisco_avp_type_vals), 0,
+ "AVP Type", HFILL }},
+
};
static gint *ett[] = {
@@ -1068,10 +1629,14 @@ proto_register_l2tp(void)
void
proto_reg_handoff_l2tp(void)
{
- dissector_handle_t l2tp_handle;
+ dissector_handle_t l2tp_udp_handle;
+ dissector_handle_t l2tp_ip_handle;
+
+ l2tp_udp_handle = create_dissector_handle(dissect_l2tp_udp, proto_l2tp);
+ dissector_add("udp.port", UDP_PORT_L2TP, l2tp_udp_handle);
- l2tp_handle = create_dissector_handle(dissect_l2tp, proto_l2tp);
- dissector_add("udp.port", UDP_PORT_L2TP, l2tp_handle);
+ l2tp_ip_handle = create_dissector_handle(dissect_l2tp_ip, proto_l2tp);
+ dissector_add("ip.proto", IP_PROTO_L2TP, l2tp_ip_handle);
/*
* Get a handle for the PPP-in-HDLC-like-framing dissector.
diff --git a/epan/sminmpec.c b/epan/sminmpec.c
index a60323a109..b376eb5233 100644
--- a/epan/sminmpec.c
+++ b/epan/sminmpec.c
@@ -40,14 +40,14 @@
* VENDOR Cisco 9
*/
const value_string sminmpec_values[] = {
- {0, "None"},
+ {VENDOR_IETF, "IETF (reserved)"},
{VENDOR_ACC, "ACC"},
{VENDOR_CISCO, "Cisco"},
{VENDOR_HEWLETT_PACKARD, "Hewlett Packard"},
{VENDOR_SUN_MICROSYSTEMS, "Sun Microsystems"},
- {VENDOR_MERIT, "Merit"},
- {VENDOR_SHIVA, "Shiva"},
- {VENDOR_ERICSSON, "Ericsson AB"},
+ {VENDOR_MERIT, "Merit"},
+ {VENDOR_SHIVA, "Shiva"},
+ {VENDOR_ERICSSON, "Ericsson AB"},
{VENDOR_CISCO_VPN5000, "Cisco VPN 5000"},
{VENDOR_LIVINGSTON, "Livingston"},
{VENDOR_MICROSOFT, "Microsoft"},
diff --git a/epan/sminmpec.h b/epan/sminmpec.h
index 9228d4641c..46c8665a79 100644
--- a/epan/sminmpec.h
+++ b/epan/sminmpec.h
@@ -33,6 +33,7 @@
*
* for a list.
*/
+#define VENDOR_IETF 0 /* reserved - used by the IETF in L2TP? */
#define VENDOR_ACC 5
#define VENDOR_CISCO 9
#define VENDOR_HEWLETT_PACKARD 11
@@ -40,7 +41,7 @@
#define VENDOR_MERIT 61
#define VENDOR_SHIVA 166
#define VENDOR_ERICSSON 193
-#define VENDOR_CISCO_VPN5000 255
+#define VENDOR_CISCO_VPN5000 255
#define VENDOR_LIVINGSTON 307
#define VENDOR_MICROSOFT 311
#define VENDOR_3COM 429