wireshark/epan/dissectors/packet-mpls-pm.c

1507 lines
50 KiB
C

/* packet-mpls-pm.c
*
* Routines for MPLS delay and loss measurement: it should conform
* to RFC 6374. 'PM' stands for Performance Measurement.
*
* Copyright 2012 _FF_
*
* Francesco Fondelli <francesco dot fondelli, gmail dot com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
#include "packet-ip.h"
#include "packet-mpls.h"
void proto_register_mpls_pm(void);
void proto_reg_handoff_mpls_pm(void);
/* message control flags */
#define MPLS_PM_FLAGS_R 0x08
#define MPLS_PM_FLAGS_T 0x04
#define MPLS_PM_FLAGS_RES 0x03
#define MPLS_PM_FLAGS_MASK 0x0F
/* data format flags */
#define MPLS_PM_DFLAGS_X 0x80
#define MPLS_PM_DFLAGS_B 0x40
#define MPLS_PM_DFLAGS_RES 0x30
#define MPLS_PM_DFLAGS_MASK 0xF0
static gint proto_mpls_pm_dlm = -1;
static gint proto_mpls_pm_ilm = -1;
static gint proto_mpls_pm_dm = -1;
static gint proto_mpls_pm_dlm_dm = -1;
static gint proto_mpls_pm_ilm_dm = -1;
static gint ett_mpls_pm = -1;
static gint ett_mpls_pm_flags = -1;
static gint ett_mpls_pm_dflags = -1;
static int hf_mpls_pm_version = -1;
static int hf_mpls_pm_flags = -1;
static int hf_mpls_pm_flags_r = -1;
static int hf_mpls_pm_flags_t = -1;
static int hf_mpls_pm_flags_res = -1;
static int hf_mpls_pm_query_ctrl_code = -1;
static int hf_mpls_pm_response_ctrl_code = -1;
static int hf_mpls_pm_length = -1;
static int hf_mpls_pm_dflags = -1;
static int hf_mpls_pm_dflags_x = -1;
static int hf_mpls_pm_dflags_b = -1;
static int hf_mpls_pm_dflags_res = -1;
static int hf_mpls_pm_otf = -1;
static int hf_mpls_pm_session_id = -1;
static int hf_mpls_pm_ds = -1;
static int hf_mpls_pm_origin_timestamp_null = -1;
static int hf_mpls_pm_origin_timestamp_seq = -1;
static int hf_mpls_pm_origin_timestamp_ntp = -1;
static int hf_mpls_pm_origin_timestamp_ptp = -1;
static int hf_mpls_pm_origin_timestamp_unk = -1;
static int hf_mpls_pm_counter1 = -1;
static int hf_mpls_pm_counter2 = -1;
static int hf_mpls_pm_counter3 = -1;
static int hf_mpls_pm_counter4 = -1;
static int hf_mpls_pm_qtf = -1;
static int hf_mpls_pm_qtf_combined = -1;
static int hf_mpls_pm_rtf = -1;
static int hf_mpls_pm_rtf_combined = -1;
static int hf_mpls_pm_rptf = -1;
static int hf_mpls_pm_rptf_combined = -1;
static int hf_mpls_pm_timestamp1_q_null = -1;
static int hf_mpls_pm_timestamp1_r_null = -1;
static int hf_mpls_pm_timestamp1_q_seq = -1;
static int hf_mpls_pm_timestamp1_r_seq = -1;
static int hf_mpls_pm_timestamp1_q_ntp = -1;
static int hf_mpls_pm_timestamp1_r_ntp = -1;
static int hf_mpls_pm_timestamp1_q_ptp = -1;
static int hf_mpls_pm_timestamp1_r_ptp = -1;
static int hf_mpls_pm_timestamp1_unk = -1;
static int hf_mpls_pm_timestamp2_q_null = -1;
static int hf_mpls_pm_timestamp2_r_null = -1;
static int hf_mpls_pm_timestamp2_q_seq = -1;
static int hf_mpls_pm_timestamp2_r_seq = -1;
static int hf_mpls_pm_timestamp2_q_ntp = -1;
static int hf_mpls_pm_timestamp2_r_ntp = -1;
static int hf_mpls_pm_timestamp2_q_ptp = -1;
static int hf_mpls_pm_timestamp2_r_ptp = -1;
static int hf_mpls_pm_timestamp2_unk = -1;
static int hf_mpls_pm_timestamp3_null = -1;
static int hf_mpls_pm_timestamp3_r_null = -1;
static int hf_mpls_pm_timestamp3_r_seq = -1;
static int hf_mpls_pm_timestamp3_r_ntp = -1;
static int hf_mpls_pm_timestamp3_r_ptp = -1;
static int hf_mpls_pm_timestamp3_unk = -1;
static int hf_mpls_pm_timestamp4_null = -1;
static int hf_mpls_pm_timestamp4_r_null = -1;
static int hf_mpls_pm_timestamp4_r_seq = -1;
static int hf_mpls_pm_timestamp4_r_ntp = -1;
static int hf_mpls_pm_timestamp4_r_ptp = -1;
static int hf_mpls_pm_timestamp4_unk = -1;
/*
* FF: please keep this list in sync with
* http://www.iana.org/assignments/mpls-lsp-ping-parameters
* Registry Name: 'Loss/Delay Measurement Control Code: Query Codes'
*/
static const range_string mpls_pm_query_ctrl_code_rvals[] = {
{ 0x00, 0x00, "In-band Response Requested" },
{ 0x01, 0x01, "Out-of-band Response Requested" },
{ 0x02, 0x02, "No Response Requested" },
{ 0x03, 0xFF, "Unassigned" },
{ 0x00, 0x00, NULL }
};
/*
* FF: please keep this list in sync with
* http://www.iana.org/assignments/mpls-lsp-ping-parameters
* Registry Name: 'Loss/Delay Measurement Control Code: Response Codes'
*/
static const range_string mpls_pm_response_ctrl_code_rvals[] = {
{ 0x00, 0x00, "Reserved" },
{ 0x01, 0x01, "Success" },
{ 0x02, 0x02, "Data Format Invalid" },
{ 0x03, 0x03, "Initialization in Progress" },
{ 0x04, 0x04, "Data Reset Occurred" },
{ 0x05, 0x05, "Resource Temporarily Unavailable" },
{ 0x06, 0x0F, "Unassigned" },
{ 0x10, 0x10, "Unspecified Error" },
{ 0x11, 0x11, "Unsupported Version" },
{ 0x12, 0x12, "Unsupported Control Code" },
{ 0x13, 0x13, "Unsupported Data Format" },
{ 0x14, 0x14, "Authentication Failure" },
{ 0x15, 0x15, "Invalid Destination Node Identifier" },
{ 0x16, 0x16, "Connection Mismatch" },
{ 0x17, 0x17, "Unsupported Mandatory TLV Object" },
{ 0x18, 0x18, "Unsupported Query Interval" },
{ 0x19, 0x19, "Administrative Block" },
{ 0x1A, 0x1A, "Resource Unavailable" },
{ 0x1B, 0x1B, "Resource Released" },
{ 0x1C, 0x1C, "Invalid Message" },
{ 0x1D, 0x1D, "Protocol Error" },
{ 0x1E, 0xFF, "Unassigned" },
{ 0x00, 0x00, NULL }
};
#define DLM 1
#define ILM 2
#define DM 3
#define DLMDM 4
#define ILMDM 5
/* FF: internal */
static const value_string pmt_vals[] = {
{ DLM, "DLM" },
{ ILM, "ILM" },
{ DM, "DM" },
{ DLMDM, "DLM+DM" },
{ ILMDM, "ILM+DM" },
{ 0, NULL }
};
/*
* FF: please keep this list in sync with
* http://www.iana.org/assignments/mpls-lsp-ping-parameters
* Registry Name: 'Loss/Delay Measurement Control Code: Response Codes'
*/
#define MPLS_PM_TSF_NULL 0
#define MPLS_PM_TSF_SEQ 1
#define MPLS_PM_TSF_NTP 2
#define MPLS_PM_TSF_PTP 3
static const range_string mpls_pm_time_stamp_format_rvals[] = {
{ MPLS_PM_TSF_NULL, MPLS_PM_TSF_NULL,
"Null Timestamp" },
{ MPLS_PM_TSF_SEQ, MPLS_PM_TSF_SEQ,
"Sequence Number" },
{ MPLS_PM_TSF_NTP, MPLS_PM_TSF_NTP,
"Network Time Protocol version 4 64-bit Timestamp" },
{ MPLS_PM_TSF_PTP, MPLS_PM_TSF_PTP,
"Truncated IEEE 1588v2 PTP Timestamp" },
{ 4, 15, "Unassigned" },
{ 0, 0, NULL }
};
static void
mpls_pm_dissect_counter(tvbuff_t *tvb, proto_tree *pm_tree,
guint32 offset, gboolean query, gboolean bflag,
guint8 i)
{
proto_item *ti;
/*
* FF: when bflag is true, indicates that the Counter 1-4
* fields represent octet counts. Otherwise Counter 1-4 fields
* represent packet counts
*/
const gchar *unit = bflag ? "octets" : "packets";
if (query) {
switch (i) {
case 1:
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_counter1, tvb,
offset, 8, ENC_BIG_ENDIAN);
proto_item_append_text(ti, " %s (A_Tx)", unit);
break;
case 2:
proto_tree_add_item(pm_tree, hf_mpls_pm_counter2, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case 3:
proto_tree_add_item(pm_tree, hf_mpls_pm_counter3, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case 4:
proto_tree_add_item(pm_tree, hf_mpls_pm_counter4, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
default:
/* never here */
break;
}
} else {
/* response */
switch (i) {
case 1:
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_counter1, tvb,
offset, 8, ENC_BIG_ENDIAN);
proto_item_append_text(ti, " %s (B_Tx)", unit);
break;
case 2:
proto_tree_add_item(pm_tree, hf_mpls_pm_counter2, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case 3:
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_counter3, tvb,
offset, 8, ENC_BIG_ENDIAN);
proto_item_append_text(ti, " %s (A_Tx)", unit);
break;
case 4:
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_counter4, tvb,
offset, 8, ENC_BIG_ENDIAN);
proto_item_append_text(ti, " %s (B_Rx)", unit);
break;
default:
/* never here */
break;
}
}
}
static void
mpls_pm_dissect_timestamp(tvbuff_t *tvb, proto_tree *pm_tree,
guint32 offset, guint8 qtf, guint8 rtf,
gboolean query, guint8 i)
{
if (query) {
/*
* FF: when a query is sent from A, Timestamp 1 is set to T1 and the
* other timestamp fields are set to 0. Moreover, it might be useful
* to decode Timestamp 2 (set to T2) as well because data can be captured
* somewhere at the responder box after the timestamp has been taken.
*/
switch (i) {
case 1:
switch (qtf) {
/*
* FF: the actual formats of the timestamp fields written by A
* are indicated by the Querier Timestamp Format.
*/
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp1_q_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_q_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_q_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_q_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
break;
case 2:
switch (qtf) {
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp2_q_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_q_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_q_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_q_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
break;
case 3:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp3_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case 4:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp4_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
default:
/* never here */
break;
} /* end of switch (i) */
} else {
/*
* FF: when B transmits the response, Timestamp 1 is set to T3,
* Timestamp 3 is set to T1 and Timestamp 4 is set to T2. Timestamp 2
* is set to 0. Moreover, it might be useful to decode Timestamp 2
* (set to T4) as well because data can be captured somewhere at the
* querier box after the timestamp has been taken.
*/
switch (i) {
case 1:
switch (rtf) {
/*
* FF: the actual formats of the timestamp fields written by B
* are indicated by the Responder Timestamp Format.
*/
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp1_r_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_r_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_r_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_r_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
break;
case 2:
switch (rtf) {
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp2_r_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_r_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_r_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_r_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp2_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
break;
case 3:
switch (rtf) {
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp3_r_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp3_r_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp3_r_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp3_r_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp3_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
break;
case 4:
switch (rtf) {
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree,
hf_mpls_pm_timestamp4_r_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp4_r_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp4_r_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp4_r_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp4_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
break;
default:
/* never here */
break;
} /* end of switch (i) */
}
}
static void
mpls_pm_build_cinfo(tvbuff_t *tvb, packet_info *pinfo, const char *str_pmt,
gboolean *query, gboolean *response,
gboolean *class_specific,
guint32 *sid, guint8 *code)
{
col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MPLS PM (%s)", str_pmt);
col_clear(pinfo->cinfo, COL_INFO);
*response = (tvb_get_guint8(tvb, 0) & 0x08) ? TRUE : FALSE;
*class_specific = (tvb_get_guint8(tvb, 0) & 0x04) ? TRUE : FALSE;
*query = !(*response);
*code = tvb_get_guint8(tvb, 1);
if (!(*class_specific)) {
/*
* FF: when the T flag is set to 0 the DS field can be considered
* part of the Session Identifier.
*/
*sid = tvb_get_ntohl(tvb, 8);
} else {
*sid = tvb_get_ntohl(tvb, 8) >> 6;
}
if (*query) {
col_add_fstr(pinfo->cinfo, COL_INFO,
"Query, sid: %u", *sid);
} else {
col_add_fstr(pinfo->cinfo, COL_INFO,
"Response, sid: %u, code: %s (%u)",
*sid,
rval_to_str(*code,
mpls_pm_response_ctrl_code_rvals,
"Unknown"),
*code);
}
}
/* FF: the message formats for direct and inferred LM are identical */
static void
dissect_mpls_pm_loss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint8 pmt)
{
proto_item *ti = NULL;
proto_tree *pm_tree;
proto_tree *pm_tree_flags;
proto_tree *pm_tree_dflags;
guint32 offset = 0;
gboolean query = 0;
gboolean response = 0;
gboolean class_specific = 0;
guint32 sid = 0;
guint8 code = 0;
guint8 otf;
gboolean bflag;
guint8 i;
mpls_pm_build_cinfo(tvb, pinfo,
val_to_str_const(pmt, pmt_vals, ""),
&query, &response, &class_specific, &sid, &code);
if (!tree) {
return;
}
/* create display subtree for the protocol */
if (pmt == DLM) {
ti = proto_tree_add_item(tree, proto_mpls_pm_dlm, tvb, 0, -1, ENC_NA);
} else {
ti = proto_tree_add_item(tree, proto_mpls_pm_ilm, tvb, 0, -1, ENC_NA);
}
pm_tree = proto_item_add_subtree(ti, ett_mpls_pm);
/* add version to the subtree */
proto_tree_add_item(pm_tree, hf_mpls_pm_version, tvb, offset, 1, ENC_BIG_ENDIAN);
/* ctrl flags subtree */
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_flags, tvb,
offset, 1, ENC_BIG_ENDIAN);
pm_tree_flags = proto_item_add_subtree(ti, ett_mpls_pm_flags);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_r, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_t, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_res, tvb,
offset, 1, ENC_NA);
offset += 1;
if (query) {
proto_tree_add_item(pm_tree, hf_mpls_pm_query_ctrl_code,
tvb, offset, 1, ENC_BIG_ENDIAN);
} else {
proto_tree_add_item(pm_tree, hf_mpls_pm_response_ctrl_code,
tvb, offset, 1, ENC_BIG_ENDIAN);
}
offset += 1;
proto_tree_add_item(pm_tree, hf_mpls_pm_length, tvb,
offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* data flags subtree */
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_dflags, tvb,
offset, 1, ENC_BIG_ENDIAN);
pm_tree_dflags = proto_item_add_subtree(ti, ett_mpls_pm_dflags);
proto_tree_add_item(pm_tree_dflags, hf_mpls_pm_dflags_x, tvb,
offset, 1, ENC_NA);
bflag = (tvb_get_guint8(tvb, offset) & 0x40) ? TRUE : FALSE;
proto_tree_add_item(pm_tree_dflags, hf_mpls_pm_dflags_b, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_dflags, hf_mpls_pm_dflags_res, tvb,
offset, 1, ENC_NA);
otf = tvb_get_guint8(tvb, offset) & 0x0F;
proto_tree_add_item(pm_tree, hf_mpls_pm_otf, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
/* skip 3 reserved bytes */
offset += 3;
proto_tree_add_uint(pm_tree, hf_mpls_pm_session_id, tvb, offset, 4, sid);
if (class_specific) {
proto_tree_add_item(pm_tree, hf_mpls_pm_ds, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
}
offset += 4;
switch (otf) {
case MPLS_PM_TSF_NULL:
proto_tree_add_item(pm_tree, hf_mpls_pm_origin_timestamp_null, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_SEQ:
proto_tree_add_item(pm_tree, hf_mpls_pm_origin_timestamp_seq, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_NTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_origin_timestamp_ntp, tvb,
offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN);
break;
case MPLS_PM_TSF_PTP:
proto_tree_add_item(pm_tree, hf_mpls_pm_origin_timestamp_ptp, tvb,
offset, 8, ENC_TIME_SECS_NSECS|ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(pm_tree, hf_mpls_pm_origin_timestamp_unk, tvb,
offset, 8, ENC_BIG_ENDIAN);
break;
}
offset += 8;
/* counters 1..4 */
for (i = 1; i <= 4; i++) {
mpls_pm_dissect_counter(tvb, pm_tree, offset, query, bflag, i);
offset += 8;
}
}
static int
dissect_mpls_pm_dlm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
/* the message formats for direct and inferred LM are identical */
dissect_mpls_pm_loss(tvb, pinfo, tree, DLM);
return tvb_captured_length(tvb);
}
static int
dissect_mpls_pm_ilm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
/* the message formats for direct and inferred LM are identical */
dissect_mpls_pm_loss(tvb, pinfo, tree, ILM);
return tvb_captured_length(tvb);
}
static int
dissect_mpls_pm_delay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_item *ti;
proto_tree *pm_tree;
proto_tree *pm_tree_flags;
guint32 offset = 0;
gboolean query = 0;
gboolean response = 0;
gboolean class_specific = 0;
guint32 sid = 0;
guint8 code = 0;
guint8 qtf;
guint8 rtf;
guint8 i;
mpls_pm_build_cinfo(tvb, pinfo,
"DM",
&query, &response, &class_specific, &sid, &code);
/* create display subtree for the protocol */
ti = proto_tree_add_item(tree, proto_mpls_pm_dm, tvb, 0, -1, ENC_NA);
pm_tree = proto_item_add_subtree(ti, ett_mpls_pm);
/* add version to the subtree */
proto_tree_add_item(pm_tree, hf_mpls_pm_version, tvb, offset, 1, ENC_BIG_ENDIAN);
/* ctrl flags subtree */
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
pm_tree_flags = proto_item_add_subtree(ti, ett_mpls_pm_flags);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_r, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_t, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_res, tvb,
offset, 1, ENC_NA);
offset += 1;
if (query) {
proto_tree_add_item(pm_tree, hf_mpls_pm_query_ctrl_code,
tvb, offset, 1, ENC_BIG_ENDIAN);
} else {
proto_tree_add_item(pm_tree, hf_mpls_pm_response_ctrl_code,
tvb, offset, 1, ENC_BIG_ENDIAN);
}
offset += 1;
proto_tree_add_item(pm_tree, hf_mpls_pm_length, tvb,
offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* qtf, rtf */
qtf = (tvb_get_guint8(tvb, offset) & 0xF0) >> 4;
proto_tree_add_item(pm_tree, hf_mpls_pm_qtf, tvb,
offset, 1, ENC_BIG_ENDIAN);
rtf = tvb_get_guint8(tvb, offset) & 0x0F;
proto_tree_add_item(pm_tree, hf_mpls_pm_rtf, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
/* rptf */
proto_tree_add_item(pm_tree, hf_mpls_pm_rptf, tvb,
offset, 1, ENC_BIG_ENDIAN);
/* skip 20 reserved bits */
offset += 3;
proto_tree_add_uint(pm_tree, hf_mpls_pm_session_id, tvb, offset, 4, sid);
if (class_specific) {
proto_tree_add_item(pm_tree, hf_mpls_pm_ds, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
}
offset += 4;
/* timestamps 1..4 */
for (i = 1; i <= 4; i++) {
mpls_pm_dissect_timestamp(tvb, pm_tree, offset, qtf, rtf, query, i);
offset += 8;
}
return tvb_captured_length(tvb);
}
static void
dissect_mpls_pm_combined(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint8 pmt)
{
proto_item *ti = NULL;
proto_tree *pm_tree;
proto_tree *pm_tree_flags;
proto_tree *pm_tree_dflags;
guint32 offset = 0;
gboolean query = 0;
gboolean response = 0;
gboolean class_specific = 0;
guint32 sid = 0;
guint8 code = 0;
guint8 qtf;
guint8 rtf;
gboolean bflag;
guint8 i;
mpls_pm_build_cinfo(tvb, pinfo,
val_to_str_const(pmt, pmt_vals, ""),
&query, &response, &class_specific, &sid, &code);
if (!tree) {
return;
}
/* create display subtree for the protocol */
if (pmt == DLMDM) {
ti = proto_tree_add_item(tree, proto_mpls_pm_dlm_dm,
tvb, 0, -1, ENC_NA);
} else {
ti = proto_tree_add_item(tree, proto_mpls_pm_ilm_dm,
tvb, 0, -1, ENC_NA);
}
pm_tree = proto_item_add_subtree(ti, ett_mpls_pm);
/* add version to the subtree */
proto_tree_add_item(pm_tree, hf_mpls_pm_version, tvb, offset, 1, ENC_BIG_ENDIAN);
/* ctrl flags subtree */
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
pm_tree_flags = proto_item_add_subtree(ti, ett_mpls_pm_flags);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_r, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_t, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_flags, hf_mpls_pm_flags_res, tvb,
offset, 1, ENC_NA);
offset += 1;
if (query) {
proto_tree_add_item(pm_tree, hf_mpls_pm_query_ctrl_code,
tvb, offset, 1, ENC_BIG_ENDIAN);
} else {
proto_tree_add_item(pm_tree, hf_mpls_pm_response_ctrl_code,
tvb, offset, 1, ENC_BIG_ENDIAN);
}
offset += 1;
proto_tree_add_item(pm_tree, hf_mpls_pm_length, tvb,
offset, 2, ENC_BIG_ENDIAN);
offset += 2;
/* data flags subtree */
ti = proto_tree_add_item(pm_tree, hf_mpls_pm_dflags, tvb,
offset, 1, ENC_BIG_ENDIAN);
pm_tree_dflags = proto_item_add_subtree(ti, ett_mpls_pm_dflags);
proto_tree_add_item(pm_tree_dflags, hf_mpls_pm_dflags_x, tvb,
offset, 1, ENC_NA);
bflag = (tvb_get_guint8(tvb, offset) & 0x40) ? TRUE : FALSE;
proto_tree_add_item(pm_tree_dflags, hf_mpls_pm_dflags_b, tvb,
offset, 1, ENC_NA);
proto_tree_add_item(pm_tree_dflags, hf_mpls_pm_dflags_res, tvb,
offset, 1, ENC_NA);
/*
* FF: the roles of the OTF and Origin Timestamp fields for LM are
* here played by the QTF and Timestamp 1 fields, respectively.
*/
qtf = tvb_get_guint8(tvb, offset) & 0x0F;
proto_tree_add_item(pm_tree, hf_mpls_pm_qtf_combined, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
/* rtf, rptf */
rtf = tvb_get_guint8(tvb, offset) & 0xF0 >> 4;
proto_tree_add_item(pm_tree, hf_mpls_pm_rtf_combined, tvb,
offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(pm_tree, hf_mpls_pm_rptf_combined, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
/* skip 2 reserved bytes */
offset += 2;
proto_tree_add_uint(pm_tree, hf_mpls_pm_session_id, tvb, offset, 4, sid);
if (class_specific) {
proto_tree_add_item(pm_tree, hf_mpls_pm_ds, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
}
offset += 4;
/* timestamps 1..4 */
for (i = 1; i <= 4; i++) {
mpls_pm_dissect_timestamp(tvb, pm_tree, offset, qtf, rtf, query, i);
offset += 8;
}
/* counters 1..4 */
for (i = 1; i <= 4; i++) {
mpls_pm_dissect_counter(tvb, pm_tree, offset, query, bflag, i);
offset += 8;
}
}
static int
dissect_mpls_pm_dlm_dm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
/* the formats of the DLM+DM and ILM+DM messages are also identical */
dissect_mpls_pm_combined(tvb, pinfo, tree, DLMDM);
return tvb_captured_length(tvb);
}
static int
dissect_mpls_pm_ilm_dm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
/* the formats of the DLM+DM and ILM+DM messages are also identical */
dissect_mpls_pm_combined(tvb, pinfo, tree, ILMDM);
return tvb_captured_length(tvb);
}
void
proto_register_mpls_pm(void)
{
static hf_register_info hf[] = {
{
&hf_mpls_pm_version,
{
"Version", "mpls_pm.version", FT_UINT8, BASE_DEC, NULL,
0xF0, NULL, HFILL
}
},
{
&hf_mpls_pm_flags,
{
"Flags", "mpls_pm.flags", FT_UINT8,
BASE_HEX, NULL, MPLS_PM_FLAGS_MASK, NULL, HFILL
}
},
{
&hf_mpls_pm_flags_r,
{
"Response indicator (R)", "mpls_pm.flags.r",
FT_BOOLEAN, 4, TFS(&tfs_set_notset), MPLS_PM_FLAGS_R,
NULL, HFILL
}
},
{
&hf_mpls_pm_flags_t,
{
"Traffic-class-specific measurement indicator (T)",
"mpls_pm.flags.t",
FT_BOOLEAN, 4, TFS(&tfs_set_notset), MPLS_PM_FLAGS_T,
NULL, HFILL
}
},
{
&hf_mpls_pm_flags_res,
{
"Reserved",
"mpls_pm.flags.res",
FT_BOOLEAN, 4, TFS(&tfs_set_notset), MPLS_PM_FLAGS_RES,
NULL, HFILL
}
},
{
&hf_mpls_pm_query_ctrl_code,
{
"Control Code",
"mpls_pm.ctrl.code",
FT_UINT8, BASE_RANGE_STRING | BASE_HEX,
RVALS(mpls_pm_query_ctrl_code_rvals), 0x0,
"Code identifying the query type", HFILL
}
},
{
&hf_mpls_pm_response_ctrl_code,
{
"Control Code",
"mpls_pm.ctrl.code",
FT_UINT8, BASE_RANGE_STRING | BASE_HEX,
RVALS(mpls_pm_response_ctrl_code_rvals), 0x0,
"Code identifying the response type", HFILL
}
},
{
&hf_mpls_pm_length,
{
"Message Length",
"mpls_pm.length",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Total length of this message in bytes", HFILL
}
},
{
&hf_mpls_pm_dflags,
{
"DFlags", "mpls_pm.dflags", FT_UINT8,
BASE_HEX, NULL, MPLS_PM_DFLAGS_MASK,
NULL, HFILL
}
},
{
&hf_mpls_pm_dflags_x,
{
"Extended counter format indicator (X)", "mpls_pm.dflags.x",
FT_BOOLEAN, 4, TFS(&tfs_set_notset), MPLS_PM_DFLAGS_X,
NULL, HFILL
}
},
{
&hf_mpls_pm_dflags_b,
{
"Octet/Byte count indicator (B)", "mpls_pm.dflags.b",
FT_BOOLEAN, 4, TFS(&tfs_set_notset), MPLS_PM_DFLAGS_B,
NULL, HFILL
}
},
{
&hf_mpls_pm_dflags_res,
{
"Reserved",
"mpls_pm.dflags.res",
FT_BOOLEAN, 4, NULL, MPLS_PM_DFLAGS_RES,
NULL, HFILL
}
},
{
&hf_mpls_pm_otf,
{
"Origin Timestamp Format (OTF)",
"mpls_pm.otf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0x0F,
NULL, HFILL
}
},
{
&hf_mpls_pm_session_id,
{
"Session Identifier",
"mpls_pm.session.id",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_ds,
{
"Differentiated Services Codepoint",
"mpls_pm.ds",
FT_UINT8, BASE_DEC | BASE_EXT_STRING,
&dscp_vals_ext, 0x3F,
NULL, HFILL
}
},
{
&hf_mpls_pm_origin_timestamp_null,
{
"Origin Timestamp",
"mpls_pm.origin.timestamp.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_origin_timestamp_seq,
{
"Origin Timestamp",
"mpls_pm.origin.timestamp.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_origin_timestamp_ntp,
{
"Origin Timestamp",
"mpls_pm.origin.timestamp.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_origin_timestamp_ptp,
{
"Origin Timestamp",
"mpls_pm.origin.timestamp.ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_origin_timestamp_unk,
{
"Origin Timestamp (Unknown Type)",
"mpls_pm.origin.timestamp.unk",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_counter1,
{
"Counter 1",
"mpls_pm.counter1",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_counter2,
{
"Counter 2",
"mpls_pm.counter2",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_counter3,
{
"Counter 3",
"mpls_pm.counter3",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_counter4,
{
"Counter 4",
"mpls_pm.counter4",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_qtf,
{
"Querier timestamp format (QTF)",
"mpls_pm.qtf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0xF0,
NULL, HFILL
}
},
{
&hf_mpls_pm_qtf_combined,
{
"Querier timestamp format (QTF)",
"mpls_pm.qtf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0x0F,
NULL, HFILL
}
},
{
&hf_mpls_pm_rtf,
{
"Responder timestamp format (RTF)",
"mpls_pm.rtf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0x0F,
NULL, HFILL
}
},
{
&hf_mpls_pm_rtf_combined,
{
"Responder timestamp format (RTF)",
"mpls_pm.rtf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0xF0,
NULL, HFILL
}
},
{
&hf_mpls_pm_rptf,
{
"Responder's preferred timestamp format (RPTF)",
"mpls_pm.rptf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0xF0,
NULL, HFILL
}
},
{
&hf_mpls_pm_rptf_combined,
{
"Responder's preferred timestamp format (RPTF)",
"mpls_pm.rptf",
FT_UINT8, BASE_RANGE_STRING | BASE_DEC,
RVALS(mpls_pm_time_stamp_format_rvals), 0x0F,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_q_null,
{
"Timestamp 1 (T1)",
"mpls_pm.timestamp1.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_r_null,
{
"Timestamp 1 (T3)",
"mpls_pm.timestamp1.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_q_seq,
{
"Timestamp 1 (T1)",
"mpls_pm.timestamp1.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_r_seq,
{
"Timestamp 1 (T3)",
"mpls_pm.timestamp1.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_q_ntp,
{
"Timestamp 1 (T1)",
"mpls_pm.timestamp1.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_r_ntp,
{
"Timestamp 1 (T3)",
"mpls_pm.timestamp1.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_q_ptp,
{
"Timestamp 1 (T1)",
"mpls_pm.timestamp1.ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_r_ptp,
{
"Timestamp 1 (T3)",
"mpls_pm.timestamp1.ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp1_unk,
{
"Timestamp 1 (Unknown Type)",
"mpls_pm.timestamp1.unk",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_q_null,
{
"Timestamp 2 (T2)",
"mpls_pm.timestamp2.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_r_null,
{
"Timestamp 2 (T4)",
"mpls_pm.timestamp2.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_q_seq,
{
"Timestamp 2 (T2)",
"mpls_pm.timestamp2.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_r_seq,
{
"Timestamp 2 (T4)",
"mpls_pm.timestamp2.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_q_ntp,
{
"Timestamp 2 (T2)",
"mpls_pm.timestamp2.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_r_ntp,
{
"Timestamp 2 (T4)",
"mpls_pm.timestamp2.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_q_ptp,
{
"Timestamp 2 (T2)",
"mpls_pm.timestamp2.ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_r_ptp,
{
"Timestamp 2 (T4)",
"mpls_pm.timestamp2.ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp2_unk,
{
"Timestamp 2 (Unknown Type)",
"mpls_pm.timestamp2.unk",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp3_null,
{
"Timestamp 3",
"mpls_pm.timestamp3.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp3_r_null,
{
"Timestamp 3 (T1)",
"mpls_pm.timestamp3.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp3_r_seq,
{
"Timestamp 3 (T1)",
"mpls_pm.timestamp3.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp3_r_ntp,
{
"Timestamp 3 (T1)",
"mpls_pm.timestamp3.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp3_r_ptp,
{
"Timestamp 3 (T1)",
"mpls_pm.timestamp3_ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp3_unk,
{
"Timestamp 3 (Unknown Type)",
"mpls_pm.timestamp3.unk",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp4_null,
{
"Timestamp 4",
"mpls_pm.timestamp4.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp4_r_null,
{
"Timestamp 4 (T2)",
"mpls_pm.timestamp4.null",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp4_r_seq,
{
"Timestamp 4 (T2)",
"mpls_pm.timestamp4.seq",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp4_r_ntp,
{
"Timestamp 4 (T2)",
"mpls_pm.timestamp4.ntp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp4_r_ptp,
{
"Timestamp 4 (T2)",
"mpls_pm.timestamp4.ptp",
FT_RELATIVE_TIME, BASE_NONE,
NULL, 0x0,
NULL, HFILL
}
},
{
&hf_mpls_pm_timestamp4_unk,
{
"Timestamp 4 (Unknown Type)",
"mpls_pm.timestamp4.unk",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL
}
}
};
static gint *ett[] = {
&ett_mpls_pm,
&ett_mpls_pm_flags,
&ett_mpls_pm_dflags
};
proto_mpls_pm_dlm =
proto_register_protocol("MPLS Direct Loss Measurement (DLM)",
"MPLS Direct Loss Measurement (DLM)",
"mplspmdlm");
proto_mpls_pm_ilm =
proto_register_protocol("MPLS Inferred Loss Measurement (ILM)",
"MPLS Inferred Loss Measurement (ILM)",
"mplspmilm");
proto_mpls_pm_dm =
proto_register_protocol("MPLS Delay Measurement (DM)",
"MPLS Delay Measurement (DM)",
"mplspmdm");
proto_mpls_pm_dlm_dm =
proto_register_protocol("MPLS Direct Loss and Delay "
"Measurement (DLM+DM)",
"MPLS Direct Loss and Delay "
"Measurement (DLM+DM)",
"mplspmdlmdm");
proto_mpls_pm_ilm_dm =
proto_register_protocol("MPLS Inferred Loss and Delay "
"Measurement (ILM+DM)",
"MPLS Inferred Loss and Delay "
"Measurement (ILM+DM)",
"mplspmilmdm");
proto_register_field_array(proto_mpls_pm_dlm, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_mpls_pm(void)
{
dissector_handle_t mpls_pm_dlm_handle, mpls_pm_ilm_handle, mpls_pm_dm_handle,
mpls_pm_dlm_dm_handle, mpls_pm_ilm_dm_handle;
mpls_pm_dlm_handle = create_dissector_handle( dissect_mpls_pm_dlm, proto_mpls_pm_dlm );
dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_DLM, mpls_pm_dlm_handle);
mpls_pm_ilm_handle = create_dissector_handle( dissect_mpls_pm_ilm, proto_mpls_pm_ilm );
dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_ILM, mpls_pm_ilm_handle);
mpls_pm_dm_handle = create_dissector_handle( dissect_mpls_pm_delay, proto_mpls_pm_dm );
dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_DM, mpls_pm_dm_handle);
mpls_pm_dlm_dm_handle = create_dissector_handle( dissect_mpls_pm_dlm_dm, proto_mpls_pm_dlm_dm );
dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_DLM_DM, mpls_pm_dlm_dm_handle);
mpls_pm_ilm_dm_handle = create_dissector_handle( dissect_mpls_pm_ilm_dm, proto_mpls_pm_ilm_dm );
dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_ILM_DM, mpls_pm_ilm_dm_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/