aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-uds.c
diff options
context:
space:
mode:
authorDr. Lars Völker <lars.voelker@technica-engineering.de>2021-05-13 21:03:02 +0200
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-05-14 07:39:10 +0000
commit9a400118dfc9d7348cb38c041c48a7bec302efe1 (patch)
treeb6b369e9c9b74dab40975bc63173069ac06d3e88 /epan/dissectors/packet-uds.c
parent771872cc7e548d5f6b433b0e7fa351e0507d2787 (diff)
UDS: Adding support for Routine ID and Data ID resolution
Diffstat (limited to 'epan/dissectors/packet-uds.c')
-rw-r--r--epan/dissectors/packet-uds.c286
1 files changed, 273 insertions, 13 deletions
diff --git a/epan/dissectors/packet-uds.c b/epan/dissectors/packet-uds.c
index e4e63744b4..2d8990a580 100644
--- a/epan/dissectors/packet-uds.c
+++ b/epan/dissectors/packet-uds.c
@@ -11,11 +11,15 @@
#include "config.h"
#include <epan/packet.h>
+#include <epan/uat.h>
#include <wsutil/bits_ctz.h>
void proto_register_uds(void);
void proto_reg_handoff_uds(void);
+#define DATAFILE_UDS_ROUTINE_IDS "UDS_routine_identifiers"
+#define DATAFILE_UDS_DATA_IDS "UDS_data_identifiers"
+
#define UDS_SERVICES_DSC 0x10
#define UDS_SERVICES_ER 0x11
#define UDS_SERVICES_CDTCI 0x14
@@ -376,6 +380,171 @@ static int proto_uds = -1;
static dissector_handle_t uds_handle;
+
+/*** Configuration ***/
+typedef struct _generic_one_id_string {
+ guint id;
+ gchar *name;
+} generic_one_id_string_t;
+
+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));
+ }
+}
+
+char *
+generic_lookup_uint16(guint16 id, GHashTable *ht) {
+ guint32 tmp = (guint32)id;
+
+ if (ht == NULL) {
+ return NULL;
+ }
+
+ return (char *)g_hash_table_lookup(ht, &tmp);
+}
+
+static void
+simple_free_key(gpointer key) {
+ wmem_free(wmem_epan_scope(), key);
+}
+
+static void
+simple_free(gpointer data) {
+ /* we need to free because of the g_strdup in post_update*/
+ g_free(data);
+}
+
+
+/* Routine IDs */
+static generic_one_id_string_t *uds_uat_routine_ids = NULL;
+static guint uds_uat_routine_id_num = 0;
+static GHashTable *uds_ht_routine_ids = NULL;
+
+UAT_HEX_CB_DEF(uds_uat_routine_ids, id, generic_one_id_string_t)
+UAT_CSTRING_CB_DEF(uds_uat_routine_ids, name, generic_one_id_string_t)
+
+static void
+post_update_uds_routine_cb(void) {
+ /* destroy old hash table, if it exists */
+ if (uds_ht_routine_ids) {
+ g_hash_table_destroy(uds_ht_routine_ids);
+ }
+
+ /* create new hash table */
+ uds_ht_routine_ids = g_hash_table_new_full(g_int_hash, g_int_equal, &simple_free_key, &simple_free);
+ post_update_one_id_string_template_cb(uds_uat_routine_ids, uds_uat_routine_id_num, uds_ht_routine_ids);
+}
+
+char *
+uds_lookup_routine_name(guint16 id) {
+ return generic_lookup_uint16(id, uds_ht_routine_ids);
+}
+
+void
+protoitem_append_routine_name(proto_item *ti, guint16 data_identifier) {
+ gchar *routine_name = uds_lookup_routine_name((guint16)data_identifier);
+ if (routine_name != NULL) {
+ proto_item_append_text(ti, " (%s)", routine_name);
+ }
+}
+
+void
+infocol_append_routine_name(packet_info *pinfo, guint16 routine_identifier) {
+ gchar *routine_name = uds_lookup_routine_name((guint16)routine_identifier);
+ if (routine_name != NULL) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", routine_name);
+ }
+}
+
+
+/* Data IDs */
+static generic_one_id_string_t *uds_uat_data_ids = NULL;
+static guint uds_uat_data_id_num = 0;
+static GHashTable *uds_ht_data_ids = NULL;
+
+UAT_HEX_CB_DEF(uds_uat_data_ids, id, generic_one_id_string_t)
+UAT_CSTRING_CB_DEF(uds_uat_data_ids, name, generic_one_id_string_t)
+
+static void
+post_update_uds_data_cb(void) {
+ /* destroy old hash table, if it exists */
+ if (uds_ht_data_ids) {
+ g_hash_table_destroy(uds_ht_data_ids);
+ }
+
+ /* create new hash table */
+ uds_ht_data_ids = g_hash_table_new_full(g_int_hash, g_int_equal, &simple_free_key, &simple_free);
+ post_update_one_id_string_template_cb(uds_uat_data_ids, uds_uat_data_id_num, uds_ht_data_ids);
+}
+
+char *
+uds_lookup_data_name(guint16 id) {
+ return generic_lookup_uint16(id, uds_ht_data_ids);
+}
+
+void
+protoitem_append_data_name(proto_item *ti, guint16 data_identifier) {
+ gchar *data_name = uds_lookup_data_name((guint16)data_identifier);
+ if (data_name != NULL) {
+ proto_item_append_text(ti, " (%s)", data_name);
+ }
+}
+
+void
+infocol_append_data_name(packet_info *pinfo, guint16 data_identifier) {
+ gchar *data_name = uds_lookup_data_name((guint16)data_identifier);
+ if (data_name != NULL) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", data_name);
+ }
+}
+
+/*** Configuration End ***/
+
+
static
guint8 masked_guint8_value(const guint8 value, const guint8 mask)
{
@@ -471,11 +640,16 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
/* Can't know the size of the data for each identifier, Decode like if there is only one idenfifier */
guint32 record_length = data_length - UDS_RDBI_DATA_RECORD_OFFSET;
guint32 data_identifier;
- proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb, UDS_RDBI_DATA_IDENTIFIER_OFFSET,
- UDS_RDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier);
+ ti = proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb,
+ UDS_RDBI_DATA_IDENTIFIER_OFFSET, UDS_RDBI_DATA_IDENTIFIER_LEN,
+ ENC_BIG_ENDIAN, &data_identifier);
+ protoitem_append_data_name(ti, (guint16)data_identifier);
+
proto_tree_add_item(subtree, hf_uds_rdbi_data_record, tvb, UDS_RDBI_DATA_RECORD_OFFSET,
record_length, ENC_NA);
- col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x %s", data_identifier,
+ col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
+ infocol_append_data_name(pinfo, data_identifier);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_RDBI_DATA_RECORD_OFFSET,
record_length, ' '));
} else {
@@ -483,9 +657,12 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
guint32 offset = UDS_RDBI_DATA_IDENTIFIER_OFFSET;
while (identifier_length > 0) {
guint32 data_identifier;
- proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb, offset,
- UDS_RDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier);
+ ti = proto_tree_add_item_ret_uint(subtree, hf_uds_rdbi_data_identifier, tvb, offset,
+ UDS_RDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier);
+ protoitem_append_data_name(ti, (guint16)data_identifier);
+
col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
+ infocol_append_data_name(pinfo, data_identifier);
offset += UDS_RDBI_DATA_IDENTIFIER_LEN;
identifier_length -= UDS_RDBI_DATA_IDENTIFIER_LEN;
}
@@ -520,15 +697,20 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
case UDS_SERVICES_WDBI:
subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_wdbi, NULL, service_name);
- proto_tree_add_item_ret_uint(subtree, hf_uds_wdbi_data_identifier, tvb, UDS_WDBI_DATA_IDENTIFIER_OFFSET,
- UDS_WDBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &enum_val);
+ ti = proto_tree_add_item_ret_uint(subtree, hf_uds_wdbi_data_identifier, tvb,
+ UDS_WDBI_DATA_IDENTIFIER_OFFSET, UDS_WDBI_DATA_IDENTIFIER_LEN,
+ ENC_BIG_ENDIAN, &enum_val);
+ protoitem_append_data_name(ti, (guint16)enum_val);
if (sid & UDS_REPLY_MASK) {
col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", enum_val);
+ infocol_append_data_name(pinfo, enum_val);
} else {
guint32 record_length = data_length - UDS_WDBI_DATA_RECORD_OFFSET;
proto_tree_add_item(subtree, hf_uds_wdbi_data_record, tvb, UDS_WDBI_DATA_RECORD_OFFSET,
record_length, ENC_NA);
- col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x %s", enum_val,
+ col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", enum_val);
+ infocol_append_data_name(pinfo, enum_val);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_WDBI_DATA_RECORD_OFFSET,
record_length, ' '));
}
@@ -539,15 +721,19 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
guint32 state_length = data_length - UDS_IOCBI_STATE_OFFSET;
subtree = proto_tree_add_subtree(uds_tree, tvb, 0, -1, ett_uds_iocbi, NULL, service_name);
- proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_data_identifier, tvb, UDS_IOCBI_DATA_IDENTIFIER_OFFSET,
- UDS_IOCBI_DATA_IDENTIFIER_LEN, ENC_BIG_ENDIAN, &data_identifier);
+ ti = proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_data_identifier, tvb,
+ UDS_IOCBI_DATA_IDENTIFIER_OFFSET, UDS_IOCBI_DATA_IDENTIFIER_LEN,
+ ENC_BIG_ENDIAN, &data_identifier);
+ protoitem_append_data_name(ti, (guint16)data_identifier);
proto_tree_add_item_ret_uint(subtree, hf_uds_iocbi_parameter, tvb, UDS_IOCBI_PARAMETER_OFFSET,
- UDS_IOCBI_PARAMETER_LEN, ENC_BIG_ENDIAN, &enum_val);
+ UDS_IOCBI_PARAMETER_LEN, ENC_BIG_ENDIAN, &enum_val);
proto_tree_add_item(subtree, hf_uds_iocbi_state, tvb, UDS_IOCBI_STATE_OFFSET,
state_length, ENC_NA);
- col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x %s %s", data_identifier,
+ col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
+ infocol_append_data_name(pinfo, data_identifier);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s %s",
val_to_str(enum_val, uds_iocbi_parameters, "Unknown (0x%02x)"),
tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, UDS_IOCBI_STATE_OFFSET,
state_length, ' '));
@@ -560,11 +746,13 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
proto_tree_add_item_ret_uint(subtree, hf_uds_rc_type, tvb, UDS_RC_TYPE_OFFSET,
UDS_RC_TYPE_LEN, ENC_BIG_ENDIAN, &enum_val);
- proto_tree_add_item_ret_uint(subtree, hf_uds_rc_identifier, tvb, UDS_RC_ROUTINE_OFFSET,
+ ti = proto_tree_add_item_ret_uint(subtree, hf_uds_rc_identifier, tvb, UDS_RC_ROUTINE_OFFSET,
UDS_RC_ROUTINE_LEN, ENC_BIG_ENDIAN, &identifier);
+ protoitem_append_routine_name(ti, identifier);
col_append_fstr(pinfo->cinfo, COL_INFO, " %s 0x%04x",
val_to_str(enum_val, uds_rc_types, "Unknown (0x%02x)"), identifier);
+ infocol_append_routine_name(pinfo, identifier);
if (sid & UDS_REPLY_MASK) {
guint32 rc_data_len = data_length - UDS_RC_INFO_OFFSET;
if (rc_data_len > 0) {
@@ -717,8 +905,22 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
}
void
+pref_update_uds(void) {
+ if (uds_ht_routine_ids && uds_uat_routine_id_num == 0) {
+ g_hash_table_destroy(uds_ht_routine_ids);
+ uds_ht_routine_ids = NULL;
+ }
+
+ if (uds_ht_data_ids && uds_uat_data_id_num == 0) {
+ g_hash_table_destroy(uds_ht_data_ids);
+ uds_ht_data_ids = NULL;
+ }
+}
+
+void
proto_register_uds(void)
{
+ module_t* uds_module;
static hf_register_info hf[] = {
{
&hf_uds_service,
@@ -1065,6 +1267,9 @@ proto_register_uds(void)
},
};
+ uat_t* uds_routine_ids_uat;
+ uat_t* uds_data_ids_uat;
+
/* Setup protocol subtree array */
static gint *ett[] =
{
@@ -1094,6 +1299,61 @@ proto_register_uds(void)
proto_register_subtree_array(ett, array_length(ett));
uds_handle = register_dissector("uds", dissect_uds, proto_uds);
+
+ /* Register preferences */
+ uds_module = prefs_register_protocol(proto_uds, &pref_update_uds);
+
+ /* UATs for user_data fields */
+ static uat_field_t uds_routine_id_uat_fields[] = {
+ UAT_FLD_HEX(uds_uat_routine_ids, id, "Routine ID", "Routine Identifier (16bit hex without leading 0x)"),
+ UAT_FLD_CSTRING(uds_uat_routine_ids, name, "Routine Name", "Name of the Routine ID (string)"),
+ UAT_END_FIELDS
+ };
+
+ /* UATs */
+ uds_routine_ids_uat = uat_new("UDS Routine Identifier List",
+ sizeof(generic_one_id_string_t), /* record size */
+ DATAFILE_UDS_ROUTINE_IDS, /* filename */
+ TRUE, /* from profile */
+ (void**)&uds_uat_routine_ids, /* data_ptr */
+ &uds_uat_routine_id_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_uds_routine_cb, /* post update callback */
+ NULL, /* reset callback */
+ uds_routine_id_uat_fields /* UAT field definitions */
+ );
+
+ prefs_register_uat_preference(uds_module, "_uds_routine_id_list", "UDS Routine Identifier List",
+ "A table to define names of UDS Routines", uds_routine_ids_uat);
+
+ static uat_field_t uds_data_id_uat_fields[] = {
+ UAT_FLD_HEX(uds_uat_data_ids, id, "Data ID", "Data Identifier (16bit hex without leading 0x)"),
+ UAT_FLD_CSTRING(uds_uat_data_ids, name, "Data Name", "Name of the Data ID (string)"),
+ UAT_END_FIELDS
+ };
+
+ uds_data_ids_uat = uat_new("UDS Data Identifier List",
+ sizeof(generic_one_id_string_t), /* record size */
+ DATAFILE_UDS_DATA_IDS, /* filename */
+ TRUE, /* from profile */
+ (void**)&uds_uat_data_ids, /* data_ptr */
+ &uds_uat_data_id_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_uds_data_cb, /* post update callback */
+ NULL, /* reset callback */
+ uds_data_id_uat_fields /* UAT field definitions */
+ );
+
+ prefs_register_uat_preference(uds_module, "_uds_data_id_list", "UDS Data Identifier List",
+ "A table to define names of UDS Data Identifier", uds_data_ids_uat);
}
void