Modbus: Add dissection of each bit for holding coils and discrete inputs

Bug: 13734
Change-Id: Ifd89bc1055edd7c123395ce0511594fc88d151a2
Reviewed-on: https://code.wireshark.org/review/21759
Reviewed-by: Graham Bloice <graham.bloice@trihedral.com>
Petri-Dish: Graham Bloice <graham.bloice@trihedral.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Graham Bloice 2017-05-25 23:00:32 +01:00 committed by Michael Mann
parent 1b02cb9b70
commit 1420e0a13a
1 changed files with 65 additions and 23 deletions

View File

@ -141,6 +141,8 @@ static int hf_modbus_more_follows = -1;
static int hf_modbus_next_object_id = -1;
static int hf_modbus_object_str_value = -1;
static int hf_modbus_object_value = -1;
static int hf_modbus_bitnum = -1;
static int hf_modbus_bitval = -1;
static int hf_modbus_regnum16 = -1;
static int hf_modbus_regnum32 = -1;
static int hf_modbus_regval_uint16 = -1;
@ -163,6 +165,7 @@ static gint ett_events_recv = -1;
static gint ett_events_send = -1;
static gint ett_device_id_objects = -1;
static gint ett_device_id_object_items = -1;
static gint ett_bit = -1;
static gint ett_register = -1;
static expert_field ei_mbrtu_crc16_incorrect = EI_INIT;
@ -196,6 +199,7 @@ typedef struct {
guint8 function_code;
gint register_format;
guint16 reg_base;
guint16 num_reg;
guint32 req_frame_num;
gboolean request_found;
} modbus_pkt_info_t;
@ -851,14 +855,18 @@ dissect_mbrtu_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat
/* Common to both Modbus/TCP and Modbus RTU dissectors */
static void
dissect_modbus_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 function_code,
gint payload_start, gint payload_len, gint register_format, guint16 reg_base)
gint payload_start, gint payload_len, gint register_format, guint16 reg_base, guint16 num_reg)
{
gint reported_len, data_offset;
guint8 data8, ii;
gboolean data_bool;
gint16 data16s;
gint32 data32s;
guint16 data16, modflt_lo, modflt_hi, reg_num=reg_base;
guint32 data32, modflt_comb;
gfloat data_float, modfloat;
proto_tree *bit_tree = NULL;
proto_item *bitnum_ti = NULL;
proto_item *register_item = NULL;
proto_tree *register_tree = NULL;
tvbuff_t *next_tvb;
@ -892,6 +900,28 @@ dissect_modbus_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8
next_tvb = tvb_new_subset_length_caplen(tvb, payload_start, payload_len, reported_len);
switch ( function_code ) {
case READ_COILS:
case READ_DISCRETE_INPUTS:
/* The bit data is packed, 8 bits per byte of data, loop over each bit */
while (data_offset < payload_len) {
data8 = tvb_get_guint8(next_tvb, data_offset);
for (ii = 0; ii < 8; ii++) {
data_bool = (data8 & (1 << ii)) > 0;
bit_tree = proto_tree_add_subtree_format(tree, next_tvb, data_offset, 1,
ett_bit, NULL, "Bit %u : %u", reg_num, data_bool);
bitnum_ti = proto_tree_add_uint(bit_tree, hf_modbus_bitnum, next_tvb, data_offset, 1, reg_num);
PROTO_ITEM_SET_GENERATED(bitnum_ti);
proto_tree_add_boolean(bit_tree, hf_modbus_bitval, next_tvb, data_offset, 1, data_bool);
reg_num++;
/* If all the requested bits have been read, stop now */
if ((reg_num - reg_base) >= num_reg) {
break;
}
}
data_offset++;
}
break;
case READ_HOLDING_REGS:
case READ_INPUT_REGS:
@ -1024,13 +1054,13 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
case WRITE_SINGLE_COIL:
proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, ENC_BIG_ENDIAN);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 1, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 1, pkt_info->register_format, reg_base, 0);
proto_tree_add_item(modbus_tree, hf_modbus_padding, tvb, payload_start + 3, 1, ENC_NA);
break;
case WRITE_SINGLE_REG:
proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, ENC_BIG_ENDIAN);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 2, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 2, pkt_info->register_format, reg_base, 0);
break;
case READ_EXCEPT_STAT:
@ -1066,7 +1096,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
case CLEAR_OVERRUN_COUNTER_AND_FLAG:
default:
if (payload_len > 2)
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start+2, payload_len-2, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start+2, payload_len-2, pkt_info->register_format, reg_base, 0);
break;
}
break;
@ -1075,7 +1105,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, ENC_BIG_ENDIAN);
byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4);
proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1, byte_cnt);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 5, byte_cnt, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 5, byte_cnt, pkt_info->register_format, reg_base, 0);
break;
case WRITE_MULT_REGS:
@ -1084,7 +1114,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, ENC_BIG_ENDIAN);
byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4);
proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1, byte_cnt);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 5, byte_cnt, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 5, byte_cnt, pkt_info->register_format, reg_base, 0);
break;
case READ_FILE_RECORD:
@ -1119,7 +1149,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, ENC_BIG_ENDIAN);
proto_tree_add_uint(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, group_word_cnt);
dissect_modbus_data(tvb, pinfo, group_tree, function_code, group_offset + 7, group_byte_cnt - 7, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, group_tree, function_code, group_offset + 7, group_byte_cnt - 7, pkt_info->register_format, reg_base, 0);
group_offset += group_byte_cnt;
byte_cnt -= group_byte_cnt;
ii++;
@ -1139,7 +1169,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
proto_tree_add_item(modbus_tree, hf_modbus_writewordcnt, tvb, payload_start + 6, 2, ENC_BIG_ENDIAN);
byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 8);
proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 8, 1, byte_cnt);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 9, byte_cnt, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 9, byte_cnt, pkt_info->register_format, reg_base, 0);
break;
case READ_FIFO_QUEUE:
@ -1160,7 +1190,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
/* CANopen protocol not part of the Modbus/TCP specification */
default:
if (payload_len > 1)
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len-1, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len-1, pkt_info->register_format, reg_base, 0);
break;
}
@ -1169,7 +1199,7 @@ dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tre
case REPORT_SLAVE_ID:
default:
if (payload_len > 0)
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info->register_format, reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info->register_format, reg_base, 0);
break;
} /* Function Code */
@ -1202,29 +1232,29 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
case READ_DISCRETE_INPUTS:
byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base, pkt_info->num_reg);
break;
case READ_HOLDING_REGS:
case READ_INPUT_REGS:
byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base, 0);
break;
case WRITE_SINGLE_COIL:
proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, ENC_BIG_ENDIAN);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 1, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 1, pkt_info->register_format, pkt_info->reg_base, 0);
proto_tree_add_item(modbus_tree, hf_modbus_padding, tvb, payload_start + 3, 1, ENC_NA);
break;
case WRITE_SINGLE_REG:
proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, ENC_BIG_ENDIAN);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 2, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 2, pkt_info->register_format, pkt_info->reg_base, 0);
break;
case READ_EXCEPT_STAT:
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, 1, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, 1, pkt_info->register_format, pkt_info->reg_base, 0);
break;
case DIAGNOSTICS:
@ -1276,7 +1306,7 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
case FORCE_LISTEN_ONLY_MODE: /* No response anticipated */
default:
if (payload_len > 2)
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start+2, payload_len-2, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start+2, payload_len-2, pkt_info->register_format, pkt_info->reg_base, 0);
break;
} /* diagnostic_code */
break;
@ -1373,7 +1403,7 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
proto_tree_add_uint(group_tree, hf_modbus_bytecnt, tvb, group_offset, 1,
group_byte_cnt);
proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset + 1, 1, ENC_BIG_ENDIAN);
dissect_modbus_data(tvb, pinfo, group_tree, function_code, group_offset + 2, group_byte_cnt - 1, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, group_tree, function_code, group_offset + 2, group_byte_cnt - 1, pkt_info->register_format, pkt_info->reg_base, 0);
group_offset += (group_byte_cnt + 1);
byte_cnt -= (group_byte_cnt + 1);
ii++;
@ -1395,7 +1425,7 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, ENC_BIG_ENDIAN);
proto_tree_add_uint(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, group_word_cnt);
dissect_modbus_data(tvb, pinfo, group_tree, function_code, group_offset + 7, group_byte_cnt - 7, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, group_tree, function_code, group_offset + 7, group_byte_cnt - 7, pkt_info->register_format, pkt_info->reg_base, 0);
group_offset += group_byte_cnt;
byte_cnt -= group_byte_cnt;
ii++;
@ -1411,14 +1441,14 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
case READ_WRITE_REG:
byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base, 0);
break;
case READ_FIFO_QUEUE:
byte_cnt = (guint32)tvb_get_ntohs(tvb, payload_start);
proto_tree_add_uint(modbus_tree, hf_modbus_lbytecnt, tvb, payload_start, 2, byte_cnt);
proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, ENC_BIG_ENDIAN);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 4, byte_cnt - 2, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 4, byte_cnt - 2, pkt_info->register_format, pkt_info->reg_base, 0);
break;
case ENCAP_INTERFACE_TRANSP:
@ -1471,7 +1501,7 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
/* CANopen protocol not part of the Modbus/TCP specification */
default:
if (payload_len > 1)
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len-1, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len-1, pkt_info->register_format, pkt_info->reg_base, 0);
break;
} /* mei_code */
break;
@ -1479,7 +1509,7 @@ dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tr
case REPORT_SLAVE_ID:
default:
if (payload_len > 0)
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info->register_format, pkt_info->reg_base);
dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info->register_format, pkt_info->reg_base, 0);
break;
} /* function code */
@ -1544,7 +1574,7 @@ dissect_modbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
frame_ptr->fnum = pinfo->num;
frame_ptr->function_code = function_code;
pkt_info->reg_base = frame_ptr->base_address = tvb_get_ntohs(tvb, 1);
frame_ptr->num_reg = tvb_get_ntohs(tvb, 3);
pkt_info->num_reg = frame_ptr->num_reg = tvb_get_ntohs(tvb, 3);
wmem_list_prepend(modbus_conv_data->modbus_request_frame_data, frame_ptr);
}
@ -1562,6 +1592,7 @@ dissect_modbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
req_function_code = request_data->function_code;
if ((pinfo->num > req_frame_num) && (req_function_code == function_code)) {
pkt_info->reg_base = request_data->base_address;
pkt_info->num_reg = request_data->num_reg;
pkt_info->request_found = TRUE;
pkt_info->req_frame_num = req_frame_num;
}
@ -1978,6 +2009,16 @@ proto_register_modbus(void)
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_modbus_bitnum,
{ "Bit Number", "modbus.bitnum",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_modbus_bitval,
{ "Bit Value", "modbus.bitval",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL }
},
{ &hf_modbus_regnum16,
{ "Register Number", "modbus.regnum16",
FT_UINT16, BASE_DEC, NULL, 0x0,
@ -2031,6 +2072,7 @@ proto_register_modbus(void)
&ett_events_send,
&ett_device_id_objects,
&ett_device_id_object_items,
&ett_bit,
&ett_register
};