diff options
author | Anders Broman <anders.broman@ericsson.com> | 2008-08-13 06:09:54 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2008-08-13 06:09:54 +0000 |
commit | a143298812a9511991f9400ed3c2b848a6e57774 (patch) | |
tree | 99a2c6e628960d8b79af6aebe13d71c77b8afb09 /epan/dissectors/packet-rtps2.c | |
parent | 7ec695d943d28417bf94e9516bb7607d575e016e (diff) |
From Fabrizio Bertocci:
- The RTPS packet dissector has been rewritten from scratch to dissect RTPS 1.0
- 1.2 packets
svn path=/trunk/; revision=25994
Diffstat (limited to 'epan/dissectors/packet-rtps2.c')
-rw-r--r-- | epan/dissectors/packet-rtps2.c | 9274 |
1 files changed, 9274 insertions, 0 deletions
diff --git a/epan/dissectors/packet-rtps2.c b/epan/dissectors/packet-rtps2.c new file mode 100644 index 0000000000..97b5d7b285 --- /dev/null +++ b/epan/dissectors/packet-rtps2.c @@ -0,0 +1,9274 @@ +/* packet-rtps2.c + * ~~~~~~~~~~~~~~ + * + * Routines for Real-Time Publish-Subscribe Protocol (RTPS) dissection + * + * Copyright 2005, Fabrizio Bertocci <fabrizio@rti.com> + * Real-Time Innovations, Inc. + * 3975 Freedom Circle + * Santa Clara, CA 95054 + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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. + * + * ------------------------------------- + * + * This is the RTPS packet dissector for RTPS version 2.x + * + * RTPS protocol was initially developed by Real-Time Innovations, Inc. as wire + * protocol for Data Distribution System, and then adopted as a standard by + * the Object Management Group (as version 2.0). + * + * Additional information at: + * Full OMG DDS Standard Specification: + * http://www.omg.org/cgi-bin/doc?ptc/2003-07-07 + * + * RTI DDS and RTPS information: http://www.rti.com/resources.html + * + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <glib.h> +#include <epan/packet.h> +#include <epan/addr_resolv.h> +#include <epan/conversation.h> +#include <epan/prefs.h> + + +#include "packet-rtps2.h" + +/* Size of the temp buffers used to format various part of the protocol. + * Note: Some of those values are bigger than expected. The reason is + * because the string buffer can also contains decoded values. + * I.e. port size is an integer, but for value 0x0000, it is interpreted + * as a string "PORT_INVALID (0x00000000)" + */ +#define MAX_FLAG_SIZE (40) +#define MAX_GUID_PREFIX_SIZE (128) +#define MAX_GUID_SIZE (160) +#define MAX_VENDOR_ID_SIZE (128) +#define MAX_NTP_TIME_SIZE (128) +#define MAX_PORT_SIZE (32) +#define MAX_PARAM_SIZE (256) +#define MAX_SUMMARY_SIZE (500) +#define MAX_LOCATOR_SIZE (200) +#define MAX_IPV6_SIZE (100) +#define MAX_BITMAP_SIZE (200) +#define MAX_LABEL_SIZE (64) +#define MAX_IPV4_ADDRESS_SIZE (64) + +/* Max octets printed on the parameter root for a sequence of octets */ +#define MAX_SEQ_OCTETS_PRINTED (20) + + +/***************************************************************************/ +/* Protocol Fields Identifiers */ +static int proto_rtps = -1; +static int hf_rtps_protocol_version = -1; +static int hf_rtps_protocol_version_major = -1; +static int hf_rtps_protocol_version_minor = -1; +static int hf_rtps_vendor_id = -1; + +static int hf_rtps_domain_id = -1; +static int hf_rtps_participant_idx = -1; +static int hf_rtps_nature_type = -1; + +static int hf_rtps_guid_prefix = -1; +static int hf_rtps_host_id = -1; +static int hf_rtps_app_id = -1; +static int hf_rtps_counter = -1; + +static int hf_rtps_sm_id = -1; +static int hf_rtps_sm_flags = -1; +static int hf_rtps_sm_octets_to_next_header = -1; +static int hf_rtps_sm_guid_prefix = -1; +static int hf_rtps_sm_host_id = -1; +static int hf_rtps_sm_app_id = -1; +static int hf_rtps_sm_instance_id = -1; +static int hf_rtps_sm_app_kind = -1; +static int hf_rtps_sm_counter = -1; +static int hf_rtps_sm_entity_id = -1; +static int hf_rtps_sm_entity_id_key = -1; +static int hf_rtps_sm_entity_id_kind = -1; +static int hf_rtps_sm_rdentity_id = -1; +static int hf_rtps_sm_rdentity_id_key = -1; +static int hf_rtps_sm_rdentity_id_kind = -1; +static int hf_rtps_sm_wrentity_id = -1; +static int hf_rtps_sm_wrentity_id_key = -1; +static int hf_rtps_sm_wrentity_id_kind = -1; +static int hf_rtps_sm_seq_number = -1; + +static int hf_rtps_parameter_id = -1; +static int hf_rtps_parameter_length = -1; +static int hf_rtps_param_ntpt = -1; +static int hf_rtps_param_ntpt_sec = -1; +static int hf_rtps_param_ntpt_fraction = -1; +static int hf_rtps_param_topic_name = -1; +static int hf_rtps_param_entity_name = -1; +static int hf_rtps_param_strength = -1; +static int hf_rtps_param_type_name = -1; +static int hf_rtps_param_user_data = -1; +static int hf_rtps_param_group_data = -1; +static int hf_rtps_param_topic_data = -1; +static int hf_rtps_param_content_filter_name = -1; +static int hf_rtps_param_related_topic_name = -1; +static int hf_rtps_param_filter_name = -1; +static int hf_rtps_issue_data = -1; +static int hf_rtps_param_status_info = -1; + + +/* Subtree identifiers */ +static gint ett_rtps = -1; +static gint ett_rtps_default_mapping = -1; +static gint ett_rtps_proto_version = -1; +static gint ett_rtps_submessage = -1; +static gint ett_rtps_parameter_sequence = -1; +static gint ett_rtps_parameter = -1; +static gint ett_rtps_flags = -1; +static gint ett_rtps_entity = -1; +static gint ett_rtps_rdentity = -1; +static gint ett_rtps_wrentity = -1; +static gint ett_rtps_guid_prefix = -1; +static gint ett_rtps_part_message_data = -1; +static gint ett_rtps_locator_udp_v4 = -1; +static gint ett_rtps_locator = -1; +static gint ett_rtps_locator_list = -1; +static gint ett_rtps_ntp_time = -1; +static gint ett_rtps_bitmap = -1; +static gint ett_rtps_seq_string = -1; +static gint ett_rtps_seq_ulong = -1; +static gint ett_rtps_serialized_data = -1; +static gint ett_rtps_sample_info_list = -1; +static gint ett_rtps_sample_info = -1; + +/***************************************************************************/ +/* Value-to-String Tables */ +static const value_string entity_id_vals[] = { + { ENTITYID_UNKNOWN, "ENTITYID_UNKNOWN" }, + { ENTITYID_PARTICIPANT, "ENTITYID_PARTICIPANT" }, + { ENTITYID_SEDP_BUILTIN_TOPIC_WRITER, "ENTITYID_SEDP_BUILTIN_TOPIC_WRITER" }, + { ENTITYID_SEDP_BUILTIN_TOPIC_READER, "ENTITYID_SEDP_BUILTIN_TOPIC_READER" }, + { ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER, "ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER" }, + { ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER, "ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER" }, + { ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER, "ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER" }, + { ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER, "ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER" }, + { ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER, "ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER" }, + { ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER, "ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER" }, + { ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER, "ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER" }, + { ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER, "ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER" }, + + /* Deprecated Items */ + { ENTITYID_APPLICATIONS_WRITER, "writerApplications [DEPRECATED]" }, + { ENTITYID_APPLICATIONS_READER, "readerApplications [DEPRECATED]" }, + { ENTITYID_CLIENTS_WRITER, "writerClients [DEPRECATED]" }, + { ENTITYID_CLIENTS_READER, "readerClients [DEPRECATED]" }, + { ENTITYID_SERVICES_WRITER, "writerServices [DEPRECATED]" }, + { ENTITYID_SERVICES_READER, "readerServices [DEPRECATED]" }, + { ENTITYID_MANAGERS_WRITER, "writerManagers [DEPRECATED]" }, + { ENTITYID_MANAGERS_READER, "readerManagers [DEPRECATED]" }, + { ENTITYID_APPLICATION_SELF, "applicationSelf [DEPRECATED]" }, + { ENTITYID_APPLICATION_SELF_WRITER, "writerApplicationSelf [DEPRECATED]" }, + { ENTITYID_APPLICATION_SELF_READER, "readerApplicationSelf [DEPRECATED]" }, + { 0, NULL } +}; + +static const value_string entity_kind_vals [] = { + { ENTITYKIND_APPDEF_UNKNOWN, "Application-defined unknown kind" }, + { ENTITYKIND_APPDEF_PARTICIPANT, "Application-defined participant" }, + { ENTITYKIND_APPDEF_WRITER_WITH_KEY, "Application-defined writer (with key)" }, + { ENTITYKIND_APPDEF_WRITER_NO_KEY, "Application-defined writer (no key)" }, + { ENTITYKIND_APPDEF_READER_WITH_KEY, "Application-defined reader (with key)" }, + { ENTITYKIND_APPDEF_READER_NO_KEY, "Application-defined reader (no key)" }, + { ENTITYKIND_BUILTIN_PARTICIPANT, "Built-in participant" }, + { ENTITYKIND_BUILTIN_WRITER_WITH_KEY, "Built-in writer (with key)" }, + { ENTITYKIND_BUILTIN_WRITER_NO_KEY, "Built-in writer (no key)" }, + { ENTITYKIND_BUILTIN_READER_WITH_KEY, "Built-in reader (with key)" }, + { ENTITYKIND_BUILTIN_READER_NO_KEY, "Built-in reader (no key)" }, + { 0, NULL } +}; + + +static const value_string nature_type_vals[] = { + { PORT_METATRAFFIC_UNICAST, "UNICAST_METATRAFFIC"}, + { PORT_METATRAFFIC_MULTICAST, "MULTICAST_METATRAFFIC"}, + { PORT_USERTRAFFIC_UNICAST, "UNICAST_USERTRAFFIC"}, + { PORT_USERTRAFFIC_MULTICAST, "MULTICAST_USERTRAFFIC"}, + { 0, NULL } +}; + + +static const value_string app_kind_vals[] = { + { APPKIND_UNKNOWN, "APPKIND_UNKNOWN" }, + { APPKIND_MANAGED_APPLICATION, "ManagedApplication" }, + { APPKIND_MANAGER, "Manager" }, + { 0, NULL } +}; + + +static const value_string submessage_id_vals[] = { + { SUBMESSAGE_PAD, "PAD" }, + { SUBMESSAGE_RTPS_DATA, "DATA" }, + { SUBMESSAGE_RTPS_DATA_FRAG, "DATA_FRAG" }, + { SUBMESSAGE_RTPS_DATA_BATCH, "DATA_BATCH" }, + { SUBMESSAGE_ACKNACK, "ACKNACK" }, + { SUBMESSAGE_HEARTBEAT, "HEARTBEAT" }, + { SUBMESSAGE_GAP, "GAP" }, + { SUBMESSAGE_INFO_TS, "INFO_TS" }, + { SUBMESSAGE_INFO_SRC, "INFO_SRC" }, + { SUBMESSAGE_INFO_REPLY_IP4, "INFO_REPLY_IP4" }, + { SUBMESSAGE_INFO_DST, "INFO_DST" }, + { SUBMESSAGE_INFO_REPLY, "INFO_REPLY" }, + { SUBMESSAGE_NACK_FRAG, "NACK_FRAG" }, + { SUBMESSAGE_HEARTBEAT_FRAG, "HEARTBEAT_FRAG" }, + { SUBMESSAGE_ACKNACK_BATCH, "ACKNACK_BATCH" }, + { SUBMESSAGE_HEARTBEAT_BATCH, "HEARTBEAT_BATCH" }, + /* Deprecated submessages */ + { SUBMESSAGE_DATA, "DATA_deprecated" }, + { SUBMESSAGE_NOKEY_DATA, "NOKEY_DATA_deprecated" }, + { SUBMESSAGE_DATA_FRAG, "DATA_FRAG_deprecated" }, + { SUBMESSAGE_NOKEY_DATA_FRAG, "NOKEY_DATA_FRAG_deprecated" }, + { 0, NULL } +}; + +static const value_string typecode_kind_vals[] = { + { RTI_CDR_TK_NULL, "(unknown)" }, + { RTI_CDR_TK_SHORT, "short" }, + { RTI_CDR_TK_LONG, "long" }, + { RTI_CDR_TK_USHORT, "unsigned short" }, + { RTI_CDR_TK_ULONG, "unsigned long" }, + { RTI_CDR_TK_FLOAT, "float" }, + { RTI_CDR_TK_DOUBLE, "double" }, + { RTI_CDR_TK_BOOLEAN, "boolean" }, + { RTI_CDR_TK_CHAR, "char" }, + { RTI_CDR_TK_OCTET, "octet" }, + { RTI_CDR_TK_STRUCT, "struct" }, + { RTI_CDR_TK_UNION, "union" }, + { RTI_CDR_TK_ENUM, "enum" }, + { RTI_CDR_TK_STRING, "string" }, + { RTI_CDR_TK_SEQUENCE, "sequence" }, + { RTI_CDR_TK_ARRAY, "array" }, + { RTI_CDR_TK_ALIAS, "alias" }, + { RTI_CDR_TK_LONGLONG, "long long" }, + { RTI_CDR_TK_ULONGLONG, "unsigned long long" }, + { RTI_CDR_TK_LONGDOUBLE, "long double" }, + { RTI_CDR_TK_WCHAR, "wchar" }, + { RTI_CDR_TK_WSTRING, "wstring" }, + { 0, NULL } +}; + +static const value_string parameter_id_vals[] = { + { PID_PAD, "PID_PAD" }, + { PID_SENTINEL, "PID_SENTINEL" }, + { PID_PARTICIPANT_LEASE_DURATION, "PID_PARTICIPANT_LEASE_DURATION" }, + { PID_TIME_BASED_FILTER, "PID_TIME_BASED_FILTER" }, + { PID_TOPIC_NAME, "PID_TOPIC_NAME" }, + { PID_OWNERSHIP_STRENGTH, "PID_OWNERSHIP_STRENGTH" }, + { PID_TYPE_NAME, "PID_TYPE_NAME" }, + { PID_METATRAFFIC_MULTICAST_IPADDRESS,"PID_METATRAFFIC_MULTICAST_IPADDRESS"}, + { PID_DEFAULT_UNICAST_IPADDRESS, "PID_DEFAULT_UNICAST_IPADDRESS" }, + { PID_METATRAFFIC_UNICAST_PORT, "PID_METATRAFFIC_UNICAST_PORT" }, + { PID_DEFAULT_UNICAST_PORT, "PID_DEFAULT_UNICAST_PORT" }, + { PID_MULTICAST_IPADDRESS, "PID_MULTICAST_IPADDRESS" }, + { PID_PROTOCOL_VERSION, "PID_PROTOCOL_VERSION" }, + { PID_VENDOR_ID, "PID_VENDOR_ID" }, + { PID_RELIABILITY, "PID_RELIABILITY" }, + { PID_LIVELINESS, "PID_LIVELINESS" }, + { PID_DURABILITY, "PID_DURABILITY" }, + { PID_DURABILITY_SERVICE, "PID_DURABILITY_SERVICE" }, + { PID_OWNERSHIP, "PID_OWNERSHIP" }, + { PID_PRESENTATION, "PID_PRESENTATION" }, + { PID_DEADLINE, "PID_DEADLINE" }, + { PID_DESTINATION_ORDER, "PID_DESTINATION_ORDER" }, + { PID_LATENCY_BUDGET, "PID_LATENCY_BUDGET" }, + { PID_PARTITION, "PID_PARTITION" }, + { PID_LIFESPAN, "PID_LIFESPAN" }, + { PID_USER_DATA, "PID_USER_DATA" }, + { PID_GROUP_DATA, "PID_GROUP_DATA" }, + { PID_TOPIC_DATA, "PID_TOPIC_DATA" }, + { PID_UNICAST_LOCATOR, "PID_UNICAST_LOCATOR" }, + { PID_MULTICAST_LOCATOR, "PID_MULTICAST_LOCATOR" }, + { PID_DEFAULT_UNICAST_LOCATOR, "PID_DEFAULT_UNICAST_LOCATOR" }, + { PID_METATRAFFIC_UNICAST_LOCATOR, "PID_METATRAFFIC_UNICAST_LOCATOR " }, + { PID_METATRAFFIC_MULTICAST_LOCATOR, "PID_METATRAFFIC_MULTICAST_LOCATOR" }, + { PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT, "PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT" }, + { PID_CONTENT_FILTER_PROPERTY, "PID_CONTENT_FILTER_PROPERTY" }, + { PID_PROPERTY_LIST, "PID_PROPERTY_LIST" }, + { PID_HISTORY, "PID_HISTORY" }, + { PID_RESOURCE_LIMIT, "PID_RESOURCE_LIMIT" }, + { PID_EXPECTS_INLINE_QOS, "PID_EXPECTS_INLINE_QOS" }, + { PID_PARTICIPANT_BUILTIN_ENDPOINTS, "PID_PARTICIPANT_BUILTIN_ENDPOINTS" }, + { PID_METATRAFFIC_UNICAST_IPADDRESS, "PID_METATRAFFIC_UNICAST_IPADDRESS" }, + { PID_METATRAFFIC_MULTICAST_PORT, "PID_METATRAFFIC_MULTICAST_PORT" }, + { PID_DEFAULT_MULTICAST_LOCATOR, "PID_DEFAULT_MULTICAST_LOCATOR" }, + { PID_TRANSPORT_PRIORITY, "PID_TRANSPORT_PRIORITY" }, + { PID_PARTICIPANT_GUID, "PID_PARTICIPANT_GUID" }, + { PID_PARTICIPANT_ENTITY_ID, "PID_PARTICIPANT_ENTITY_ID" }, + { PID_GROUP_GUID, "PID_GROUP_GUID" }, + { PID_GROUP_ENTITY_ID, "PID_GROUP_ENTITY_ID" }, + { PID_CONTENT_FILTER_INFO, "PID_CONTENT_FILTER_INFO" }, + { PID_COHERENT_SET, "PID_COHERENT_SET" }, + { PID_DIRECTED_WRITE, "PID_DIRECTED_WRITE" }, + { PID_BUILTIN_ENDPOINT_SET, "PID_BUILTIN_ENDPOINT_SET" }, + { PID_PROPERTY_LIST_OLD, "PID_PROPERTY_LIST" }, + { PID_ENDPOINT_GUID, "PID_ENDPOINT_GUID" }, + { PID_TYPE_MAX_SIZE_SERIALIZED, "PID_TYPE_MAX_SIZE_SERIALIZED" }, + { PID_ORIGINAL_WRITER_INFO, "PID_ORIGINAL_WRITER_INFO" }, + { PID_ENTITY_NAME, "PID_ENTITY_NAME" }, + { PID_KEY_HASH, "PID_KEY_HASH" }, + { PID_STATUS_INFO, "PID_STATUS_INFO" }, + + /* Vendor specific: RTI */ + { PID_PRODUCT_VERSION, "PID_PRODUCT_VERSION" }, + { PID_PLUGIN_PROMISCUITY_KIND, "PID_PLUGIN_PROMISCUITY_KIND" }, + { PID_ENTITY_VIRTUAL_GUID, "PID_ENTITY_VIRTUAL_GUID" }, + { PID_SERVICE_KIND, "PID_SERVICE_KIND" }, + { PID_TYPECODE, "PID_TYPECODE" }, + + /* The following PID are deprecated */ + { PID_DEADLINE_OFFERED, "PID_DEADLINE_OFFERED [deprecated]" }, + { PID_PERSISTENCE, "PID_PERSISTENCE [deprecated]" }, + { PID_TYPE_CHECKSUM, "PID_TYPE_CHECKSUM [deprecated]" }, + { PID_TYPE2_NAME, "PID_TYPE2_NAME [deprecated]" }, + { PID_TYPE2_CHECKSUM, "PID_TYPE2_CHECKSUM [deprecated]" }, + { PID_IS_RELIABLE, "PID_IS_RELIABLE [deprecated]" }, + { PID_EXPECTS_ACK, "PID_EXPECTS_ACK [deprecated]" }, + { PID_MANAGER_KEY, "PID_MANAGER_KEY [deprecated]" }, + { PID_SEND_QUEUE_SIZE, "PID_SEND_QUEUE_SIZE [deprecated]" }, + { PID_RELIABILITY_ENABLED, "PID_RELIABILITY_ENABLED [deprecated]" }, + { PID_VARGAPPS_SEQUENCE_NUMBER_LAST, "PID_VARGAPPS_SEQUENCE_NUMBER_LAST [deprecated]" }, + { PID_RECV_QUEUE_SIZE, "PID_RECV_QUEUE_SIZE [deprecated]" }, + { PID_RELIABILITY_OFFERED, "PID_RELIABILITY_OFFERED [deprecated]" }, + { PID_LIVELINESS_OFFERED, "PID_LIVELINESS_OFFERED [deprecated]" }, + { PID_PRESENTATION_OFFERED, "PID_PRESENTATION_OFFERED [deprecated]" }, + { PID_OWNERSHIP_OFFERED, "PID_OWNERSHIP_OFFERED [deprecated]" }, + { PID_DESTINATION_ORDER_OFFERED, "PID_DESTINATION_ORDER_OFFERED [deprecated]" }, + { PID_LATENCY_BUDGET_OFFERED, "PID_LATENCY_BUDGET_OFFERED [deprecated]" }, + { PID_PARTITION_OFFERED, "PID_PARTITION_OFFERED [deprecated]" }, + { 0, NULL } +}; + +static const value_string liveliness_qos_vals[] = { + { LIVELINESS_AUTOMATIC, "AUTOMATIC_LIVELINESS_QOS" }, + { LIVELINESS_BY_PARTICIPANT, "MANUAL_BY_PARTICIPANT_LIVELINESS_QOS" }, + { LIVELINESS_BY_TOPIC, "MANUAL_BY_TOPIC_LIVELINESS_QOS" }, + { 0, NULL } +}; + +static const value_string durability_qos_vals[] = { + { DURABILITY_VOLATILE, "VOLATILE_DURABILITY_QOS" }, + { DURABILITY_TRANSIENT_LOCAL, "TRANSIENT_LOCAL_DURABILITY_QOS" }, + { DURABILITY_TRANSIENT, "TRANSIENT_DURABILITY_QOS" }, + { DURABILITY_PERSISTENT, "PERSISTENT_DURABILITY_QOS" }, + { 0, NULL } +}; + +static const value_string ownership_qos_vals[] = { + { OWNERSHIP_SHARED, "SHARED_OWNERSHIP_QOS" }, + { OWNERSHIP_EXCLUSIVE, "EXCLUSIVE_OWNERSHIP_QOS" }, + { 0, NULL } +}; + +static const value_string presentation_qos_vals[] = { + { PRESENTATION_INSTANCE, "INSTANCE_PRESENTATION_QOS" }, + { PRESENTATION_TOPIC, "TOPIC_PRESENTATION_QOS" }, + { PRESENTATION_GROUP, "GROUP_PRESENTATION_QOS" }, + { 0, NULL } +}; + +static const value_string history_qos_vals[] = { + { HISTORY_KIND_KEEP_LAST, "KEEP_LAST_HISTORY_QOS" }, + { HISTORY_KIND_KEEP_ALL, "KEEP_ALL_HISTORY_QOS" }, + { 0, NULL } +}; + +static const value_string reliability_qos_vals[] = { + { RELIABILITY_BEST_EFFORT, "BEST_EFFORT_RELIABILITY_QOS" }, + { RELIABILITY_RELIABLE, "RELIABLE_RELIABILITY_QOS" }, + { 0, NULL } +}; + +static const value_string destination_order_qos_vals[] = { + { BY_RECEPTION_TIMESTAMP, "BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS" }, + { BY_SOURCE_TIMESTAMP, "BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS" }, + { 0, NULL } +}; + + +static const value_string encapsulation_id_vals[] = { + { ENCAPSULATION_CDR_BE, "CDR_BE" }, + { ENCAPSULATION_CDR_LE, "CDR_LE" }, + { ENCAPSULATION_PL_CDR_BE, "PL_CDR_BE" }, + { ENCAPSULATION_PL_CDR_LE, "PL_CDR_LE" }, + { 0, NULL } +}; + +static const value_string plugin_promiscuity_kind_vals[] = { + { 0x0001, "MATCHING_REMOTE_ENTITIES_PROMISCUITY" }, + { 0xffff, "ALL_REMOTE_ENTITIES_PROMISCUITY" }, + { 0, NULL } +}; + +static const value_string service_kind_vals[] = { + { 0x00000000, "NO_SERVICE_QOS" }, + { 0x00000001, "PERSISTENCE_SERVICE_QOS" }, + { 0, NULL } +}; + +static const value_string participant_message_data_kind [] = { + { PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN, "PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN" }, + { PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE, "PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE" }, + { PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE, "PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE" }, + { 0, NULL } +}; + + + +/* Flag Decoding defintions ***********************************************/ +struct Flag_definition { + const char letter; + const char *description; +}; + +#define RESERVEDFLAG_CHAR ('_') +#define RESERVEDFLAG_STRING ("reserved bit") + +static const struct Flag_definition PAD_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition DATA_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { 'I', "Status info flag" }, /* Bit 4 */ + { 'H', "Hash key flag" }, /* Bit 3 */ + { 'D', "Data present" }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition NOKEY_DATA_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { 'H', "Key Hash" }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition ACKNACK_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'F', "Final flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition GAP_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition HEARTBEAT_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { 'L', "Liveliness flag" }, /* Bit 2 */ + { 'F', "Final flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition HEARTBEAT_BATCH_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { 'L', "Liveliness flag" }, /* Bit 2 */ + { 'F', "Final flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition INFO_TS_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'I', "Invalidate flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition INFO_SRC_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition INFO_REPLY_IP4_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'M', "Multicast flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition INFO_DST_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition INFO_REPLY_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'M', "Multicast flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition NOKEY_DATA_FRAG_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition HEARTBEAT_FRAG_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition NACK_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'F', "Final flag" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition DATA_FRAG_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { 'H', "Hash key flag" }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition NACK_FRAG_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition RTPS_DATA_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { 'D', "Data present" }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition RTPS_DATA_FRAG_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition RTPS_DATA_BATCH_FLAGS[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 4 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 3 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'E', "Endianess bit" } /* Bit 0 */ +}; + +static const struct Flag_definition RTPS_SAMPLE_INFO_FLAGS16[] = { + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 15 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 14 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 13 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 12 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 11 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 10 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 9 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 8 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ + { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 5 */ + { 'I', "Invalid sample" }, /* Bit 4 */ + { 'D', "Data present" }, /* Bit 3 */ + { 'O', "OffsetSN present" }, /* Bit 2 */ + { 'Q', "Inline QoS" }, /* Bit 1 */ + { 'T', "Timestamp present" } /* Bit 0 */ +}; + + +/***************************************************************************/ + + + + + +/*************************************************************************** + * Function prototypes + * ~~~~~~~~~~~~~~~~~~~ + */ + +/* Utility to add elements to the protocol tree */ +static void rtps_util_format_ipv6(guint8 *, guint8 *, gint); +static void rtps_util_add_protocol_version(proto_tree *, tvbuff_t *, gint); +static void rtps_util_add_vendor_id(proto_tree *, tvbuff_t *, + gint, guint8 *, gint); +static void rtps_util_add_locator_t(proto_tree *, tvbuff_t *, + gint, int, const guint8 *, guint8 *, gint); +static int rtps_util_add_locator_list(proto_tree *, tvbuff_t *, + gint, const guint8 *, int); +static void rtps_util_add_ipv4_address_t(proto_tree *, tvbuff_t *, + gint, int, const guint8 *, guint8 *, gint); +static void rtps_util_add_locator_udp_v4(proto_tree *, tvbuff_t *, + gint, const guint8 *, int); +static void rtps_util_add_guid_prefix(proto_tree *, tvbuff_t *, + gint, int, int, int, int, const guint8 *, + guint8 *, gint); +static void rtps_util_add_entity_id(proto_tree *, tvbuff_t *, + gint, int, int, int, int, const char *, guint32 *); +static void rtps_util_add_generic_entity_id(proto_tree *, tvbuff_t *, + gint, const char *, + guint8 *, gint); +static void rtps_util_add_generic_guid(proto_tree *, tvbuff_t *, + gint, const char *, guint8 *, gint); +static guint64 rtps_util_add_seq_number(proto_tree *, tvbuff_t *, + gint, int, const char *); +static void rtps_util_add_ntp_time(proto_tree *, tvbuff_t *, + gint, int, const char *, guint8 *, gint); +static gint rtps_util_add_string(proto_tree *, tvbuff_t *, + gint, int, int, const guint8 *, guint8 *, gint); +static guint32 rtps_util_add_long(proto_tree *, tvbuff_t *, + gint, int, int, gboolean, gboolean, const char *, + guint8 *, gint); +static guint16 rtps_util_add_short(proto_tree *, tvbuff_t *, + gint, int, int, gboolean, gboolean, const char *, + guint8 *, gint); +static void rtps_util_add_port(proto_tree *, tvbuff_t *, + gint, int, char *, guint8 *, gint); +static void rtps_util_add_boolean(proto_tree *, tvbuff_t *, + gint, char *, guint8 *, gint); +static void rtps_util_add_durability_service_qos(proto_tree *, tvbuff_t *, + gint, int, guint8 *, gint); +static void rtps_util_add_liveliness_qos(proto_tree *, tvbuff_t *, + gint, int, guint8 *, gint); +static void rtps_util_add_kind_qos(proto_tree *, tvbuff_t *, + gint, int, char *, const value_string *, guint8 *, gint); +static gint rtps_util_add_seq_string(proto_tree *, tvbuff_t *, + gint, int, int, char *, guint8 *, gint); +static void rtps_util_add_seq_octets(proto_tree *, tvbuff_t *, + gint, int, int, int, guint8 *, gint); +static int rtps_util_add_bitmap(proto_tree *, tvbuff_t *, + gint, int, const char *); +static int rtps_util_add_fragment_number_set(proto_tree *, tvbuff_t *, + gint, int, const char *, gint); +static void rtps_util_decode_flags(proto_tree *, tvbuff_t *, + gint, guint8, const struct Flag_definition *); +static void rtps_util_decode_flags_16bit(proto_tree *, tvbuff_t *, + gint, guint16, const struct Flag_definition *); +static gint rtps_util_add_seq_ulong(proto_tree *, tvbuff_t *, + gint, int, int, int, int, char *); +static void rtps_util_add_extra_flags(proto_tree *, tvbuff_t *, + gint, const char *); + +/* The data (payload) dissector */ +static void dissect_serialized_data(proto_tree *, tvbuff_t *, + gint, int, const char *, guint16 vendor_id); + +static void dissect_octet_seq(proto_tree *, tvbuff_t *, + gint, const char *); + +/* The data (payload) dissector for parameter sequences */ +static gint dissect_parameter_sequence(proto_tree *, tvbuff_t *, + gint, int, int, const char *, guint32 *, guint16 vendor_id); + + + + +/* Sub-message dissector functions */ +#define DECLARE_DISSECTOR_SUBMESSAGE(sm) \ +static void dissect_## sm (tvbuff_t *tvb, gint offset, guint8 flags, \ + gboolean little_endian, int next_submsg_offset, \ + proto_tree *rtps_submessage_tree, \ + char *info_summary_text, guint16 vendor_id) +DECLARE_DISSECTOR_SUBMESSAGE(PAD); +DECLARE_DISSECTOR_SUBMESSAGE(DATA); +DECLARE_DISSECTOR_SUBMESSAGE(DATA_FRAG); +DECLARE_DISSECTOR_SUBMESSAGE(NOKEY_DATA); +DECLARE_DISSECTOR_SUBMESSAGE(NOKEY_DATA_FRAG); +DECLARE_DISSECTOR_SUBMESSAGE(NACK_FRAG); +DECLARE_DISSECTOR_SUBMESSAGE(ACKNACK); +DECLARE_DISSECTOR_SUBMESSAGE(HEARTBEAT); +DECLARE_DISSECTOR_SUBMESSAGE(HEARTBEAT_FRAG); +DECLARE_DISSECTOR_SUBMESSAGE(GAP); +DECLARE_DISSECTOR_SUBMESSAGE(INFO_TS); +DECLARE_DISSECTOR_SUBMESSAGE(INFO_SRC); +DECLARE_DISSECTOR_SUBMESSAGE(INFO_REPLY_IP4); +DECLARE_DISSECTOR_SUBMESSAGE(INFO_DST); +DECLARE_DISSECTOR_SUBMESSAGE(INFO_REPLY); +DECLARE_DISSECTOR_SUBMESSAGE(RTPS_DATA); +DECLARE_DISSECTOR_SUBMESSAGE(RTPS_DATA_FRAG); +DECLARE_DISSECTOR_SUBMESSAGE(RTPS_DATA_BATCH); +DECLARE_DISSECTOR_SUBMESSAGE(HEARTBEAT_BATCH); +#undef DECLARE_DISSECTOR_SUBMESSAGE + +/* The main packet dissector */ +static gboolean dissect_rtps(tvbuff_t *, packet_info *, proto_tree *); + + +/***************************************************************************/ +/* Inline macros */ +/***************************************************************************/ +#define NEXT_guint16(tvb, offset, le) \ + (le ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset)) + +#define NEXT_guint32(tvb, offset, le) \ + (le ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset)) + + +/***************************************************************************/ +/* Global variables controlled by Wireshark preference panel */ +/***************************************************************************/ +//static gboolean glob_do_something = TRUE; +static guint rtps_max_batch_samples_dissected = 16; + +static void reinit_rtps(void) { + /* Do something here when global arguments are changed */ +} + + + + + +/* *********************************************************************** */ +/* Appends a submessage description to the info summary text + */ +void info_summary_append(char *summaryText, int submessageId, const char * extra_text) { + gint len = strlen(summaryText); + if (extra_text == NULL) { + extra_text=""; + } + if (summaryText[0] != '\0') { + g_strlcat(summaryText, ", ", MAX_SUMMARY_SIZE-len-1); + len += 2; + } + g_snprintf(summaryText + len, + MAX_SUMMARY_SIZE - len, + "%s%s", + val_to_str(submessageId, submessage_id_vals, "Unknown[%02x]"), + extra_text); +} + +/* *********************************************************************** */ +/* Appends a submessage description to the info summary text, with + * extra formatting for those submessages that has a status info + */ +void info_summary_append_ex(char *info_summary_text, + int submessageId, + guint32 writer_id, + guint32 status_info) { + + /* Defines the extra information associated to the writer involved in + * this communication + * + * Format: [?Ptwrpm]\(u?d?\) + * + * First letter table: + * + * writerEntityId value | Letter + * ---------------------------------------------------+-------------- + * ENTITYID_UNKNOWN | ? + * ENTITYID_PARTICIPANT | P + * ENTITYID_SEDP_BUILTIN_TOPIC_WRITER | t + * ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER | w + * ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER | r + * ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER | p + * ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER | m + * + * The letter is followed by: + * status_info &1 | status_info & 2 | Text + * ---------------+-----------------------+-------------- + * status_info not defined in inlineQos | [?] + * 0 | 0 | [__] + * 0 | 1 | [u_] + * 1 | 0 | [_d] + * 1 | 1 | [ud] + */ + /* 0123456 */ + char buffer[10] = "(?[??])"; + + if (writer_id == ENTITYID_PARTICIPANT) + buffer[1] = 'P'; + else if (writer_id == ENTITYID_SEDP_BUILTIN_TOPIC_WRITER) + buffer[1] = 't'; + else if (writer_id == ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER) + buffer[1] = 'w'; + else if (writer_id == ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER) + buffer[1] = 'r'; + else if (writer_id == ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) + buffer[1] = 'p'; + else if (writer_id == ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER) + buffer[1] = 'm'; + else { + /* Unknown writer ID, don't format anything */ + info_summary_append(info_summary_text, submessageId, NULL); + return; + } + + switch(status_info) { + case 0: buffer[3] = '_'; buffer[4] = '_'; break; + case 1: buffer[3] = '_'; buffer[4] = 'D'; break; + case 2: buffer[3] = 'U'; buffer[4] = '_'; break; + case 3: buffer[3] = 'U'; buffer[4] = 'D'; break; + default: /* Unknown status info, omit it */ + buffer[2] = ')'; + buffer[3] = '\0'; + } + info_summary_append(info_summary_text, submessageId, buffer); +} + + + + +/* *********************************************************************** */ +/* Format the given address (16 octets) as an IPv6 address + */ +static void rtps_util_format_ipv6(guint8 *addr, + guint8 *buffer, + gint buffer_size) { + guint32 i; + guint8 temp[5]; /* Contains a 4-digit hex value */ + + buffer[0] = '\0'; + for (i = 0; i < 16; i+=2) { + /* Unfortunately %x is the same thing as %02x all the time... sigh */ + g_snprintf(temp, 5, "%02x%02x", addr[i], addr[i+1]); + if (temp[0] == '0') { + if (temp[1] == '0') { + if (temp[2] == '0') { + g_strlcat(buffer, &temp[3], buffer_size); + } else { + g_strlcat(buffer, &temp[2], buffer_size); + } + } else { + g_strlcat(buffer, &temp[1], buffer_size); + } + } else { + g_strlcat(buffer, temp, buffer_size); + } + if (i < 14) { + g_strlcat(buffer, ":", buffer_size); + } + } +} + + + + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * NOTE: + * In general those utility functions (they all starts with 'rtps_util') + * are used to dissect some part of a submessage. + * They take as first parameter the proto_tree. + * Now, the proto_tree can be NULL if the dissector is invoked without + * a packet tree. + * Sometimes those functions they also return some value (as result of + * the dissecting). + * At the price of optimizing the code, each function MUST tollerate + * a NULl tree. + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + + + +/* *********************************************************************** */ +static void rtps_util_add_extra_flags(proto_tree *tree, + tvbuff_t *tvb, + gint offset, + const char *label) { + if (tree) { + guint16 flags = NEXT_guint16(tvb, offset, 0); /* Always big endian */ + guint8 temp_buffer[20]; + int i; + for (i = 0; i < 16; ++i) { + temp_buffer[i] = ((flags & (1 << (15-i))) != 0) ? '1' : '0'; + } + temp_buffer[16] = '\0'; + + proto_tree_add_text(tree, + tvb, + offset, + 2, + "%s: %s", + label, + temp_buffer); + } +} + +/* *********************************************************************** */ +static void rtps_util_add_protocol_version(proto_tree *tree, + tvbuff_t * tvb, + gint offset) { + if (tree) { + proto_item * ti; + proto_tree * version_tree; + guint8 major = 0; + guint8 minor = 0; + + major = tvb_get_guint8(tvb, offset); + minor = tvb_get_guint8(tvb, offset+1); + + ti = proto_tree_add_none_format(tree, + hf_rtps_protocol_version, + tvb, + offset, + 2, + "Protocol version: %d.%d", + tvb_get_guint8(tvb, offset), + tvb_get_guint8(tvb, offset+1)); + version_tree = proto_item_add_subtree(ti, + ett_rtps_proto_version); + proto_tree_add_item(version_tree, + hf_rtps_protocol_version_major, + tvb, + offset, + 1, + FALSE); + proto_tree_add_item(version_tree, + hf_rtps_protocol_version_minor, + tvb, + offset+1, + 1, + FALSE); + } +} + + +/* ------------------------------------------------------------------------- */ +/* Interpret the next bytes as vendor ID. If proto_tree and field ID is + * provided, it can also set. + */ +static void rtps_util_add_vendor_id(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { /* Can be 0 */ + guint8 major, minor; + guint32 vendor_id = 0; + guint8 vendor_name[MAX_VENDOR_ID_SIZE]; + + major = tvb_get_guint8(tvb, offset); + minor = tvb_get_guint8(tvb, offset+1); + vendor_id = (major<<8) | minor; + switch(vendor_id) { + case RTPS_VENDOR_UNKNOWN: + g_strlcpy(vendor_name, RTPS_VENDOR_UNKNOWN_STRING, MAX_VENDOR_ID_SIZE); + break; + + case RTPS_VENDOR_RTI: + g_strlcpy(vendor_name, RTPS_VENDOR_RTI_STRING, MAX_VENDOR_ID_SIZE); + break; + + default: + g_snprintf(vendor_name, MAX_VENDOR_ID_SIZE, "%d.%d", major, minor); + } + + if (tree) { + proto_tree_add_uint_format(tree, + hf_rtps_vendor_id, + tvb, + offset, + 2, + vendor_id, + "vendor: %s", + vendor_name); + } + if (buffer != NULL) { + g_strlcpy(buffer, vendor_name, buffer_size); + } +} + + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next 8 bytes interpreted as Locator_t + * + * Locator_t is a struct defined as: + * struct { + * long kind; // kind of locator + * unsigned long port; + * octet[16] address; + * } Locator_t; + */ +static void rtps_util_add_locator_t(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + const guint8 * label, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { /* Can be 0 */ + + proto_item * ti; + proto_tree * locator_tree; + gint32 kind; + guint8 addr[16]; + guint32 port; + char temp_buff[MAX_LOCATOR_SIZE]; + char addr_buff[MAX_IPV6_SIZE]; + const char *kind_string = NULL; + int i; + + + kind = NEXT_guint32(tvb, offset, little_endian); + port = NEXT_guint32(tvb, offset+4, little_endian); + for (i = 0; i < 16; ++i) { + addr[i] = tvb_get_guint8(tvb, offset + 8 + i); + } + + + switch(kind) { + case LOCATOR_KIND_UDPV4: + kind_string = "LOCATOR_KIND_UDPV4"; + g_snprintf(addr_buff, MAX_IPV6_SIZE, + "%d.%d.%d.%d", + addr[12], + addr[13], + addr[14], + addr[15]); + g_snprintf(temp_buff, MAX_LOCATOR_SIZE, "%s:%d", + addr_buff, + port); + break; + + case LOCATOR_KIND_UDPV6: + kind_string = "LOCATOR_KIND_UDPV6"; + rtps_util_format_ipv6(addr, &addr_buff[0], MAX_IPV6_SIZE); + g_snprintf(temp_buff, MAX_LOCATOR_SIZE, + "IPv6: { addr=%s, port=%d }", + addr_buff, + port); + break; + + case LOCATOR_KIND_INVALID: + kind_string = "LOCATOR_KIND_INVALID"; + + case LOCATOR_KIND_RESERVED: + if (!kind_string) /* Need to guard overrides (no break before) */ + kind_string = "LOCATOR_KIND_RESERVED"; + + default: + if (!kind_string) /* Need to guard overrides (no break before) */ + kind_string = "(unknown)"; + g_snprintf(temp_buff, MAX_LOCATOR_SIZE, + "{ kind=%02x, port=%d, addr=%02x %02x %02x ... %02x %02x }", + kind, + port, + addr[0], + addr[1], + addr[2], + /* ... */ + addr[14], + addr[15]); + } + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + offset, + 24, + "%s: %s", + label, + temp_buff); + + locator_tree = proto_item_add_subtree(ti, + ett_rtps_locator); + proto_tree_add_text(locator_tree, + tvb, + offset, + 4, + "kind: %02x (%s)", + kind, + kind_string); + proto_tree_add_text(locator_tree, + tvb, + offset+4, + 4, + "port: %d%s", + port, + (port == 0) ? " (PORT_INVALID)" : ""); + proto_tree_add_text(locator_tree, + tvb, + offset + 8, + 16, + "address: %s", + addr_buff); + } + if (buffer) { + g_strlcpy(buffer, temp_buff, buffer_size); + } +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as a list of + * Locators: + * - unsigned long numLocators + * - locator 1 + * - locator 2 + * - ... + * - locator n + * Returns the new offset after parsing the locator list + */ +static int rtps_util_add_locator_list(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + const guint8 * label, + int little_endian) { + + proto_item *ti; + proto_tree *locator_tree; + guint32 num_locators; + + num_locators = NEXT_guint32(tvb, offset, little_endian); + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %d Locators", + label, + num_locators); + } else { + return offset + 4 + ((num_locators > 0) ? (24 * num_locators) : 0); + } + offset += 4; + if (num_locators > 0) { + guint32 i; + char temp_buff[20]; + + locator_tree = proto_item_add_subtree(ti, + ett_rtps_locator_udp_v4); + + for (i = 0; i < num_locators; ++i) { + g_snprintf(temp_buff, 20, "Locator[%d]", i); + rtps_util_add_locator_t(tree, + tvb, + offset, + little_endian, + temp_buff, + NULL, + 0); + offset += 24; + } + } + return offset; +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next 4 bytes interpreted as IPV4Address_t + */ +static void rtps_util_add_ipv4_address_t(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + const guint8 * label, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { /* Can be 0 */ + + guint32 address; + + address = NEXT_guint32(tvb, offset, little_endian); + if (address == IPADDRESS_INVALID) { + if (buffer) { + g_strlcpy(buffer, IPADDRESS_INVALID_STRING, buffer_size); + } + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %s", + label, + IPADDRESS_INVALID_STRING); + } + } else { + if (buffer) { + g_snprintf(buffer, buffer_size, + "%d.%d.%d.%d", + (address >> 24) & 0xff, + (address >> 16) & 0xff, + (address >> 8) & 0xff, + address & 0xff); + } + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %d.%d.%d.%d", + label, + (address >> 24) & 0xff, + (address >> 16) & 0xff, + (address >> 8) & 0xff, + address & 0xff); + } + } +} + + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next 8 bytes interpreted as LocatorUDPv4 + * + * LocatorUDPv4 is a struct defined as: + * struct { + * unsigned long address; + * unsigned long port; + * } LocatorUDPv4_t; + * + */ +static void rtps_util_add_locator_udp_v4(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + const guint8 * label, + int little_endian) { + if (tree) { + proto_item * ti; + proto_tree * locator_tree; + guint32 port; + char portLabel[MAX_PORT_SIZE]; + char address[MAX_IPV4_ADDRESS_SIZE]; + + port = NEXT_guint32(tvb, offset+4, little_endian); + + if (port == PORT_INVALID) { + g_snprintf(portLabel, MAX_PORT_SIZE, "%s (0x00000000)", PORT_INVALID_STRING); + } else { + g_snprintf(portLabel, MAX_PORT_SIZE, "%u", port); + } + + ti = proto_tree_add_text(tree, + tvb, + offset, + 8, + "addr"); /* Add text later */ + locator_tree = proto_item_add_subtree(ti, ett_rtps_locator_udp_v4); + rtps_util_add_ipv4_address_t(locator_tree, + tvb, + offset, + little_endian, + "address", + address, + MAX_IPV4_ADDRESS_SIZE); + proto_tree_add_text(locator_tree, + tvb, + offset + 4, + 4, + "port: %s", + portLabel); + + proto_item_set_text(ti, "%s: { address=%s, port=%s }", + label, + address, + portLabel); + } +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next 12 bytes interpreted as GuidPrefix + * If tree is specified, it fills up the protocol tree item: + * - hf_rtps_guid_prefix + * - hf_rtps_host_id + * - hf_rtps_app_id + * - hf_rtps_counter + * + * If buffer is specified, it returns in it a string representation of the + * data read. + */ +static void rtps_util_add_guid_prefix(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int hf_prefix, /* Cannot be 0 if tree != NULL */ + int hf_host_id, + int hf_app_id, + int hf_counter, + const guint8 * label, /* Can be NULL */ + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + guint32 host_id; + guint32 app_id; + guint32 counter; + guint8 * temp_buff; + guint8 guid_prefix[12]; + const guint8 * safe_label; + int i; + + safe_label = (label == NULL) ? (const guint8 *)"guidPrefix" : label; + + /* Read values from TVB */ + host_id = tvb_get_ntohl(tvb, offset); + app_id = tvb_get_ntohl(tvb, offset + 4); + counter = tvb_get_ntohl(tvb, offset + 8); + for (i = 0; i < 12; ++i) { + guid_prefix[i] = tvb_get_guint8(tvb, offset+i); + } + + /* Format the string */ + temp_buff = (guint8 *)g_malloc(MAX_GUID_PREFIX_SIZE); + g_snprintf(temp_buff, MAX_GUID_PREFIX_SIZE, + "%s=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x" + " { hostId=%08x, appId=%08x, counter=%08x }", + safe_label, + guid_prefix[0], + guid_prefix[1], + guid_prefix[2], + guid_prefix[3], + guid_prefix[4], + guid_prefix[5], + guid_prefix[6], + guid_prefix[7], + guid_prefix[8], + guid_prefix[9], + guid_prefix[10], + guid_prefix[11], + host_id, + app_id, + counter); + + if (tree) { + proto_item * ti, *hidden_item; + proto_tree * guid_tree; + + /* The numeric value (used for searches) */ + hidden_item = proto_tree_add_item(tree, + hf_prefix, + tvb, + offset, + 12, + FALSE); + PROTO_ITEM_SET_HIDDEN(hidden_item); + + /* The text node (root of the guid prefix sub-tree) */ + ti = proto_tree_add_text(tree, + tvb, + offset, + 12, + temp_buff); + + guid_tree = proto_item_add_subtree(ti, + ett_rtps_guid_prefix); + + /* Host Id */ + proto_tree_add_item(guid_tree, + hf_host_id, + tvb, + offset, + 4, + FALSE); + + /* App Id */ + proto_tree_add_item(guid_tree, + hf_app_id, + tvb, + offset+4, + 4, + FALSE); + + /* Counter */ + proto_tree_add_item(guid_tree, + hf_counter, + tvb, + offset+8, + 4, + FALSE); + } + + if (buffer != NULL) { + g_strlcpy(buffer, temp_buff, buffer_size); + } + g_free(temp_buff); +} + + + +/* ------------------------------------------------------------------------- */ + /* Insert the entityId from the next 4 bytes. Since there are more than + * one entityId, we need to specify also the IDs of the entityId (and its + * sub-components), as well as the label identifying it. + */ +static void rtps_util_add_entity_id(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int hf_item, + int hf_item_entity_key, + int hf_item_entity_kind, + int subtree_entity_id, + const char *label, + guint32 * entity_id_out) { /* Can be NULL */ + guint32 entity_id = tvb_get_ntohl(tvb, offset); + guint32 entity_key = (entity_id >> 8); + guint8 entity_kind = (entity_id & 0xff); + const char *str_predef = match_strval(entity_id, entity_id_vals); + + if (entity_id_out != NULL) { + *entity_id_out = entity_id; + } + + + if (tree) { + proto_tree * entity_tree; + proto_item * ti; + + if (str_predef == NULL) { + /* entityId is not a predefined value, format it */ + ti = proto_tree_add_uint_format(tree, + hf_item, + tvb, + offset, + 4, + entity_id, + "%s: 0x%08x (%s: 0x%06x)", + label, + entity_id, + val_to_str(entity_kind, entity_kind_vals, + "unknown kind (%02x)"), + entity_key); + } else { + /* entityId is a predefined value */ + ti = proto_tree_add_uint_format(tree, + hf_item, + tvb, + offset, + 4, + entity_id, + "%s: %s (0x%08x)", label, str_predef, entity_id); + } + + entity_tree = proto_item_add_subtree(ti, + subtree_entity_id); + + proto_tree_add_item(entity_tree, + hf_item_entity_key, + tvb, + offset, + 3, + FALSE); + + proto_tree_add_item(entity_tree, + hf_item_entity_kind, + tvb, + offset+3, + 1, + FALSE); + + } +} + +/* ------------------------------------------------------------------------- */ + /* Insert the entityId from the next 4 bytes as a generic one (not connected + * to any protocol field). It simply insert the content as a simple text entry + * and returns in the passed buffer only the value (without the label). + */ +static void rtps_util_add_generic_entity_id(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + const char *label, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + guint32 entity_id = tvb_get_ntohl(tvb, offset); + guint32 entity_key = (entity_id >> 8); + guint8 entity_kind = (entity_id & 0xff); + const char *str_predef = match_strval(entity_id, entity_id_vals); + guint8 temp_buffer[MAX_GUID_SIZE]; + + if (str_predef == NULL) { + /* entityId is not a predefined value, format it */ + g_snprintf(temp_buffer, MAX_GUID_SIZE, + "0x%08x (%s: 0x%06x)", + entity_id, + val_to_str(entity_kind, entity_kind_vals, + "unknown kind (%02x)"), + entity_key); + } else { + /* entityId is a predefined value */ + g_snprintf(temp_buffer, MAX_GUID_SIZE, + "%s (0x%08x)", + str_predef, + entity_id); + } + + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %s", + label, + temp_buffer); + } + + if (buffer != NULL) { + g_strlcpy(buffer, temp_buffer, buffer_size); + } +} + + + +/* ------------------------------------------------------------------------- */ + /* Interpret the next 16 octets as a generic GUID and insert it in the protocol + * tree as simple text (no reference fields are set). + * It is mostly used in situation where is not required to perform search for + * this kind of GUID (i.e. like in some DATA parameter lists). + */ +static void rtps_util_add_generic_guid(proto_tree *tree, + tvbuff_t * tvb, /* Cannot be NULL */ + gint offset, + const char *label, /* Cannot be NULL */ + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + + guint32 host_id; + guint32 app_id; + guint32 entity_id; + guint32 entity_key; + guint32 counter; + guint8 entity_kind; + guint8 guid_raw[16]; + const char * str_entity_kind; + guint8 temp_buff[MAX_GUID_SIZE]; + int i; + + /* Read typed data */ + host_id = tvb_get_ntohl(tvb, offset); + app_id = tvb_get_ntohl(tvb, offset + 4); + counter = tvb_get_ntohl(tvb, offset + 8); + entity_id = tvb_get_ntohl(tvb, offset + 12); + + /* Re-Read raw data */ + for (i = 0; i < 16; ++i) { + guid_raw[i] = tvb_get_guint8(tvb, offset+i); + } + + /* Split components from typed data */ + entity_key = (entity_id >> 8); + entity_kind = (entity_id & 0xff); + + /* Lookup for predefined app kind and entity kind */ + str_entity_kind = val_to_str(entity_kind, entity_kind_vals, "%02x"); + + /* Compose output buffer for raw guid */ + g_snprintf(temp_buff, MAX_GUID_SIZE, + "%s=%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x: " + "{ hostId=%08x, appId=%08x, counter=%08x, entityId=%08x (%s: %06x) }", + label, + guid_raw[0], guid_raw[1], guid_raw[2], guid_raw[3], + guid_raw[4], guid_raw[5], guid_raw[6], guid_raw[7], + guid_raw[8], guid_raw[9], guid_raw[10], guid_raw[11], + guid_raw[12], guid_raw[13], guid_raw[14], guid_raw[15], + host_id, + app_id, + counter, + entity_id, str_entity_kind, entity_key); + if (tree) { + proto_tree_add_text(tree, tvb, offset, 16, temp_buff); + } + if (buffer != NULL) { + g_strlcpy(buffer, temp_buff, buffer_size); + } +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next 8 bytes interpreted as sequence + * number. + */ +static guint64 rtps_util_add_seq_number(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + const char *label) { + guint64 hi = (guint64)NEXT_guint32(tvb, offset, little_endian); + guint64 lo = (guint64)NEXT_guint32(tvb, offset+4, little_endian); + guint64 all = (hi << 32) | lo; + + if (tree) { + proto_tree_add_int64_format(tree, + hf_rtps_sm_seq_number, + tvb, + offset, + 8, + all, + "%s: %" PRIu64, label, all); + } + return all; +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next 8 bytes interpreted as NtpTime + */ +static void rtps_util_add_ntp_time(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + const char * label, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + guint8 tempBuffer[MAX_NTP_TIME_SIZE]; + + gint32 sec = NEXT_guint32(tvb, offset, little_endian); + guint32 frac = NEXT_guint32(tvb, offset+4, little_endian); + double absolute; + + if ((sec == 0x7fffffff) && (frac == 0xffffffff)) { + g_strlcpy(tempBuffer, "INFINITE", MAX_NTP_TIME_SIZE); + } else if ((sec == 0) && (frac == 0)) { + g_strlcpy(tempBuffer, "0 sec", MAX_NTP_TIME_SIZE); + } else { + absolute = (double)sec + (double)frac / ((double)(0x80000000) * 2.0); + g_snprintf(tempBuffer, MAX_NTP_TIME_SIZE, + "%f sec (%ds + 0x%08x)", absolute, sec, frac); + } + if (tree) { + proto_item * ti; + proto_tree *time_tree; + + ti = proto_tree_add_none_format(tree, + hf_rtps_param_ntpt, + tvb, + offset, + 8, + "%s: %s", + label, + tempBuffer); + time_tree = proto_item_add_subtree(ti, ett_rtps_ntp_time); + proto_tree_add_item(time_tree, + hf_rtps_param_ntpt_sec, + tvb, + offset, + 4, + little_endian); + proto_tree_add_item(time_tree, + hf_rtps_param_ntpt_fraction, + tvb, + offset+4, + 4, + little_endian); + } + if (buffer != NULL) { + g_strlcpy(buffer, tempBuffer, buffer_size); + } +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next data interpreted as a String + * Returns the new offset (after reading the string) + */ +static gint rtps_util_add_string(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int hf_item, /* Can be -1 (if label!=NULL) */ + int little_endian, + const guint8 * label, /* Can be NULL (if hf_item!=-1) */ + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + guint8 * retVal = NULL; + guint32 size = NEXT_guint32(tvb, offset, little_endian); + + if (size > 0) { + retVal = tvb_get_string(tvb, offset+4, size); + } + + if (tree) { + if (hf_item != -1) { + proto_item * hidden_item; + hidden_item = proto_tree_add_string(tree, + hf_item, + tvb, + offset, + size+4, + (size == 0) ? (guint8 *)"" : retVal); + PROTO_ITEM_SET_HIDDEN(hidden_item); + } + proto_tree_add_text(tree, + tvb, + offset, + size+4, + "%s: \"%s\"", + ((label != NULL) ? label : (const guint8 *)"value") , + (size == 0) ? (guint8 *)"" : retVal); + } + if (buffer != NULL) { + if (size == 0) { + buffer[0] = '\0'; + } else { + g_snprintf(buffer, buffer_size, "%s", retVal); + } + } + if (retVal != NULL) { + g_free(retVal); + } + /* NDDS align strings at 4-bytes word. So: + * string_length: 4 -> buffer_length = 4; + * string_length: 5 -> buffer_length = 8; + * string_length: 6 -> buffer_length = 8; + * string_length: 7 -> buffer_length = 8; + * string_length: 8 -> buffer_length = 8; + * ... + */ + return offset + 4 + ((size + 3) & 0xfffffffc); +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next data interpreted as a signed long. + * Returns the value inserted as a guint32 + */ +static guint32 rtps_util_add_long(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int hf_item, /* Can be -1 */ + int little_endian, + gboolean is_hex, /* Format as 0x... */ + gboolean is_signed, /* Signed/Unsigned */ + const char *label, /* Can be NULL */ + guint8 * buffer, + gint buffer_size) { + + char temp_buff[16]; + + guint32 retVal = NEXT_guint32(tvb, offset, little_endian); + g_snprintf(temp_buff, 16, + (is_hex ? "0x%08x" : (is_signed ? "%d" : "%u")), + NEXT_guint32(tvb, offset, little_endian)); + if (tree != NULL) { + if (hf_item != -1) { + proto_tree_add_item(tree, + hf_item, + tvb, + offset, + 4, + little_endian); + } else if (label != NULL) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %s", + label, + temp_buff); + } + } + if (buffer != NULL) { + g_strlcpy(buffer, temp_buff, buffer_size); + } + return retVal; +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next data interpreted as a 16-bit short + */ +static guint16 rtps_util_add_short(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int hf_item, /* Can be -1 */ + int little_endian, + gboolean is_hex, /* Format as 0x... */ + gboolean is_signed, /* Signed/Unsigned */ + const char *label, /* Can be NULL */ + guint8 * buffer, + gint buffer_size) { + + char temp_buff[16]; + guint16 retVal = NEXT_guint16(tvb, offset, little_endian); + g_snprintf(temp_buff, 16, + (is_hex ? "0x%04x" : (is_signed ? "%d" : "%u")), + retVal); + if (tree != NULL) { + if (hf_item != -1) { + proto_tree_add_item(tree, + hf_item, + tvb, + offset, + 2, + little_endian); + } else if (label != NULL) { + proto_tree_add_text(tree, + tvb, + offset, + 2, + "%s: %s", + label, + temp_buff); + } + } + if (buffer != NULL) { + g_strlcpy(buffer, temp_buff, buffer_size); + } + return retVal; +} + + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next data interpreted as a port (unsigned + * 32-bit integer) + */ +static void rtps_util_add_port(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + char * label, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + guint8 tempBuffer[MAX_PORT_SIZE]; + guint32 value = NEXT_guint32(tvb, offset, little_endian); + + if (value == PORT_INVALID) { + g_snprintf(buffer, buffer_size, "%s (0x00000000)", PORT_INVALID_STRING); + } else { + g_snprintf(tempBuffer, MAX_PORT_SIZE, "%u", value); + } + + if (tree != NULL) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %s", + label, + tempBuffer); + } + if (buffer != NULL) { + g_strlcpy(buffer, tempBuffer, buffer_size); + } +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next data interpreted as a boolean + * Returns the pointer to a dynamically allocated buffer containing the + * formatted version of the value. + */ +static void rtps_util_add_boolean(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + char * label, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + const char *str; + guint8 value = tvb_get_guint8(tvb, offset); + + str = value ? "TRUE" : "FALSE"; + + if (buffer) { + g_strlcpy(buffer, str, buffer_size); + } + + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 1, + "%s: %s", + label, + str); + } +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as + * DurabilityServiceQosPolicy + */ +static void rtps_util_add_durability_service_qos(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + guint8 * buffer, + gint buffer_size) { + guint8 temp_buffer[MAX_NTP_TIME_SIZE]; + gint32 kind = NEXT_guint32(tvb, offset+8, little_endian); + gint32 history_depth = NEXT_guint32(tvb, offset+12, little_endian); + gint32 max_samples = NEXT_guint32(tvb, offset+16, little_endian); + gint32 max_instances = NEXT_guint32(tvb, offset+20, little_endian); + gint32 max_spi = NEXT_guint32(tvb, offset+24, little_endian); + + rtps_util_add_ntp_time(NULL, + tvb, + offset, + little_endian, + NULL, + temp_buffer, + MAX_NTP_TIME_SIZE); + + g_snprintf(buffer, buffer_size, + "{ service_cleanup_delay=%s, history_kind='%s', " + "history_depth=%d, max_samples=%d, max_instances=%d, " + "max_samples_per_instances=%d }", + temp_buffer, + val_to_str(kind, history_qos_vals, "0x%08x"), + history_depth, + max_samples, + max_instances, + max_spi); + if (tree) { + rtps_util_add_ntp_time(tree, + tvb, + offset, + little_endian, + "service_cleanup_delay", + NULL, + 0); + proto_tree_add_text(tree, + tvb, + offset+8, + 4, + "history_kind: %s", + val_to_str(kind, history_qos_vals, "0x%08x")); + proto_tree_add_text(tree, + tvb, + offset+12, + 4, + "history_depth: %d", + history_depth); + proto_tree_add_text(tree, + tvb, + offset+16, + 4, + "max_samples: %d", + max_samples); + proto_tree_add_text(tree, + tvb, + offset+20, + 4, + "max_instances: %d", + max_instances); + proto_tree_add_text(tree, + tvb, + offset+24, + 4, + "max_samples_per_instances: %d", + max_spi); + } +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as Liveliness + * QoS Policy structure. + */ +static void rtps_util_add_liveliness_qos(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + guint8 * buffer, + gint buffer_size) { + guint8 temp_buffer[MAX_NTP_TIME_SIZE]; + guint32 kind = NEXT_guint32(tvb, offset, little_endian); + + rtps_util_add_ntp_time(NULL, + tvb, + offset+4, + little_endian, + NULL, + temp_buffer, + MAX_NTP_TIME_SIZE); + + g_snprintf(buffer, buffer_size, + "{ kind=%s, lease_duration=%s }", + val_to_str(kind, liveliness_qos_vals, "0x%08x"), + temp_buffer); + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "kind: %s", + val_to_str(kind, liveliness_qos_vals, "0x%08x")); + rtps_util_add_ntp_time(tree, + tvb, + offset+4, + little_endian, + "lease_duration", + NULL, + 0); + } +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as enum type. + */ +static void rtps_util_add_kind_qos(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + char * label, + const value_string *vals, + guint8 * buffer, /* Can be NULL */ + gint buffer_size) { + guint32 kind = NEXT_guint32(tvb, offset, little_endian); + + if (buffer) { + g_strlcpy(buffer, val_to_str(kind, vals, "0x%08x"), + buffer_size); + } + + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 4, + "%s: %s", + label, + buffer); + } +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as Sequence of + * Strings. + * The formatted buffer is: "string1", "string2", "string3", ... + * Returns the new updated offset + */ +static gint rtps_util_add_seq_string(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + int param_length, + char * label, + guint8 * buffer, /* Can NOT be NULL */ + gint buffer_size) { + guint32 num_strings; + guint32 i; + proto_tree *string_tree = NULL; + proto_item *ti = NULL; + char temp_buff[MAX_LABEL_SIZE]; + guint8 overview_buffer[MAX_LABEL_SIZE]; + + num_strings = NEXT_guint32(tvb, offset, little_endian); + proto_tree_add_text(tree, + tvb, + offset, + 4, + "size: %d", num_strings); + offset += 4; + + /* Create the string node with a fake string, the replace it later */ + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + offset, + param_length-8, + "Strings"); + string_tree = proto_item_add_subtree(ti, ett_rtps_seq_string); + } + + overview_buffer[0] = '\0'; + + for (i = 0; i < num_strings; ++i) { + g_snprintf(temp_buff, MAX_LABEL_SIZE, + "%s[%d]", + label, + i); + /* This call safe with string_tree=NULL and is required to calculate offset */ + offset = rtps_util_add_string(string_tree, + tvb, + offset, + -1, + little_endian, + temp_buff, + overview_buffer+strlen(overview_buffer), + MAX_LABEL_SIZE-strlen(overview_buffer)); + } + if (tree) { + proto_item_set_text(ti, + "%s: %s", + label, + overview_buffer); + } + if (buffer != NULL) { + g_strlcpy(buffer, overview_buffer, buffer_size); + } + return offset; +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as Sequence of + * longs. + * The formatted buffer is: val1, val2, val3, ... + * Returns the new updated offset + */ +static gint rtps_util_add_seq_ulong(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + int param_length, + int is_hex, + int is_signed, + char * label) { + guint32 num_elem; + guint32 i; + proto_tree *string_tree; + proto_item *ti; + char temp_buff[MAX_LABEL_SIZE]; + char overview_buff[MAX_PARAM_SIZE]; + + num_elem = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* Create the string node with an empty string, the replace it later */ + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + offset, + param_length-8, + "Seq"); + string_tree = proto_item_add_subtree(ti, ett_rtps_seq_ulong); + } else { + return offset + 4*num_elem; + } + + overview_buff[0] = '\0'; + + for (i = 0; i < num_elem; ++i) { + g_snprintf(temp_buff, MAX_LABEL_SIZE, + "%s[%d]", + label, + i); + rtps_util_add_long( string_tree, + tvb, + offset, + -1, + little_endian, + is_hex, + is_signed, + temp_buff, + overview_buff+strlen(overview_buff), + MAX_PARAM_SIZE-strlen(overview_buff)); + offset += 4; + } + proto_item_set_text(ti, + "%s: %s", + label, + overview_buff); + return offset; +} + + +#define LONG_ALIGN(x) (x = (x+3)&0xfffffffc) +#define SHORT_ALIGN(x) (x = (x+1)&0xfffffffe) +#define MAX_ARRAY_DIMENSION 10 +#define KEY_COMMENT (" //@key") + +/* ------------------------------------------------------------------------- */ +static const char * rtps_util_typecode_id_to_string(guint32 typecode_id) { + switch(typecode_id) { + case RTI_CDR_TK_ENUM: return "enum"; + case RTI_CDR_TK_UNION: return "union"; + case RTI_CDR_TK_STRUCT: return "struct"; + case RTI_CDR_TK_LONG: return "long"; + case RTI_CDR_TK_SHORT: return "short"; + case RTI_CDR_TK_USHORT: return "unsigned short"; + case RTI_CDR_TK_ULONG: return "unsigned long"; + case RTI_CDR_TK_FLOAT: return "float"; + case RTI_CDR_TK_DOUBLE: return "double"; + case RTI_CDR_TK_BOOLEAN:return "boolean"; + case RTI_CDR_TK_CHAR: return "char"; + case RTI_CDR_TK_OCTET: return "octet"; + case RTI_CDR_TK_LONGLONG:return "longlong"; + case RTI_CDR_TK_ULONGLONG: return "unsigned long long"; + case RTI_CDR_TK_LONGDOUBLE: return "long double"; + case RTI_CDR_TK_WCHAR: return "wchar"; + case RTI_CDR_TK_WSTRING:return "wstring"; + case RTI_CDR_TK_STRING: return "string"; + case RTI_CDR_TK_SEQUENCE: return "sequence"; + case RTI_CDR_TK_ARRAY: return "array"; + case RTI_CDR_TK_ALIAS: return "alias"; + case RTI_CDR_TK_VALUE: return "valuetype"; + + case RTI_CDR_TK_NULL: + default: + return "<unknown type>"; + } +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as typecode info + * Returns the number of bytes parsed + */ +static gint rtps_util_add_typecode(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + int indent_level, + int is_pointer, + guint16 bitfield, + int is_key, + const gint offset_begin, + char * name, + int seq_max_len, /* -1 = not a sequence field */ + guint32 * arr_dimension, /* if !NULL: array of 10 int */ + int ndds_40_hack) { + const gint original_offset = offset; + guint32 tk_id; + guint16 tk_size; + unsigned int i; + char indent_string[40]; + gint retVal; + char type_name[40]; + + /* Structure of the typecode data: + * Offset | Size | Field | Notes + * ----------|-------|------------------------------|--------------------- + * ? | ? | pad? | + * 0 | 4 | RTI_CDR_TK_XXXXX | 4 bytes aligned + * 4 | 2 | length the struct | + */ + + /* Calc indent string */ + memset(indent_string, ' ', 40); + indent_string[indent_level*2] = '\0'; + + /* Gets TK ID */ + LONG_ALIGN(offset); + tk_id = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* Gets TK size */ + tk_size = NEXT_guint16(tvb, offset, little_endian); + offset += 2; + + retVal = tk_size + 6; /* 6 = 4 (typecode ID) + 2 (size) */ + + /* The first bit of typecode is set to 1, clear it */ + tk_id &= 0x7fffffff; + + /* HACK: NDDS 4.0 and NDDS 4.1 has different typecode ID list. + * The ID listed in the RTI_CDR_TK_XXXXX are the one from NDDS 4.1 + * In order to correctly dissect NDDS 4.0 packets containing typecode + * information, we check if the ID of the element at level zero is a + * struct or union. If not, it means we are dissecting a ndds 4.0 packet + * (and we can decrement the ID to match the correct values). + */ + if (indent_level == 0) { + if (tk_id == RTI_CDR_TK_OCTET) { + ndds_40_hack = 1; + } + } + if (ndds_40_hack) { + ++tk_id; + } + + g_strlcpy(type_name, rtps_util_typecode_id_to_string(tk_id), 40); + + /* Structure of the typecode data: + * + * <type_code_header> ::= + * <kind> + * <type_code_length> + * + * <kind> ::= long (0=TK_NULL, 1=TK_SHORT...) + * <type_code_length> ::= unsugned short + * + */ + switch(tk_id) { + + /* Structure of the typecode data: + * + * <union_type_code> ::= + * <type_code_header> + * <name> + * <default_index> + * <discriminator_type_code> + * <member_count> + * <union_member>+ + * <union_member> ::= <member_length><name><union_member_detail> + * <member_length> ::= unsigned short + * <name> ::= <string> + * <string> ::= <length>char+<eol> + * <length> ::= unsigned long + * <eol> ::= (char)0 + * + * <union_member_detail> ::= <is_pointer> + * <labels_count> + * <label>+ + * <type_code> + * <labels_count> ::= unsigned long + * <label> ::= long + * + */ + case RTI_CDR_TK_UNION: { + guint32 struct_name_len; + gint8 * struct_name; + const char * discriminator_name = "<unknown>"; /* for unions */ + char * discriminator_enum_name = NULL; /* for unions with enum discriminator */ + guint32 defaultIdx; /* Currently is ignored */ + guint32 disc_id; /* Used temporarily to populate 'discriminator_name' */ + guint16 disc_size; /* Currently is ignored */ + guint32 disc_offset_begin; + guint32 num_members; + guint16 member_length; + guint32 member_name_len; + guint8 *member_name = NULL; + guint8 member_is_pointer; + guint32 next_offset; + guint32 field_offset_begin; + guint32 member_label_count; + gint32 member_label; + guint32 discriminator_enum_name_length; + guint j; + + /* - - - - - - - Union name - - - - - - - */ + /* Pad-align */ + LONG_ALIGN(offset); + + /* Get structure name length */ + struct_name_len = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + struct_name = tvb_get_string(tvb, offset, struct_name_len); + offset += struct_name_len; + + /* - - - - - - - Default index - - - - - - - */ + LONG_ALIGN(offset); + defaultIdx = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* - - - - - - - Discriminator type code - - - - - - - */ + /* We don't recursively dissect everything, instead we just read the type */ + disc_id = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + disc_size = NEXT_guint16(tvb, offset, little_endian); + offset += 2; + disc_offset_begin = offset; + disc_id &= 0x7fffffff; + discriminator_name = rtps_util_typecode_id_to_string(disc_id); + if (disc_id == RTI_CDR_TK_ENUM) { + /* Enums has also a name that we should print */ + LONG_ALIGN(offset); + discriminator_enum_name_length = NEXT_guint32(tvb, offset, little_endian); + discriminator_enum_name = tvb_get_string(tvb, offset+4, discriminator_enum_name_length); + } + offset = disc_offset_begin + disc_size; +/* + field_offset_begin = offset; + offset += rtps_util_add_typecode( + tree, + tvb, next_offset = offset; + + offset, + little_endian, + indent_level+1, + 0, + 0, + 0, + field_offset_begin, + member_name, + -1, + NULL, + ndds_40_hack); +*/ + + + /* Add the entry of the union in the tree */ + proto_tree_add_text(tree, + tvb, + original_offset, + retVal, + "%sunion %s (%s%s%s) {", + indent_string, + struct_name, + discriminator_name, + (discriminator_enum_name ? " " : ""), + (discriminator_enum_name ? discriminator_enum_name : "")); + + if (seq_max_len != -1) { + /* We're dissecting a sequence of struct, bypass the seq definition */ + g_snprintf(type_name, 40, "%s", struct_name); + g_free(struct_name); + break; + } + + g_free(struct_name); + /* - - - - - - - Number of members - - - - - - - */ + LONG_ALIGN(offset); + num_members = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* - - - - - - - <union_member>+ - - - - - - - */ + next_offset = offset; + + for (i = 0; i < num_members; ++i) { + /* Safety: this theoretically should be the same already */ + field_offset_begin = offset = next_offset; + + SHORT_ALIGN(offset); + + /* member's length */ + member_length = NEXT_guint16(tvb, offset, little_endian); + offset += 2; + next_offset = offset + member_length; + + /* Name length */ + LONG_ALIGN(offset); + member_name_len = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* Name */ + member_name = tvb_get_string(tvb, offset, member_name_len); + offset += member_name_len; + + /* is Pointer ? */ + member_is_pointer = tvb_get_guint8(tvb, offset); + offset++; + + /* Label count */ + LONG_ALIGN(offset); + member_label_count = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + for (j = 0; j < member_label_count; ++j) { + /* Label count */ + LONG_ALIGN(offset); + member_label = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* Add the entry of the union in the tree */ + proto_tree_add_text(tree, + tvb, + field_offset_begin, + retVal, + "%s case %d:", + indent_string, + member_label); + } + + offset += rtps_util_add_typecode( + tree, + tvb, + offset, + little_endian, + indent_level+2, + member_is_pointer, + 0, + 0, + field_offset_begin, + member_name, + -1, + NULL, + ndds_40_hack); + g_free(member_name); + } + /* Finally prints the name of the struct (if provided) */ + g_strlcpy(type_name, "}", 40); + break; + + } /* end of case UNION */ + + + case RTI_CDR_TK_ENUM: + case RTI_CDR_TK_STRUCT: { + /* Structure of the typecode data: + * + * <union_type_code> ::= + * <type_code_header> + * <name> + * <default_index> + * <discriminator_type_code> + * <member_count> + * <member>+ + * + * <struct_type_code> ::= + * <type_code_header> + * <name> + * <member_count> + * <member>+ + * + * <name> ::= <string> + * <string> ::= <length>char+<eol> + * <length> ::= unsigned long + * <eol> ::= (char)0 + * <member_count> ::= unsigned long + * + * STRUCT / UNION: + * Foreach member { + * - A2: 2: member length + * - A4: 4: member name length + * - n: member name + * - 1: isPointer? + * - A2 2: bitfield bits (-1=none) + * - 1: isKey? + * - A4 4: Typecode ID + * - A2 2: length + * } + * + * ENUM: + * Foreach member { + * - A2: 2: member length + * - A4: 4: member name length + * - n: member name + * - A4: 4: ordinal number + * + * -> ----------------------------------------------------- <- + * -> The alignment pad bytes belong to the FOLLOWING field <- + * -> A4 = 4 bytes alignment, A2 = 2 bytes alignment <- + * -> ----------------------------------------------------- <- + */ + guint32 struct_name_len; + gint8 * struct_name; + guint32 num_members; + guint16 member_length; + guint8 member_is_pointer; + guint16 member_bitfield; + guint8 member_is_key; + guint32 member_name_len; + guint8 *member_name = NULL; + guint32 next_offset; + guint32 field_offset_begin; + guint32 ordinal_number; + const char * typecode_name; + + /* Pad-align */ + LONG_ALIGN(offset); + + /* Get structure name length */ + struct_name_len = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* struct name */ + struct_name = tvb_get_string(tvb, offset, struct_name_len); + offset += struct_name_len; + + + if (tk_id == RTI_CDR_TK_ENUM) { + typecode_name = "enum"; + } else { + typecode_name = "struct"; + } + + if (seq_max_len != -1) { + /* We're dissecting a sequence of struct, bypass the seq definition */ + g_snprintf(type_name, 40, "%s", struct_name); + g_free(struct_name); + break; + } + /* Prints it */ + proto_tree_add_text(tree, + tvb, + original_offset, + retVal, + "%s%s %s {", + indent_string, + typecode_name, + struct_name); + g_free(struct_name); + + /* PAD align */ + LONG_ALIGN(offset); + + /* number of members */ + num_members = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + next_offset = offset; + for (i = 0; i < num_members; ++i) { + /* Safety: this theoretically should be the same already */ + field_offset_begin = offset = next_offset; + + SHORT_ALIGN(offset); + + /* member's length */ + member_length = NEXT_guint16(tvb, offset, little_endian); + offset += 2; + next_offset = offset + member_length; + + /* Name length */ + LONG_ALIGN(offset); + member_name_len = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* Name */ + member_name = tvb_get_string(tvb, offset, member_name_len); + offset += member_name_len; + + if (tk_id == RTI_CDR_TK_ENUM) { + /* ordinal number */ + LONG_ALIGN(offset); + ordinal_number = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + proto_tree_add_text(tree, + tvb, + field_offset_begin, + (offset-field_offset_begin), + "%s %s = %d;", + indent_string, + member_name, + ordinal_number); + } else { + /* Structs */ + + /* is Pointer ? */ + member_is_pointer = tvb_get_guint8(tvb, offset); + offset++; + + /* Bitfield */ + SHORT_ALIGN(offset); + member_bitfield = NEXT_guint16(tvb, offset, little_endian); + offset += 2; /* pad will be added by typecode dissector */ + + /* is Key ? */ + member_is_key = tvb_get_guint8(tvb, offset); + offset++; + + offset += rtps_util_add_typecode( + tree, + tvb, + offset, + little_endian, + indent_level+1, + member_is_pointer, + member_bitfield, + member_is_key, + field_offset_begin, + member_name, + -1, + NULL, + ndds_40_hack); + } + + g_free(member_name); + } + /* Finally prints the name of the struct (if provided) */ + g_strlcpy(type_name, "}", 40); + break; + } + + case RTI_CDR_TK_WSTRING: + case RTI_CDR_TK_STRING: { + /* Structure of the typecode data: + * Offset | Size | Field | Notes + * ----------|-------|------------------------------|--------------------- + * 6 | 2 | pad | + * 8 | 4 | String length | 4-bytes aligned + */ + guint32 string_length; + + LONG_ALIGN(offset); + string_length = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + g_snprintf(type_name, 40, "%s<%d>", + (tk_id == RTI_CDR_TK_STRING) ? "string" : "wstring", + string_length); + break; + } + + case RTI_CDR_TK_SEQUENCE: { + /* Structure of the typecode data: + * + * - A4: 4: Sequence max length + * - the sequence typecode + */ + guint32 seq_max_len; + LONG_ALIGN(offset); + seq_max_len = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* Recursive decode seq typecode */ + offset += rtps_util_add_typecode( + tree, + tvb, + offset, + little_endian, + indent_level, + is_pointer, + bitfield, + is_key, + offset_begin, + name, + seq_max_len, + NULL, + ndds_40_hack); + /* Differently from the other typecodes, the line has been already printed */ + return retVal; + } + + case RTI_CDR_TK_ARRAY: { + /* Structure of the typecode data: + * + * - A4: 4: number of dimensions + * - A4: 4: dim1 + * - <A4: 4: dim2> + * - ... + * - the array typecode + */ + guint32 size[MAX_ARRAY_DIMENSION]; /* Max dimensions */ + guint32 dim_max; + + LONG_ALIGN(offset); + dim_max = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + for (i = 0; i < MAX_ARRAY_DIMENSION; ++i) size[i] = 0; + for (i = 0; i < dim_max; ++i) { + size[i] = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + } + + /* Recursive decode seq typecode */ + offset += rtps_util_add_typecode( + tree, + tvb, + offset, + little_endian, + indent_level, + is_pointer, + bitfield, + is_key, + offset_begin, + name, + -1, + size, + ndds_40_hack); + /* Differently from the other typecodes, the line has been already printed */ + return retVal; + } + + case RTI_CDR_TK_ALIAS: { + /* Structure of the typecode data: + * + * - A4: 4: alias name size + * - A4: 4: alias name + * - A4: 4: the alias typecode + */ + guint32 alias_name_length; + guint8 *alias_name; + + LONG_ALIGN(offset); + alias_name_length = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + alias_name = tvb_get_string(tvb, offset, alias_name_length); + offset += alias_name_length; + g_strlcpy(type_name, alias_name, 40); + g_free(alias_name); + break; + } + + + /* + * VALUETYPES: + * - A4: 4: name length + * - n: name + * - A2: type modifier + * - A4: base type code + * - A4: number of members + * Foreach member: (it's just like a struct) + * + */ + case RTI_CDR_TK_VALUE: { + /* Not fully dissected for now */ + /* Pad-align */ + guint32 value_name_len; + gint8 * value_name; + LONG_ALIGN(offset); + + /* Get structure name length */ + value_name_len = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + + /* value name */ + value_name = tvb_get_string(tvb, offset, value_name_len); + offset += value_name_len; + + g_snprintf(type_name, 40, "valuetype %s", value_name); + break; + } + } /* switch(tk_id) */ + + /* Sequence print */ + if (seq_max_len != -1) { + proto_tree_add_text(tree, + tvb, + offset_begin, + (offset-offset_begin), + "%ssequence<%s, %d> %s%s;%s", + indent_string, + type_name, + seq_max_len, + is_pointer ? "*" : "", + name ? name : "", + is_key ? KEY_COMMENT : ""); + return retVal; + } + + /* Array print */ + if (arr_dimension != NULL) { + /* Printing an array */ + char dim_str[40]; + dim_str[0] = '\0'; + for (i = 0; i < MAX_ARRAY_DIMENSION; ++i) { + if (arr_dimension[i] != 0) { + g_snprintf(dim_str+strlen(dim_str), + 40-strlen(dim_str), + "[%d]", arr_dimension[i]); + } else { + break; + } + } + proto_tree_add_text(tree, + tvb, + offset_begin, + (offset-offset_begin), + "%s%s %s%s;%s", + indent_string, + type_name, + name ? name : "", + dim_str, + is_key ? KEY_COMMENT : ""); + return retVal; + } + + /* Bitfield print */ + if (bitfield != 0xffff && name != NULL && is_pointer == 0) { + proto_tree_add_text(tree, + tvb, + offset_begin, + (offset-offset_begin), + "%s%s %s:%d;%s", + indent_string, + type_name, + name ? name : "", + bitfield, + is_key ? KEY_COMMENT : ""); + return retVal; + } + + /* Everything else */ + proto_tree_add_text(tree, + tvb, + offset_begin, + (offset-offset_begin), + "%s%s%s%s%s;%s", + indent_string, + type_name, + name ? " " : "", + is_pointer ? "*" : "", + name ? name : "", + is_key ? KEY_COMMENT : ""); + return retVal; +} + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as Sequence of + * Octets. + * The formatted buffer is: [ 0x01, 0x02, 0x03, 0x04, ...] + * The maximum number of elements displayed is 10, after that a '...' is + * inserted. + */ +static void rtps_util_add_seq_octets(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + int param_length, + int hf_id, + guint8 * buffer, + gint buffer_size) { + gint idx = 0; + guint32 seq_length; + guint32 i; + gint original_offset = offset; + guint32 original_seq_length; + + + original_seq_length = seq_length = NEXT_guint32(tvb, offset, little_endian); + + offset += 4; + if (param_length < 4 + (int)seq_length) { + g_strlcpy(buffer, "RTPS PROTOCOL ERROR: parameter value too small", buffer_size); + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + param_length, + buffer); + } + return ; + } + + /* Limit the number of octets displayed to MAX_SEQ_OCTETS_PRINTED */ + if (seq_length > MAX_SEQ_OCTETS_PRINTED) { + seq_length = MAX_SEQ_OCTETS_PRINTED; + } + for (i = 0; i < seq_length; ++i) { + idx += g_snprintf(&buffer[idx], + buffer_size - idx - 1, + "%02x", + tvb_get_guint8(tvb, offset++)); + if (idx >= buffer_size) { + break; + } + } + if (seq_length != original_seq_length) { + /* seq_length was reduced, add '...' */ + g_strlcat(buffer, "...", buffer_size); + } + + if (tree) { + proto_tree_add_text(tree, + tvb, + original_offset, + 4, + "sequenceSize: %d octets", + original_seq_length); + proto_tree_add_item(tree, + hf_id, + tvb, + original_offset+4, + original_seq_length, + little_endian); + + } +} + + + + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as a Bitmap + * struct { + * SequenceNumber_t bitmapBase; + * sequence<long, 8> bitmap; + * } SequenceNumberSet; + * + * Returns the new offset after reading the bitmap. + */ +static int rtps_util_add_bitmap(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + const char *label) { + guint64 seq_base; + gint32 num_bits; + guint32 data; + char temp_buff[MAX_BITMAP_SIZE]; + int i, j, idx; + proto_item * ti; + proto_tree * bitmap_tree; + const gint original_offset = offset; + guint32 datamask; + + /* Bitmap base sequence number */ + seq_base = rtps_util_add_seq_number(NULL, + tvb, + offset, + little_endian, + NULL); + offset += 8; + + /* Reads the bitmap size */ + num_bits = NEXT_guint32(tvb, offset, little_endian); + + offset += 4; + + /* Reads the bits (and format the print buffer) */ + idx = 0; + temp_buff[0] = '\0'; + for (i = 0; i < num_bits; i += 32) { + data = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + for (j = 0; j < 32; ++j) { + datamask = (1 << (31-j)); + temp_buff[idx] = ((data & datamask) == datamask) ? '1':'0'; + ++idx; + if (idx >= num_bits) { + break; + } + if (idx >= MAX_BITMAP_SIZE-1) { + break; + } + } + } + temp_buff[idx] = '\0'; + + /* removes all the ending '0' */ + for (i = strlen(temp_buff) - 1; (i>0 && temp_buff[i] == '0'); --i) { + temp_buff[i] = '\0'; + } + + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + original_offset, + offset-original_offset, + "%s: %" PRIu64 "/%d:%s", + label, + seq_base, + num_bits, + temp_buff); + bitmap_tree = proto_item_add_subtree(ti, ett_rtps_bitmap); + proto_tree_add_text(bitmap_tree, + tvb, + original_offset, + 8, + "bitmapBase: %" PRIu64, + seq_base); + proto_tree_add_text(bitmap_tree, + tvb, + original_offset + 8, + 4, + "numBits: %u", + num_bits); + if (temp_buff[0] != '\0') { + proto_tree_add_text(bitmap_tree, + tvb, + original_offset + 12, + offset - original_offset - 12, + "bitmap: %s", + temp_buff); + } + } + return offset; +} + +/* ------------------------------------------------------------------------- */ +/* Insert in the protocol tree the next bytes interpreted as a FragmentNumberSet + * typedef unsigned long FragmentNumber_t; + * struct { + * FragmentNumber_t bitmapBase; + * sequence<FragmentNumber_t> bitmap; + * } FragmentNumberSet; + * + * Returns the new offset after reading the bitmap. + */ +static int rtps_util_add_fragment_number_set(proto_tree *tree, + tvbuff_t * tvb, + gint offset, + int little_endian, + const char *label, + gint section_size) { + guint64 base; + gint32 num_bits; + guint32 data; + char temp_buff[MAX_BITMAP_SIZE]; + int i, j, idx; + proto_item * ti; + proto_tree * bitmap_tree; + const gint original_offset = offset; + guint32 datamask; + gint expected_size; + gint base_size; + + /* RTI DDS 4.2d was sending the FragmentNumber_t as a 64-bit long integer + * instead of 32-bit long. + * Attempt to decode this section as 32-bit, then check if the size of the + * message match what is here. If not re-decode it as 64-bit. + */ + num_bits = NEXT_guint32(tvb, offset+4, little_endian); + expected_size = (((num_bits / 8) + 3) / 4) * 4 + 8; + if (expected_size == section_size) { + base = (guint64)NEXT_guint32(tvb, offset, little_endian); + base_size = 4; + offset += 8; + } else { + /* Attempt to use 64-bit for base */ + num_bits = NEXT_guint32(tvb, offset+8, little_endian); + /* num_bits/8 must be aligned to the 4-byte word */ + expected_size = (((num_bits / 8) + 3) / 4) * 4 + 12; + if (expected_size == section_size) { + guint64 hi = (guint64)NEXT_guint32(tvb, offset, little_endian); + guint64 lo = (guint64)NEXT_guint32(tvb, offset+4, little_endian); + base = (hi << 32) | lo; + base_size = 8; + offset += 12; + } else { + /* size don't match, packet error */ + if (tree) { + proto_tree_add_text(tree, + tvb, + original_offset, + section_size, + "Packet malformed: illegal size for fragment number set"); + } + return -1; + } + } + + /* Reads the bits (and format the print buffer) */ + idx = 0; + temp_buff[0] = '\0'; + for (i = 0; i < num_bits; i += 32) { + data = NEXT_guint32(tvb, offset, little_endian); + offset += 4; + for (j = 0; j < 32; ++j) { + datamask = (1 << (31-j)); + temp_buff[idx] = ((data & datamask) != 0) ? '1':'0'; + ++idx; + if (idx > num_bits) { + break; + } + if (idx >= MAX_BITMAP_SIZE-1) { + break; + } + } + } + temp_buff[idx] = '\0'; + + /* removes all (but the last one) characters '0' */ + for (i = strlen(temp_buff) - 1; (i>0 && temp_buff[i] == '0'); --i) { + temp_buff[i] = '\0'; + } + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + original_offset, + offset-original_offset, + "%s: %" PRIu64 "/%d:%s", + label, + base, + num_bits, + temp_buff); + bitmap_tree = proto_item_add_subtree(ti, ett_rtps_bitmap); + proto_tree_add_text(bitmap_tree, + tvb, + original_offset, + base_size, + "bitmapBase: %" PRIu64, + base); + proto_tree_add_text(bitmap_tree, + tvb, + original_offset + base_size, + 4, + "numBits: %u", + num_bits); + if (temp_buff[0] != '\0') { + proto_tree_add_text(bitmap_tree, + tvb, + original_offset + base_size + 4, + offset - original_offset - base_size - 4, + "bitmap: %s", + temp_buff); + } + } + return offset; +} + + +/* ------------------------------------------------------------------------- */ +/* Decode the submessage flags (8 bit version) + */ +static void rtps_util_decode_flags(proto_tree * tree, + tvbuff_t *tvb, + gint offset, + guint8 flags, + const struct Flag_definition * flag_def) { + + proto_item * ti; + proto_tree * flags_tree; + int i, j; + char flags_str[MAX_FLAG_SIZE]; + if (tree == NULL) { + return; + } + + flags_str[0] = '\0'; + for (i = 0; i < 8; ++i) { + g_snprintf(flags_str + (2 * i), MAX_FLAG_SIZE - (2 * i), "%c ", + ((flags & (1<<(7-i))) ? flag_def[i].letter : RESERVEDFLAG_CHAR)); + } + + ti = proto_tree_add_uint_format(tree, + hf_rtps_sm_flags, + tvb, + offset, + 1, + flags, + "Flags: 0x%02x (%s)", + flags, + flags_str); + + flags_tree = proto_item_add_subtree(ti, + ett_rtps_flags); + + for (i = 0; i < 8; ++i) { + int is_set = (flags & (1 << (7-i))); + + for (j = 0; j < 8; ++j) { + flags_str[j] = (i == j) ? (is_set ? '1' : '0') : '.'; + } + flags_str[8] = '\0'; + + proto_tree_add_text(flags_tree, + tvb, + offset, + 1, + "%s = %s: %s", + flags_str, + flag_def[i].description, + is_set ? "Set" : "Not set"); + } + +} + +/* ------------------------------------------------------------------------- */ +/* Decode the submessage flags (16 bit version) + */ +static void rtps_util_decode_flags_16bit(proto_tree * tree, + tvbuff_t *tvb, + gint offset, + guint16 flags, + const struct Flag_definition * flag_def) { + + proto_item * ti; + proto_tree * flags_tree; + int i, j; + char flags_str[MAX_FLAG_SIZE]; + if (tree == NULL) { + return; + } + + flags_str[0] = '\0'; + for (i = 0; i < 16; ++i) { + g_snprintf(flags_str + (2 * i), MAX_FLAG_SIZE - (2 * i), "%c ", + ((flags & (1<<(15-i))) ? flag_def[i].letter : RESERVEDFLAG_CHAR)); + } + + ti = proto_tree_add_uint_format(tree, + hf_rtps_sm_flags, + tvb, + offset, + 2, + flags, + "Flags: 0x%04x (%s)", + flags, + flags_str); + + flags_tree = proto_item_add_subtree(ti, + ett_rtps_flags); + + for (i = 0; i < 16; ++i) { + int is_set = (flags & (1 << (15-i))); + + for (j = 0; j < 16; ++j) { + flags_str[j] = (i == j) ? (is_set ? '1' : '0') : '.'; + } + flags_str[16] = '\0'; + + proto_tree_add_text(flags_tree, + tvb, + offset, + 2, + "%s = %s: %s", + flags_str, + flag_def[i].description, + is_set ? "Set" : "Not set"); + } +} + + + +/* *********************************************************************** */ +/* * Serialized data dissector * */ +/* *********************************************************************** */ +/* Note: the encapsulation header is ALWAYS big endian, then the encapsulation + * type specified the type of endianess of the payload. + */ +static void dissect_serialized_data(proto_tree *tree, + tvbuff_t *tvb, + gint offset, + int size, + const char * label, + guint16 vendor_id) { + proto_item * ti; + proto_tree * rtps_parameter_sequence_tree; + guint16 encapsulation_id; + guint16 encapsulation_len; + int encapsulation_little_endian = 0; + if (tree == NULL) { + return; + } + + /* Creates the sub-tree */ + ti = proto_tree_add_text(tree, + tvb, + offset, + -1, + "%s:", label); + rtps_parameter_sequence_tree = proto_item_add_subtree(ti, + ett_rtps_serialized_data); + + + /* Encapsulation ID */ + encapsulation_id = NEXT_guint16(tvb, offset, 0); /* Always big endian */ + + proto_tree_add_text(rtps_parameter_sequence_tree, + tvb, + offset, + 2, + "encapsulation kind: %s", + val_to_str(encapsulation_id, encapsulation_id_vals, "unknown (%02x)")); + offset += 2; + + /* Sets the correct values for encapsulation_le */ + if (encapsulation_id == ENCAPSULATION_CDR_LE || + encapsulation_id == ENCAPSULATION_PL_CDR_LE) { + encapsulation_little_endian = 1; + } + + /* Encapsulation length (or option) */ + encapsulation_len = NEXT_guint16(tvb, offset, 0); /* Always big endian */ + proto_tree_add_text(rtps_parameter_sequence_tree, + tvb, + offset, + 2, + "encapsulation options: %04x", + encapsulation_len); + offset += 2; + + /* The payload */ + size -= 4; + switch (encapsulation_id) { + case ENCAPSULATION_CDR_LE: + case ENCAPSULATION_CDR_BE: + proto_tree_add_item(rtps_parameter_sequence_tree, + hf_rtps_issue_data, + tvb, + offset, + size, + encapsulation_little_endian); + break; + + case ENCAPSULATION_PL_CDR_LE: + case ENCAPSULATION_PL_CDR_BE: + dissect_parameter_sequence(rtps_parameter_sequence_tree, + tvb, + offset, + encapsulation_little_endian, + size, + label, NULL, vendor_id); + break; + + default: + proto_tree_add_text(rtps_parameter_sequence_tree, + tvb, + offset, + size, + label); + } +} + + +/* *********************************************************************** + * The dissector for octet seq (serialized data) + * For a sequence of octets, the first word is always the sequence length + * followed by all the raw bytes. + */ +static void dissect_octet_seq(proto_tree *tree, + tvbuff_t *tvb, + gint offset, + const char * label) { + proto_item * ti; + proto_tree * rtps_parameter_sequence_tree; + guint32 length; + if (tree == NULL) { + return; + } + + /* Creates the sub-tree */ + ti = proto_tree_add_text(tree, + tvb, + offset, + -1, + "%s:", label); + rtps_parameter_sequence_tree = proto_item_add_subtree(ti, + ett_rtps_serialized_data); + + + /* Length */ + length = NEXT_guint32(tvb, offset, 0); /* Always big endian */ + + proto_tree_add_text(rtps_parameter_sequence_tree, + tvb, + offset, + 4, + "Sequence length: %d", length); + offset += 4; + + /* The payload */ + proto_tree_add_item(rtps_parameter_sequence_tree, + hf_rtps_issue_data, + tvb, + offset, + length, + 0); +} + + + +/* *********************************************************************** */ +/* * Parameter Sequence dissector * */ +/* *********************************************************************** */ +/* + * It returns the new offset representing the point where the parameter + * sequence terminates. + * In case of protocol error, it returns 0 (cannot determine the end of + * the sequence, the caller should be responsible to find the end of the + * section if possible or pass the error back and abort dissecting the + * current packet). + * If no error occurred, the returned value is ALWAYS > than the offset passed. + * + * Note: even if tree==NULL, we still have to go through the PID because + * since RTPS 2.1, the status info is now stored in a PID (and the + * status info is required to format the INFO column). + */ +#define ENSURE_LENGTH(size) \ + if (param_length < size) { \ + proto_tree_add_text(rtps_parameter_tree, \ + tvb, offset, param_length, \ + "RTPS PROTOCOL ERROR: parameter value too small"\ + " (must be at least %d octets)", size); \ + break; \ + } + +static gint dissect_parameter_sequence(proto_tree *tree, + tvbuff_t *tvb, + gint offset, + int little_endian, + int size, + const char * label, + guint32 *pStatusInfo, + guint16 vendor_id) { + proto_item * ti = NULL; + proto_tree * rtps_parameter_sequence_tree = NULL; + proto_tree * rtps_parameter_tree = NULL; + guint16 parameter, param_length; + guint8 buffer[MAX_PARAM_SIZE]; + gint original_offset = offset; + + buffer[0] = '\0'; + if (tree) { + ti = proto_tree_add_text(tree, + tvb, + offset, + -1, + "%s:", label); + rtps_parameter_sequence_tree = proto_item_add_subtree(ti, + ett_rtps_parameter_sequence); + } + + /* Loop through all the parameters defined until PID_SENTINEL is found */ + for (;;) { + size -= offset - original_offset; + if (size < 4) { + proto_tree_add_text(tree, + tvb, + offset, + 1, + "RTPS PROTOCOL ERROR: not enough bytes to read " + " the next parameter"); + return 0; + } + original_offset = offset; + + /* Reads parameter and create the sub tree. At this point we don't know + * the final string that will identify the node or its length. It will + * be set later... + */ + parameter = NEXT_guint16(tvb, offset, little_endian); + if (tree) { + ti = proto_tree_add_text(rtps_parameter_sequence_tree, + tvb, + offset, + -1, + "%s", + val_to_str(parameter, parameter_id_vals, + "Unknown (0x%04x)")); + rtps_parameter_tree = proto_item_add_subtree(ti, ett_rtps_parameter); + proto_tree_add_uint_format(rtps_parameter_tree, + hf_rtps_parameter_id, + tvb, + offset, + 2, + parameter, + "parameterId: 0x%04x (%s)", + parameter, + val_to_str(parameter, parameter_id_vals, + "unknown %04x")); + } + offset += 2; + + if (parameter == PID_SENTINEL) { + /* PID_SENTINEL closes the parameter list, (length is ignored) */ + return offset +2; + } + + /* parameter length */ + param_length = NEXT_guint16(tvb, offset, little_endian); + if (tree) { + proto_tree_add_item(rtps_parameter_tree, + hf_rtps_parameter_length, + tvb, + offset, + 2, + little_endian); + } + offset += 2; + /* Make sure we have enough bytes for the param value */ + if (size-4 < param_length) { + if (tree) { + proto_tree_add_text(tree, + tvb, + offset, + 1, + "RTPS PROTOCOL ERROR: not enough bytes to read " + " the parameter value"); + } + return 0; + } + + /* Sets the end of this item (now we know it!) */ + if (tree) { + proto_item_set_len(ti, param_length+4); + } + + /* Do a shortcut when tree == NULL. In this case we only care of + * PID_STATUS_INFO. + */ + if (tree == NULL) { + if (parameter == PID_STATUS_INFO) { + if (pStatusInfo != NULL) { + *pStatusInfo = NEXT_guint32(tvb, offset, little_endian); + } + } + offset += param_length; + continue; + } + + switch(parameter) { + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_STATUS_INFO | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long statusInfo | + * +---------------+---------------+---------------+---------------+ + */ + case PID_STATUS_INFO: { + guint32 si = 0xffffffff; + ENSURE_LENGTH(4); + si = rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + hf_rtps_param_status_info, + FALSE, /* ALWAYS in network byte order (big endian) */ + TRUE, /* Is Hex ? */ + FALSE, /* Is Signed ? */ + NULL, /* No Label, use the protocol item ID */ + buffer, + MAX_PARAM_SIZE); + if (pStatusInfo != NULL) { + *pStatusInfo = si; + } + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DIRECTED_WRITE | 0x0010 | + * +---------------+---------------+---------------+---------------+ + * | | + * +- -+ + * | octet[12] guidPrefix | + * +- -+ + * | | + * +---------------+---------------+---------------+---------------+ + * | octet[4] entityId | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DIRECTED_WRITE: { + guint8 guidPart; + int i; + ENSURE_LENGTH(16); + rtps_util_add_guid_prefix(rtps_parameter_tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + "guidPrefix", + NULL, + 0); + rtps_util_add_entity_id(rtps_parameter_tree, + tvb, + offset+12, + hf_rtps_sm_entity_id, + hf_rtps_sm_entity_id_key, + hf_rtps_sm_entity_id_kind, + ett_rtps_entity, + "guidSuffix", + NULL); + memset(buffer, 0, MAX_PARAM_SIZE); + for (i = 0; i < 16; ++i) { + guidPart = tvb_get_guint8(tvb, offset+i); + g_snprintf(buffer+strlen(buffer), MAX_PARAM_SIZE-strlen(buffer), + "%02x", guidPart); + if (i == 3 || i == 7 || i == 11) g_strlcat(buffer, ":", MAX_PARAM_SIZE); + } + break; + } + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_KEY_HASH | xxxx | + * +---------------+---------------+---------------+---------------+ + * | | + * +- -+ + * | octet[xxxx] guid | + * +- -+ + * | | + * +---------------+---------------+---------------+---------------+ + * Differently from the other GUID, the KEY_HASH parameter may have + * variable length in the future. + * As consequence, no interpretation is performed here (and no check + * for size). + */ + case PID_KEY_HASH: { + guint8 guidPart; + int i; + g_strlcat(buffer, "guid: ", MAX_PARAM_SIZE); + for (i = 0; i < param_length; ++i) { + guidPart = tvb_get_guint8(tvb, offset+i); + g_snprintf(buffer+strlen(buffer), MAX_PARAM_SIZE-strlen(buffer), + "%02x", guidPart); + if (( ((i+1) % 4) == 0 ) && (i != param_length-1) ) + g_strlcat(buffer, ":", MAX_PARAM_SIZE); + } + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + buffer); + break; + } + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PARTICIPANT_LEASE_DURATION| 0x0008 | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PARTICIPANT_LEASE_DURATION: + ENSURE_LENGTH(8); + rtps_util_add_ntp_time(rtps_parameter_tree, + tvb, + offset, + little_endian, + "duration", + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TIME_BASED_FILTER | 0x0008 | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TIME_BASED_FILTER: + ENSURE_LENGTH(8); + rtps_util_add_ntp_time(rtps_parameter_tree, + tvb, + offset, + little_endian, + "minimum_separation", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TOPIC_NAME | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String.length | + * +---------------+---------------+---------------+---------------+ + * | str[0] | str[1] | str[2] | str[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TOPIC_NAME: + rtps_util_add_string(rtps_parameter_tree, + tvb, + offset, + hf_rtps_param_topic_name, + little_endian, + NULL, /* No label, use hf param */ + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_OWNERSHIP_STRENGTH | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long strength | + * +---------------+---------------+---------------+---------------+ + */ + case PID_OWNERSHIP_STRENGTH: + ENSURE_LENGTH(4); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + hf_rtps_param_strength, + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + NULL, /* No Label, use the protocol item ID */ + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TYPE_NAME | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String.length | + * +---------------+---------------+---------------+---------------+ + * | str[0] | str[1] | str[2] | str[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TYPE_NAME: + rtps_util_add_string(rtps_parameter_tree, + tvb, + offset, + hf_rtps_param_type_name, + little_endian, + NULL, /* No label, use hf param */ + buffer, + MAX_PARAM_SIZE); + break; + + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_XXXXXXXXXXX | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + */ + case PID_METATRAFFIC_MULTICAST_PORT: + case PID_METATRAFFIC_UNICAST_PORT: + case PID_DEFAULT_UNICAST_PORT: + ENSURE_LENGTH(4); + rtps_util_add_port(rtps_parameter_tree, + tvb, + offset, + little_endian, + "port", + buffer, + MAX_PARAM_SIZE); + break; + + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_EXPECTS_INLINE_QOS | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | boolean | N O T U S E D | + * +---------------+---------------+---------------+---------------+ + */ + case PID_EXPECTS_INLINE_QOS: + ENSURE_LENGTH(1); + rtps_util_add_boolean(rtps_parameter_tree, + tvb, + offset, + "inline_qos", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_XXXXXXXXXXX | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long ip_address | + * +---------------+---------------+---------------+---------------+ + */ + case PID_METATRAFFIC_MULTICAST_IPADDRESS: + case PID_DEFAULT_UNICAST_IPADDRESS: + case PID_MULTICAST_IPADDRESS: + case PID_METATRAFFIC_UNICAST_IPADDRESS: + rtps_util_add_ipv4_address_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "address", + buffer, + MAX_PARAM_SIZE); + break; + + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PROTOCOL_VERSION | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | uint8 major | uint8 minor | N O T U S E D | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PROTOCOL_VERSION: { + guint8 major = 0; + guint8 minor = 0; + + ENSURE_LENGTH(2); + major = tvb_get_guint8(tvb, offset); + minor = tvb_get_guint8(tvb, offset+1); + g_snprintf(buffer, MAX_PARAM_SIZE, "%d.%d", major, minor); + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + "protocolVersion: %s", + buffer); + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_VENDOR_ID | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | uint8 major | uint8 minor | N O T U S E D | + * +---------------+---------------+---------------+---------------+ + */ + case PID_VENDOR_ID: + ENSURE_LENGTH(2); + rtps_util_add_vendor_id(NULL, + tvb, + offset, + buffer, + MAX_PARAM_SIZE); + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + 2, + "vendorId: %s", + buffer); + + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_RELIABILITY | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + */ + case PID_RELIABILITY_OFFERED: /* Deprecated */ + case PID_RELIABILITY: + ENSURE_LENGTH(4); + rtps_util_add_kind_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + "kind", + reliability_qos_vals, + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_LIVELINESS | 0x000c | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + * NDDS 3.1 sends only 'kind' on the wire. + * + */ + case PID_LIVELINESS_OFFERED: /* Deprecated */ + case PID_LIVELINESS: + ENSURE_LENGTH(12); + rtps_util_add_liveliness_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DURABILITY | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DURABILITY: + ENSURE_LENGTH(4); + rtps_util_add_kind_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + "durability", + durability_qos_vals, + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DURABILITY_SERVICE | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + * | long history_depth | + * +---------------+---------------+---------------+---------------+ + * | long max_samples | + * +---------------+---------------+---------------+---------------+ + * | long max_instances | + * +---------------+---------------+---------------+---------------+ + * | long max_samples_per_instance | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DURABILITY_SERVICE: + ENSURE_LENGTH(28); + rtps_util_add_durability_service_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_OWNERSHIP | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + */ + case PID_OWNERSHIP_OFFERED: /* Deprecated */ + case PID_OWNERSHIP: + ENSURE_LENGTH(4); + rtps_util_add_kind_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + "kind", + ownership_qos_vals, + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TRANSPORT_PRIORITY | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | unsigned long value | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TRANSPORT_PRIORITY: + ENSURE_LENGTH(4); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + -1, /* No protocol ID, use label below */ + little_endian, + FALSE, /* Is Hex ? */ + FALSE, /* Is Signed ? */ + "value", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PRESENTATION | 0x0008 | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + * | boolean | boolean | N O T U S E D | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PRESENTATION_OFFERED: /* Deprecated */ + case PID_PRESENTATION: + ENSURE_LENGTH(6); + g_strlcpy(buffer, "{ ", MAX_PARAM_SIZE); + rtps_util_add_kind_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + "access_scope", + presentation_qos_vals, + buffer+strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, ", ", MAX_PARAM_SIZE); + rtps_util_add_boolean(rtps_parameter_tree, + tvb, + offset+4, + "coherent_access", + buffer+strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, ", ", MAX_PARAM_SIZE); + rtps_util_add_boolean(rtps_parameter_tree, + tvb, + offset+4, + "ordered_access", + buffer+strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, " }", MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DEADLINE | 0x0008 | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DEADLINE_OFFERED: /* Deprecated */ + case PID_DEADLINE: + ENSURE_LENGTH(8); + rtps_util_add_ntp_time(rtps_parameter_tree, + tvb, + offset, + little_endian, + "period", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DESTINATION_ORDER | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | unsigned long kind | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DESTINATION_ORDER_OFFERED: /* Deprecated */ + case PID_DESTINATION_ORDER: + ENSURE_LENGTH(4); + rtps_util_add_kind_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + "kind", + destination_order_qos_vals, + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_LATENCY_BUDGET | 0x0008 | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + */ + case PID_LATENCY_BUDGET_OFFERED: + case PID_LATENCY_BUDGET: + ENSURE_LENGTH(8); + rtps_util_add_ntp_time(rtps_parameter_tree, + tvb, + offset, + little_endian, + "duration", + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PARTITION | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sequence_size | + * +---------------+---------------+---------------+---------------+ + * | unsigned long string[0].size | + * +---------------+---------------+---------------+---------------+ + * | string[0][0] | string[0][1] | string[0][2] | string[0][3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + * The value is a sequence of strings. + */ + case PID_PARTITION_OFFERED: /* Deprecated */ + case PID_PARTITION: + ENSURE_LENGTH(4); + rtps_util_add_seq_string(rtps_parameter_tree, + tvb, + offset, + little_endian, + param_length, + "name", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_LIFESPAN | 0x0008 | + * +---------------+---------------+---------------+---------------+ + * | long NtpTime.seconds | + * +---------------+---------------+---------------+---------------+ + * | unsigned long NtpTime.fraction | + * +---------------+---------------+---------------+---------------+ + */ + case PID_LIFESPAN: + ENSURE_LENGTH(8); + rtps_util_add_ntp_time(rtps_parameter_tree, + tvb, + offset, + little_endian, + "duration", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_USER_DATA | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sequence_size | + * +---------------+---------------+---------------+---------------+ + * | octet[0] | octet[1] | octet[2] | octet[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + */ + case PID_USER_DATA: + ENSURE_LENGTH(4); + rtps_util_add_seq_octets(rtps_parameter_tree, + tvb, + offset, + little_endian, + param_length, + hf_rtps_param_user_data, + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_GROUP_DATA | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sequence_size | + * +---------------+---------------+---------------+---------------+ + * | octet[0] | octet[1] | octet[2] | octet[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + */ + case PID_GROUP_DATA: + ENSURE_LENGTH(4); + rtps_util_add_seq_octets(rtps_parameter_tree, + tvb, + offset, + little_endian, + param_length, + hf_rtps_param_group_data, + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TOPIC_DATA | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sequence_size | + * +---------------+---------------+---------------+---------------+ + * | octet[0] | octet[1] | octet[2] | octet[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TOPIC_DATA: + ENSURE_LENGTH(4); + rtps_util_add_seq_octets(rtps_parameter_tree, + tvb, + offset, + little_endian, + param_length, + hf_rtps_param_topic_data, + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_UNICAST_LOCATOR | 0x0018 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[0] | ipv6addr[1] | ipv6addr[2] | ipv6addr[3] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[4] | ipv6addr[5] | ipv6addr[6] | ipv6addr[7] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[8] | ipv6addr[9] | ipv6addr[10] | ipv6addr[11] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[12] | ipv6addr[13] | ipv6addr[14] | ipv6addr[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_UNICAST_LOCATOR: + ENSURE_LENGTH(24); + rtps_util_add_locator_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "locator", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DEFAULT_MULTICAST_LOCATOR | 0x0018 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[0] | ipv6addr[1] | ipv6addr[2] | ipv6addr[3] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[4] | ipv6addr[5] | ipv6addr[6] | ipv6addr[7] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[8] | ipv6addr[9] | ipv6addr[10] | ipv6addr[11] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[12] | ipv6addr[13] | ipv6addr[14] | ipv6addr[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DEFAULT_MULTICAST_LOCATOR: + ENSURE_LENGTH(24); + rtps_util_add_locator_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "locator", + buffer, + MAX_PARAM_SIZE); + + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_MULTICAST_LOCATOR | 0x0018 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[0] | ipv6addr[1] | ipv6addr[2] | ipv6addr[3] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[4] | ipv6addr[5] | ipv6addr[6] | ipv6addr[7] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[8] | ipv6addr[9] | ipv6addr[10] | ipv6addr[11] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[12] | ipv6addr[13] | ipv6addr[14] | ipv6addr[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_MULTICAST_LOCATOR: + ENSURE_LENGTH(24); + rtps_util_add_locator_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "locator", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_DEFAULT_UNICAST_LOCATOR | 0x0018 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[0] | ipv6addr[1] | ipv6addr[2] | ipv6addr[3] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[4] | ipv6addr[5] | ipv6addr[6] | ipv6addr[7] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[8] | ipv6addr[9] | ipv6addr[10] | ipv6addr[11] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[12] | ipv6addr[13] | ipv6addr[14] | ipv6addr[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_DEFAULT_UNICAST_LOCATOR: + ENSURE_LENGTH(24); + rtps_util_add_locator_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "locator", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_METATRAFFIC_UNICAST_LOC...| 0x0018 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[0] | ipv6addr[1] | ipv6addr[2] | ipv6addr[3] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[4] | ipv6addr[5] | ipv6addr[6] | ipv6addr[7] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[8] | ipv6addr[9] | ipv6addr[10] | ipv6addr[11] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[12] | ipv6addr[13] | ipv6addr[14] | ipv6addr[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_METATRAFFIC_UNICAST_LOCATOR: + ENSURE_LENGTH(24); + rtps_util_add_locator_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "locator", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_METATRAFFIC_MULTICAST_L...| 0x0018 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long port | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[0] | ipv6addr[1] | ipv6addr[2] | ipv6addr[3] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[4] | ipv6addr[5] | ipv6addr[6] | ipv6addr[7] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[8] | ipv6addr[9] | ipv6addr[10] | ipv6addr[11] | + * +---------------+---------------+---------------+---------------+ + * | ipv6addr[12] | ipv6addr[13] | ipv6addr[14] | ipv6addr[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_METATRAFFIC_MULTICAST_LOCATOR: + ENSURE_LENGTH(24); + rtps_util_add_locator_t(rtps_parameter_tree, + tvb, + offset, + little_endian, + "locator", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PARTICIPANT_MANUAL_LIVE...| 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long livelinessEpoch | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PARTICIPANT_BUILTIN_ENDPOINTS: + case PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT: + ENSURE_LENGTH(4); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + -1, /* No protocol ID, use label below */ + little_endian, + TRUE, /* Is Hex ? */ + FALSE, /* Is Signed ? */ + "value", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_HISTORY | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long kind | + * +---------------+---------------+---------------+---------------+ + * | long depth | + * +---------------+---------------+---------------+---------------+ + */ + case PID_HISTORY: + ENSURE_LENGTH(8); + g_strlcpy(buffer, "{ ", MAX_PARAM_SIZE); + rtps_util_add_kind_qos(rtps_parameter_tree, + tvb, + offset, + little_endian, + "kind", + history_qos_vals, + buffer+strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, ", ", MAX_PARAM_SIZE); + + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset+4, + -1, /* No protocol ID, use label below */ + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + "depth", + buffer + strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, " }", MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_RESOURCE_LIMIT | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | long max_samples | + * +---------------+---------------+---------------+---------------+ + * | long max_instances | + * +---------------+---------------+---------------+---------------+ + * | long max_samples_per_instances | + * +---------------+---------------+---------------+---------------+ + */ + case PID_RESOURCE_LIMIT: + ENSURE_LENGTH(12); + g_strlcpy(buffer, "{ ", MAX_PARAM_SIZE); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + -1, /* No protocol ID, use label below */ + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + "max_samples", + buffer + strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, ", ", MAX_PARAM_SIZE); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset+4, + -1, /* No protocol ID, use label below */ + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + "max_instances", + buffer + strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, ", ", MAX_PARAM_SIZE); + + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset+8, + -1, /* No protocol ID, use label below */ + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + "max_samples_per_instances", + buffer + strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer)); + g_strlcat(buffer, " }", MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_CONTENT_FILTER_PROPERTY | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String1.length | + * +---------------+---------------+---------------+---------------+ + * | str1[0] | str1[1] | str1[2] | str1[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String2.length | + * +---------------+---------------+---------------+---------------+ + * | str2[0] | str2[1] | str2[2] | str2[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String3.length | + * +---------------+---------------+---------------+---------------+ + * | str3[0] | str3[1] | str3[2] | str3[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String4.length | + * +---------------+---------------+---------------+---------------+ + * | str4[0] | str4[1] | str4[2] | str4[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + * | ... | + * | Filter Parameters | + * | ... | + * +---------------+---------------+---------------+---------------+ + * + * String1: ContentFilterName + * String2: RelatedTopicName + * String3: FilterName + * String4: FilterExpression + * FilterParameters: sequence of Strings + * + * Note: those strings starts all to a word-aligned (4 bytes) offset + */ + case PID_CONTENT_FILTER_PROPERTY: { + guint32 temp_offset = offset; + ENSURE_LENGTH(20); + temp_offset = rtps_util_add_string(rtps_parameter_tree, + tvb, + temp_offset, + hf_rtps_param_content_filter_name, + little_endian, + NULL, /* No label, use hf param */ + buffer, + MAX_PARAM_SIZE); + temp_offset = rtps_util_add_string(rtps_parameter_tree, + tvb, + temp_offset, + hf_rtps_param_related_topic_name, + little_endian, + NULL, + NULL, + 0); + temp_offset = rtps_util_add_string(rtps_parameter_tree, + tvb, + temp_offset, + hf_rtps_param_filter_name, + little_endian, + NULL, + NULL, + 0); + temp_offset = rtps_util_add_string(rtps_parameter_tree, + tvb, + temp_offset, + -1, + little_endian, + "filterExpression", + NULL, + 0); + temp_offset = rtps_util_add_seq_string(rtps_parameter_tree, + tvb, + temp_offset, + little_endian, + param_length, + "filterParameters", + NULL, + 0); + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PROPERTY_LIST | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long Seq.Length | + * +---------------+---------------+---------------+---------------+ + * | ... | + * | Property 1 | + * | ... | + * +---------------+---------------+---------------+---------------+ + * | ... | + * | Property 2 | + * | ... | + * +---------------+---------------+---------------+---------------+ + * | ... | + * | Property n | + * | ... | + * +---------------+---------------+---------------+---------------+ + * + * IDL: + * struct PROPERTY { + * String Name; + * String Value; + * }; + * + * struct PROPERTY_LIST { + * Sequence<PROPERTY> PropertyList; + * }; + * + */ + case PID_PROPERTY_LIST: + case PID_PROPERTY_LIST_OLD: + ENSURE_LENGTH(4); + { + guint32 prev_offset; + guint32 temp_offset; + guint8 tempName[MAX_PARAM_SIZE]; + guint8 tempValue[MAX_PARAM_SIZE]; + guint32 seq_size = NEXT_guint32(tvb, offset, little_endian); + g_snprintf(buffer, MAX_PARAM_SIZE, "%d properties", seq_size); + if (seq_size > 0) { + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + 0, + /* 123456789012345678901234567890|123456789012345678901234567890 */ + " Property Name | Property Value"); + + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + 0, + /* 123456789012345678901234567890|123456789012345678901234567890 */ + "------------------------------|------------------------------"); + + temp_offset = offset+4; + while(seq_size-- > 0) { + prev_offset = temp_offset; + temp_offset = rtps_util_add_string(NULL, + tvb, + temp_offset, + -1, + little_endian, + NULL, + tempName, + MAX_PARAM_SIZE); + temp_offset = rtps_util_add_string(NULL, + tvb, + temp_offset, + -1, + little_endian, + NULL, + tempValue, + MAX_PARAM_SIZE); + proto_tree_add_text(rtps_parameter_tree, + tvb, + prev_offset, + temp_offset - prev_offset, + "%-29s | %-29s", + tempName, + tempValue); + } + } + } + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_CONTENT_FILTER_INFO | length | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + * + * IDL: + * struct CONTENT_FILTER_SIGNATURE { + * sequence<long> filterBitmap; + * sequence<FILTER_SIGNATURE, 4> filterSignature; + * } + * + * where: + * struct FILTER_SIGNATURE { + * long filterSignature[4]; + * } + */ + case PID_CONTENT_FILTER_INFO: { + guint32 temp_offset = offset; + guint32 prev_offset; + guint32 fs_elem; + guint32 fs[4]; + ENSURE_LENGTH(8); + + /* Dissect filter bitmap */ + temp_offset = rtps_util_add_seq_ulong(rtps_parameter_tree, + tvb, + offset, + little_endian, + param_length, + TRUE, /* is_hex */ + FALSE, /* filterSignature: is_signed */ + "filterBitmap"); + + /* Dissect sequence of FILTER_SIGNATURE */ + fs_elem = NEXT_guint32(tvb, temp_offset, little_endian); + temp_offset += 4; + while (fs_elem-- > 0) { + prev_offset = temp_offset; + /* Dissect the next FILTER_SIGNATURE object */ + fs[0] = NEXT_guint32(tvb, temp_offset, little_endian); + temp_offset += 4; + fs[1] = NEXT_guint32(tvb, temp_offset, little_endian); + temp_offset += 4; + fs[2] = NEXT_guint32(tvb, temp_offset, little_endian); + temp_offset += 4; + fs[3] = NEXT_guint32(tvb, temp_offset, little_endian); + temp_offset += 4; + proto_tree_add_text(rtps_parameter_tree, + tvb, + prev_offset, + temp_offset - prev_offset, + "filterSignature: %08x %08x %08x %08x", + fs[0], fs[1], fs[2], fs[3]); + } + + break; + } + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_COHERENT_SET | length | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber seqNumber + + * | | + * +---------------+---------------+---------------+---------------+ + */ + case PID_COHERENT_SET: + ENSURE_LENGTH(8); + rtps_util_add_seq_number(rtps_parameter_tree, + tvb, + offset, + little_endian, + "sequenceNumber"); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_BUILTIN_ENDPOINT_SET | length | + * +---------------+---------------+---------------+---------------+ + * | long value | + * +---------------+---------------+---------------+---------------+ + */ + case PID_BUILTIN_ENDPOINT_SET: { + guint32 data; + guint32 datamask; + char bitbuf[33]; + int i; + ENSURE_LENGTH(4); + data = NEXT_guint32(tvb, offset, little_endian); + for (i = 0; i < 32; ++i) { + datamask = (1 << (31-i)); + bitbuf[i] = ((data & datamask) == datamask) ? '1':'0'; + } + bitbuf[i] = '\0'; + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + 4, + "value: %08x (%s)", + data, bitbuf); + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TYPE_MAX_SIZE_SERIALIZED | length | + * +---------------+---------------+---------------+---------------+ + * | long value | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TYPE_MAX_SIZE_SERIALIZED: + ENSURE_LENGTH(4); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + -1, /* No protocol ID, use label below */ + little_endian, + FALSE, /* Is Hex ? */ + FALSE, /* Is Signed ? */ + "value", + buffer, + MAX_PARAM_SIZE); + break; + + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_ORIGINAL_WRITER_INFO | length | + * +---------------+---------------+---------------+---------------+ + * | | + * +- -+ + * | octet[12] guidPrefix | + * +- -+ + * | | + * +---------------+---------------+---------------+---------------+ + * | octet[4] entityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + */ + case PID_ORIGINAL_WRITER_INFO: + ENSURE_LENGTH(16); + rtps_util_add_guid_prefix(rtps_parameter_tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + "virtualGUIDPrefix", + NULL, + 0); + rtps_util_add_entity_id(rtps_parameter_tree, + tvb, + offset+12, + hf_rtps_sm_entity_id, + hf_rtps_sm_entity_id_key, + hf_rtps_sm_entity_id_kind, + ett_rtps_entity, + "virtualGUIDSuffix", + NULL); + + /* Sequence number */ + rtps_util_add_seq_number(rtps_parameter_tree, + tvb, + offset+16, + little_endian, + "virtualSeqNumber"); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_ENTITY_NAME | length | + * +---------------+---------------+---------------+---------------+ + * | unsigned long String.length | + * +---------------+---------------+---------------+---------------+ + * | str[0] | str[1] | str[2] | str[3] | + * +---------------+---------------+---------------+---------------+ + * | ... | + * +---------------+---------------+---------------+---------------+ + */ + case PID_ENTITY_NAME: + rtps_util_add_string(rtps_parameter_tree, + tvb, + offset, + hf_rtps_param_entity_name, + little_endian, + NULL, /* No label, use hf param */ + buffer, + MAX_PARAM_SIZE); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PARTICIPANT_GUID | 0x0010 | + * | PID_ENDPOINT_GUID | | + * +---------------+---------------+---------------+---------------+ + * | guid[0] | guid[1] | guid[2] | guid[3] | + * +---------------+---------------+---------------+---------------+ + * | guid[4] | guid[5] | guid[6] | guid[7] | + * +---------------+---------------+---------------+---------------+ + * | guid[8] | guid[9] | guid[10] | guid[11] | + * +---------------+---------------+---------------+---------------+ + * | guid[12] | guid[13] | guid[14] | guid[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PARTICIPANT_GUID: + case PID_ENDPOINT_GUID: + ENSURE_LENGTH(16); + rtps_util_add_generic_guid(rtps_parameter_tree, + tvb, + offset, + "GUID", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PARTICIPANT_ENTITY_ID | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | entity[0] | entity[1] | entity[2] | entity[3] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PARTICIPANT_ENTITY_ID: + ENSURE_LENGTH(4); + rtps_util_add_generic_entity_id(rtps_parameter_tree, + tvb, + offset, + "Participant entity ID", + buffer, + MAX_PARAM_SIZE); + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_GROUP_GUID | 0x0010 | + * +---------------+---------------+---------------+---------------+ + * | guid[0] | guid[1] | guid[2] | guid[3] | + * +---------------+---------------+---------------+---------------+ + * | guid[4] | guid[5] | guid[6] | guid[7] | + * +---------------+---------------+---------------+---------------+ + * | guid[8] | guid[9] | guid[10] | guid[11] | + * +---------------+---------------+---------------+---------------+ + * | guid[12] | guid[13] | guid[14] | guid[15] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_GROUP_GUID: + ENSURE_LENGTH(16); + rtps_util_add_generic_guid(rtps_parameter_tree, + tvb, + offset, + "Group GUID", + buffer, + MAX_PARAM_SIZE); + + break; + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_GROUP_ENTITY_ID | 0x0004 | + * +---------------+---------------+---------------+---------------+ + * | entity[0] | entity[1] | entity[2] | entity[3] | + * +---------------+---------------+---------------+---------------+ + */ + case PID_GROUP_ENTITY_ID: + ENSURE_LENGTH(4); + + rtps_util_add_generic_entity_id(rtps_parameter_tree, + tvb, + offset, + "Group entity ID", + buffer, + MAX_PARAM_SIZE); + + break; + + + + + + /* ================================================================== + * Here are all the deprecated items. + */ + + case PID_PERSISTENCE: + ENSURE_LENGTH(8); + rtps_util_add_ntp_time(rtps_parameter_tree, + tvb, + offset, + little_endian, + "persistence", + buffer, + MAX_PARAM_SIZE); + break; + + case PID_TYPE_CHECKSUM: + ENSURE_LENGTH(4); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + -1, + little_endian, + TRUE, /* Is Hex? */ + FALSE, /* Is signed ? */ + "checksum", + buffer, + MAX_PARAM_SIZE); + break; + + case PID_EXPECTS_ACK: + ENSURE_LENGTH(1); + rtps_util_add_boolean(rtps_parameter_tree, + tvb, + offset, + "expectsAck", + buffer, + MAX_PARAM_SIZE); + break; + + case PID_MANAGER_KEY: { + int i = 0; + char sep = ':'; + guint32 manager_key; + + buffer[0] = '\0'; + while (param_length >= 4) { + manager_key = NEXT_guint32(tvb, offset, little_endian); + g_snprintf(buffer+strlen(buffer), + MAX_PARAM_SIZE-strlen(buffer), + "%c 0x%08x", + sep, + manager_key); + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + "Key[%d]: 0x%X", i, manager_key); + ++i; + offset +=4; + sep = ','; + param_length -= 4; /* decrement count */ + } + offset += param_length; + break; + } + + + case PID_RECV_QUEUE_SIZE: + case PID_SEND_QUEUE_SIZE: + ENSURE_LENGTH(4); + rtps_util_add_long(rtps_parameter_tree, + tvb, + offset, + -1, + little_endian, + TRUE, /* Is Hex? */ + FALSE, /* Is signed ? */ + "queueSize", + buffer, + MAX_PARAM_SIZE); + break; + + + case PID_VARGAPPS_SEQUENCE_NUMBER_LAST: + ENSURE_LENGTH(4); + rtps_util_add_seq_number(rtps_parameter_tree, + tvb, + offset, + little_endian, + "sequenceNumberLast"); + break; + + /* This is the default branch when we don't have enough information + * on how to decode the parameter. It can be used also for known + * parameters. + */ + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | <pid_id> | 0x0000 | + * +---------------+---------------+---------------+---------------+ + */ + case PID_IS_RELIABLE: + case PID_TYPE2_NAME: + case PID_TYPE2_CHECKSUM: + case PID_RELIABILITY_ENABLED: + g_strlcpy(buffer, "[DEPRECATED] - Parameter not decoded", MAX_PARAM_SIZE); + + case PID_PAD: + break; + + default: + + /* The following PIDS are vendor-specific */ + if (vendor_id == RTPS_VENDOR_RTI) { + switch(parameter) { + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PRODUCT_VERSION | length | + * +---------------+---------------+---------------+---------------+ + * | uint8 major | uint8 minor | N O T U S E D | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PRODUCT_VERSION: { + guint8 major = 0; + guint8 minor = 0; + guint8 release; + guint8 revision; + + ENSURE_LENGTH(4); + major = tvb_get_guint8(tvb, offset); + minor = tvb_get_guint8(tvb, offset+1); + release = tvb_get_guint8(tvb, offset+2); + revision = tvb_get_guint8(tvb, offset+3); + g_snprintf(buffer, MAX_PARAM_SIZE, "%d.%d%c rev%d", + major, minor, release, revision); + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + "productVersion: %s", + buffer); + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_PLUGIN_PROMISCUITY_KIND | length | + * +---------------+---------------+---------------+---------------+ + * | short value | | + * +---------------+---------------+---------------+---------------+ + */ + case PID_PLUGIN_PROMISCUITY_KIND: { + guint32 val; + ENSURE_LENGTH(4); + val = NEXT_guint32(tvb, offset, little_endian); + g_snprintf(buffer, MAX_PARAM_SIZE, "%s", + val_to_str(val, plugin_promiscuity_kind_vals, + "unknown (%04x)")); + + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + "promiscuityKind: %s", + buffer); + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_ENTITY_VIRTUAL_GUID | length | + * +---------------+---------------+---------------+---------------+ + * | | + * +- -+ + * | octet[12] guidPrefix | + * +- -+ + * | | + * +---------------+---------------+---------------+---------------+ + * | octet[4] entityId | + * +---------------+---------------+---------------+---------------+ + */ + case PID_ENTITY_VIRTUAL_GUID: + ENSURE_LENGTH(16); + rtps_util_add_guid_prefix(rtps_parameter_tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + "virtualGUIDPrefix", + NULL, + 0); + rtps_util_add_entity_id(rtps_parameter_tree, + tvb, + offset+12, + hf_rtps_sm_entity_id, + hf_rtps_sm_entity_id_key, + hf_rtps_sm_entity_id_kind, + ett_rtps_entity, + "virtualGUIDSuffix", + NULL); + break; + + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_SERVICE_KIND | length | + * +---------------+---------------+---------------+---------------+ + * | long value | + * +---------------+---------------+---------------+---------------+ + */ + case PID_SERVICE_KIND: { + guint32 val; + ENSURE_LENGTH(4); + val = NEXT_guint32(tvb, offset, little_endian); + + g_snprintf(buffer, MAX_PARAM_SIZE, "%s", + val_to_str(val, service_kind_vals, "unknown (%04x)")); + + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + "serviceKind: %s", + buffer); + break; + } + + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PID_TYPECODE | length | + * +---------------+---------------+---------------+---------------+ + * | | + * + Type code description + + * | | + * +---------------+---------------+---------------+---------------+ + */ + case PID_TYPECODE: + rtps_util_add_typecode(rtps_parameter_tree, + tvb, + offset, + little_endian, + 0, /* indent level */ + 0, /* isPointer */ + -1, /* bitfield */ + 0, /* isKey */ + offset, + NULL, /* name */ + -1, /* not a seq field */ + NULL, /* not an array */ + 0); /* ndds 4.0 hack: init to false */ + break; + + } /* End of switch for parameters for vendor RTI */ + } /* End of branch vendor RTI */ + + /* Put here other branches if you are planning to dissect parameters + * ID from different vendors. + */ + + else { + if (param_length > 0) { + proto_tree_add_text(rtps_parameter_tree, + tvb, + offset, + param_length, + "parameterData"); + } + } + } /* End main parameter switch */ + + if (buffer[0]) { + proto_item_append_text(ti, ": %s", buffer); + buffer[0] = '\0'; + } + offset += param_length; + + } /* for all the parameters */ + return offset; +} +#undef ENSURE_LENGTH + + + + +/* *********************************************************************** */ +/* * P A D * */ +/* *********************************************************************** */ +static void dissect_PAD(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PAD |X|X|X|X|X|X|X|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + */ + if (tree) { + rtps_util_decode_flags(tree, tvb, offset + 1, flags, PAD_FLAGS); + + if (octets_to_next_header != 0) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be ZERO)", + octets_to_next_header); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + } + info_summary_append(info_summary_text, SUBMESSAGE_PAD, NULL); +} + + + + + +/* *********************************************************************** */ +/* * D A T A * */ +/* *********************************************************************** */ +static void dissect_DATA(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 vendor_id) { + /* + * + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | DATA |X|X|X|I|H|D|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + + + * | KeyHashPrefix keyHashPrefix [only if H==1] | + * + + + * | | + * +---------------+---------------+---------------+---------------+ + * | KeyHashSuffix keyHashSuffix | + * +---------------+---------------+---------------+---------------+ + * | StatusInfo statusInfo [only if I==1] | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList inlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData [only if D==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + int min_len; + gint old_offset = offset; + guint32 wid; /* Writer EntityID */ + guint32 status_info = 0xffffffff; + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, DATA_FLAGS); + + + /* Calculates the minimum length for this submessage */ + min_len = 20; + if ((flags & FLAG_DATA_Q) != 0) min_len += 4; + if ((flags & FLAG_DATA_D) != 0) min_len += 4; + if ((flags & FLAG_DATA_H) != 0) min_len += 12; + + if (octets_to_next_header < min_len) { + if (tree) proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + offset += 8; /* Skip to writer entity ID */ + wid = NEXT_guint32(tvb, offset, little_endian); + offset += 12; /* Skip to keyHashPrefix */ + if ((flags & FLAG_DATA_H) != 0) { + offset += 12; + } + offset += 4; /* GUID Entity ID */ + if ((flags & FLAG_DATA_I) != 0) { + status_info = NEXT_guint32(tvb, offset, little_endian); + } + info_summary_append_ex(info_summary_text, SUBMESSAGE_DATA, wid, status_info); + return; + } + + if (tree) proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + &wid); + offset += 4; + + + /* Sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* If flag H is defined, read the GUID Prefix */ + if ((flags & FLAG_DATA_H) != 0) { + rtps_util_add_guid_prefix(tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + "keyHashPrefix", + NULL, + 0); + + offset += 12; + } else { + /* Flag H not set, use hostId, appId from the packet header */ + } + + /* Complete the GUID by reading the Object ID */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_entity_id, + hf_rtps_sm_entity_id_key, + hf_rtps_sm_entity_id_kind, + ett_rtps_entity, + "keyHashSuffix", + NULL); + offset += 4; + + if ((flags & FLAG_DATA_I) != 0) { + status_info = rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 1, /* is_hex */ + 0, /* is_signed */ + "statusInfo", + NULL, + 0); + offset += 4; + } + + /* InlineQos */ + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + NULL, + vendor_id); + } + + /* SerializedData */ + if ((flags & FLAG_DATA_D) != 0) { + dissect_serialized_data(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData", + vendor_id); + } + info_summary_append_ex(info_summary_text, SUBMESSAGE_DATA, wid, status_info); +} + + +/* *********************************************************************** */ +/* * D A T A _ F R A G * */ +/* *********************************************************************** */ +static void dissect_DATA_FRAG(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char *info_summary_text, + guint16 vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | DATA_FRAG |X|X|X|X|X|H|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + + + * | KeyHashPrefix keyHashPrefix [only if H==1] | + * + + + * | | + * +---------------+---------------+---------------+---------------+ + * | KeyHashSuffix keyHashSuffix | + * +---------------+---------------+---------------+---------------+ + * | FragmentNumber fragmentStartingNum | + * +---------------+---------------+---------------+---------------+ + * | ushort fragmentsInSubmessage | ushort fragmentSize | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sampleSize | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList inlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + + int min_len; + gint old_offset = offset; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, NOKEY_DATA_FRAG_FLAGS); + + + /* Calculates the minimum length for this submessage */ + min_len = 32; + if ((flags & FLAG_DATA_FRAG_Q) != 0) min_len += 4; + if ((flags & FLAG_DATA_FRAG_H) != 0) min_len += 12; + + if (octets_to_next_header < min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_DATA_FRAG, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* Sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* If flag H is defined, read the GUID Prefix */ + if ((flags & FLAG_DATA_H) != 0) { + rtps_util_add_guid_prefix(tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + "keyHashPrefix", + NULL, + 0); + + offset += 12; + } else { + /* Flag H not set, use hostId, appId from the packet header */ + } + + /* Complete the GUID by reading the Object ID */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_entity_id, + hf_rtps_sm_entity_id_key, + hf_rtps_sm_entity_id_kind, + ett_rtps_entity, + "keyHashSuffix", + NULL); + offset += 4; + + + /* Fragment number */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentStartingNum", + NULL, + 0); + offset += 4; + + /* Fragments in submessage */ + rtps_util_add_short(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentsInSubmessage", + NULL, + 0); + offset += 2; + + /* Fragment size */ + rtps_util_add_short(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentSize", + NULL, + 0); + offset += 2; + + /* sampleSize */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "sampleSize", + NULL, + 0); + offset += 4; + + /* InlineQos */ + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + NULL, + vendor_id); + } + + /* SerializedData */ + if ((flags & FLAG_DATA_D) != 0) { + dissect_serialized_data(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData", + vendor_id); + } + info_summary_append(info_summary_text, SUBMESSAGE_DATA_FRAG, NULL); +} + + + +/* *********************************************************************** */ +/* * N O K E Y _ D A T A * */ +/* *********************************************************************** */ +static void dissect_NOKEY_DATA(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 vendor_id) { + /* + * RTPS 2.0: + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NOKEY_DATA |X|X|X|X|X|D|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList inlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData [only if D==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + + int min_len; + gint old_offset = offset; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, NOKEY_DATA_FLAGS); + + + /* Calculates the minimum length for this submessage */ + min_len = 16; + if ((flags & FLAG_NOKEY_DATA_Q) != 0) min_len += 4; + + if (octets_to_next_header < min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_NOKEY_DATA, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* Sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* InlineQos */ + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + NULL, + vendor_id); + } + + /* SerializedData */ + if ((flags & FLAG_DATA_D) != 0) { + dissect_serialized_data(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData", + vendor_id); + } + info_summary_append(info_summary_text, SUBMESSAGE_NOKEY_DATA, NULL); +} + + +/* *********************************************************************** */ +/* * N O K E Y _ D A T A _ F R A G * */ +/* *********************************************************************** */ +static void dissect_NOKEY_DATA_FRAG(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |NOKEY_DATA_FRAG|X|X|X|X|X|X|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + * | FragmentNumber fragmentStartingNum | + * +---------------+---------------+---------------+---------------+ + * | ushort fragmentsInSubmessage | ushort fragmentSize | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sampleSize | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList inlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + + int min_len; + gint old_offset = offset; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, NOKEY_DATA_FRAG_FLAGS); + + + /* Calculates the minimum length for this submessage */ + min_len = 28; + if ((flags & FLAG_NOKEY_DATA_Q) != 0) min_len += 4; + + if (octets_to_next_header < min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_NOKEY_DATA_FRAG, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* Sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* Fragment number */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentStartingNum", + NULL, + 0); + offset += 4; + + /* Fragments in submessage */ + rtps_util_add_short(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentsInSubmessage", + NULL, + 0); + offset += 2; + + /* Fragment size */ + rtps_util_add_short(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentSize", + NULL, + 0); + offset += 2; + + /* InlineQos */ + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + NULL, + vendor_id); + } + + /* SerializedData */ + if ((flags & FLAG_DATA_D) != 0) { + dissect_serialized_data(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData", + vendor_id); + } + info_summary_append(info_summary_text, SUBMESSAGE_NOKEY_DATA_FRAG, NULL); +} + + + +/* *********************************************************************** */ +/* * A C K N A C K * */ +/* *********************************************************************** */ +static void dissect_ACKNACK(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id ) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ACKNACK |X|X|X|X|X|X|F|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumberSet readerSNState + + * | | + * +---------------+---------------+---------------+---------------+ + * | Counter count | + * +---------------+---------------+---------------+---------------+ + */ + gint original_offset; /* Offset to the readerEntityId */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, ACKNACK_FLAGS); + + if (octets_to_next_header < 20) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= 20)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_ACKNACK, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + original_offset = offset; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* Bitmap */ + offset = rtps_util_add_bitmap(tree, + tvb, + offset, + little_endian, + "readerSNState"); + + + /* RTPS 1.0 didn't have count: make sure we don't decode it wrong + * in this case + */ + if (offset + 4 == original_offset + octets_to_next_header) { + /* Count is present */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + "counter", /* No Label, use the protocol item ID */ + NULL, + 0); + } else if (offset < original_offset + octets_to_next_header) { + /* In this case there must be something wrong in the bitmap: there + * are some extra bytes that we don't know how to decode + */ + proto_tree_add_text(tree, + tvb, + offset, + octets_to_next_header - offset, + "Packet malformed: don't know how to decode those " + "extra bytes: %d", + octets_to_next_header - offset); + } else if (offset > original_offset + octets_to_next_header) { + /* Decoding the bitmap went over the end of this submessage. + * Enter an item in the protocol tree that spans over the entire + * submessage. + */ + proto_tree_add_text(tree, + tvb, + original_offset, + octets_to_next_header + original_offset, + "Packet malformed: not enough bytes to decode"); + } + info_summary_append(info_summary_text, SUBMESSAGE_ACKNACK, NULL); +} + + +/* *********************************************************************** */ +/* * N A C K _ F R A G * */ +/* *********************************************************************** */ +static void dissect_NACK_FRAG(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id ) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NACK_FRAG |X|X|X|X|X|X|X|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumberSet writerSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ FragmentNumberSet fragmentNumberState + + * | | + * +---------------+---------------+---------------+---------------+ + * | Counter count | + * +---------------+---------------+---------------+---------------+ + */ + rtps_util_decode_flags(tree, tvb, offset + 1, flags, NACK_FRAG_FLAGS); + + if (octets_to_next_header < 24) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= 24)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_NACK_FRAG, NULL); + return; + } + + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* Writer sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSN"); + offset += 8; + + /* FragmentNumberSet */ + offset = rtps_util_add_fragment_number_set(tree, + tvb, + offset, + little_endian, + "fragmentNumberState", + octets_to_next_header - 20); + info_summary_append(info_summary_text, SUBMESSAGE_NACK_FRAG, NULL); + + if (offset == -1) { + return; + } + /* Count */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + FALSE, /* Is Hex ? */ + TRUE, /* Is Signed ? */ + "count", /* No Label, use the protocol item ID */ + NULL, + 0); +} + + + +/* *********************************************************************** */ +/* * H E A R T B E A T * */ +/* *********************************************************************** */ +static void dissect_HEARTBEAT(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | HEARTBEAT |X|X|X|X|X|L|F|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber firstSeqNumber + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber lastSeqNumber + + * | | + * +---------------+---------------+---------------+---------------+ + * | Counter count | + * +---------------+---------------+---------------+---------------+ + */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, HEARTBEAT_FLAGS); + + + if (octets_to_next_header < 28) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= 28)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_HEARTBEAT, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* First available Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "firstSeqNumber"); + offset += 8; + + /* Last Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "lastSeqNumber"); + offset += 8; + + /* Counter */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "count", + NULL, + 0); + info_summary_append(info_summary_text, SUBMESSAGE_HEARTBEAT, NULL); +} + + +/* *********************************************************************** */ +/* * H E A R T B E A T _ B A T C H * */ +/* *********************************************************************** */ +static void dissect_HEARTBEAT_BATCH(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + + + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |HEARTBEAT_BATCH|X|X|X|X|X|L|F|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber firstBatchSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber lastBatchSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber firstSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber lastSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | Count count | + * +---------------+---------------+---------------+---------------+ + */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, HEARTBEAT_BATCH_FLAGS); + + + if (octets_to_next_header < 36) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= 36)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_HEARTBEAT, NULL); + return; + } + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* First available Batch Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "firstBatchSN"); + offset += 8; + + /* Last Batch Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "lastBatchSN"); + offset += 8; + + /* First available Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "firstSeqNumber"); + offset += 8; + + /* Last Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "lastSeqNumber"); + offset += 8; + + /* Counter */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "count", + NULL, + 0); + info_summary_append(info_summary_text, SUBMESSAGE_HEARTBEAT_BATCH, NULL); +} + + +/* *********************************************************************** */ +/* * H E A R T B E A T _ F R A G * */ +/* *********************************************************************** */ +static void dissect_HEARTBEAT_FRAG(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |HEARTBEAT_FRAG |X|X|X|X|X|X|X|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNumber + + * | | + * +---------------+---------------+---------------+---------------+ + * | FragmentNumber lastFragmentNum | + * +---------------+---------------+---------------+---------------+ + * | Counter count | + * +---------------+---------------+---------------+---------------+ + */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, HEARTBEAT_FRAG_FLAGS); + + if (octets_to_next_header < 24) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= 24)", + octets_to_next_header); + return; + } + + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_HEARTBEAT_FRAG, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + /* First available Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* Fragment number */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "lastFragmentNum", + NULL, + 0); + offset += 4; + + /* Counter */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "count", + NULL, + 0); + info_summary_append(info_summary_text, SUBMESSAGE_HEARTBEAT_FRAG, NULL); +} + + + +/* *********************************************************************** */ +/* * G A P * */ +/* *********************************************************************** */ +static void dissect_GAP(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | GAP |X|X|X|X|X|X|X|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber gapStart + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SequenceNumberSet gapList ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, GAP_FLAGS); + + if (octets_to_next_header < 24) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= 24)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_GAP, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + NULL); + offset += 4; + + + /* First Sequence Number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "gapStart"); + offset += 8; + + /* Bitmap */ + rtps_util_add_bitmap(tree, + tvb, + offset, + little_endian, + "gapList"); + info_summary_append(info_summary_text, SUBMESSAGE_GAP, NULL); +} + + +/* *********************************************************************** */ +/* * I N F O _ T S * */ +/* *********************************************************************** */ +static void dissect_INFO_TS(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | INFO_TS |X|X|X|X|X|X|I|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | | + * + Timestamp timestamp [only if I==1] + + * | | + * +---------------+---------------+---------------+---------------+ + */ + + int min_len; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, INFO_TS_FLAGS); + + min_len = 0; + if ((flags & FLAG_INFO_TS_T) == 0) min_len += 8; + + if (octets_to_next_header != min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be == %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_INFO_TS, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + if ((flags & FLAG_INFO_TS_T) == 0) { + rtps_util_add_ntp_time(tree, + tvb, + offset, + little_endian, + "timestamp", + NULL, + 0); + } + info_summary_append(info_summary_text, SUBMESSAGE_INFO_TS, NULL); +} + + +/* *********************************************************************** */ +/* * I N F O _ S R C * */ +/* *********************************************************************** */ +static void dissect_INFO_SRC(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | INFO_SRC |X|X|X|X|X|X|X|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | long unused | + * +---------------+---------------+---------------+---------------+ + * | ProtocolVersion version | VendorId vendor | + * +---------------+---------------+---------------+---------------+ + * | | + * + + + * | GuidPrefix guidPrefix | + * + + + * | | + * +---------------+---------------+---------------+---------------+ + */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, INFO_SRC_FLAGS); + + if (octets_to_next_header != 16) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be == 16)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_INFO_SRC, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + /* Ip Address */ + { + guint32 ip = NEXT_guint32(tvb, offset, little_endian); + proto_tree_add_text(tree, + tvb, + offset, + 4, + "unused: 0x%08x (appIpAddress: %d.%d.%d.%d)", + ip, + (ip >> 24) & 0xff, + (ip >> 16) & 0xff, + (ip >> 8) & 0xff, + ip & 0xff); + offset += 4; + } + + /* Version */ + { + guint8 major = 0; + guint8 minor = 0; + major = tvb_get_guint8(tvb, offset); + minor = tvb_get_guint8(tvb, offset+1); + + proto_tree_add_text(tree, + tvb, + offset, + 2, + "version: %d.%d", + major, + minor); + offset += 2; + } + + /* Vendor ID */ + { + guint8 vendor[MAX_VENDOR_ID_SIZE]; + rtps_util_add_vendor_id(NULL, + tvb, + offset, + vendor, + MAX_VENDOR_ID_SIZE); + proto_tree_add_text(tree, + tvb, + offset, + 2, + "vendor: %s", + vendor); + offset += 2; + } + + { + /* guint8 temp_buffer[MAX_GUID_PREFIX_SIZE]; */ + rtps_util_add_guid_prefix(tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + NULL, /* Use default 'guidPrefix' */ + NULL, + 0); + } + info_summary_append(info_summary_text, SUBMESSAGE_INFO_SRC, NULL); +} + + +/* *********************************************************************** */ +/* * I N F O _ R E P L Y _ I P 4 * */ +/* *********************************************************************** */ +static void dissect_INFO_REPLY_IP4(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |INFO_REPLY_IP4 |X|X|X|X|X|X|M|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | | + * + LocatorUDPv4 unicastReplyLocator + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + LocatorUDPv4 multicastReplyLocator [only if M==1] + + * | | + * +---------------+---------------+---------------+---------------+ + */ + + int min_len; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, INFO_REPLY_IP4_FLAGS); + + min_len = 8; + if ((flags & FLAG_INFO_REPLY_IP4_M) == 1) min_len += 8; + + + if (octets_to_next_header != min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be == %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_INFO_REPLY_IP4, NULL); + return; + } + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + + /* unicastReplyLocator */ + rtps_util_add_locator_udp_v4(tree, + tvb, + offset, + "unicastReplyLocator", + little_endian); + + offset += 8; + + /* multicastReplyLocator */ + if ((flags & FLAG_INFO_REPLY_IP4_M) == 1) { + rtps_util_add_locator_udp_v4(tree, + tvb, + offset, + "multicastReplyLocator", + little_endian); + offset += 8; + } + info_summary_append(info_summary_text, SUBMESSAGE_INFO_REPLY_IP4, NULL); +} + +/* *********************************************************************** */ +/* * I N F O _ D S T * */ +/* *********************************************************************** */ +static void dissect_INFO_DST(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | INFO_DST |X|X|X|X|X|X|X|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | | + * + + + * | GuidPrefix guidPrefix | + * + + + * | | + * +---------------+---------------+---------------+---------------+ + */ + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, INFO_DST_FLAGS); + + if (octets_to_next_header != 12) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be == 12)", + octets_to_next_header); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_INFO_DST, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + rtps_util_add_guid_prefix(tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + NULL, + NULL, + 0); + info_summary_append(info_summary_text, SUBMESSAGE_INFO_DST, NULL); +} + + + +/* *********************************************************************** */ +/* * I N F O _ R E P L Y * */ +/* *********************************************************************** */ +static void dissect_INFO_REPLY(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 G_GNUC_UNUSED vendor_id) { + /* + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | INFO_REPLY |X|X|X|X|X|X|M|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ LocatorList unicastReplyLocatorList ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ LocatorList multicastReplyLocatorList [only if M==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + + int min_len; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, INFO_REPLY_FLAGS); + + min_len = 8; + if ((flags & FLAG_INFO_REPLY_M) == 1) min_len += 8; + + + if (octets_to_next_header != min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be == %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + info_summary_append(info_summary_text, SUBMESSAGE_INFO_REPLY, NULL); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + + /* unicastReplyLocatorList */ + offset = rtps_util_add_locator_list(tree, + tvb, + offset, + "unicastReplyLocatorList", + little_endian); + + + /* multicastReplyLocatorList */ + if ((flags & FLAG_INFO_REPLY_M) == 1) { + offset = rtps_util_add_locator_list(tree, + tvb, + offset, + "multicastReplyLocatorList", + little_endian); + } + info_summary_append(info_summary_text, SUBMESSAGE_INFO_REPLY, NULL); +} + +/* *********************************************************************** */ +/* * R T P S _ D A T A * */ +/* *********************************************************************** */ +static void dissect_RTPS_DATA(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 vendor_id) { + /* + * + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RTPS_DATA |X|X|X|X|X|D|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | Flags extraFlags | octetsToInlineQos | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList inlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData [only if D==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + int min_len; + gint old_offset = offset; + guint32 wid; /* Writer EntityID */ + guint32 status_info = 0xffffffff; + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, RTPS_DATA_FLAGS); + + /* Calculates the minimum length for this submessage */ + min_len = 24; + if ((flags & FLAG_RTPS_DATA_Q) != 0) min_len += 4; + if ((flags & FLAG_RTPS_DATA_D) != 0) min_len += 4; + + if (octets_to_next_header < min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + offset += 12; + /* writerEntityId */ + wid = NEXT_guint32(tvb, offset, little_endian); + + offset += 12; + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + &status_info, + vendor_id); + } + info_summary_append_ex(info_summary_text, SUBMESSAGE_RTPS_DATA, wid, status_info); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + + /* extraFlags */ + rtps_util_add_extra_flags(tree, + tvb, + offset, + "Extra flags:"); + offset += 2; + + /* octetsToInlineQos */ + proto_tree_add_text(tree, + tvb, + offset, + 2, + "Octets to inline QoS: %d", + NEXT_guint16(tvb, offset, little_endian)); + offset += 2; + + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + &wid); + offset += 4; + + /* Sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* InlineQos */ + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + &status_info, + vendor_id); + } + + /* SerializedData */ + if ((flags & FLAG_DATA_D) != 0) { + if (wid == ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER) { + /* Dissect the serialized data as ParticipantMessageData: + * struct ParticipantMessageData { + * KeyHashPrefix_t participantGuidPrefix; + * KeyHashSuffix_t kind; + * sequence<octet> data; + * } + */ + proto_tree * guid_tree; + guint32 kind; + proto_item * ti = proto_tree_add_text(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "ParticipantMessageData"); + guid_tree = proto_item_add_subtree(ti, + ett_rtps_part_message_data); + + rtps_util_add_guid_prefix(guid_tree, + tvb, + offset, + hf_rtps_sm_guid_prefix, + hf_rtps_sm_host_id, + hf_rtps_sm_app_id, + hf_rtps_sm_counter, + "participantGuidPrefix", + NULL, + 0); + offset += 12; + + /* Kind */ + kind = NEXT_guint32(tvb, offset, 0); /* Always big endian */ + proto_tree_add_text(guid_tree, + tvb, + offset, + 4, + "kind: %s", + val_to_str(kind, participant_message_data_kind, "unknown (%04x)")); + offset += 4; + + dissect_octet_seq(guid_tree, + tvb, + offset, + "serializedData"); + } else { + /* At the end still dissect the rest of the bytes as raw data */ + dissect_serialized_data(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData", + vendor_id); + } + } + + info_summary_append_ex(info_summary_text, SUBMESSAGE_RTPS_DATA, wid, status_info); +} + + + + +/* *********************************************************************** */ +/* * R T P S _ D A T A _ F R A G * */ +/* *********************************************************************** */ +static void dissect_RTPS_DATA_FRAG(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 vendor_id) { + /* + * + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |RTPS_DATA_FRAG |X|X|X|X|X|X|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | Flags extraFlags | octetsToInlineQos | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerEntityId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerEntityId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber writerSeqNum + + * | | + * +---------------+---------------+---------------+---------------+ + * | FragmentNumber fragmentStartingNum | + * +---------------+---------------+---------------+---------------+ + * | ushort fragmentsInSubmessage | ushort fragmentSize | + * +---------------+---------------+---------------+---------------+ + * | unsigned long sampleSize | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList inlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData ~ + * | | + * +---------------+---------------+---------------+---------------+ + */ + int min_len; + gint old_offset = offset; + guint32 wid; /* Writer EntityID */ + guint32 status_info = 0xffffffff; + + rtps_util_decode_flags(tree, tvb, offset + 1, flags, RTPS_DATA_FRAG_FLAGS); + + /* Calculates the minimum length for this submessage */ + min_len = 36; + if ((flags & FLAG_RTPS_DATA_FRAG_Q) != 0) min_len += 4; + + if (octets_to_next_header < min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + offset += 12; + /* writerEntityId */ + wid = NEXT_guint32(tvb, offset, little_endian); + + offset += 24; + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + &status_info, + vendor_id); + } + info_summary_append_ex(info_summary_text, SUBMESSAGE_RTPS_DATA_FRAG, wid, status_info); + return; + } + + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + + /* extraFlags */ + rtps_util_add_extra_flags(tree, + tvb, + offset, + "Extra flags:"); + offset += 2; + + /* octetsToInlineQos */ + proto_tree_add_text(tree, + tvb, + offset, + 2, + "Octets to inline QoS: %d", + NEXT_guint16(tvb, offset, little_endian)); + offset += 2; + + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + &wid); + offset += 4; + + + /* Sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "writerSeqNumber"); + offset += 8; + + /* Fragment number */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentStartingNum", + NULL, + 0); + offset += 4; + + /* Fragments in submessage */ + rtps_util_add_short(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentsInSubmessage", + NULL, + 0); + offset += 2; + + /* Fragment size */ + rtps_util_add_short(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "fragmentSize", + NULL, + 0); + offset += 2; + + /* sampleSize */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "sampleSize", + NULL, + 0); + offset += 4; + + /* InlineQos */ + if ((flags & FLAG_RTPS_DATA_FRAG_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + &status_info, + vendor_id); + } + + /* SerializedData */ + dissect_serialized_data(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData", + vendor_id); + info_summary_append_ex(info_summary_text, SUBMESSAGE_RTPS_DATA_FRAG, wid, status_info); +} + + + + + +/* *********************************************************************** */ +/* * R T P S _ D A T A _ B A T C H * */ +/* *********************************************************************** */ +static void dissect_RTPS_DATA_BATCH(tvbuff_t *tvb, + gint offset, + guint8 flags, + gboolean little_endian, + int octets_to_next_header, + proto_tree *tree, + char * info_summary_text, + guint16 vendor_id) { + /* + * + * 0...2...........7...............15.............23...............31 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |RTPS_DATA_BATCH|X|X|X|X|X|X|Q|E| octetsToNextHeader | + * +---------------+---------------+---------------+---------------+ + * | Flags extraFlags | octetsToInlineQos | + * +---------------+---------------+---------------+---------------+ + * | EntityId readerId | + * +---------------+---------------+---------------+---------------+ + * | EntityId writerId | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber batchSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | | + * + SequenceNumber firstSampleSN + + * | | + * +---------------+---------------+---------------+---------------+ + * | SequenceNumberOffset offsetToLastSampleSN | + * +---------------+---------------+---------------+---------------+ + * | unsigned long batchSampleCount | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList batchInlineQos [only if Q==1] ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | unsigned long octetsToSLEncapsulationId | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SampleInfoList sampleInfoList ~ + * | | + * +---------------+---------------+---------------+---------------+ + * | SampleListEncapsulationId | | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SampleList sampleList ~ + * | | + * +---------------+---------------+---------------+---------------+ + * + * + * SampleInfo: + * 0...............8..............16..............24..............32 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |X|X|X|X|X|X|X|X|X|X|X|I|D|O|Q|T| octetsToInlineQoS | + * +---------------+---------------+---------------+---------------+ + * | unsigned long serializedDataLength | + * +---------------+---------------+---------------+---------------+ + * | | + * + Timestamp timestamp [only if T==1] + + * | | + * +---------------+---------------+---------------+---------------+ + * | SequenceNumberOffset offsetSN [only if O==1] | + * +---------------+---------------+---------------+---------------+ + * | | + * ~ ParameterList sampleInlineQos [only if Q==1] ~ + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * Sample: + * 0...............8..............16..............24..............32 + * +---------------+---------------+---------------+---------------+ + * | | + * ~ SerializedData serializedData [only if SampleInfo.D==1 ] ~ + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + int min_len; + gint old_offset = offset; + guint32 wid; /* Writer EntityID */ + guint32 status_info = 0xffffffff; + gint32 octectsToSLEncapsulationId; + guint32 batchSampleCount; + gint32 sampleListOffset; + guint16 encapsulation_id; + rtps_util_decode_flags(tree, tvb, offset + 1, flags, RTPS_DATA_BATCH_FLAGS); + + /* Calculates the minimum length for this submessage */ + min_len = 44; + if ((flags & FLAG_RTPS_DATA_BATCH_Q) != 0) min_len += 4; + + if (octets_to_next_header < min_len) { + proto_tree_add_uint_format(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset+2, + 2, + octets_to_next_header, + "octetsToNextHeader: %u (Error: should be >= %u)", + octets_to_next_header, + min_len); + return; + } + + /* Skip decoding the entire packet if (tree == NULL) + * Note that we still need to decode the statusInfo and the writer ID + */ + if (tree == NULL) { + offset += 12; + /* writerEntityId */ + wid = NEXT_guint32(tvb, offset, little_endian); + + offset += 24; + if ((flags & FLAG_DATA_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "inlineQos", + &status_info, + vendor_id); + } + info_summary_append_ex(info_summary_text, SUBMESSAGE_RTPS_DATA_BATCH, wid, status_info); + return; + } + proto_tree_add_item(tree, + hf_rtps_sm_octets_to_next_header, + tvb, + offset + 2, + 2, + little_endian); + offset += 4; + + + /* extraFlags */ + rtps_util_add_extra_flags(tree, + tvb, + offset, + "Extra flags:"); + offset += 2; + + /* octetsToInlineQos */ + proto_tree_add_text(tree, + tvb, + offset, + 2, + "Octets to inline QoS: %d", + NEXT_guint16(tvb, offset, little_endian)); + offset += 2; + + + /* readerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_rdentity_id, + hf_rtps_sm_rdentity_id_key, + hf_rtps_sm_rdentity_id_kind, + ett_rtps_rdentity, + "readerEntityId", + NULL); + offset += 4; + + /* writerEntityId */ + rtps_util_add_entity_id(tree, + tvb, + offset, + hf_rtps_sm_wrentity_id, + hf_rtps_sm_wrentity_id_key, + hf_rtps_sm_wrentity_id_kind, + ett_rtps_wrentity, + "writerEntityId", + &wid); + offset += 4; + + + /* Batch sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "batchSeqNumber"); + offset += 8; + + /* First stample sequence number */ + rtps_util_add_seq_number(tree, + tvb, + offset, + little_endian, + "firstSampleSeqNumber"); + offset += 8; + + /* offsetToLastSampleSN */ + rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "offsetToLastSampleSN", + NULL, + 0); + offset += 4; + + /* batchSampleCount */ + batchSampleCount = rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "batchSampleCount", + NULL, + 0); + offset += 4; + + /* Parameter list (if Q==1) */ + /* InlineQos */ + if ((flags & FLAG_RTPS_DATA_BATCH_Q) != 0) { + offset = dissect_parameter_sequence(tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "batchInlineQos", + &status_info, + vendor_id); + } + + /* octetsToSLEncapsulationId */ + octectsToSLEncapsulationId = (gint32)rtps_util_add_long(tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "octetsToSLEncapsulationId", + NULL, + 0); + offset += 4; + sampleListOffset = offset + octectsToSLEncapsulationId; + + + /* Sample info list */ + { + proto_item * ti; + proto_tree * sil_tree; + guint count = 0; + + ti = proto_tree_add_text(tree, + tvb, + offset, + -1, + "Sample Info List"); + sil_tree = proto_item_add_subtree(ti, ett_rtps_sample_info_list); + + /* Sample Info List: start decoding the sample info list until the offset + * is greater or equal than 'sampleListOffset' */ + while (offset < sampleListOffset) { + guint16 flags; + guint16 octetsToInlineQos; + gint min_length; + proto_tree * si_tree; + gint offset_begin_sampleinfo = offset; + + if (rtps_max_batch_samples_dissected > 0 && count >= rtps_max_batch_samples_dissected) { + ti = proto_tree_add_text(sil_tree, + tvb, + offset, + -1, + "... (more samples available. Configure this limit from preferences dialog)"); + offset = sampleListOffset; + break; + } + + ti = proto_tree_add_text(sil_tree, + tvb, + offset, + -1, + "sampleInfo[%d]", count++); + si_tree = proto_item_add_subtree(ti, ett_rtps_sample_info); + + flags = NEXT_guint16(tvb, offset, 0); /* Flags are always big endian */ + rtps_util_decode_flags_16bit(si_tree, tvb, offset, flags, RTPS_SAMPLE_INFO_FLAGS16); + offset += 2; + octetsToInlineQos = rtps_util_add_short(si_tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "octetsToInlineQos", + NULL, + 0); + offset += 2; + + min_length = 4; + if ((flags & FLAG_SAMPLE_INFO_T) != 0) min_len += 8; + if ((flags & FLAG_SAMPLE_INFO_Q) != 0) min_len += 4; + if ((flags & FLAG_SAMPLE_INFO_O) != 0) min_len += 4; + + /* Ensure there are enough bytes to decode */ + if (sampleListOffset - offset < min_length) { + proto_tree_add_text(si_tree, + tvb, + offset-4, + 4, + "Error: not enough bytes to dissec sample inof"); + return; + } + + /* Serialized data length */ + rtps_util_add_long(si_tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "serializedDataLength", + NULL, + 0); + offset += 4; + + /* Timestamp [only if T==1] */ + if ((flags & FLAG_SAMPLE_INFO_T) != 0) { + rtps_util_add_ntp_time(si_tree, + tvb, + offset, + little_endian, + "timestamp", + NULL, + 0); + offset += 8; + } + + /* Offset SN [only if O==1] */ + if ((flags & FLAG_SAMPLE_INFO_O) != 0) { + rtps_util_add_long(si_tree, + tvb, + offset, + -1, + little_endian, + 0, /* is_hex */ + 0, /* is_signed */ + "offsetSN", + NULL, + 0); + offset += 4; + } + + /* Parameter list [only if Q==1] */ + if ((flags & FLAG_SAMPLE_INFO_Q) != 0) { + offset = dissect_parameter_sequence(si_tree, + tvb, + offset, + little_endian, + octets_to_next_header - (offset - old_offset) + 4, + "sampleInlineQos", + &status_info, + vendor_id); + } + proto_item_set_len(ti, offset - offset_begin_sampleinfo); + } /* while (offset < sampleListOffset) */ + } + + /* Encapsulation ID for the entire data sequence */ + encapsulation_id = NEXT_guint16(tvb, offset, 0); /* Always big endian */ + proto_tree_add_text(tree, + tvb, + offset, + 2, + "encapsulation kind: %s", + val_to_str(encapsulation_id, encapsulation_id_vals, "unknown (%02x)")); + offset += 2; + + /* The next two bytes are ignored */ + offset += 2; + + /* Now the list of serialized data: */ + proto_tree_add_text(tree, + tvb, + offset, + octets_to_next_header - (offset - old_offset) + 4, + "serializedData"); + + /* TODO: enter one entry in the tree per sample (still keep it serialized) + */ + info_summary_append_ex(info_summary_text, SUBMESSAGE_RTPS_DATA_BATCH, wid, status_info); +} + + + + + +/***************************************************************************/ +/* The main packet dissector function + */ +static gboolean dissect_rtps(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree) { + proto_item *ti = NULL; + proto_tree *rtps_tree = NULL; + gint offset = 0; + proto_tree *rtps_submessage_tree = NULL; + guint8 submessageId; + guint8 flags; + gboolean little_endian; + gboolean is_ping = FALSE; + gint next_submsg, octets_to_next_header; + guint16 vendor_id = RTPS_VENDOR_UNKNOWN; + char info_summary_text[MAX_SUMMARY_SIZE]; + + info_summary_text[0] = '\0'; + + /* Check 'RTPS' signature: + * A header is invalid if it has less than 16 octets + */ + if (!tvb_bytes_exist(tvb, offset, 16)) return FALSE; + + /* Check packet signature */ + if ( (tvb_get_guint8(tvb,offset) != 'R') || + (tvb_get_guint8(tvb,offset+1) != 'T') || + (tvb_get_guint8(tvb,offset+2) != 'P') || + (tvb_get_guint8(tvb,offset+3) != 'S') || + (tvb_get_guint8(tvb,offset+4) != 2) ) { + return FALSE; + } + + /* --- Make entries in Protocol column ---*/ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTPS2"); + } + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_clear(pinfo->cinfo, COL_INFO); + } + + /* Check if is NDDSPING */ + { + guint8 nddsPing[8]; + tvb_memcpy(tvb, nddsPing, offset+8, 8); + is_ping = (nddsPing[0] == 'N' && + nddsPing[1] == 'D' && + nddsPing[2] == 'D' && + nddsPing[3] == 'S' && + nddsPing[4] == 'P' && + nddsPing[5] == 'I' && + nddsPing[6] == 'N' && + nddsPing[7] == 'G'); + } + + if (tree) { + /* create display subtree for the protocol */ + ti = proto_tree_add_item(tree, proto_rtps, tvb, 0, -1, FALSE); + rtps_tree = proto_item_add_subtree(ti, ett_rtps); + + /* Protocol Version */ + rtps_util_add_protocol_version(rtps_tree, tvb, offset+4); + + /* Vendor Id */ + vendor_id = NEXT_guint16(tvb, offset+6, FALSE); + rtps_util_add_vendor_id(rtps_tree, tvb, offset+6, NULL, 0); + + /* If is not PING, the next 12 bytes are the GUID prefix */ + if (!is_ping) { + rtps_util_add_guid_prefix(rtps_tree, + tvb, + offset+8, + hf_rtps_guid_prefix, + hf_rtps_host_id, + hf_rtps_app_id, + hf_rtps_sm_counter, + NULL, + NULL, + 0); + } + } + + if (is_ping) { + g_strlcpy(info_summary_text, "PING", MAX_SUMMARY_SIZE); + } + + /* Extract the domain id and participant index for the default mapping */ + if (tree) { + int domain_id; + int participant_idx = -1; + int nature; + int Doffset; + proto_item *ti; + proto_tree *mapping_tree; + + /* For a complete description of these rules, see RTPS documentation + + RTPS 1.2 mapping: + domain_id = ((pinfo->destport - PORT_BASE)/10) % 100; + participant_idx = (pinfo->destport - PORT_BASE) / 1000; + nature = (pinfo->destport % 10); + + For Unicast, the port mapping formula is: + metatraffic_unicast_port = port_base + + (domain_id_gain * domain_id) + + (participant_id_gain * participant_id) + + builtin_unicast_port_offset + For Multicast, the port mapping is: + metatraffic_multicast_port = port_base + + (domain_id_gain * domain_id) + + builtin_multicast_port_offset + + Where the constants are: + port_base = 7400 + domain_id_gain = 250 + participant_id_gain = 2 + builtin_multicast_port_offset = 0 + builtin_unicast_port_offset = 10 + user_multicast_port_offset = 1 + user_unicast_port_offset = 11 + + + To obtain the individual components from the port number, the reverse formulas are: + domain_id = (port - port_base) / 250 (valid both multicast / unicast) + Doffset = (port - port_Base - (domain_id * 250)); + participant_idx = (Doffset - 10) / 2; + + */ + domain_id = (pinfo->destport - PORT_BASE) / 250; + Doffset = (pinfo->destport - PORT_BASE - domain_id * 250); + if (Doffset == 0) { + nature = PORT_METATRAFFIC_MULTICAST; + } else if (Doffset == 1) { + nature = PORT_USERTRAFFIC_MULTICAST; + } else { + participant_idx = (Doffset - 10) / 2; + if ( (Doffset - 10) % 2 == 0) { + nature = PORT_METATRAFFIC_UNICAST; + } else { + nature = PORT_USERTRAFFIC_UNICAST; + } + } + + if (nature == PORT_METATRAFFIC_UNICAST || nature == PORT_USERTRAFFIC_UNICAST) { + ti = proto_tree_add_text(rtps_tree, + tvb, + 0, + 4, + "Default port mapping: %s, domainId=%d, " + "participantIdx=%d", + val_to_str(nature, nature_type_vals, "%02x"), + domain_id, + participant_idx); + } else { + /* Multicast doesn't print the participant index */ + ti = proto_tree_add_text(rtps_tree, + tvb, + 0, + 4, + "Default port mapping: %s, domainId=%d", + val_to_str(nature, nature_type_vals, "%02x"), + domain_id); + } + + /* Build the searchable protocol tree */ + mapping_tree = proto_item_add_subtree(ti, ett_rtps_default_mapping); + proto_tree_add_uint(mapping_tree, + hf_rtps_domain_id, + tvb, + 0, + 4, + domain_id); + if (nature == PORT_METATRAFFIC_UNICAST || nature == PORT_USERTRAFFIC_UNICAST) { + proto_tree_add_uint(mapping_tree, + hf_rtps_participant_idx, + tvb, + 0, + 4, + participant_idx); + } + proto_tree_add_uint(mapping_tree, + hf_rtps_nature_type, + tvb, + 0, + 4, + nature); + } + + /* offset behind RTPS's Header (need to be set in case tree=NULL)*/ + offset=20; + + while (tvb_reported_length_remaining(tvb, offset) > 0) { + submessageId = tvb_get_guint8(tvb, offset); + + /* Creates the subtree 'Submessage: XXXX' */ + if (rtps_tree) { + if (submessageId & 0x80) { + ti = proto_tree_add_text(rtps_tree, + tvb, + offset, + -1, + "Submessage: %s", + val_to_str(submessageId, submessage_id_vals, + "Vendor-specific (0x%02x)")); + } else { + ti = proto_tree_add_text(rtps_tree, + tvb, + offset, + -1, + "Submessage: %s", + val_to_str(submessageId, submessage_id_vals, + "Unknown (0x%02x)")); + } + rtps_submessage_tree = proto_item_add_subtree(ti, ett_rtps_submessage); + + /* Decode the submessage ID */ + if (submessageId & 0x80) { + proto_tree_add_uint_format(rtps_submessage_tree, + hf_rtps_sm_id, + tvb, + offset, + 1, + submessageId, + "submessageId: Vendor-specific (0x%02x)", + submessageId); + } else { + proto_tree_add_uint(rtps_submessage_tree, hf_rtps_sm_id, + tvb, offset, 1, submessageId); + } + } /* tree is present */ + + /* Gets the flags */ + flags = tvb_get_guint8(tvb, offset + 1); + + /* Gets the E (Little endian) flag */ + little_endian = ((flags & FLAG_E) != 0); + + /* octet-to-next-header */ + octets_to_next_header = NEXT_guint16(tvb, offset + 2, little_endian); + next_submsg = offset + octets_to_next_header + 4; + + /* Set length of this item */ + if (ti != NULL) { + proto_item_set_len(ti, octets_to_next_header + 4); + } + + /* Now decode each single submessage + * + * Note: if tree==NULL, it's true we don't care too much about the + * details, but we are still calling the individual submessage + * dissectors in order to correctly compose the INFO list. + * The offset passed to the dissectors points to the start of the + * submessage (at the ID byte). + */ + switch (submessageId) { + case SUBMESSAGE_PAD: + dissect_PAD(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_DATA: + dissect_DATA(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_DATA_FRAG: + dissect_DATA_FRAG(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_NOKEY_DATA: + dissect_NOKEY_DATA(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_NOKEY_DATA_FRAG: + dissect_NOKEY_DATA_FRAG(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_NACK_FRAG: + dissect_NACK_FRAG(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + + case SUBMESSAGE_ACKNACK_BATCH: + case SUBMESSAGE_ACKNACK: + dissect_ACKNACK(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_HEARTBEAT: + dissect_HEARTBEAT(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_HEARTBEAT_BATCH: + dissect_HEARTBEAT_BATCH(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_HEARTBEAT_FRAG: + dissect_HEARTBEAT_FRAG(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_GAP: + dissect_GAP(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_INFO_TS: + dissect_INFO_TS(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_INFO_SRC: + dissect_INFO_SRC(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_INFO_REPLY_IP4: + dissect_INFO_REPLY_IP4(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_INFO_DST: + dissect_INFO_DST(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_INFO_REPLY: + dissect_INFO_REPLY(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_RTPS_DATA: + dissect_RTPS_DATA(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_RTPS_DATA_FRAG: + dissect_RTPS_DATA_FRAG(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + case SUBMESSAGE_RTPS_DATA_BATCH: + dissect_RTPS_DATA_BATCH(tvb, + offset, + flags, + little_endian, + octets_to_next_header, + rtps_submessage_tree, + info_summary_text, + vendor_id); + break; + + + default: + if (rtps_submessage_tree != NULL) { + proto_tree_add_uint(rtps_submessage_tree, hf_rtps_sm_flags, + tvb, offset + 1, 1, flags); + proto_tree_add_uint(rtps_submessage_tree, + hf_rtps_sm_octets_to_next_header, + tvb, offset + 2, 2, next_submsg); + } + } + + /* next submessage's offset */ + offset = next_submsg; + } + + /* Compose the content of the 'summary' column */ + if ((pinfo != NULL) && (pinfo->cinfo != NULL) && (check_col(pinfo->cinfo, COL_INFO))) { + col_add_fstr(pinfo->cinfo, COL_INFO, info_summary_text); + } + return TRUE; + +} /* dissect_rtps(...) */ + + + + + +/*************************************************************************** + * Register the protocol with Wireshark + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +void proto_register_rtps2(void) { + + /* Definition of the protocol tree items: + * This section declares all the protocol items that are parsed in the + * dissectors. + * Structure of each element: + * { + * item_id, { + * name, // As appears in the GUI tree + * abbrev, // Referenced by filters (rtps.xxxx[.yyyy]) + * type, // FT_BOOLEAN, FT_UINT8, ... + * display, // BASE_HEX | BASE_DEC | BASE_OCT or other meanings + * strings, // String table (for enums) or NULL + * bitmask, // only for bitfields + * blurb, // Complete description of this item + * HFILL + * } + * } + */ + static hf_register_info hf[] = { + + /* Protocol Version (composed as major.minor) -------------------------- */ + { &hf_rtps_protocol_version, { + "version", + "rtps2.version", + FT_NONE, + BASE_NONE, + NULL, + 0, + "RTPS protocol version number", + HFILL } + }, + { &hf_rtps_protocol_version_major, { + "major", + "rtps2.version.major", + FT_INT8, + BASE_DEC, + NULL, + 0, + "RTPS major protocol version number", + HFILL } + }, + { &hf_rtps_protocol_version_minor, { + "minor", + "rtps2.version.minor", + FT_INT8, + BASE_DEC, + NULL, + 0, + "RTPS minor protocol version number", + HFILL } + }, + + /* Domain Participant and Participant Index ---------------------------- */ + { &hf_rtps_domain_id, { + "domain_id", + "rtps2.domain_id", + FT_UINT32, + BASE_DEC, + NULL, + 0, + "Domain ID", + HFILL } + }, + + { &hf_rtps_participant_idx, { + "participant_idx", + "rtps2.participant_idx", + FT_UINT32, + BASE_DEC, + NULL, + 0, + "Participant index", + HFILL } + }, + { &hf_rtps_nature_type, { + "traffic_nature", + "rtps2.traffic_nature", + FT_UINT32, + BASE_DEC, + VALS(nature_type_vals), + 0, + "Nature of the traffic (meta/user-traffic uni/multi-cast)", + HFILL } + }, + + /* Vendor ID ----------------------------------------------------------- */ + { &hf_rtps_vendor_id, { + "vendorId", + "rtps2.vendorId", + FT_UINT16, + BASE_HEX, + NULL, + 0, + "Unique identifier of the DDS vendor that generated this packet", + HFILL } + }, + + /* Guid Prefix for the Packet ------------------------------------------ */ + { &hf_rtps_guid_prefix, { + "guidPrefix", + "rtps2.guidPrefix", + FT_BYTES, + BASE_HEX, + NULL, + 0, + "GuidPrefix of the RTPS packet", + HFILL } + }, + + /* Host ID ------------------------------------------------------------- */ + { &hf_rtps_host_id, { /* HIDDEN */ + "hostId", + "rtps2.hostId", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "Sub-component 'hostId' of the GuidPrefix of the RTPS packet", + HFILL } + }, + + /* AppID --------------------------------------------------------------- */ + { &hf_rtps_app_id, { + "appId", + "rtps2.appId", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "Sub-component 'appId' of the GuidPrefix of the RTPS packet", + HFILL } + }, + + /* Counter ------------------------------------------------------------- */ + { &hf_rtps_counter, { /* HIDDEN */ + "counter", + "rtps2.counter", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "Sub-component 'counter' of the GuidPrefix of the RTPS packet", + HFILL } + }, + + + /* Submessage ID ------------------------------------------------------- */ + { &hf_rtps_sm_id, { + "submessageId", + "rtps2.sm.id", + FT_UINT8, + BASE_HEX, + VALS(submessage_id_vals), + 0, + "defines the type of submessage", + HFILL } + }, + + /* Submessage flags ---------------------------------------------------- */ + { &hf_rtps_sm_flags, { + "flags", + "rtps2.sm.flags", + FT_UINT8, + BASE_HEX, + NULL, + 0, + "bitmask representing the flags associated with a submessage", + HFILL } + }, + + /* octets to next header ---------------------------------------------- */ + { &hf_rtps_sm_octets_to_next_header, { + "octetsToNextHeader", + "rtps2.sm.octetsToNextHeader", + FT_UINT16, + BASE_DEC, + NULL, + 0, + "Size of the submessage payload", + HFILL } + }, + + /* GUID as {GuidPrefix, EntityId} ------------------------------------ */ + { &hf_rtps_sm_guid_prefix, { + "guidPrefix", + "rtps2.sm.guidPrefix", + FT_BYTES, + BASE_HEX, + NULL, + 0, + "a generic guidPrefix that is transmitted inside the submessage " + "(this is NOT the guidPrefix described in the packet header", + HFILL } + }, + + { &hf_rtps_sm_host_id, { + "host_id", + "rtps2.sm.guidPrefix.hostId", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "The hostId component of the rtps2.sm.guidPrefix", + HFILL } + }, + + { &hf_rtps_sm_app_id, { + "appId", + "rtps2.sm.guidPrefix.appId", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "AppId component of the rtps2.sm.guidPrefix", + HFILL } + }, + { &hf_rtps_sm_instance_id, { + "instanceId", + "rtps2.sm.guidPrefix.appId.instanceId", + FT_UINT24, + BASE_HEX, + NULL, + 0, + "instanceId component of the AppId of the rtps2.sm.guidPrefix", + HFILL } + }, + { &hf_rtps_sm_app_kind, { + "appKind", + "rtps2.sm.guidPrefix.appId.appKind", + FT_UINT8, + BASE_HEX, + NULL, + 0, + "appKind component of the AppId of the rtps2.sm.guidPrefix", + HFILL } + }, + + { &hf_rtps_sm_counter, { + "counter", + "rtps2.sm.guidPrefix.counter", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "The counter component of the rtps2.sm.guidPrefix", + HFILL } + }, + + /* Entity ID (composed as entityKey, entityKind) ----------------------- */ + { &hf_rtps_sm_entity_id, { + "entityId", + "rtps2.sm.entityId", + FT_UINT32, + BASE_HEX, + VALS(entity_id_vals), + 0, + "Object entity ID as it appears in a DATA submessage (keyHashSuffix)", + HFILL } + }, + { &hf_rtps_sm_entity_id_key, { + "entityKey", + "rtps2.sm.entityId.entityKey", + FT_UINT24, + BASE_HEX, + NULL, + 0, + "'entityKey' field of the object entity ID", + HFILL } + }, + { &hf_rtps_sm_entity_id_kind, { + "entityKind", + "rtps2.sm.entityId.entityKind", + FT_UINT8, + BASE_HEX, + VALS(entity_kind_vals), + 0, + "'entityKind' field of the object entity ID", + HFILL } + }, + + { &hf_rtps_sm_rdentity_id, { + "readerEntityId", + "rtps2.sm.rdEntityId", + FT_UINT32, + BASE_HEX, + VALS(entity_id_vals), + 0, + "Reader entity ID as it appears in a submessage", + HFILL } + }, + { &hf_rtps_sm_rdentity_id_key, { + "readerEntityKey", + "rtps2.sm.rdEntityId.entityKey", + FT_UINT24, + BASE_HEX, + NULL, + 0, + "'entityKey' field of the reader entity ID", + HFILL } + }, + { &hf_rtps_sm_rdentity_id_kind, { + "readerEntityKind", + "rtps2.sm.rdEntityId.entityKind", + FT_UINT8, + BASE_HEX, + VALS(entity_kind_vals), + 0, + "'entityKind' field of the reader entity ID", + HFILL } + }, + + { &hf_rtps_sm_wrentity_id, { + "writerEntityId", + "rtps2.sm.wrEntityId", + FT_UINT32, + BASE_HEX, + VALS(entity_id_vals), + 0, + "Writer entity ID as it appears in a submessage", + HFILL } + }, + { &hf_rtps_sm_wrentity_id_key, { + "writerEntityKey", + "rtps2.sm.wrEntityId.entityKey", + FT_UINT24, + BASE_HEX, + NULL, + 0, + "'entityKey' field of the writer entity ID", + HFILL } + }, + { &hf_rtps_sm_wrentity_id_kind, { + "writerEntityKind", + "rtps2.sm.wrEntityId.entityKind", + FT_UINT8, + BASE_HEX, + VALS(entity_kind_vals), + 0, + "'entityKind' field of the writer entity ID", + HFILL } + }, + + + + /* Sequence number ----------------------------------------------------- */ + { &hf_rtps_sm_seq_number, { + "writerSeqNumber", + "rtps2.sm.seqNumber", + FT_INT64, + BASE_DEC, + NULL, + 0, + "Writer sequence number", + HFILL } + }, + + /* Parameter Id -------------------------------------------------------- */ + { &hf_rtps_parameter_id, { + "parameterId", + "rtps2.param.id", + FT_UINT16, + BASE_HEX, + VALS(parameter_id_vals), + 0, + "Parameter Id", + HFILL } + }, + + /* Parameter Length ---------------------------------------------------- */ + { &hf_rtps_parameter_length, { + "parameterLength", + "rtps2.param.length", + FT_UINT16, + BASE_DEC, + NULL, + 0, + "Parameter Length", + HFILL } + }, + + /* Parameter / Status Info --------------------------------------------- */ + { &hf_rtps_param_status_info, { + "statusInfo", + "rtps2.param.statusInfo", + FT_UINT32, + BASE_HEX, + NULL, + 0, + "State information of the data object to which the message apply" + " (i.e. lifecycle)", + HFILL } + }, + + /* Parameter / NtpTime ------------------------------------------------- */ + { &hf_rtps_param_ntpt, { + "ntpTime", + "rtps2.param.ntpTime", + FT_NONE, + BASE_NONE, + NULL, + 0, + "Time using the NTP standard format", + HFILL } + }, + { &hf_rtps_param_ntpt_sec, { + "seconds", + "rtps2.param.ntpTime.sec", + FT_INT32, + BASE_DEC, + NULL, + 0, + "The 'second' component of a NTP time", + HFILL } + }, + { &hf_rtps_param_ntpt_fraction, { + "fraction", + "rtps2.param.ntpTime.fraction", + FT_UINT32, + BASE_DEC, + NULL, + 0, + "The 'fraction' component of a NTP time", + HFILL } + }, + + + /* Parameter / Topic --------------------------------------------------- */ + { &hf_rtps_param_topic_name, { + "topic", + "rtps2.param.topicName", + FT_STRINGZ, + BASE_NONE, + NULL, + 0, + "String representing the value value of a PID_TOPIC parameter", + HFILL } + }, + + /* Parameter / Entity -------------------------------------------------- */ + { &hf_rtps_param_entity_name, { + "entity", + "rtps2.param.entityName", + FT_STRINGZ, + BASE_NONE, + NULL, + 0, + "String representing the name of the entity addressed by the submessage", + HFILL } + }, + + + /* Parameter / Strength ------------------------------------------------ */ + { &hf_rtps_param_strength, { + "strength", + "rtps2.param.strength", + FT_INT32, + BASE_DEC, + NULL, + 0, + "Decimal value representing the value of a PID_OWNERSHIP_STRENGTH " + "parameter", + HFILL } + }, + + /* Parameter / Type Name ----------------------------------------------- */ + { &hf_rtps_param_type_name, { + "typeName", + "rtps2.param.typeName", + FT_STRINGZ, + BASE_NONE, + NULL, + 0, + "String representing the value of a PID_TYPE_NAME parameter", + HFILL } + }, + + /* Parameter / User Data ----------------------------------------------- */ + { &hf_rtps_param_user_data, { + "userData", + "rtps2.param.userData", + FT_BYTES, + BASE_HEX, + NULL, + 0, + "The user data sent in a PID_USER_DATA parameter", + HFILL } + }, + + /* Parameter / Group Data ---------------------------------------------- */ + { &hf_rtps_param_group_data, { + "groupData", + "rtps2.param.groupData", + FT_BYTES, + BASE_HEX, + NULL, + 0, + "The user data sent in a PID_GROUP_DATA parameter", + HFILL } + }, + + /* Parameter / Topic Data ---------------------------------------------- */ + { &hf_rtps_param_topic_data, { + "topicData", + "rtps2.param.topicData", + FT_BYTES, + BASE_HEX, + NULL, + 0, + "The user data sent in a PID_TOPIC_DATA parameter", + HFILL } + }, + + + /* Parameter / Content Filter Name ------------------------------------- */ + { &hf_rtps_param_content_filter_name, { + "contentFilterName", + "rtps2.param.contentFilterName", + FT_STRINGZ, + BASE_NONE, + NULL, + 0, + "Value of the content filter name as sent in a PID_CONTENT_FILTER_PROPERTY parameter", + HFILL } + }, + { &hf_rtps_param_related_topic_name, { + "relatedTopicName", + "rtps2.param.relatedTopicName", + FT_STRINGZ, + BASE_NONE, + NULL, + 0, + "Value of the related topic name as sent in a PID_CONTENT_FILTER_PROPERTY parameter", + HFILL } + }, + { &hf_rtps_param_filter_name, { + "filterName", + "rtps2.param.filterName", + FT_STRINGZ, + BASE_NONE, + NULL, + 0, + "Value of the filter name as sent in a PID_CONTENT_FILTER_PROPERTY parameter", + HFILL } + }, + + /* Finally the raw issue data ------------------------------------------ */ + { &hf_rtps_issue_data, { + "serializedData", + "rtps2.serializedData", + FT_BYTES, + BASE_HEX, + NULL, + 0, + "The user data transferred in a ISSUE submessage", + HFILL } + }, + + }; + + static gint *ett[] = { + &ett_rtps, + &ett_rtps_default_mapping, + &ett_rtps_proto_version, + &ett_rtps_submessage, + &ett_rtps_parameter_sequence, + &ett_rtps_parameter, + &ett_rtps_flags, + &ett_rtps_entity, + &ett_rtps_rdentity, + &ett_rtps_wrentity, + &ett_rtps_guid_prefix, + &ett_rtps_part_message_data, + &ett_rtps_locator_udp_v4, + &ett_rtps_locator, + &ett_rtps_locator_list, + &ett_rtps_ntp_time, + &ett_rtps_bitmap, + &ett_rtps_seq_string, + &ett_rtps_seq_ulong, + &ett_rtps_serialized_data, + &ett_rtps_sample_info_list, + &ett_rtps_sample_info + }; + module_t *rtps_module; + + proto_rtps = proto_register_protocol( + "Real-Time Publish-Subscribe Wire Protocol 2.x", + "RTPS2", + "rtps2"); + proto_register_field_array(proto_rtps, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Registers the control in the preference panel */ + rtps_module = prefs_register_protocol(proto_rtps, reinit_rtps); +/* + prefs_register_bool_preference(rtps_module, "do_something", + "Do somethinig short description", + "Do something long and very exhaustive description " + "that can go on and on and on and on... ", + &glob_do_something); +*/ + prefs_register_uint_preference(rtps_module, "max_batch_samples_dissected", + "Max samples dissected for DATA_BATCH", + "Specifies the maximum number of samples dissected in " + "a DATA_BATCH submessage. Increasing this value may affect " + "performances if the trace has a lot of big batched samples.", + 10, &rtps_max_batch_samples_dissected); + + +} + +void proto_reg_handoff_rtps2(void) { + heur_dissector_add("udp", dissect_rtps, proto_rtps); +} + |