UDS: Adding support for Routine ID and Data ID resolution
This commit is contained in:
parent
771872cc7e
commit
9a400118df
|
@ -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) {
|
||||
|
@ -716,9 +904,23 @@ dissect_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data
|
|||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue