diff options
author | Alexis La Goutte <alexis.lagoutte@gmail.com> | 2012-03-01 13:36:18 +0000 |
---|---|---|
committer | Alexis La Goutte <alexis.lagoutte@gmail.com> | 2012-03-01 13:36:18 +0000 |
commit | b5efd24a0059ca6058a669bbf6a58bfb4d92cb57 (patch) | |
tree | ad744ca99f6b5617cb0b8795d965b410c2fd08f4 | |
parent | ffbba61fdfab8c49db0dd0a4c2095f9963f642de (diff) |
From Francesco Fondelli via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6881
Support for MPLS Packet Loss and Delay Measurement, RFC 6374
Support for MPLS Packet Loss and Delay Measurement, RFC 6374.
Any packetformat is supported: DLM, ILM, DM, DLM+DM and ILM+DM.
From me :
* Prefer proto_tree_add_item when it is possible
* add Modelines information
svn path=/trunk/; revision=41260
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/dissectors/Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-mpls-pm.c | 1425 | ||||
-rw-r--r-- | epan/dissectors/packet-mpls.c | 30 |
5 files changed, 1458 insertions, 0 deletions
@@ -2351,6 +2351,7 @@ Francesco Fondelli <francesco.fondelli [AT] gmail.com> { user preference option. RSVP IF_ID ERROR_STRING TLV support, RFC 4783 Support for Vendor Private objects, RFC 3936 + Support for MPLS Packet Loss and Delay Measurement, RFC 6374 } Artem Tamazov <artem.tamazov [AT] tellabs.com> { diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index bd85c234b4..f837dd325f 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -809,6 +809,7 @@ set(DISSECTOR_SRC dissectors/packet-mpeg1.c dissectors/packet-mpls.c dissectors/packet-mpls-echo.c + dissectors/packet-mpls-pm.c dissectors/packet-mq.c dissectors/packet-mq-pcf.c dissectors/packet-mrdisc.c diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 6a372fcd11..cd04664cb6 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -728,6 +728,7 @@ DISSECTOR_SRC = \ packet-mpeg1.c \ packet-mpls.c \ packet-mpls-echo.c \ + packet-mpls-pm.c \ packet-mq.c \ packet-mq-pcf.c \ packet-mrdisc.c \ diff --git a/epan/dissectors/packet-mpls-pm.c b/epan/dissectors/packet-mpls-pm.c new file mode 100644 index 0000000000..d507b842e7 --- /dev/null +++ b/epan/dissectors/packet-mpls-pm.c @@ -0,0 +1,1425 @@ +/* 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> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <glib.h> + +#include <epan/packet.h> +#include <packet-ip.h> + +/* 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_null = -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; + +static dissector_handle_t mpls_pm_dlm_handle; +static dissector_handle_t mpls_pm_ilm_handle; +static dissector_handle_t mpls_pm_dm_handle; +static dissector_handle_t mpls_pm_dlm_dm_handle; +static dissector_handle_t mpls_pm_ilm_dm_handle; + +/* + * 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' + */ +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' + */ +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 +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; + gchar strunitp[] = "packets"; + gchar strunitb[] = "octets"; + /* + * FF: when bflag is true, indicates that the Counter 1-4 + * fields represent octet counts. Otherwise Counter 1-4 fields + * represent packet counts + */ + gchar *unit = bflag ? strunitb : strunitp; + + 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. + */ + 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: + { + nstime_t ts; + ts.secs = tvb_get_ntohl(tvb, offset); + ts.nsecs = tvb_get_ntohl(tvb, offset + 4); + proto_tree_add_time(pm_tree, hf_mpls_pm_timestamp1_q_ptp, + tvb, offset, 8, &ts); + } + break; + default: + proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_unk, tvb, + offset, 8, ENC_BIG_ENDIAN); + break; + } + break; + case 2: + proto_tree_add_item(pm_tree, + hf_mpls_pm_timestamp2_null, tvb, + offset, 8, ENC_BIG_ENDIAN); + 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. + */ + 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: + { + nstime_t ts; + ts.secs = tvb_get_ntohl(tvb, offset); + ts.nsecs = tvb_get_ntohl(tvb, offset + 4); + proto_tree_add_time(pm_tree, hf_mpls_pm_timestamp1_r_ptp, + tvb, offset, 8, &ts); + } + break; + default: + proto_tree_add_item(pm_tree, hf_mpls_pm_timestamp1_unk, tvb, + offset, 8, ENC_BIG_ENDIAN); + break; + } + break; + case 2: + proto_tree_add_item(pm_tree, + hf_mpls_pm_timestamp2_null, tvb, + offset, 8, ENC_BIG_ENDIAN); + 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: + { + nstime_t ts; + ts.secs = tvb_get_ntohl(tvb, offset); + ts.nsecs = tvb_get_ntohl(tvb, offset + 4); + proto_tree_add_time(pm_tree, hf_mpls_pm_timestamp3_r_ptp, + tvb, offset, 8, &ts); + } + 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: + { + nstime_t ts; + ts.secs = tvb_get_ntohl(tvb, offset); + ts.nsecs = tvb_get_ntohl(tvb, offset + 4); + proto_tree_add_time(pm_tree, hf_mpls_pm_timestamp4_r_ptp, + tvb, offset, 8, &ts); + } + 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) +{ + int offset = 0; + guint8 sid3, sid2, sid1, sid0; + + *response = (tvb_get_guint8(tvb, offset) & 0x08) ? TRUE : FALSE; + *class_specific = (tvb_get_guint8(tvb, offset) & 0x04) ? TRUE : FALSE; + *query = !(*response); + *code = tvb_get_guint8(tvb, offset + 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, offset + 8); + } else { + sid3 = tvb_get_guint8(tvb, offset + 8); + sid2 = tvb_get_guint8(tvb, offset + 9); + sid1 = tvb_get_guint8(tvb, offset + 10); + sid0 = tvb_get_guint8(tvb, offset + 11) & 0xC0; + *sid = ((guint32) sid0 >> 6) | ((guint32) sid1 >> 8) | + ((guint32) sid2 >> 16) | ((guint32) sid3 >> 24); + } + + col_clear(pinfo->cinfo, COL_PROTOCOL); + col_clear(pinfo->cinfo, COL_INFO); + + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "MPLS PM (%s)", str_pmt); + + 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 = NULL; + proto_tree *pm_tree_flags = NULL; + proto_tree *pm_tree_dflags = NULL; + guint32 offset = 0; + gboolean query = 0; + gboolean response = 0; + gboolean class_specific = 0; + guint32 sid = 0; + guint8 code = 0; + guint8 otf = 0; + gboolean bflag = FALSE; + guint8 i = 0; + + mpls_pm_build_cinfo(tvb, pinfo, + val_to_str(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_NA); + + /* ctrl flags subtree */ + + ti = proto_tree_add_item(pm_tree, hf_mpls_pm_flags, tvb, offset, 1, ENC_NA); + 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_NA); + } else { + proto_tree_add_item(pm_tree, hf_mpls_pm_response_ctrl_code, + tvb, offset, 1, ENC_NA); + } + 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_NA); + 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_NA); + } + 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: + { + nstime_t ts; + ts.secs = tvb_get_ntohl(tvb, offset); + ts.nsecs = tvb_get_ntohl(tvb, offset + 4); + proto_tree_add_time(pm_tree, hf_mpls_pm_origin_timestamp_ptp, tvb, + offset, 8, &ts); + } + 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 void +dissect_mpls_pm_dlm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* the message formats for direct and inferred LM are identical */ + return dissect_mpls_pm_loss(tvb, pinfo, tree, DLM); +} + +static void +dissect_mpls_pm_ilm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* the message formats for direct and inferred LM are identical */ + return dissect_mpls_pm_loss(tvb, pinfo, tree, ILM); +} + +static void +dissect_mpls_pm_delay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_item *ti = NULL; + proto_tree *pm_tree = NULL; + proto_tree *pm_tree_flags = NULL; + guint32 offset = 0; + gboolean query = 0; + gboolean response = 0; + gboolean class_specific = 0; + guint32 sid = 0; + guint8 code = 0; + guint8 qtf = 0; + guint8 rtf = 0; + guint8 i = 0; + + mpls_pm_build_cinfo(tvb, pinfo, + "DM", + &query, &response, &class_specific, &sid, &code); + + if (!tree) { + return; + } + + /* 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_NA); + + /* ctrl flags subtree */ + ti = proto_tree_add_item(pm_tree, hf_mpls_pm_flags, tvb, offset, 1, ENC_NA); + 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_NA); + } else { + proto_tree_add_item(pm_tree, hf_mpls_pm_response_ctrl_code, + tvb, offset, 1, ENC_NA); + } + 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_NA); + } + 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; + } +} + +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 = NULL; + proto_tree *pm_tree_flags = NULL; + proto_tree *pm_tree_dflags = NULL; + guint32 offset = 0; + gboolean query = 0; + gboolean response = 0; + gboolean class_specific = 0; + guint32 sid = 0; + guint8 code = 0; + guint8 qtf = 0; + guint8 rtf = 0; + gboolean bflag = FALSE; + guint8 i = 0; + + mpls_pm_build_cinfo(tvb, pinfo, + val_to_str(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_NA); + + /* ctrl flags subtree */ + ti = proto_tree_add_item(pm_tree, hf_mpls_pm_flags, tvb, offset, 1, ENC_NA); + 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_NA); + } else { + proto_tree_add_item(pm_tree, hf_mpls_pm_response_ctrl_code, + tvb, offset, 1, ENC_NA); + } + 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_NA); + 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_NA); + } + 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 void +dissect_mpls_pm_dlm_dm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* the formats of the DLM+DM and ILM+DM messages are also identical */ + dissect_mpls_pm_combined(tvb, pinfo, tree, DLMDM); +} + +static void +dissect_mpls_pm_ilm_dm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* the formats of the DLM+DM and ILM+DM messages are also identical */ + dissect_mpls_pm_combined(tvb, pinfo, tree, ILMDM); +} + +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, + VALS(dscp_vals), 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_RELATIVE_TIME, BASE_NONE, + 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_RELATIVE_TIME, BASE_NONE, + NULL, 0x0, + NULL, HFILL + } + }, + { + &hf_mpls_pm_timestamp1_r_ntp, + { + "Timestamp 1 (T3)", + "mpls.pm.timestamp1.ntp", + FT_RELATIVE_TIME, BASE_NONE, + 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_null, + { + "Timestamp 2", + "mpls.pm.timestamp2.null", + 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_RELATIVE_TIME, BASE_NONE, + 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_RELATIVE_TIME, BASE_NONE, + 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)); + + register_dissector("mpls_pm_dlm", dissect_mpls_pm_dlm, + proto_mpls_pm_dlm); + + register_dissector("mpls_pm_ilm", dissect_mpls_pm_ilm, + proto_mpls_pm_ilm); + + register_dissector("mpls_pm_dm", dissect_mpls_pm_delay, + proto_mpls_pm_dm); + + register_dissector("mpls_pm_dlm_dm", dissect_mpls_pm_dlm_dm, + proto_mpls_pm_dlm_dm); + + register_dissector("mpls_pm_ilm_dm", dissect_mpls_pm_ilm_dm, + proto_mpls_pm_ilm_dm); +} + +void +proto_reg_handoff_mpls_pm(void) +{ + mpls_pm_dlm_handle = + create_dissector_handle(dissect_mpls_pm_dlm, proto_mpls_pm_dlm); + + mpls_pm_ilm_handle = + create_dissector_handle(dissect_mpls_pm_ilm, proto_mpls_pm_ilm); + + mpls_pm_dm_handle = + create_dissector_handle(dissect_mpls_pm_delay, proto_mpls_pm_dm); + + mpls_pm_dlm_dm_handle = + create_dissector_handle(dissect_mpls_pm_dlm_dm, proto_mpls_pm_dlm_dm); + + mpls_pm_ilm_dm_handle = + create_dissector_handle(dissect_mpls_pm_ilm_dm, proto_mpls_pm_ilm_dm); +} +/* + * Editor modelines - http://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: + */ diff --git a/epan/dissectors/packet-mpls.c b/epan/dissectors/packet-mpls.c index f1e681466d..4d93273b16 100644 --- a/epan/dissectors/packet-mpls.c +++ b/epan/dissectors/packet-mpls.c @@ -115,6 +115,11 @@ static dissector_handle_t dissector_data; static dissector_handle_t dissector_ipv6; static dissector_handle_t dissector_ip; static dissector_handle_t dissector_bfd; +static dissector_handle_t dissector_mpls_pm_dlm; +static dissector_handle_t dissector_mpls_pm_ilm; +static dissector_handle_t dissector_mpls_pm_dm; +static dissector_handle_t dissector_mpls_pm_dlm_dm; +static dissector_handle_t dissector_mpls_pm_ilm_dm; static dissector_handle_t dissector_pw_eth_heuristic; static dissector_handle_t dissector_pw_fr; static dissector_handle_t dissector_pw_hdlc_nocw_fr; @@ -490,6 +495,26 @@ dissect_pw_ach(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { call_dissector(dissector_ipv6, next_tvb, pinfo, tree); } + else if (channel_type == 0x000A) /* FF: MPLS PM, RFC 6374, DLM */ + { + call_dissector(dissector_mpls_pm_dlm, next_tvb, pinfo, tree); + } + else if (channel_type == 0x000B) /* FF: MPLS PM, RFC 6374, ILM */ + { + call_dissector(dissector_mpls_pm_ilm, next_tvb, pinfo, tree); + } + else if (channel_type == 0x000C) /* FF: MPLS PM, RFC 6374, DM */ + { + call_dissector(dissector_mpls_pm_dm, next_tvb, pinfo, tree); + } + else if (channel_type == 0x000D) /* FF: MPLS PM, RFC 6374, DLM+DM */ + { + call_dissector(dissector_mpls_pm_dlm_dm, next_tvb, pinfo, tree); + } + else if (channel_type == 0x000E) /* FF: MPLS PM, RFC 6374, ILM+DM */ + { + call_dissector(dissector_mpls_pm_ilm_dm, next_tvb, pinfo, tree); + } else { call_dissector(dissector_data, next_tvb, pinfo, tree); @@ -1042,6 +1067,11 @@ proto_reg_handoff_mpls(void) dissector_ipv6 = find_dissector("ipv6"); dissector_ip = find_dissector("ip"); dissector_bfd = find_dissector("bfd"); + dissector_mpls_pm_dlm = find_dissector("mpls_pm_dlm"); + dissector_mpls_pm_ilm = find_dissector("mpls_pm_ilm"); + dissector_mpls_pm_dm = find_dissector("mpls_pm_dm"); + dissector_mpls_pm_dlm_dm = find_dissector("mpls_pm_dlm_dm"); + dissector_mpls_pm_ilm_dm = find_dissector("mpls_pm_ilm_dm"); dissector_pw_eth_heuristic = find_dissector("pw_eth_heuristic"); dissector_pw_fr = find_dissector("pw_fr"); dissector_pw_hdlc_nocw_fr = find_dissector("pw_hdlc_nocw_fr"); |