diff options
author | Jaap Keuter <jkeuter@aimvalley.nl> | 2018-12-28 21:45:41 +0100 |
---|---|---|
committer | Jaap Keuter <jaap.keuter@xs4all.nl> | 2018-12-31 10:59:45 +0000 |
commit | 5016cd478e4f09bc2e9521f4b4e67a93f3ff0bdf (patch) | |
tree | b7edfacfe9afcb6519348fd2bfe6c2b3efee6d0b /epan/dissectors | |
parent | 63106bcf60dfcd1b6a95c7d4720e01a60c5d898b (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.txt | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-cesoeth.c | 345 | ||||
-rw-r--r-- | epan/dissectors/packet-rtp.c | 167 | ||||
-rw-r--r-- | epan/dissectors/packet-rtp.h | 6 |
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__*/ |