CAN protocols have a CAN ID and up to 8 bytes of data. How the CAN ID and data are presented is the responsibility of the previous layer. Make the interface be passing the CAN ID in dissector data and have the (up to) 8 bytes be the tvb. CAN protocols should treat the CAN ID as "generated" data.

svn path=/trunk/; revision=53792
This commit is contained in:
Michael Mann 2013-12-05 03:36:49 +00:00
parent 0ccb4a7ef4
commit 8d0dc9f935
2 changed files with 77 additions and 72 deletions

View File

@ -107,29 +107,6 @@ static const value_string CAN_open_p2p_msg_type_vals[] = {
#define MT_SDO 6
#define MT_NMT_GUARD 7
/* PDO offsets */
#define CO_PDO_DATA_OFFSET 8
/* SDO offsets */
#define CO_SDO_CMD_OFFSET 8
#define CO_SDO_MAIN_IDX_OFFSET 9
#define CO_SDO_MAIN_SUB_OFFSET 11
#define CO_SDO_DATA_OFFSET 12
/* EMERGENCY offsets */
#define CO_EM_ERR_CODE_OFFSET 8
#define CO_EM_ERR_REG_OFFSET 10
#define CO_EM_ERR_FIELD_OFFSET 11
/* NMT offsets */
#define CO_NMT_CTRL_CS_OFFSET 8
#define CO_NMT_CTRL_NODE_ID_OFFSET 9
#define CO_NMT_GUARD_STATE_OFFSET 8
/* TIME STAMP offsets */
#define CO_TIME_STAMP_MS_OFFSET 8
#define CO_TIME_STAMP_DAYS_OFFSET 12
/* TIME STAMP conversion defines */
#define TS_DAYS_BETWEEN_1970_AND_1984 5113
#define TS_SECONDS_IN_PER_DAY 86400
@ -213,28 +190,34 @@ canopen_detect_msg_type(guint function_code, guint node_id)
}
}
struct can_identifier
{
guint32 id;
};
/* Code to actually dissect the packets */
static void
dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
static int
dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
guint function_code;
guint node_id;
guint32 id;
guint32 time_stamp_msec;
guint32 time_stamp_days;
struct can_identifier can_id;
guint msg_type_id;
nstime_t time_stamp;
gint can_data_len;
gint can_data_len = tvb_reported_length(tvb);
const gchar *function_code_str;
int offset = 0;
DISSECTOR_ASSERT(data);
can_id = *((struct can_identifier*)data);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANopen");
col_clear(pinfo->cinfo, COL_INFO);
can_data_len = tvb_get_guint8(tvb, 4);
id = tvb_get_ntohl(tvb, 0);
node_id = id & 0x7F;
function_code = (id >> 7) & 0xF;
node_id = can_id.id & 0x7F;
function_code = (can_id.id >> 7) & 0x0F;
msg_type_id = canopen_detect_msg_type(function_code, node_id);
@ -248,7 +231,7 @@ dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
col_add_fstr(pinfo->cinfo, COL_INFO, "p2p %s", function_code_str);
}
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
tvb_bytes_to_str_punct(tvb, CO_PDO_DATA_OFFSET, can_data_len, ' '));
tvb_bytes_to_str_punct(tvb, offset, can_data_len, ' '));
if (tree) {
proto_item *ti, *cob_ti, *type_ti;
@ -257,23 +240,23 @@ dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree *canopen_type_tree;
ti = proto_tree_add_item(tree, proto_canopen, tvb, 0, -1, ENC_NA);
canopen_tree = proto_item_add_subtree(ti, ett_canopen);
/* add COB-ID with function code and node id */
cob_ti = proto_tree_add_item(canopen_tree, hf_canopen_cob_id, tvb, 0, 4, ENC_BIG_ENDIAN);
cob_ti = proto_tree_add_uint(canopen_tree, hf_canopen_cob_id, tvb, 0, 0, can_id.id);
canopen_cob_tree = proto_item_add_subtree(cob_ti, ett_canopen);
/* add function code */
proto_tree_add_item(canopen_cob_tree, hf_canopen_function_code, tvb, 0, 4, ENC_BIG_ENDIAN);
ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_function_code, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
/* add node id */
proto_tree_add_item(canopen_cob_tree, hf_canopen_node_id, tvb, 0, 4, ENC_BIG_ENDIAN);
ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_node_id, tvb, 0, 0, can_id.id);
PROTO_ITEM_SET_GENERATED(ti);
/* add CANopen frame type */
type_ti = proto_tree_add_text(canopen_tree, tvb,
(msg_type_id != MT_SYNC) ? 8 : 0,
type_ti = proto_tree_add_text(canopen_tree, tvb, 0,
(msg_type_id != MT_SYNC) ? -1 : 0,
"Type: %s", function_code_str);
canopen_type_tree = proto_item_add_subtree(type_ti, ett_canopen);
@ -282,70 +265,79 @@ dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
case MT_NMT_CTRL:
proto_tree_add_item(canopen_type_tree,
hf_canopen_nmt_ctrl_cs, tvb, CO_NMT_CTRL_CS_OFFSET, 1, ENC_BIG_ENDIAN);
hf_canopen_nmt_ctrl_cs, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(canopen_type_tree,
hf_canopen_nmt_ctrl_node_id, tvb, CO_NMT_CTRL_NODE_ID_OFFSET, 1, ENC_BIG_ENDIAN);
hf_canopen_nmt_ctrl_node_id, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
case MT_NMT_GUARD:
proto_tree_add_item(canopen_type_tree,
hf_canopen_nmt_guard_state, tvb, CO_NMT_GUARD_STATE_OFFSET, 1, ENC_BIG_ENDIAN);
hf_canopen_nmt_guard_state, tvb, offset, 1, ENC_BIG_ENDIAN);
break;
case MT_SYNC:
break;
case MT_TIME_STAMP:
/* calculate the real time stamp */
time_stamp_msec = tvb_get_letohl(tvb, CO_PDO_DATA_OFFSET);
time_stamp_days = tvb_get_ntohs(tvb, CO_PDO_DATA_OFFSET + 4);
time_stamp_msec = tvb_get_letohl(tvb, offset);
time_stamp_days = tvb_get_ntohs(tvb, offset + 4);
time_stamp.secs = (time_stamp_days + TS_DAYS_BETWEEN_1970_AND_1984)
* TS_SECONDS_IN_PER_DAY + (time_stamp_msec / 1000);
time_stamp.nsecs = (time_stamp_msec % 1000) * TS_NANOSEC_PER_MSEC;
proto_tree_add_time(canopen_type_tree,
hf_canopen_time_stamp, tvb, CO_TIME_STAMP_MS_OFFSET, 6, &time_stamp);
hf_canopen_time_stamp, tvb, offset, 6, &time_stamp);
proto_tree_add_uint(canopen_type_tree,
hf_canopen_time_stamp_ms, tvb, CO_TIME_STAMP_MS_OFFSET, 4, time_stamp_msec);
hf_canopen_time_stamp_ms, tvb, offset, 4, time_stamp_msec);
offset += 2;
proto_tree_add_uint(canopen_type_tree,
hf_canopen_time_stamp_days, tvb, CO_TIME_STAMP_DAYS_OFFSET, 2, time_stamp_days);
hf_canopen_time_stamp_days, tvb, offset, 2, time_stamp_days);
break;
case MT_EMERGENCY:
proto_tree_add_item(canopen_type_tree,
hf_canopen_em_err_code, tvb, CO_EM_ERR_CODE_OFFSET, 2, ENC_BIG_ENDIAN);
hf_canopen_em_err_code, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_item(canopen_type_tree,
hf_canopen_em_err_reg, tvb, CO_EM_ERR_REG_OFFSET, 1, ENC_BIG_ENDIAN);
hf_canopen_em_err_reg, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(canopen_type_tree,
hf_canopen_em_err_field, tvb, CO_EM_ERR_FIELD_OFFSET, 4, ENC_NA);
hf_canopen_em_err_field, tvb, offset, 4, ENC_NA);
break;
case MT_PDO:
if (can_data_len != 0) {
proto_tree_add_item(canopen_type_tree,
hf_canopen_pdo_data, tvb, CO_PDO_DATA_OFFSET, can_data_len, ENC_NA);
hf_canopen_pdo_data, tvb, offset, can_data_len, ENC_NA);
}
else {
proto_tree_add_string(canopen_type_tree,
hf_canopen_pdo_data_string, tvb, CO_PDO_DATA_OFFSET, 0, "empty");
hf_canopen_pdo_data_string, tvb, offset, 0, "empty");
}
break;
case MT_SDO:
proto_tree_add_item(canopen_type_tree,
hf_canopen_sdo_cmd, tvb, CO_SDO_CMD_OFFSET, 1, ENC_BIG_ENDIAN);
hf_canopen_sdo_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(canopen_type_tree,
hf_canopen_sdo_main_idx, tvb, CO_SDO_MAIN_IDX_OFFSET, 2, ENC_BIG_ENDIAN);
hf_canopen_sdo_main_idx, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_item(canopen_type_tree,
hf_canopen_sdo_sub_idx, tvb, CO_SDO_MAIN_SUB_OFFSET, 1, ENC_BIG_ENDIAN);
hf_canopen_sdo_sub_idx, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item(canopen_type_tree,
hf_canopen_sdo_data, tvb, CO_SDO_DATA_OFFSET, 4, ENC_NA);
hf_canopen_sdo_data, tvb, offset, 4, ENC_NA);
break;
}
}
return tvb_length(tvb);
}
@ -454,7 +446,7 @@ proto_register_canopen(void)
"CANOPEN",
"canopen");
register_dissector("canopen", dissect_canopen, proto_canopen);
new_register_dissector("canopen", dissect_canopen, proto_canopen);
proto_register_field_array(proto_canopen, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));

