dissectors: can: Handle CAN id flags

The change adds support of CAN flags stored in ids.
The flags allow dissectors to distinguish error frames,
remote transmission request frames and identify id type used (either
standard 11-bit or extended 29-bit).

Addition of bit flags allowed to add more checks whether a CAN frame may
be decoded by a particular dissector. I.e. some dissectors work only
with 11-bit ids (CANopen, DeviceNet) some only with 29-bit (J1939,
ISObus), others should be fine with bot types (OBD-II, ISO 15765).

The change also fixes 2 bugs in the DeviceNet dissector:
* removed byte swapping of CAN id (the pcap file seems to be broken;
  verified dissector operation with random traffic generated by cangen)
* fixed "Warn Dissector bug, protocol DeviceNet, in packet N":
  added a default value for fragmented message type string value lookup.

Bug: 15418
Change-Id: I70e91130789bb3367fe19e51489cd34e97d678a6
Reviewed-on: https://code.wireshark.org/review/31471
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Maksim Salau 2019-01-09 21:46:38 +03:00 committed by Anders Broman
parent eba51f9122
commit eaee707941
9 changed files with 97 additions and 63 deletions

View File

@ -23,7 +23,12 @@
#include <epan/dissectors/packet-socketcan.h>
#define CAN_FRAME_LEN 15
#define CAN_DATA_OFFSET 5
#define CAN_ID_OFFSET 0
#define CAN_DLC_OFFSET 4
#define CAN_DATA_OFFSET 5
#define CAN_EXT_FLAG_OFFSET 13
#define CAN_RTR_FLAG_OFFSET 14
static const gchar magic[] = "ISO11898";
@ -88,15 +93,18 @@ dissect_caneth_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *da
proto_item *ti;
guint32 data_len;
guint32 raw_can_id;
gint8 ext_flag = 1;
gint8 ext_flag;
gint8 rtr_flag;
tvbuff_t* next_tvb;
struct can_identifier can_id;
ti = proto_tree_add_item(tree, proto_can, tvb, 0, -1, ENC_NA);
can_tree = proto_item_add_subtree(ti, ett_caneth_can);
ext_flag = tvb_get_guint8(tvb, 13);
proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_ident_ext, tvb, 0, 4, ENC_LITTLE_ENDIAN, &raw_can_id);
ext_flag = tvb_get_guint8(tvb, CAN_EXT_FLAG_OFFSET);
rtr_flag = tvb_get_guint8(tvb, CAN_RTR_FLAG_OFFSET);
proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_ident_ext, tvb, CAN_ID_OFFSET, 4, ENC_LITTLE_ENDIAN, &raw_can_id);
if (ext_flag)
{
can_id.id = raw_can_id & CAN_EFF_MASK;
@ -106,9 +114,11 @@ dissect_caneth_can(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *da
can_id.id = raw_can_id & CAN_SFF_MASK;
}
proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_len, tvb, 4, 1, ENC_NA, &data_len);
proto_tree_add_item(can_tree, hf_caneth_can_extflag, tvb, 13, 1, ENC_NA);
proto_tree_add_item(can_tree, hf_caneth_can_rtrflag, tvb, 14, 1, ENC_NA);
can_id.id |= (ext_flag ? CAN_EFF_FLAG : 0) | (rtr_flag ? CAN_RTR_FLAG : 0);
proto_tree_add_item_ret_uint(can_tree, hf_caneth_can_len, tvb, CAN_DLC_OFFSET, 1, ENC_NA, &data_len);
proto_tree_add_item(can_tree, hf_caneth_can_extflag, tvb, CAN_EXT_FLAG_OFFSET, 1, ENC_NA);
proto_tree_add_item(can_tree, hf_caneth_can_rtrflag, tvb, CAN_RTR_FLAG_OFFSET, 1, ENC_NA);
next_tvb = tvb_new_subset_length(tvb, CAN_DATA_OFFSET, data_len);

View File

