diff options
author | Dr. Lars Völker <lars.voelker@technica-engineering.de> | 2021-07-14 10:34:15 +0200 |
---|---|---|
committer | Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org> | 2021-07-14 09:31:06 +0000 |
commit | 95dc4f52bc6bbd1a4608e7ba81ccc0c1fa48f7ba (patch) | |
tree | 3472ea659400e262402d7fd70f9fcfe851cf1119 | |
parent | cc36b7413932350cd7bfa90396f3d6b5321af5fb (diff) |
LIN: Adding support for LIN dissection
This patch adds support for LIN (Local Interconnect Network) as
well as support for:
- Signal PDUs on LIN
- ISO 15765 (ISO TP) on LIN
- TECMP transported LIN is handle like LIN
LIN is a simple automotive fieldbus to connect for example simple
sensors and actuators to an electronic control unit.
-rw-r--r-- | docbook/release-notes.adoc | 1 | ||||
-rw-r--r-- | epan/dissectors/CMakeLists.txt | 3 | ||||
-rw-r--r-- | epan/dissectors/packet-iso15765.c | 108 | ||||
-rw-r--r-- | epan/dissectors/packet-iso15765.h | 39 | ||||
-rw-r--r-- | epan/dissectors/packet-lin.c | 278 | ||||
-rw-r--r-- | epan/dissectors/packet-lin.h | 40 | ||||
-rw-r--r-- | epan/dissectors/packet-obd-ii.c | 20 | ||||
-rw-r--r-- | epan/dissectors/packet-signal-pdu.c | 160 | ||||
-rw-r--r-- | epan/dissectors/packet-tecmp.c | 15 |
9 files changed, 629 insertions, 35 deletions
diff --git a/docbook/release-notes.adoc b/docbook/release-notes.adoc index 1f654534d1..469fd47ea6 100644 --- a/docbook/release-notes.adoc +++ b/docbook/release-notes.adoc @@ -106,6 +106,7 @@ Bluetooth Link Manager Protocol (BT LMP) Event Tracing for Windows (ETW) Kerberos SPAKE Linux psample protocol +Local Interconnect Network (LIN) Microsoft Task Scheduler Service O-RAN fronthaul UC-plane (O-RAN) Opus Interactive Audio Codec (OPUS) diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index 7b5d9ee567..9640976237 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -412,6 +412,7 @@ set(DISSECTOR_PUBLIC_HEADERS packet-isis.h packet-isis-clv.h packet-isl.h + packet-iso15765.h packet-isup.h packet-its.h packet-iwarp-ddp-rdmap.h @@ -429,6 +430,7 @@ set(DISSECTOR_PUBLIC_HEADERS packet-ldap.h packet-lcsap.h packet-ldp.h + packet-lin.h packet-link16.h packet-lisp.h packet-llc.h @@ -1346,6 +1348,7 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-lg8979.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-lge_monitor.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-link16.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-lin.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-linx.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-lisp-data.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-lisp-tcp.c diff --git a/epan/dissectors/packet-iso15765.c b/epan/dissectors/packet-iso15765.c index 5b21e24a4c..e87e7c17e3 100644 --- a/epan/dissectors/packet-iso15765.c +++ b/epan/dissectors/packet-iso15765.c @@ -19,6 +19,8 @@ #include <wsutil/bits_ctz.h> #include "packet-socketcan.h" +#include "packet-lin.h" +#include "packet-iso15765.h" void proto_register_iso15765(void); void proto_reg_handoff_iso15765(void); @@ -84,6 +86,7 @@ static const value_string iso15765_message_types[] = { static gint addressing = NORMAL_ADDRESSING; static guint window = 8; +static gboolean register_lin_diag_frames = TRUE; /* Encoding */ static const enum_val_t enum_addressing[] = { @@ -92,6 +95,7 @@ static const enum_val_t enum_addressing[] = { {NULL, NULL, 0} }; +static int hf_iso15765_address = -1; static int hf_iso15765_message_type = -1; static int hf_iso15765_data_length = -1; static int hf_iso15765_frame_length = -1; @@ -106,6 +110,8 @@ static gint ett_iso15765 = -1; static expert_field ei_iso15765_message_type_bad = EI_INIT; static int proto_iso15765 = -1; +static dissector_handle_t iso15765_handle_can = NULL; +static dissector_handle_t iso15765_handle_lin = NULL; static dissector_table_t subdissector_table; @@ -155,7 +161,7 @@ masked_guint16_value(const guint16 value, const guint16 mask) } static int -dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 bus_type, guint32 frame_id, guint32 frame_length) { static guint32 msg_seqid = 0; @@ -164,9 +170,9 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data proto_item *message_type_item; tvbuff_t* next_tvb = NULL; guint16 pci, message_type; - struct can_info can_info; iso15765_identifier_t* iso15765_info; - guint8 ae = (addressing == NORMAL_ADDRESSING) ? 0 : 1; + /* LIN is always extended addressing */ + guint8 ae = (addressing == NORMAL_ADDRESSING && bus_type != ISO15765_TYPE_LIN) ? 0 : 1; guint16 frag_id_low = 0; guint8 pci_len = 0; guint8 pci_offset = 0; @@ -176,14 +182,6 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data gboolean fragmented = FALSE; gboolean complete = FALSE; - DISSECTOR_ASSERT(data); - can_info = *((struct can_info*)data); - - if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { - /* Error and RTR frames are not for us. */ - return 0; - } - col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISO15765"); col_clear(pinfo->cinfo, COL_INFO); @@ -191,13 +189,16 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data if (!iso15765_info) { iso15765_info = wmem_new0(wmem_file_scope(), iso15765_identifier_t); - iso15765_info->id = can_info.id; + iso15765_info->id = frame_id; iso15765_info->last = FALSE; p_add_proto_data(wmem_file_scope(), pinfo, proto_iso15765, 0, iso15765_info); } ti = proto_tree_add_item(tree, proto_iso15765, tvb, 0, -1, ENC_NA); iso15765_tree = proto_item_add_subtree(ti, ett_iso15765); + if (ae != 0) { + proto_tree_add_item(iso15765_tree, hf_iso15765_address, tvb, 0, ae, ENC_NA); + } message_type_item = proto_tree_add_item(iso15765_tree, hf_iso15765_message_type, tvb, ae + ISO15765_PCI_OFFSET, ISO15765_PCI_LEN, ENC_BIG_ENDIAN); @@ -208,7 +209,7 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data switch(message_type) { case ISO15765_MESSAGE_TYPES_SINGLE_FRAME: { - if (can_info.fd && can_info.len > 8) { + if (bus_type == ISO15765_TYPE_CAN_FD && frame_length > 8) { pci = tvb_get_guint16(tvb, ae + ISO15765_PCI_OFFSET, ENC_BIG_ENDIAN); pci_len = ISO15765_PCI_FD_SF_LEN; offset = ae + ISO15765_PCI_OFFSET + ISO15765_PCI_FD_SF_LEN; @@ -230,7 +231,7 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data } case ISO15765_MESSAGE_TYPES_FIRST_FRAME: { pci = tvb_get_guint16(tvb, ae + ISO15765_PCI_OFFSET, ENC_BIG_ENDIAN); - if (can_info.fd && pci == 0x1000) { + if (bus_type == ISO15765_TYPE_CAN_FD && pci == 0x1000) { pci_len = ISO15765_PCI_FD_FF_LEN - 2; full_len = tvb_get_guint32(tvb, ae + ISO15765_PCI_OFFSET + 2, ENC_BIG_ENDIAN); offset = ae + ISO15765_MESSAGE_FRAME_LENGTH_OFFSET + ISO15765_PCI_FD_FF_LEN - 1; @@ -374,7 +375,12 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data } if (next_tvb) { - if (!complete || !dissector_try_payload_new(subdissector_table, next_tvb, pinfo, tree, TRUE, data)) { + iso15765_info_t iso15765data; + iso15765data.bus_type = bus_type; + iso15765data.id = frame_id; + iso15765data.len = frame_length; + + if (!complete || !dissector_try_payload_new(subdissector_table, next_tvb, pinfo, tree, TRUE, &iso15765data)) { call_data_dissector(next_tvb, pinfo, tree); } } @@ -382,11 +388,65 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data return tvb_captured_length(tvb); } +static int +dissect_iso15765_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +{ + struct can_info can_info; + + DISSECTOR_ASSERT(data); + can_info = *((struct can_info*)data); + + if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + /* Error and RTR frames are not for us. */ + return 0; + } + + if (can_info.fd) { + return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_CAN_FD, can_info.id, can_info.len); + } else { + return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_CAN, can_info.id, can_info.len); + } +} + +static int +dissect_iso15765_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +{ + DISSECTOR_ASSERT(data); + + lin_info_t *lininfo = (lin_info_t *)data; + + return dissect_iso15765(tvb, pinfo, tree, ISO15765_TYPE_LIN, lininfo->id, lininfo->len); +} + +void +register_lin_frames(void) +{ + if (iso15765_handle_lin == NULL) { + return; + } + + dissector_delete_all("lin.frame_id", iso15765_handle_lin); + if (register_lin_diag_frames) { + /* LIN specification states that 0x3c and 0x3d are for diagnostics */ + dissector_add_uint("lin.frame_id", LIN_DIAG_MASTER_REQUEST_FRAME, iso15765_handle_lin); + dissector_add_uint("lin.frame_id", LIN_DIAG_SLAVE_RESPONSE_FRAME, iso15765_handle_lin); + } +} + void proto_register_iso15765(void) { static hf_register_info hf[] = { { + &hf_iso15765_address, + { + "Address", "iso15765.address", + FT_UINT8, BASE_HEX, + NULL, 0, + NULL, HFILL + } + }, + { &hf_iso15765_message_type, { "Message Type", "iso15765.message_type", @@ -569,7 +629,7 @@ proto_register_iso15765(void) "ISO 15765", /* short name */ "iso15765" /* abbrev */ ); - register_dissector("iso15765", dissect_iso15765, proto_iso15765); + register_dissector("iso15765", dissect_iso15765_lin, proto_iso15765); expert_iso15765 = expert_register_protocol(proto_iso15765); proto_register_field_array(proto_iso15765, hf, array_length(hf)); @@ -577,7 +637,7 @@ proto_register_iso15765(void) expert_register_field_array(expert_iso15765, ei, array_length(ei)); - iso15765_module = prefs_register_protocol(proto_iso15765, NULL); + iso15765_module = prefs_register_protocol(proto_iso15765, register_lin_frames); prefs_register_enum_preference(iso15765_module, "addressing", "Addressing", @@ -590,6 +650,12 @@ proto_register_iso15765(void) "Window of ISO 15765 fragments", 10, &window); + prefs_register_static_text_preference(iso15765_module, "empty2", "", NULL); + prefs_register_static_text_preference(iso15765_module, "map", "Protocol Handling:", NULL); + + prefs_register_bool_preference(iso15765_module, "lin_diag", "Handle LIN Diagnostic Frames", + "Handle LIN Diagnostic Frames", ®ister_lin_diag_frames); + iso15765_frame_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal); reassembly_table_register(&iso15765_reassembly_table, &addresses_reassembly_table_functions); @@ -600,10 +666,10 @@ proto_register_iso15765(void) void proto_reg_handoff_iso15765(void) { - static dissector_handle_t iso15765_handle; - - iso15765_handle = create_dissector_handle(dissect_iso15765, proto_iso15765); - dissector_add_for_decode_as("can.subdissector", iso15765_handle); + iso15765_handle_can = create_dissector_handle(dissect_iso15765_can, proto_iso15765); + iso15765_handle_lin = create_dissector_handle(dissect_iso15765_lin, proto_iso15765); + dissector_add_for_decode_as("can.subdissector", iso15765_handle_can); + register_lin_frames(); } /* diff --git a/epan/dissectors/packet-iso15765.h b/epan/dissectors/packet-iso15765.h new file mode 100644 index 0000000000..02f8592180 --- /dev/null +++ b/epan/dissectors/packet-iso15765.h @@ -0,0 +1,39 @@ +/* packet-iso15765.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __PACKET_ISO15765_H__ +#define __PACKET_ISO15765_H__ + +#define ISO15765_TYPE_NONE 0 +#define ISO15765_TYPE_CAN 1 +#define ISO15765_TYPE_CAN_FD 2 +#define ISO15765_TYPE_LIN 3 + +struct iso15765_info { + guint32 bus_type; + guint32 id; + guint32 len; +}; + +typedef struct iso15765_info iso15765_info_t; + +#endif /* __PACKET_ISO15765_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: + */ diff --git a/epan/dissectors/packet-lin.c b/epan/dissectors/packet-lin.c new file mode 100644 index 0000000000..5cc1d14309 --- /dev/null +++ b/epan/dissectors/packet-lin.c @@ -0,0 +1,278 @@ +/* packet-lin.c + * + * LIN dissector. + * 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 + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/decode_as.h> +#include <epan/prefs.h> +#include <wiretap/wtap.h> +#include <epan/expert.h> + +#include <packet-lin.h> + + /* + * Dissector for the Local Interconnect Network (LIN) bus. + * + * see ISO 17987 or search for "LIN Specification 2.2a" online. + */ + +#define LIN_NAME "LIN" +#define LIN_NAME_LONG "LIN Protocol" +#define LIN_NAME_FILTER "lin" + +static heur_dissector_list_t heur_subdissector_list; +static heur_dtbl_entry_t *heur_dtbl_entry; + +static int proto_lin = -1; + +/* header field */ +static int hf_lin_msg_format_rev = -1; +static int hf_lin_reserved1 = -1; +static int hf_lin_payload_length = -1; +static int hf_lin_message_type = -1; +static int hf_lin_checksum_type = -1; +static int hf_lin_pid = -1; +static int hf_lin_id = -1; +static int hf_lin_parity = -1; +static int hf_lin_checksum = -1; +static int hf_lin_err_errors = -1; +static int hf_lin_err_no_slave_response = -1; +static int hf_lin_err_framing = -1; +static int hf_lin_err_parity = -1; +static int hf_lin_err_checksum = -1; +static int hf_lin_err_invalidid = -1; +static int hf_lin_err_overflow = -1; +static int hf_lin_event_id = -1; + +static gint ett_lin = -1; +static gint ett_lin_pid = -1; +static gint ett_errors = -1; + +static int * const error_fields[] = { + &hf_lin_err_overflow, + &hf_lin_err_invalidid, + &hf_lin_err_checksum, + &hf_lin_err_parity, + &hf_lin_err_framing, + &hf_lin_err_no_slave_response, + NULL +}; + +static dissector_table_t subdissector_table; + +#define LIN_MSG_TYPE_FRAME 0 +#define LIN_MSG_TYPE_EVENT 3 + +static const value_string lin_msg_type_names[] = { + { LIN_MSG_TYPE_FRAME, "Frame" }, + { LIN_MSG_TYPE_EVENT, "Event" }, + {0, NULL} +}; + +#define LIN_CHKSUM_TYPE_UNKN_ERR 0 +#define LIN_CHKSUM_TYPE_CLASSIC 1 +#define LIN_CHKSUM_TYPE_ENHANCED 2 +#define LIN_CHKSUM_TYPE_UNDEF 3 + +static const value_string lin_checksum_type_names[] = { + { LIN_CHKSUM_TYPE_UNKN_ERR, "Unknown/Error" }, + { LIN_CHKSUM_TYPE_CLASSIC, "Classic" }, + { LIN_CHKSUM_TYPE_ENHANCED, "Enhanced" }, + { LIN_CHKSUM_TYPE_UNDEF, "Undefined" }, + {0, NULL} +}; + +#define LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_GO_TO_SLEEP 0xB0B00001 +#define LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_INACTIVITY 0xB0B00002 +#define LIN_EVENT_TYPE_WAKE_UP_BY_WAKE_UP_SIGNAL 0xB0B00004 + +static const value_string lin_event_type_names[] = { + { LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_GO_TO_SLEEP, "Go-to-Sleep event by Go-to-Sleep frame" }, + { LIN_EVENT_TYPE_GO_TO_SLEEP_EVENT_BY_INACTIVITY, "Go-to-Sleep event by Inactivity for more than 4s" }, + { LIN_EVENT_TYPE_WAKE_UP_BY_WAKE_UP_SIGNAL, "Wake-up event by Wake-up signal" }, + {0, NULL} +}; + +void proto_reg_handoff_lin(void); +void proto_register_lin(void); + + +static int +dissect_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { + proto_item *ti; + proto_item *ti_root; + proto_tree *lin_tree; + proto_tree *lin_id_tree; + tvbuff_t *next_tvb; + + guint payload_length; + guint msg_type; + lin_info_t lininfo; + + 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); + + proto_tree_add_item(lin_tree, hf_lin_msg_format_rev, tvb, 0, 1, ENC_BIG_ENDIAN); + ti = proto_tree_add_item(lin_tree, hf_lin_reserved1, tvb, 1, 3, ENC_BIG_ENDIAN); + proto_item_set_hidden(ti); + + proto_tree_add_item_ret_uint(lin_tree, hf_lin_payload_length, tvb, 4, 1, ENC_BIG_ENDIAN, &payload_length); + proto_tree_add_item_ret_uint(lin_tree, hf_lin_message_type, tvb, 4, 1, ENC_BIG_ENDIAN, &msg_type); + if (msg_type != LIN_MSG_TYPE_EVENT) { + proto_tree_add_item(lin_tree, hf_lin_checksum_type, tvb, 4, 1, ENC_BIG_ENDIAN); + + ti = proto_tree_add_item(lin_tree, hf_lin_pid, tvb, 5, 1, ENC_BIG_ENDIAN); + lin_id_tree = proto_item_add_subtree(ti, ett_lin_pid); + proto_tree_add_item_ret_uint(lin_id_tree, hf_lin_id, tvb, 5, 1, ENC_BIG_ENDIAN, &(lininfo.id)); + proto_tree_add_item(lin_id_tree, hf_lin_parity, tvb, 5, 1, ENC_BIG_ENDIAN); + + proto_tree_add_item(lin_tree, hf_lin_checksum, tvb, 6, 1, ENC_BIG_ENDIAN); + } + proto_tree_add_bitmask(lin_tree, tvb, 7, hf_lin_err_errors, ett_errors, error_fields, ENC_BIG_ENDIAN); + + col_add_fstr(pinfo->cinfo, COL_INFO, "LIN %s", val_to_str(msg_type, lin_msg_type_names, "(0x%02x)")); + + switch (msg_type) { + case LIN_MSG_TYPE_EVENT: { + guint event_id; + proto_tree_add_item_ret_uint(lin_tree, hf_lin_event_id, tvb, 8, 4, ENC_BIG_ENDIAN, &event_id); + col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(event_id, lin_event_type_names, "0x%08x")); + proto_item_set_end(ti_root, tvb, 12); + 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); + } + } + } + break; + } + + /* format pads to 4 bytes*/ + if (payload_length <= 4) { + proto_item_set_end(ti_root, tvb, 12); + return 12; + } else if (payload_length <= 8) { + proto_item_set_end(ti_root, tvb, 16); + return 16; + } else { + return tvb_captured_length(tvb); + } +} + +void +proto_register_lin(void) { + //module_t *lin_module; + + static hf_register_info hf[] = { + { &hf_lin_msg_format_rev, + { "Message Format Revision", "lin.message_format", + FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { &hf_lin_reserved1, + { "Reserved", "lin.reserved", + FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }}, + { &hf_lin_payload_length, + { "Length", "lin.length", + FT_UINT8, BASE_DEC, NULL, 0xf0, NULL, HFILL }}, + { &hf_lin_message_type, + { "Message Type", "lin.message_type", + FT_UINT8, BASE_DEC, VALS(lin_msg_type_names), 0x0c, NULL, HFILL }}, + { &hf_lin_checksum_type, + { "Checksum Type", "lin.checksum_type", + FT_UINT8, BASE_DEC, VALS(lin_checksum_type_names), 0x03, NULL, HFILL }}, + { &hf_lin_pid, + { "Protected ID", "lin.protected_id", + FT_UINT8, BASE_HEX_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_lin_id, + { "Frame ID", "lin.frame_id", + FT_UINT8, BASE_HEX_DEC, NULL, 0xfc, NULL, HFILL }}, + { &hf_lin_parity, + { "Parity", "lin.frame_parity", + FT_UINT8, BASE_HEX_DEC, NULL, 0x03, NULL, HFILL }}, + { &hf_lin_checksum, + { "Checksum", "lin.checksum", + FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_lin_err_errors, + { "Errors", "lin.errors", + FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_lin_err_no_slave_response, + { "No Slave Response Error", "lin.errors.no_slave_response", + FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }}, + { &hf_lin_err_framing, + { "Framing Error", "lin.errors.framing_error", + FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }}, + { &hf_lin_err_parity, + { "Parity Error", "lin.errors.parity_error", + FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }}, + { &hf_lin_err_checksum, + { "Checksum Error", "lin.errors.checksum_error", + FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }}, + { &hf_lin_err_invalidid, + { "Invalid ID Error", "lin.errors.invalid_id_error", + FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }}, + { &hf_lin_err_overflow, + { "Overflow Error", "lin.errors.overflow_error", + FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }}, + { &hf_lin_event_id, + { "Event ID", "lin.event_id", + FT_UINT32, BASE_HEX_DEC, VALS(lin_event_type_names), 0x00, NULL, HFILL }}, + }; + + static gint *ett[] = { + &ett_lin, + &ett_lin_pid, + &ett_errors, + }; + + proto_lin = proto_register_protocol(LIN_NAME_LONG, LIN_NAME, LIN_NAME_FILTER); + //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); + + 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); +} + +void +proto_reg_handoff_lin(void) { + static dissector_handle_t lin_handle; + lin_handle = create_dissector_handle(dissect_lin, proto_lin); + dissector_add_uint("wtap_encap", WTAP_ENCAP_LIN, lin_handle); +} + +/* + * 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: + */ diff --git a/epan/dissectors/packet-lin.h b/epan/dissectors/packet-lin.h new file mode 100644 index 0000000000..b475cc8a2a --- /dev/null +++ b/epan/dissectors/packet-lin.h @@ -0,0 +1,40 @@ +/* packet-lin.h + * + * Definitions for LIN + * By Dr. Lars Voelker <lars.voelker@technica-engineering.de> / <lars.voelker@bmw.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_LIN_H__ +#define __PACKET_LIN_H__ + +#define LIN_DIAG_MASTER_REQUEST_FRAME 0x3c +#define LIN_DIAG_SLAVE_RESPONSE_FRAME 0x3d + +struct lin_info { + guint32 id; + guint32 len; +}; + +typedef struct lin_info lin_info_t; + +#endif /* __PACKET_LIN_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: + */ diff --git a/epan/dissectors/packet-obd-ii.c b/epan/dissectors/packet-obd-ii.c index eda3de4732..ba6509ccae 100644 --- a/epan/dissectors/packet-obd-ii.c +++ b/epan/dissectors/packet-obd-ii.c @@ -19,6 +19,7 @@ #include <wsutil/utf8_entities.h> #include "packet-socketcan.h" +#include "packet-iso15765.h" void proto_register_obdii(void); void proto_reg_handoff_obdii(void); @@ -1358,8 +1359,8 @@ dissect_obdii_response(tvbuff_t *tvb, struct obdii_packet_info *oinfo, proto_tre static int dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { - struct can_info can_info; - guint32 can_id_only; + iso15765_info_t iso15765_info; + guint32 can_id_only; struct obdii_packet_info oinfo; proto_tree *obdii_tree; @@ -1371,11 +1372,16 @@ dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) gboolean id_is_response; DISSECTOR_ASSERT(data); - can_info = *((struct can_info *) data); - can_id_only = can_info.id & CAN_EFF_MASK; + + iso15765_info = *((iso15765_info_t *) data); + if (iso15765_info.bus_type != ISO15765_TYPE_CAN && iso15765_info.bus_type != ISO15765_TYPE_CAN_FD) { + return 0; + } + + can_id_only = iso15765_info.id & CAN_EFF_MASK; /* If we're using 29bit extended ID's then use extended ID parameters */ - if (can_info.id & CAN_EFF_FLAG) + if (iso15765_info.id & CAN_EFF_FLAG) { id_is_query = (can_id_only == ODBII_CAN_QUERY_ID_EFF); id_is_response = ((((can_id_only & ~ODBII_CAN_RESPONSE_ID_LOWER_MASK_EFF) ^ ODBII_CAN_RESPONSE_ID_LOWER_MIN_EFF) == 0) || @@ -1389,7 +1395,7 @@ dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) } /* validate */ - if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) + if (iso15765_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) return 0; if (!(id_is_query || id_is_response)) @@ -1401,7 +1407,7 @@ dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) /* Mode 7 is a datalength of 1, all other queries either 2 or 3 bytes */ if (id_is_query) { - if (can_info.len != 8) + if (iso15765_info.len != 8) expert_add_info(pinfo, NULL, &ei_obdii_padding); if (data_bytes == 0 || data_bytes > 3) return 0; diff --git a/epan/dissectors/packet-signal-pdu.c b/epan/dissectors/packet-signal-pdu.c index 72ea549dd6..2c942c9376 100644 --- a/epan/dissectors/packet-signal-pdu.c +++ b/epan/dissectors/packet-signal-pdu.c @@ -29,6 +29,7 @@ #include <packet-socketcan.h> #include <packet-flexray.h> #include <packet-pdu-transport.h> +#include <packet-lin.h> /* * Dissector for CAN, FlexRay, and other message payloads. @@ -54,6 +55,7 @@ #define DATAFILE_SPDU_SOMEIP_MAPPING "Signal_PDU_Binding_SOMEIP" #define DATAFILE_SPDU_CAN_MAPPING "Signal_PDU_Binding_CAN" #define DATAFILE_SPDU_FLEXRAY_MAPPING "Signal_PDU_Binding_FlexRay" +#define DATAFILE_SPDU_LIN_MAPPING "Signal_PDU_Binding_LIN" #define DATAFILE_SPDU_PDU_TRANSPORT_MAPPING "Signal_PDU_Binding_PDU_Transport" /* ID wireshark identifies the dissector by */ @@ -62,6 +64,7 @@ static int proto_signal_pdu = -1; static dissector_handle_t signal_pdu_handle_someip = NULL; static dissector_handle_t signal_pdu_handle_can = NULL; static dissector_handle_t signal_pdu_handle_flexray = NULL; +static dissector_handle_t signal_pdu_handle_lin = NULL; static dissector_handle_t signal_pdu_handle_pdu_transport = NULL; static int hf_payload_unparsed = -1; @@ -85,6 +88,7 @@ static GHashTable *data_spdu_signal_value_names = NULL; static GHashTable *data_spdu_someip_mappings = NULL; static GHashTable *data_spdu_can_mappings = NULL; static GHashTable *data_spdu_flexray_mappings = NULL; +static GHashTable *data_spdu_lin_mappings = NULL; static GHashTable *data_spdu_pdu_transport_mappings = NULL; static hf_register_info *dynamic_hf = NULL; @@ -216,6 +220,13 @@ typedef struct _spdu_flexray_mapping { typedef spdu_flexray_mapping_t spdu_flexray_mapping_uat_t; +typedef struct _spdu_lin_mapping { + guint32 frame_id; + guint32 message_id; +} spdu_lin_mapping_t; +typedef spdu_lin_mapping_t spdu_lin_mapping_uat_t; + + typedef struct _spdu_pdu_transport_mapping { guint32 pdu_id; guint32 message_id; @@ -241,13 +252,36 @@ static guint spdu_can_mapping_num = 0; static spdu_flexray_mapping_t *spdu_flexray_mapping = NULL; static guint spdu_flexray_mapping_num = 0; +static spdu_lin_mapping_t *spdu_lin_mapping = NULL; +static guint spdu_lin_mapping_num = 0; + static spdu_pdu_transport_mapping_t *spdu_pdu_transport_mapping = NULL; static guint spdu_pdu_transport_mapping_num = 0; void proto_register_signal_pdu(void); void proto_reg_handoff_signal_pdu(void); -void proto_reg_handoff_signal_pdu_someip(void); -void proto_reg_handoff_signal_pdu_pdu_transport(void); + +void +proto_reg_handoff_signal_pdu_lin(void) { + if (signal_pdu_handle_lin == NULL) { + return; + } + + dissector_delete_all("lin.frame_id", signal_pdu_handle_lin); + + /* LIN: loop over all frame IDs in HT */ + if (data_spdu_lin_mappings != NULL) { + GList *keys = g_hash_table_get_keys(data_spdu_lin_mappings); + + 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); + } + } +} void proto_reg_handoff_signal_pdu_someip(void) { @@ -288,7 +322,6 @@ proto_reg_handoff_signal_pdu_pdu_transport(void) { dissector_add_uint("pdu_transport.id", ((guint32)((guint64)(*id)) & 0xffffffff), signal_pdu_handle_pdu_transport); } } - } /*** UAT Callbacks and Helpers ***/ @@ -1105,6 +1138,77 @@ 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, message_id, spdu_lin_mapping_uat_t) + +static void * +copy_spdu_lin_mapping_cb(void *n, const void *o, size_t size _U_) { + spdu_lin_mapping_uat_t *new_rec = (spdu_lin_mapping_uat_t*)n; + 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->message_id = old_rec->message_id; + + return new_rec; +} + +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) { + *err = g_strdup_printf("LIN Frame IDs are only uint with 6 bits (ID: %i)", rec->frame_id); + return FALSE; + } + + return TRUE; +} + +static void +post_update_spdu_lin_mapping_cb(void) { + /* destroy old hash table, if it exists */ + if (data_spdu_lin_mappings) { + g_hash_table_destroy(data_spdu_lin_mappings); + data_spdu_lin_mappings = NULL; + } + + /* we dont need to free the data as long as we don't alloc it first */ + data_spdu_lin_mappings = g_hash_table_new_full(g_int_hash, g_int_equal, &spdu_payload_free_key, NULL); + + if (data_spdu_lin_mappings == NULL || spdu_lin_mapping == NULL) { + return; + } + + if (spdu_lin_mapping_num > 0) { + 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; + + g_hash_table_insert(data_spdu_lin_mappings, key, &spdu_lin_mapping[i]); + } + } + + /* we need to make sure we register again */ + proto_reg_handoff_signal_pdu_lin(); +} + +static spdu_lin_mapping_t* +get_lin_mapping(guint32 lin_id) { + if (data_spdu_lin_mappings == NULL) { + return NULL; + } + + gint32 *key = wmem_new(wmem_epan_scope(), gint32); + *key = lin_id; + + spdu_lin_mapping_uat_t *tmp = (spdu_lin_mapping_uat_t*)g_hash_table_lookup(data_spdu_lin_mappings, key); + wmem_free(wmem_epan_scope(), key); + + return tmp; +} + /* UAT: PDU Transport Mapping */ UAT_HEX_CB_DEF(spdu_pdu_transport_mapping, pdu_id, spdu_pdu_transport_mapping_uat_t) UAT_HEX_CB_DEF(spdu_pdu_transport_mapping, message_id, spdu_pdu_transport_mapping_uat_t) @@ -1291,7 +1395,11 @@ dissect_spdu_payload_signal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, expert_spdu_config_error(tree, pinfo, tvb, offset, signal_length); } - if (item != NULL && item->hf_id_raw != NULL) { + if (item == NULL) { + return tvb_captured_length_remaining(tvb, offset); + } + + if (item->hf_id_raw != NULL) { hf_id_raw = *item->hf_id_raw; } else { expert_spdu_config_error(tree, pinfo, tvb, offset, signal_length); @@ -1473,6 +1581,21 @@ dissect_spdu_message_flexray_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree } static int +dissect_spdu_message_lin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + lin_info_t *lininfo = (lin_info_t *)data; + + DISSECTOR_ASSERT(lininfo); + + spdu_lin_mapping_t *lin_mapping = get_lin_mapping(lininfo->id); + + if (lin_mapping == NULL) { + return 0; + } + + return dissect_spdu_payload(tvb, pinfo, tree, lin_mapping->message_id, FALSE); +} + +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; DISSECTOR_ASSERT(pdu_info); @@ -1507,6 +1630,7 @@ proto_register_signal_pdu(void) { uat_t *spdu_someip_mapping_uat; uat_t *spdu_can_mapping_uat; uat_t *spdu_flexray_mapping_uat; + uat_t *spdu_lin_mapping_uat; uat_t *spdu_pdu_transport_mapping_uat; @@ -1581,6 +1705,12 @@ proto_register_signal_pdu(void) { UAT_END_FIELDS }; + 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, message_id, "Signal PDU ID", "ID of the Signal PDU (32bit hex without leading 0x)"), + UAT_END_FIELDS + }; + static uat_field_t spdu_pdu_transport_mapping_uat_fields[] = { UAT_FLD_HEX(spdu_pdu_transport_mapping, pdu_id, "PDU ID", "PDU ID (32bit hex without leading 0x)"), UAT_FLD_HEX(spdu_pdu_transport_mapping, message_id, "Signal PDU ID", "ID of the Signal PDU (32bit hex without leading 0x)"), @@ -1737,6 +1867,24 @@ proto_register_signal_pdu(void) { "A table to map FlexRay payloads to Signal PDUs", spdu_flexray_mapping_uat); + spdu_lin_mapping_uat = uat_new("LIN", + sizeof(spdu_lin_mapping_uat_t), DATAFILE_SPDU_LIN_MAPPING, TRUE, + (void**)&spdu_lin_mapping, + &spdu_lin_mapping_num, + UAT_AFFECTS_DISSECTION, + NULL, /* help */ + copy_spdu_lin_mapping_cb, + update_spdu_lin_mapping, + NULL, + post_update_spdu_lin_mapping_cb, + NULL, /* reset */ + spdu_lin_mapping_uat_fields + ); + + prefs_register_uat_preference(spdu_module, "_spdu_lin_mapping", "LIN Mappings", + "A table to map LIN payloads to Signal PDUs", spdu_lin_mapping_uat); + + spdu_pdu_transport_mapping_uat = uat_new("PDU Transport", sizeof(spdu_pdu_transport_mapping_uat_t), DATAFILE_SPDU_PDU_TRANSPORT_MAPPING, TRUE, (void**)&spdu_pdu_transport_mapping, @@ -1757,7 +1905,7 @@ proto_register_signal_pdu(void) { void proto_reg_handoff_signal_pdu(void) { - static gboolean initialized = FALSE; + static gboolean initialized = FALSE; if (!initialized) { signal_pdu_handle_someip = register_dissector("signal_pdu_over_someip", dissect_spdu_message_someip, proto_signal_pdu); @@ -1770,6 +1918,8 @@ proto_reg_handoff_signal_pdu(void) { dissector_add_for_decode_as("flexray.subdissector", signal_pdu_handle_flexray); heur_dissector_add("flexray", dissect_spdu_message_flexray_heur, "Signal-PDU-Heuristic", "signal_pdu_flexray_heur", proto_signal_pdu, HEURISTIC_ENABLE); + signal_pdu_handle_lin = register_dissector("signal_pdu_over_lin", dissect_spdu_message_lin, proto_signal_pdu); + signal_pdu_handle_pdu_transport = register_dissector("signal_pdu_over_pdu_transport", dissect_spdu_message_pdu_transport, proto_signal_pdu); initialized = TRUE; diff --git a/epan/dissectors/packet-tecmp.c b/epan/dissectors/packet-tecmp.c index 55908c85fb..9c3f6dfd46 100644 --- a/epan/dissectors/packet-tecmp.c +++ b/epan/dissectors/packet-tecmp.c @@ -27,6 +27,7 @@ #include <epan/proto_data.h> #include <packet-socketcan.h> #include <packet-flexray.h> +#include <packet-lin.h> void proto_register_tecmp(void); void proto_reg_handoff_tecmp(void); @@ -49,6 +50,8 @@ static dissector_table_t fr_subdissector_table; static heur_dissector_list_t fr_heur_subdissector_list; static heur_dtbl_entry_t *fr_heur_dtbl_entry; +static dissector_table_t lin_subdissector_table; + /* Header fields */ /* TECMP */ @@ -1098,6 +1101,7 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree struct can_info can_info; flexray_identifier fr_info; + lin_info_t lin_info; static int * const tecmp_payload_id_flags_can_11[] = { &hf_tecmp_payload_data_id_type, @@ -1135,7 +1139,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(tecmp_tree, hf_tecmp_payload_data_id_field_8bit, sub_tvb, offset2, 1, ENC_NA); + proto_tree_add_item_ret_uint(tecmp_tree, hf_tecmp_payload_data_id_field_8bit, sub_tvb, offset2, 1, ENC_NA, &(lin_info.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; @@ -1146,7 +1150,11 @@ dissect_tecmp_log_or_replay_stream(tvbuff_t *tvb, packet_info *pinfo, proto_tree } if (length2 > 0) { - proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_payload, sub_tvb, offset2, (gint)length2, ENC_NA); + 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); + } offset2 += (gint)length2; proto_tree_add_item(tecmp_tree, hf_tecmp_payload_data_checksum_8bit, sub_tvb, offset2, 1, ENC_NA); } @@ -1802,6 +1810,9 @@ proto_reg_handoff_tecmp(void) { fr_subdissector_table = find_dissector_table("flexray.subdissector"); fr_heur_subdissector_list = find_heur_dissector_list("flexray"); + + lin_subdissector_table = find_dissector_table("lin.frame_id"); + } /* |