wireshark/epan/dissectors/packet-rtps-utils.c

437 lines
18 KiB
C

/* packet-rtps-utils.c
* ~~~~~~~~~~~~~
*
* The following file contains helper routines for the RTPS packet dissector
*
* (c) 2005-2020 Copyright, Real-Time Innovations, Inc.
* Real-Time Innovations, Inc.
* 232 East Java Drive
* Sunnyvale, CA 94089
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* -------------------------------------
*
* 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:
*
* OMG DDS standards: http://portals.omg.org/dds/omg-dds-standard/
*
* Older OMG DDS specification:
* http://www.omg.org/cgi-bin/doc?ptc/2003-07-07
*
* NDDS and RTPS information: http://www.rti.com/resources.html
*
*/
#include "config.h"
#include <epan/packet.h>
#include "packet-rtps.h"
static wmem_map_t * dissection_infos = NULL;
static wmem_map_t * union_member_mappings = NULL;
static wmem_map_t * mutable_member_mappings = NULL;
#define DISSECTION_INFO_MAX_ELEMENTS (100)
#define MAX_MEMBER_NAME (256)
#define HASHMAP_DISCRIMINATOR_CONSTANT (-2)
typedef struct _union_member_mapping {
guint64 union_type_id;
guint64 member_type_id;
gint32 discriminator;
gchar member_name[MAX_MEMBER_NAME];
} union_member_mapping;
typedef struct _mutable_member_mapping {
gint64 key;
guint64 struct_type_id;
guint64 member_type_id;
guint32 member_id;
gchar member_name[MAX_MEMBER_NAME];
} mutable_member_mapping;
typedef struct _dissection_element {
guint64 type_id;
guint16 flags;
guint32 member_id;
gchar member_name[MAX_MEMBER_NAME];
} dissection_element;
typedef struct _dissection_info {
guint64 type_id;
gint member_kind;
guint64 base_type_id;
guint32 member_length;
gchar member_name[MAX_MEMBER_NAME];
RTICdrTypeObjectExtensibility extensibility;
gint32 bound;
gint32 num_elements;
dissection_element elements[DISSECTION_INFO_MAX_ELEMENTS];
} dissection_info;
gint dissect_user_defined(proto_tree *tree, tvbuff_t * tvb, gint offset, guint encoding,
dissection_info * _info, guint64 type_id, gchar * name,
RTICdrTypeObjectExtensibility extensibility, gint offset_zero,
guint16 flags, guint32 element_member_id);
static
gint dissect_mutable_member(proto_tree *tree , tvbuff_t * tvb, gint offset, guint encoding,
dissection_info * info, gboolean * is_end) {
proto_tree * member;
guint32 member_id, member_length;
mutable_member_mapping * mapping;
gint64 key;
rtps_util_dissect_parameter_header(tvb, &offset, encoding, &member_id, &member_length);
if ((member_id & PID_LIST_END) == PID_LIST_END){
/* If this is the end of the list, don't add a tree.
* If we add more logic here in the future, take into account that
* offset is incremented by 4 */
offset += 0;
*is_end = TRUE;
return offset;
}
if (member_length == 0){
return offset;
}
member = proto_tree_add_subtree_format(tree, tvb, offset, member_length, ett_rtps_dissection_tree,
NULL, "ID: %d, Length: %d", member_id, member_length);
{
if (info->base_type_id > 0) {
key = (info->base_type_id + info->base_type_id * member_id);
mapping = (mutable_member_mapping *) wmem_map_lookup(mutable_member_mappings, &(key));
if (mapping) { /* the library knows how to dissect this */
proto_item_append_text(member, "(base found 0x%016" G_GINT64_MODIFIER "x)", key);
dissect_user_defined(tree, tvb, offset, encoding, NULL, mapping->member_type_id,
mapping->member_name, EXTENSIBILITY_INVALID, offset, 0, mapping->member_id);
PROTO_ITEM_SET_HIDDEN(member);
return offset + member_length;
} else
proto_item_append_text(member, "(base not found 0x%016" G_GINT64_MODIFIER "x from 0x%016" G_GINT64_MODIFIER "x)",
key, info->base_type_id);
}
}
key = (info->type_id + info->type_id * member_id);
mapping = (mutable_member_mapping *) wmem_map_lookup(mutable_member_mappings, &(key));
if (mapping) { /* the library knows how to dissect this */
proto_item_append_text(member, "(found 0x%016" G_GINT64_MODIFIER "x)", key);
dissect_user_defined(tree, tvb, offset, encoding, NULL, mapping->member_type_id,
mapping->member_name, EXTENSIBILITY_INVALID, offset, 0, mapping->member_id);
} else
proto_item_append_text(member, "(not found 0x%016" G_GINT64_MODIFIER "x from 0x%016" G_GINT64_MODIFIER "x)",
key, info->type_id);
PROTO_ITEM_SET_HIDDEN(member);
return offset + member_length;
}
/* this is a recursive function. _info may or may not be NULL depending on the use iteration */
gint dissect_user_defined(proto_tree *tree, tvbuff_t * tvb, gint offset, guint encoding,
dissection_info * _info, guint64 type_id, gchar * name,
RTICdrTypeObjectExtensibility extensibility, gint offset_zero,
guint16 flags, guint32 element_member_id) {
guint64 member_kind;
dissection_info * info = NULL;
guint32 member_id, member_length;
if (_info) { /* first call enters here */
info = _info;
member_kind = info->member_kind;
} else {
info = (dissection_info *) wmem_map_lookup(dissection_infos, &(type_id));
if (info != NULL) {
member_kind = info->member_kind;
} else {
member_kind = type_id;
}
}
if (info && (flags & MEMBER_OPTIONAL) == MEMBER_OPTIONAL) {
gint offset_before = offset;
rtps_util_dissect_parameter_header(tvb, &offset, encoding, &member_id, &member_length);
offset = offset_before;
if (element_member_id != 0 && member_id != element_member_id)
return offset;
}
if (extensibility == EXTENSIBILITY_MUTABLE) {
rtps_util_dissect_parameter_header(tvb, &offset, encoding, &member_id, &member_length);
offset_zero = offset;
if ((member_id & PID_LIST_END) == PID_LIST_END){
/* If this is the end of the list, don't add a tree.
* If we add more logic here in the future, take into account that
* offset is incremented by 4 */
offset += 0;
return offset;
}
if (member_length == 0){
return offset;
}
}
//proto_item_append_text(tree, "(Before Switch 0x%016" G_GINT64_MODIFIER "x)", type_id);
switch (member_kind) {
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_BOOLEAN_TYPE: {
gint length = 1;
ALIGN_ZERO(offset, length, offset_zero);
gint16 value = tvb_get_gint8(tvb, offset);
proto_tree_add_boolean_format(tree, hf_rtps_dissection_boolean, tvb, offset, length, value,
"%s: %d", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_CHAR_8_TYPE:
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_BYTE_TYPE: {
gint length = 1;
ALIGN_ZERO(offset, length, offset_zero);
gint16 value = tvb_get_gint8(tvb, offset);
proto_tree_add_uint_format(tree, hf_rtps_dissection_byte, tvb, offset, length, value,
"%s: %d", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_INT_16_TYPE: {
gint length = 2;
ALIGN_ZERO(offset, length, offset_zero);
gint16 value = tvb_get_gint16(tvb, offset, encoding);
proto_tree_add_int_format(tree, hf_rtps_dissection_int16, tvb, offset, length, value,
"%s: %d", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_UINT_16_TYPE: {
gint length = 2;
ALIGN_ZERO(offset, length, offset_zero);
guint16 value = tvb_get_guint16(tvb, offset, encoding);
proto_tree_add_uint_format(tree, hf_rtps_dissection_uint16, tvb, offset, length, value,
"%s: %u", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_ENUMERATION_TYPE:
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_INT_32_TYPE: {
gint length = 4;
ALIGN_ZERO(offset, length, offset_zero);
gint value = tvb_get_gint32(tvb, offset, encoding);
proto_tree_add_int_format(tree, hf_rtps_dissection_int32, tvb, offset, length, value,
"%s: %d", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_UINT_32_TYPE: {
gint length = 4;
ALIGN_ZERO(offset, length, offset_zero);
guint value = tvb_get_guint32(tvb, offset, encoding);
proto_tree_add_uint_format(tree, hf_rtps_dissection_uint32, tvb, offset, length, value,
"%s: %u", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_INT_64_TYPE: {
gint length = 8;
ALIGN_ZERO(offset, length, offset_zero);
gint64 value = tvb_get_gint64(tvb, offset, encoding);
proto_tree_add_int64_format(tree, hf_rtps_dissection_int64, tvb, offset, length, value,
"%s: %"G_GINT64_MODIFIER"d", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_UINT_64_TYPE: {
gint length = 8;
ALIGN_ZERO(offset, length, offset_zero);
guint64 value = tvb_get_guint64(tvb, offset, encoding);
proto_tree_add_uint64_format(tree, hf_rtps_dissection_uint64, tvb, offset, length, value,
"%s: %"G_GINT64_MODIFIER"u", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_FLOAT_32_TYPE: {
gint length = 4;
ALIGN_ZERO(offset, length, offset_zero);
gfloat value = tvb_get_ieee_float(tvb, offset, encoding);
proto_tree_add_float_format(tree, hf_rtps_dissection_float, tvb, offset, length, value,
"%s: %.6f", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_FLOAT_64_TYPE: {
gint length = 8;
ALIGN_ZERO(offset, length, offset_zero);
gdouble value = tvb_get_ieee_double(tvb, offset, encoding);
proto_tree_add_double_format(tree, hf_rtps_dissection_double, tvb, offset, length, value,
"%s: %.6f", name, value);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_FLOAT_128_TYPE: {
gint length = 16;
ALIGN_ZERO(offset, length, offset_zero);
proto_tree_add_item(tree, hf_rtps_dissection_int128, tvb, offset, length, encoding);
offset += length;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_ARRAY_TYPE: {
gint i;
proto_tree * aux_tree;
gint base_offset = offset;
aux_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rtps_dissection_tree,
NULL, name);
for (i = 0; i < info->bound; i++) {
gchar temp_buff[MAX_MEMBER_NAME];
g_snprintf(temp_buff, MAX_MEMBER_NAME, "%s[%u]", name, i);
offset = dissect_user_defined(aux_tree, tvb, offset, encoding, NULL,
info->base_type_id, temp_buff, EXTENSIBILITY_INVALID, offset_zero, 0, 0);
}
proto_item_set_len(aux_tree, offset - base_offset);
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_SEQUENCE_TYPE: {
guint i;
proto_tree * aux_tree;
gint base_offset = offset;
gint length = 4;
ALIGN_ZERO(offset, length, offset_zero);
guint seq_size = tvb_get_guint32(tvb, offset, encoding);
aux_tree = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_rtps_dissection_tree,
NULL, "%s (%u elements)", name, seq_size);
offset += 4;
for (i = 0; i < seq_size; i++) {
gchar temp_buff[MAX_MEMBER_NAME];
g_snprintf(temp_buff, MAX_MEMBER_NAME, "%s[%u]", name, i);
if (info->base_type_id > 0)
offset = dissect_user_defined(aux_tree, tvb, offset, encoding, NULL,
info->base_type_id, temp_buff, EXTENSIBILITY_INVALID, offset_zero, 0, 0);
}
proto_item_set_len(aux_tree, offset - base_offset);
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_STRING_TYPE: {
gchar * string_value = NULL;
gint length = 4;
ALIGN_ZERO(offset, length, offset_zero);
guint string_size = tvb_get_guint32(tvb, offset, encoding);
offset += 4;
//proto_item_append_text(tree, "(String length: %u)", string_size);
string_value = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, string_size, ENC_ASCII);
proto_tree_add_string_format(tree, hf_rtps_dissection_string, tvb, offset, string_size,
string_value, "%s: %s", name, string_value);
offset += string_size;
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_ALIAS_TYPE: {
offset = dissect_user_defined(tree, tvb, offset, encoding, NULL,
info->base_type_id, name, EXTENSIBILITY_INVALID, offset_zero, 0, 0);
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_UNION_TYPE: {
guint64 key = type_id - 1;
union_member_mapping * result = (union_member_mapping *)wmem_map_lookup(union_member_mappings, &(key));
if (result != NULL) {
switch (result->member_type_id) {
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_ENUMERATION_TYPE:
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_INT_32_TYPE: {
gint value = tvb_get_gint32(tvb, offset, encoding);
offset += 4;
key = type_id + value;
result = (union_member_mapping *)wmem_map_lookup(union_member_mappings, &(key));
if (result != NULL) {
proto_item_append_text(tree, " (discriminator = %d, type_id = 0x%016" G_GINT64_MODIFIER "x)",
value, result->member_type_id);
offset = dissect_user_defined(tree, tvb, offset, encoding, NULL,
result->member_type_id, result->member_name, EXTENSIBILITY_INVALID, offset, 0, 0);
} else {
/* the hashmap uses the type_id to index the objects. substracting -2 here to lookup the discriminator
related to the type_id that identifies an union */
key = type_id + HASHMAP_DISCRIMINATOR_CONSTANT;
result = (union_member_mapping *)wmem_map_lookup(union_member_mappings, &(key));
if (result != NULL) {
proto_item_append_text(tree, " (discriminator = %d, type_id = 0x%016" G_GINT64_MODIFIER "x)",
value, result->member_type_id);
offset = dissect_user_defined(tree, tvb, offset, encoding, NULL,
result->member_type_id, result->member_name, EXTENSIBILITY_INVALID, offset, 0, 0);
}
}
break;
}
default:
break;
}
} else {
proto_item_append_text(tree, "(NULL 0x%016" G_GINT64_MODIFIER "x)", type_id);
}
break;
}
case RTI_CDR_TYPE_OBJECT_TYPE_KIND_STRUCTURE_TYPE: {
gint i;
proto_tree * aux_tree;
offset_zero = offset;
aux_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_rtps_dissection_tree,
NULL, name);
if (info->extensibility == EXTENSIBILITY_MUTABLE) {
gboolean is_end = FALSE;
while(!is_end)
offset = dissect_mutable_member(aux_tree, tvb, offset, encoding, info, &is_end);
} else {
if (info->base_type_id > 0) {
proto_item_append_text(tree, "(BaseId: 0x%016" G_GINT64_MODIFIER "x)", info->base_type_id);
offset = dissect_user_defined(aux_tree, tvb, offset, encoding, NULL,
info->base_type_id, info->member_name, EXTENSIBILITY_INVALID,
offset, 0, 0);
}
for (i = 0; i < info->num_elements && i < DISSECTION_INFO_MAX_ELEMENTS; i++) {
if (info->elements[i].type_id > 0)
offset = dissect_user_defined(aux_tree, tvb, offset, encoding, NULL,
info->elements[i].type_id, info->elements[i].member_name, info->extensibility,
offset_zero, info->elements[i].flags, info->elements[i].member_id);
}
}
break;
}
default:{
/* undefined behavior. this should not happen. the following line helps to debug if it happened */
proto_item_append_text(tree, "(unknown 0x%016" G_GINT64_MODIFIER "x)", member_kind);
break;
}
}
if (extensibility == EXTENSIBILITY_MUTABLE) {
offset_zero += member_length;
return offset_zero;
} else {
return offset;
}
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/