aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Lars Völker <lars.voelker@technica-engineering.de>2021-07-14 10:34:15 +0200
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-07-14 09:31:06 +0000
commit95dc4f52bc6bbd1a4608e7ba81ccc0c1fa48f7ba (patch)
tree3472ea659400e262402d7fd70f9fcfe851cf1119
parentcc36b7413932350cd7bfa90396f3d6b5321af5fb (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.adoc1
-rw-r--r--epan/dissectors/CMakeLists.txt3
-rw-r--r--epan/dissectors/packet-iso15765.c108
-rw-r--r--epan/dissectors/packet-iso15765.h39
-rw-r--r--epan/dissectors/packet-lin.c278
-rw-r--r--epan/dissectors/packet-lin.h40
-rw-r--r--epan/dissectors/packet-obd-ii.c20
-rw-r--r--epan/dissectors/packet-signal-pdu.c160
-rw-r--r--epan/dissectors/packet-tecmp.c15
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", &register_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");
+
}
/*