View File

@ -2,6 +2,10 @@
* Routines for disassembly of packets from SocketCAN
* Felix Obenhuber <felix@obenhuber.de>
*
* Added support for the DeviceNet Dissector
* Hans-Jörgen Gunnarsson <hag@hms.se>
* Copyright 2013
*
* $Id$
*
* Wireshark - Network traffic analyzer
@ -66,12 +70,23 @@ static dissector_handle_t canopen_handle;
typedef enum {
CAN_DATA_DISSECTOR = 1,
CAN_CANOPEN_DISSECTOR = 2
CAN_CANOPEN_DISSECTOR = 2,
CAN_DEVICENET_DISSECTOR = 3
} Dissector_Option;
/* Structure that gets passed between dissectors. Since it's just a simple 32-bit
value, no sense in creating a header file for it. Just expect subdissectors
to provide their own.
*/
struct can_identifier
{
guint32 id;
};
static const enum_val_t can_high_level_protocol_dissector_options[] = {
{ "raw", "Raw data (no further dissection)", CAN_DATA_DISSECTOR },
{ "CANopen", "CANopen protocol", CAN_CANOPEN_DISSECTOR },
{ "DeviceNet", "DeviceNet protocol", CAN_DEVICENET_DISSECTOR },
{ NULL, NULL, 0 }
};
@ -93,23 +108,24 @@ dissect_socketcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *ti;
guint8 frame_type;
gint frame_len;
guint32 id;
struct can_identifier can_id;
tvbuff_t* next_tvb;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CAN");
col_clear(pinfo->cinfo,COL_INFO);
frame_len = tvb_get_guint8( tvb, CAN_LEN_OFFSET);
id = tvb_get_ntohl(tvb, 0);
can_id.id = tvb_get_ntohl(tvb, 0);
if (id & CAN_RTR_FLAG)
if (can_id.id & CAN_RTR_FLAG)
{
frame_type = LINUX_CAN_RTR;
}
else if (id & CAN_ERR_FLAG)
else if (can_id.id & CAN_ERR_FLAG)
{
frame_type = LINUX_CAN_ERR;
}
else if (id & CAN_EFF_FLAG)
else if (can_id.id & CAN_EFF_FLAG)
{
frame_type = LINUX_CAN_EXT;
}
@ -118,10 +134,10 @@ dissect_socketcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
frame_type = LINUX_CAN_STD;
}
id &= CAN_EFF_MASK;
can_id.id &= CAN_EFF_MASK;
col_add_fstr(pinfo->cinfo, COL_INFO, "%s: 0x%08x",
val_to_str(frame_type, frame_type_vals, "Unknown (0x%02x)"), id);
val_to_str(frame_type, frame_type_vals, "Unknown (0x%02x)"), can_id.id);
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
tvb_bytes_to_str_punct(tvb, CAN_DATA_OFFSET, frame_len, ' '));
@ -135,18 +151,15 @@ dissect_socketcan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_item(can_tree, hf_can_len, tvb, CAN_LEN_OFFSET, 1, ENC_BIG_ENDIAN);
next_tvb = tvb_new_subset_length(tvb, CAN_DATA_OFFSET, frame_len);
switch (can_high_level_protocol_dissector)
{
case CAN_DATA_DISSECTOR:
call_dissector(data_handle,
tvb_new_subset(tvb, CAN_DATA_OFFSET, frame_len, frame_len),
pinfo, tree);
call_dissector(data_handle, next_tvb, pinfo, tree);
break;
case CAN_CANOPEN_DISSECTOR:
/* XXX: The canopen dissector *redissects in a different manner* */
/* the same header bytes dissected above. */
/* What's the right way to handle SocketCan dissection ? */
call_dissector(canopen_handle, tvb, pinfo, tree);
call_dissector_with_data(canopen_handle, next_tvb, pinfo, tree, &can_id);
break;
}
}