/* packet-someip.c * SOME/IP dissector. * By Dr. Lars Voelker / * Copyright 2012-2020 Dr. Lars Voelker * Copyright 2019 Ana Pantar * Copyright 2019 Guenter Ebermann * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #include #include #include #include #include #include #include "packet-udp.h" #include "packet-someip.h" /* * Dissector for SOME/IP, SOME/IP-TP, and SOME/IP Payloads. * * See * http://www.some-ip.com */ #define SOMEIP_NAME "SOME/IP" #define SOMEIP_NAME_LONG "SOME/IP Protocol" #define SOMEIP_NAME_FILTER "someip" #define SOMEIP_NAME_LONG_MULTIPLE "SOME/IP Protocol (Multiple Payloads)" #define SOMEIP_NAME_LONG_BROKEN "SOME/IP: Incomplete headers!" #define SOMEIP_NAME_LONG_TOO_SHORT "SOME/IP: Incomplete SOME/IP payload!" /*** Configuration ***/ #define DATAFILE_SOMEIP_SERVICES "SOMEIP_service_identifiers" #define DATAFILE_SOMEIP_METHODS "SOMEIP_method_event_identifiers" #define DATAFILE_SOMEIP_EVENTGROUPS "SOMEIP_eventgroup_identifiers" #define DATAFILE_SOMEIP_PARAMETERS "SOMEIP_parameter_list" #define DATAFILE_SOMEIP_BASE_TYPES "SOMEIP_parameter_base_types" #define DATAFILE_SOMEIP_ARRAYS "SOMEIP_parameter_arrays" #define DATAFILE_SOMEIP_STRINGS "SOMEIP_parameter_strings" #define DATAFILE_SOMEIP_TYPEDEFS "SOMEIP_parameter_typedefs" #define DATAFILE_SOMEIP_STRUCTS "SOMEIP_parameter_structs" #define DATAFILE_SOMEIP_UNIONS "SOMEIP_parameter_unions" #define DATAFILE_SOMEIP_ENUMS "SOMEIP_parameter_enums" #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_UNKNOWN 0 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_BASE_TYPE 1 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_STRING 2 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_ARRAY 3 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_STRUCT 4 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_UNION 5 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_TYPEDEF 6 #define SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_ENUM 7 /*** SOME/IP ***/ #define SOMEIP_HDR_LEN 16 #define SOMEIP_HDR_PART1_LEN 8 #define SOMEIP_HDR_PART2_LEN_INCL_TP 12 #define SOMEIP_TP_HDR_LEN 4 #define SOMEIP_PROTOCOL_VERSION 1 /* Message Types */ #define SOMEIP_MSGTYPE_REQUEST 0x00 #define SOMEIP_MSGTYPE_REQUEST_NO_RESPONSE 0x01 #define SOMEIP_MSGTYPE_NOTIFICATION 0x02 #define SOMEIP_MSGTYPE_RESPONSE 0x80 #define SOMEIP_MSGTYPE_ERROR 0x81 #define SOMEIP_MSGTYPE_ACK_MASK 0x40 #define SOMEIP_MSGTYPE_TP_MASK 0x20 #define SOMEIP_MSGTYPE_FLAGS_MASK 0x60 #define SOMEIP_MSGTYPE_NO_FLAGS_MASK 0x9f #define SOMEIP_MSGTYPE_TP_STRING "SOME/IP-TP segment" #define SOMEIP_MSGTYPE_ACK_STRING "ACK" /* SOME/IP-TP */ #define SOMEIP_TP_OFFSET_MASK 0xfffffff0 #define SOMEIP_TP_OFFSET_MASK_FLAGS 0x0000000f #define SOMEIP_TP_OFFSET_MASK_RESERVED 0x0000000e #define SOMEIP_TP_OFFSET_MASK_MORE_SEGMENTS 0x00000001 /* Return Codes */ #define SOMEIP_RETCODE_OK 0x00 #define SOMEIP_RETCODE_NOT_OK 0x01 #define SOMEIP_RETCODE_UNKNOWN_SERVICE 0x02 #define SOMEIP_RETCODE_UNKNOWN_METHOD 0x03 #define SOMEIP_RETCODE_NOT_READY 0x04 #define SOMEIP_RETCODE_NOT_REACHABLE 0x05 #define SOMEIP_RETCODE_TIMEOUT 0x06 #define SOMEIP_RETCODE_WRONG_PROTO_VER 0x07 #define SOMEIP_RETCODE_WRONG_INTERFACE_VER 0x08 #define SOMEIP_RETCODE_MALFORMED_MSG 0x09 #define SOMEIP_RETCODE_WRONG_MESSAGE_TYPE 0x0a /* ID wireshark identifies the dissector by */ static int proto_someip = -1; static dissector_handle_t someip_handle_udp = NULL; static dissector_handle_t someip_handle_tcp = NULL; /* header field */ static int hf_someip_messageid = -1; static int hf_someip_serviceid = -1; static int hf_someip_methodid = -1; static int hf_someip_length = -1; static int hf_someip_clientid = -1; static int hf_someip_sessionid = -1; static int hf_someip_protover = -1; static int hf_someip_interface_ver = -1; static int hf_someip_messagetype = -1; static int hf_someip_messagetype_ack_flag = -1; static int hf_someip_messagetype_tp_flag = -1; static int hf_someip_returncode = -1; static int hf_someip_tp = -1; static int hf_someip_tp_offset = -1; static int hf_someip_tp_flags = -1; static int hf_someip_tp_reserved = -1; static int hf_someip_tp_more_segments = -1; static int hf_someip_payload = -1; /* protocol tree items */ static gint ett_someip = -1; static gint ett_someip_msgtype = -1; static gint ett_someip_tp = -1; static gint ett_someip_tp_flags = -1; /* dissector handling */ static dissector_table_t someip_dissector_table = NULL; /* message reassembly for SOME/IP-TP */ static int hf_someip_tp_fragments = -1; static int hf_someip_tp_fragment = -1; static int hf_someip_tp_fragment_overlap = -1; static int hf_someip_tp_fragment_overlap_conflicts = -1; static int hf_someip_tp_fragment_multiple_tails = -1; static int hf_someip_tp_fragment_too_long_fragment = -1; static int hf_someip_tp_fragment_error = -1; static int hf_someip_tp_fragment_count = -1; static int hf_someip_tp_reassembled_in = -1; static int hf_someip_tp_reassembled_length = -1; static int hf_someip_tp_reassembled_data = -1; static int hf_payload_unparsed = -1; static int hf_payload_length_field_8bit = -1; static int hf_payload_length_field_16bit = -1; static int hf_payload_length_field_32bit = -1; static int hf_payload_type_field_8bit = -1; static int hf_payload_type_field_16bit = -1; static int hf_payload_type_field_32bit = -1; static int hf_payload_str_base = -1; static int hf_payload_str_string = -1; static int hf_payload_str_struct = -1; static gint ett_someip_tp_fragment = -1; static gint ett_someip_tp_fragments = -1; static gint ett_someip_payload = -1; static gint ett_someip_string = -1; static gint ett_someip_array = -1; static gint ett_someip_array_dim = -1; static gint ett_someip_struct = -1; static gint ett_someip_union = -1; static const fragment_items someip_tp_frag_items = { &ett_someip_tp_fragment, &ett_someip_tp_fragments, &hf_someip_tp_fragments, &hf_someip_tp_fragment, &hf_someip_tp_fragment_overlap, &hf_someip_tp_fragment_overlap_conflicts, &hf_someip_tp_fragment_multiple_tails, &hf_someip_tp_fragment_too_long_fragment, &hf_someip_tp_fragment_error, &hf_someip_tp_fragment_count, &hf_someip_tp_reassembled_in, &hf_someip_tp_reassembled_length, &hf_someip_tp_reassembled_data, "SOME/IP-TP Segments" }; static reassembly_table someip_tp_reassembly_table; static range_t *someip_ports_udp = NULL; static range_t *someip_ports_tcp = NULL; static gboolean someip_tp_reassemble = TRUE; static gboolean someip_derserializer_activated = FALSE; /* SOME/IP Message Types */ static const value_string someip_msg_type[] = { {SOMEIP_MSGTYPE_REQUEST, "Request"}, {SOMEIP_MSGTYPE_REQUEST_NO_RESPONSE, "Request no response"}, {SOMEIP_MSGTYPE_NOTIFICATION, "Notification"}, {SOMEIP_MSGTYPE_RESPONSE, "Response"}, {SOMEIP_MSGTYPE_ERROR, "Error"}, {SOMEIP_MSGTYPE_REQUEST | SOMEIP_MSGTYPE_ACK_MASK, "Request Ack"}, {SOMEIP_MSGTYPE_REQUEST_NO_RESPONSE | SOMEIP_MSGTYPE_ACK_MASK, "Request no response Ack"}, {SOMEIP_MSGTYPE_NOTIFICATION | SOMEIP_MSGTYPE_ACK_MASK, "Notification Ack"}, {SOMEIP_MSGTYPE_RESPONSE | SOMEIP_MSGTYPE_ACK_MASK, "Response Ack"}, {SOMEIP_MSGTYPE_ERROR | SOMEIP_MSGTYPE_ACK_MASK, "Error Ack"}, {0, NULL} }; /* SOME/IP Return Code */ static const value_string someip_return_code[] = { {SOMEIP_RETCODE_OK, "Ok"}, {SOMEIP_RETCODE_NOT_OK, "Not Ok"}, {SOMEIP_RETCODE_UNKNOWN_SERVICE, "Unknown Service"}, {SOMEIP_RETCODE_UNKNOWN_METHOD, "Unknown Method/Event"}, {SOMEIP_RETCODE_NOT_READY, "Not Ready"}, {SOMEIP_RETCODE_NOT_REACHABLE, "Not Reachable (internal)"}, {SOMEIP_RETCODE_TIMEOUT, "Timeout (internal)"}, {SOMEIP_RETCODE_WRONG_PROTO_VER, "Wrong Protocol Version"}, {SOMEIP_RETCODE_WRONG_INTERFACE_VER, "Wrong Interface Version"}, {SOMEIP_RETCODE_MALFORMED_MSG, "Malformed Message"}, {SOMEIP_RETCODE_WRONG_MESSAGE_TYPE, "Wrong Message Type"}, {0, NULL} }; /*** expert info items ***/ static expert_field ef_someip_unknown_version = EI_INIT; static expert_field ef_someip_message_truncated = EI_INIT; static expert_field ef_someip_incomplete_headers = EI_INIT; static expert_field ef_someip_payload_truncated = EI_INIT; static expert_field ef_someip_payload_malformed = EI_INIT; static expert_field ef_someip_payload_config_error = EI_INIT; static expert_field ef_someip_payload_alignment_error = EI_INIT; static expert_field ef_someip_payload_static_array_min_not_max = EI_INIT; static expert_field ef_someip_payload_dyn_array_not_within_limit = EI_INIT; /*** Data Structure for mapping IDs to Names (Services, Methods, ...) ***/ static GHashTable *data_someip_services = NULL; static GHashTable *data_someip_methods = NULL; static GHashTable *data_someip_eventgroups = NULL; static GHashTable *data_someip_parameter_list = NULL; static GHashTable *data_someip_parameter_base_type_list = NULL; static GHashTable *data_someip_parameter_strings = NULL; static GHashTable *data_someip_parameter_typedefs = NULL; static GHashTable *data_someip_parameter_arrays = NULL; static GHashTable *data_someip_parameter_structs = NULL; static GHashTable *data_someip_parameter_unions = NULL; static GHashTable *data_someip_parameter_enums = NULL; /*********************************************** ********* Preferences / Configuration ********* ***********************************************/ typedef struct _someip_payload_parameter_item { guint32 pos; gchar *name; guint32 data_type; guint32 id_ref; } someip_payload_parameter_item_t; #define INIT_SOMEIP_PAYLOAD_PARAMETER_ITEM(NAME) \ (NAME)->pos = 0; \ (NAME)->name = NULL; \ (NAME)->data_type = 0; \ (NAME)->id_ref = 0; typedef struct _someip_payload_parameter_base_type_list { guint32 id; gchar *name; gchar *data_type; gboolean big_endian; guint32 bitlength_base_type; guint32 bitlength_encoded_type; } someip_payload_parameter_base_type_list_t; #define INIT_COMMON_BASE_TYPE_LIST_ITEM(NAME) \ (NAME)->id = 0; \ (NAME)->name = NULL; \ (NAME)->data_type = NULL ; \ (NAME)->big_endian = TRUE; \ (NAME)->bitlength_base_type = 0; \ (NAME)->bitlength_encoded_type = 0; typedef struct _someip_payload_parameter_string { guint32 id; gchar *name; gchar *encoding; gboolean dynamic_length; guint32 max_length; guint32 length_of_length; /* default: 32 */ gboolean big_endian; guint32 pad_to; } someip_payload_parameter_string_t; #define INIT_SOMEIP_PAYLOAD_PARAMETER_STRING(NAME) \ (NAME)->id = 0; \ (NAME)->name = NULL; \ (NAME)->encoding = NULL; \ (NAME)->dynamic_length = FALSE; \ (NAME)->max_length = 0; \ (NAME)->length_of_length = 0; \ (NAME)->big_endian = TRUE; \ (NAME)->pad_to = 0; typedef struct _someip_payload_parameter_typedef { guint32 id; gchar* name; guint32 data_type; guint32 id_ref; } someip_payload_parameter_typedef_t; #define INIT_SOMEIP_PAYLOAD_PARAMETER_TYPEDEF(NAME) \ (NAME)->id = 0; \ (NAME)->name = NULL; \ (NAME)->data_type = 0; \ (NAME)->id_ref = 0; typedef struct _someip_payload_parameter_struct { guint32 id; gchar *struct_name; guint32 length_of_length; /* default: 0 */ guint32 pad_to; /* default: 0 */ guint32 num_of_items; /* array of items */ someip_payload_parameter_item_t *items; } someip_payload_parameter_struct_t; #define INIT_SOMEIP_PAYLOAD_PARAMETER_STRUCT(NAME) \ (NAME)->id = 0; \ (NAME)->struct_name = NULL; \ (NAME)->length_of_length = 0; \ (NAME)->pad_to = 0; \ (NAME)->num_of_items = 0; typedef struct _someip_payload_parameter_enum_item { guint64 value; gchar *name; } someip_payload_parameter_enum_item_t; #define INIT_SOMEIP_PAYLOAD_PARAMETER_ENUM_ITEM(NAME) \ (NAME)->value = 0; \ (NAME)->name = NULL; typedef struct _someip_payload_parameter_enum { guint32 id; gchar *name; guint32 data_type; guint32 id_ref; guint32 num_of_items; someip_payload_parameter_enum_item_t *items; } someip_payload_parameter_enum_t; #define INIT_SOMEIP_PAYLOAD_PARAMETER_ENUM(NAME) \ (NAME)->id = 0; \ (NAME)->name = NULL; \ (NAME)->data_type = 0; \ (NAME)->id_ref = 0; \ (NAME)->num_of_items = 0; \ (NAME)->items = NULL; typedef struct _someip_parameter_union_item { guint32 id; gchar *name; guint32 data_type; guint32 id_ref; } someip_parameter_union_item_t; typedef struct _someip_parameter_union { guint32 id; gchar *name; guint32 length_of_length; /* default: 32 */ guint32 length_of_type; /* default: 32 */ guint32 pad_to; /* default: 0 */ guint32 num_of_items; someip_parameter_union_item_t *items; } someip_parameter_union_t; typedef struct _someip_parameter_union_uat { guint32 id; gchar *name; guint32 length_of_length; guint32 length_of_type; guint32 pad_to; guint32 num_of_items; guint32 type_id; gchar *type_name; guint32 data_type; guint32 id_ref; } someip_parameter_union_uat_t; typedef struct _someip_parameter_enum_uat { guint32 id; gchar *name; guint32 data_type; guint32 id_ref; guint32 num_of_items; guint32 value; gchar *value_name; } someip_parameter_enum_uat_t; typedef struct _someip_parameter_array_dim { guint32 num; guint32 lower_limit; guint32 upper_limit; guint32 length_of_length; guint32 pad_to; } someip_parameter_array_dim_t; typedef struct _someip_parameter_array { guint32 id; gchar *name; guint32 data_type; guint32 id_ref; guint32 num_of_dims; someip_parameter_array_dim_t *dims; } someip_parameter_array_t; typedef struct _someip_parameter_array_uat { guint32 id; gchar *name; guint32 data_type; guint32 id_ref; guint32 num_of_dims; guint32 num; guint32 lower_limit; guint32 upper_limit; guint32 length_of_length; guint32 pad_to; } someip_parameter_array_uat_t; typedef struct _someip_parameter_list { guint32 service_id; guint32 method_id; guint32 version; guint32 message_type; guint32 num_of_items; someip_payload_parameter_item_t *items; } someip_parameter_list_t; typedef struct _someip_parameter_list_uat { guint32 service_id; guint32 method_id; guint32 version; guint32 message_type; guint32 num_of_params; guint32 pos; gchar *name; guint32 data_type; guint32 id_ref; } someip_parameter_list_uat_t; typedef struct _someip_parameter_struct_uat { guint32 id; gchar *struct_name; guint32 length_of_length; /* default: 0 */ guint32 pad_to; /* default: 0 */ guint32 num_of_items; guint32 pos; gchar *name; guint32 data_type; guint32 id_ref; } someip_parameter_struct_uat_t; typedef someip_payload_parameter_base_type_list_t someip_parameter_base_type_list_uat_t; typedef someip_payload_parameter_string_t someip_parameter_string_uat_t; typedef someip_payload_parameter_typedef_t someip_parameter_typedef_uat_t; typedef struct _generic_one_id_string { guint id; gchar *name; } generic_one_id_string_t; typedef struct _generic_two_id_string { guint id; guint id2; gchar *name; } generic_two_id_string_t; static generic_one_id_string_t* someip_service_ident = NULL; static guint someip_service_ident_num = 0; static generic_two_id_string_t* someip_method_ident = NULL; static guint someip_method_ident_num = 0; static generic_two_id_string_t* someip_eventgroup_ident = NULL; static guint someip_eventgroup_ident_num = 0; static someip_parameter_list_uat_t *someip_parameter_list = NULL; static guint someip_parameter_list_num = 0; static someip_parameter_string_uat_t *someip_parameter_strings = NULL; static guint someip_parameter_strings_num = 0; static someip_parameter_typedef_uat_t *someip_parameter_typedefs = NULL; static guint someip_parameter_typedefs_num = 0; static someip_parameter_array_uat_t *someip_parameter_arrays = NULL; static guint someip_parameter_arrays_num = 0; static someip_parameter_struct_uat_t *someip_parameter_structs = NULL; static guint someip_parameter_structs_num = 0; static someip_parameter_union_uat_t *someip_parameter_unions = NULL; static guint someip_parameter_unions_num = 0; static someip_parameter_enum_uat_t *someip_parameter_enums = NULL; static guint someip_parameter_enums_num = 0; static someip_parameter_base_type_list_uat_t *someip_parameter_base_type_list = NULL; static guint someip_parameter_base_type_list_num = 0; void proto_register_someip(void); void proto_reg_handoff_someip(void); /* register a UDP SOME/IP port */ void register_someip_port_udp(guint32 portnumber) { dissector_add_uint("udp.port", portnumber, someip_handle_udp); } /* register a TCP SOME/IP port */ void register_someip_port_tcp(guint32 portnumber) { dissector_add_uint("tcp.port", portnumber, someip_handle_tcp); } /*** UAT Callbacks and Helpers ***/ static void someip_free_key(gpointer key) { wmem_free(wmem_epan_scope(), key); } static void simple_free(gpointer data _U_) { /* we need to free because of the g_strdup in post_update*/ g_free(data); } /* ID -> Name */ static void * copy_generic_one_id_string_cb(void* n, const void* o, size_t size _U_) { generic_one_id_string_t* new_rec = (generic_one_id_string_t*)n; const generic_one_id_string_t* old_rec = (const generic_one_id_string_t*)o; new_rec->name = g_strdup(old_rec->name); new_rec->id = old_rec->id; return new_rec; } static gboolean update_generic_one_identifier_16bit(void *r, char **err) { generic_one_id_string_t *rec = (generic_one_id_string_t *)r; if ( rec->id>0xffff ) { *err = g_strdup_printf("We currently only support 16 bit identifiers (ID: %i Name: %s)", rec->id, rec->name); return FALSE; } if (rec->name == NULL || rec->name[0] == 0) { *err = g_strdup("Name cannot be empty"); return FALSE; } return TRUE; } static void free_generic_one_id_string_cb(void*r) { generic_one_id_string_t* rec = (generic_one_id_string_t*)r; /* freeing result of g_strdup */ g_free(rec->name); rec->name = NULL; } static void post_update_one_id_string_template_cb(generic_one_id_string_t *data, guint data_num, GHashTable *ht) { guint i; int *key = NULL; for (i = 0; i < data_num; i++) { key = wmem_new(wmem_epan_scope(), int); *key = data[i].id; g_hash_table_insert(ht, key, g_strdup(data[i].name)); } } /* ID/ID2 -> Name */ static void * copy_generic_two_id_string_cb(void* n, const void* o, size_t size _U_) { generic_two_id_string_t* new_rec = (generic_two_id_string_t*)n; const generic_two_id_string_t* old_rec = (const generic_two_id_string_t*)o; new_rec->name = g_strdup(old_rec->name); new_rec->id = old_rec->id; new_rec->id2 = old_rec->id2; return new_rec; } static gboolean update_generic_two_identifier_16bit(void *r, char **err) { generic_two_id_string_t *rec = (generic_two_id_string_t *)r; if ( rec->id > 0xffff ) { *err = g_strdup_printf("We currently only support 16 bit identifiers (ID: %i Name: %s)", rec->id, rec->name); return FALSE; } if ( rec->id2 > 0xffff ) { *err = g_strdup_printf("We currently only support 16 bit identifiers (ID: %i ID2: %i Name: %s)", rec->id, rec->id2, rec->name); return FALSE; } if (rec->name == NULL || rec->name[0] == 0 ) { *err = g_strdup("Name cannot be empty"); return FALSE; } return TRUE; } static void free_generic_two_id_string_cb(void*r) { generic_two_id_string_t* rec = (generic_two_id_string_t*)r; /* freeing result of g_strdup */ g_free(rec->name); rec->name = NULL; } static void post_update_generic_two_id_string_template_cb(generic_two_id_string_t *data, guint data_num, GHashTable *ht) { guint i; int *key = NULL; guint tmp; guint tmp2; for (i = 0; i < data_num; i++) { key = wmem_new(wmem_epan_scope(), int); tmp = (data[i].id & 0xffff) << 16; tmp2 = (data[i].id2 & 0xffff); /* the hash table does not know about uint32, so we use int32 */ *key = (int)(tmp + tmp2); g_hash_table_insert(ht, key, g_strdup(data[i].name)); } } char* someip_lookup_service_name(guint16 serviceid) { guint32 tmp = (guint32)serviceid; if (data_someip_services == NULL) { return NULL; } return (char *)g_hash_table_lookup(data_someip_services, &tmp); } static char* someip_lookup_method_name(guint16 serviceid, guint16 methodid) { guint32 tmp = (serviceid << 16) + methodid; if (data_someip_methods == NULL) { return NULL; } return (char *)g_hash_table_lookup(data_someip_methods, &tmp); } char* someip_lookup_eventgroup_name(guint16 serviceid, guint16 eventgroupid) { guint32 tmp = (serviceid << 16) + eventgroupid; if (data_someip_eventgroups == NULL) { return NULL; } return (char *)g_hash_table_lookup(data_someip_eventgroups, &tmp); } /*** SOME/IP Services ***/ UAT_HEX_CB_DEF (someip_service_ident, id, generic_one_id_string_t) UAT_CSTRING_CB_DEF (someip_service_ident, name, generic_one_id_string_t) static void post_update_someip_service_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_services) { g_hash_table_destroy (data_someip_services); data_someip_services = NULL; } /* create new hash table */ data_someip_services = g_hash_table_new_full(g_int_hash, g_int_equal, &someip_free_key, &simple_free); post_update_one_id_string_template_cb(someip_service_ident, someip_service_ident_num, data_someip_services); } /*** SOME/IP Methods/Events/Fields ***/ UAT_HEX_CB_DEF (someip_method_ident, id, generic_two_id_string_t) UAT_HEX_CB_DEF (someip_method_ident, id2, generic_two_id_string_t) UAT_CSTRING_CB_DEF (someip_method_ident, name, generic_two_id_string_t) static void post_update_someip_method_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_methods) { g_hash_table_destroy (data_someip_methods); data_someip_methods = NULL; } /* create new hash table */ data_someip_methods = g_hash_table_new_full(g_int_hash, g_int_equal, &someip_free_key, &simple_free); post_update_generic_two_id_string_template_cb(someip_method_ident, someip_method_ident_num, data_someip_methods); } /*** SOME/IP Eventgroups ***/ UAT_HEX_CB_DEF (someip_eventgroup_ident, id, generic_two_id_string_t) UAT_HEX_CB_DEF (someip_eventgroup_ident, id2, generic_two_id_string_t) UAT_CSTRING_CB_DEF (someip_eventgroup_ident, name, generic_two_id_string_t) static void post_update_someip_eventgroup_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_eventgroups) { g_hash_table_destroy (data_someip_eventgroups); data_someip_eventgroups = NULL; } /* create new hash table */ data_someip_eventgroups = g_hash_table_new_full(g_int_hash, g_int_equal, &someip_free_key, &simple_free); post_update_generic_two_id_string_template_cb(someip_eventgroup_ident, someip_eventgroup_ident_num, data_someip_eventgroups); } static void someip_payload_free_key(gpointer key) { wmem_free(wmem_epan_scope(), key); } static void someip_payload_free_generic_data(gpointer data) { wmem_free(wmem_epan_scope(), (void *)data); } static gint64 someip_parameter_key(guint16 serviceid, guint16 methodid, guint8 version, guint8 msgtype) { gint64 tmp1; gint64 tmp2; gint64 tmp3; gint64 tmp4; /* key: Service-ID [16bit] | Method-ID [16bit] | Version [8bit] | Message-Type [8bit] */ tmp1 = (gint64)(serviceid & 0xffff); tmp2 = (gint64)(methodid & 0xffff) << 16; tmp3 = (gint64)(version & 0xff) << 32; tmp4 = (gint64)(msgtype & 0xff) << 40; return (gint64)(tmp1 + tmp2 + tmp3 + tmp4); } static someip_parameter_list_t* get_parameter_config(guint16 serviceid, guint16 methodid, guint8 version, guint8 msgtype) { gint64 *key = NULL; someip_parameter_list_t* tmp = NULL; if (data_someip_parameter_list == NULL) { return NULL; } key = wmem_new(wmem_epan_scope(), gint64); *key = someip_parameter_key(serviceid, methodid, version, msgtype); tmp = (someip_parameter_list_t*)g_hash_table_lookup(data_someip_parameter_list, key); wmem_free(wmem_epan_scope(), key); return tmp; } static gpointer get_generic_config(GHashTable *ht, gint64 id) { if (ht == NULL) { return NULL; } return (gpointer)g_hash_table_lookup(ht, &id); } static someip_payload_parameter_base_type_list_t* get_base_type_config(guint32 id) { return (someip_payload_parameter_base_type_list_t*)get_generic_config(data_someip_parameter_base_type_list, (gint64)id); } static someip_payload_parameter_string_t* get_string_config(guint32 id) { return (someip_payload_parameter_string_t*)get_generic_config(data_someip_parameter_strings, (gint64)id); } static someip_payload_parameter_typedef_t* get_typedef_config(guint32 id) { return (someip_payload_parameter_typedef_t*)get_generic_config(data_someip_parameter_typedefs, (gint64)id); } static someip_parameter_array_t* get_array_config(guint32 id) { return (someip_parameter_array_t*)get_generic_config(data_someip_parameter_arrays, (gint64)id); } static someip_payload_parameter_struct_t* get_struct_config(guint32 id) { return (someip_payload_parameter_struct_t*)get_generic_config(data_someip_parameter_structs, (gint64)id); } static someip_parameter_union_t* get_union_config(guint32 id) { return (someip_parameter_union_t*)get_generic_config(data_someip_parameter_unions, (gint64)id); } static someip_payload_parameter_enum_t* get_enum_config(guint32 id) { return (someip_payload_parameter_enum_t*)get_generic_config(data_someip_parameter_enums, (gint64)id); } UAT_HEX_CB_DEF(someip_parameter_list, service_id, someip_parameter_list_uat_t) UAT_HEX_CB_DEF(someip_parameter_list, method_id, someip_parameter_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_list, version, someip_parameter_list_uat_t) UAT_HEX_CB_DEF(someip_parameter_list, message_type, someip_parameter_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_list, num_of_params, someip_parameter_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_list, pos, someip_parameter_list_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_list, name, someip_parameter_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_list, data_type, someip_parameter_list_uat_t) UAT_HEX_CB_DEF(someip_parameter_list, id_ref, someip_parameter_list_uat_t) static void * copy_someip_parameter_list_cb(void* n, const void* o, size_t size _U_) { someip_parameter_list_uat_t *new_rec = (someip_parameter_list_uat_t*)n; const someip_parameter_list_uat_t *old_rec = (const someip_parameter_list_uat_t*)o; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } new_rec->service_id = old_rec->service_id; new_rec->method_id = old_rec->method_id; new_rec->version = old_rec->version; new_rec->message_type = old_rec->message_type; new_rec->num_of_params = old_rec->num_of_params; new_rec->pos = old_rec->pos; new_rec->data_type = old_rec->data_type; new_rec->id_ref = old_rec->id_ref; return new_rec; } static gboolean update_someip_parameter_list(void *r, char **err) { someip_parameter_list_uat_t *rec = (someip_parameter_list_uat_t *)r; if (rec->service_id > 0xffff) { *err = g_strdup_printf("We currently only support 16 bit Service IDs (Service-ID: %i Name: %s)", rec->service_id, rec->name); return FALSE; } if (rec->method_id > 0xffff) { *err = g_strdup_printf("We currently only support 16 bit Method IDs (Service-ID: %i Method-ID: %i Name: %s)", rec->service_id, rec->method_id, rec->name); return FALSE; } if (rec->version > 0xff) { *err = g_strdup_printf("We currently only support 8 bit Version (Service-ID: %i Method-ID: %i Version: %d Name: %s)", rec->service_id, rec->method_id, rec->version, rec->name); return FALSE; } if (rec->message_type > 0xff) { *err = g_strdup_printf("We currently only support 8 bit Message Type (Service-ID: %i Method-ID: %i Version: %d Message Type: %x Name: %s)", rec->service_id, rec->method_id, rec->version, rec->message_type, rec->name); return FALSE; } if (rec->name == NULL || rec->name[0] == 0) { *err = g_strdup_printf("Name cannot be empty"); return FALSE; } if (rec->pos >= rec->num_of_params) { *err = g_strdup_printf("Position >= Number of Parameters"); return FALSE; } return TRUE; } static void free_someip_parameter_list_cb(void*r) { someip_parameter_list_uat_t* rec = (someip_parameter_list_uat_t*)r; if (rec->name) g_free(rec->name); } static void post_update_someip_parameter_list_read_in_data(someip_parameter_list_uat_t *data, guint data_num, GHashTable *ht) { guint i = 0; gint64 *key = NULL; someip_parameter_list_t *list = NULL; someip_payload_parameter_item_t *item = NULL; someip_payload_parameter_item_t *items = NULL; if (ht == NULL || data == NULL || data_num == 0) { return; } for (i = 0; i < data_num; i++) { /* the hash table does not know about uint64, so we use int64*/ key = wmem_new(wmem_epan_scope(), gint64); *key = someip_parameter_key((guint16)data[i].service_id, (guint16)data[i].method_id, (guint8)data[i].version, (guint8)data[i].message_type); list = (someip_parameter_list_t *)g_hash_table_lookup(ht, key); if (list == NULL) { list = wmem_new(wmem_epan_scope(), someip_parameter_list_t); list->service_id = data[i].service_id; list->method_id = data[i].method_id; list->version = data[i].version; list->message_type = data[i].message_type; list->num_of_items = data[i].num_of_params; items = (someip_payload_parameter_item_t *)wmem_alloc_array(wmem_epan_scope(), someip_payload_parameter_item_t, data[i].num_of_params); memset(items, 0, sizeof(someip_payload_parameter_item_t) * data[i].num_of_params); list->items = items; /* create new entry ... */ g_hash_table_insert(ht, key, list); } else { /* already present, deleting key */ wmem_free(wmem_epan_scope(), key); } /* and now we add to item array */ if (data[i].num_of_params == list->num_of_items && data[i].pos < list->num_of_items) { item = &(list->items[data[i].pos]); /* we do not care if we overwrite param */ item->name = data[i].name; item->id_ref = data[i].id_ref; item->pos = data[i].pos; item->data_type = data[i].data_type; } } } static void post_update_someip_parameter_list_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_parameter_list) { g_hash_table_destroy(data_someip_parameter_list); data_someip_parameter_list = NULL; } data_someip_parameter_list = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, &someip_payload_free_generic_data); post_update_someip_parameter_list_read_in_data(someip_parameter_list, someip_parameter_list_num, data_someip_parameter_list); } UAT_HEX_CB_DEF(someip_parameter_enums, id, someip_parameter_enum_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_enums, name, someip_parameter_enum_uat_t) UAT_DEC_CB_DEF(someip_parameter_enums, data_type, someip_parameter_enum_uat_t) UAT_HEX_CB_DEF(someip_parameter_enums, id_ref, someip_parameter_enum_uat_t) UAT_DEC_CB_DEF(someip_parameter_enums, num_of_items, someip_parameter_enum_uat_t) UAT_HEX_CB_DEF(someip_parameter_enums, value, someip_parameter_enum_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_enums, value_name, someip_parameter_enum_uat_t) static void * copy_someip_parameter_enum_cb(void* n, const void* o, size_t size _U_) { someip_parameter_enum_uat_t *new_rec = (someip_parameter_enum_uat_t*)n; const someip_parameter_enum_uat_t *old_rec = (const someip_parameter_enum_uat_t*)o; new_rec->id = old_rec->id; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } new_rec->data_type = old_rec->data_type; new_rec->id_ref = old_rec->id_ref; new_rec->num_of_items = old_rec->num_of_items; new_rec->value = old_rec->value; if (old_rec->value_name) { new_rec->value_name = g_strdup(old_rec->value_name); } else { new_rec->value_name = NULL; } return new_rec; } static gboolean update_someip_parameter_enum(void *r, char **err) { someip_parameter_enum_uat_t *rec = (someip_parameter_enum_uat_t *)r; if (rec->name == NULL || rec->name[0] == 0) { *err = g_strdup_printf("Name cannot be empty"); return FALSE; } if (rec->value_name == NULL || rec->value_name[0] == 0) { *err = g_strdup_printf("Value Name cannot be empty"); return FALSE; } if (rec->num_of_items == 0) { *err = g_strdup_printf("Number_of_Items = 0"); return FALSE; } return TRUE; } static void free_someip_parameter_enum_cb(void*r) { someip_parameter_enum_uat_t* rec = (someip_parameter_enum_uat_t*)r; if (rec->name) g_free(rec->name); if (rec->value_name) g_free(rec->value_name); } static void post_update_someip_parameter_enum_read_in_data(someip_parameter_enum_uat_t *data, guint data_num, GHashTable *ht) { guint i = 0; guint j = 0; gint64 *key = NULL; someip_payload_parameter_enum_t *list = NULL; someip_payload_parameter_enum_item_t *item = NULL; if (ht == NULL || data == NULL || data_num == 0) { return; } for (i = 0; i < data_num; i++) { key = wmem_new(wmem_epan_scope(), gint64); *key = data[i].id; list = (someip_payload_parameter_enum_t *)g_hash_table_lookup(ht, key); if (list == NULL) { list = wmem_new(wmem_epan_scope(), someip_payload_parameter_enum_t); INIT_SOMEIP_PAYLOAD_PARAMETER_ENUM(list) list->id = data[i].id; list->name = data[i].name; list->data_type = data[i].data_type; list->id_ref = data[i].id_ref; list->num_of_items = data[i].num_of_items; list->items = (someip_payload_parameter_enum_item_t *)wmem_alloc_array(wmem_epan_scope(), someip_payload_parameter_enum_item_t, list->num_of_items); memset(list->items, 0, sizeof(someip_payload_parameter_enum_item_t) * list->num_of_items); /* create new entry ... */ g_hash_table_insert(ht, key, list); } else { /* dont need it anymore */ wmem_free(wmem_epan_scope(), key); } /* and now we add to item array */ if (list->num_of_items > 0 && data[i].num_of_items == list->num_of_items) { /* find first empty slot */ for (j = 0; j < list->num_of_items && list->items[j].name != NULL; j++); if (j < list->num_of_items) { item = &(list->items[j]); INIT_SOMEIP_PAYLOAD_PARAMETER_ENUM_ITEM(item) /* we do not care if we overwrite param */ item->value = data[i].value; item->name = data[i].value_name; } } } } static void post_update_someip_parameter_enum_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_parameter_enums) { g_hash_table_destroy(data_someip_parameter_enums); data_someip_parameter_enums = NULL; } data_someip_parameter_enums = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, &someip_payload_free_generic_data); post_update_someip_parameter_enum_read_in_data(someip_parameter_enums, someip_parameter_enums_num, data_someip_parameter_enums); } UAT_HEX_CB_DEF(someip_parameter_arrays, id, someip_parameter_array_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_arrays, name, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, data_type, someip_parameter_array_uat_t) UAT_HEX_CB_DEF(someip_parameter_arrays, id_ref, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, num_of_dims, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, num, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, lower_limit, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, upper_limit, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, length_of_length, someip_parameter_array_uat_t) UAT_DEC_CB_DEF(someip_parameter_arrays, pad_to, someip_parameter_array_uat_t) static void * copy_someip_parameter_array_cb(void* n, const void* o, size_t size _U_) { someip_parameter_array_uat_t* new_rec = (someip_parameter_array_uat_t*)n; const someip_parameter_array_uat_t* old_rec = (const someip_parameter_array_uat_t*)o; new_rec->id = old_rec->id; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } new_rec->data_type = old_rec->data_type; new_rec->id_ref = old_rec->id_ref; new_rec->num_of_dims = old_rec->num_of_dims; new_rec->num = old_rec->num; new_rec->lower_limit = old_rec->lower_limit; new_rec->upper_limit = old_rec->upper_limit; new_rec->length_of_length = old_rec->length_of_length; new_rec->pad_to = old_rec->pad_to; return new_rec; } static gboolean update_someip_parameter_array(void *r, char **err) { someip_parameter_array_uat_t *rec = (someip_parameter_array_uat_t *)r; if (rec->name == NULL || rec->name[0] == 0) { *err = g_strdup_printf("Name cannot be empty"); return FALSE; } if (rec->num >= rec->num_of_dims) { *err = g_strdup_printf("Dimension >= Number of Dimensions"); return FALSE; } return TRUE; } static void free_someip_parameter_array_cb(void*r) { someip_parameter_array_uat_t* rec = (someip_parameter_array_uat_t*)r; if (rec->name) g_free(rec->name); } static void post_update_someip_parameter_array_read_in_data(someip_parameter_array_uat_t *data, guint data_num, GHashTable *ht) { guint i = 0; gint64 *key = NULL; someip_parameter_array_t *list = NULL; someip_parameter_array_dim_t *item = NULL; someip_parameter_array_dim_t *items = NULL; if (ht == NULL || data == NULL || data_num == 0) { return; } for (i = 0; i < data_num; i++) { key = wmem_new(wmem_epan_scope(), gint64); *key = data[i].id; list = (someip_parameter_array_t *)g_hash_table_lookup(ht, key); if (list == NULL) { list = wmem_new(wmem_epan_scope(), someip_parameter_array_t); list->id = data[i].id; list->name = data[i].name; list->data_type = data[i].data_type; list->id_ref = data[i].id_ref; list->num_of_dims = data[i].num_of_dims; items = (someip_parameter_array_dim_t *)wmem_alloc_array(wmem_epan_scope(), someip_parameter_array_dim_t, data[i].num_of_dims); memset(items, 0, sizeof(someip_parameter_array_dim_t) * data[i].num_of_dims); list->dims = items; /* create new entry ... */ g_hash_table_insert(ht, key, list); } /* and now we add to item array */ if (data[i].num_of_dims == list->num_of_dims && data[i].num < list->num_of_dims) { item = &(list->dims[data[i].num]); /* we do not care if we overwrite param */ item->num = data[i].num; item->lower_limit = data[i].lower_limit; item->upper_limit = data[i].upper_limit; item->length_of_length = data[i].length_of_length; item->pad_to = data[i].pad_to; } } } static void post_update_someip_parameter_array_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_parameter_arrays) { g_hash_table_destroy(data_someip_parameter_arrays); data_someip_parameter_arrays = NULL; } data_someip_parameter_arrays = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, &someip_payload_free_generic_data); post_update_someip_parameter_array_read_in_data(someip_parameter_arrays, someip_parameter_arrays_num, data_someip_parameter_arrays); } UAT_HEX_CB_DEF(someip_parameter_structs, id, someip_parameter_struct_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_structs, struct_name, someip_parameter_struct_uat_t) UAT_DEC_CB_DEF(someip_parameter_structs, length_of_length, someip_parameter_struct_uat_t) UAT_DEC_CB_DEF(someip_parameter_structs, pad_to, someip_parameter_struct_uat_t) UAT_DEC_CB_DEF(someip_parameter_structs, num_of_items, someip_parameter_struct_uat_t) UAT_DEC_CB_DEF(someip_parameter_structs, pos, someip_parameter_struct_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_structs, name, someip_parameter_struct_uat_t) UAT_DEC_CB_DEF(someip_parameter_structs, data_type, someip_parameter_struct_uat_t) UAT_HEX_CB_DEF(someip_parameter_structs, id_ref, someip_parameter_struct_uat_t) static void * copy_someip_parameter_struct_cb(void* n, const void* o, size_t size _U_) { someip_parameter_struct_uat_t *new_rec = (someip_parameter_struct_uat_t*)n; const someip_parameter_struct_uat_t *old_rec = (const someip_parameter_struct_uat_t*)o; new_rec->id = old_rec->id; if (old_rec->struct_name) { new_rec->struct_name = g_strdup(old_rec->struct_name); } else { new_rec->struct_name = NULL; } new_rec->length_of_length = old_rec->length_of_length; new_rec->pad_to = old_rec->pad_to; new_rec->num_of_items = old_rec->num_of_items; new_rec->pos = old_rec->pos; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } new_rec->data_type = old_rec->data_type; new_rec->id_ref = old_rec->id_ref; return new_rec; } static gboolean update_someip_parameter_struct(void *r, char **err) { someip_parameter_struct_uat_t *rec = (someip_parameter_struct_uat_t *)r; if (rec->struct_name == NULL || rec->struct_name[0] == 0) { *err = g_strdup_printf("Struct name cannot be empty"); return FALSE; } if (rec->name == NULL || rec->name[0] == 0) { *err = g_strdup_printf("Name cannot be empty"); return FALSE; } if (rec->pos >= rec->num_of_items) { *err = g_strdup_printf("Position >= Number of Parameters"); return FALSE; } return TRUE; } static void free_someip_parameter_struct_cb(void*r) { someip_parameter_struct_uat_t* rec = (someip_parameter_struct_uat_t*)r; if (rec->struct_name) g_free(rec->struct_name); if (rec->name) g_free(rec->name); } static void post_update_someip_parameter_struct_read_in_data(someip_parameter_struct_uat_t *data, guint data_num, GHashTable *ht) { guint i = 0; gint64 *key = NULL; someip_payload_parameter_struct_t *list = NULL; someip_payload_parameter_item_t *item = NULL; someip_payload_parameter_item_t *items = NULL; if (ht == NULL || data == NULL || data_num == 0) { return; } for (i = 0; i < data_num; i++) { key = wmem_new(wmem_epan_scope(), gint64); *key = data[i].id; list = (someip_payload_parameter_struct_t *)g_hash_table_lookup(ht, key); if (list == NULL) { list = wmem_new(wmem_epan_scope(), someip_payload_parameter_struct_t); INIT_SOMEIP_PAYLOAD_PARAMETER_STRUCT(list) list->id = data[i].id; list->struct_name = data[i].struct_name; list->length_of_length = data[i].length_of_length; list->pad_to = data[i].pad_to; list->num_of_items = data[i].num_of_items; items = (someip_payload_parameter_item_t *)wmem_alloc_array(wmem_epan_scope(), someip_payload_parameter_item_t, data[i].num_of_items); memset(items, 0, sizeof(someip_payload_parameter_item_t) * data[i].num_of_items); list->items = items; /* create new entry ... */ g_hash_table_insert(ht, key, list); } /* and now we add to item array */ if (data[i].num_of_items == list->num_of_items && data[i].pos < list->num_of_items) { item = &(list->items[data[i].pos]); INIT_SOMEIP_PAYLOAD_PARAMETER_ITEM(item) /* we do not care if we overwrite param */ item->name = data[i].name; item->id_ref = data[i].id_ref; item->pos = data[i].pos; item->data_type = data[i].data_type; } } } static void post_update_someip_parameter_struct_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_parameter_structs) { g_hash_table_destroy(data_someip_parameter_structs); data_someip_parameter_structs = NULL; } data_someip_parameter_structs = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, &someip_payload_free_generic_data); post_update_someip_parameter_struct_read_in_data(someip_parameter_structs, someip_parameter_structs_num, data_someip_parameter_structs); } UAT_HEX_CB_DEF(someip_parameter_unions, id, someip_parameter_union_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_unions, name, someip_parameter_union_uat_t) UAT_DEC_CB_DEF(someip_parameter_unions, length_of_length, someip_parameter_union_uat_t) UAT_DEC_CB_DEF(someip_parameter_unions, length_of_type, someip_parameter_union_uat_t) UAT_DEC_CB_DEF(someip_parameter_unions, pad_to, someip_parameter_union_uat_t) UAT_DEC_CB_DEF(someip_parameter_unions, num_of_items, someip_parameter_union_uat_t) UAT_DEC_CB_DEF(someip_parameter_unions, type_id, someip_parameter_union_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_unions, type_name, someip_parameter_union_uat_t) UAT_DEC_CB_DEF(someip_parameter_unions, data_type, someip_parameter_union_uat_t) UAT_HEX_CB_DEF(someip_parameter_unions, id_ref, someip_parameter_union_uat_t) static void * copy_someip_parameter_union_cb(void* n, const void* o, size_t size _U_) { someip_parameter_union_uat_t *new_rec = (someip_parameter_union_uat_t*)n; const someip_parameter_union_uat_t *old_rec = (const someip_parameter_union_uat_t*)o; new_rec->id = old_rec->id; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } new_rec->length_of_length = old_rec->length_of_length; new_rec->length_of_type = old_rec->length_of_type; new_rec->pad_to = old_rec->pad_to; new_rec->num_of_items = old_rec->num_of_items; new_rec->type_id = old_rec->type_id; if (old_rec->type_name) { new_rec->type_name = g_strdup(old_rec->type_name); } else { new_rec->type_name = NULL; } new_rec->data_type = old_rec->data_type; new_rec->id_ref = old_rec->id_ref; return new_rec; } static gboolean update_someip_parameter_union(void *r, char **err) { someip_parameter_union_uat_t *rec = (someip_parameter_union_uat_t *)r; if (rec->name == NULL || rec->name[0] == 0) { *err = g_strdup_printf("Union name cannot be empty"); return FALSE; } if (rec->type_name == NULL || rec->type_name[0] == 0) { *err = g_strdup_printf("Type Name cannot be empty"); return FALSE; } return TRUE; } static void free_someip_parameter_union_cb(void*r) { someip_parameter_union_uat_t *rec = (someip_parameter_union_uat_t*)r; if (rec->name) g_free(rec->name); if (rec->type_name) g_free(rec->type_name); } static void post_update_someip_parameter_union_read_in_data(someip_parameter_union_uat_t *data, guint data_num, GHashTable *ht) { guint i = 0; guint j = 0; gint64 *key = NULL; someip_parameter_union_t *list = NULL; someip_parameter_union_item_t *item = NULL; if (ht == NULL || data == NULL || data_num == 0) { return; } for (i = 0; i < data_num; i++) { key = wmem_new(wmem_epan_scope(), gint64); *key = data[i].id; list = (someip_parameter_union_t *)g_hash_table_lookup(ht, key); if (list == NULL) { list = wmem_new(wmem_epan_scope(), someip_parameter_union_t); list->id = data[i].id; list->name = data[i].name; list->length_of_length = data[i].length_of_length; list->length_of_type = data[i].length_of_type; list->pad_to = data[i].pad_to; list->num_of_items = data[i].num_of_items; list->items = (someip_parameter_union_item_t *)wmem_alloc_array(wmem_epan_scope(), someip_parameter_union_item_t, list->num_of_items); memset(list->items, 0, sizeof(someip_parameter_union_item_t) * list->num_of_items); /* create new entry ... */ g_hash_table_insert(ht, key, list); } else { /* dont need it anymore */ wmem_free(wmem_epan_scope(), key); } /* and now we add to item array */ if (data[i].num_of_items == list->num_of_items) { /* find first empty slot */ for (j = 0; j < list->num_of_items && list->items[j].name != NULL; j++); if (j < list->num_of_items) { item = &(list->items[j]); /* we do not care if we overwrite param */ item->id = data[i].type_id; item->name = data[i].type_name; item->data_type = data[i].data_type; item->id_ref = data[i].id_ref; } } } } static void post_update_someip_parameter_union_cb(void) { /* destroy old hash table, if it exists */ if (data_someip_parameter_unions) { g_hash_table_destroy(data_someip_parameter_unions); data_someip_parameter_unions = NULL; } data_someip_parameter_unions = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, &someip_payload_free_generic_data); post_update_someip_parameter_union_read_in_data(someip_parameter_unions, someip_parameter_unions_num, data_someip_parameter_unions); } UAT_HEX_CB_DEF(someip_parameter_base_type_list, id, someip_parameter_base_type_list_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_base_type_list, name, someip_parameter_base_type_list_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_base_type_list, data_type, someip_parameter_base_type_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_base_type_list, big_endian, someip_parameter_base_type_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_base_type_list, bitlength_base_type, someip_parameter_base_type_list_uat_t) UAT_DEC_CB_DEF(someip_parameter_base_type_list, bitlength_encoded_type, someip_parameter_base_type_list_uat_t) static void * copy_someip_parameter_base_type_list_cb(void* n, const void* o, size_t size _U_) { someip_parameter_base_type_list_uat_t *new_rec = (someip_parameter_base_type_list_uat_t*)n; const someip_parameter_base_type_list_uat_t *old_rec = (const someip_parameter_base_type_list_uat_t*)o; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } if (old_rec->data_type) { new_rec->data_type = g_strdup(old_rec->data_type); } else { new_rec->data_type = NULL; } new_rec->id = old_rec->id; new_rec->big_endian = old_rec->big_endian; new_rec->bitlength_base_type = old_rec->bitlength_base_type; new_rec->bitlength_encoded_type = old_rec->bitlength_encoded_type; return new_rec; } static gboolean update_someip_parameter_base_type_list(void *r, char **err) { someip_parameter_base_type_list_uat_t *rec = (someip_parameter_base_type_list_uat_t *)r; if (rec->id > 0xffffffff) { *err = g_strdup_printf("We currently only support 32 bit IDs (%i) Name: %s", rec->id, rec->name); return FALSE; } if (rec->big_endian != 0 && rec->big_endian != 1) { *err = g_strdup_printf("Big Endian can be only 0 or 1 but not %d (IDs: %i Name: %s)", rec->big_endian, rec->id, rec->name); return FALSE; } return TRUE; } static void free_someip_parameter_base_type_list_cb(void*r) { someip_parameter_base_type_list_uat_t* rec = (someip_parameter_base_type_list_uat_t*)r; if (rec->name) g_free(rec->name); if (rec->data_type) g_free(rec->data_type); } static void post_update_someip_parameter_base_type_list_cb(void) { guint i; gint64* key = NULL; /* destroy old hash table, if it exists */ if (data_someip_parameter_base_type_list) { g_hash_table_destroy(data_someip_parameter_base_type_list); data_someip_parameter_base_type_list = NULL; } /* we dont need to free the data as long as we don't alloc it first */ data_someip_parameter_base_type_list = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, NULL); if (data_someip_parameter_base_type_list == NULL || someip_parameter_base_type_list == NULL || someip_parameter_base_type_list_num == 0) { return; } if (someip_parameter_base_type_list_num > 0) { for (i = 0; i < someip_parameter_base_type_list_num; i++) { key = wmem_new(wmem_epan_scope(), gint64); *key = someip_parameter_base_type_list[i].id; g_hash_table_insert(data_someip_parameter_base_type_list, key, &someip_parameter_base_type_list[i]); } } } UAT_HEX_CB_DEF(someip_parameter_strings, id, someip_parameter_string_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_strings, name, someip_parameter_string_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_strings, encoding, someip_parameter_string_uat_t) UAT_DEC_CB_DEF(someip_parameter_strings, dynamic_length, someip_parameter_string_uat_t) UAT_DEC_CB_DEF(someip_parameter_strings, max_length, someip_parameter_string_uat_t) UAT_DEC_CB_DEF(someip_parameter_strings, length_of_length, someip_parameter_string_uat_t) UAT_DEC_CB_DEF(someip_parameter_strings, big_endian, someip_parameter_string_uat_t) UAT_DEC_CB_DEF(someip_parameter_strings, pad_to, someip_parameter_string_uat_t) static void * copy_someip_parameter_string_list_cb(void* n, const void* o, size_t size _U_) { someip_parameter_string_uat_t* new_rec = (someip_parameter_string_uat_t*)n; const someip_parameter_string_uat_t* old_rec = (const someip_parameter_string_uat_t*)o; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } if (old_rec->encoding) { new_rec->encoding = g_strdup(old_rec->encoding); } else { new_rec->encoding = NULL; } new_rec->id = old_rec->id; new_rec->dynamic_length = old_rec->dynamic_length; new_rec->max_length = old_rec->max_length; new_rec->length_of_length = old_rec->length_of_length; new_rec->big_endian = old_rec->big_endian; new_rec->pad_to = old_rec->pad_to; return new_rec; } static gboolean update_someip_parameter_string_list(void *r, char **err) { someip_parameter_string_uat_t *rec = (someip_parameter_string_uat_t *)r; if (rec->id > 0xffffffff) { *err = g_strdup_printf("We currently only support 32 bit IDs (%i) Name: %s", rec->id, rec->name); return FALSE; } if (rec->dynamic_length != 0 && rec->dynamic_length != 1) { *err = g_strdup_printf("Dynamic Length can be only 0 or 1 but not %d (IDs: %i Name: %s)", rec->dynamic_length, rec->id, rec->name); return FALSE; } if (rec->big_endian != 0 && rec->big_endian != 1) { *err = g_strdup_printf("Big Endian can be only 0 or 1 but not %d (IDs: %i Name: %s)", rec->big_endian, rec->id, rec->name); return FALSE; } if (rec->max_length > 0xffffffff) { *err = g_strdup_printf("We currently only support 32 bit max_length (%i) Name: %s", rec->max_length, rec->name); return FALSE; } if (rec->length_of_length != 0 && rec->length_of_length != 8 && rec->length_of_length != 16 && rec->length_of_length != 32) { *err = g_strdup_printf("length_of_length can be only 0, 8, 16, or 32 but not %d (IDs: %i Name: %s)", rec->length_of_length, rec->id, rec->name); return FALSE; } return TRUE; } static void free_someip_parameter_string_list_cb(void*r) { someip_parameter_string_uat_t* rec = (someip_parameter_string_uat_t*)r; if (rec->name) g_free(rec->name); if (rec->encoding) g_free(rec->encoding); } static void post_update_someip_parameter_string_list_cb(void) { guint i; gint64* key = NULL; /* destroy old hash table, if it exists */ if (data_someip_parameter_strings) { g_hash_table_destroy(data_someip_parameter_strings); data_someip_parameter_strings = NULL; } /* we dont need to free the data as long as we don't alloc it first */ data_someip_parameter_strings = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, NULL); if (data_someip_parameter_strings == NULL || someip_parameter_strings == NULL || someip_parameter_strings_num == 0) { return; } if (someip_parameter_strings_num > 0) { for (i = 0; i < someip_parameter_strings_num; i++) { key = wmem_new(wmem_epan_scope(), gint64); *key = someip_parameter_strings[i].id; g_hash_table_insert(data_someip_parameter_strings, key, &someip_parameter_strings[i]); } } } UAT_HEX_CB_DEF(someip_parameter_typedefs, id, someip_parameter_typedef_uat_t) UAT_CSTRING_CB_DEF(someip_parameter_typedefs, name, someip_parameter_typedef_uat_t) UAT_DEC_CB_DEF(someip_parameter_typedefs, data_type, someip_parameter_typedef_uat_t) UAT_HEX_CB_DEF(someip_parameter_typedefs, id_ref, someip_parameter_typedef_uat_t) static void * copy_someip_parameter_typedef_list_cb(void* n, const void* o, size_t size _U_) { someip_parameter_typedef_uat_t *new_rec = (someip_parameter_typedef_uat_t*)n; const someip_parameter_typedef_uat_t *old_rec = (const someip_parameter_typedef_uat_t*)o; if (old_rec->name) { new_rec->name = g_strdup(old_rec->name); } else { new_rec->name = NULL; } new_rec->id = old_rec->id; new_rec->data_type = old_rec->data_type; new_rec->id_ref = old_rec->id_ref; return new_rec; } static gboolean update_someip_parameter_typedef_list(void *r, char **err) { someip_parameter_typedef_uat_t *rec = (someip_parameter_typedef_uat_t *)r; if (rec->id > 0xffffffff) { *err = g_strdup_printf("We currently only support 32 bit IDs (%i) Name: %s", rec->id, rec->name); return FALSE; } return TRUE; } static void free_someip_parameter_typedef_list_cb(void*r) { someip_parameter_typedef_uat_t* rec = (someip_parameter_typedef_uat_t*)r; if (rec->name) g_free(rec->name); } static void post_update_someip_parameter_typedef_list_cb(void) { guint i; gint64 *key = NULL; /* destroy old hash table, if it exists */ if (data_someip_parameter_typedefs) { g_hash_table_destroy(data_someip_parameter_typedefs); data_someip_parameter_typedefs = NULL; } /* we dont need to free the data as long as we don't alloc it first */ data_someip_parameter_typedefs = g_hash_table_new_full(g_int64_hash, g_int64_equal, &someip_payload_free_key, NULL); if (data_someip_parameter_typedefs == NULL || someip_parameter_typedefs == NULL || someip_parameter_typedefs_num == 0) { return; } if (someip_parameter_typedefs_num > 0) { for (i = 0; i < someip_parameter_typedefs_num; i++) { /* key: ID [32bit] */ key = wmem_new(wmem_epan_scope(), gint64); *key = someip_parameter_typedefs[i].id; g_hash_table_insert(data_someip_parameter_typedefs, key, &someip_parameter_typedefs[i]); } } } static void expert_someip_payload_truncated(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, gint length) { proto_tree_add_expert(tree, pinfo, &ef_someip_payload_truncated, tvb, offset, length); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP Payload: Truncated payload!]"); } static void expert_someip_payload_malformed(proto_tree* tree, packet_info* pinfo, tvbuff_t* tvb, gint offset, gint length) { proto_tree_add_expert(tree, pinfo, &ef_someip_payload_malformed, tvb, offset, length); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP Payload: Malformed payload!]"); } static void expert_someip_payload_config_error(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, gint length, const char *message) { proto_tree_add_expert_format(tree, pinfo, &ef_someip_payload_config_error, tvb, offset, length, "SOME/IP Payload: %s", message); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP Payload: Config Error]"); } static void expert_someip_payload_alignment_error(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, gint length) { proto_tree_add_expert(tree, pinfo, &ef_someip_payload_alignment_error, tvb, offset, length); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP Payload: Alignment problem]"); } /******************************************* ******** SOME/IP Payload Dissector ******** *******************************************/ static int dissect_someip_payload_parameter(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset, gint offset_bits, guint8 data_type, guint32 idref, gchar *name); /* add a flexible size length field, -1 for error*/ static gint64 dissect_someip_payload_length_field(tvbuff_t* tvb, packet_info* pinfo, proto_tree *subtree, gint offset, gint length_of_length_field) { guint32 tmp = 0; switch (length_of_length_field) { case 8: proto_tree_add_item_ret_uint(subtree, hf_payload_length_field_8bit, tvb, offset, length_of_length_field / 8, ENC_NA, &tmp); break; case 16: proto_tree_add_item_ret_uint(subtree, hf_payload_length_field_16bit, tvb, offset, length_of_length_field / 8, ENC_BIG_ENDIAN, &tmp); break; case 32: proto_tree_add_item_ret_uint(subtree, hf_payload_length_field_32bit, tvb, offset, length_of_length_field / 8, ENC_BIG_ENDIAN, &tmp); break; default: proto_tree_add_expert_format(subtree, pinfo, &ef_someip_payload_config_error, tvb, offset, 0, "SOME/IP: Payload: length of length field does not make sense: %d bits", length_of_length_field); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP: Payload Config Error]"); return -1; } return (gint64)tmp; } /* add a flexible size type field */ static gint64 dissect_someip_payload_type_field(tvbuff_t* tvb, packet_info* pinfo, proto_tree *subtree, gint offset, gint length_of_type_field) { guint32 tmp = 0; switch (length_of_type_field) { case 8: proto_tree_add_item_ret_uint(subtree, hf_payload_type_field_8bit, tvb, offset, length_of_type_field / 8, ENC_NA, &tmp); break; case 16: proto_tree_add_item_ret_uint(subtree, hf_payload_type_field_16bit, tvb, offset, length_of_type_field / 8, ENC_BIG_ENDIAN, &tmp); break; case 32: proto_tree_add_item_ret_uint(subtree, hf_payload_type_field_32bit, tvb, offset, length_of_type_field / 8, ENC_BIG_ENDIAN, &tmp); break; default: proto_tree_add_expert_format(subtree, pinfo, &ef_someip_payload_config_error, tvb, offset, 0, "SOME/IP: Payload: length of type field does not make sense: %d bits", length_of_type_field); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP: Payload Config Error]"); return -1; } return (gint64)tmp; } static gint dissect_someip_payload_base_type(tvbuff_t* tvb, packet_info* pinfo _U_, proto_tree *tree, gint offset, gint offset_bits, guint8 data_type, guint32 id, gchar* name) { someip_payload_parameter_base_type_list_t *base_type = NULL; someip_payload_parameter_enum_t *enum_config = NULL; guint32 basetype_id = 0; guint32 enum_id = 0; gint buf_length = -1; gint param_length = -1; guint32 bit_length = 0; proto_item *ti = NULL; guint64 value = 0; guint8 tmp = 0; gint tmp_bit_count = 8; gboolean value_set = FALSE; gint32 i = 0; guint32 j = 0; gchar *value_name = NULL; gint offset_end = 0; gint offset_end_bits = 0; gboolean big_endian = TRUE; if (offset_bits < 0) { return 0; } switch (data_type) { case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_BASE_TYPE: basetype_id = id; break; case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_ENUM: enum_id = id; enum_config = get_enum_config(enum_id); if (enum_config == NULL) { return 0; } basetype_id = enum_config->id_ref; break; default: return 0; } base_type = get_base_type_config(basetype_id); if (base_type == NULL) { return 0; } big_endian = base_type->big_endian; buf_length = tvb_captured_length_remaining(tvb, 0); bit_length = base_type->bitlength_encoded_type; /* +7 to round up, if more than 0 bits */ param_length = (gint)((offset_bits + bit_length + 7) / 8); if (param_length <= buf_length - offset) { if (name == NULL) { ti = proto_tree_add_string_format(tree, hf_payload_str_base, tvb, offset, param_length, base_type->name, "[%s]", base_type->name); } else { ti = proto_tree_add_string_format(tree, hf_payload_str_base, tvb, offset, param_length, base_type->name, "%s [%s]", name, base_type->name); } /* Regular (non-shortened!) SOME/IP types! */ if (offset_bits == 0 && base_type->bitlength_base_type == bit_length && bit_length % 8 == 0) { if (strcmp(base_type->data_type, "uint8") == 0 && base_type->bitlength_base_type == 8) { value = tvb_get_guint8(tvb, offset); value_set = TRUE; proto_item_append_text(ti, ": %u", (guint8)value); } else if (strcmp(base_type->data_type, "uint16") == 0 && base_type->bitlength_base_type == 16) { if (big_endian) { value = tvb_get_ntohs(tvb, offset); } else { value = tvb_get_letohs(tvb, offset); } value_set = TRUE; proto_item_append_text(ti, ": %u", (guint16)value); } else if (strcmp(base_type->data_type, "uint32") == 0 && base_type->bitlength_base_type == 32) { if (big_endian) { value = tvb_get_ntohl(tvb, offset); } else { value = tvb_get_letohl(tvb, offset); } value_set = TRUE; proto_item_append_text(ti, ": %u", (guint32)value); } else if (strcmp(base_type->data_type, "uint64") == 0 && base_type->bitlength_base_type == 64) { if (big_endian) { value = tvb_get_ntoh64(tvb, offset); } else { value = tvb_get_letoh64(tvb, offset); } value_set = TRUE; proto_item_append_text(ti, ": %" G_GUINT64_FORMAT, value); } else if (strcmp(base_type->data_type, "int8") == 0 && base_type->bitlength_base_type == 8) { proto_item_append_text(ti, ": %d", (gint8)tvb_get_guint8(tvb, offset)); } else if (strcmp(base_type->data_type, "int16") == 0 && base_type->bitlength_base_type == 16) { if (big_endian) { proto_item_append_text(ti, ": %d", (gint16)tvb_get_ntohs(tvb, offset)); } else { proto_item_append_text(ti, ": %d", (gint16)tvb_get_letohs(tvb, offset)); } } else if (strcmp(base_type->data_type, "int32") == 0 && base_type->bitlength_base_type == 32) { if (big_endian) { proto_item_append_text(ti, ": %d", (gint32)tvb_get_ntohl(tvb, offset)); } else { proto_item_append_text(ti, ": %d", (gint32)tvb_get_letohl(tvb, offset)); } } else if (strcmp(base_type->data_type, "int64") == 0 && base_type->bitlength_base_type == 64) { if (big_endian) { proto_item_append_text(ti, ": %" G_GINT64_FORMAT, (gint64)tvb_get_ntoh64(tvb, offset)); } else { proto_item_append_text(ti, ": %" G_GINT64_FORMAT, (gint64)tvb_get_letoh64(tvb, offset)); } } else if (strcmp(base_type->data_type, "float32") == 0 && base_type->bitlength_base_type == 32) { if (big_endian) { proto_item_append_text(ti, ": %f", (float)tvb_get_ntohieee_float(tvb, offset)); } else { proto_item_append_text(ti, ": %f", (float)tvb_get_letohieee_float(tvb, offset)); } } else if (strcmp(base_type->data_type, "float64") == 0 && base_type->bitlength_base_type == 64) { if (big_endian) { proto_item_append_text(ti, ": %f", (double)tvb_get_ntohieee_double(tvb, offset)); } else { proto_item_append_text(ti, ": %f", (double)tvb_get_letohieee_double(tvb, offset)); } } } else { /* Shortened datatypes (e.g.CAN over SOME/IP) */ offset_end = (gint)((8 * offset + offset_bits + bit_length) / 8); offset_end_bits = (gint)((8 * offset + offset_bits + bit_length) % 8); if (!big_endian) { /* offset and offset_end need to be included */ for (i = offset_end; i >= offset; i--) { if (i != offset_end || offset_end_bits != 0) { tmp = tvb_get_guint8(tvb, i); tmp_bit_count = 8; if (i == offset_end) { tmp = tmp & (0xff >> (8 - offset_end_bits)); /* don't need to shift value, in the first round */ tmp_bit_count = 0; } if (i == offset) { tmp >>= offset_bits; tmp_bit_count = 8 - offset_bits; } value <<= (guint)tmp_bit_count; value |= tmp; } } } else { /* offset_end needs to be included. */ for (i = offset; i <= offset_end; i++) { /* Do not read the last byte, if you do not need any bit of it. Else we read behind buffer! */ if (i != offset_end || offset_end_bits != 0) { tmp = tvb_get_guint8(tvb, i); tmp_bit_count = 8; if (i == offset) { tmp = tmp & (0xff >> offset_bits); /* don't need to shift value, in the first round */ tmp_bit_count = 0; } if (i == offset_end) { tmp >>= 8 - offset_end_bits; tmp_bit_count = offset_end_bits; } value <<= (guint)tmp_bit_count; value |= tmp; } } } value_set = TRUE; proto_item_append_text(ti, ": %" G_GUINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x)", value, value); } } else { return 0; } if (enum_config != NULL && value_set == TRUE) { for (j = 0; j < enum_config->num_of_items; j++) { if (enum_config->items[j].value == value) { value_name = enum_config->items[j].name; break; } } if (value_name != NULL) { proto_item_append_text(ti, " (%s)", value_name); } } return (gint)bit_length; } static int dissect_someip_payload_string(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset, gint offset_bits, guint32 id, gchar* name) { someip_payload_parameter_string_t *config = NULL; guint8 *buf = NULL; guint32 i = 0; guint32 ret = 0; proto_item *ti = NULL; proto_tree *subtree = NULL; gint64 tmp = 0; guint32 length = 0; gint offset_orig = offset; gint offset_bits_orig = offset_bits; guint str_encoding = 0; config = get_string_config(id); if (config == NULL || offset_bits != 0) { return 0; } if (tvb_captured_length_remaining(tvb, 0) < (gint)(config->length_of_length >> 3)) { expert_someip_payload_malformed(tree, pinfo, tvb, offset, 0); return 0; }; if (config->length_of_length == 0) { length = config->max_length; } else { tmp = dissect_someip_payload_length_field(tvb, pinfo, tree, offset, config->length_of_length); if (tmp < 0) { /* error */ return config->length_of_length / 8; } length = (guint32)tmp; offset += config->length_of_length / 8; } if ((guint32)tvb_captured_length_remaining(tvb, offset) < length) { expert_someip_payload_malformed(tree, pinfo, tvb, offset, 0); return 0; } if (strcmp(config->encoding, "utf-8") == 0) { str_encoding = ENC_UTF_8; } else if (strcmp(config->encoding, "utf-16") == 0) { str_encoding = ENC_UTF_16; } else { str_encoding = ENC_ASCII; } buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, length, str_encoding); /* sanitizing buffer */ if (str_encoding == ENC_ASCII || str_encoding == ENC_UTF_8) { for (i = 0; i < length; i++) { if (buf[i] > 0x00 && buf[i] < 0x20) { buf[i] = 0x20; } } } ti = proto_tree_add_string_format(tree, hf_payload_str_string, tvb, offset_orig, length + (offset - offset_orig), buf, "%s [%s]: %s", name, config->name, buf); subtree = proto_item_add_subtree(ti, ett_someip_string); proto_tree_add_string_format(subtree, hf_payload_str_string, tvb, offset_orig, offset - offset_orig, buf, "string length: %d", length); offset += length; ret = 8 * (offset - offset_orig) + (offset_bits - offset_bits_orig); return ret; } static int dissect_someip_payload_struct(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset_orig, gint offset_bits_orig, guint32 id, gchar* name) { someip_payload_parameter_item_t* item = NULL; someip_payload_parameter_struct_t *config = NULL; proto_tree *subtree = NULL; proto_item *ti = NULL; gint64 length = 0; gint offset = offset_orig; gint offset_bits = offset_bits_orig; gint bits_parsed = 0; guint i = 0; config = get_struct_config(id); if (config == NULL || tree == NULL || tvb == NULL) { return 0; } ti = proto_tree_add_string_format(tree, hf_payload_str_struct, tvb, offset, 0, config->struct_name, "struct %s [%s]", name, config->struct_name); subtree = proto_item_add_subtree(ti, ett_someip_struct); if (tvb_captured_length_remaining(tvb, 0) < (gint)(config->length_of_length >> 3)) { expert_someip_payload_malformed(tree, pinfo, tvb, offset, 0); return 0; }; if (config->length_of_length != 0) { length = dissect_someip_payload_length_field(tvb, pinfo, subtree, offset, config->length_of_length); if (length < 0) { /* error */ return config->length_of_length / 8; } offset += config->length_of_length / 8; proto_item_set_end(ti, tvb, offset_orig + (config->length_of_length / 8) + (guint32)length); } for (i = 0; i < config->num_of_items; i++) { item = &(config->items[i]); bits_parsed = dissect_someip_payload_parameter(tvb, pinfo, subtree, offset, offset_bits, (guint8)item->data_type, item->id_ref, item->name); offset = (8 * offset + offset_bits + bits_parsed) / 8; offset_bits = (8 * offset + offset_bits + bits_parsed) % 8; } if (config->length_of_length == 0) { if (offset_bits == 0) { proto_item_set_end(ti, tvb, offset); } else { proto_item_set_end(ti, tvb, offset + 1); } return 8 * (offset - offset_orig) + (offset_bits - offset_bits_orig); } else { return 8 * ((config->length_of_length / 8) + (guint32)length); } } static int dissect_someip_payload_typedef(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset, gint offset_bits, guint32 id, gchar* name _U_) { gint bits_parsed = 0; someip_payload_parameter_typedef_t *config = NULL; config = get_typedef_config(id); if (config == NULL) { return 0; } /* we basically skip over the typedef for now */ bits_parsed = dissect_someip_payload_parameter(tvb, pinfo, tree, offset, offset_bits, (guint8)config->data_type, config->id_ref, config->name); return bits_parsed; } /* returns bytes parsed, length needs to be gint to encode "non-existing" as -1 */ static int dissect_someip_payload_array_dim_length(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset_orig, gint *length, gint *lower_limit, gint *upper_limit, someip_parameter_array_t *config, gint current_dim) { gint offset = offset_orig; gint64 tmp = 0; *lower_limit = config->dims[current_dim].lower_limit; *upper_limit = config->dims[current_dim].upper_limit; /* length needs to be -1, if we do not have a dynamic length array */ *length = -1; if (config->dims[current_dim].length_of_length > 0) { /* we are filling the length with number of bytes we found in the packet */ tmp = dissect_someip_payload_length_field(tvb, pinfo, tree, offset, config->dims[current_dim].length_of_length); if (tmp < 0) { /* leave *length = -1 */ return config->dims[current_dim].length_of_length/8; } *length = (gint32)tmp; offset += config->dims[current_dim].length_of_length/8; } else { /* without a length field, the number of elements needs be fixed */ if (config->dims[current_dim].lower_limit != config->dims[current_dim].upper_limit) { proto_tree_add_expert_format(tree, pinfo, &ef_someip_payload_static_array_min_not_max, tvb, offset_orig, 0, "Static array config with Min!=Max (%d, %d)", config->dims[current_dim].lower_limit, config->dims[current_dim].upper_limit); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP Payload: Static array config with Min!=Max!]"); return 0; } } return offset - offset_orig; } /* returns bits parsed, length needs to be gint to encode "non-existing" as -1 */ static gint dissect_someip_payload_array_payload(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset_orig, gint length, gint lower_limit, gint upper_limit, someip_parameter_array_t *config) { tvbuff_t *subtvb = NULL; guint32 offset = offset_orig; guint32 offset_bits = 0; guint32 bits_parsed = 0; guint32 ret = 0; gint count = 0; if (length != -1) { if (length <= tvb_captured_length_remaining(tvb, offset)) { subtvb = tvb_new_subset_length_caplen(tvb, offset, length, length); } else { expert_someip_payload_truncated(tree, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset)); return tvb_captured_length_remaining(tvb, offset); } } else { subtvb = tvb; } /* created subtvb. so we set offset=0 */ offset = 0; while ((length == -1 && count < upper_limit) || ((gint)(8 * offset + offset_bits) < 8 * length)) { bits_parsed = dissect_someip_payload_parameter(subtvb, pinfo, tree, offset, offset_bits, (guint8)config->data_type, config->id_ref, config->name); if (bits_parsed == 0) { return 1; } offset = (8 * offset + bits_parsed) / 8; offset_bits = (8 * offset + bits_parsed) % 8; count++; } if (countupper_limit) { proto_tree_add_expert_format(tree, pinfo, &ef_someip_payload_dyn_array_not_within_limit, tvb, offset_orig, length, "Number of items (%d) outside limit %d-%d", count, lower_limit, upper_limit); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP Payload: Dynamic array does not stay between Min and Max values]"); } ret = 8 * offset + offset_bits; return ret; } /* returns bits parsed */ static gint dissect_someip_payload_array_dim(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset_orig, gint length, gint lower_limit, gint upper_limit, someip_parameter_array_t *config, guint current_dim, gchar* name) { proto_tree *subtree = NULL; gint sub_length = 0; gint sub_lower_limit = 0; gint sub_upper_limit = 0; gint i = 0; gint sub_offset = 0; gint offset = offset_orig; gint offset_bits = 0; gint ret = 0; gint len_of_len = 0; if (config->num_of_dims == current_dim + 1) { /* only payload left. :) */ offset_bits += dissect_someip_payload_array_payload(tvb, pinfo, tree, offset, length, lower_limit, upper_limit, config); } else { if (length != -1) { while (offset < offset_orig + (gint)length) { sub_offset = offset; offset += dissect_someip_payload_array_dim_length(tvb, pinfo, tree, offset, &sub_length, &sub_lower_limit, &sub_upper_limit, config, current_dim + 1); len_of_len = offset - sub_offset; if (tvb_captured_length_remaining(tvb, offset) < (gint)sub_length) { expert_someip_payload_truncated(tree, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset)); return 0; } subtree = proto_tree_add_subtree_format(tree, tvb, sub_offset, sub_length + len_of_len, ett_someip_array_dim, NULL, "subarray (dim: %d, limit %d-%d)", current_dim + 1, sub_lower_limit, sub_upper_limit); offset_bits += dissect_someip_payload_array_dim(tvb, pinfo, subtree, offset, sub_length, sub_lower_limit, sub_upper_limit, config, current_dim + 1, name); offset = (8 * offset + offset_bits) / 8; offset_bits = (8 * offset + offset_bits) % 8; } } else { /* Multi-dim static array */ sub_lower_limit = config->dims[current_dim].lower_limit; sub_upper_limit = config->dims[current_dim].upper_limit; for (i = 0; i < upper_limit; i++) { offset += dissect_someip_payload_array_dim(tvb, pinfo, tree, offset, -1, sub_lower_limit, sub_upper_limit, config, current_dim + 1, name); } } } ret = 8 * (offset - offset_orig) + (offset_bits - 0); return ret; } static int dissect_someip_payload_array(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset_orig, gint offset_bits_orig, guint32 id, gchar* name) { someip_parameter_array_t *config = NULL; proto_tree *subtree; gint offset = offset_orig; gint offset_bits = offset_bits_orig; gint length = 0; gint lower_limit = 0; gint upper_limit = 0; config = get_array_config(id); if (config == NULL) { return 0; } if (config->num_of_dims == 0 || config->dims == NULL) { expert_someip_payload_config_error(tree, pinfo, tvb, offset, 0, "Array config has not enough dimensions for this array!"); return 0; } if (offset_bits_orig != 0) { expert_someip_payload_alignment_error(tree, pinfo, tvb, offset, 0); return 0; } offset += dissect_someip_payload_array_dim_length(tvb, pinfo, tree, offset_orig, &length, &lower_limit, &upper_limit, config, 0); if (length != -1) { subtree = proto_tree_add_subtree_format(tree, tvb, offset_orig, length + (offset - offset_orig), ett_someip_array, NULL, "array %s (elements limit: %d-%d)", name, lower_limit, upper_limit); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset_orig, length + (offset - offset_orig), ett_someip_array, NULL, "array %s (elements limit: %d)", name, upper_limit); } offset_bits += dissect_someip_payload_array_dim(tvb, pinfo, subtree, offset, length, lower_limit, upper_limit, config, 0, name); return 8 * (length + (offset - offset_orig)) + (offset_bits - offset_bits_orig); } static int dissect_someip_payload_union(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset_orig, gint offset_bits_orig, guint32 id, gchar* name) { someip_parameter_union_t *config = NULL; someip_parameter_union_item_t *item = NULL; proto_tree *subtree = NULL; tvbuff_t *subtvb; gint buf_length = -1; gint64 tmp = 0; guint32 length = 0; guint32 type = 0; guint32 i = 0; gint offset = offset_orig; gint offset_bits = offset_bits_orig; config = get_union_config(id); buf_length = tvb_captured_length_remaining(tvb, 0); if (config == NULL) { expert_someip_payload_config_error(tree, pinfo, tvb, offset, 0, "Union ID not configured"); return 0; } if (offset_bits_orig != 0) { expert_someip_payload_alignment_error(tree, pinfo, tvb, offset_orig, 0); return 0; } if ((config->length_of_length + config->length_of_type) / 8 > (guint)buf_length - offset) { expert_someip_payload_truncated(tree, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset)); return 0; } subtree = proto_tree_add_subtree_format(tree, tvb, offset_orig, offset - offset_orig + length, ett_someip_union, NULL, "union %s [%s]", name, config->name); tmp = dissect_someip_payload_length_field(tvb, pinfo, subtree, offset_orig, config->length_of_length); if (tmp == -1) { return 8 * (offset - offset_orig) + (offset_bits - 0); } else { length = (guint32)tmp; } tmp = dissect_someip_payload_type_field(tvb, pinfo, subtree, offset_orig + config->length_of_length / 8, config->length_of_type); if (tmp == -1) { return 8 * (offset - offset_orig) + (offset_bits - 0); } else { type = (guint32)tmp; } offset += (config->length_of_length + config->length_of_type) / 8; item = NULL; for (i = 0; i < config->num_of_items; i++) { if (config->items[i].id == type && config->items[i].name != NULL) { item = &(config->items[i]); } } if (item != NULL) { subtvb = tvb_new_subset_length_caplen(tvb, offset, length, length); dissect_someip_payload_parameter(subtvb, pinfo, subtree, 0, 0, (guint8)item->data_type, item->id_ref, item->name); } else { expert_someip_payload_config_error(tree, pinfo, tvb, offset, 0, "Union type not configured"); } /* there might be some padding present, if 8*length != bits_parsed */ return 8 * length + config->length_of_type + config->length_of_length; } static int dissect_someip_payload_parameter(tvbuff_t* tvb, packet_info* pinfo, proto_tree *tree, gint offset, gint offset_bits, guint8 data_type, guint32 idref, gchar *name) { gint bits_parsed = 0; switch (data_type) { case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_TYPEDEF: bits_parsed = dissect_someip_payload_typedef(tvb, pinfo, tree, offset, offset_bits, idref, name); break; case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_BASE_TYPE: case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_ENUM: bits_parsed = dissect_someip_payload_base_type(tvb, pinfo, tree, offset, offset_bits, data_type, idref, name); break; case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_STRING: bits_parsed = dissect_someip_payload_string(tvb, pinfo, tree, offset, offset_bits, idref, name); break; case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_ARRAY: bits_parsed = dissect_someip_payload_array(tvb, pinfo, tree, offset, offset_bits, idref, name); break; case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_STRUCT: bits_parsed = dissect_someip_payload_struct(tvb, pinfo, tree, offset, offset_bits, idref, name); break; case SOMEIP_PAYLOAD_PARAMETER_DATA_TYPE_UNION: bits_parsed = dissect_someip_payload_union(tvb, pinfo, tree, offset, offset_bits, idref, name); break; default: proto_tree_add_expert_format(tree, pinfo, &ef_someip_payload_config_error, tvb, offset, 0, "SOME/IP: Payload: item->data_type (0x%x) unknown/not implemented yet! name: %s, id_ref: 0x%x", data_type, name, idref); col_append_str(pinfo->cinfo, COL_INFO, " [SOME/IP: Payload Config Error]"); break; } return bits_parsed; } static void dissect_someip_payload(tvbuff_t* tvb, packet_info* pinfo, proto_item *ti, guint16 serviceid, guint16 methodid, guint8 version, guint8 msgtype) { someip_parameter_list_t* paramlist = NULL; someip_payload_parameter_item_t* item = NULL; gint length = -1; gint offset = 0; gint offset_bits = 0; gint bits_parsed = 0; proto_tree *tree = NULL; guint i = 0; length = tvb_captured_length_remaining(tvb, 0); tree = proto_item_add_subtree(ti, ett_someip_payload); paramlist = get_parameter_config(serviceid, methodid, version, msgtype); if (paramlist == NULL) { return; } for (i = 0; i < paramlist->num_of_items; i++) { item = &(paramlist->items[i]); bits_parsed = dissect_someip_payload_parameter(tvb, pinfo, tree, offset, offset_bits, (guint8)item->data_type, item->id_ref, item->name); offset = (8 * offset + offset_bits + bits_parsed) / 8; offset_bits = (8 * offset + offset_bits + bits_parsed) % 8; } if (length > offset + 1) { proto_tree_add_item(tree, hf_payload_unparsed, tvb, offset + 1, length - (offset + 1), ENC_NA); } } /*********************************** ******** SOME/IP Dissector ******** ***********************************/ static int dissect_someip_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { guint32 offset = 0; guint32 someip_messageid = 0; guint32 someip_serviceid = 0; guint32 someip_methodid = 0; guint32 someip_sessionid = 0; guint32 someip_length = 0; const gchar *service_description = NULL; const gchar *method_description = NULL; guint32 someip_payload_length = 0; tvbuff_t *subtvb = NULL; proto_item *ti = NULL; proto_item *ti_someip = NULL; proto_tree *someip_tree = NULL; proto_tree *msgtype_tree = NULL; guint32 protocol_version = 0; guint32 version = 0; guint32 msgtype = 0; gboolean msgtype_ack = FALSE; gboolean msgtype_tp = FALSE; guint32 retcode = 0; int tmp = 0; gint tvb_length = tvb_captured_length_remaining(tvb, offset); static int * const someip_tp_flags[] = { &hf_someip_tp_reserved, &hf_someip_tp_more_segments, NULL }; col_set_str(pinfo->cinfo, COL_PROTOCOL, SOMEIP_NAME); col_set_str(pinfo->cinfo, COL_INFO, SOMEIP_NAME_LONG); ti_someip = proto_tree_add_item(tree, proto_someip, tvb, offset, -1, ENC_NA); someip_tree = proto_item_add_subtree(ti_someip, ett_someip); /* we should never get called with less than 8 bytes */ if (tvb_length < 8) { return tvb_length; } /* Message ID = Service ID + Method ID*/ someip_messageid = tvb_get_ntohl(tvb, 0); ti = proto_tree_add_uint_format_value(someip_tree, hf_someip_messageid, tvb, offset, 4, someip_messageid, "0x%08x", someip_messageid); PROTO_ITEM_SET_HIDDEN(ti); /* Service ID */ ti = proto_tree_add_item_ret_uint(someip_tree, hf_someip_serviceid, tvb, offset, 2, ENC_BIG_ENDIAN, &someip_serviceid); service_description = someip_lookup_service_name(someip_serviceid); if (service_description != NULL) { proto_item_append_text(ti, " (%s)", service_description); } offset += 2; /* Method ID */ ti = proto_tree_add_item_ret_uint(someip_tree, hf_someip_methodid, tvb, offset, 2, ENC_BIG_ENDIAN, &someip_methodid); method_description = someip_lookup_method_name(someip_serviceid, someip_methodid); if (method_description != NULL) { proto_item_append_text(ti, " (%s)", method_description); } offset += 2; /* Length */ proto_tree_add_item_ret_uint(someip_tree, hf_someip_length, tvb, offset, 4, ENC_BIG_ENDIAN, &someip_length); offset += 4; /* this checks if value of the header field */ if (someip_length < 8) { expert_add_info_format(pinfo, ti_someip, &ef_someip_incomplete_headers, "%s", "SOME/IP length too short (<8 Bytes)!"); return tvb_length; } /* Add some additional info to the Protocol line and the Info Column*/ if (service_description == NULL) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s (Service ID: 0x%04x, Method ID: 0x%04x, Length: %i)", SOMEIP_NAME_LONG, someip_serviceid, someip_methodid, someip_length); } else if (method_description == NULL) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s (Service ID: 0x%04x (%s), Method ID: 0x%04x, Length: %i)", SOMEIP_NAME_LONG, someip_serviceid, service_description, someip_methodid, someip_length); } else { col_add_fstr(pinfo->cinfo, COL_INFO, "%s (Service ID: 0x%04x (%s), Method ID: 0x%04x (%s), Length: %i)", SOMEIP_NAME_LONG, someip_serviceid, service_description, someip_methodid, method_description, someip_length); } proto_item_append_text(ti_someip, " (Service ID: 0x%04x, Method ID: 0x%04x, Length: %i)", someip_serviceid, someip_methodid, someip_length); /* check if we have bytes for the rest of the header */ if (tvb_length < 0 || offset + 8 > (guint32)tvb_length) { expert_add_info_format(pinfo, ti_someip, &ef_someip_incomplete_headers, "%s", "SOME/IP not enough buffer bytes for header!"); return tvb_length; } /* Client ID */ proto_tree_add_item(someip_tree, hf_someip_clientid, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Session ID */ proto_tree_add_item_ret_uint(someip_tree, hf_someip_sessionid, tvb, offset, 2, ENC_BIG_ENDIAN, &someip_sessionid); offset += 2; /* Protocol Version*/ ti = proto_tree_add_item_ret_uint(someip_tree, hf_someip_protover, tvb, offset, 1, ENC_BIG_ENDIAN, &protocol_version); if (protocol_version!=SOMEIP_PROTOCOL_VERSION) { expert_add_info(pinfo, ti, &ef_someip_unknown_version); } offset += 1; /* Major Version of Service Interface */ proto_tree_add_item_ret_uint(someip_tree, hf_someip_interface_ver, tvb, offset, 1, ENC_BIG_ENDIAN, &version); offset += 1; /* Message Type */ ti = proto_tree_add_item_ret_uint(someip_tree, hf_someip_messagetype, tvb, offset, 1, ENC_BIG_ENDIAN, &msgtype); msgtype_tree = proto_item_add_subtree(ti, ett_someip_msgtype); proto_tree_add_item_ret_boolean(msgtype_tree, hf_someip_messagetype_ack_flag, tvb, offset, 1, ENC_BIG_ENDIAN, &msgtype_ack); proto_tree_add_item_ret_boolean(msgtype_tree, hf_someip_messagetype_tp_flag, tvb, offset, 1, ENC_BIG_ENDIAN, &msgtype_tp); proto_item_append_text(ti, " (%s)", val_to_str((~SOMEIP_MSGTYPE_TP_MASK)&msgtype, someip_msg_type, "Unknown Message Type")); if (msgtype_tp) { proto_item_append_text(ti, " (%s)", SOMEIP_MSGTYPE_TP_STRING); } offset += 1; /* Return Code */ ti = proto_tree_add_item_ret_uint(someip_tree, hf_someip_returncode, tvb, offset, 1, ENC_BIG_ENDIAN, &retcode); proto_item_append_text(ti, " (%s)", val_to_str(retcode, someip_return_code, "Unknown Return Code")); offset += 1; /* lets figure out what we have for the rest */ if (((guint32)tvb_length >= (someip_length + 8)) ) { someip_payload_length = someip_length - SOMEIP_HDR_PART1_LEN; } else { someip_payload_length = tvb_length - SOMEIP_HDR_LEN; expert_add_info(pinfo, ti_someip, &ef_someip_message_truncated); } /* Is this a SOME/IP-TP segment? */ if (msgtype_tp) { guint32 tp_offset = 0; gboolean tp_more_segments = FALSE; gboolean update_col_info = TRUE; guint32 segment_key; fragment_item *someip_tp_head = NULL; proto_tree *tp_tree = NULL; ti = proto_tree_add_item(someip_tree, hf_someip_tp, tvb, offset, someip_payload_length, ENC_NA); tp_tree = proto_item_add_subtree(ti, ett_someip_tp); tp_offset = (tvb_get_ntohl(tvb, offset) & SOMEIP_TP_OFFSET_MASK); tp_more_segments = ((tvb_get_ntohl(tvb, offset) & SOMEIP_TP_OFFSET_MASK_MORE_SEGMENTS) != 0); /* Why can I not mask an FT_UINT32 without it being shifted. :( . */ proto_tree_add_uint(tp_tree, hf_someip_tp_offset, tvb, offset, 4, tp_offset); proto_tree_add_bitmask_with_flags(tp_tree, tvb, offset+3, hf_someip_tp_flags, ett_someip_tp_flags, someip_tp_flags, ENC_BIG_ENDIAN, BMT_NO_TFS | BMT_NO_INT); offset += 4; proto_tree_add_item(tp_tree, hf_someip_payload, tvb, offset, someip_payload_length - SOMEIP_TP_HDR_LEN, ENC_NA); if (someip_tp_reassemble && tvb_bytes_exist(tvb, offset, someip_payload_length - SOMEIP_TP_HDR_LEN)) { segment_key = someip_messageid ^ (version << 24) ^ (msgtype << 16) ^ someip_sessionid; someip_tp_head = fragment_add_check(&someip_tp_reassembly_table, tvb, offset, pinfo, segment_key, NULL, tp_offset, someip_payload_length - SOMEIP_TP_HDR_LEN, tp_more_segments); subtvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled SOME/IP-TP Segment", someip_tp_head, &someip_tp_frag_items, &update_col_info, someip_tree); } } else { subtvb = tvb_new_subset_length_caplen(tvb, SOMEIP_HDR_LEN, someip_payload_length, someip_payload_length); } if (subtvb!=NULL) { tvb_length = tvb_captured_length_remaining(subtvb, 0); if (tvb_length > 0) { tmp = dissector_try_uint(someip_dissector_table, someip_messageid, subtvb, pinfo, tree); /* if no subdissector was found, the generic payload dissector takes over. */ if (tmp==0) { ti = proto_tree_add_item(someip_tree, hf_someip_payload, subtvb, 0, tvb_length, ENC_NA); if (someip_derserializer_activated) { dissect_someip_payload(subtvb, pinfo, ti, (guint16)someip_serviceid, (guint16)someip_methodid, (guint8)version, (guint8)(~SOMEIP_MSGTYPE_TP_MASK)&msgtype); } } } } return SOMEIP_HDR_LEN + someip_payload_length; } static guint get_someip_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void* data _U_) { return SOMEIP_HDR_PART1_LEN + (guint)tvb_get_ntohl(tvb, offset + 4); } static int dissect_someip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { tcp_dissect_pdus(tvb, pinfo, tree, TRUE, SOMEIP_HDR_PART1_LEN, get_someip_message_len, dissect_someip_message, data); return tvb_reported_length(tvb); } static int dissect_someip_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { return udp_dissect_pdus(tvb, pinfo, tree, SOMEIP_HDR_PART1_LEN, NULL, get_someip_message_len, dissect_someip_message, data); } static gboolean test_someip(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_) { if (tvb_captured_length(tvb) < SOMEIP_HDR_LEN) { return FALSE; } if (tvb_get_guint32(tvb, 4, ENC_BIG_ENDIAN) < 8) { return FALSE; } if ((tvb_get_guint8(tvb, 12)) != SOMEIP_PROTOCOL_VERSION) { return FALSE; } if (!try_val_to_str((tvb_get_guint8(tvb, 14) & ~SOMEIP_MSGTYPE_TP_MASK), someip_msg_type)) { return FALSE; } return TRUE; } static gboolean dissect_some_ip_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { if (test_someip(pinfo, tvb, 0, data)) { tcp_dissect_pdus(tvb, pinfo, tree, TRUE, SOMEIP_HDR_PART1_LEN, get_someip_message_len, dissect_someip_message, data); return TRUE; } return FALSE; } static gboolean dissect_some_ip_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { udp_dissect_pdus(tvb, pinfo, tree, SOMEIP_HDR_PART1_LEN, test_someip, get_someip_message_len, dissect_someip_message, data); return TRUE; } void proto_register_someip(void) { module_t *someip_module; expert_module_t *expert_module_someip; uat_t* someip_service_uat; uat_t* someip_method_uat; uat_t* someip_eventgroup_uat; uat_t *someip_parameter_base_type_list_uat; uat_t *someip_parameter_strings_uat; uat_t *someip_parameter_typedefs_uat; uat_t *someip_parameter_list_uat; uat_t *someip_parameter_arrays_uat; uat_t *someip_parameter_structs_uat; uat_t *someip_parameter_unions_uat; uat_t *someip_parameter_enums_uat; /* data fields */ static hf_register_info hf[] = { { &hf_someip_serviceid, { "Service ID", "someip.serviceid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_methodid, { "Method ID", "someip.methodid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_messageid, { "Message ID", "someip.messageid", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_length, { "Length", "someip.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_someip_clientid, { "Client ID", "someip.clientid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_sessionid, { "Session ID", "someip.sessionid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_protover, { "SOME/IP Version", "someip.protoversion", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_interface_ver, { "Interface Version", "someip.interfaceversion", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_messagetype, { "Message Type", "someip.messagetype", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_messagetype_ack_flag, { "Message Type Ack Flag", "someip.messagetype.ack", FT_BOOLEAN, 8, NULL, SOMEIP_MSGTYPE_ACK_MASK, NULL, HFILL }}, { &hf_someip_messagetype_tp_flag, { "Message Type TP Flag", "someip.messagetype.tp", FT_BOOLEAN, 8, NULL, SOMEIP_MSGTYPE_TP_MASK, NULL, HFILL }}, { &hf_someip_returncode, { "Return Code", "someip.returncode", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_someip_payload, { "Payload", "someip.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_someip_tp, { "SOME/IP-TP", "someip.tp", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_someip_tp_offset, { "Offset", "someip.tp.offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_someip_tp_flags, { "Flags", "someip.tp.flags", FT_UINT8, BASE_HEX, NULL, SOMEIP_TP_OFFSET_MASK_FLAGS, NULL, HFILL }}, { &hf_someip_tp_reserved, { "Reserved", "someip.tp.flags.reserved", FT_UINT8, BASE_HEX, NULL, SOMEIP_TP_OFFSET_MASK_RESERVED, NULL, HFILL }}, { &hf_someip_tp_more_segments, { "More Segments", "someip.tp.flags.more_segments", FT_BOOLEAN, 8, NULL, SOMEIP_TP_OFFSET_MASK_MORE_SEGMENTS, NULL, HFILL }}, {&hf_someip_tp_fragments, {"SOME/IP-TP segments", "someip.tp.fragments", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment, {"SOME/IP-TP segment", "someip.tp.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment_overlap, {"SOME/IP-TP segment overlap", "someip.tp.fragment.overlap", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment_overlap_conflicts, {"SOME/IP-TP segment overlapping with conflicting data", "someip.tp.fragment.overlap.conflicts", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment_multiple_tails, {"SOME/IP-TP Message has multiple tail fragments", "someip.tp.fragment.multiple_tails", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment_too_long_fragment, {"SOME/IP-TP segment too long", "someip.tp.fragment.too_long_fragment", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment_error, {"SOME/IP-TP Message defragmentation error", "someip.tp.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_fragment_count, {"SOME/IP-TP segment count", "someip.tp.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_reassembled_in, {"Reassembled in", "someip.tp.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_reassembled_length, {"Reassembled length", "someip.tp.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } }, {&hf_someip_tp_reassembled_data, {"Reassembled data", "someip.tp.reassembled.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_payload_unparsed, { "Unparsed Payload", "someip.payload.unparsed", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_payload_length_field_8bit, { "Length", "someip.payload.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_payload_length_field_16bit, { "Length", "someip.payload.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_payload_length_field_32bit, { "Length", "someip.payload.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_payload_type_field_8bit, { "Type", "someip.payload.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_payload_type_field_16bit, { "Type", "someip.payload.type", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_payload_type_field_32bit, { "Type", "someip.payload.type", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_payload_str_base, { "(base)", "someip.payload.base", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_payload_str_string, { "(string)", "someip.payload.string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_payload_str_struct, { "(struct)", "someip.payload.struct", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, }; static gint *ett[] = { &ett_someip, &ett_someip_msgtype, &ett_someip_tp, &ett_someip_tp_flags, &ett_someip_tp_fragment, &ett_someip_tp_fragments, &ett_someip_payload, &ett_someip_string, &ett_someip_array, &ett_someip_array_dim, &ett_someip_struct, &ett_someip_union, }; /* UATs for user_data fields */ static uat_field_t someip_service_uat_fields[] = { UAT_FLD_HEX(someip_service_ident, id, "Service ID", "ID of the SOME/IP Service (16bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_service_ident, name, "Service Name", "Name of the SOME/IP Service (string)"), UAT_END_FIELDS }; static uat_field_t someip_method_uat_fields[] = { UAT_FLD_HEX(someip_method_ident, id, "Service ID", "ID of the SOME/IP Service (16bit hex without leading 0x)"), UAT_FLD_HEX(someip_method_ident, id2, "Methods ID", "ID of the SOME/IP Method/Event/Notifier (16bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_method_ident, name, "Method Name", "Name of the SOME/IP Method/Event/Notifier (string)"), UAT_END_FIELDS }; static uat_field_t someip_eventgroup_uat_fields[] = { UAT_FLD_HEX(someip_eventgroup_ident, id, "Service ID", "ID of the SOME/IP Service (16bit hex without leading 0x)"), UAT_FLD_HEX(someip_eventgroup_ident, id2, "Eventgroup ID", "ID of the SOME/IP Eventgroup (16bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_eventgroup_ident, name, "Eventgroup Name", "Name of the SOME/IP Service (string)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_list_uat_fields[] = { UAT_FLD_HEX(someip_parameter_list, service_id, "Service ID", "ID of the SOME/IP Service (16bit hex without leading 0x)"), UAT_FLD_HEX(someip_parameter_list, method_id, "Method ID", "ID of the SOME/IP Method/Event/Notifier (16bit hex without leading 0x)"), UAT_FLD_DEC(someip_parameter_list, version, "Version", "Version of the SOME/IP Service (8bit dec)"), UAT_FLD_HEX(someip_parameter_list, message_type, "Message Type", "Message Type (8bit hex without leading 0x)"), UAT_FLD_DEC(someip_parameter_list, num_of_params, "Number of Parameter", "Number of Parameters (16bit dec)"), UAT_FLD_DEC(someip_parameter_list, pos, "Parameter Position", "Position of parameter (16bit dec, starting with 0)"), UAT_FLD_CSTRING(someip_parameter_list, name, "Parameter Name", "Name of parameter (string)"), UAT_FLD_DEC(someip_parameter_list, data_type, "Parameter Type", "Type of parameter (1: base, 2: string, 3: array, 4: struct, 5: union, 6: typedef, 7: enum)"), UAT_FLD_HEX(someip_parameter_list, id_ref, "ID Reference", "ID Reference (32bit hex)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_array_uat_fields[] = { UAT_FLD_HEX(someip_parameter_arrays, id, "ID", "ID of SOME/IP array (32bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_parameter_arrays, name, "Array Name", "Name of array"), UAT_FLD_DEC(someip_parameter_arrays, data_type, "Parameter Type", "Type of parameter (1: base, 2: string, 3: array, 4: struct, 5: union, 6: typedef, 7: enum)"), UAT_FLD_HEX(someip_parameter_arrays, id_ref, "ID Reference", "ID Reference (32bit hex)"), UAT_FLD_DEC(someip_parameter_arrays, num_of_dims, "Number of Items", "Number of Dimensions (16bit dec)"), UAT_FLD_DEC(someip_parameter_arrays, num, "Dimension", "Dimension (16bit dec, starting with 0)"), UAT_FLD_DEC(someip_parameter_arrays, lower_limit, "Lower Limit", "Dimension (32bit dec)"), UAT_FLD_DEC(someip_parameter_arrays, upper_limit, "Upper Limit", "Dimension (32bit dec)"), UAT_FLD_DEC(someip_parameter_arrays, length_of_length, "Length of Length Field", "Version of the SOME/IP Service (8bit dec)"), UAT_FLD_DEC(someip_parameter_arrays, pad_to, "Pad to", "Padding pads to reach alignment (8bit dec)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_struct_uat_fields[] = { UAT_FLD_HEX(someip_parameter_structs, id, "ID", "ID of SOME/IP struct (32bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_parameter_structs, struct_name, "Struct Name", "Name of struct"), UAT_FLD_DEC(someip_parameter_structs, length_of_length, "Length of Length Field", "Length of the strcuts length field (8bit dec)"), UAT_FLD_DEC(someip_parameter_structs, pad_to, "Pad to", "Padding pads to reach alignment (8bit dec)"), UAT_FLD_DEC(someip_parameter_structs, num_of_items, "Number of Items", "Number of Items (16bit dec)"), UAT_FLD_DEC(someip_parameter_structs, pos, "Parameter Position", "Position of parameter (16bit dec, starting with 0)"), UAT_FLD_CSTRING(someip_parameter_structs, name, "Parameter Name", "Name of parameter (string)"), UAT_FLD_DEC(someip_parameter_structs, data_type, "Parameter Type", "Type of parameter (1: base, 2: string, 3: array, 4: struct, 5: union, 6: typedef, 7: enum)"), UAT_FLD_HEX(someip_parameter_structs, id_ref, "ID Reference", "ID Reference (32bit hex)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_union_uat_fields[] = { UAT_FLD_HEX(someip_parameter_unions, id, "ID", "ID of SOME/IP union (32bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_parameter_unions, name, "Union Name", "Name of union"), UAT_FLD_DEC(someip_parameter_unions, length_of_length, "Length of Length Field", "Length of the unions length field (uint8 dec)"), UAT_FLD_DEC(someip_parameter_unions, length_of_type, "Length of Type Field", "Length of the unions type field (8bit dec)"), UAT_FLD_DEC(someip_parameter_unions, pad_to, "Pad to", "Padding pads to reach alignment (8bit dec)"), UAT_FLD_DEC(someip_parameter_unions, num_of_items, "Number of Items", "Number of Items (32bit dec)"), UAT_FLD_DEC(someip_parameter_unions, type_id, "Type ID", "ID of Type (32bit dec, starting with 0)"), UAT_FLD_CSTRING(someip_parameter_unions, type_name, "Type Name", "Name of Type (string)"), UAT_FLD_DEC(someip_parameter_unions, data_type, "Data Type", "Type of payload (1: base, 2: string, 3: array, 4: struct, 5: union, 6: typedef, 7: enum)"), UAT_FLD_HEX(someip_parameter_unions, id_ref, "ID Reference", "ID Reference (32bit hex)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_enum_uat_fields[] = { UAT_FLD_HEX(someip_parameter_enums, id, "ID", "ID of SOME/IP enum (32bit hex without leading 0x)"), UAT_FLD_CSTRING(someip_parameter_enums, name, "Name", "Name of Enumeration (string)"), UAT_FLD_DEC(someip_parameter_enums, data_type, "Parameter Type", "Type of parameter (dec)"), UAT_FLD_HEX(someip_parameter_enums, id_ref, "ID Reference", "ID Reference (32bit hex)"), UAT_FLD_DEC(someip_parameter_enums, num_of_items, "Number of Items", "Number of Items (32bit dec)"), UAT_FLD_HEX(someip_parameter_enums, value, "Value", "Value (64bit uint hex)"), UAT_FLD_CSTRING(someip_parameter_enums, value_name, "Value Name", "Name (string)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_base_type_list_uat_fields[] = { UAT_FLD_HEX(someip_parameter_base_type_list, id, "ID ", "ID (32bit hex)"), UAT_FLD_CSTRING(someip_parameter_base_type_list, name, "Name", "Name of type (string)"), UAT_FLD_CSTRING(someip_parameter_base_type_list, data_type, "Data Type", "Data type (string)"), UAT_FLD_DEC(someip_parameter_base_type_list, big_endian, "Big Endian", "Encoded Big Endian 0=no 1=yes"), UAT_FLD_DEC(someip_parameter_base_type_list, bitlength_base_type, "Bitlength base type", "Bitlength base type (uint32 dec)"), UAT_FLD_DEC(someip_parameter_base_type_list, bitlength_encoded_type, "Bitlength enc. type", "Bitlength encoded type (uint32 dec)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_string_list_uat_fields[] = { UAT_FLD_HEX(someip_parameter_strings, id, "ID ", "ID (32bit hex)"), UAT_FLD_CSTRING(someip_parameter_strings, name, "Name", "Name of string (string)"), UAT_FLD_CSTRING(someip_parameter_strings, encoding, "Encoding", "String Encoding (ascii, utf-8, utf-16)"), UAT_FLD_DEC(someip_parameter_strings, dynamic_length, "Dynamic Length", "Dynamic length of string 0=no 1=yes"), UAT_FLD_DEC(someip_parameter_strings, max_length, "Max. Length", "Maximum length/Length (uint32 dec)"), UAT_FLD_DEC(someip_parameter_strings, length_of_length, "Length of Len Field", "Length of the length field (uint8 dec)"), UAT_FLD_DEC(someip_parameter_strings, big_endian, "Big Endian", "Encoded Big Endian 0=no 1=yes"), UAT_FLD_DEC(someip_parameter_strings, pad_to, "Pad to" , "Padding pads to reach alignment (8bit dec)"), UAT_END_FIELDS }; static uat_field_t someip_parameter_typedef_list_uat_fields[] = { UAT_FLD_HEX(someip_parameter_typedefs, id, "ID ", "ID (32bit hex)"), UAT_FLD_CSTRING(someip_parameter_typedefs, name, "Name", "Name of typedef (string)"), UAT_FLD_DEC(someip_parameter_typedefs, data_type, "Data Type", "Type referenced item (1: base, 2: string, 3: array, 4: struct, 5: union, 6: typedef, 7: enum)"), UAT_FLD_HEX(someip_parameter_typedefs, id_ref, "ID Reference", "ID Reference (32bit hex)"), UAT_END_FIELDS }; static ei_register_info ei[] = { { &ef_someip_unknown_version,{ "someip.unknown_protocol_version", PI_PROTOCOL, PI_WARN, "SOME/IP Unknown Protocol Version!", EXPFILL } }, { &ef_someip_message_truncated,{ "someip.message_truncated", PI_MALFORMED, PI_ERROR, "SOME/IP Truncated message!", EXPFILL } }, { &ef_someip_incomplete_headers,{ "someip.incomplete_headers", PI_MALFORMED, PI_ERROR, "SOME/IP Incomplete headers or some bytes left over!", EXPFILL } }, { &ef_someip_payload_truncated, {"someip.payload.expert_truncated", PI_MALFORMED, PI_ERROR, "SOME/IP Payload: Truncated payload!", EXPFILL} }, { &ef_someip_payload_malformed, {"someip.payload.expert_malformed", PI_MALFORMED, PI_ERROR, "SOME/IP Payload: Malformed payload!", EXPFILL} }, { &ef_someip_payload_config_error, {"someip.payload.expert_config_error", PI_MALFORMED, PI_ERROR, "SOME/IP Payload: Config Error!", EXPFILL} }, { &ef_someip_payload_alignment_error, {"someip.payload.expert_alignment_error", PI_MALFORMED, PI_ERROR, "SOME/IP Payload: SOME/IP datatype must be align to a byte!", EXPFILL} }, { &ef_someip_payload_static_array_min_not_max, {"someip.payload.expert_static_array_min_max", PI_MALFORMED, PI_ERROR, "SOME/IP Payload: Static array with min!=max!", EXPFILL} }, { &ef_someip_payload_dyn_array_not_within_limit, {"someip.payload.expert_dyn_array_not_within_limit", PI_MALFORMED, PI_WARN, "SOME/IP Payload: Dynamic array does not stay between Min and Max values!", EXPFILL} }, }; /* Register ETTs */ proto_someip = proto_register_protocol(SOMEIP_NAME_LONG, SOMEIP_NAME, SOMEIP_NAME_FILTER); proto_register_field_array(proto_someip, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_module_someip = expert_register_protocol(proto_someip); expert_register_field_array(expert_module_someip, ei, array_length(ei)); someip_dissector_table = register_dissector_table("someip.messageid", "SOME/IP Message ID", proto_someip, FT_UINT32, BASE_HEX); /* init for SOME/IP-TP */ reassembly_table_init(&someip_tp_reassembly_table, &addresses_ports_reassembly_table_functions); /* Register preferences */ someip_module = prefs_register_protocol(proto_someip, &proto_reg_handoff_someip); range_convert_str(wmem_epan_scope(), &someip_ports_udp, "", 65535); prefs_register_range_preference(someip_module, "ports.udp", "UDP Ports", "SOME/IP Port Ranges UDP.", &someip_ports_udp, 65535); range_convert_str(wmem_epan_scope(), &someip_ports_tcp, "", 65535); prefs_register_range_preference(someip_module, "ports.tcp", "TCP Ports", "SOME/IP Port Ranges TCP.", &someip_ports_tcp, 65535); /* UATs */ someip_service_uat = uat_new("SOME/IP Services", sizeof(generic_one_id_string_t), /* record size */ DATAFILE_SOMEIP_SERVICES, /* filename */ TRUE, /* from profile */ (void**) &someip_service_ident, /* data_ptr */ &someip_service_ident_num, /* numitems_ptr */ UAT_AFFECTS_DISSECTION, /* but not fields */ NULL, /* help */ copy_generic_one_id_string_cb, /* copy callback */ update_generic_one_identifier_16bit, /* update callback */ free_generic_one_id_string_cb, /* free callback */ post_update_someip_service_cb, /* post update callback */ NULL, /* reset callback */ someip_service_uat_fields /* UAT field definitions */ ); prefs_register_uat_preference(someip_module, "services", "SOME/IP Services", "A table to define names of SOME/IP services", someip_service_uat); someip_method_uat = uat_new("SOME/IP Methods/Events/Fields", sizeof(generic_two_id_string_t), /* record size */ DATAFILE_SOMEIP_METHODS, /* record size */ TRUE, /* from profile */ (void**) &someip_method_ident, /* data_ptr */ &someip_method_ident_num, /* numitems_ptr */ UAT_AFFECTS_DISSECTION, /* but not fields */ NULL, /* help */ copy_generic_two_id_string_cb, /* copy callback */ update_generic_two_identifier_16bit, /* update callback */ free_generic_two_id_string_cb, /* free callback */ post_update_someip_method_cb, /* post update callback */ NULL, /* reset callback */ someip_method_uat_fields /* UAT field definitions */ ); prefs_register_uat_preference(someip_module, "methods", "SOME/IP Methods", "A table to define names of SOME/IP methods", someip_method_uat); someip_eventgroup_uat = uat_new("SOME/IP Eventgroups", sizeof(generic_two_id_string_t), /* record size */ DATAFILE_SOMEIP_EVENTGROUPS, /* record size */ TRUE, /* from profile */ (void**) &someip_eventgroup_ident, /* data_ptr */ &someip_eventgroup_ident_num, /* numitems_ptr */ UAT_AFFECTS_DISSECTION, /* but not fields */ NULL, /* help */ copy_generic_two_id_string_cb, /* copy callback */ update_generic_two_identifier_16bit, /* update callback */ free_generic_two_id_string_cb, /* free callback */ post_update_someip_eventgroup_cb, /* post update callback */ NULL, /* reset callback */ someip_eventgroup_uat_fields /* UAT field definitions */ ); prefs_register_uat_preference(someip_module, "eventgroups", "SOME/IP Eventgroups", "A table to define names of SOME/IP eventgroups", someip_eventgroup_uat); someip_parameter_list_uat = uat_new("SOME/IP Parameter List", sizeof(someip_parameter_list_uat_t), DATAFILE_SOMEIP_PARAMETERS, TRUE, (void**)&someip_parameter_list, &someip_parameter_list_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_list_cb, update_someip_parameter_list, free_someip_parameter_list_cb, post_update_someip_parameter_list_cb, NULL, /* reset */ someip_parameter_list_uat_fields ); prefs_register_bool_preference(someip_module, "reassemble_tp", "Reassemble SOME/IP-TP", "Reassemble SOME/IP-TP segments", &someip_tp_reassemble); prefs_register_bool_preference(someip_module, "payload_dissector_activated", "Dissect Payload", "Should the SOME/IP Dissector use the payload dissector?", &someip_derserializer_activated); prefs_register_uat_preference(someip_module, "_someip_parameter_list", "SOME/IP Parameter List", "A table to define names of SOME/IP parameters", someip_parameter_list_uat); someip_parameter_arrays_uat = uat_new("SOME/IP Parameter Arrays", sizeof(someip_parameter_array_uat_t), DATAFILE_SOMEIP_ARRAYS, TRUE, (void**)&someip_parameter_arrays, &someip_parameter_arrays_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_array_cb, update_someip_parameter_array, free_someip_parameter_array_cb, post_update_someip_parameter_array_cb, NULL, /* reset */ someip_parameter_array_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_arrays", "SOME/IP Parameter Arrays", "A table to define arrays used by SOME/IP", someip_parameter_arrays_uat); someip_parameter_structs_uat = uat_new("SOME/IP Parameter Structs", sizeof(someip_parameter_struct_uat_t), DATAFILE_SOMEIP_STRUCTS, TRUE, (void**)&someip_parameter_structs, &someip_parameter_structs_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_struct_cb, update_someip_parameter_struct, free_someip_parameter_struct_cb, post_update_someip_parameter_struct_cb, NULL, /* reset */ someip_parameter_struct_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_structs", "SOME/IP Parameter Structs", "A table to define structs used by SOME/IP", someip_parameter_structs_uat); someip_parameter_unions_uat = uat_new("SOME/IP Parameter Unions", sizeof(someip_parameter_union_uat_t), DATAFILE_SOMEIP_UNIONS, TRUE, (void**)&someip_parameter_unions, &someip_parameter_unions_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_union_cb, update_someip_parameter_union, free_someip_parameter_union_cb, post_update_someip_parameter_union_cb, NULL, /* reset */ someip_parameter_union_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_unions", "SOME/IP Parameter Unions", "A table to define unions used by SOME/IP", someip_parameter_unions_uat); someip_parameter_enums_uat = uat_new("SOME/IP Parameter Enums", sizeof(someip_parameter_enum_uat_t), DATAFILE_SOMEIP_ENUMS, TRUE, (void**)&someip_parameter_enums, &someip_parameter_enums_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_enum_cb, update_someip_parameter_enum, free_someip_parameter_enum_cb, post_update_someip_parameter_enum_cb, NULL, /* reset */ someip_parameter_enum_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_enums", "SOME/IP Parameter Enums", "A table to define enumerations used by SOME/IP", someip_parameter_enums_uat); someip_parameter_base_type_list_uat = uat_new("SOME/IP Parameter Base Type List", sizeof(someip_parameter_base_type_list_uat_t), DATAFILE_SOMEIP_BASE_TYPES, TRUE, (void**)&someip_parameter_base_type_list, &someip_parameter_base_type_list_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_base_type_list_cb, update_someip_parameter_base_type_list, free_someip_parameter_base_type_list_cb, post_update_someip_parameter_base_type_list_cb, NULL, /* reset */ someip_parameter_base_type_list_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_base_type_list", "SOME/IP Parameter Base Type List", "A table to define base types of SOME/IP parameters", someip_parameter_base_type_list_uat); someip_parameter_strings_uat = uat_new("SOME/IP Parameter String List", sizeof(someip_parameter_string_uat_t), DATAFILE_SOMEIP_STRINGS, TRUE, (void**)&someip_parameter_strings, &someip_parameter_strings_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_string_list_cb, update_someip_parameter_string_list, free_someip_parameter_string_list_cb, post_update_someip_parameter_string_list_cb, NULL, /* reset */ someip_parameter_string_list_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_string_list", "SOME/IP Parameter String List", "A table to define strings parameters", someip_parameter_strings_uat); someip_parameter_typedefs_uat = uat_new("SOME/IP Parameter Typedef List", sizeof(someip_parameter_typedef_uat_t), DATAFILE_SOMEIP_TYPEDEFS, TRUE, (void**)&someip_parameter_typedefs, &someip_parameter_typedefs_num, UAT_AFFECTS_DISSECTION, NULL, /* help */ copy_someip_parameter_typedef_list_cb, update_someip_parameter_typedef_list, free_someip_parameter_typedef_list_cb, post_update_someip_parameter_typedef_list_cb, NULL, /* reset */ someip_parameter_typedef_list_uat_fields ); prefs_register_uat_preference(someip_module, "_someip_parameter_typedef_list", "SOME/IP Parameter Typedef List", "A table to define typedefs", someip_parameter_typedefs_uat); } void proto_reg_handoff_someip(void) { static gboolean initialized = FALSE; if (!initialized) { someip_handle_udp = create_dissector_handle(dissect_someip_udp, proto_someip); someip_handle_tcp = create_dissector_handle(dissect_someip_tcp, proto_someip); heur_dissector_add("udp", dissect_some_ip_heur_udp, "SOME/IP_UDP_Heuristic", "someip_udp_heur", proto_someip, HEURISTIC_DISABLE); heur_dissector_add("tcp", dissect_some_ip_heur_tcp, "SOME/IP_TCP_Heuristic", "someip_tcp_heur", proto_someip, HEURISTIC_DISABLE); initialized = TRUE; } else { /* delete all my ports even the dynamically registered ones */ dissector_delete_all("udp.port", someip_handle_tcp); dissector_delete_all("tcp.port", someip_handle_tcp); } dissector_add_uint_range("udp.port", someip_ports_udp, someip_handle_udp); dissector_add_uint_range("tcp.port", someip_ports_tcp, someip_handle_tcp); } /* * 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: */