diff options
Diffstat (limited to 'epan/dissectors/packet-autosar-ipdu-multiplexer.c')
-rw-r--r-- | epan/dissectors/packet-autosar-ipdu-multiplexer.c | 1037 |
1 files changed, 1037 insertions, 0 deletions
diff --git a/epan/dissectors/packet-autosar-ipdu-multiplexer.c b/epan/dissectors/packet-autosar-ipdu-multiplexer.c new file mode 100644 index 00000000..fbf8b0e7 --- /dev/null +++ b/epan/dissectors/packet-autosar-ipdu-multiplexer.c @@ -0,0 +1,1037 @@ +/* packet-autosar-ipdu-multiplexer.c + * Dissector for AUTOSAR I-PDU Multiplexer. + * By Dr. Lars Voelker <lars.voelker@technica-engineering.de> + * Copyright 2021-2022 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 + * + */ + +#include <config.h> +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/uat.h> +#include "packet-autosar-ipdu-multiplexer.h" + +#include "packet-socketcan.h" +#include "packet-flexray.h" +#include "packet-pdu-transport.h" +#include "packet-lin.h" + +void proto_register_autosar_ipdu_multiplexer(void); +void proto_reg_handoff_autosar_ipdu_multiplexer(void); + +/* + * Dissector for AUTOSAR I-PDU Multiplexer + * + * See https ://www.autosar.org/fileadmin/user_upload/standards/classic/20-11/AUTOSAR_SWS_IPDUMultiplexer.pdf + */ + +/* this protocol */ +static int proto_ipdu_multiplexer = -1; +#define IPDUM_NAME "AUTOSAR I-PduM" + +/* dissector handles - incoming messages */ +static dissector_handle_t ipdum_handle_can = NULL; +static dissector_handle_t ipdum_handle_flexray = NULL; +static dissector_handle_t ipdum_handle_lin = NULL; +static dissector_handle_t ipdum_handle_pdu_transport = NULL; + +/* subdissectors - outgoing messages */ +static dissector_table_t subdissector_table; + +/* header field */ +static int hf_pdu = -1; +static int hf_pdu_id = -1; +static int hf_pdu_name = -1; +static int hf_payload_unparsed = -1; + +/* etts */ +static gint ett_ipdum = -1; +static gint ett_ipdum_pdu = -1; + +/************************************** + ******** UAT configs ******** + **************************************/ +#define DATAFILE_IPDUM_MESSAGES "AUTOSAR_IPDUM_Messages" +#define DATAFILE_IPDUM_CAN_MAPPING "AUTOSAR_IPDUM_Binding_CAN" +#define DATAFILE_IPDUM_FLEXRAY_MAPPING "AUTOSAR_IPDUM_Binding_FlexRay" +#define DATAFILE_IPDUM_LIN_MAPPING "AUTOSAR_IPDUM_Binding_LIN" +#define DATAFILE_IPDUM_PDU_TRANSPORT_MAPPING "AUTOSAR_IPDUM_Binding_PDU_Transport" + + +typedef struct _ipdum_message_item { + guint32 pos; + guint32 pdu_id; + gchar *name; + guint32 start_pos; + guint32 bit_length; + guint32 update_bit_pos; +} ipdum_message_item_t; + +typedef struct _ipdum_message_list { + guint32 id; + guint32 num_of_items; + + ipdum_message_item_t *items; +} ipdum_message_list_t; + +typedef struct _ipdum_message_list_uat { + guint32 id; + guint32 num_of_params; + + guint32 pos; + guint32 pdu_id; + gchar *name; + guint32 start_pos; + guint32 bit_length; + guint32 update_bit_pos; +} ipdum_message_list_uat_t; + + +typedef struct _ipdum__can_mapping { + guint32 can_id; + guint32 bus_id; + guint32 message_id; +} ipdum_can_mapping_t; +typedef ipdum_can_mapping_t ipdum_can_mapping_uat_t; + +typedef struct _ipdum_flexray_mapping { + guint32 channel; + guint32 cycle; + guint32 frame_id; + guint32 message_id; +} ipdum_flexray_mapping_t; +typedef ipdum_flexray_mapping_t ipdum_flexray_mapping_uat_t; + +typedef struct _ipdum_lin_mapping { + guint32 frame_id; + guint32 bus_id; + guint32 message_id; +} ipdum_lin_mapping_t; +typedef ipdum_lin_mapping_t ipdum_lin_mapping_uat_t; + +typedef struct _ipdum_pdu_transport_mapping { + guint32 pdu_id; + guint32 message_id; +} ipdum_pdu_transport_mapping_t; +typedef ipdum_pdu_transport_mapping_t ipdum_pdu_transport_mapping_uat_t; + +static ipdum_message_list_uat_t *ipdum_message_list = NULL; +static guint ipdum_message_list_num = 0; +static GHashTable *data_ipdum_messages = NULL; + +static ipdum_can_mapping_t *ipdum_can_mapping = NULL; +static guint ipdum_can_mapping_num = 0; +static GHashTable *data_ipdum_can_mappings = NULL; + +static ipdum_flexray_mapping_t *ipdum_flexray_mapping = NULL; +static guint ipdum_flexray_mapping_num = 0; +static GHashTable *data_ipdum_flexray_mappings = NULL; + +static ipdum_lin_mapping_t *ipdum_lin_mapping = NULL; +static guint ipdum_lin_mapping_num = 0; +static GHashTable *data_ipdum_lin_mappings = NULL; + +static ipdum_pdu_transport_mapping_t *ipdum_pdu_transport_mapping = NULL; +static guint ipdum_pdu_transport_mapping_num = 0; +static GHashTable *data_ipdum_pdu_transport_mappings = NULL; + + +/* UAT Callbacks and Helpers */ + +static void +ipdum_payload_free_key(gpointer key) { + wmem_free(wmem_epan_scope(), key); +} + +static void +ipdum_payload_free_generic_data(gpointer data _U_) { + /* currently nothing to be free */ +} + + +/* UAT: I-PduM Message Config */ +UAT_HEX_CB_DEF(ipdum_message_list, id, ipdum_message_list_uat_t) +UAT_DEC_CB_DEF(ipdum_message_list, num_of_params, ipdum_message_list_uat_t) +UAT_DEC_CB_DEF(ipdum_message_list, pos, ipdum_message_list_uat_t) +UAT_HEX_CB_DEF(ipdum_message_list, pdu_id, ipdum_message_list_uat_t) +UAT_CSTRING_CB_DEF(ipdum_message_list, name, ipdum_message_list_uat_t) +UAT_DEC_CB_DEF(ipdum_message_list, start_pos, ipdum_message_list_uat_t) +UAT_DEC_CB_DEF(ipdum_message_list, bit_length, ipdum_message_list_uat_t) +UAT_DEC_CB_DEF(ipdum_message_list, update_bit_pos, ipdum_message_list_uat_t) + +static void * +copy_ipdum_message_list_cb(void *n, const void *o, size_t size _U_) { + ipdum_message_list_uat_t *new_rec = (ipdum_message_list_uat_t *)n; + const ipdum_message_list_uat_t *old_rec = (const ipdum_message_list_uat_t *)o; + + new_rec->id = old_rec->id; + new_rec->num_of_params = old_rec->num_of_params; + + new_rec->pos = old_rec->pos; + new_rec->pdu_id = old_rec->pdu_id; + + if (old_rec->name) { + new_rec->name = g_strdup(old_rec->name); + } else { + new_rec->name = NULL; + } + + new_rec->start_pos = old_rec->start_pos; + new_rec->bit_length = old_rec->bit_length; + new_rec->update_bit_pos = old_rec->update_bit_pos; + + return new_rec; +} + +static bool +update_ipdum_message_list(void *r, char **err) { + ipdum_message_list_uat_t *rec = (ipdum_message_list_uat_t *)r; + + if (rec->pos >= 0xffff) { + *err = ws_strdup_printf("Position too big"); + return FALSE; + } + + if (rec->num_of_params >= 0xffff) { + *err = ws_strdup_printf("Number of PDUs too big"); + return FALSE; + } + + if (rec->pos >= rec->num_of_params) { + *err = ws_strdup_printf("Position >= Number of PDUs"); + return FALSE; + } + + if (rec->name == NULL || rec->name[0] == 0) { + *err = ws_strdup_printf("Name cannot be empty"); + return FALSE; + } + + return TRUE; +} + +static void +free_ipdum_message_list_cb(void*r) { + ipdum_message_list_uat_t *rec = (ipdum_message_list_uat_t *)r; + if (rec->name) { + g_free(rec->name); + rec->name = NULL; + } +} + +static void +post_update_ipdum_message_list_read_in_data(ipdum_message_list_uat_t *data, guint data_num, GHashTable *ht) { + if (ht == NULL || data == NULL || data_num == 0) { + return; + } + + if (data_num) { + guint i = 0; + for (i = 0; i < data_num; i++) { + + /* the hash table does not know about uint64, so we use int64*/ + gint64 *key = wmem_new(wmem_epan_scope(), gint64); + *key = (guint32)data[i].id; + + ipdum_message_list_t *list = (ipdum_message_list_t *)g_hash_table_lookup(ht, key); + if (list == NULL) { + + list = wmem_new(wmem_epan_scope(), ipdum_message_list_t); + + list->id = data[i].id; + list->num_of_items = data[i].num_of_params; + + ipdum_message_item_t *items = (ipdum_message_item_t *)wmem_alloc0_array(wmem_epan_scope(), ipdum_message_item_t, data[i].num_of_params); + + list->items = items; + + /* create new entry ... */ + g_hash_table_insert(ht, key, list); + } else { + /* already present, deleting key */ + wmem_free(wmem_epan_scope(), key); + } + + /* and now we add to item array */ + if (data[i].num_of_params == list->num_of_items && data[i].pos < list->num_of_items) { + ipdum_message_item_t *item = &(list->items[data[i].pos]); + + /* we do not care if we overwrite param */ + item->pos = data[i].pos; + item->pdu_id = data[i].pdu_id; + item->name = g_strdup(data[i].name); + item->start_pos = data[i].start_pos; + item->bit_length = data[i].bit_length; + item->update_bit_pos = data[i].update_bit_pos; + } + } + } +} + +static void +post_update_ipdum_message_list_cb(void) { + /* destroy old hash table, if it exists */ + if (data_ipdum_messages) { + g_hash_table_destroy(data_ipdum_messages); + data_ipdum_messages = NULL; + } + + data_ipdum_messages = g_hash_table_new_full(g_int64_hash, g_int64_equal, &ipdum_payload_free_key, &ipdum_payload_free_generic_data); + post_update_ipdum_message_list_read_in_data(ipdum_message_list, ipdum_message_list_num, data_ipdum_messages); +} + +static ipdum_message_list_t * +get_message_config(guint32 id) { + if (data_ipdum_messages == NULL) { + return NULL; + } + + gint64 key = (gint64)id; + return (ipdum_message_list_t *)g_hash_table_lookup(data_ipdum_messages, &key); +} + + +/* UAT: CAN Binding Config */ +UAT_HEX_CB_DEF(ipdum_can_mapping, can_id, ipdum_can_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_can_mapping, bus_id, ipdum_can_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_can_mapping, message_id, ipdum_can_mapping_uat_t) + +static void * +copy_ipdum_can_mapping_cb(void *n, const void *o, size_t size _U_) { + ipdum_can_mapping_uat_t *new_rec = (ipdum_can_mapping_uat_t *)n; + const ipdum_can_mapping_uat_t *old_rec = (const ipdum_can_mapping_uat_t *)o; + + new_rec->can_id = old_rec->can_id; + new_rec->bus_id = old_rec->bus_id; + new_rec->message_id = old_rec->message_id; + + return new_rec; +} + +static bool +update_ipdum_can_mapping(void *r, char **err) { + ipdum_can_mapping_uat_t *rec = (ipdum_can_mapping_uat_t *)r; + + if ((rec->can_id & (CAN_RTR_FLAG | CAN_ERR_FLAG)) != 0) { + *err = g_strdup_printf("We currently do not support CAN IDs with RTR or Error Flag set (CAN_ID: 0x%x)", rec->can_id); + return FALSE; + } + + if ((rec->can_id & CAN_EFF_FLAG) == 0 && rec->can_id > CAN_SFF_MASK) { + *err = g_strdup_printf("Standard CAN ID (EFF flag not set) cannot be bigger than 0x7ff (CAN_ID: 0x%x)", rec->can_id); + return FALSE; + } + + return TRUE; +} + +static void +post_update_register_can(void) { + if (ipdum_handle_can == NULL) { + return; + } + + dissector_delete_all("can.id", ipdum_handle_can); + dissector_delete_all("can.extended_id", ipdum_handle_can); + + /* CAN: loop over all frame IDs in HT */ + if (data_ipdum_can_mappings != NULL) { + GList *keys = g_hash_table_get_keys(data_ipdum_can_mappings); + + GList *tmp; + for (tmp = keys; tmp != NULL; tmp = tmp->next) { + gint32 id = (*(gint32*)tmp->data); + + if ((id & CAN_EFF_FLAG) == CAN_EFF_FLAG) { + dissector_add_uint("can.extended_id", id & CAN_EFF_MASK, ipdum_handle_can); + } else { + dissector_add_uint("can.id", id & CAN_SFF_MASK, ipdum_handle_can); + } + } + + g_list_free(keys); + } +} + +static void +post_update_ipdum_can_mapping_cb(void) { + /* destroy old hash table, if it exists */ + if (data_ipdum_can_mappings) { + g_hash_table_destroy(data_ipdum_can_mappings); + data_ipdum_can_mappings = NULL; + } + + /* we don't need to free the data as long as we don't alloc it first */ + data_ipdum_can_mappings = g_hash_table_new_full(g_int64_hash, g_int64_equal, &ipdum_payload_free_key, NULL); + + if (data_ipdum_can_mappings == NULL || ipdum_can_mapping == NULL) { + return; + } + + if (ipdum_can_mapping_num > 0) { + guint i; + for (i = 0; i < ipdum_can_mapping_num; i++) { + gint64 *key = wmem_new(wmem_epan_scope(), gint64); + *key = ipdum_can_mapping[i].can_id; + *key |= ((gint64)(ipdum_can_mapping[i].bus_id & 0xffff)) << 32; + + g_hash_table_insert(data_ipdum_can_mappings, key, &ipdum_can_mapping[i]); + } + } + + /* we need to make sure we register again */ + post_update_register_can(); +} + +static ipdum_can_mapping_t * +get_can_mapping(guint32 id, guint16 bus_id) { + if (data_ipdum_can_mappings == NULL) { + return NULL; + } + + gint64 key = ((gint64)id & (CAN_EFF_MASK | CAN_EFF_FLAG)) | ((gint64)bus_id << 32); + ipdum_can_mapping_t *tmp = (ipdum_can_mapping_t *)g_hash_table_lookup(data_ipdum_can_mappings, &key); + if (tmp == NULL) { + /* try again without Bus ID set */ + key = id & (CAN_EFF_MASK | CAN_EFF_FLAG); + tmp = (ipdum_can_mapping_t *)g_hash_table_lookup(data_ipdum_can_mappings, &key); + } + + return tmp; +} + + +/* UAT: FlexRay Binding Config */ +UAT_HEX_CB_DEF(ipdum_flexray_mapping, channel, ipdum_flexray_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_flexray_mapping, cycle, ipdum_flexray_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_flexray_mapping, frame_id, ipdum_flexray_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_flexray_mapping, message_id, ipdum_flexray_mapping_uat_t) + +static void * +copy_ipdum_flexray_mapping_cb(void *n, const void *o, size_t size _U_) { + ipdum_flexray_mapping_uat_t *new_rec = (ipdum_flexray_mapping_uat_t *)n; + const ipdum_flexray_mapping_uat_t *old_rec = (const ipdum_flexray_mapping_uat_t *)o; + + new_rec->channel = old_rec->channel; + new_rec->cycle = old_rec->cycle; + new_rec->frame_id = old_rec->frame_id; + new_rec->message_id = old_rec->message_id; + + return new_rec; +} + +static bool +update_ipdum_flexray_mapping(void *r, char **err) { + ipdum_flexray_mapping_uat_t *rec = (ipdum_flexray_mapping_uat_t *)r; + + if (rec->cycle > 0xff) { + *err = ws_strdup_printf("We currently only support 8 bit Cycles (Cycle: %i Frame ID: %i)", rec->cycle, rec->frame_id); + return FALSE; + } + + if (rec->frame_id > 0xffff) { + *err = ws_strdup_printf("We currently only support 16 bit Frame IDs (Cycle: %i Frame ID: %i)", rec->cycle, rec->frame_id); + return FALSE; + } + + return TRUE; +} + +static void +post_update_ipdum_flexray_mapping_cb(void) { + /* destroy old hash table, if it exists */ + if (data_ipdum_flexray_mappings) { + g_hash_table_destroy(data_ipdum_flexray_mappings); + data_ipdum_flexray_mappings = NULL; + } + + /* we don't need to free the data as long as we don't alloc it first */ + data_ipdum_flexray_mappings = g_hash_table_new_full(g_int64_hash, g_int64_equal, &ipdum_payload_free_key, NULL); + + if (data_ipdum_flexray_mappings == NULL || ipdum_flexray_mapping == NULL) { + return; + } + + if (ipdum_flexray_mapping_num > 0) { + guint i; + for (i = 0; i < ipdum_flexray_mapping_num; i++) { + gint64 *key = wmem_new(wmem_epan_scope(), gint64); + *key = ipdum_flexray_mapping[i].frame_id & 0xffff; + *key |= ((gint64)ipdum_flexray_mapping[i].cycle & 0xff) << 16; + *key |= ((gint64)ipdum_flexray_mapping[i].channel & 0xff) << 24; + + g_hash_table_insert(data_ipdum_flexray_mappings, key, &ipdum_flexray_mapping[i]); + } + } +} + +static ipdum_flexray_mapping_t * +get_flexray_mapping(guint8 channel, guint8 cycle, guint16 flexray_id) { + if (data_ipdum_flexray_mappings == NULL) { + return NULL; + } + + gint64 *key = wmem_new(wmem_epan_scope(), gint64); + *key = (channel << 24) | (cycle << 16) | flexray_id; + + ipdum_flexray_mapping_t *tmp = (ipdum_flexray_mapping_t*)g_hash_table_lookup(data_ipdum_flexray_mappings, key); + wmem_free(wmem_epan_scope(), key); + + return tmp; +} + + +/* UAT: LIN Binding Config */ +UAT_HEX_CB_DEF(ipdum_lin_mapping, frame_id, ipdum_lin_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_lin_mapping, bus_id, ipdum_lin_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_lin_mapping, message_id, ipdum_lin_mapping_uat_t) + +static void * +copy_ipdum_lin_mapping_cb(void *n, const void *o, size_t size _U_) { + ipdum_lin_mapping_uat_t *new_rec = (ipdum_lin_mapping_uat_t *)n; + const ipdum_lin_mapping_uat_t *old_rec = (const ipdum_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; +} + +static bool +update_ipdum_lin_mapping(void *r, char **err) { + ipdum_lin_mapping_uat_t *rec = (ipdum_lin_mapping_uat_t *)r; + + if (rec->frame_id > LIN_ID_MASK) { + *err = ws_strdup_printf("LIN Frame IDs are only uint with 6 bits (ID: %i)", rec->frame_id); + return FALSE; + } + + if (rec->bus_id > 0xffff) { + *err = ws_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; +} + +static void +post_update_register_lin(void) { + if (ipdum_handle_lin == NULL) { + return; + } + + dissector_delete_all("lin.frame_id", ipdum_handle_lin); + + /* LIN: loop over all frame IDs in HT */ + if (data_ipdum_lin_mappings != NULL) { + GList *keys = g_hash_table_get_keys(data_ipdum_lin_mappings); + + GList *tmp; + for (tmp = keys; tmp != NULL; tmp = tmp->next) { + gint32 *id = (gint32*)tmp->data; + /* we register the combination of bus and frame id */ + dissector_add_uint("lin.frame_id", *id, ipdum_handle_lin); + } + + g_list_free(keys); + } +} + +static void +post_update_ipdum_lin_mapping_cb(void) { + /* destroy old hash table, if it exists */ + if (data_ipdum_lin_mappings) { + g_hash_table_destroy(data_ipdum_lin_mappings); + data_ipdum_lin_mappings = NULL; + } + + /* we don't need to free the data as long as we don't alloc it first */ + data_ipdum_lin_mappings = g_hash_table_new_full(g_int_hash, g_int_equal, &ipdum_payload_free_key, NULL); + + if (data_ipdum_lin_mappings == NULL || ipdum_lin_mapping == NULL) { + return; + } + + if (ipdum_lin_mapping_num > 0) { + guint i; + for (i = 0; i < ipdum_lin_mapping_num; i++) { + gint *key = wmem_new(wmem_epan_scope(), gint); + *key = (ipdum_lin_mapping[i].frame_id) & LIN_ID_MASK; + *key |= ((ipdum_lin_mapping[i].bus_id) & 0xffff) << 16; + + g_hash_table_insert(data_ipdum_lin_mappings, key, &ipdum_lin_mapping[i]); + } + } + + /* we need to make sure we register again */ + post_update_register_lin(); +} + +static ipdum_lin_mapping_t* +get_lin_mapping(lin_info_t *lininfo) { + if (data_ipdum_lin_mappings == NULL) { + return NULL; + } + + gint32 key = ((lininfo->id) & LIN_ID_MASK) | (((lininfo->bus_id) & 0xffff) << 16); + + ipdum_lin_mapping_t *tmp = (ipdum_lin_mapping_t *)g_hash_table_lookup(data_ipdum_lin_mappings, &key); + + if (tmp == NULL) { + /* try again without Bus ID set */ + key = (lininfo->id) & LIN_ID_MASK; + tmp = (ipdum_lin_mapping_t *)g_hash_table_lookup(data_ipdum_lin_mappings, &key); + } + + return tmp; +} + + +/* UAT: PDU Transport Binding Config */ +UAT_HEX_CB_DEF(ipdum_pdu_transport_mapping, pdu_id, ipdum_pdu_transport_mapping_uat_t) +UAT_HEX_CB_DEF(ipdum_pdu_transport_mapping, message_id, ipdum_pdu_transport_mapping_uat_t) + +static void * +copy_ipdum_pdu_transport_mapping_cb(void *n, const void *o, size_t size _U_) { + ipdum_pdu_transport_mapping_uat_t *new_rec = (ipdum_pdu_transport_mapping_uat_t*)n; + const ipdum_pdu_transport_mapping_uat_t *old_rec = (const ipdum_pdu_transport_mapping_uat_t*)o; + + new_rec->pdu_id = old_rec->pdu_id; + new_rec->message_id = old_rec->message_id; + + return new_rec; +} + +static bool +update_ipdum_pdu_transport_mapping(void *r, char **err) { + ipdum_pdu_transport_mapping_uat_t *rec = (ipdum_pdu_transport_mapping_uat_t *)r; + + if (rec->pdu_id > 0xffffffff) { + *err = ws_strdup_printf("PDU-Transport IDs are only uint32 (ID: %i)", rec->pdu_id); + return FALSE; + } + + return TRUE; +} + +static void +post_update_register_pdu_transport(void) { + if (ipdum_handle_pdu_transport == NULL) { + return; + } + + dissector_delete_all("pdu_transport.id", ipdum_handle_pdu_transport); + + /* PDU Transport: loop over all messages IDs in HT */ + if (data_ipdum_pdu_transport_mappings != NULL) { + GList *keys = g_hash_table_get_keys(data_ipdum_pdu_transport_mappings); + + GList *tmp; + for (tmp = keys; tmp != NULL; tmp = tmp->next) { + gint64 *id = (gint64*)tmp->data; + dissector_add_uint("pdu_transport.id", ((guint32)((guint64)(*id)) & 0xffffffff), ipdum_handle_pdu_transport); + } + + g_list_free(keys); + } +} + +static void +post_update_ipdum_pdu_transport_mapping_cb(void) { + /* destroy old hash table, if it exists */ + if (data_ipdum_pdu_transport_mappings) { + g_hash_table_destroy(data_ipdum_pdu_transport_mappings); + data_ipdum_pdu_transport_mappings = NULL; + } + + /* we don't need to free the data as long as we don't alloc it first */ + data_ipdum_pdu_transport_mappings = g_hash_table_new_full(g_int64_hash, g_int64_equal, &ipdum_payload_free_key, NULL); + + if (data_ipdum_pdu_transport_mappings == NULL || ipdum_pdu_transport_mapping == NULL) { + return; + } + + if (ipdum_pdu_transport_mapping_num > 0) { + guint i; + for (i = 0; i < ipdum_pdu_transport_mapping_num; i++) { + gint64 *key = wmem_new(wmem_epan_scope(), gint64); + *key = ipdum_pdu_transport_mapping[i].pdu_id; + + g_hash_table_insert(data_ipdum_pdu_transport_mappings, key, &ipdum_pdu_transport_mapping[i]); + } + } + + /* we need to make sure we register again */ + post_update_register_pdu_transport(); +} + +static ipdum_pdu_transport_mapping_t * +get_pdu_transport_mapping(guint32 pdu_transport_id) { + if (data_ipdum_pdu_transport_mappings == NULL) { + return NULL; + } + + gint64 key = (gint64)pdu_transport_id; + return (ipdum_pdu_transport_mapping_t *)g_hash_table_lookup(data_ipdum_pdu_transport_mappings, &key); +} + +/************************************** + ******** Dissection ******** + **************************************/ + +static int +dissect_ipdum_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root_tree, guint32 id) { + gint offset = 0; + gint length = tvb_captured_length_remaining(tvb, 0); + + proto_item *ti = proto_tree_add_item(root_tree, proto_ipdu_multiplexer, tvb, offset, -1, ENC_NA); + proto_tree *tree = proto_item_add_subtree(ti, ett_ipdum); + + ipdum_message_list_t *config = get_message_config(id); + guint i; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, IPDUM_NAME); + col_set_str(pinfo->cinfo, COL_INFO, IPDUM_NAME); + + if (config == NULL || config->num_of_items == 0) { + proto_tree_add_item(tree, hf_payload_unparsed, tvb, offset, length, ENC_NA); + } else { + for (i = 0; i < config->num_of_items; i++) { + gboolean update_bit_ok = true; + + if (config->items[i].update_bit_pos != 0xffff) { + gint update_byte = config->items[i].update_bit_pos / 8; + gint update_bit_mask = 1 << (config->items[i].update_bit_pos % 8); + guint8 tmp = tvb_get_guint8(tvb, update_byte); + update_bit_ok = (tmp & update_bit_mask) == update_bit_mask; + } + + if (update_bit_ok) { + gint start_byte = config->items[i].start_pos / 8; + gint end_byte = (config->items[i].start_pos + config->items[i].bit_length) / 8; + if ((config->items[i].start_pos + config->items[i].bit_length) % 8 != 0) { + end_byte++; + } + + gint pdu_len = end_byte - start_byte; + if (pdu_len > tvb_captured_length_remaining(tvb, offset + start_byte)) { + pdu_len = tvb_captured_length_remaining(tvb, offset + start_byte); + } + + ti = proto_tree_add_item(tree, hf_pdu, tvb, offset + start_byte, pdu_len, ENC_NA); + proto_tree *pdu_tree = proto_item_add_subtree(ti, ett_ipdum_pdu); + proto_tree_add_string(pdu_tree, hf_pdu_name, tvb, offset + start_byte, pdu_len, config->items[i].name); + proto_tree_add_uint(pdu_tree, hf_pdu_id, tvb, offset + start_byte, pdu_len, config->items[i].pdu_id); + + tvbuff_t *subtvb = tvb_new_subset_length(tvb, offset + start_byte, pdu_len); + if (subtvb != NULL) { + autosar_ipdu_multiplexer_info_t pdu_t_info; + pdu_t_info.pdu_id = config->items[i].pdu_id; + + dissector_try_uint_new(subdissector_table, config->items[i].pdu_id, subtvb, pinfo, root_tree, FALSE, (void *)(&pdu_t_info)); + } + } + } + } + return length; +} + +static int +dissect_ipdum_message_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { + struct can_info *can_info = (struct can_info *)data; + DISSECTOR_ASSERT(can_info); + + if (can_info->id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + /* Error and RTR frames are not for us. */ + return 0; + } + + ipdum_can_mapping_t *can_mapping = get_can_mapping(can_info->id, can_info->bus_id); + if (can_mapping == NULL) { + return 0; + } + + return dissect_ipdum_payload(tvb, pinfo, tree, can_mapping->message_id); +} + +static gboolean +dissect_ipdum_message_can_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + return dissect_ipdum_message_can(tvb, pinfo, tree, data) != 0; +} + +static int +dissect_ipdum_message_flexray(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + struct flexray_info *flexray_data = (struct flexray_info*)data; + DISSECTOR_ASSERT(flexray_data); + + ipdum_flexray_mapping_t *flexray_mapping = get_flexray_mapping(flexray_data->ch, flexray_data->cc, flexray_data->id); + + if (flexray_mapping == NULL) { + return 0; + } + + return dissect_ipdum_payload(tvb, pinfo, tree, flexray_mapping->message_id); +} + +static gboolean +dissect_ipdum_message_flexray_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + return dissect_ipdum_message_flexray(tvb, pinfo, tree, data) != 0; +} + +static int +dissect_ipdum_message_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + lin_info_t *lininfo = (lin_info_t *)data; + DISSECTOR_ASSERT(lininfo); + + ipdum_lin_mapping_t *lin_mapping = get_lin_mapping(lininfo); + + if (lin_mapping == NULL) { + return 0; + } + + return dissect_ipdum_payload(tvb, pinfo, tree, lin_mapping->message_id); +} + +static int +dissect_ipdum_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; + DISSECTOR_ASSERT(pdu_info); + + ipdum_pdu_transport_mapping_t *pdu_transport_mapping = get_pdu_transport_mapping(pdu_info->id); + + if (pdu_transport_mapping == NULL) { + return 0; + } + + return dissect_ipdum_payload(tvb, pinfo, tree, pdu_transport_mapping->message_id); +} + + +/************************************** + ******** Register Dissector ******** + **************************************/ + +void +proto_register_autosar_ipdu_multiplexer(void) { + module_t *ipdum_module; + + /* UAT for parsing the message */ + uat_t *ipdum_message_uat; + + /* UATs for binding to protocol */ + uat_t *ipdum_can_mapping_uat; + uat_t *ipdum_flexray_mapping_uat; + uat_t *ipdum_lin_mapping_uat; + uat_t *ipdum_pdu_transport_mapping_uat; + + static hf_register_info hf[] = { + { &hf_pdu, + { "PDU", "ipdum.pdu", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_pdu_id, + { "PDU-ID", "ipdum.pdu.id", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, + { &hf_pdu_name, + { "Name", "ipdum.pdu.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_payload_unparsed, + { "Unparsed Payload", "ipdum.unparsed", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + }; + + static gint *ett[] = { + &ett_ipdum, + &ett_ipdum_pdu, + }; + + static uat_field_t ipdum_message_list_uat_fields[] = { + UAT_FLD_HEX(ipdum_message_list, id, "I-PduM Message ID", "ID of the I-PduM Message (32bit hex without leading 0x)"), + UAT_FLD_DEC(ipdum_message_list, num_of_params, "Number of PDUs", "Number of PDUs (16bit dec)"), + + UAT_FLD_DEC(ipdum_message_list, pos, "PDU Position", "Position of PDU (16bit dec, starting with 0)"), + UAT_FLD_HEX(ipdum_message_list, pdu_id, "PDU ID", "ID of the PDU (32bit hex without leading 0x)"), + UAT_FLD_CSTRING(ipdum_message_list, name, "PDU Name", "Name of PDU (string)"), + UAT_FLD_DEC(ipdum_message_list, start_pos, "PDU Start Pos (bits)", "Start Position of PDU in bits (16bit dec, starting with 0)"), + UAT_FLD_DEC(ipdum_message_list, bit_length, "PDU Length (bits)", "Lenght of PDU in bits (16bit dec, starting with 0)"), + UAT_FLD_DEC(ipdum_message_list, update_bit_pos, "PDU Update Bit", "Position of Update bit (16bit dec, starting with 0, 65535 disabled)"), + UAT_END_FIELDS + }; + + static uat_field_t ipdum_can_mapping_uat_fields[] = { + UAT_FLD_HEX(ipdum_can_mapping, can_id, "CAN ID", "CAN ID (32bit hex without leading 0x, highest bit 1 for extended, 0 for standard ID)"), + UAT_FLD_HEX(ipdum_can_mapping, bus_id, "Bus ID", "Bus ID on which frame was recorded with 0=any (16bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_can_mapping, message_id, "Message ID", "ID of the I-PduM Config (32bit hex without leading 0x)"), + UAT_END_FIELDS + }; + + static uat_field_t ipdum_flexray_mapping_uat_fields[] = { + UAT_FLD_HEX(ipdum_flexray_mapping, channel, "Channel", "Channel (8bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_flexray_mapping, frame_id, "Frame ID", "Frame ID (16bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_flexray_mapping, cycle, "Cycle", "Cycle (8bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_flexray_mapping, message_id, "Message ID", "ID of the I-PduM Config (32bit hex without leading 0x)"), + UAT_END_FIELDS + }; + + static uat_field_t ipdum_lin_mapping_uat_fields[] = { + UAT_FLD_HEX(ipdum_lin_mapping, frame_id, "Frame ID", "LIN Frame ID (6bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_lin_mapping, bus_id, "Bus ID", "Bus ID on which frame was recorded with 0=any (16bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_lin_mapping, message_id, "Message ID", "ID of the I-PduM Config (32bit hex without leading 0x)"), + UAT_END_FIELDS + }; + + static uat_field_t ipdum_pdu_transport_mapping_uat_fields[] = { + UAT_FLD_HEX(ipdum_pdu_transport_mapping, pdu_id, "PDU ID", "PDU ID (32bit hex without leading 0x)"), + UAT_FLD_HEX(ipdum_pdu_transport_mapping, message_id, "Message ID", "ID of the I-PduM Config (32bit hex without leading 0x)"), + UAT_END_FIELDS + }; + + + proto_ipdu_multiplexer = proto_register_protocol("AUTOSAR I-PDU Multiplexer", IPDUM_NAME, "ipdum"); + ipdum_module = prefs_register_protocol(proto_ipdu_multiplexer, NULL); + + proto_register_field_array(proto_ipdu_multiplexer, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + subdissector_table = register_dissector_table("ipdum.pdu.id", "I-PduM PDU ID", proto_ipdu_multiplexer, FT_UINT32, BASE_HEX); + + + ipdum_message_uat = uat_new("I-PduM Message List", + sizeof(ipdum_message_list_uat_t), /* record size */ + DATAFILE_IPDUM_MESSAGES, /* filename */ + TRUE, /* from profile */ + (void**)&ipdum_message_list, /* data_ptr */ + &ipdum_message_list_num, /* numitems_ptr */ + UAT_AFFECTS_DISSECTION, /* but not fields */ + NULL, /* help */ + copy_ipdum_message_list_cb, /* copy callback */ + update_ipdum_message_list, /* update callback */ + free_ipdum_message_list_cb, /* free callback */ + post_update_ipdum_message_list_cb, /* post update callback */ + NULL, /* reset callback */ + ipdum_message_list_uat_fields /* UAT field definitions */ + ); + + prefs_register_uat_preference(ipdum_module, "_ipdum_message_list", "Message List", + "A table to define messages and PDUs", ipdum_message_uat); + + + prefs_register_static_text_preference(ipdum_module, "empty1", "", NULL); + prefs_register_static_text_preference(ipdum_module, "map", "Protocol Mappings:", NULL); + + + ipdum_can_mapping_uat = uat_new("CAN", + sizeof(ipdum_can_mapping_uat_t), /* record size */ + DATAFILE_IPDUM_CAN_MAPPING, /* filename */ + TRUE, /* from profile */ + (void**)&ipdum_can_mapping, /* data_ptr */ + &ipdum_can_mapping_num, /* numitems_ptr */ + UAT_AFFECTS_DISSECTION, /* but not fields */ + NULL, /* help */ /* help */ + copy_ipdum_can_mapping_cb, /* copy callback */ + update_ipdum_can_mapping, /* update callback */ + NULL, /* free callback */ + post_update_ipdum_can_mapping_cb, /* post update callback */ + NULL, /* reset */ /* reset callback */ + ipdum_can_mapping_uat_fields /* UAT field definitions */ + ); + + prefs_register_uat_preference(ipdum_module, "_ipdum_can_mapping", "CAN Mappings", + "A table to map CAN payloads to I-PduM Message configuration", ipdum_can_mapping_uat); + + + ipdum_flexray_mapping_uat = uat_new("FlexRay", + sizeof(ipdum_flexray_mapping_uat_t), /* record size */ + DATAFILE_IPDUM_FLEXRAY_MAPPING, /* filename */ + TRUE, /* from profile */ + (void**)&ipdum_flexray_mapping, /* data_ptr */ + &ipdum_flexray_mapping_num, /* numitems_ptr */ + UAT_AFFECTS_DISSECTION, /* but not fields */ + NULL, /* help */ + copy_ipdum_flexray_mapping_cb, /* copy callback */ + update_ipdum_flexray_mapping, /* update callback */ + NULL, /* free callback */ + post_update_ipdum_flexray_mapping_cb, /* post update callback */ + NULL, /* reset callback */ + ipdum_flexray_mapping_uat_fields /* UAT field definitions */ + ); + + prefs_register_uat_preference(ipdum_module, "_ipdum_flexray_mapping", "FlexRay Mappings", + "A table to map FlexRay payloads to I-PduM Message configuration", ipdum_flexray_mapping_uat); + + + ipdum_lin_mapping_uat = uat_new("LIN", + sizeof(ipdum_lin_mapping_uat_t), /* record size */ + DATAFILE_IPDUM_LIN_MAPPING, /* filename */ + TRUE, /* from profile */ + (void**)&ipdum_lin_mapping, /* data_ptr */ + &ipdum_lin_mapping_num, /* numitems_ptr */ + UAT_AFFECTS_DISSECTION, /* but not fields */ + NULL, /* help */ + copy_ipdum_lin_mapping_cb, /* copy callback */ + update_ipdum_lin_mapping, /* update callback */ + NULL, /* free callback */ + post_update_ipdum_lin_mapping_cb, /* post update callback */ + NULL, /* reset callback */ + ipdum_lin_mapping_uat_fields /* UAT field definitions */ + ); + + prefs_register_uat_preference(ipdum_module, "_ipdum_lin_mapping", "LIN Mappings", + "A table to map LIN payloads to I-PduM Message configuration", ipdum_lin_mapping_uat); + + + ipdum_pdu_transport_mapping_uat = uat_new("PDU Transport", + sizeof(ipdum_pdu_transport_mapping_uat_t), /* record size */ + DATAFILE_IPDUM_PDU_TRANSPORT_MAPPING, /* filename */ + TRUE, /* from profile */ + (void**)&ipdum_pdu_transport_mapping, /* data_ptr */ + &ipdum_pdu_transport_mapping_num, /* numitems_ptr */ + UAT_AFFECTS_DISSECTION, /* but not fields */ + NULL, /* help */ + copy_ipdum_pdu_transport_mapping_cb, /* copy callback */ + update_ipdum_pdu_transport_mapping, /* update callback */ + NULL, /* free callback */ + post_update_ipdum_pdu_transport_mapping_cb, /* post update callback */ + NULL, /* reset callback */ + ipdum_pdu_transport_mapping_uat_fields /* UAT field definitions */ + ); + + prefs_register_uat_preference(ipdum_module, "_ipdum_pdu_transport_mapping", "PDU Transport Mappings", + "A table to map PDU Transport payloads to I-PduM Message configuration", ipdum_pdu_transport_mapping_uat); +} + +void +proto_reg_handoff_autosar_ipdu_multiplexer(void) { + static gboolean initialized = FALSE; + + if (!initialized) { + ipdum_handle_can = register_dissector("ipdu_multiplexer_over_can", dissect_ipdum_message_can, proto_ipdu_multiplexer); + dissector_add_for_decode_as("can.subdissector", ipdum_handle_can); + heur_dissector_add("can", dissect_ipdum_message_can_heur, "IPDU Multiplexer over CAN", "ipdu_multiplexer_can_heur", proto_ipdu_multiplexer, HEURISTIC_ENABLE); + + ipdum_handle_flexray = register_dissector("ipdu_multiplexer_over_flexray", dissect_ipdum_message_flexray, proto_ipdu_multiplexer); + dissector_add_for_decode_as("flexray.subdissector", ipdum_handle_flexray); + heur_dissector_add("flexray", dissect_ipdum_message_flexray_heur, "IPDU Multiplexer over FlexRay", "ipdu_multiplexer_flexray_heur", proto_ipdu_multiplexer, HEURISTIC_ENABLE); + + ipdum_handle_lin = register_dissector("ipdu_multiplexer_over_lin", dissect_ipdum_message_lin, proto_ipdu_multiplexer); + + ipdum_handle_pdu_transport = register_dissector("ipdu_multiplexer_over_pdu_transport", dissect_ipdum_message_pdu_transport, proto_ipdu_multiplexer); + + initialized = TRUE; + } +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |