/* packet-rtps.c * ~~~~~~~~~~~~~ * * Routines for Real-Time Publish-Subscribe Protocol (RTPS) dissection * * Copyright 2005, Fabrizio Bertocci * Real-Time Innovations, Inc. * 385 Moffett Park Drive * Sunnyvale, CA 94089 * * Copyright 2003, LUKAS POKORNY * PETR SMOLIK * ZDENEK SEBEK * Czech Technical University in Prague * Faculty of Electrical Engineering * Department of Control Engineering * * $Id$ * * Wireshark - Network traffic analyzer * By Gerald Combs * 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. * * ------------------------------------- * * The following file is part of the RTPS packet dissector for Wireshark. * * RTPS protocol was developed by Real-Time Innovations, Inc. as wire * protocol for Data Distribution System. * Additional information at: * Full OMG DDS Standard Specification: * http://www.omg.org/cgi-bin/doc?ptc/2003-07-07 * * NDDS and RTPS information: http://www.rti.com/resources.html * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include "packet-rtps.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 (20) #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_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 octects printed on the parameter root for a sequence of octects */ #define MAX_SEQ_OCTETS_PRINTED (20) static const char * const SM_EXTRA_RPLUS = "(r+)"; static const char * const SM_EXTRA_RMINUS = "(r-)"; static const char * const SM_EXTRA_WPLUS = "(w+)"; static const char * const SM_EXTRA_WMINUS = "(w-)"; static const char * const SM_EXTRA_PPLUS = "(p+)"; static const char * const SM_EXTRA_PMINUS = "(p-)"; static const char * const SM_EXTRA_TPLUS = "(t+)"; static const char * const SM_EXTRA_TMINUS = "(t-)"; /* This structure is used to keep a list of submessages for the current * packet. The list is ordered by position of the submessage Id inside * the packet. * Submessages of the same kind are grouped together in one record. */ struct SMCounterRecord { int id; /* PAD, DATA, ... */ const char * extra; /* (r+, w+)... */ struct SMCounterRecord * next; /* Ptr to next */ }; /***************************************************************************/ /* 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_app_id_instance_id = -1; static int hf_rtps_app_id_app_kind = -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_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_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; /* 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_app_id = -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; /***************************************************************************/ /* Value-to-String Tables */ static const value_string entity_id_vals[] = { { ENTITYID_UNKNOWN, "ENTITYID_UNKNOWN" }, { ENTITYID_BUILTIN_TOPIC_WRITER, "ENTITYID_BUILTIN_TOPIC_WRITER" }, { ENTITYID_BUILTIN_TOPIC_READER, "ENTITYID_BUILTIN_TOPIC_READER" }, { ENTITYID_BUILTIN_PUBLICATIONS_WRITER, "ENTITYID_BUILTIN_PUBLICATIONS_WRITER" }, { ENTITYID_BUILTIN_PUBLICATIONS_READER, "ENTITYID_BUILTIN_PUBLICATIONS_READER" }, { ENTITYID_BUILTIN_SUBSCRIPTIONS_WRITER, "ENTITYID_BUILTIN_SUBSCRIPTIONS_WRITER" }, { ENTITYID_BUILTIN_SUBSCRIPTIONS_READER, "ENTITYID_BUILTIN_SUBSCRIPTIONS_READER" }, { ENTITYID_BUILTIN_SDP_PARTICIPANT_WRITER, "ENTITYID_BUILTIN_SDP_PARTICIPANT_WRITER" }, { ENTITYID_BUILTIN_SDP_PARTICIPANT_READER, "ENTITYID_BUILTIN_SDP_PARTICIPANT_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[] = { { PAD, "PAD" }, { DATA, "DATA" }, { NOKEY_DATA, "NOKEY_DATA" }, { ACKNACK, "ACKNACK" }, { HEARTBEAT, "HEARTBEAT" }, { GAP, "GAP" }, { INFO_TS, "INFO_TS" }, { INFO_SRC, "INFO_SRC" }, { INFO_REPLY_IP4, "INFO_REPLY_IP4" }, { INFO_DST, "INFO_DST" }, { INFO_REPLY, "INFO_REPLY" }, { 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_USER_DATA, "PID_USER_DATA" }, { PID_TOPIC_NAME, "PID_TOPIC_NAME" }, { PID_TYPE_NAME, "PID_TYPE_NAME" }, { PID_GROUP_DATA, "PID_GROUP_DATA" }, { PID_DEADLINE, "PID_DEADLINE" }, { PID_DEADLINE_OFFERED, "PID_DEADLINE_OFFERED [deprecated]" }, { PID_PARTICIPANT_LEASE_DURATION, "PID_PARTICIPANT_LEASE_DURATION" }, { PID_PERSISTENCE, "PID_PERSISTENCE" }, { PID_TIME_BASED_FILTER, "PID_TIME_BASED_FILTER" }, { PID_OWNERSHIP_STRENGTH, "PID_OWNERSHIP_STRENGTH" }, { PID_TYPE_CHECKSUM, "PID_TYPE_CHECKSUM [deprecated]" }, { PID_TYPE2_NAME, "PID_TYPE2_NAME [deprecated]" }, { PID_TYPE2_CHECKSUM, "PID_TYPE2_CHECKSUM [deprecated]" }, { 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_IS_RELIABLE, "PID_IS_RELIABLE [deprecated]" }, { PID_EXPECTS_ACK, "PID_EXPECTS_ACK" }, { PID_MULTICAST_IPADDRESS, "PID_MULTICAST_IPADDRESS" }, { PID_MANAGER_KEY, "PID_MANAGER_KEY [deprecated]" }, { PID_SEND_QUEUE_SIZE, "PID_SEND_QUEUE_SIZE" }, { PID_RELIABILITY_ENABLED, "PID_RELIABILITY_ENABLED" }, { PID_PROTOCOL_VERSION, "PID_PROTOCOL_VERSION" }, { PID_VENDOR_ID, "PID_VENDOR_ID" }, { 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_RELIABILITY, "PID_RELIABILITY" }, { PID_LIVELINESS, "PID_LIVELINESS" }, { PID_LIVELINESS_OFFERED, "PID_LIVELINESS_OFFERED [deprecated]" }, { PID_DURABILITY, "PID_DURABILITY" }, { PID_DURABILITY_SERVICE, "PID_DURABILITY_SERVICE" }, { PID_PRESENTATION_OFFERED, "PID_PRESENTATION_OFFERED [deprecated]" }, { PID_OWNERSHIP, "PID_OWNERSHIP" }, { PID_OWNERSHIP_OFFERED, "PID_OWNERSHIP_OFFERED [deprecated]" }, { PID_PRESENTATION, "PID_PRESENTATION" }, { PID_DESTINATION_ORDER, "PID_DESTINATION_ORDER" }, { PID_DESTINATION_ORDER_OFFERED, "PID_DESTINATION_ORDER_OFFERED [deprecated]" }, { PID_LATENCY_BUDGET, "PID_LATENCY_BUDGET" }, { PID_LATENCY_BUDGET_OFFERED, "PID_LATENCY_BUDGET_OFFERED [deprecated]" }, { PID_PARTITION, "PID_PARTITION" }, { PID_PARTITION_OFFERED, "PID_PARTITION_OFFERED [deprecated]" }, { PID_LIFESPAN, "PID_LIFESPAN" }, { 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_HISTORY, "PID_HISTORY" }, { PID_RESOURCE_LIMIT, "PID_RESOURCE_LIMIT" }, { PID_METATRAFFIC_MULTICAST_PORT, "PID_METATRAFFIC_MULTICAST_PORT" }, { PID_DEFAULT_EXPECTS_INLINE_QOS, "PID_DEFAULT_EXPECTS_INLINE_QOS" }, { PID_METATRAFFIC_UNICAST_IPADDRESS, "PID_METATRAFFIC_UNICAST_IPADDRESS" }, { PID_PARTICIPANT_BUILTIN_ENDPOINTS, "PID_PARTICIPANT_BUILTIN_ENDPOINTS" }, { PID_CONTENT_FILTER_PROPERTY, "PID_CONTENT_FILTER_PROPERTY" }, { PID_PROPERTY_LIST, "PID_PROPERTY_LIST" }, { PID_FILTER_SIGNATURE, "PID_FILTER_SIGNATURE" }, { PID_COHERENT_SET, "PID_COHERENT_SET" }, { PID_TYPECODE, "PID_TYPECODE" }, { 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" }, { 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 } }; /* 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', "Endianness bit" } /* Bit 0 */ }; static const struct Flag_definition DATA_FLAGS[] = { { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 7 */ { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 6 */ { 'U', "Unregister flag" }, /* Bit 5 */ { 'Q', "Inline QoS" }, /* Bit 4 */ { 'H', "Hash key flag" }, /* Bit 3 */ { 'A', "Alive flag" }, /* Bit 2 */ { 'D', "Data present" }, /* Bit 1 */ { 'E', "Endianness 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 */ { RESERVEDFLAG_CHAR, RESERVEDFLAG_STRING }, /* Bit 2 */ { 'Q', "Inline QoS" }, /* Bit 1 */ { 'E', "Endianness 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', "Endianness 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', "Endianness 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', "Endianness 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 */ { 'T', "Timestamp flag" }, /* Bit 1 */ { 'E', "Endianness 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', "Endianness 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', "Endianness 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', "Endianness 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', "Endianness bit" } /* Bit 0 */ }; /***************************************************************************/ /*************************************************************************** * Function prototypes * ~~~~~~~~~~~~~~~~~~~ */ /* Sm management */ static struct SMCounterRecord * sm_counter_add(struct SMCounterRecord *, guint8, const char * const extra); static void sm_counter_free(struct SMCounterRecord *); /* 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 void 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, int, const guint8 *, guint8 *, gint); static int 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 *, size_t); static void rtps_util_add_long(proto_tree *, tvbuff_t *, gint, int, int, gboolean, gboolean, const char *, guint8 *, size_t); 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 *, size_t); 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 *, size_t); 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 void rtps_util_decode_flags(proto_tree *, tvbuff_t *, gint, guint8, const struct Flag_definition *); static gint rtps_util_add_seq_ulong(proto_tree *, tvbuff_t *, gint, int, int, int, int, char *); /* The parameter dissector */ static gint dissect_parameter_sequence(proto_tree *, tvbuff_t *, gint, int, int, const char *); /* Sub-message dissector functions */ static void dissect_DATA(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree, const char **sm_extra); static void dissect_NOKEY_DATA(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_ACKNACK(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_HEARTBEAT(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_GAP(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_INFO_TS(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_INFO_SRC(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_INFO_REPLY_IP4(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_INFO_DST(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); static void dissect_INFO_REPLY(tvbuff_t *tvb,gint offset,guint8 flags, gboolean little_endian,int next_submsg_offset, proto_tree *rtps_submessage_tree); /* 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)) /* *********************************************************************** */ /* Adds a new record to the SMCounterRecord archive * It always inserts to the end of the list. Insert is not performed if * the last element is like the current one. * Parameters: * last = ptr to the last element or NULL if the list is empty * * Returns: * ptr to the last element of the list or NULL if out of memory occurred. */ static struct SMCounterRecord * sm_counter_add( struct SMCounterRecord *last, guint8 submessage, const char * const extra) { /* Can be NULL */ #if 0 if ((last == NULL) || (last->id != submessage)) { struct SMCounterRecord *ptr; /* Add message */ ptr = (struct SMCounterRecord *)g_malloc(sizeof(struct SMCounterRecord)); if (ptr == NULL) { return NULL; } ptr->id = submessage; ptr->counter = 1; ptr->next = NULL; if (last) { last->next = ptr; } return ptr; } last->counter++; #endif struct SMCounterRecord *ptr; ptr = (struct SMCounterRecord *)g_malloc(sizeof(struct SMCounterRecord)); if (ptr == NULL) { return NULL; } ptr->id = submessage; ptr->extra = extra; ptr->next = NULL; if (last) { last->next = ptr; } return ptr; } /* Free the entire list */ static void sm_counter_free(struct SMCounterRecord *head) { struct SMCounterRecord *ptr; while (head != NULL) { ptr = head->next; g_free(head); head = ptr; } } /* *********************************************************************** */ /* Format the given address (16 octects) 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); } } } /* *********************************************************************** */ static void rtps_util_add_protocol_version(proto_tree *tree, /* Can NOT be NULL */ tvbuff_t * tvb, gint offset) { 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, /* Can be NULL */ 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 != NULL) { 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, /* Can NOT be NULL */ 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]); } 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 */ static void 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); ti = proto_tree_add_text(tree, tvb, offset, 4, "%s: %d Locators", label, num_locators); 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 + 4 + (i * 24), little_endian, temp_buff, NULL, 0); } } } /* ------------------------------------------------------------------------- */ /* Insert in the protocol tree the next 4 bytes interpreted as IPV4Address_t */ static void rtps_util_add_ipv4_address_t(proto_tree *tree, /* Can be NULL */ tvbuff_t * tvb, gint offset, int little_endian, const guint8 * label, guint8 * buffer, /* Can be NULL */ gint buffer_size) { /* Can be 0 */ guint32 addr; addr = NEXT_guint32(tvb, offset, little_endian); if (addr == 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", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); } if (tree) { proto_tree_add_text(tree, tvb, offset, 4, "%s: %d.%d.%d.%d", label, (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 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, /* Can NOT be NULL */ tvbuff_t * tvb, gint offset, const guint8 * label, int little_endian) { proto_item * ti; proto_tree * locator_tree; guint32 port; char portLabel[MAX_PORT_SIZE]; char addr[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", addr, 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, addr, portLabel); } /* ------------------------------------------------------------------------- */ /* Insert in the protocol tree the next 8 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_app_id_instance_id * - hf_rtps_app_id_app_kind * * 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, /* Can be NULL */ tvbuff_t * tvb, gint offset, int hf_prefix, /* Cannot be 0 if tree != NULL */ int hf_host_id, int hf_app_id, int hf_app_id_instance_id, int hf_app_id_app_kind, const guint8 * label, /* Can be NULL */ guint8 * buffer, /* Can be NULL */ gint buffer_size) { guint32 host_id; guint32 app_id; guint32 instance_id; guint8 app_kind; guint8 * temp_buff; guint8 guid_prefix[8]; 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); for (i = 0; i < 8; ++i) { guid_prefix[i] = tvb_get_guint8(tvb, offset+i); } instance_id = (app_id >> 8); app_kind = (app_id & 0xff); /* Format the string */ temp_buff = (guint8 *)ep_alloc(MAX_GUID_PREFIX_SIZE); g_snprintf(temp_buff, MAX_GUID_PREFIX_SIZE, "%s=%02x%02x%02x%02x %02x%02x%02x%02x" " { hostId=%08x, appId=%08x" " (%s: %06x) }", 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], host_id, app_id, val_to_str(app_kind, app_kind_vals, "%02x"), instance_id); if (tree != NULL) { proto_item * ti, *hidden_item; proto_tree * guid_tree; proto_tree * appid_tree; /* The numeric value (used for searches) */ hidden_item = proto_tree_add_item(tree, hf_prefix, tvb, offset, 8, 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, 8, "%s", 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); /* AppId (root of the app_id sub-tree */ ti = proto_tree_add_item(guid_tree, hf_app_id, tvb, offset+4, 4, FALSE); appid_tree = proto_item_add_subtree(ti, ett_rtps_app_id); /* InstanceId */ proto_tree_add_item(appid_tree, hf_app_id_instance_id, tvb, offset+4, 3, FALSE); /* AppKind */ proto_tree_add_item(appid_tree, hf_app_id_app_kind, tvb, offset+7, 1, FALSE); } if (buffer != NULL) { g_strlcpy(buffer, temp_buff, buffer_size); } } /* ------------------------------------------------------------------------- */ /* 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. * Returns true if the entityKind is one of the NDDS built-in entities. */ static int 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 != NULL) { 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 (%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); } /* is a built-in entity if the bit M and R (5 and 6) of the entityKind are set */ /* return ((entity_kind & 0xc0) == 0xc0); */ return ( entity_id == ENTITYID_BUILTIN_TOPIC_WRITER || entity_id == ENTITYID_BUILTIN_TOPIC_READER || entity_id == ENTITYID_BUILTIN_PUBLICATIONS_WRITER || entity_id == ENTITYID_BUILTIN_PUBLICATIONS_READER || entity_id == ENTITYID_BUILTIN_SUBSCRIPTIONS_WRITER || entity_id == ENTITYID_BUILTIN_SUBSCRIPTIONS_READER || entity_id == ENTITYID_BUILTIN_SDP_PARTICIPANT_WRITER || entity_id == ENTITYID_BUILTIN_SDP_PARTICIPANT_READER ); } /* ------------------------------------------------------------------------- */ /* 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 != NULL) { 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 12 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, /* Cannot be NULL */ 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; guint8 app_kind; guint32 instance_id; guint32 entity_id; guint32 entity_key; guint8 entity_kind; guint8 guid_raw[12]; const char * str_entity_kind; const char * str_app_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); entity_id = tvb_get_ntohl(tvb, offset + 8); /* Re-Read raw data */ for (i = 0; i < 12; ++i) { guid_raw[i] = tvb_get_guint8(tvb, offset+i); } /* Split components from typed data */ instance_id = (app_id >> 8); app_kind = (app_id & 0xff); 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"); str_app_kind = val_to_str(app_kind, app_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: " "{ hostId=%08x, appId=%08x (%s: %06x), 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], host_id, app_id, str_app_kind, instance_id, entity_id, str_entity_kind, entity_key); proto_tree_add_text(tree, tvb, offset, 12, "%s", 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 _U_) { 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 != NULL) { proto_tree_add_int64_format(tree, hf_rtps_sm_seq_number, tvb, offset, 8, all, "%s: %" G_GINT64_MODIFIER "u", 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, /* Can be NULL */ 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 != NULL) { 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, /* Can be NULL */ 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 */ size_t buffer_size) { guint8 * retVal = NULL; guint32 size = NEXT_guint32(tvb, offset, little_endian); if (size > 0) { retVal = tvb_get_ephemeral_string(tvb, offset+4, size); } if (tree != NULL) { 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, (gulong) buffer_size, "%s", 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. */ static void rtps_util_add_long(proto_tree *tree, /* Can be NULL */ 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, size_t buffer_size) { char temp_buff[16]; 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, (gulong) buffer_size); } } /* ------------------------------------------------------------------------- */ /* 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, /* Can be NULL */ 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, /* Can be NULL */ tvbuff_t * tvb, gint offset, char * label, guint8 * buffer, /* Can be NULL */ size_t buffer_size) { const char *str; guint8 value = tvb_get_guint8(tvb, offset); str = value ? "TRUE" : "FALSE"; if (buffer) { g_strlcpy(buffer, str, (gulong) 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); 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); 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, /* Can be NULL */ tvbuff_t * tvb, gint offset, int little_endian, char * label, const value_string *vals, guint8 * buffer, /* Can be NULL */ size_t buffer_size) { guint32 kind = NEXT_guint32(tvb, offset, little_endian); if (buffer) { g_strlcpy(buffer, val_to_str(kind, vals, "0x%08x"), (gulong) 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, /* Can NOT be NULL */ 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; proto_item *ti; 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 */ 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); 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)); } 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, /* Can NOT be NULL */ 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 */ ti = proto_tree_add_text(tree, tvb, offset, param_length-8, "Seq"); string_tree = proto_item_add_subtree(ti, ett_rtps_seq_ulong); 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 ""; } } /* ------------------------------------------------------------------------- */ /* 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: * * ::= * * * * ::= long (0=TK_NULL, 1=TK_SHORT...) * ::= unsugned short * */ switch(tk_id) { /* Structure of the typecode data: * * ::= * * * * * * + * ::= * ::= unsigned short * ::= * ::= char+ * ::= unsigned long * ::= (char)0 * * ::= * *