LIN: Add support for bus specific dissectors

Since typically multiple LINs are used in parallel the IDs of the
small ID space are reused. This patch adds support for handling
multiple LIN ID spaces in parallel.
This commit is contained in:
Dr. Lars Völker 2021-07-22 21:35:04 +02:00 committed by Wireshark GitLab Utility
parent 6d02f1dcf9
commit aac942e44b
4 changed files with 394 additions and 84 deletions

View File

@ -18,6 +18,7 @@
#include <epan/prefs.h>
#include <wiretap/wtap.h>
#include <epan/expert.h>
#include <epan/uat.h>
#include <packet-lin.h>
@ -107,6 +108,175 @@ static const value_string lin_event_type_names[] = {
void proto_reg_handoff_lin(void);
void proto_register_lin(void);
/********* UATs *********/
/* Interface Config UAT */
typedef struct _interface_config {
guint interface_id;
gchar *interface_name;
guint bus_id;
} interface_config_t;
#define DATAFILE_LIN_INTERFACE_MAPPING "LIN_interface_mapping"
static GHashTable *data_lin_interfaces_by_id = NULL;
static GHashTable *data_lin_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_lin_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_lin_interfaces_by_name, key);
wmem_free(wmem_epan_scope(), key);
return tmp;
}
static void
lin_free_key(gpointer key) {
wmem_free(wmem_epan_scope(), key);
}
static void
post_update_lin_interfaces_cb(void) {
guint i;
int *key_id = NULL;
gchar *key_name = NULL;
/* destroy old hash tables, if they exist */
if (data_lin_interfaces_by_id) {
g_hash_table_destroy(data_lin_interfaces_by_id);
data_lin_interfaces_by_id = NULL;
}
if (data_lin_interfaces_by_name) {
g_hash_table_destroy(data_lin_interfaces_by_name);
data_lin_interfaces_by_name = NULL;
}
/* create new hash table */
data_lin_interfaces_by_id = g_hash_table_new_full(g_int_hash, g_int_equal, &lin_free_key, NULL);
data_lin_interfaces_by_name = g_hash_table_new_full(g_str_hash, g_str_equal, &lin_free_key, NULL);
if (data_lin_interfaces_by_id == NULL || data_lin_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_lin_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_lin_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;
}
static int
dissect_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
@ -123,7 +293,6 @@ dissect_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
col_set_str(pinfo->cinfo, COL_PROTOCOL, LIN_NAME);
col_clear(pinfo->cinfo, COL_INFO);
// TODO: Set end later!?
ti_root = proto_tree_add_item(tree, proto_lin, tvb, 0, -1, ENC_NA);
lin_tree = proto_item_add_subtree(ti_root, ett_lin);
@ -156,13 +325,20 @@ dissect_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
return 12; /* 8 Byte header + 4 Byte payload */
}
break;
case LIN_MSG_TYPE_FRAME:
if (payload_length > 0) {
next_tvb = tvb_new_subset_length(tvb, 8, payload_length);
lininfo.len = payload_length;
if (!dissector_try_uint_new(subdissector_table, lininfo.id, next_tvb, pinfo, tree, TRUE, &lininfo)) {
if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &heur_dtbl_entry, &lininfo)) {
call_data_dissector(next_tvb, pinfo, tree);
proto_item_set_end(ti_root, tvb, 8 + payload_length);
lininfo.len = (guint16)payload_length;
lininfo.bus_id = (guint16)get_bus_id(pinfo);
guint32 bus_frame_id = lininfo.id | (lininfo.bus_id << 16);
if (!dissector_try_uint_new(subdissector_table, bus_frame_id, next_tvb, pinfo, tree, TRUE, &lininfo)) {
if (!dissector_try_uint_new(subdissector_table, lininfo.id, next_tvb, pinfo, tree, TRUE, &lininfo)) {
if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &heur_dtbl_entry, &lininfo)) {
call_data_dissector(next_tvb, pinfo, tree);
}
}
}
}
@ -183,7 +359,8 @@ dissect_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
void
proto_register_lin(void) {
//module_t *lin_module;
module_t *lin_module;
uat_t *lin_interface_uat = NULL;
static hf_register_info hf[] = {
{ &hf_lin_msg_format_rev,
@ -246,15 +423,42 @@ proto_register_lin(void) {
};
proto_lin = proto_register_protocol(LIN_NAME_LONG, LIN_NAME, LIN_NAME_FILTER);
//lin_module = prefs_register_protocol(proto_lin, NULL);
lin_module = prefs_register_protocol(proto_lin, NULL);
proto_register_field_array(proto_lin, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_dissector(LIN_NAME_FILTER, dissect_lin, proto_lin);
/* the lin.frame_id subdissector table carries the bus id in the higher 16 bits */
subdissector_table = register_dissector_table("lin.frame_id", "LIN Frame ID", proto_lin, FT_UINT8, BASE_HEX);
heur_subdissector_list = register_heur_dissector_list(LIN_NAME_FILTER, proto_lin);
static uat_field_t lin_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
};
lin_interface_uat = uat_new("LIN Interface Mapping",
sizeof(interface_config_t), /* record size */
DATAFILE_LIN_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_lin_interfaces_cb, /* post update callback */
NULL, /* reset callback */
lin_interface_mapping_uat_fields /* UAT field definitions */
);
prefs_register_uat_preference(lin_module, "_lin_interface_mapping", "Interface Mapping",
"A table to define the mapping between interface and Bus ID.", lin_interface_uat);
}
void

View File

@ -16,10 +16,13 @@
#define LIN_DIAG_MASTER_REQUEST_FRAME 0x3c
#define LIN_DIAG_SLAVE_RESPONSE_FRAME 0x3d
#define LIN_ID_MASK 0x3f
/* bus_id 0 means ANY Bus */
struct lin_info {
guint32 id;
guint32 len;
guint16 bus_id;
guint16 len;
};
typedef struct lin_info lin_info_t;

View File

@ -222,6 +222,7 @@ typedef spdu_flexray_mapping_t spdu_flexray_mapping_uat_t;
typedef struct _spdu_lin_mapping {
guint32 frame_id;
guint32 bus_id;
guint32 message_id;
} spdu_lin_mapping_t;
typedef spdu_lin_mapping_t spdu_lin_mapping_uat_t;
@ -302,9 +303,8 @@ proto_reg_handoff_signal_pdu_lin(void) {
GList *tmp;
for (tmp = keys; tmp != NULL; tmp = tmp->next) {
gint32 *id = (gint32*)tmp->data;
/* LIN Frame IDs are only 6 bit long */
guint8 frame_id = (guint8)((guint32)(*id)) & 0xcf;
dissector_add_uint("lin.frame_id", frame_id, signal_pdu_handle_lin);
/* we register the combination of bus and frame id */
dissector_add_uint("lin.frame_id", *id, signal_pdu_handle_lin);
}
}
}
@ -1169,6 +1169,7 @@ get_flexray_mapping(guint8 channel, guint8 cycle, guint16 flexray_id) {
/* UAT: LIN Mapping */
UAT_HEX_CB_DEF(spdu_lin_mapping, frame_id, spdu_lin_mapping_uat_t)
UAT_HEX_CB_DEF(spdu_lin_mapping, bus_id, spdu_lin_mapping_uat_t)
UAT_HEX_CB_DEF(spdu_lin_mapping, message_id, spdu_lin_mapping_uat_t)
static void *
@ -1177,6 +1178,7 @@ copy_spdu_lin_mapping_cb(void *n, const void *o, size_t size _U_) {
const spdu_lin_mapping_uat_t *old_rec = (const spdu_lin_mapping_uat_t*)o;
new_rec->frame_id = old_rec->frame_id;
new_rec->bus_id = old_rec->bus_id;
new_rec->message_id = old_rec->message_id;
return new_rec;
@ -1186,11 +1188,16 @@ static gboolean
update_spdu_lin_mapping(void *r, char **err) {
spdu_lin_mapping_uat_t *rec = (spdu_lin_mapping_uat_t *)r;
if (rec->frame_id > 0xcf) {
if (rec->frame_id > LIN_ID_MASK) {
*err = g_strdup_printf("LIN Frame IDs are only uint with 6 bits (ID: %i)", rec->frame_id);
return FALSE;
}
if (rec->bus_id > 0xffff) {
*err = g_strdup_printf("LIN Bus IDs are only uint with 16 bits (ID: 0x%x, Bus ID: 0x%x)", rec->frame_id, rec->bus_id);
return FALSE;
}
return TRUE;
}
@ -1213,7 +1220,8 @@ post_update_spdu_lin_mapping_cb(void) {
guint i;
for (i = 0; i < spdu_lin_mapping_num; i++) {
gint *key = wmem_new(wmem_epan_scope(), gint);
*key = spdu_lin_mapping[i].frame_id;
*key = (spdu_lin_mapping[i].frame_id)&LIN_ID_MASK;
*key |= ((spdu_lin_mapping[i].bus_id) & 0xffff) << 16;
g_hash_table_insert(data_spdu_lin_mappings, key, &spdu_lin_mapping[i]);
}
@ -1224,15 +1232,23 @@ post_update_spdu_lin_mapping_cb(void) {
}
static spdu_lin_mapping_t*
get_lin_mapping(guint32 lin_id) {
get_lin_mapping(lin_info_t *lininfo) {
if (data_spdu_lin_mappings == NULL) {
return NULL;
}
gint32 *key = wmem_new(wmem_epan_scope(), gint32);
*key = lin_id;
*key = (lininfo->id)&LIN_ID_MASK;
*key |= ((lininfo->bus_id) & 0xffff) << 16;
spdu_lin_mapping_uat_t *tmp = (spdu_lin_mapping_uat_t*)g_hash_table_lookup(data_spdu_lin_mappings, key);
if (tmp == NULL) {
/* try again without Bus ID set */
*key = (lininfo->id) & LIN_ID_MASK;
tmp = (spdu_lin_mapping_uat_t*)g_hash_table_lookup(data_spdu_lin_mappings, key);
}
wmem_free(wmem_epan_scope(), key);
return tmp;
@ -1615,7 +1631,7 @@ dissect_spdu_message_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo
DISSECTOR_ASSERT(lininfo);
spdu_lin_mapping_t *lin_mapping = get_lin_mapping(lininfo->id);
spdu_lin_mapping_t *lin_mapping = get_lin_mapping(lininfo);
if (lin_mapping == NULL) {
return 0;
@ -1736,6 +1752,7 @@ proto_register_signal_pdu(void) {
static uat_field_t spdu_lin_mapping_uat_fields[] = {
UAT_FLD_HEX(spdu_lin_mapping, frame_id, "Frame ID", "LIN Frame ID (6bit hex without leading 0x)"),
UAT_FLD_HEX(spdu_lin_mapping, bus_id , "Bus ID", "Bus ID on which frame was recorded with 0=any (16bit hex without leading 0x)"),
UAT_FLD_HEX(spdu_lin_mapping, message_id, "Signal PDU ID", "ID of the Signal PDU (32bit hex without leading 0x)"),
UAT_END_FIELDS
};

View File

@ -75,8 +75,6 @@ static int hf_tecmp_payload_timestamp_res = -1;
static int hf_tecmp_payload_length = -1;
static int hf_tecmp_payload_data = -1;
static int hf_tecmp_payload_data_length = -1;
static int hf_tecmp_payload_data_payload = -1;
static int hf_tecmp_payload_data_payload_ascii = -1;
/* TECMP Payload flags */
/* Generic */
@ -432,6 +430,32 @@ typedef struct _generic_one_id_string {
gchar *name;
} generic_one_id_string_t;
/* Channel UAT */
typedef struct _channel_config {
guint id;
guint bus_id;
gchar *name;
} channel_config_t;
#define DATAFILE_TECMP_CM_IDS "TECMP_capture_module_identifiers"
#define DATAFILE_TECMP_CH_IDS "TECMP_channel_identifiers"
static GHashTable *data_tecmp_cms = NULL;
static generic_one_id_string_t* tecmp_cms = NULL;
static guint tecmp_cms_num = 0;
UAT_DEC_CB_DEF(tecmp_cms, id, generic_one_id_string_t)
UAT_CSTRING_CB_DEF(tecmp_cms, name, generic_one_id_string_t)
static GHashTable *data_tecmp_channels = NULL;
static channel_config_t* tecmp_channels = NULL;
static guint tecmp_channel_num = 0;
UAT_HEX_CB_DEF(tecmp_channels, id, channel_config_t)
UAT_CSTRING_CB_DEF(tecmp_channels, name, channel_config_t)
UAT_HEX_CB_DEF(tecmp_channels, bus_id, channel_config_t)
/* generic UAT */
static void
tecmp_free_key(gpointer key) {
wmem_free(wmem_epan_scope(), key);
@ -445,9 +469,9 @@ simple_free(gpointer 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;
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;
@ -471,26 +495,9 @@ update_generic_one_identifier_16bit(void *r, char **err) {
return TRUE;
}
static gboolean
update_generic_one_identifier_32bit(void *r, char **err) {
generic_one_id_string_t *rec = (generic_one_id_string_t *)r;
if (rec->id > 0xffffffff) {
*err = g_strdup_printf("We currently only support 32 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;
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;
@ -509,8 +516,8 @@ post_update_one_id_string_template_cb(generic_one_id_string_t *data, guint data_
}
}
static char*
ht_lookup_name(GHashTable* ht, unsigned int identifier) {
static char *
ht_lookup_name(GHashTable *ht, unsigned int identifier) {
char *tmp = NULL;
unsigned int *id = NULL;
@ -526,23 +533,87 @@ ht_lookup_name(GHashTable* ht, unsigned int identifier) {
return tmp;
}
/* ID -> ID, Name */
static void *
copy_channel_config_cb(void *n, const void *o, size_t size _U_) {
channel_config_t *new_rec = (channel_config_t *)n;
const channel_config_t *old_rec = (const channel_config_t *)o;
new_rec->id = old_rec->id;
new_rec->name = g_strdup(old_rec->name);
new_rec->bus_id = old_rec->bus_id;
return new_rec;
}
static gboolean
update_channel_config(void *r, char **err) {
channel_config_t *rec = (channel_config_t *)r;
if (rec->id > 0xffffffff) {
*err = g_strdup_printf("We currently only support 32 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;
}
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->id, rec->name, rec->bus_id);
return FALSE;
}
return TRUE;
}
static void
free_channel_config_cb(void *r) {
channel_config_t *rec = (channel_config_t *)r;
/* freeing result of g_strdup */
g_free(rec->name);
rec->name = NULL;
}
static channel_config_t *
ht_lookup_channel_config(unsigned int identifier) {
channel_config_t *tmp = NULL;
unsigned int *id = NULL;
if (data_tecmp_channels == NULL) {
return NULL;
}
id = wmem_new(wmem_epan_scope(), unsigned int);
*id = (unsigned int)identifier;
tmp = (channel_config_t *)g_hash_table_lookup(data_tecmp_channels, id);
wmem_free(wmem_epan_scope(), id);
return tmp;
}
static gchar *
ht_channel_config_to_string(unsigned int identifier) {
channel_config_t *tmp = ht_lookup_channel_config(identifier);
if (tmp == NULL) {
return NULL;
}
return tmp->name;
}
static guint16
ht_channel_config_to_bus_id(unsigned int identifier) {
channel_config_t *tmp = ht_lookup_channel_config(identifier);
if (tmp == NULL) {
/* 0 means basically any or none */
return 0;
}
return tmp->bus_id;
}
/*** UAT TECMP_CM_IDs ***/
#define DATAFILE_TECMP_CM_IDS "TECMP_capture_module_identifiers"
#define DATAFILE_TECMP_CH_IDS "TECMP_channel_identifiers"
static GHashTable *data_tecmp_cms = NULL;
static generic_one_id_string_t* tecmp_cms = NULL;
static guint tecmp_cms_num = 0;
UAT_DEC_CB_DEF(tecmp_cms, id, generic_one_id_string_t)
UAT_CSTRING_CB_DEF(tecmp_cms, name, generic_one_id_string_t)
static GHashTable *data_tecmp_channels = NULL;
static generic_one_id_string_t* tecmp_channels = NULL;
static guint tecmp_channel_num = 0;
UAT_HEX_CB_DEF(tecmp_channels, id, generic_one_id_string_t)
UAT_CSTRING_CB_DEF(tecmp_channels, name, generic_one_id_string_t)
static void
post_update_tecmp_cms_cb(void) {
@ -559,6 +630,9 @@ post_update_tecmp_cms_cb(void) {
static void
post_update_tecmp_channels_cb(void) {
guint i;
int *key = NULL;
/* destroy old hash table, if it exists */
if (data_tecmp_channels) {
g_hash_table_destroy(data_tecmp_channels);
@ -566,10 +640,18 @@ post_update_tecmp_channels_cb(void) {
}
/* create new hash table */
data_tecmp_channels = g_hash_table_new_full(g_int_hash, g_int_equal, &tecmp_free_key, &simple_free);
post_update_one_id_string_template_cb(tecmp_channels, tecmp_channel_num, data_tecmp_channels);
}
data_tecmp_channels = g_hash_table_new_full(g_int_hash, g_int_equal, &tecmp_free_key, NULL);
if (data_tecmp_channels == NULL || tecmp_channels == NULL || tecmp_channel_num == 0) {
return;
}
for (i = 0; i < tecmp_channel_num; i++) {
key = wmem_new(wmem_epan_scope(), int);
*key = tecmp_channels[i].id;
g_hash_table_insert(data_tecmp_channels, key, &tecmp_channels[i]);
}
}
static void
add_cm_id_text(proto_item *ti, guint16 cm_id) {
@ -592,8 +674,9 @@ add_cm_id_text(proto_item *ti, guint16 cm_id) {
}
static void
add_channel_id_text_and_name(proto_item *ti, guint32 channel_id, tvbuff_t *tvb, gint offset) {
const gchar *descr = ht_lookup_name(data_tecmp_channels, channel_id);
const gchar *descr = ht_channel_config_to_string(channel_id);
if (descr != NULL) {
proto_item_append_text(ti, " (%s)", descr);
@ -621,7 +704,7 @@ tecmp_entry_header_present(tvbuff_t *tvb, guint offset) {
static guint
dissect_tecmp_entry_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset_orig, guint16 msg_type,
gboolean first, guint16 *dataflags) {
gboolean first, guint16 *dataflags, guint32 *channel_id) {
proto_item *ti;
proto_tree *subtree = NULL;
guint offset = offset_orig;
@ -704,6 +787,9 @@ dissect_tecmp_entry_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
ti = proto_tree_add_item_ret_uint(tree, hf_tecmp_payload_channelid, tvb, offset, 4, ENC_BIG_ENDIAN, &tmp);
add_channel_id_text_and_name(ti, tmp, tvb, offset);
if (channel_id != NULL) {
*channel_id = tmp;
}
ns = tvb_get_guint64(tvb, offset + 4, ENC_BIG_ENDIAN) & 0x3fffffffffffffff;
@ -939,7 +1025,7 @@ dissect_tecmp_control_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
proto_item_append_text(ti, " Control Message");
tecmp_tree = proto_item_add_subtree(ti, ett_tecmp_payload);
offset += dissect_tecmp_entry_header(tvb, pinfo, tecmp_tree, offset, msg_type, TRUE, NULL);
offset += dissect_tecmp_entry_header(tvb, pinfo, tecmp_tree, offset, msg_type, TRUE, NULL, NULL);
col_set_str(pinfo->cinfo, COL_INFO, "TECMP Control Message");
@ -976,7 +1062,7 @@ dissect_tecmp_status_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gui
ti_tecmp_payload = proto_tree_add_item(tree, proto_tecmp_payload, tvb, offset, (gint)length + 16, ENC_NA);
tecmp_tree = proto_item_add_subtree(ti_tecmp_payload, ett_tecmp_payload);
offset += dissect_tecmp_entry_header(tvb, pinfo, tecmp_tree, offset, msg_type, TRUE, NULL);
offset += dissect_tecmp_entry_header(tvb, pinfo, tecmp_tree, offset, msg_type, TRUE, NULL, NULL);
proto_tree_add_item_ret_uint(tecmp_tree, hf_tecmp_payload_status_vendor_id, tvb, offset, 1, ENC_NA,
&vendor_id);
@ -1030,7 +1116,7 @@ dissect_tecmp_status_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gui
ti = proto_tree_add_item_ret_uint(tecmp_tree_bus, hf_tecmp_payload_status_bus_channelid, tvb, offset, 4,
ENC_NA, &tmp);
descr = ht_lookup_name(data_tecmp_channels, tmp);
descr = ht_channel_config_to_string(tmp);
if (descr != NULL) {
proto_item_append_text(ti, " (%s)", descr);
proto_item_append_text(ti_tecmp_bus, ": (Channel ID: 0x%08x, %s)", tmp, descr);
@ -1096,6 +1182,7 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
tvbuff_t *sub_tvb;
tvbuff_t *payload_tvb;
gboolean first = TRUE;
guint32 channel_id = 0;
gdouble analog_value_scale_factor;
@ -1129,7 +1216,7 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
proto_item_append_text(ti_tecmp, " (%s)", val_to_str(msg_type, tecmp_msgtype_names, "Unknown (%d)"));
tecmp_tree = proto_item_add_subtree(ti_tecmp, ett_tecmp_payload);
offset += dissect_tecmp_entry_header(tvb, pinfo, tecmp_tree, offset, msg_type, first, &dataflags);
offset += dissect_tecmp_entry_header(tvb, pinfo, tecmp_tree, offset, msg_type, first, &dataflags, &channel_id);
first = FALSE;
@ -1140,6 +1227,7 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
switch (msg_type) {
case TECMP_DATA_TYPE_LIN:
proto_tree_add_item_ret_uint(tecmp_tree, hf_tecmp_payload_data_id_field_8bit, sub_tvb, offset2, 1, ENC_NA, &(lin_info.id));
lin_info.bus_id = ht_channel_config_to_bus_id(channel_id);
ti = proto_tree_add_item_ret_uint(tecmp_tree, hf_tecmp_payload_data_length, sub_tvb, offset2 + 1, 1,
ENC_NA, &length2);
offset2 += 2;
@ -1151,9 +1239,12 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
if (length2 > 0) {
lin_info.len = tvb_captured_length_remaining(sub_tvb, offset2);
payload_tvb = tvb_new_subset_length(sub_tvb, offset2, tvb_captured_length_remaining(sub_tvb, offset2));
if (!dissector_try_uint_new(lin_subdissector_table, lin_info.id, payload_tvb, pinfo, tree, FALSE, &lin_info)) {
proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_payload, payload_tvb, 0, (gint)length2, ENC_NA);
payload_tvb = tvb_new_subset_length(sub_tvb, offset2, tvb_captured_length_remaining(sub_tvb, offset2) - 1);
guint32 bus_frame_id = lin_info.id | (lin_info.bus_id << 16);
if (!dissector_try_uint_new(lin_subdissector_table, bus_frame_id, payload_tvb, pinfo, tree, FALSE, &lin_info)) {
if (!dissector_try_uint_new(lin_subdissector_table, lin_info.id, payload_tvb, pinfo, tree, FALSE, &lin_info)) {
call_data_dissector(payload_tvb, pinfo, tree);
}
}
offset2 += (gint)length2;
proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_checksum_8bit, sub_tvb, offset2, 1, ENC_NA);
@ -1198,7 +1289,7 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
}
if (!socketcan_call_subdissectors(payload_tvb, pinfo, tree, &can_info, heuristic_first)) {
proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_payload, payload_tvb, 0, (gint)length2, ENC_NA);
call_data_dissector(payload_tvb, pinfo, tree);
}
}
@ -1228,13 +1319,13 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
if (!heuristic_first) {
if (!dissector_try_payload_new(fr_subdissector_table, payload_tvb, pinfo, tree, TRUE, &fr_info)) {
if (!dissector_try_heuristic(fr_heur_subdissector_list, payload_tvb, pinfo, tree, &fr_heur_dtbl_entry, &fr_info)) {
proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_payload, payload_tvb, 0, (gint)length2, ENC_NA);
call_data_dissector(payload_tvb, pinfo, tree);
}
}
} else {
if (!dissector_try_heuristic(fr_heur_subdissector_list, payload_tvb, pinfo, tree, &fr_heur_dtbl_entry, &fr_info)) {
if (!dissector_try_payload_new(fr_subdissector_table, payload_tvb, pinfo, tree, FALSE, &fr_info)) {
proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_payload, payload_tvb, 0, (gint)length2, ENC_NA);
call_data_dissector(payload_tvb, pinfo, tree);
}
}
}
@ -1242,7 +1333,7 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree
break;
case TECMP_DATA_TYPE_RS232_ASCII:
proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_payload_ascii, sub_tvb, offset2, length, ENC_ASCII|ENC_NA);
call_data_dissector(sub_tvb, pinfo, tree);
break;
case TECMP_DATA_TYPE_ANALOG:
@ -1420,12 +1511,6 @@ proto_register_tecmp_payload(void) {
{ &hf_tecmp_payload_data_length,
{ "Payload Length", "tecmp.payload.data.payload_length",
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_tecmp_payload_data_payload,
{ "Payload", "tecmp.payload.data.payload",
FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_tecmp_payload_data_payload_ascii,
{ "Payload", "tecmp.payload.data.payload_ascii",
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_tecmp_payload_data_flags,
{ "Data Flags", "tecmp.payload.data_flags",
@ -1739,6 +1824,7 @@ proto_register_tecmp(void) {
static uat_field_t tecmp_channel_id_uat_fields[] = {
UAT_FLD_HEX(tecmp_channels, id, "ID", "ID of the Channel (hex uint32 without leading 0x)"),
UAT_FLD_CSTRING(tecmp_channels, name, "Channel Name", "Name of the Channel (string)"),
UAT_FLD_HEX(tecmp_channels, bus_id, "Bus ID", "Bus ID of the Channel (hex uint16 without leading 0x)"),
UAT_END_FIELDS
};
@ -1768,16 +1854,16 @@ proto_register_tecmp(void) {
"A table to define names of Capture Modules, which override default names.", tecmp_cmid_uat);
tecmp_channelid_uat = uat_new("TECMP Channels",
sizeof(generic_one_id_string_t), /* record size */
sizeof(channel_config_t), /* record size */
DATAFILE_TECMP_CH_IDS, /* filename */
TRUE, /* from profile */
(void**)&tecmp_channels, /* data_ptr */
&tecmp_channel_num, /* numitems_ptr */
UAT_AFFECTS_DISSECTION, /* but not fields */
NULL, /* help */
copy_generic_one_id_string_cb, /* copy callback */
update_generic_one_identifier_32bit, /* update callback */
free_generic_one_id_string_cb, /* free callback */
copy_channel_config_cb, /* copy callback */
update_channel_config, /* update callback */
free_channel_config_cb, /* free callback */
post_update_tecmp_channels_cb, /* post update callback */
NULL, /* reset callback */
tecmp_channel_id_uat_fields /* UAT field definitions */