aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis Colmenero <colmenero@rti.com>2020-10-07 22:30:16 +0200
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-04-27 06:15:42 +0000
commit3cdbbcdfb93ecd8df79f3ac76e4b00c0e743cc77 (patch)
tree1ee23f37b7bdffd6ef2ed8ab4bcb3e5aed9b299e
parent2549e51ee4720262c66b97ffd9e0a329eb340eea (diff)
RTPS-VT: New dissector to enhance the RTPS protocol
Added dissectors for RTPS Virtual Transport and RTPS Processed Protocols RTI Connext DDS can capture RTPS-related traffic by using the Network Capture Utility. The generated .pcap capture files will follow these protocols, establishing a format for how information must be saved, and then parsed. This will improve debuggability by including additional information obtained from within Connext DDS. RTPS-VT parses the information related to the transport. It then, calls the RTPS-PROC dissector, which handles the rest: calling the RTPS dissector when needed, and parsing additional information such as the one related to security.
-rw-r--r--epan/dissectors/CMakeLists.txt2
-rw-r--r--epan/dissectors/packet-rtps-processed.c450
-rw-r--r--epan/dissectors/packet-rtps-virtual-transport.c1207
-rw-r--r--epan/dissectors/packet-rtps.c63
-rw-r--r--epan/dissectors/packet-rtps.h70
5 files changed, 1760 insertions, 32 deletions
diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt
index a942ea63a1..2726b2bb40 100644
--- a/epan/dissectors/CMakeLists.txt
+++ b/epan/dissectors/CMakeLists.txt
@@ -1693,6 +1693,8 @@ set(DISSECTOR_SRC
${CMAKE_CURRENT_SOURCE_DIR}/packet-rtp-ed137.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-rtpproxy.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-rtps.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtps-virtual-transport.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet-rtps-processed.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-rtsp.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-rudp.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-rwall.c
diff --git a/epan/dissectors/packet-rtps-processed.c b/epan/dissectors/packet-rtps-processed.c
new file mode 100644
index 0000000000..1fb6fa25b3
--- /dev/null
+++ b/epan/dissectors/packet-rtps-processed.c
@@ -0,0 +1,450 @@
+/* packet-rtps-processed.c
+ * Dissector for the Real-Time Publish-Subscribe (RTPS) Processed Protocol.
+ *
+ * (c) 2020 Copyright, Real-Time Innovations, Inc.
+ * Real-Time Innovations, Inc.
+ * 232 East Java Drive
+ * Sunnyvale, CA 94089
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ * RTI Connext DDS can capture RTPS-related traffic by using the Network Capture
+ * Utility. The generated .pcap capture files will follow a format that
+ * defines how information must be saved, and then parsed.
+ *
+ * The format is divided into two layers/protocols: virtual transport
+ * (packet-rtps-virtual-transport.c) and processed (packet-rtps-processed.c).
+ * This file is about the processed dissector. For a general introduction and
+ * information about the virtual transport dissector, read the documentation at
+ * the beginning of packet-rtps-virtual-transport.c.
+ *
+ * The processed dissector is called by the transport dissector. It should never
+ * be called directly by Wireshark without going through the transport
+ * dissector first.
+ *
+ * The advanced information contains one parameter that it is really important
+ * (and compulsory). This parameter is the "main frame", i.e. the frame that
+ * would usually be captured over the wire. This frame is encrypted if security
+ * applies.
+ *
+ * Then we have two optional fields: advanced frame0 and frame1.
+ * - frame0: Contains the RTPS frame with submessage protection (but
+ * decrypted at the RTPS level).
+ * - frame1:
+ * - Inbound traffic: A list of decrypted RTPS submessages (the protected
+ * ones from frame0).
+ * - Outbound traffic: The RTPS message before any kind of protection.
+ * The contents encrypted at RTPS message level can be found in the main frame.
+ *
+ * We can see there is a difference between frame1 (the parameter containing the
+ * decrypted RTPS submessages): inbound traffic has a list of submessages (no
+ * RTPS header) but outbound traffic has a RTPS message. The reason behind
+ * this is related to how RTI Connext DDS handles protected inbound traffic.
+ *
+ * An alternative would be to build the RTPS message from frame0 and frame1 and
+ * then pass it to the RTPS dissector. This solution would be cleaner but would
+ * require to keep a buffer and information between parameters.
+ * The current solution is kept for the moment.
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/expert.h>
+#include <epan/prefs.h>
+#include <epan/addr_resolv.h>
+#include <epan/wmem/wmem.h>
+#include <epan/conversation.h>
+#include <epan/column.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/dissectors/packet-rtps.h>
+
+#include <stdio.h>
+
+#define PARAM_ID_ADVANCED_FRAME0 0x000C1
+#define PARAM_ID_ADVANCED_FRAME1 0x000C2
+
+void proto_reg_handoff_rtps_processed(void);
+void proto_register_rtps_processed(void);
+static gint dissect_rtps_processed(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree,
+ void *data);
+void get_new_colinfo_w_submessages(
+ wmem_strbuf_t *out,
+ wmem_strbuf_t *frame,
+ const gchar *submessages);
+
+/* Subtree pointers */
+static gint rtpsproc_tree = -1;
+static gint rtpsproc_ett = -1;
+static gint rtpsproc_ett_security = -1;
+static gint rtpsproc_ett_advanced_frame0 = -1;
+static gint rtpsproc_ett_advanced_frame1 = -1;
+
+/* Initialize the protocol and registered fields */
+static header_field_info *rtpsproc_hf = NULL;
+static gint rtpsproc_hf_param_id = -1;
+static gint rtpsproc_hf_param_length = -1;
+
+/* Used for caching a handle to the RTPS dissector */
+static dissector_handle_t rtps_handle = NULL;
+
+/* ========================================================================== */
+/* Dissector */
+/* ========================================================================== */
+/*
+ * Parameters must be in the right order or dissector will fail.
+ * This was done instead of looping for all parameters (like in
+ * packet-rtps-virtual-transport.c) because:
+ * - The number of parameters is small.
+ * - This way we can skip creating some headings if they are not needed (by
+ * using zeros instead).
+ */
+static gint dissect_rtps_processed(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree,
+ void *data)
+{
+ proto_tree *rtpsproc_tree_general = NULL;
+ proto_tree *rtpsproc_tree_security = NULL;
+ proto_item *rtpsproc_ti = NULL;
+ guint16 param_id;
+ guint16 param_length;
+ gint offset = 0;
+ gint offset_version = 4; /* 'R', 'T', 'P', 'S' */
+ tvbuff_t *rtps_payload = NULL;
+ tvbuff_t *message_payload = NULL;
+ struct rtpsvt_data *transport_data = (struct rtpsvt_data *) data;
+ const gchar *title_security = transport_data->direction == 1
+ ? "RTPS Security decoding"
+ : "RTPS Security pre-encoding";
+ guint16 rtps_version = 0x0203;
+ guint16 rtps_vendor_id = 0x0101;
+
+ if (transport_data == NULL) {
+ /* Reject the packet if no transport information */
+ return 0;
+ }
+ param_length = transport_data->rtps_length;
+
+ /* ***************************** MAIN ***********************************/
+ /*
+ * The contents passed to the rtpsproc dissector must start with the RTPS
+ * frame.
+ */
+ rtps_version = tvb_get_guint16(
+ tvb,
+ offset + offset_version,
+ ENC_BIG_ENDIAN);
+ rtps_vendor_id = tvb_get_guint16(
+ tvb,
+ offset + offset_version + 2,
+ ENC_BIG_ENDIAN);
+
+ rtps_payload = tvb_new_subset_length(tvb, offset, param_length);
+ if (rtps_handle != NULL) {
+ call_dissector(rtps_handle, rtps_payload, pinfo, tree);
+ }
+ offset += param_length;
+
+ /* *********** Add subtree used for the fields of our rtpsproc_tree *******/
+ rtpsproc_ti = proto_tree_add_item(
+ tree,
+ rtpsproc_tree,
+ tvb,
+ offset,
+ -1,
+ ENC_BIG_ENDIAN);
+ rtpsproc_tree_general = proto_item_add_subtree(rtpsproc_ti, rtpsproc_ett);
+
+ /* *************************** ADVANCED 0 *******************************/
+ param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ if (param_id == PARAM_ID_ADVANCED_FRAME0) {
+ proto_tree *rtpsproc_tree_frame0 = NULL;
+ param_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN);
+
+ rtpsproc_tree_security = proto_tree_add_subtree_format(
+ rtpsproc_tree_general,
+ tvb,
+ offset,
+ 0,
+ rtpsproc_ett_security,
+ NULL,
+ "%s",
+ title_security);
+
+ rtpsproc_tree_frame0 = proto_tree_add_subtree_format(
+ rtpsproc_tree_security,
+ tvb,
+ offset,
+ 0,
+ rtpsproc_ett_advanced_frame0,
+ NULL,
+ "%s",
+ "RTPS level");
+
+ proto_tree_add_uint(
+ rtpsproc_tree_frame0,
+ rtpsproc_hf_param_id,
+ tvb,
+ offset,
+ 2, /* length */
+ param_id);
+ offset += 2;
+
+ proto_tree_add_uint(
+ rtpsproc_tree_frame0,
+ rtpsproc_hf_param_length,
+ tvb,
+ offset,
+ 2, /* length */
+ param_length);
+ offset += 2;
+
+ message_payload = tvb_new_subset_length(tvb, offset, param_length);
+ if (rtps_handle != NULL) {
+ call_dissector(
+ rtps_handle,
+ message_payload,
+ pinfo,
+ rtpsproc_tree_frame0);
+ }
+ offset += param_length;
+ } else {
+ /*
+ * If there is no security information, param_id is zeroed.
+ * In that case the length is also zero, so we move 4 Bytes in total.
+ */
+ offset += 4;
+ }
+
+ /* *************************** ADVANCED 1 *******************************/
+ param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ if (param_id == PARAM_ID_ADVANCED_FRAME1) {
+ proto_tree *rtpsproc_tree_frame1 = NULL;
+ const gchar *title = transport_data->direction
+ ? "Submessage level"
+ : "RTPS and Submessage level (no protection)";
+ param_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN);
+
+ if (rtpsproc_tree_security == NULL) {
+ rtpsproc_tree_security = proto_tree_add_subtree_format(
+ rtpsproc_tree_general,
+ tvb,
+ offset,
+ 0,
+ rtpsproc_ett_security,
+ NULL,
+ "%s",
+ title_security);
+ }
+
+ rtpsproc_tree_frame1 = proto_tree_add_subtree_format(
+ rtpsproc_tree_security,
+ tvb,
+ offset,
+ 0,
+ rtpsproc_ett_advanced_frame1,
+ NULL,
+ "%s",
+ title);
+
+ proto_tree_add_uint(
+ rtpsproc_tree_frame1,
+ rtpsproc_hf_param_id,
+ tvb,
+ offset,
+ 2, /* length */
+ param_id);
+ offset += 2;
+
+ proto_tree_add_uint(
+ rtpsproc_tree_frame1,
+ rtpsproc_hf_param_length,
+ tvb,
+ offset,
+ 2, /* length */
+ param_length);
+ offset += 2;
+
+ /*
+ * Depending on the direction we have:
+ * - Inbound: List of decrypted submessages.
+ * - Outbound: The RTPS message before any kind of protection.
+ * So, we handle them differently.
+ */
+ if (transport_data->direction) {
+ tvbuff_t *rtps_submessages = NULL;
+ wmem_strbuf_t *info_w_encrypted = NULL; /* Current info */
+ wmem_strbuf_t *info_w_decrypted = NULL; /* New info */
+ /*
+ * Get the current column info. This has the RTPS frames with the
+ * encrypted submessages. We are going to update the text so that
+ * it has the decrypted information, which is more useful to the
+ * user.
+ */
+ if (pinfo->cinfo) {
+ const gchar *colinfo = col_get_text(pinfo->cinfo, COL_INFO);
+ if (colinfo) {
+ info_w_encrypted = wmem_strbuf_new(
+ wmem_packet_scope(),
+ colinfo);
+ col_clear(pinfo->cinfo, COL_INFO);
+ }
+ }
+ /* Dissect the submessages using the RTPS dissector */
+ rtps_submessages = tvb_new_subset_length(tvb, offset, param_length);
+ dissect_rtps_submessages(
+ rtps_submessages,
+ 0, /* offset */
+ pinfo,
+ rtpsproc_tree_frame1,
+ rtps_version,
+ rtps_vendor_id);
+ offset += param_length;
+ /*
+ * Get the decrypted submessages and update the column information.
+ */
+ if (pinfo->cinfo) {
+ const gchar *colinfo = col_get_text(pinfo->cinfo, COL_INFO);
+ info_w_decrypted = wmem_strbuf_new(wmem_packet_scope(), "");
+ if (colinfo) {
+ get_new_colinfo_w_submessages(
+ info_w_decrypted, /* out */
+ info_w_encrypted, /* in */
+ colinfo); /* in */
+ col_clear(pinfo->cinfo, COL_INFO);
+ col_set_str(
+ pinfo->cinfo,
+ COL_INFO,
+ wmem_strbuf_get_str(info_w_decrypted));
+ }
+ }
+ } else {
+ message_payload = tvb_new_subset_length(tvb, offset, param_length);
+ if (rtps_handle != NULL) {
+ call_dissector(
+ rtps_handle,
+ message_payload,
+ pinfo,
+ rtpsproc_tree_frame1);
+ }
+ offset += param_length;
+ }
+ } else {
+ /*
+ * If there is no security information, param_id is zeroed.
+ * In that case the length is also zero, so we move 4 Bytes in total.
+ */
+ offset += 4;
+ }
+ return tvb_captured_length(tvb);
+}
+
+/* ========================================================================== */
+/* Other */
+/* ========================================================================== */
+
+/*
+ * This function is called at startup and caches the handle for the register.
+ * That way we don't have to find the dissector for each packet.
+ */
+void proto_reg_handoff_rtps_processed(void)
+{
+ rtps_handle = find_dissector("rtps");
+}
+
+void get_new_colinfo_w_submessages(
+ wmem_strbuf_t *out,
+ wmem_strbuf_t *frame,
+ const gchar *submessages)
+{
+ const gchar *pattern = "SEC_PREFIX, SEC_BODY, SEC_POSTFIX";
+ const gchar *frame_str = wmem_strbuf_get_str(frame);
+ gsize idx = 0; /* index for iterating frame_str */
+ gchar *submessages_dup = g_strdup(submessages);
+ /* First decrypted submessage in submessages list */
+ gchar *submessage_current = strtok(submessages_dup, ", ");
+ /* First encrypted submessage. Found by searching the RTPS colinfo */
+ gchar *encrypted_current = strstr(&frame_str[idx], pattern);
+
+ while (encrypted_current != NULL) {
+ /* Copy the RTPS frame up to the newly found encrypted submessage */
+ gsize length_to_copy = encrypted_current - &frame_str[idx];
+ wmem_strbuf_append_len(out, &frame_str[idx], length_to_copy);
+
+ /* Copy the decrypted contents that replace the encrypted submessage */
+ wmem_strbuf_append(out, submessage_current);
+
+ /* Advance the index and continue searching */
+ idx += length_to_copy + strlen(pattern);
+ encrypted_current = strstr(&frame_str[idx], pattern);
+ }
+ /* Copy the remaining from the RTPS frame */
+ wmem_strbuf_append(out, &frame_str[idx]);
+}
+
+/* ========================================================================== */
+/* Protocol egistration */
+/* ========================================================================== */
+void
+proto_register_rtps_processed(void)
+{
+ static hf_register_info hf[] = {
+ {
+ &rtpsproc_hf_param_id,
+ {
+ "Parameter Identifier", "rtpsproc.param.id",
+ FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL
+ },
+ },
+ {
+ &rtpsproc_hf_param_length,
+ {
+ "Parameter Length", "rtpsproc.param.length",
+ FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL
+ }
+ },
+ };
+ static gint *ett[] = {
+ &rtpsproc_ett,
+ &rtpsproc_ett_security,
+ &rtpsproc_ett_advanced_frame0,
+ &rtpsproc_ett_advanced_frame1
+ };
+
+ /* Register the protocol name and description */
+ rtpsproc_tree = proto_register_protocol(
+ "Real-Time Publish-Subscribe Wire Protocol (processed)",
+ "RTPS-PROC",
+ "rtpsproc");
+
+ /* Required function calls to register the header fields and subtrees */
+ rtpsproc_hf = proto_registrar_get_nth(rtpsproc_tree);
+ proto_register_field_array(rtpsproc_tree, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ register_dissector("rtpsproc", dissect_rtps_processed, rtpsproc_tree);
+}
+
+// /*
+// * 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-rtps-virtual-transport.c b/epan/dissectors/packet-rtps-virtual-transport.c
new file mode 100644
index 0000000000..e4785fb473
--- /dev/null
+++ b/epan/dissectors/packet-rtps-virtual-transport.c
@@ -0,0 +1,1207 @@
+/* packet-rtps-virtual-transport.c
+ * Dissector for the Real-Time Publish-Subscribe (RTPS) Virtual Transport
+ * Protocol.
+ *
+ * (c) 2020 Copyright, Real-Time Innovations, Inc.
+ * Real-Time Innovations, Inc.
+ * 232 East Java Drive
+ * Sunnyvale, CA 94089
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ * RTI Connext DDS can capture RTPS-related traffic by using the Network Capture
+ * Utility. The generated .pcap capture files will follow the RTPS-VT protocol,
+ * which establishes a format for how information must be saved, and then
+ * parsed.
+ *
+ * The protocol is divided into two layers: transport
+ * (packet-rtps-virtual-transport.c) and advanced (packet-rtps-processed.c).
+ * This file is about the transport dissector. For more information about the
+ * advanced dissector, read the documentation at the beginning of
+ * packet-rtps-processed.c.
+ *
+ * Every packet saved in the capture file follows the PCAP file format.
+ * As a consequence, there are two headers: a global one (unique per file) and
+ * a per-packet header. These headers have the typical content described in the
+ * PCAP format: a magic number, version number, some timestamps, information
+ * describing the length of the packet and the data link layer (0x000000fc, i.e.
+ * custom protocol), etc. Then, we have a header that indicates Wireshark the
+ * name of the protocol: "rtpsvt". The transport dissector is called when
+ * Wireshark finds "rtpsvt" as the protocol name.
+ *
+ * After the RTPS-VT header, we have the frame type. The frame type determines
+ * what kind of information has the dumped packet. RTPS-VT data comes as a
+ * series of [parameter identifier, content length, content]. Depending on the
+ * type of frame (RTPS or lossInfo), the dissector will expect some parameters
+ * or others.
+ *
+ * If the frame type is RTPS, we will continue parsing transport-layer data.
+ * The transport layer contains all information about the source and destination
+ * of a packet. This corresponds to data typically found on Network or Transport
+ * protocols. However, because RTI Connext DDS generates the capture file
+ * directly at application-level, this information is added at the moment of
+ * writing the capture file.
+ * After the transport-layer information, we will call the advanced dissector.
+ *
+ * If the frame type is lossInfo, the dissector will generate a packet
+ * indicating that there were missing frames (and the range of sequence
+ * numbers).
+ */
+#include "config.h"
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/expert.h>
+#include <epan/prefs.h>
+#include <epan/addr_resolv.h>
+#include <epan/wmem/wmem.h>
+#include <epan/conversation.h>
+#include <epan/column.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/dissectors/packet-rtps.h>
+
+#include <stdio.h>
+
+#define CONTENT_KIND_RTPS 0x01
+#define CONTENT_KIND_LOSS_INFO 0x02
+
+#define PARAM_ID_TRANSPORT_CLASS 0x0001
+#define PARAM_ID_MONITORING_GUID 0x0002
+#define PARAM_ID_MONITORING_SN 0x0003
+#define PARAM_ID_SOURCE_IP_ADDRESS 0x0004
+#define PARAM_ID_SOURCE_PORT 0x0005
+#define PARAM_ID_DESTINATION_IP_ADDRESS 0x0006
+#define PARAM_ID_DESTINATION_RTPS_PORT 0x0007
+#define PARAM_ID_DESTINATION_PORT 0x0008
+#define PARAM_ID_DIRECTION 0x0009
+#define FIRST_PARAM_ID_RTPS PARAM_ID_TRANSPORT_CLASS
+#define LAST_PARAM_ID_RTPS PARAM_ID_DIRECTION
+
+/* First parameter Identifier that the "rtpsproc" protocol accepts */
+#define PARAM_ID_MAIN_FRAME 0x00C0
+
+#define PARAM_ID_LOST_MESSAGES 0x0001
+
+void proto_register_rtps_virtual_transport(void);
+static gint dissect_rtps_virtual_transport(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree,
+ void *data _U_);
+static gint dissect_rtps_virtual_transport_rtps_type(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree,
+ proto_tree *tree_transport,
+ gint offset,
+ struct rtpsvt_data *transport_data);
+static gint dissect_parameter_transport_rtps_type(
+ tvbuff_t *tvb,
+ proto_tree *rtpsvt_tree_general,
+ proto_tree *rtpsvt_tree_identifier,
+ proto_tree *rtpsvt_tree_information,
+ gint offset,
+ packet_info *pinfo,
+ struct rtpsvt_data *transport_data);
+static gint dissect_rtps_virtual_transport_loss_info_type(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree_transport,
+ gint offset);
+
+/* Subtree pointers */
+static gint proto_rtpsvt = -1;
+static gint rtpsvt_ett = -1;
+static gint rtpsvt_ett_version = -1;
+static gint rtpsvt_ett_identifier = -1;
+static gint rtpsvt_ett_information = -1;
+static gint rtpsvt_ett_information_class = -1;
+static gint rtpsvt_ett_information_src_port = -1;
+static gint rtpsvt_ett_information_dst_port = -1;
+static gint rtpsvt_ett_information_src_addr = -1;
+static gint rtpsvt_ett_information_dst_addr = -1;
+static gint rtpsvt_ett_information_direction = -1;
+static gint rtpsvt_ett_monitoring_sn = -1;
+static gint rtpsvt_ett_frame = -1;
+
+/* Initialize the protocol and registered fields */
+static header_field_info *rtpsvt_hf = NULL;
+static gint rtpsvt_hf_version = -1;
+static gint rtpsvt_hf_version_major = -1;
+static gint rtpsvt_hf_version_minor = -1;
+static gint rtpsvt_hf_content_kind = -1;
+static gint rtpsvt_hf_param_id = -1;
+static gint rtpsvt_hf_param_length = -1;
+static gint rtpsvt_hf_packet_identifier = -1;
+static gint rtpsvt_hf_monitoring_guid = -1;
+static gint rtpsvt_hf_monitoring_seqNr = -1;
+static gint rtpsvt_hf_information = -1;
+static gint rtpsvt_hf_class = -1;
+static gint rtpsvt_hf_source_port = -1;
+static gint rtpsvt_hf_source_address = -1;
+static gint rtpsvt_hf_source_pid = -1;
+static gint rtpsvt_hf_destination_port = -1;
+static gint rtpsvt_hf_destination_rtps_port = -1;
+static gint rtpsvt_hf_destination_address = -1;
+static gint rtpsvt_hf_direction = -1;
+static gint rtpsvt_hf_destination_pid = -1;
+static gint rtpsvt_hf_missing_messages = -1;
+
+/* expert info fields */
+static expert_field ei_missing_msg = EI_INIT;
+
+/* Vendor specific: RTI */
+static const value_string ndds_transport_class_id_vals[] = {
+ { NDDS_TRANSPORT_CLASSID_ANY, "ANY" },
+ { NDDS_TRANSPORT_CLASSID_UDPv4, "UDPv4" },
+ { NDDS_TRANSPORT_CLASSID_UDPv4_WAN, "UDPv4_WAN"},
+ { NDDS_TRANSPORT_CLASSID_SHMEM, "SHMEM" },
+ { NDDS_TRANSPORT_CLASSID_INTRA, "INTRA" },
+ { NDDS_TRANSPORT_CLASSID_UDPv6, "UDPv6" },
+ { NDDS_TRANSPORT_CLASSID_DTLS, "DTLS" },
+ { NDDS_TRANSPORT_CLASSID_WAN, "WAN" },
+ { NDDS_TRANSPORT_CLASSID_TCPV4_LAN, "TCPv4_LAN" },
+ { NDDS_TRANSPORT_CLASSID_TCPV4_WAN, "TCPv4_WAN" },
+ { NDDS_TRANSPORT_CLASSID_TLSV4_LAN, "TLSv4_LAN" },
+ { NDDS_TRANSPORT_CLASSID_TLSV4_WAN, "TLSv4_WAN" },
+ { NDDS_TRANSPORT_CLASSID_PCIE, "PCIE" },
+ { NDDS_TRANSPORT_CLASSID_ITP, "ITP" },
+ { 0, NULL }
+};
+
+static gint dissect_rtps_virtual_transport(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree,
+ void *data _U_)
+{
+ proto_tree *rtpsvt_tree_transport;
+ proto_item *rtpsvt_ti_transport;
+ proto_item *rtpsvt_ti_version;
+ proto_tree *rtpsvt_tree_version;
+ proto_item *rtpsvt_ti_content_kind;
+ struct rtpsvt_data transport_data;
+ guint16 version;
+ guint8 content_type;
+ const gchar *content_type_label;
+ gint offset = 0;
+ gint output = 0;
+
+ /* Add transport tree, used for the fields of our proto_rtpsvt */
+ rtpsvt_ti_transport = proto_tree_add_item(
+ tree,
+ proto_rtpsvt,
+ tvb,
+ offset,
+ -1,
+ ENC_BIG_ENDIAN);
+ rtpsvt_tree_transport = proto_item_add_subtree(rtpsvt_ti_transport, rtpsvt_ett);
+
+ /* Add the version to the transport protocol */
+ version = tvb_get_ntohs(tvb, offset);
+ transport_data.version_major = version >> 8;
+ transport_data.version_minor = version & 0xff;
+ rtpsvt_ti_version = proto_tree_add_uint_format(
+ rtpsvt_tree_transport,
+ rtpsvt_hf_version,
+ tvb,
+ offset,
+ sizeof(guint16),
+ version,
+ "Version: %d.%d",
+ transport_data.version_major,
+ transport_data.version_minor);
+ rtpsvt_tree_version = proto_item_add_subtree(
+ rtpsvt_ti_version,
+ rtpsvt_ett_version);
+
+ proto_tree_add_item(
+ rtpsvt_tree_version,
+ rtpsvt_hf_version_major,
+ tvb,
+ offset,
+ sizeof(guint8),
+ ENC_NA);
+ proto_tree_add_item(
+ rtpsvt_tree_version,
+ rtpsvt_hf_version_minor,
+ tvb,
+ offset + 1,
+ sizeof(guint8),
+ ENC_NA);
+ offset += 2;
+
+ /* Add the content kind. */
+ content_type = tvb_get_guint8(tvb, offset);
+ rtpsvt_ti_content_kind = proto_tree_add_item(
+ rtpsvt_ti_transport,
+ rtpsvt_hf_content_kind,
+ tvb,
+ offset,
+ sizeof(guint8),
+ ENC_NA);
+ if (content_type == CONTENT_KIND_RTPS) {
+ content_type_label = "RTPS";
+ } else {
+ content_type_label = "LOST_INFO";
+ }
+ proto_item_append_text(rtpsvt_ti_content_kind, " (%s)", content_type_label);
+ offset += 1;
+
+ switch(content_type) {
+ case CONTENT_KIND_RTPS:
+ output = dissect_rtps_virtual_transport_rtps_type(
+ tvb,
+ pinfo,
+ tree,
+ rtpsvt_tree_transport,
+ offset,
+ &transport_data);
+ break;
+
+ case CONTENT_KIND_LOSS_INFO:
+ output = dissect_rtps_virtual_transport_loss_info_type(
+ tvb,
+ pinfo,
+ rtpsvt_tree_transport,
+ offset);
+ break;
+ }
+ return output;
+}
+
+static gint dissect_rtps_virtual_transport_rtps_type(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree,
+ proto_tree *tree_transport,
+ gint offset,
+ struct rtpsvt_data *transport_data)
+{
+ proto_item *rtpsvt_ti_identifier;
+ proto_tree *rtpsvt_tree_identifier;
+ proto_item *rtpsvt_ti_information;
+ proto_tree *rtpsvt_tree_information;
+ tvbuff_t *advanced_payload;
+ static dissector_handle_t advanced_handle = NULL;
+ unsigned int idx = FIRST_PARAM_ID_RTPS;
+ guint16 param_id;
+ guint16 param_length;
+
+ /*
+ * Add the tree for the packet identifier, which will be populated in
+ * dissect_parameter_transport_rtps_type.
+ */
+ rtpsvt_ti_identifier = proto_tree_add_item(
+ tree_transport,
+ rtpsvt_hf_packet_identifier,
+ tvb,
+ offset,
+ -1,
+ ENC_NA);
+ rtpsvt_tree_identifier = proto_item_add_subtree(
+ rtpsvt_ti_identifier,
+ rtpsvt_ett_identifier);
+
+ /*
+ * Add the tree for the transport information, which will be populated in
+ * dissect_parameter_transport_rtps_type.
+ */
+ rtpsvt_ti_information = proto_tree_add_item(
+ tree_transport,
+ rtpsvt_hf_information,
+ tvb,
+ offset,
+ -1,
+ ENC_NA);
+ rtpsvt_tree_information = proto_item_add_subtree(
+ rtpsvt_ti_information,
+ rtpsvt_ett_information);
+
+ /*
+ * Each parameter has an id, a length and a value.
+ */
+ for (idx = FIRST_PARAM_ID_RTPS; idx <= LAST_PARAM_ID_RTPS; idx++) {
+ offset = dissect_parameter_transport_rtps_type(
+ tvb,
+ tree_transport,
+ rtpsvt_tree_identifier,
+ rtpsvt_tree_information,
+ offset,
+ pinfo,
+ transport_data);
+ }
+
+ /*
+ * In the future we may have more transport parameters.
+ * These parameters will have an identifier less than PARAM_ID_MAIN_FRAME
+ * (which is parsed by the rtpsproc dissector).
+ * If we open a "future" capture file with this dissector, we will skip all
+ * of those parameters and parse only the ones we know about.
+ */
+ do {
+ param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ offset += sizeof(guint16);
+ param_length = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ offset += sizeof(guint16);
+ if (param_id == PARAM_ID_MAIN_FRAME) {
+ proto_tree *rtpsvt_tree_frame;
+ transport_data->rtps_length = param_length;
+ rtpsvt_tree_frame = proto_tree_add_subtree_format(
+ tree_transport,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_frame,
+ NULL,
+ "Real-Time Publish-Subscribe Wire Protocol (content)");
+
+ proto_tree_add_uint(
+ rtpsvt_tree_frame,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ proto_tree_add_uint(
+ rtpsvt_tree_frame,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset + sizeof(guint16),
+ sizeof(guint16),
+ param_length);
+ break;
+ }
+ offset += param_length;
+ } while (tvb_reported_length_remaining(tvb, offset) > 0);
+
+ if (param_id != PARAM_ID_MAIN_FRAME || param_length <= 0) {
+ /*
+ * Reject the packet if we don't have an RTPS frame.
+ * The rtpsproc dissector assumes that the contents start with the
+ * RTPS frame (parameter value; the length is obtained from
+ * transport_data).
+ */
+ return 0;
+ }
+
+ advanced_payload = tvb_new_subset_length(tvb, offset, -1);
+ advanced_handle = find_dissector("rtpsproc");
+ call_dissector_with_data(
+ advanced_handle,
+ advanced_payload,
+ pinfo,
+ tree,
+ (void *) transport_data);
+
+ return tvb_captured_length(tvb);
+}
+
+static gint dissect_parameter_transport_rtps_type(
+ tvbuff_t *tvb,
+ proto_tree *rtpsvt_tree_general,
+ proto_tree *rtpsvt_tree_identifier,
+ proto_tree *rtpsvt_tree_information,
+ gint offset,
+ packet_info *pinfo,
+ struct rtpsvt_data *transport_data)
+{
+ /*
+ * We will add the parameter id and length later, as part of a subtree
+ * dependent of the parameter.
+ * That is why value of the parameter is now at offset + 4
+ * (i.e. offset + sizeof(param_id) + sizeof(param_length))
+ */
+ guint16 param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ guint16 param_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN);
+ const gint OFFSET_TO_VAL = offset + 2 * sizeof(guint16);
+ if (param_length <=0) {
+ /* Length not valid: skip parameter (id + length) */
+ return OFFSET_TO_VAL;
+ }
+
+ switch(param_id) {
+ case PARAM_ID_TRANSPORT_CLASS:
+ {
+ proto_tree *rtpsvt_tree_information_class;
+ gint32 classId = tvb_get_gint32(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN);
+ const gchar *className = val_to_str(
+ classId,
+ ndds_transport_class_id_vals,
+ "%d");
+
+ rtpsvt_tree_information_class = proto_tree_add_subtree_format(
+ rtpsvt_tree_information,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_class,
+ NULL,
+ "Class: %s",
+ className);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_information_class,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16), /* length: 2B */
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_information_class,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16), /* length: 2B */
+ param_length);
+ offset += sizeof(guint16);
+
+ /*
+ * Add transport class as item to the tree.
+ * This is useful to apply as column or filter.
+ */
+ proto_tree_add_string(
+ rtpsvt_tree_information_class,
+ rtpsvt_hf_class,
+ tvb,
+ offset,
+ param_length,
+ className);
+ offset += param_length;
+
+ /* Add summary to protocol header */
+ proto_item_append_text(rtpsvt_tree_general, ", %s", className);
+
+ /* Add summary to the transport information header */
+ proto_item_append_text(
+ rtpsvt_tree_information,
+ ", %s",
+ className);
+ }
+ break;
+
+ case PARAM_ID_MONITORING_GUID:
+ {
+ proto_tree *rtpsvt_tree_monitoring_guid;
+ const guint8 *guid_bytes = tvb_get_ptr(
+ tvb,
+ OFFSET_TO_VAL,
+ param_length);
+ const gchar *guid_string = bytestring_to_str(
+ wmem_packet_scope(),
+ guid_bytes,
+ MIN(param_length, 12),
+ 0);
+
+ rtpsvt_tree_monitoring_guid = proto_tree_add_subtree_format(
+ rtpsvt_tree_identifier,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_src_addr,
+ NULL,
+ "Monitoring GUID Prefix: %s",
+ guid_string);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_monitoring_guid,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_monitoring_guid,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ proto_tree_add_item(
+ rtpsvt_tree_monitoring_guid,
+ rtpsvt_hf_monitoring_guid,
+ tvb,
+ offset,
+ param_length,
+ ENC_NA);
+ offset += param_length;
+
+ /* Add summary to packet identifier header */
+ proto_item_append_text(
+ rtpsvt_tree_identifier,
+ ", GUID: %s",
+ guid_string);
+ }
+ break;
+ case PARAM_ID_MONITORING_SN:
+ {
+ proto_tree *rtpsvt_tree_seqNr;
+ guint64 seqNr = tvb_get_guint64(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN);
+
+ rtpsvt_tree_seqNr = proto_tree_add_subtree_format(
+ rtpsvt_tree_identifier,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_monitoring_sn,
+ NULL,
+ "Monitoring Sequence Number: %lu",
+ seqNr);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_seqNr,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_seqNr,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ proto_tree_add_uint64(
+ rtpsvt_tree_seqNr,
+ rtpsvt_hf_monitoring_seqNr,
+ tvb,
+ offset,
+ param_length,
+ seqNr);
+ offset += param_length;
+
+ /* Add summary to packet identifier header */
+ proto_item_append_text(
+ rtpsvt_tree_identifier,
+ ", SeqNum: %lu",
+ seqNr);
+ }
+ break;
+ case PARAM_ID_SOURCE_IP_ADDRESS:
+ {
+ proto_tree *rtpsvt_tree_information_address;
+ gint temporary_hf = rtpsvt_hf_source_address;
+ const gchar *prefix = "shmem_prefix";
+ const gchar *title_tree = "Source address";
+ gchar addr[COL_MAX_LEN];
+ ws_in6_addr addr_raw;
+ const guint8 bytes_zeroed[12] = {0};
+ tvb_get_ipv6(tvb, OFFSET_TO_VAL, &addr_raw);
+
+ /* shared memory pid or address? */
+ if (memcmp(&addr_raw.bytes, prefix, strlen(prefix)) == 0) {
+ temporary_hf = rtpsvt_hf_source_pid;
+ title_tree = "Source process ID";
+ guint32 pid = tvb_get_guint32(
+ tvb,
+ OFFSET_TO_VAL + (gint) (strlen(prefix)),
+ ENC_BIG_ENDIAN);
+ g_snprintf(addr, sizeof(addr), "%u", pid);
+ } else if (memcmp(
+ &addr_raw.bytes,
+ bytes_zeroed,
+ sizeof(bytes_zeroed)) == 0){
+ g_snprintf(
+ addr,
+ sizeof(addr),
+ "%s",
+ tvb_ip_to_str(tvb, OFFSET_TO_VAL + sizeof(bytes_zeroed)));
+ } else {
+ g_snprintf(
+ addr,
+ sizeof(addr),
+ "%s",
+ tvb_ip6_to_str(tvb, OFFSET_TO_VAL));
+ }
+
+ /* Add source to destination column field */
+ if (pinfo->cinfo) {
+ col_append_str(pinfo->cinfo, COL_DEF_SRC, addr);
+ }
+
+ rtpsvt_tree_information_address = proto_tree_add_subtree_format(
+ rtpsvt_tree_information,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_src_addr,
+ NULL,
+ "%s: %s",
+ title_tree,
+ addr);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_information_address,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_information_address,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ /* Add source to the transport information tree */
+ proto_tree_add_string(
+ rtpsvt_tree_information_address,
+ temporary_hf,
+ tvb,
+ offset,
+ param_length,
+ addr);
+ offset += param_length;
+
+ /* Add summary to protocol header */
+ proto_item_append_text(rtpsvt_tree_general, ", Src: (%s", addr);
+
+ /* Add summary to transport information header */
+ proto_item_append_text(
+ rtpsvt_tree_information,
+ ", Src: (%s",
+ addr);
+ }
+ break;
+ case PARAM_ID_SOURCE_PORT:
+ {
+ proto_tree *rtpsvt_tree_information_port;
+ guint32 port = tvb_get_guint32(
+ tvb,
+ OFFSET_TO_VAL,
+ ENC_BIG_ENDIAN);
+
+ rtpsvt_tree_information_port = proto_tree_add_subtree_format(
+ rtpsvt_tree_information,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_src_port,
+ NULL,
+ "Source port: %d",
+ port);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_information_port,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_information_port,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ proto_tree_add_uint(
+ rtpsvt_tree_information_port,
+ rtpsvt_hf_source_port,
+ tvb,
+ offset,
+ param_length,
+ port);
+ offset += param_length;
+
+ /* Add summary to protocol header */
+ proto_item_append_text(rtpsvt_tree_general, ":%d)", port);
+
+ /* Add summary to transport information header */
+ proto_item_append_text(
+ rtpsvt_tree_information,
+ ":%d)",
+ port);
+
+ /*
+ * Add the source port to pinfo.
+ * This is used by the RTPS dissector to get the domainId and
+ * participantIdx information displayed in discovery packets.
+ */
+ pinfo->srcport = port;
+ }
+ break;
+ case PARAM_ID_DESTINATION_IP_ADDRESS:
+ {
+ proto_tree *rtpsvt_tree_information_address;
+ gint temporary_hf= rtpsvt_hf_destination_address;
+ const gchar *prefix = "shmem_prefix";
+ const gchar *title_tree = "Destination address";
+ gchar addr[COL_MAX_LEN];
+ ws_in6_addr addr_raw;
+ const guint8 bytes_zeroed[12] = {0};
+ tvb_get_ipv6(tvb, OFFSET_TO_VAL, &addr_raw);
+
+ /* shared memory pid or address? */
+ if (memcmp(&addr_raw.bytes, prefix, strlen(prefix)) == 0) {
+ temporary_hf = rtpsvt_hf_destination_pid;
+ title_tree = "Destination process ID";
+ guint32 pid = tvb_get_guint32(
+ tvb,
+ OFFSET_TO_VAL + (gint) (strlen(prefix)),
+ ENC_BIG_ENDIAN);
+ g_snprintf(addr, sizeof(addr), "%u", pid);
+ } else if (memcmp(
+ &addr_raw.bytes,
+ bytes_zeroed,
+ sizeof(bytes_zeroed)) == 0){
+ g_snprintf(
+ addr,
+ sizeof(addr),
+ "%s",
+ tvb_ip_to_str(tvb, OFFSET_TO_VAL + sizeof(bytes_zeroed)));
+ } else {
+ g_snprintf(
+ addr,
+ sizeof(addr),
+ "%s",
+ tvb_ip6_to_str(tvb, OFFSET_TO_VAL));
+ }
+
+ /* Add address to destination column field */
+ if (pinfo->cinfo) {
+ col_append_str(pinfo->cinfo, COL_DEF_DST, addr);
+ }
+
+ rtpsvt_tree_information_address = proto_tree_add_subtree_format(
+ rtpsvt_tree_information,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_dst_addr,
+ NULL,
+ "%s: %s",
+ title_tree,
+ addr);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_information_address,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_information_address,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ /* Add destination to the transport information tree */
+ proto_tree_add_string(
+ rtpsvt_tree_information_address,
+ temporary_hf,
+ tvb,
+ offset,
+ param_length,
+ addr);
+ offset += param_length;
+
+ /* Add summary to protocol header */
+ proto_item_append_text(rtpsvt_tree_general, ", Dst: (%s", addr);
+
+ /* Add summary to transport information header */
+ proto_item_append_text(
+ rtpsvt_tree_information,
+ ", Dst: (%s",
+ addr);
+ }
+ break;
+ case PARAM_ID_DESTINATION_RTPS_PORT:
+ {
+ guint32 port = tvb_get_guint32(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN);
+
+ proto_tree_add_uint(
+ rtpsvt_tree_information,
+ rtpsvt_hf_destination_rtps_port,
+ tvb,
+ OFFSET_TO_VAL,
+ param_length,
+ port);
+
+ offset = OFFSET_TO_VAL + param_length;
+ }
+ break;
+ case PARAM_ID_DESTINATION_PORT:
+ {
+ proto_tree *rtpsvt_tree_information_port;
+ guint32 port = tvb_get_guint32(tvb, OFFSET_TO_VAL, ENC_BIG_ENDIAN);
+
+ rtpsvt_tree_information_port = proto_tree_add_subtree_format(
+ rtpsvt_tree_information,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_dst_port,
+ NULL,
+ "Destination port: %d",
+ port);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_information_port,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_information_port,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ proto_tree_add_uint(
+ rtpsvt_tree_information_port,
+ rtpsvt_hf_destination_port,
+ tvb,
+ offset,
+ param_length,
+ port);
+ offset += param_length;
+
+ /* Add summary to protocol header */
+ proto_item_append_text(rtpsvt_tree_general, ":%d)", port);
+
+ /* Add summary to transport information header */
+ proto_item_append_text(
+ rtpsvt_tree_information,
+ ":%d)",
+ port);
+
+ /*
+ * Add the destination port to pinfo.
+ * This is used by the RTPS dissector to get the domainId and
+ * participantIdx information displayed in discovery packets.
+ */
+ pinfo->destport = port;
+ }
+ break;
+ case PARAM_ID_DIRECTION:
+ {
+ proto_tree *rtpsvt_tree_direction;
+ guint8 value = tvb_get_guint8(tvb, OFFSET_TO_VAL);
+ const gchar *direction = value ? "INBOUND" : "OUTBOUND";
+
+ rtpsvt_tree_direction = proto_tree_add_subtree_format(
+ rtpsvt_tree_general,
+ tvb,
+ offset,
+ 0,
+ rtpsvt_ett_information_src_addr,
+ NULL,
+ "Traffic Direction: %s",
+ direction);
+
+ /* Add parameter identifier and length */
+ proto_tree_add_uint(
+ rtpsvt_tree_direction,
+ rtpsvt_hf_param_id,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_id);
+ offset += sizeof(guint16);
+ proto_tree_add_uint(
+ rtpsvt_tree_direction,
+ rtpsvt_hf_param_length,
+ tvb,
+ offset,
+ sizeof(guint16),
+ param_length);
+ offset += sizeof(guint16);
+
+ proto_tree_add_string(
+ rtpsvt_tree_direction,
+ rtpsvt_hf_direction,
+ tvb,
+ OFFSET_TO_VAL,
+ param_length,
+ direction);
+ offset = OFFSET_TO_VAL + param_length;
+
+ /* Save transport direction for the RTPS-PROC protocol */
+ transport_data->direction = value;
+ }
+ break;
+ }
+ return offset;
+}
+
+static gint dissect_rtps_virtual_transport_loss_info_type(
+ tvbuff_t *tvb,
+ packet_info *pinfo,
+ proto_tree *tree_transport,
+ gint offset)
+{
+
+ guint16 param_id;
+ guint16 param_length;
+
+ param_id = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ offset += sizeof(guint16);
+ param_length = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN);
+ offset += sizeof(guint16);
+ if (param_id == PARAM_ID_LOST_MESSAGES) {
+ guint64 first_lost = tvb_get_guint64(tvb, offset, ENC_BIG_ENDIAN);
+ guint64 last_lost = tvb_get_guint64(tvb, offset+8, ENC_BIG_ENDIAN);
+
+ if (pinfo->cinfo) {
+ char info[COL_MAX_INFO_LEN] = {'\0'};
+ g_snprintf(
+ info,
+ sizeof(info),
+ "Missing RTPS messages [%ld-%ld]",
+ first_lost,
+ last_lost);
+ col_append_str(pinfo->cinfo, COL_INFO, info);
+ }
+ expert_add_info(NULL, tree_transport, &ei_missing_msg);
+ }
+ offset += param_length;
+
+ return tvb_captured_length(tvb);
+}
+
+/* Register the protocol with Wireshark */
+void
+proto_register_rtps_virtual_transport(void)
+{
+ expert_module_t* expert_info;
+
+ static hf_register_info hf[] = {
+ {
+ &rtpsvt_hf_version,
+ {
+ "Version", "rtpsvt.version",
+ FT_UINT16, BASE_HEX, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_version_major,
+ {
+ "Major", "rtpsvt.version.major",
+ FT_INT8, BASE_DEC, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_version_minor,
+ {
+ "Minor", "rtpsvt.version.minor",
+ FT_INT8, BASE_DEC, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_content_kind,
+ {
+ "Content kind", "rtpsvt.content.kind",
+ FT_INT8, BASE_DEC, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_param_id,
+ {
+ "Parameter Identifier", "rtpsvt.param.id",
+ FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL
+ },
+ },
+ {
+ &rtpsvt_hf_param_length,
+ {
+ "Parameter Length", "rtpsvt.param.length",
+ FT_UINT16, BASE_DEC, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_direction,
+ {
+ "Traffic Direction", "rtpsvt.direction",
+ FT_STRING, BASE_NONE, NULL, 0x0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_packet_identifier,
+ {
+ "Packet identifier", "rtpsvt.identifier",
+ FT_NONE, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_monitoring_guid,
+ {
+ "GUID", "rtpsvt.monitoring_guid",
+ FT_BYTES, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_monitoring_seqNr,
+ {
+ "SeqNum", "rtpsvt.seqNr",
+ FT_UINT64, BASE_DEC, NULL, 0x0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_information,
+ {
+ "Transport Information", "rtpsvt.information",
+ FT_NONE, BASE_NONE, NULL, 0x0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_source_port,
+ {
+ "Source Port", "rtpsvt.source_port",
+ FT_UINT32, BASE_DEC, NULL, 0x0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_source_address,
+ {
+ "Source address", "rtpsvt.source_address",
+ FT_STRING, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_source_pid,
+ {
+ "Source process ID", "rtpsvt.source_pid",
+ FT_STRING, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_destination_port,
+ {
+ "Destination Port", "rtpsvt.port",
+ FT_UINT32, BASE_DEC, NULL, 0x0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_destination_rtps_port,
+ {
+ "Destination RTPS Port", "rtpsvt.rtps_port",
+ FT_UINT32, BASE_DEC, NULL, 0x0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_destination_address,
+ {
+ "Destination address", "rtpsvt.destination_address",
+ FT_STRING, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_destination_pid,
+ {
+ "Destination process ID", "rtpsvt.destination_pid",
+ FT_STRING, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ &rtpsvt_hf_class,
+ {
+ "Transport class", "rtpsvt.class",
+ FT_STRING, BASE_NONE, NULL, 0, 0, HFILL
+ }
+ },
+ {
+ /* Information related to the 'lost' content type */
+ &rtpsvt_hf_missing_messages,
+ {
+ "Packets lost", "rtpsvt.missing_messages",
+ FT_UINT64, BASE_DEC, NULL, 0x0, 0, HFILL
+ }
+ }
+ };
+
+ static gint *ett[] = {
+ &rtpsvt_ett,
+ &rtpsvt_ett_version,
+ &rtpsvt_ett_identifier,
+ &rtpsvt_ett_information,
+ &rtpsvt_ett_information_class,
+ &rtpsvt_ett_information_src_port,
+ &rtpsvt_ett_information_dst_port,
+ &rtpsvt_ett_information_src_addr,
+ &rtpsvt_ett_information_dst_addr,
+ &rtpsvt_ett_information_direction,
+ &rtpsvt_ett_monitoring_sn,
+ &rtpsvt_ett_frame
+ };
+
+ static ei_register_info ei[] = {
+ {
+ &ei_missing_msg,
+ {
+ "rtpsvt.expert.missing_messages",
+ PI_PROTOCOL,
+ PI_NOTE,
+ "Missing RTPS Messages because of full buffer pool",
+ EXPFILL
+ }
+ },
+ };
+
+ /* Register the protocol name and description */
+ proto_rtpsvt = proto_register_protocol(
+ "Real-Time Publish-Subscribe Virtual Transport",
+ "RTPS-VT",
+ "rtpsvt");
+
+ /* Required function calls to register the header fields and subtrees */
+ rtpsvt_hf = proto_registrar_get_nth(proto_rtpsvt);
+ proto_register_field_array(proto_rtpsvt, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ /* Register expert information */
+ expert_info = expert_register_protocol(proto_rtpsvt);
+ expert_register_field_array(expert_info, ei, array_length(ei));
+
+ register_dissector("rtpsvt", dissect_rtps_virtual_transport, proto_rtpsvt);
+}
+
+/*
+ * 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-rtps.c b/epan/dissectors/packet-rtps.c
index cc5886772e..94d3341948 100644
--- a/epan/dissectors/packet-rtps.c
+++ b/epan/dissectors/packet-rtps.c
@@ -47,6 +47,7 @@
#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/prefs.h>
+#include "packet-rtps.h"
#include <epan/addr_resolv.h>
#include <epan/reassemble.h>
#include "zlib.h"
@@ -699,22 +700,6 @@ static dissector_table_t rtps_type_name_table;
#define CRYPTO_TRANSFORMATION_KIND_AES256_GMAC (3)
#define CRYPTO_TRANSFORMATION_KIND_AES256_GCM (4)
-/* Vendor specific - rti */
-#define NDDS_TRANSPORT_CLASSID_ANY (0)
-#define NDDS_TRANSPORT_CLASSID_UDPv4 (1)
-#define NDDS_TRANSPORT_CLASSID_UDPv6 (2)
-#define NDDS_TRANSPORT_CLASSID_INTRA (3)
-#define NDDS_TRANSPORT_CLASSID_DTLS (6)
-#define NDDS_TRANSPORT_CLASSID_WAN (7)
-#define NDDS_TRANSPORT_CLASSID_TCPV4_LAN (8)
-#define NDDS_TRANSPORT_CLASSID_TCPV4_WAN (9)
-#define NDDS_TRANSPORT_CLASSID_TLSV4_LAN (10)
-#define NDDS_TRANSPORT_CLASSID_TLSV4_WAN (11)
-#define NDDS_TRANSPORT_CLASSID_PCIE (12)
-#define NDDS_TRANSPORT_CLASSID_ITP (13)
-#define NDDS_TRANSPORT_CLASSID_SHMEM (0x01000000)
-#define NDDS_TRANSPORT_CLASSID_UDPv4_WAN (0x01000001)
-
#define TOPIC_INFO_ADD_GUID (0x01)
#define TOPIC_INFO_ADD_TYPE_NAME (0x02)
#define TOPIC_INFO_ADD_TOPIC_NAME (0x04)
@@ -11863,16 +11848,11 @@ static gboolean dissect_rtps_submessage_v1(tvbuff_t *tvb, packet_info *pinfo, gi
static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
{
proto_item *ti;
- proto_tree *rtps_tree, *rtps_submessage_tree;
- guint8 submessageId, flags, majorRev;
+ proto_tree *rtps_tree;
+ guint8 majorRev;
guint16 version, vendor_id;
gboolean is_ping;
- guint encoding;
- gint next_submsg, octets_to_next_header;
- int sub_hf;
- const value_string *sub_vals;
endpoint_guid guid;
- endpoint_guid dst_guid;
guint32 magic_number;
gchar domain_id_str[RTPS_UNKNOWN_DOMAIN_ID_STR_LEN] = RTPS_UNKNOWN_DOMAIN_ID_STR;
/* Check 'RTPS' signature:
@@ -11891,9 +11871,8 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
if ((majorRev != 1) && (majorRev != 2))
return FALSE;
- /* No fields have been set in either GUID yet. */
+ /* No fields have been set in GUID yet. */
guid.fields_present = 0;
- dst_guid.fields_present = 0;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPS");
col_clear(pinfo->cinfo, COL_INFO);
@@ -12044,6 +12023,30 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
/* offset behind RTPS's Header (need to be set in case tree=NULL)*/
offset += ((version < 0x0200) ? 16 : 20);
+ dissect_rtps_submessages(tvb, offset, pinfo, rtps_tree, version, vendor_id);
+
+ /* If TCP there's an extra OOB byte at the end of the message */
+ /* TODO: What to do with it? */
+ return TRUE;
+
+} /* dissect_rtps(...) */
+
+void dissect_rtps_submessages(
+ tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *rtps_tree,
+ guint16 version, guint16 vendor_id)
+{
+ guint8 submessageId, flags;
+ int sub_hf;
+ const value_string *sub_vals;
+ proto_item *ti;
+ proto_tree *rtps_submessage_tree;
+ guint encoding;
+ gint next_submsg, octets_to_next_header;
+ endpoint_guid guid;
+ endpoint_guid dst_guid;
+
+ /* No fields have been set in GUID yet. */
+ dst_guid.fields_present = 0;
while (tvb_reported_length_remaining(tvb, offset) > 0) {
submessageId = tvb_get_guint8(tvb, offset);
@@ -12085,7 +12088,8 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
/* Octets-to-next-header */
octets_to_next_header = tvb_get_guint16(tvb, offset + 2, encoding);
- if ((octets_to_next_header == 0) && (version >= 0x0200) && (submessageId != SUBMESSAGE_PAD) && (submessageId != SUBMESSAGE_INFO_TS)) {
+ if ((octets_to_next_header == 0) && (version >= 0x0200)
+ && (submessageId != SUBMESSAGE_PAD) && (submessageId != SUBMESSAGE_INFO_TS)) {
octets_to_next_header = tvb_reported_length_remaining(tvb, offset + 4);
}
next_submsg = offset + octets_to_next_header + 4;
@@ -12116,12 +12120,7 @@ static gboolean dissect_rtps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
/* next submessage's offset */
offset = next_submsg;
}
-
- /* If TCP there's an extra OOB byte at the end of the message */
- /* TODO: What to do with it? */
- return TRUE;
-
-} /* dissect_rtps(...) */
+}
static gboolean dissect_rtps_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
diff --git a/epan/dissectors/packet-rtps.h b/epan/dissectors/packet-rtps.h
new file mode 100644
index 0000000000..b264a94488
--- /dev/null
+++ b/epan/dissectors/packet-rtps.h
@@ -0,0 +1,70 @@
+/* packet-rtps.h
+ * Header file for the Real-Time Publish-Subscribe (RTPS) and related (RTPS
+ * Virtual Transport and Processed) protocols.
+ *
+ * (c) 2020 Copyright, Real-Time Innovations, Inc.
+ * Real-Time Innovations, Inc.
+ * 232 East Java Drive
+ * Sunnyvale, CA 94089
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _TYPEDEFS_DEFINES_RTPS_H
+#define _TYPEDEFS_DEFINES_RTPS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Vendor specific - rti */
+#define NDDS_TRANSPORT_CLASSID_ANY (0)
+#define NDDS_TRANSPORT_CLASSID_UDPv4 (1)
+#define NDDS_TRANSPORT_CLASSID_UDPv6 (2)
+#define NDDS_TRANSPORT_CLASSID_INTRA (3)
+#define NDDS_TRANSPORT_CLASSID_DTLS (6)
+#define NDDS_TRANSPORT_CLASSID_WAN (7)
+#define NDDS_TRANSPORT_CLASSID_TCPV4_LAN (8)
+#define NDDS_TRANSPORT_CLASSID_TCPV4_WAN (9)
+#define NDDS_TRANSPORT_CLASSID_TLSV4_LAN (10)
+#define NDDS_TRANSPORT_CLASSID_TLSV4_WAN (11)
+#define NDDS_TRANSPORT_CLASSID_PCIE (12)
+#define NDDS_TRANSPORT_CLASSID_ITP (13)
+#define NDDS_TRANSPORT_CLASSID_SHMEM (0x01000000)
+#define NDDS_TRANSPORT_CLASSID_UDPv4_WAN (0x01000001)
+
+/* Process a submessage: used in packet-rtps-processed.c */
+extern void dissect_rtps_submessages(
+ tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *rtps_tree,
+ guint16 version, guint16 vendor_id);
+
+/* Information that the RTPS-VT protocol passes to RTPS-PROC */
+struct rtpsvt_data {
+ guint8 version_major;
+ guint8 version_minor;
+ guint8 direction;
+ guint16 rtps_length;
+};
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* _TYPEDEFS_DEFINES_RTPS_H */
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=2 tabstop=8 expandtab:
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */