aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-socketcan.c
diff options
context:
space:
mode:
authorDr. Lars Völker <lars.voelker@technica-engineering.de>2021-08-01 18:38:34 +0200
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-08-06 03:05:51 +0000
commita030a70bde0674df374eb7c0c9ed748e406e037f (patch)
treefaf87d7631f859dd4ee6390d1d5ad28ba91bdf98 /epan/dissectors/packet-socketcan.c
parentc2d7ed28af3b53d6d08cf711f302164a2ac05df6 (diff)
CAN: Add support for multiple CANs in a trace (bus ID)
This patch allows CAN frames coming in over SocketCAN and TECMP to be differentiated in order to follow up with different parsing in the Signal PDU dissector et. al.
Diffstat (limited to 'epan/dissectors/packet-socketcan.c')
-rw-r--r--epan/dissectors/packet-socketcan.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/epan/dissectors/packet-socketcan.c b/epan/dissectors/packet-socketcan.c
index 0c4c2023ac..739cfb0f6e 100644
--- a/epan/dissectors/packet-socketcan.c
+++ b/epan/dissectors/packet-socketcan.c
@@ -19,6 +19,7 @@
#include <epan/prefs.h>
#include <epan/expert.h>
#include <epan/decode_as.h>
+#include <epan/uat.h>
#include <wiretap/wtap.h>
#include "packet-sll.h"
@@ -155,6 +156,176 @@ static const value_string can_err_trx_canl_vals[] =
{ 0, NULL }
};
+/********* UATs *********/
+
+/* Interface Config UAT */
+typedef struct _interface_config {
+ guint interface_id;
+ gchar *interface_name;
+ guint bus_id;
+} interface_config_t;
+
+#define DATAFILE_CAN_INTERFACE_MAPPING "CAN_interface_mapping"
+
+static GHashTable *data_can_interfaces_by_id = NULL;
+static GHashTable *data_can_interfaces_by_name = NULL;
+static interface_config_t* interface_configs = NULL;
+static guint interface_config_num = 0;
+
+UAT_HEX_CB_DEF(interface_configs, interface_id, interface_config_t)
+UAT_CSTRING_CB_DEF(interface_configs, interface_name, interface_config_t)
+UAT_HEX_CB_DEF(interface_configs, bus_id, interface_config_t)
+
+static void *
+copy_interface_config_cb(void *n, const void *o, size_t size _U_) {
+ interface_config_t *new_rec = (interface_config_t *)n;
+ const interface_config_t *old_rec = (const interface_config_t *)o;
+
+ new_rec->interface_id = old_rec->interface_id;
+ new_rec->interface_name = g_strdup(old_rec->interface_name);
+ new_rec->bus_id = old_rec->bus_id;
+ return new_rec;
+}
+
+static gboolean
+update_interface_config(void *r, char **err) {
+ interface_config_t *rec = (interface_config_t *)r;
+
+ if (rec->interface_id > 0xffffffff) {
+ *err = g_strdup_printf("We currently only support 32 bit identifiers (ID: %i Name: %s)",
+ rec->interface_id, rec->interface_name);
+ return FALSE;
+ }
+
+ if (rec->bus_id > 0xffff) {
+ *err = g_strdup_printf("We currently only support 16 bit bus identifiers (ID: %i Name: %s Bus-ID: %i)",
+ rec->interface_id, rec->interface_name, rec->bus_id);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+free_interface_config_cb(void *r) {
+ interface_config_t *rec = (interface_config_t *)r;
+ /* freeing result of g_strdup */
+ g_free(rec->interface_name);
+ rec->interface_name = NULL;
+}
+
+static interface_config_t *
+ht_lookup_interface_config_by_id(unsigned int identifier) {
+ interface_config_t *tmp = NULL;
+ unsigned int *id = NULL;
+
+ if (interface_configs == NULL) {
+ return NULL;
+ }
+
+ id = wmem_new(wmem_epan_scope(), unsigned int);
+ *id = (unsigned int)identifier;
+ tmp = (interface_config_t *)g_hash_table_lookup(data_can_interfaces_by_id, id);
+ wmem_free(wmem_epan_scope(), id);
+
+ return tmp;
+}
+
+static interface_config_t *
+ht_lookup_interface_config_by_name(const gchar *name) {
+ interface_config_t *tmp = NULL;
+ gchar *key = NULL;
+
+ if (interface_configs == NULL) {
+ return NULL;
+ }
+
+ key = wmem_strdup(wmem_epan_scope(), name);
+ tmp = (interface_config_t *)g_hash_table_lookup(data_can_interfaces_by_name, key);
+ wmem_free(wmem_epan_scope(), key);
+
+ return tmp;
+}
+
+static void
+can_free_key(gpointer key) {
+ wmem_free(wmem_epan_scope(), key);
+}
+
+static void
+post_update_can_interfaces_cb(void) {
+ guint i;
+ int *key_id = NULL;
+ gchar *key_name = NULL;
+
+ /* destroy old hash tables, if they exist */
+ if (data_can_interfaces_by_id) {
+ g_hash_table_destroy(data_can_interfaces_by_id);
+ data_can_interfaces_by_id = NULL;
+ }
+ if (data_can_interfaces_by_name) {
+ g_hash_table_destroy(data_can_interfaces_by_name);
+ data_can_interfaces_by_name = NULL;
+ }
+
+ /* create new hash table */
+ data_can_interfaces_by_id = g_hash_table_new_full(g_int_hash, g_int_equal, &can_free_key, NULL);
+ data_can_interfaces_by_name = g_hash_table_new_full(g_str_hash, g_str_equal, &can_free_key, NULL);
+
+ if (data_can_interfaces_by_id == NULL || data_can_interfaces_by_name == NULL || interface_configs == NULL || interface_config_num == 0) {
+ return;
+ }
+
+ for (i = 0; i < interface_config_num; i++) {
+ if (interface_configs[i].interface_id != 0xfffffff) {
+ key_id = wmem_new(wmem_epan_scope(), int);
+ *key_id = interface_configs[i].interface_id;
+ g_hash_table_insert(data_can_interfaces_by_id, key_id, &interface_configs[i]);
+ }
+
+ if (interface_configs[i].interface_name != NULL && interface_configs[i].interface_name[0] != 0) {
+ key_name = wmem_strdup(wmem_epan_scope(), interface_configs[i].interface_name);
+ g_hash_table_insert(data_can_interfaces_by_name, key_name, &interface_configs[i]);
+ }
+ }
+}
+
+/* We match based on the config in the following order:
+ * - interface_name matches and interface_id matches
+ * - interface_name matches and interface_id = 0xffffffff
+ * - interface_name = "" and interface_id matches
+ */
+
+static guint
+get_bus_id(packet_info *pinfo) {
+ guint32 interface_id = pinfo->rec->rec_header.packet_header.interface_id;
+ const char *interface_name = epan_get_interface_name(pinfo->epan, interface_id);
+ interface_config_t *tmp = NULL;
+
+ if (!(pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID)) {
+ return 0;
+ }
+
+ if (interface_name != NULL && interface_name[0] != 0) {
+ tmp = ht_lookup_interface_config_by_name(interface_name);
+
+ if (tmp != NULL && (tmp->interface_id == 0xffffffff || tmp->interface_id == interface_id)) {
+ /* name + id match or name match and id = any */
+ return tmp->bus_id;
+ }
+
+ tmp = ht_lookup_interface_config_by_id(interface_id);
+
+ if (tmp != NULL && (tmp->interface_name == NULL || tmp->interface_name[0] == 0)) {
+ /* id matches and name is any */
+ return tmp->bus_id;
+ }
+ }
+
+ /* we found nothing */
+ return 0;
+}
+
gboolean
socketcan_call_subdissectors(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, struct can_info* can_info, const gboolean use_heuristics_first)
{
@@ -229,6 +400,7 @@ dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu
can_info.id = tvb_get_guint32(tvb, 0, encoding);
can_info.len = tvb_get_guint8(tvb, CAN_LEN_OFFSET);
can_info.fd = FALSE;
+ can_info.bus_id = get_bus_id(pinfo);
/* Error Message Frames are only encapsulated in Classic CAN frames */
if (can_info.id & CAN_ERR_FLAG)
@@ -394,6 +566,7 @@ dissect_socketcanfd_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
can_info.id = tvb_get_guint32(tvb, 0, encoding);
can_info.len = tvb_get_guint8(tvb, CAN_LEN_OFFSET);
can_info.fd = TRUE;
+ can_info.bus_id = get_bus_id(pinfo);
if (can_info.id & CAN_EFF_FLAG)
{
@@ -811,6 +984,7 @@ proto_register_socketcan(void)
}
},
};
+ uat_t *can_interface_uat = NULL;
/* Setup protocol subtree array */
static gint *ett[] =
@@ -864,6 +1038,32 @@ proto_register_socketcan(void)
subdissector_table = register_decode_as_next_proto(proto_can, "can.subdissector", "CAN next level dissector", NULL);
heur_subdissector_list = register_heur_dissector_list("can", proto_can);
+
+ static uat_field_t can_interface_mapping_uat_fields[] = {
+ UAT_FLD_HEX(interface_configs, interface_id, "Interface ID", "ID of the Interface with 0xffffffff = any (hex uint32 without leading 0x)"),
+ UAT_FLD_CSTRING(interface_configs, interface_name, "Interface Name", "Name of the Interface, empty = any (string)"),
+ UAT_FLD_HEX(interface_configs, bus_id, "Bus ID", "Bus ID of the Interface (hex uint16 without leading 0x)"),
+ UAT_END_FIELDS
+ };
+
+ can_interface_uat = uat_new("CAN Interface Mapping",
+ sizeof(interface_config_t), /* record size */
+ DATAFILE_CAN_INTERFACE_MAPPING, /* filename */
+ TRUE, /* from profile */
+ (void**)&interface_configs, /* data_ptr */
+ &interface_config_num, /* numitems_ptr */
+ UAT_AFFECTS_DISSECTION, /* but not fields */
+ NULL, /* help */
+ copy_interface_config_cb, /* copy callback */
+ update_interface_config, /* update callback */
+ free_interface_config_cb, /* free callback */
+ post_update_can_interfaces_cb, /* post update callback */
+ NULL, /* reset callback */
+ can_interface_mapping_uat_fields /* UAT field definitions */
+ );
+
+ prefs_register_uat_preference(can_module, "_can_interface_mapping", "Interface Mapping",
+ "A table to define the mapping between interface and Bus ID.", can_interface_uat);
}
void