@ -1083,6 +1083,12 @@ dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
DISSECTOR_ASSERT(data);
can_id = *((struct can_identifier*)data);
if (can_id.id & (CAN_ERR_FLAG | CAN_RTR_FLAG | CAN_EFF_FLAG))
{
/* Error, RTR and frames with extended ids are not for us. */
return 0;
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANopen");
col_clear(pinfo->cinfo, COL_INFO);

View File

@ -31,7 +31,7 @@
void proto_register_devicenet(void);
void proto_reg_handoff_devicenet(void);
#define DEVICENET_CANID_MASK 0x7FF
#define DEVICENET_CANID_MASK CAN_SFF_MASK
#define MESSAGE_GROUP_1_ID 0x3FF
#define MESSAGE_GROUP_1_MSG_MASK 0x3C0
#define MESSAGE_GROUP_1_MAC_ID_MASK 0x03F
@ -418,13 +418,9 @@ static int dissect_devicenet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
DISSECTOR_ASSERT(data);
can_id = *((struct can_identifier*)data);
/* XXX - Not sure this is correct. But the capture provided in
* bug 8564 provides CAN ID in little endian format, so this makes it work */
can_id.id = GUINT32_SWAP_LE_BE(can_id.id);
if (can_id.id & (~DEVICENET_CANID_MASK))
if (can_id.id & (CAN_ERR_FLAG | CAN_RTR_FLAG | CAN_EFF_FLAG))
{
/* Not for us */
/* Error, RTR and frames with extended ids are not for us. */
return 0;
}
@ -551,7 +547,10 @@ static int dissect_devicenet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
/* TODO: Handle fragmentation */
proto_tree_add_expert(content_tree, pinfo, &ei_devicenet_frag_not_supported, tvb, offset, -1);
col_set_str(pinfo->cinfo, COL_INFO, try_val_to_str((tvb_get_guint8(tvb, offset) & 0xC0) >> 6, devicenet_fragmented_message_type_vals));
col_set_str(pinfo->cinfo, COL_INFO,
val_to_str_const((tvb_get_guint8(tvb, offset) & 0xC0) >> 6,
devicenet_fragmented_message_type_vals,
"Unknown fragmented message type"));
}
else
{

View File

@ -161,7 +161,7 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
proto_item *message_type_item;
tvbuff_t* next_tvb = NULL;
guint8 pci, message_type;
can_identifier_t* can_info;
can_identifier_t can_id;
iso15765_identifier_t* iso15765_info;
guint8 ae = (addressing == NORMAL_ADDRESSING)?0:1;
guint8 frag_id_low = 0;
@ -170,17 +170,23 @@ dissect_iso15765(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
gboolean fragmented = FALSE;
gboolean complete = FALSE;
DISSECTOR_ASSERT(data);
can_id = *((can_identifier_t*)data);
if (can_id.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);
DISSECTOR_ASSERT(data);
can_info = ((can_identifier_t*)data);
iso15765_info = (iso15765_identifier_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_iso15765, 0);
if (!iso15765_info) {
iso15765_info = wmem_new0(wmem_file_scope(), iso15765_identifier_t);
iso15765_info->id = can_info->id;
iso15765_info->id = can_id.id;
iso15765_info->last = FALSE;
p_add_proto_data(wmem_file_scope(), pinfo, proto_iso15765, 0, iso15765_info);
}

View File

@ -316,6 +316,13 @@ dissect_isobus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
DISSECTOR_ASSERT(data);
can_id = *((struct can_identifier*)data);
if ((can_id.id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) ||
!(can_id.id & CAN_EFF_FLAG))
{
/* Error, RTR and frames with standard ids are not for us. */
return 0;
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISObus");
col_clear(pinfo->cinfo, COL_INFO);

View File

@ -170,8 +170,8 @@ static int dissect_j1939(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo
DISSECTOR_ASSERT(data);
can_id = *((struct can_identifier*)data);
if ((can_id.raw_id & CAN_ERR_FLAG) ||
!(can_id.raw_id & CAN_EFF_FLAG))
if ((can_id.id & CAN_ERR_FLAG) ||
!(can_id.id & CAN_EFF_FLAG))
{
/* Error frames and frames with standards ids are not for us */
return 0;
@ -184,51 +184,51 @@ static int dissect_j1939(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, vo
j1939_tree = proto_item_add_subtree(ti, ett_j1939);
can_tree = proto_tree_add_subtree_format(j1939_tree, tvb, 0, 0,
ett_j1939_can, NULL, "CAN Identifier: 0x%08x", can_id.raw_id);
can_id_item = proto_tree_add_uint(can_tree, hf_j1939_can_id, tvb, 0, 0, can_id.raw_id);
ett_j1939_can, NULL, "CAN Identifier: 0x%08x", can_id.id);
can_id_item = proto_tree_add_uint(can_tree, hf_j1939_can_id, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(can_id_item);
ti = proto_tree_add_uint(can_tree, hf_j1939_priority, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_priority, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
ti = proto_tree_add_uint(can_tree, hf_j1939_extended_data_page, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_extended_data_page, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
ti = proto_tree_add_uint(can_tree, hf_j1939_data_page, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_data_page, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
ti = proto_tree_add_uint(can_tree, hf_j1939_pdu_format, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_pdu_format, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
ti = proto_tree_add_uint(can_tree, hf_j1939_pdu_specific, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_pdu_specific, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
ti = proto_tree_add_uint(can_tree, hf_j1939_src_addr, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_src_addr, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
/* Set source address */
src_addr = (guint8*)wmem_alloc(pinfo->pool, 1);
*src_addr = (guint8)(can_id.raw_id & 0xFF);
*src_addr = (guint8)(can_id.id & 0xFF);
set_address(&pinfo->src, j1939_address_type, 1, (const void*)src_addr);
pgn = (can_id.raw_id & 0x3FFFF00) >> 8;
pgn = (can_id.id & 0x3FFFF00) >> 8;
/* If PF < 240, PS is destination address, last byte of PGN is cleared */
if (((can_id.raw_id & 0xFF0000) >> 16) < 240)
if (((can_id.id & 0xFF0000) >> 16) < 240)
{
pgn &= 0x3FF00;
ti = proto_tree_add_uint(can_tree, hf_j1939_dst_addr, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_dst_addr, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
}
else
{
ti = proto_tree_add_uint(can_tree, hf_j1939_group_extension, tvb, 0, 0, can_id.raw_id);
ti = proto_tree_add_uint(can_tree, hf_j1939_group_extension, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
}
/* Fill in "destination" address even if its "broadcast" */
dest_addr = (guint8*)wmem_alloc(pinfo->pool, 1);
*dest_addr = (guint8)((can_id.raw_id & 0xFF00) >> 8);
*dest_addr = (guint8)((can_id.id & 0xFF00) >> 8);
set_address(&pinfo->dst, j1939_address_type, 1, (const void*)dest_addr);
col_add_fstr(pinfo->cinfo, COL_INFO, "PGN: %-6" PRIu32, pgn);
if (can_id.raw_id & CAN_RTR_FLAG)
if (can_id.id & CAN_RTR_FLAG)
{
/* RTR frames don't have payload */
col_append_fstr(pinfo->cinfo, COL_INFO, " %s", "(Remote Transmission Request)");

View File

@ -1228,7 +1228,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_identifier *can_id = (struct can_identifier *) data;
struct can_identifier can_id;
guint32 can_id_only;
struct obdii_packet_info oinfo;
proto_tree *obdii_tree;
@ -1237,8 +1238,15 @@ dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
guint8 data_bytes;
guint8 mode;
DISSECTOR_ASSERT(data);
can_id = *((struct can_identifier *) data);
can_id_only = can_id.id & ~CAN_FLAG_MASK;
/* validate */
if (!can_id || !(can_id->id == ODBII_CAN_QUERY_ID || (can_id->id >= ODBII_CAN_RESPONSE_ID_MIN && can_id->id <= ODBII_CAN_RESPONSE_ID_MAX)))
if (can_id.id & (CAN_ERR_FLAG | CAN_RTR_FLAG))
return 0;
if (!(can_id_only == ODBII_CAN_QUERY_ID || (can_id_only >= ODBII_CAN_RESPONSE_ID_MIN && can_id_only <= ODBII_CAN_RESPONSE_ID_MAX)))
return 0;
if (tvb_reported_length(tvb) != 8)
@ -1247,13 +1255,13 @@ dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
data_bytes = tvb_get_guint8(tvb, 0);
mode = tvb_get_guint8(tvb, 1);
if (can_id->id == ODBII_CAN_QUERY_ID)
if (can_id_only == ODBII_CAN_QUERY_ID)
{
if (!(data_bytes == 2 || data_bytes == 3))
return 0;
}
if ((can_id->id >= ODBII_CAN_RESPONSE_ID_MIN && can_id->id <= ODBII_CAN_RESPONSE_ID_MAX))
if ((can_id_only >= ODBII_CAN_RESPONSE_ID_MIN && can_id_only <= ODBII_CAN_RESPONSE_ID_MAX))
{
if (!(data_bytes >= 3 && data_bytes <= 7))
return 0;
@ -1274,14 +1282,14 @@ dissect_obdii(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
memset(&oinfo, 0, sizeof(oinfo));
oinfo.pinfo = pinfo;
oinfo.can_id = can_id->id;
oinfo.can_id = can_id_only;
oinfo.data_bytes = data_bytes;
oinfo.mode = mode;
if (can_id->id == ODBII_CAN_QUERY_ID)
if (can_id_only == ODBII_CAN_QUERY_ID)
return dissect_obdii_query(tvb, &oinfo, obdii_tree);
if (can_id->id >= ODBII_CAN_RESPONSE_ID_MIN && can_id->id <= ODBII_CAN_RESPONSE_ID_MAX)
if (can_id_only >= ODBII_CAN_RESPONSE_ID_MIN && can_id_only <= ODBII_CAN_RESPONSE_ID_MAX)
return dissect_obdii_response(tvb, &oinfo, obdii_tree);
/* never here */

View File

@ -80,7 +80,6 @@ dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint8 frame_type;
gint frame_len;
struct can_identifier can_id;
guint32 raw_can_id;
tvbuff_t* next_tvb;
int * can_flags[] = {
&hf_can_ident_ext,
@ -90,34 +89,34 @@ dissect_socketcan_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
NULL,
};
raw_can_id = tvb_get_guint32(tvb, 0, encoding);
frame_len = tvb_get_guint8( tvb, CAN_LEN_OFFSET);
can_id.id = tvb_get_guint32(tvb, 0, encoding);
frame_len = tvb_get_guint8(tvb, CAN_LEN_OFFSET);
if (raw_can_id & CAN_EFF_FLAG)
if (can_id.id & CAN_EFF_FLAG)
{
frame_type = LINUX_CAN_EXT;
can_id.id = raw_can_id & CAN_EFF_MASK;
can_id.id &= (CAN_EFF_MASK | CAN_FLAG_MASK);
}
else
{
frame_type = LINUX_CAN_STD;
can_id.id = raw_can_id & CAN_SFF_MASK;
can_id.id &= (CAN_SFF_MASK | CAN_FLAG_MASK);
can_flags[0] = &hf_can_ident_std;
}
can_id.raw_id = raw_can_id;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CAN");
col_clear(pinfo->cinfo, COL_INFO);
/* Error Message Frames are only encapsulated in Classic CAN frames */
if (raw_can_id & CAN_ERR_FLAG)
if (can_id.id & CAN_ERR_FLAG)
{
frame_type = LINUX_CAN_ERR;
}
col_add_fstr(pinfo->cinfo, COL_INFO, "%s: 0x%08x ",
val_to_str(frame_type, frame_type_vals, "Unknown (0x%02x)"), can_id.id);
if (raw_can_id & CAN_RTR_FLAG)
val_to_str(frame_type, frame_type_vals, "Unknown (0x%02x)"), (can_id.id & ~CAN_FLAG_MASK));
if (can_id.id & CAN_RTR_FLAG)
{
col_append_str(pinfo->cinfo, COL_INFO, "(Remote Transmission Request)");
}
@ -179,7 +178,6 @@ dissect_socketcanfd_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint8 frame_type;
gint frame_len;
struct can_identifier can_id;
guint32 raw_can_id;
tvbuff_t* next_tvb;
int * can_flags_fd[] = {
&hf_can_ident_ext,
@ -192,27 +190,26 @@ dissect_socketcanfd_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
NULL,
};
raw_can_id = tvb_get_guint32(tvb, 0, encoding);
frame_len = tvb_get_guint8( tvb, CAN_LEN_OFFSET);
can_id.id = tvb_get_guint32(tvb, 0, encoding);
frame_len = tvb_get_guint8(tvb, CAN_LEN_OFFSET);
if (raw_can_id & CAN_EFF_FLAG)
if (can_id.id & CAN_EFF_FLAG)
{
frame_type = LINUX_CAN_EXT;
can_id.id = raw_can_id & CAN_EFF_MASK;
can_id.id &= (CAN_EFF_MASK | CAN_FLAG_MASK);
}
else
{
frame_type = LINUX_CAN_STD;
can_id.id = raw_can_id & CAN_SFF_MASK;
can_id.id &= (CAN_SFF_MASK | CAN_FLAG_MASK);
can_flags_fd[0] = &hf_can_ident_std;
}
can_id.raw_id = raw_can_id;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANFD");
col_clear(pinfo->cinfo, COL_INFO);
col_add_fstr(pinfo->cinfo, COL_INFO, "%s: 0x%08x %s",
val_to_str(frame_type, frame_type_vals, "Unknown (0x%02x)"), can_id.id,
val_to_str(frame_type, frame_type_vals, "Unknown (0x%02x)"), (can_id.id & ~CAN_FLAG_MASK),
tvb_bytes_to_str_punct(wmem_packet_scope(), tvb, CAN_DATA_OFFSET, frame_len, ' '));
ti = proto_tree_add_item(tree, proto_canfd, tvb, 0, -1, ENC_NA);

View File

@ -14,7 +14,6 @@
struct can_identifier
{
guint32 id;
guint32 raw_id;
};
typedef struct can_identifier can_identifier_t;
@ -29,6 +28,8 @@ typedef struct can_identifier can_identifier_t;
#define CAN_RTR_FLAG 0x40000000 /* remote transmission request */
#define CAN_ERR_FLAG 0x20000000 /* error frame */
#define CAN_FLAG_MASK (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_ERR_FLAG)
#define CAN_EFF_MASK 0x1FFFFFFF /* extended frame format (EFF) has a 29 bit identifier */
#define CAN_SFF_MASK 0x000007FF /* standard frame format (SFF) has a 11 bit identifier */