aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors
diff options
context:
space:
mode:
authorDr. Lars Völker <lars.voelker@technica-engineering.de>2022-01-04 15:49:39 +0100
committerA Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2022-01-05 06:06:33 +0000
commit382fe23aa8129d8f2ad2fb3ed484946625e70a50 (patch)
tree26a2918f18bc61b5121ea659b2db00b175c02f79 /epan/dissectors
parent27ccf26b4bdacefbd25a185721f88e07677b95e5 (diff)
UDS: add subdissector support
Adding subdissector support to UDS and allow Signal PDUs for it. This patch supports: - ReadDataByIdentifier (RDBI) Reply - WriteDataByIdentifier (WDBI) Request - RoutineControl (RC) Request - RoutineControl (RC) Reply
Diffstat (limited to 'epan/dissectors')
-rw-r--r--epan/dissectors/CMakeLists.txt1
-rw-r--r--epan/dissectors/packet-signal-pdu.c175
-rw-r--r--epan/dissectors/packet-uds.c61
-rw-r--r--epan/dissectors/packet-uds.h63
4 files changed, 269 insertions, 31 deletions
diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt
index 817575f218..94698143cd 100644
--- a/epan/dissectors/CMakeLists.txt
+++ b/epan/dissectors/CMakeLists.txt
@@ -601,6 +601,7 @@ set(DISSECTOR_PUBLIC_HEADERS
packet-uavcan-dsdl.h
packet-ubertooth.h
packet-udp.h
+ packet-uds.h
packet-umts_fp.h
packet-umts_mac.h
packet-umts_rlc.h
diff --git a/epan/dissectors/packet-signal-pdu.c b/epan/dissectors/packet-signal-pdu.c
index 277e6827c3..4aa8fa26e5 100644
--- a/epan/dissectors/packet-signal-pdu.c
+++ b/epan/dissectors/packet-signal-pdu.c
@@ -32,6 +32,7 @@
#include <packet-lin.h>
#include <packet-autosar-ipdu-multiplexer.h>
#include <packet-dlt.h>
+#include <packet-uds.h>
/*
@@ -62,6 +63,7 @@
#define DATAFILE_SPDU_PDU_TRANSPORT_MAPPING "Signal_PDU_Binding_PDU_Transport"
#define DATAFILE_SPDU_IPDUM_MAPPING "Signal_PDU_Binding_AUTOSAR_IPduM"
#define DATAFILE_SPDU_DLT_MAPPING "Signal_PDU_Binding_DLT"
+#define DATAFILE_SPDU_UDS_MAPPING "Signal_PDU_Binding_UDS"
/* ID wireshark identifies the dissector by */
static int proto_signal_pdu = -1;
@@ -99,6 +101,7 @@ static GHashTable *data_spdu_lin_mappings = NULL;
static GHashTable *data_spdu_pdu_transport_mappings = NULL;
static GHashTable *data_spdu_ipdum_mappings = NULL;
static GHashTable *data_spdu_dlt_mappings = NULL;
+static GHashTable *data_spdu_uds_mappings = NULL;
static hf_register_info *dynamic_hf = NULL;
static guint dynamic_hf_size = 0;
@@ -259,6 +262,7 @@ typedef struct _spdu_ipdum_mapping {
} spdu_ipdum_mapping_t;
typedef spdu_ipdum_mapping_t spdu_ipdum_mapping_uat_t;
+
typedef struct _spdu_dlt_mapping {
gchar *ecu_id;
guint32 dlt_message_id;
@@ -266,6 +270,17 @@ typedef struct _spdu_dlt_mapping {
} spdu_dlt_mapping_t;
typedef spdu_dlt_mapping_t spdu_dlt_mapping_uat_t;
+
+typedef struct _spdu_uds_mapping {
+ guint32 uds_address;
+ guint32 service;
+ gboolean reply;
+ guint32 id;
+ guint32 message_id;
+} spdu_uds_mapping_t;
+typedef spdu_uds_mapping_t spdu_uds_mapping_uat_t;
+
+
static generic_one_id_string_t *spdu_message_ident = NULL;
static guint spdu_message_ident_num = 0;
@@ -296,6 +311,10 @@ static guint spdu_ipdum_mapping_num = 0;
static spdu_dlt_mapping_t *spdu_dlt_mapping = NULL;
static guint spdu_dlt_mapping_num = 0;
+static spdu_uds_mapping_t *spdu_uds_mapping = NULL;
+static guint spdu_uds_mapping_num = 0;
+
+
void proto_register_signal_pdu(void);
void proto_reg_handoff_signal_pdu(void);
@@ -1582,7 +1601,7 @@ update_spdu_dlt_mapping(void *r, char **err) {
spdu_dlt_mapping_uat_t *rec = (spdu_dlt_mapping_uat_t *)r;
if (rec->ecu_id != NULL && strlen(rec->ecu_id) > 4) {
- *err = ws_strdup_printf("ECU ID can only be up to 4 characters long!");
+ *err = ws_strdup_printf("ECU ID can only be up to 4 characters long!");
return FALSE;
}
@@ -1628,6 +1647,112 @@ get_dlt_mapping(guint32 pdu_id, const gchar *ecu_id) {
return (spdu_dlt_mapping_uat_t *)g_hash_table_lookup(data_spdu_dlt_mappings, &key);
}
+/* UAT: UDS Mapping */
+UAT_HEX_CB_DEF(spdu_uds_mapping, uds_address, spdu_uds_mapping_uat_t)
+UAT_HEX_CB_DEF(spdu_uds_mapping, service, spdu_uds_mapping_uat_t)
+UAT_BOOL_CB_DEF(spdu_uds_mapping, reply, spdu_uds_mapping_uat_t)
+UAT_HEX_CB_DEF(spdu_uds_mapping, id, spdu_uds_mapping_uat_t)
+UAT_HEX_CB_DEF(spdu_uds_mapping, message_id, spdu_uds_mapping_uat_t)
+
+static void *
+copy_spdu_uds_mapping_cb(void *n, const void *o, size_t size _U_) {
+ spdu_uds_mapping_uat_t *new_rec = (spdu_uds_mapping_uat_t *)n;
+ const spdu_uds_mapping_uat_t *old_rec = (const spdu_uds_mapping_uat_t *)o;
+
+ new_rec->uds_address = old_rec->uds_address;
+ new_rec->service = old_rec->service;
+ new_rec->reply = old_rec->reply;
+ new_rec->id = old_rec->id;
+ new_rec->message_id = old_rec->message_id;
+
+ return new_rec;
+}
+
+static gboolean
+update_spdu_uds_mapping(void *r, char **err) {
+ spdu_uds_mapping_uat_t *rec = (spdu_uds_mapping_uat_t *)r;
+
+ if (rec->id > 0xffff) {
+ *err = g_strdup_printf("UDS IDs are only uint16!");
+ return FALSE;
+ }
+
+ if (rec->service > 0xff) {
+ *err = g_strdup_printf("UDS Services are only uint8!");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+post_update_spdu_uds_mapping_cb(void) {
+ /* destroy old hash table, if it exists */
+ if (data_spdu_uds_mappings) {
+ g_hash_table_destroy(data_spdu_uds_mappings);
+ data_spdu_uds_mappings = NULL;
+ }
+
+ /* we don't need to free the data as long as we don't alloc it first */
+ data_spdu_uds_mappings = g_hash_table_new_full(g_int64_hash, g_int64_equal, &spdu_payload_free_key, NULL);
+
+ if (data_spdu_uds_mappings == NULL || spdu_uds_mapping == NULL) {
+ return;
+ }
+
+ if (spdu_uds_mapping_num > 0) {
+ guint i;
+ guint32 sid;
+ for (i = 0; i < spdu_uds_mapping_num; i++) {
+ gint64 *key = wmem_new(wmem_epan_scope(), gint64);
+ if (spdu_uds_mapping[i].reply) {
+ sid = (0xff & spdu_uds_mapping[i].service) | UDS_REPLY_MASK;
+ } else {
+ sid = (0xff & spdu_uds_mapping[i].service);
+ }
+
+ *key = (guint64)(spdu_uds_mapping[i].uds_address) | ((guint64)(0xffff & spdu_uds_mapping[i].id) << 32) | ((guint64)sid << 48);
+ g_hash_table_insert(data_spdu_uds_mappings, key, &spdu_uds_mapping[i]);
+
+ /* Adding with 0xffffffff (ANY) as address too */
+ key = wmem_new(wmem_epan_scope(), gint64);
+ *key = (guint64)(0xffffffff) | ((guint64)(0xffff & spdu_uds_mapping[i].id) << 32) | ((guint64)sid << 48);
+ g_hash_table_insert(data_spdu_uds_mappings, key, &spdu_uds_mapping[i]);
+ }
+ }
+}
+
+static spdu_uds_mapping_uat_t *
+get_uds_mapping(uds_info_t *uds_info) {
+ guint32 sid;
+
+ DISSECTOR_ASSERT(uds_info);
+ if (data_spdu_uds_mappings == NULL) {
+ return NULL;
+ }
+
+ gint64 *key = wmem_new(wmem_epan_scope(), gint64);
+ if (uds_info->reply) {
+ sid = (0xff & uds_info->service) | UDS_REPLY_MASK;
+ } else {
+ sid = (0xff & uds_info->service);
+ }
+ *key = (guint64)(uds_info->uds_address) | ((guint64)(0xffff & uds_info->id) << 32) | ((guint64)sid << 48);
+
+ spdu_uds_mapping_uat_t *tmp = (spdu_uds_mapping_uat_t *)g_hash_table_lookup(data_spdu_uds_mappings, key);
+
+ /* if we cannot find it for the Address, lets look at MAXUINT32 */
+ if (tmp == NULL) {
+ *key = (guint64)(G_MAXUINT32) | ((guint64)(0xffff & uds_info->id) << 32) | ((guint64)sid << 48);
+
+ tmp = (spdu_uds_mapping_uat_t *)g_hash_table_lookup(data_spdu_uds_mappings, key);
+ }
+
+ wmem_free(wmem_epan_scope(), key);
+
+ return tmp;
+}
+
/**************************************
******** Expert Infos ********
**************************************/
@@ -2058,7 +2183,7 @@ dissect_spdu_message_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo
static int
dissect_spdu_message_pdu_transport(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
- pdu_transport_info_t *pdu_info = (pdu_transport_info_t*)data;
+ pdu_transport_info_t *pdu_info = (pdu_transport_info_t *)data;
DISSECTOR_ASSERT(pdu_info);
spdu_pdu_transport_mapping_t *pdu_transport_mapping = get_pdu_transport_mapping(pdu_info->id);
@@ -2072,7 +2197,7 @@ dissect_spdu_message_pdu_transport(tvbuff_t *tvb, packet_info *pinfo, proto_tree
static int
dissect_spdu_message_ipdum(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
- autosar_ipdu_multiplexer_info_t *pdu_info = (autosar_ipdu_multiplexer_info_t*)data;
+ autosar_ipdu_multiplexer_info_t *pdu_info = (autosar_ipdu_multiplexer_info_t *)data;
DISSECTOR_ASSERT(pdu_info);
spdu_ipdum_mapping_uat_t *ipdum_mapping = get_ipdum_mapping(pdu_info->pdu_id);
@@ -2098,6 +2223,19 @@ dissect_spdu_message_dlt_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
return dissect_spdu_payload(tvb, pinfo, tree, dlt_mapping->message_id, TRUE);
}
+static gboolean
+dissect_spdu_message_uds_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
+ uds_info_t *uds_info = (uds_info_t *)data;
+ DISSECTOR_ASSERT(uds_info);
+
+ spdu_uds_mapping_t *uds_mapping = get_uds_mapping(uds_info);
+ if (uds_mapping == NULL) {
+ return FALSE;
+ }
+
+ return dissect_spdu_payload(tvb, pinfo, tree, uds_mapping->message_id, FALSE) != 0;
+}
+
/**************************************
******** Register Dissector ********
**************************************/
@@ -2122,7 +2260,7 @@ proto_register_signal_pdu(void) {
uat_t *spdu_pdu_transport_mapping_uat;
uat_t *spdu_ipdum_mapping_uat;
uat_t *spdu_dlt_mapping_uat;
-
+ uat_t *spdu_uds_mapping_uat;
/* data fields */
static hf_register_info hf[] = {
@@ -2222,6 +2360,15 @@ proto_register_signal_pdu(void) {
UAT_END_FIELDS
};
+ static uat_field_t spdu_uds_mapping_uat_fields[] = {
+ UAT_FLD_HEX(spdu_uds_mapping, uds_address, "ECU Address", "ECU Address (32bit hex without leading 0x, 0xffffffff means any)"),
+ UAT_FLD_HEX(spdu_uds_mapping, service, "UDS Service", "UDS Service (8bit hex without leading 0x)"),
+ UAT_FLD_BOOL(spdu_uds_mapping, reply, "Reply", "Reply [FALSE|TRUE]"),
+ UAT_FLD_HEX(spdu_uds_mapping, id, "ID", "ID (16bit hex without leading 0x)"),
+ UAT_FLD_HEX(spdu_uds_mapping, message_id, "Signal PDU ID", "ID of the Signal PDU (32bit hex without leading 0x)"),
+ UAT_END_FIELDS
+ };
+
static ei_register_info ei[] = {
{ &ef_spdu_payload_truncated, {"signal_pdu.payload.expert_truncated",
PI_MALFORMED, PI_ERROR, "Signal PDU: Truncated payload!", EXPFILL} },
@@ -2444,6 +2591,24 @@ proto_register_signal_pdu(void) {
prefs_register_uat_preference(spdu_module, "_spdu_dlt_mapping", "DLT Mappings",
"A table to map DLT non-verbose Payloads to Signal PDUs", spdu_dlt_mapping_uat);
+
+
+ spdu_uds_mapping_uat = uat_new("UDS",
+ sizeof(spdu_uds_mapping_uat_t), DATAFILE_SPDU_UDS_MAPPING, TRUE,
+ (void **)&spdu_uds_mapping,
+ &spdu_uds_mapping_num,
+ UAT_AFFECTS_DISSECTION,
+ NULL, /* help */
+ copy_spdu_uds_mapping_cb,
+ update_spdu_uds_mapping,
+ NULL,
+ post_update_spdu_uds_mapping_cb,
+ NULL, /* reset */
+ spdu_uds_mapping_uat_fields
+ );
+
+ prefs_register_uat_preference(spdu_module, "_spdu_uds_mapping", "UDS Mappings",
+ "A table to map UDS payloads to Signal PDUs", spdu_uds_mapping_uat);
}
void
@@ -2469,6 +2634,8 @@ proto_reg_handoff_signal_pdu(void) {
heur_dissector_add("dlt", dissect_spdu_message_dlt_heur, "Signal-PDU-Heuristic", "signal_pdu_dlt_heur", proto_signal_pdu, HEURISTIC_ENABLE);
+ heur_dissector_add("uds", dissect_spdu_message_uds_heur, "Signal-PDU-Heuristic", "signal_pdu_uds_heur", proto_signal_pdu, HEURISTIC_ENABLE);
+
initialized = TRUE;
}
}
diff --git a/epan/dissectors/packet-uds.c b/epan/dissectors/packet-uds.c
index ac9e96ad5a..13b38f6757 100644
--- a/epan/dissectors/packet-uds.c
+++ b/epan/dissectors/packet-uds.c
@@ -13,6 +13,7 @@
#include <epan/packet.h>
#include <epan/uat.h>
#include <wsutil/bits_ctz.h>
+#include <epan/dissectors/packet-uds.h>
#include <epan/dissectors/packet-doip.h>
#include <epan/dissectors/packet-iso10681.h>
#include <epan/dissectors/packet-iso15765.h>
@@ -23,30 +24,6 @@ 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
-#define UDS_SERVICES_RDTCI 0x19
-#define UDS_SERVICES_RDBI 0x22
-#define UDS_SERVICES_RMBA 0x23
-#define UDS_SERVICES_RSDBI 0x24
-#define UDS_SERVICES_SA 0x27
-#define UDS_SERVICES_CC 0x28
-#define UDS_SERVICES_RDBPI 0x2A
-#define UDS_SERVICES_DDDI 0x2C
-#define UDS_SERVICES_WDBI 0x2E
-#define UDS_SERVICES_IOCBI 0x2F
-#define UDS_SERVICES_RC 0x31
-#define UDS_SERVICES_RD 0x34
-#define UDS_SERVICES_RU 0x35
-#define UDS_SERVICES_TD 0x36
-#define UDS_SERVICES_RTE 0x37
-#define UDS_SERVICES_RFT 0x38
-#define UDS_SERVICES_WMBA 0x3D
-#define UDS_SERVICES_TP 0x3E
-#define UDS_SERVICES_ERR 0x3F
-#define UDS_SERVICES_CDTCS 0x85
-
#define UDS_RESPONSE_CODES_GR 0x10
#define UDS_RESPONSE_CODES_SNS 0x11
#define UDS_RESPONSE_CODES_SFNS 0x12
@@ -70,9 +47,6 @@ void proto_reg_handoff_uds(void);
#define UDS_RESPONSE_CODES_SFNSIAS 0x7E
#define UDS_RESPONSE_CODES_SNSIAS 0x7F
-
-#define UDS_SID_MASK 0xBF
-#define UDS_REPLY_MASK 0x40
#define UDS_SID_OFFSET 0
#define UDS_SID_LEN 1
#define UDS_DATA_OFFSET 1
@@ -386,6 +360,9 @@ static dissector_handle_t uds_handle_doip;
static dissector_handle_t uds_handle_iso10681;
static dissector_handle_t uds_handle_iso15765;
+/*** Subdissectors ***/
+static heur_dissector_list_t heur_subdissector_list;
+static heur_dtbl_entry_t *heur_dtbl_entry;
/*** Configuration ***/
typedef struct _generic_addr_id_string {
@@ -609,6 +586,19 @@ tvb_get_guintX(tvbuff_t *tvb, const gint offset, const gint size, const guint en
return 0;
}
+gboolean
+call_heur_subdissector_uds(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 service, gboolean reply, guint32 id, guint32 uds_address)
+{
+ uds_info_t uds_info;
+
+ uds_info.id = id;
+ uds_info.uds_address = uds_address;
+ uds_info.reply = reply;
+ uds_info.service = service;
+
+ return dissector_try_heuristic(heur_subdissector_list, tvb, pinfo, tree, &heur_dtbl_entry, &uds_info);
+}
+
static int
dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 source_address, guint16 target_address, guint8 number_of_addresses_valid)
{
@@ -619,6 +609,7 @@ dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint1
const char *service_name;
guint32 ecu_address;
guint32 data_length = tvb_reported_length(tvb);
+ tvbuff_t *payload_tvb;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDS");
col_clear(pinfo->cinfo,COL_INFO);
@@ -700,6 +691,10 @@ dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint1
proto_tree_add_item(subtree, hf_uds_rdbi_data_record, tvb, UDS_RDBI_DATA_RECORD_OFFSET,
record_length, ENC_NA);
+
+ payload_tvb = tvb_new_subset_length(tvb, UDS_RDBI_DATA_RECORD_OFFSET, record_length);
+ call_heur_subdissector_uds(payload_tvb, pinfo, tree, service, TRUE, data_identifier, ecu_address);
+
col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", data_identifier);
infocol_append_data_name(pinfo, ecu_address, data_identifier);
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
@@ -761,6 +756,10 @@ dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint1
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);
+
+ payload_tvb = tvb_new_subset_length(tvb, UDS_WDBI_DATA_RECORD_OFFSET, record_length);
+ call_heur_subdissector_uds(payload_tvb, pinfo, tree, service, FALSE, enum_val, ecu_address);
+
col_append_fstr(pinfo->cinfo, COL_INFO, " 0x%04x", enum_val);
infocol_append_data_name(pinfo, ecu_address, enum_val);
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
@@ -820,6 +819,9 @@ dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint1
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
tvb_bytes_to_str_punct(pinfo->pool, tvb,
UDS_RC_STATUS_RECORD_OFFSET, status_record_len, ' '));
+
+ payload_tvb = tvb_new_subset_length(tvb, UDS_RC_STATUS_RECORD_OFFSET, status_record_len);
+ call_heur_subdissector_uds(payload_tvb, pinfo, tree, service, TRUE, identifier, ecu_address);
}
}
} else {
@@ -830,6 +832,9 @@ dissect_uds_internal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint1
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
tvb_bytes_to_str_punct(pinfo->pool, tvb,
UDS_RC_OPTION_RECORD_OFFSET, option_record_len, ' '));
+
+ payload_tvb = tvb_new_subset_length(tvb, UDS_RC_OPTION_RECORD_OFFSET, option_record_len);
+ call_heur_subdissector_uds(payload_tvb, pinfo, tree, service, FALSE, identifier, ecu_address);
}
}
break;
@@ -1441,6 +1446,8 @@ proto_register_uds(void)
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);
+
+ heur_subdissector_list = register_heur_dissector_list("uds", proto_uds);
}
void
diff --git a/epan/dissectors/packet-uds.h b/epan/dissectors/packet-uds.h
new file mode 100644
index 0000000000..49910b2d79
--- /dev/null
+++ b/epan/dissectors/packet-uds.h
@@ -0,0 +1,63 @@
+/* packet-uds.h
+ * ISO 14229-2 ISO UDS
+ * By Dr. Lars Voelker <lars.voelker@technica-engineering.de>
+ * Copyright 2021-2021 Dr. Lars Voelker
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __PACKET_UDS_H__
+#define __PACKET_UDS_H__
+
+#define UDS_SID_MASK 0xBF
+#define UDS_REPLY_MASK 0x40
+
+#define UDS_SERVICES_DSC 0x10
+#define UDS_SERVICES_ER 0x11
+#define UDS_SERVICES_CDTCI 0x14
+#define UDS_SERVICES_RDTCI 0x19
+#define UDS_SERVICES_RDBI 0x22
+#define UDS_SERVICES_RMBA 0x23
+#define UDS_SERVICES_RSDBI 0x24
+#define UDS_SERVICES_SA 0x27
+#define UDS_SERVICES_CC 0x28
+#define UDS_SERVICES_RDBPI 0x2A
+#define UDS_SERVICES_DDDI 0x2C
+#define UDS_SERVICES_WDBI 0x2E
+#define UDS_SERVICES_IOCBI 0x2F
+#define UDS_SERVICES_RC 0x31
+#define UDS_SERVICES_RD 0x34
+#define UDS_SERVICES_RU 0x35
+#define UDS_SERVICES_TD 0x36
+#define UDS_SERVICES_RTE 0x37
+#define UDS_SERVICES_RFT 0x38
+#define UDS_SERVICES_WMBA 0x3D
+#define UDS_SERVICES_TP 0x3E
+#define UDS_SERVICES_ERR 0x3F
+#define UDS_SERVICES_CDTCS 0x85
+
+typedef struct uds_info {
+ guint32 id;
+ guint32 uds_address;
+ gboolean reply;
+ guint8 service;
+} uds_info_t;
+
+#endif /* __PACKET_UDS_H__ */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */