aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors
diff options
context:
space:
mode:
authorJaap Keuter <jkeuter@aimvalley.nl>2018-12-28 21:45:41 +0100
committerJaap Keuter <jaap.keuter@xs4all.nl>2018-12-31 10:59:45 +0000
commit5016cd478e4f09bc2e9521f4b4e67a93f3ff0bdf (patch)
treeb7edfacfe9afcb6519348fd2bfe6c2b3efee6d0b /epan/dissectors
parent63106bcf60dfcd1b6a95c7d4720e01a60c5d898b (diff)
CESoETH: Add dissection of MEF 8 CES over Ethernet
Add dissection of Metro Ethernet Forum specification of Implementation Agreement for the Emulation of PDH Circuits over Metro Ethernet Networks [MEF 8]. This includes the introduction of a RTP shim header dissection function, as is not uncommon in PW and CES services. Signed-off-by: Jaap Keuter <jaap.keuter@aimvalley.nl> Change-Id: I6de81007ce11793cd5352fadadd80d3f6f45ae0d Reviewed-on: https://code.wireshark.org/review/31239 Petri-Dish: Jaap Keuter <jaap.keuter@xs4all.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Jaap Keuter <jaap.keuter@xs4all.nl>
Diffstat (limited to 'epan/dissectors')
-rw-r--r--epan/dissectors/CMakeLists.txt1
-rw-r--r--epan/dissectors/packet-cesoeth.c345
-rw-r--r--epan/dissectors/packet-rtp.c167
-rw-r--r--epan/dissectors/packet-rtp.h6
4 files changed, 519 insertions, 0 deletions
diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt
index a12eab352b..331bf75c21 100644
--- a/epan/dissectors/CMakeLists.txt
+++ b/epan/dissectors/CMakeLists.txt
@@ -776,6 +776,7 @@ set(DISSECTOR_SRC
${CMAKE_CURRENT_SOURCE_DIR}/packet-cell_broadcast.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-cemi.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-ceph.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet-cesoeth.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-cfdp.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-cfm.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-cgmp.c
diff --git a/epan/dissectors/packet-cesoeth.c b/epan/dissectors/packet-cesoeth.c
new file mode 100644
index 0000000000..4c5e252cf5
--- /dev/null
+++ b/epan/dissectors/packet-cesoeth.c
@@ -0,0 +1,345 @@
+/* packet-cesoeth.c
+ * Dissection of Circuit Emulation Service over Ethernet (MEF 8)
+ * www.mef.net
+ *
+ * Copyright 2018, AimValley B.V.
+ * Jaap Keuter <jkeuter@aimvalley.nl>
+ *
+ * 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 <epan/prefs.h>
+#include <epan/expert.h>
+#include <epan/etypes.h>
+#include <epan/dissectors/packet-rtp.h>
+
+static int proto_cesoeth = -1;
+static int hf_cesoeth_pw_ecid = -1;
+static int hf_cesoeth_pw_res = -1;
+static int hf_cesoeth_cw = -1;
+static int hf_cesoeth_cw_reserved1 = -1;
+static int hf_cesoeth_cw_l = -1;
+static int hf_cesoeth_cw_r = -1;
+static int hf_cesoeth_cw_l0_m = -1;
+static int hf_cesoeth_cw_l1_m = -1;
+static int hf_cesoeth_cw_frg = -1;
+static int hf_cesoeth_cw_len = -1;
+static int hf_cesoeth_cw_seq = -1;
+static int hf_cesoeth_padding = -1;
+
+static gint ett_cesoeth = -1;
+static gint ett_cesoeth_cw = -1;
+
+static expert_field ei_cesoeth_reserved = EI_INIT;
+static expert_field ei_cesoeth_length = EI_INIT;
+
+static const int* cesoeth_l0_cw[] =
+{
+ &hf_cesoeth_cw_reserved1,
+ &hf_cesoeth_cw_l,
+ &hf_cesoeth_cw_r,
+ &hf_cesoeth_cw_l0_m,
+ &hf_cesoeth_cw_frg,
+ &hf_cesoeth_cw_len,
+ &hf_cesoeth_cw_seq,
+ NULL
+};
+
+static const int* cesoeth_l1_cw[] =
+{
+ &hf_cesoeth_cw_reserved1,
+ &hf_cesoeth_cw_l,
+ &hf_cesoeth_cw_r,
+ &hf_cesoeth_cw_l1_m,
+ &hf_cesoeth_cw_frg,
+ &hf_cesoeth_cw_len,
+ &hf_cesoeth_cw_seq,
+ NULL
+};
+
+static const value_string frg_names[] =
+{
+ { 0, "No fragmentation" },
+ { 1, "First fragment" },
+ { 2, "Last fragment" },
+ { 3, "Intermediate fragment" },
+ { 0, NULL }
+};
+
+static const value_string l0_m_names[] =
+{
+ { 0, "No local TDM defect" },
+ { 1, "Reserved" },
+ { 2, "RDI on TDM input" },
+ { 3, "Non-TDM data" },
+ { 0, NULL }
+};
+
+static const value_string l1_m_names[] =
+{
+ { 0, "TDM defect" },
+ { 1, "Reserved" },
+ { 2, "Reserved" },
+ { 3, "Reserved" },
+ { 0, NULL }
+};
+
+/* Preferences */
+static gboolean has_rtp_header = FALSE;
+static gboolean heuristic_rtp_header = TRUE;
+
+
+static int
+dissect_cesoeth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ proto_tree *cesoeth_tree;
+ proto_item *cesoeth_ti;
+ proto_item *bitmask_ti;
+ int offset = 0;
+ guint32 ecid, reserved;
+ gboolean l_bit, r_bit;
+ guint8 m_bits, frg;
+ gint cw_len, padding_len, tail_len, payload_len;
+ guint16 sn;
+ tvbuff_t *next_tvb;
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CESoETH");
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ cesoeth_ti = proto_tree_add_item(tree, proto_cesoeth, tvb, 0, -1, ENC_NA);
+ cesoeth_tree = proto_item_add_subtree(cesoeth_ti, ett_cesoeth);
+
+ proto_tree_add_item_ret_uint(cesoeth_tree, hf_cesoeth_pw_ecid, tvb, offset, 4, ENC_BIG_ENDIAN, &ecid);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "ECID: 0x%05x", ecid);
+ bitmask_ti = proto_tree_add_item_ret_uint(cesoeth_tree, hf_cesoeth_pw_res, tvb, offset, 4, ENC_BIG_ENDIAN, &reserved);
+ if (reserved != 0x102)
+ expert_add_info_format(pinfo, bitmask_ti, &ei_cesoeth_reserved, "Reserved field must be 0x102");
+ offset += 4;
+
+ /*
+ * CES header control word
+ *
+ * bits name description
+ * 31-28 reserved set to 0
+ * 27 L-bit set to 1 to indicate local TDM failure
+ * 26 R-bit set to 1 to indicate remote loss of frame
+ * 25-24 M-bits modifier bits
+ * 23-22 FRG bits fragmentation bits
+ * 21-16 length length (0 if no padding applied)
+ * 15-0 sequence sequence number
+ */
+
+ l_bit = (tvb_get_guint8(tvb, offset) & 0x08) ? TRUE : FALSE;
+ r_bit = (tvb_get_guint8(tvb, offset) & 0x04) ? TRUE : FALSE;
+ m_bits = (tvb_get_guint8(tvb, offset) & 0x03);
+ frg = tvb_get_bits8(tvb, 40, 2);
+ cw_len = tvb_get_bits8(tvb, 42, 6);
+ sn = tvb_get_ntohs(tvb, offset + 2);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", SN: %u", sn);
+
+ if (l_bit)
+ {
+ bitmask_ti = proto_tree_add_bitmask(cesoeth_tree, tvb, offset, hf_cesoeth_cw, ett_cesoeth_cw, cesoeth_l1_cw, ENC_NA);
+ col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s", val_to_str_const(m_bits, l1_m_names, "Unknown"));
+ } else {
+ bitmask_ti = proto_tree_add_bitmask(cesoeth_tree, tvb, offset, hf_cesoeth_cw, ett_cesoeth_cw, cesoeth_l0_cw, ENC_NA);
+ if (m_bits)
+ col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s", val_to_str_const(m_bits, l0_m_names, "Unknown"));
+ }
+
+ if (cw_len >= 42)
+ {
+ /*
+ * Now we have to go spelunking in the bitmask tree for the length item
+ * in order to add an expert item to it.
+ */
+ proto_tree *bm_tree = proto_item_get_subtree(bitmask_ti);
+ if (bm_tree) {
+ proto_item *pi;
+
+ for (pi = tree->first_child; pi; pi = pi->next)
+ {
+ field_info *fi;
+ fi = PITEM_FINFO(pi);
+ if (fi && (fi->hfinfo->id == hf_cesoeth_cw_len))
+ break;
+ }
+
+ expert_add_info_format(pinfo, pi, &ei_cesoeth_length, "Length can not be 42 or larger");
+ }
+
+ cw_len = 0; /* Put a stop to this madness */
+ }
+
+ if (r_bit)
+ col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Remote loss of frame");
+
+ if (frg)
+ col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s", val_to_str_const(frg, frg_names, "Unknown"));
+
+ offset += 4;
+
+ /*
+ * When L is set the TDM payload MAY be missing.
+ * But also when snap value is used on capture.
+ * Will the optional RTP header be there when the TDM payload is missing? I guess so.
+ * Length includes the size of the CW (being 4), the optional RTP header (being 12) and
+ * the TDM payload, as long as it doesn't exceed 42 octets. Length > 0 indicates padding,
+ * which must NOT be passed to the RTP dissector, it's not RTP padding.
+ */
+
+ padding_len = (cw_len > 0) ? (42 - cw_len) : 0;
+ tail_len = tvb_reported_length_remaining(tvb, offset);
+ payload_len = tail_len - padding_len;
+
+ if (payload_len > 0)
+ {
+ next_tvb = tvb_new_subset_length(tvb, offset, payload_len);
+
+ if ((has_rtp_header) ||
+ ((heuristic_rtp_header) &&
+ /* Check for RTP version 2, the other fields must be zero */
+ (tvb_get_guint8(tvb, offset) == 0x80) &&
+ /* Check the marker is zero. Unfortnately PT is not always from the dynamic range */
+ ((tvb_get_guint8(tvb, offset + 1) & 0x80) == 0) &&
+ /* The sequence numbers from cw and RTP header must match */
+ (tvb_get_ntohs(tvb, offset + 2) == sn)))
+ {
+ struct _rtp_info rtp_info;
+
+ gint rtp_header_len = dissect_rtp_shim_header(tvb, offset, pinfo, cesoeth_tree, &rtp_info);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CESoETH (w RTP)");
+ col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "RTP PT: %u, SSRC: 0x%X, Seq: %u, Time=%u",
+ rtp_info.info_payload_type,
+ rtp_info.info_sync_src,
+ rtp_info.info_seq_num,
+ rtp_info.info_timestamp
+ );
+
+ next_tvb = tvb_new_subset_length(tvb, offset + rtp_header_len, payload_len - rtp_header_len);
+ }
+
+ call_data_dissector(next_tvb, pinfo, tree);
+
+ offset += payload_len;
+ }
+
+ if (padding_len > 0)
+ {
+ proto_tree_add_item(cesoeth_tree, hf_cesoeth_padding, tvb, offset, padding_len, ENC_NA);
+
+ offset += padding_len;
+ }
+
+ return offset;
+}
+
+void
+proto_register_cesoeth(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_cesoeth_pw_ecid,
+ { "ECID", "cesoeth.ecid", FT_UINT32, BASE_HEX,
+ NULL, 0xFFFFF000, NULL, HFILL }},
+ { &hf_cesoeth_pw_res,
+ { "Reserved", "cesoeth.res", FT_UINT32, BASE_HEX,
+ NULL, 0x00000FFF, "Reserved (0x102)", HFILL }},
+
+ { &hf_cesoeth_cw,
+ { "Control word", "cesoeth.cw", FT_UINT32, BASE_HEX,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_cesoeth_cw_reserved1,
+ { "Reserved", "cesoeth.cw.reserved", FT_UINT32, BASE_HEX,
+ NULL, 0xF0000000, NULL, HFILL }},
+ { &hf_cesoeth_cw_l,
+ { "L-bit", "cesoeth.cw.l", FT_BOOLEAN, 32,
+ NULL, 0x08000000, "Local TDM failure", HFILL }},
+ { &hf_cesoeth_cw_r,
+ { "R-bit", "cesoeth.cw.r", FT_BOOLEAN, 32,
+ NULL, 0x04000000, "Remote Loss of Frames indication", HFILL }},
+ { &hf_cesoeth_cw_l0_m,
+ { "M-bits", "cesoeth.cw.m", FT_UINT32, BASE_HEX,
+ VALS(l0_m_names), 0x03000000, "Modifier bits", HFILL }},
+ { &hf_cesoeth_cw_l1_m,
+ { "M-bits", "cesoeth.cw.m", FT_UINT32, BASE_HEX,
+ VALS(l1_m_names), 0x03000000, "Modifier bits", HFILL }},
+ { &hf_cesoeth_cw_frg,
+ { "Frg", "cesoeth.cw.frg", FT_UINT32, BASE_HEX,
+ VALS(frg_names), 0x00C00000, "Fragmentation bits", HFILL }},
+ { &hf_cesoeth_cw_len,
+ { "Len", "cesoeth.cw.len", FT_UINT32, BASE_DEC,
+ NULL, 0x003F0000, "Length", HFILL }},
+ { &hf_cesoeth_cw_seq,
+ { "SN", "cesoeth.cw.sn", FT_UINT32, BASE_DEC,
+ NULL, 0x0000FFFF, "Sequence number", HFILL }},
+
+ { &hf_cesoeth_padding,
+ { "Padding", "cesoeth.padding", FT_BYTES, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }}
+ };
+
+ static gint *ett[] = {
+ &ett_cesoeth,
+ &ett_cesoeth_cw
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_cesoeth_reserved,
+ { "cesoeth.reserved", PI_PROTOCOL, PI_WARN,
+ "Reserved field", EXPFILL }},
+ { &ei_cesoeth_length,
+ { "cesoeth.length", PI_PROTOCOL, PI_WARN,
+ "Length field", EXPFILL }}
+ };
+
+ module_t *cesoeth_module;
+ expert_module_t* expert_cesoeth;
+
+ proto_cesoeth = proto_register_protocol("Circuit Emulation Service over Ethernet", "CESoETH", "cesoeth");
+ proto_register_field_array(proto_cesoeth, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_cesoeth = expert_register_protocol(proto_cesoeth);
+ expert_register_field_array(expert_cesoeth, ei, array_length(ei));
+
+ cesoeth_module = prefs_register_protocol(proto_cesoeth, NULL);
+
+ prefs_register_bool_preference(cesoeth_module, "rtp_header", "RTP header in CES payload",
+ "Whether or not the RTP header is present in the CES payload.", &has_rtp_header);
+
+ prefs_register_bool_preference(cesoeth_module, "rtp_header_heuristic", "Try to find RTP header in CES payload",
+ "Heuristically determine if an RTP header is present in the CES payload.", &heuristic_rtp_header);
+
+}
+
+void
+proto_reg_handoff_cesoeth(void)
+{
+ dissector_handle_t cesoeth_handle;
+
+ cesoeth_handle = create_dissector_handle(dissect_cesoeth, proto_cesoeth);
+
+ dissector_add_uint("ethertype", ETHERTYPE_CESOETH, cesoeth_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:
+ */
diff --git a/epan/dissectors/packet-rtp.c b/epan/dissectors/packet-rtp.c
index c803f7544a..67698961da 100644
--- a/epan/dissectors/packet-rtp.c
+++ b/epan/dissectors/packet-rtp.c
@@ -2305,6 +2305,173 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
return offset;
}
+gint
+dissect_rtp_shim_header(tvbuff_t *tvb, gint start, packet_info *pinfo _U_, proto_tree *tree, struct _rtp_info *rtp_info)
+{
+ proto_item *rtp_ti = NULL;
+ proto_tree *rtp_tree = NULL;
+ proto_item *ti;
+ guint8 octet1, octet2;
+ unsigned int version;
+ gboolean padding_set;
+ gboolean extension_set;
+ unsigned int csrc_count;
+ gboolean marker_set;
+ unsigned int payload_type;
+ unsigned int i;
+ gint offset = start;
+ guint16 seq_num;
+ guint32 timestamp;
+ guint32 sync_src;
+ const char *pt = NULL;
+ static const int * octet1_fields[] = {
+ &hf_rtp_version,
+ &hf_rtp_padding,
+ &hf_rtp_extension,
+ &hf_rtp_csrc_count,
+ NULL
+ };
+
+ /* Get the fields in the first octet */
+ octet1 = tvb_get_guint8( tvb, offset );
+ version = RTP_VERSION( octet1 );
+
+ /* fill in the rtp_info structure */
+ if (rtp_info) rtp_info->info_version = version;
+ if (version != 2) {
+ /*
+ * Unknown or unsupported version.
+ */
+ if ( tree ) {
+ ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, 1, ENC_NA );
+ rtp_tree = proto_item_add_subtree( ti, ett_rtp );
+
+ proto_tree_add_uint( rtp_tree, hf_rtp_version, tvb,
+ offset, 1, octet1);
+ }
+ return offset;
+ }
+
+ padding_set = RTP_PADDING( octet1 );
+ extension_set = RTP_EXTENSION( octet1 );
+ csrc_count = RTP_CSRC_COUNT( octet1 );
+
+ /* Get the fields in the second octet */
+ octet2 = tvb_get_guint8( tvb, offset + 1 );
+ marker_set = RTP_MARKER( octet2 );
+ payload_type = RTP_PAYLOAD_TYPE( octet2 );
+
+ /* Get the subsequent fields */
+ seq_num = tvb_get_ntohs( tvb, offset + 2 );
+ timestamp = tvb_get_ntohl( tvb, offset + 4 );
+ sync_src = tvb_get_ntohl( tvb, offset + 8 );
+
+ /* fill in the rtp_info structure */
+ if (rtp_info) {
+ rtp_info->info_padding_set = padding_set;
+ rtp_info->info_padding_count = 0;
+ rtp_info->info_marker_set = marker_set;
+ rtp_info->info_media_types = 0;
+ rtp_info->info_payload_type = payload_type;
+ rtp_info->info_seq_num = seq_num;
+ rtp_info->info_timestamp = timestamp;
+ rtp_info->info_sync_src = sync_src;
+ rtp_info->info_data_len = 0;
+ rtp_info->info_all_data_present = FALSE;
+ rtp_info->info_payload_offset = 0;
+ rtp_info->info_payload_len = 0;
+ rtp_info->info_is_srtp = FALSE;
+ rtp_info->info_setup_frame_num = 0;
+ rtp_info->info_data = NULL;
+ rtp_info->info_payload_type_str = NULL;
+ rtp_info->info_payload_rate = 0;
+ rtp_info->info_is_ed137 = FALSE;
+ rtp_info->info_ed137_info = NULL;
+ }
+
+ if ( tree ) {
+ /* Create RTP protocol tree */
+ rtp_ti = proto_tree_add_item(tree, proto_rtp, tvb, offset, 0, ENC_NA );
+ rtp_tree = proto_item_add_subtree(rtp_ti, ett_rtp );
+
+ proto_tree_add_bitmask_list(rtp_tree, tvb, offset, 1, octet1_fields, ENC_NA);
+ offset++;
+
+ proto_tree_add_boolean( rtp_tree, hf_rtp_marker, tvb, offset,
+ 1, octet2 );
+
+ pt = val_to_str_ext(payload_type, &rtp_payload_type_vals_ext, "Unknown (%u)");
+
+ proto_tree_add_uint_format( rtp_tree, hf_rtp_payload_type, tvb,
+ offset, 1, octet2, "Payload type: %s (%u)", pt, payload_type);
+
+ offset++;
+
+ /* Sequence number 16 bits (2 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_seq_nr, tvb, offset, 2, seq_num );
+ offset += 2;
+
+ /* Timestamp 32 bits (4 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_timestamp, tvb, offset, 4, timestamp );
+ offset += 4;
+
+ /* Synchronization source identifier 32 bits (4 octets) */
+ proto_tree_add_uint( rtp_tree, hf_rtp_ssrc, tvb, offset, 4, sync_src );
+ offset += 4;
+ } else {
+ offset += 12;
+ }
+ /* CSRC list*/
+ if ( csrc_count > 0 ) {
+ proto_tree *rtp_csrc_tree;
+ guint32 csrc_item;
+ ti = proto_tree_add_item(rtp_tree, hf_rtp_csrc_items, tvb, offset,
+ csrc_count * 4, ENC_NA);
+ proto_item_append_text(ti, " (%u items)", csrc_count);
+ rtp_csrc_tree = proto_item_add_subtree( ti, ett_csrc_list );
+
+ for (i = 0; i < csrc_count; i++ ) {
+ csrc_item = tvb_get_ntohl( tvb, offset );
+ proto_tree_add_uint_format( rtp_csrc_tree,
+ hf_rtp_csrc_item, tvb, offset, 4,
+ csrc_item,
+ "CSRC item %d: 0x%X",
+ i, csrc_item );
+ offset += 4;
+ }
+ }
+
+ /* Optional RTP header extension */
+ if ( extension_set ) {
+ unsigned int hdr_extension_len;
+ unsigned int hdr_extension_id;
+
+ /* Defined by profile field is 16 bits (2 octets) */
+ hdr_extension_id = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( rtp_tree, hf_rtp_prof_define, tvb, offset, 2, hdr_extension_id );
+ offset += 2;
+
+ hdr_extension_len = tvb_get_ntohs( tvb, offset );
+ proto_tree_add_uint( rtp_tree, hf_rtp_length, tvb, offset, 2, hdr_extension_len);
+ offset += 2;
+ if ( hdr_extension_len > 0 ) {
+ proto_tree *rtp_hext_tree = NULL;
+
+ ti = proto_tree_add_item(rtp_tree, hf_rtp_hdr_exts, tvb, offset, hdr_extension_len * 4, ENC_NA);
+ rtp_hext_tree = proto_item_add_subtree( ti, ett_hdr_ext );
+
+ for ( i = 0; i < hdr_extension_len; i++ ) {
+ proto_tree_add_item( rtp_hext_tree, hf_rtp_hdr_ext, tvb, offset, 4, ENC_BIG_ENDIAN );
+ offset += 4;
+ }
+ }
+ }
+
+ proto_item_set_len(rtp_ti, offset - start);
+
+ return (offset - start);
+}
+
/* calculate the extended sequence number - top 16 bits of the previous sequence number,
* plus our own; then correct for wrapping */
static guint32
diff --git a/epan/dissectors/packet-rtp.h b/epan/dissectors/packet-rtp.h
index 197d4cd4b3..d8b1beee5d 100644
--- a/epan/dissectors/packet-rtp.h
+++ b/epan/dissectors/packet-rtp.h
@@ -219,4 +219,10 @@ bluetooth_add_address(packet_info *pinfo, address *addr, guint32 stream_number,
const gchar *setup_method, guint32 setup_frame_number,
guint32 media_types, void *data);
+/* Dissect the header only, without side effects */
+WS_DLL_PUBLIC
+gint dissect_rtp_shim_header(tvbuff_t *tvb, gint start,
+ packet_info *pinfo, proto_tree *tree,
+ struct _rtp_info *rtp_info);
+
#endif /*__PACKET_RTP_H__*/