can: more specific dissector tables for CAN IDs and extended IDs

Introduces two new dissector tables can.id and can.extended_id to enable a
more precise control of subdissectors dependent on the can id which is often
used to identify the the payload.

Since standard CAN IDs and extended IDs can be used in the same network and
their ranges overlap it is necessary to have two different dissector tables.

Existing Decode as dissector table can.subdissector stays as is to prevent a
breaking change. But new dissector tables can.id and can.extended_id get
priority over can.subdissector since they are more specific. Id they get a
match can.subdissector won't be called.

New dissector tables can.id and can.extended_id are accessible in lua scripts
via DissectorTable:add() while can.subdissector unfortunately is not.

For related Discussion see MR !3405
This commit is contained in:
Developer Alexander 2021-07-14 20:35:12 +02:00 committed by Wireshark GitLab Utility
parent 34ef2066e5
commit 2a1ebd1e91
4 changed files with 58 additions and 44 deletions

View File

@ -102,7 +102,9 @@ static heur_dtbl_entry_t *heur_dtbl_entry;
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
static dissector_table_t subdissector_table;
static dissector_table_t can_id_dissector_table = NULL;
static dissector_table_t can_extended_id_dissector_table = NULL;
static dissector_table_t subdissector_table = NULL;
static dissector_handle_t socketcan_bigendian_handle;
static dissector_handle_t socketcan_hostendian_handle;
static dissector_handle_t socketcan_fd_handle;
@ -161,9 +163,41 @@ static const value_string can_err_trx_canl_vals[] =
{ 0, NULL }
};
gboolean
socketcan_call_subdissectors(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, struct can_info* can_info, const gboolean use_heuristics_first)
{
dissector_table_t effective_can_id_dissector_table = (can_info->id & CAN_EFF_FLAG) ? can_extended_id_dissector_table : can_id_dissector_table;
guint32 effective_can_id = (can_info->id & CAN_EFF_FLAG) ? can_info->id & CAN_EFF_MASK : can_info->id & CAN_SFF_MASK;
if (!dissector_try_uint_new(effective_can_id_dissector_table, effective_can_id, tvb, pinfo, tree, TRUE, can_info))
{
if (!use_heuristics_first)
{
if (!dissector_try_payload_new(subdissector_table, tvb, pinfo, tree, TRUE, can_info))
{
if (!dissector_try_heuristic(heur_subdissector_list, tvb, pinfo, tree, &heur_dtbl_entry, can_info))
{
return FALSE;
}
}
}
else
{
if (!dissector_try_heuristic(heur_subdissector_list, tvb, pinfo, tree, &heur_dtbl_entry, can_info))
{
if (!dissector_try_payload_new(subdissector_table, tvb, pinfo, tree, FALSE, can_info))
{
return FALSE;
}
}
}
}
return TRUE;
}
static int
dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint encoding)
dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint encoding)
{
proto_tree *can_tree;
proto_item *ti;
@ -317,25 +351,9 @@ dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
next_tvb = tvb_new_subset_length(tvb, CAN_DATA_OFFSET, can_info.len);
if (!heuristic_first)
if (!socketcan_call_subdissectors(next_tvb, pinfo, tree, &can_info, heuristic_first))
{
if (!dissector_try_payload_new(subdissector_table, next_tvb, pinfo, tree, TRUE, &can_info))
{
if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &heur_dtbl_entry, &can_info))
{
call_data_dissector(next_tvb, pinfo, tree);
}
}
}
else
{
if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &heur_dtbl_entry, &can_info))
{
if (!dissector_try_payload_new(subdissector_table, next_tvb, pinfo, tree, FALSE, &can_info))
{
call_data_dissector(next_tvb, pinfo, tree);
}
}
call_data_dissector(next_tvb, pinfo, tree);
}
}
@ -417,25 +435,9 @@ dissect_socketcanfd_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
next_tvb = tvb_new_subset_length(tvb, CAN_DATA_OFFSET, can_info.len);
if(!heuristic_first)
if (!socketcan_call_subdissectors(next_tvb, pinfo, tree, &can_info, heuristic_first))
{
if (!dissector_try_payload_new(subdissector_table, next_tvb, pinfo, tree, TRUE, &can_info))
{
if(!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &heur_dtbl_entry, &can_info))
{
call_data_dissector(next_tvb, pinfo, tree);
}
}
}
else
{
if (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &heur_dtbl_entry, &can_info))
{
if(!dissector_try_payload_new(subdissector_table, next_tvb, pinfo, tree, FALSE, &can_info))
{
call_data_dissector(next_tvb, pinfo, tree);
}
}
call_data_dissector(next_tvb, pinfo, tree);
}
if (tvb_captured_length_remaining(tvb, CAN_DATA_OFFSET+can_info.len) > 0)
@ -462,7 +464,7 @@ proto_register_socketcan(void)
&hf_can_infoent_ext,
{
"Identifier", "can.id",
FT_UINT32, BASE_HEX,
FT_UINT32, BASE_DEC_HEX,
NULL, CAN_EFF_MASK,
NULL, HFILL
}
@ -471,7 +473,7 @@ proto_register_socketcan(void)
&hf_can_infoent_std,
{
"Identifier", "can.id",
FT_UINT32, BASE_HEX,
FT_UINT32, BASE_DEC_HEX,
NULL, CAN_SFF_MASK,
NULL, HFILL
}
@ -865,6 +867,10 @@ proto_register_socketcan(void)
" before using a sub-dissector registered to \"decode as\"",
&heuristic_first);
can_id_dissector_table = register_dissector_table("can.id", "CAN ID", proto_can, FT_UINT32, BASE_DEC);
can_extended_id_dissector_table = register_dissector_table("can.extended_id", "CAN Extended ID", proto_can, FT_UINT32, BASE_DEC);
subdissector_table = register_decode_as_next_proto(proto_can, "can.subdissector", "CAN next level dissector", NULL);
heur_subdissector_list = register_heur_dissector_list("can", proto_can);

View File

@ -10,6 +10,11 @@
#ifndef __PACKET_SOCKETCAN_H__
#define __PACKET_SOCKETCAN_H__
#include <epan/tvbuff.h>
#include <epan/packet_info.h>
#include <epan/proto.h>
/* Structure that gets passed between dissectors. */
struct can_info
{
@ -49,6 +54,9 @@ typedef struct can_info can_info_t;
#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */
#define CAN_ERR_RESERVED 0x1FFFFE00U /* reserved bits */
gboolean socketcan_call_subdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct can_info *can_info, const gboolean use_heuristics_first);
#endif /* __PACKET_SOCKETCAN_H__ */
/*

View File

@ -157,7 +157,7 @@ header ::= version ENDL maybe_lines
state->entry_type = LOG_ENTRY_HEADER;
state->header.start_date = S.date;
state->header.start_time = S.time;
state->header.protocol = (protocol_t)P.v0;
state->header.protocol = (protocol_type_t)P.v0;
state->header.data_mode = (data_mode_t)D.v0;
state->header.time_mode = (time_mode_t)T.v0;
}

View File

@ -35,7 +35,7 @@ typedef enum {
PROTOCOL_CAN,
PROTOCOL_LIN,
PROTOCOL_J1939,
} protocol_t;
} protocol_type_t;
typedef enum {
DATA_MODE_UNKNOWN = 0,
@ -100,7 +100,7 @@ typedef struct {
typedef struct {
gint64 file_start_offset;
gint64 file_end_offset;
protocol_t protocol;
protocol_type_t protocol;
data_mode_t data_mode;
time_mode_t time_mode;
msg_date_t start_date;