/* Globals for Modbus Preferences */
static gint global_mbus_register_format = MODBUS_PREF_REGISTER_FORMAT_UINT16;
+typedef struct {
+ guint8 function_code;
+ gint register_format;
+ guint16 reg_base;
+ guint32 req_frame_num;
+ gboolean request_found;
+} modbus_pkt_info_t;
+
static int
classify_mbtcp_packet(packet_info *pinfo, guint port)
{
/* Code to dissect Modbus request message */
static int
-dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tree, guint8 function_code, gint payload_start, gint payload_len)
+dissect_modbus_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tree, guint8 function_code, gint payload_start, gint payload_len, modbus_pkt_info_t *pkt_info)
{
proto_tree *group_tree;
gint byte_cnt, group_offset, ii;
- gint register_format = MODBUS_PREF_REGISTER_FORMAT_UINT16; /* Default value for register formatting.. */
guint8 mei_code;
guint16 reg_base=0, diagnostic_code;
guint32 group_byte_cnt, group_word_cnt;
- modbus_conversation *conv;
-
- /* See if we have any context */
- conv = (modbus_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_modbus, 0);
-
- if (conv) {
- register_format = conv->register_format;
- }
-
switch (function_code) {
case READ_COILS:
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 1, pkt_info->register_format, reg_base);
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 2, pkt_info->register_format, reg_base);
break;
case READ_EXCEPT_STAT:
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, 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);
break;
}
break;
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 5, byte_cnt, pkt_info->register_format, reg_base);
break;
case WRITE_MULT_REGS:
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 5, byte_cnt, pkt_info->register_format, reg_base);
break;
case READ_FILE_RECORD:
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, 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);
group_offset += group_byte_cnt;
byte_cnt -= group_byte_cnt;
ii++;
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 9, byte_cnt, pkt_info->register_format, reg_base);
break;
case READ_FIFO_QUEUE:
/* 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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len-1, pkt_info->register_format, reg_base);
break;
}
case REPORT_SLAVE_ID:
default:
if (payload_len > 0)
- dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info->register_format, reg_base);
break;
} /* Function Code */
/* Code to dissect Modbus Response message */
static int
-dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tree, guint8 function_code, gint payload_start, gint payload_len)
+dissect_modbus_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *modbus_tree, guint8 function_code, gint payload_start, gint payload_len, modbus_pkt_info_t *pkt_info)
{
proto_tree *group_tree, *event_tree, *event_item_tree, *device_objects_tree, *device_objects_item_tree;
proto_item *mei;
gint byte_cnt, group_offset, event_index, object_index, object_len, num_objects, ii;
- gint register_format = MODBUS_PREF_REGISTER_FORMAT_UINT16; /* Default value for register formatting.. */
guint8 object_type, mei_code, event_code;
- guint16 reg_base=0, diagnostic_code;
+ guint16 diagnostic_code;
guint32 group_byte_cnt, group_word_cnt;
- /* Conversation tracking */
proto_item *request_frame_item;
- modbus_conversation *conv;
- guint8 req_function_code;
- guint32 req_frame_num;
- gboolean request_found = FALSE;
- modbus_request_info_t *request_data;
-
- /* See if we have any context */
- conv = (modbus_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_modbus, 0);
-
- if (conv) {
-
- wmem_list_frame_t *frame = wmem_list_head(conv->modbus_request_frame_data);
- /* Step backward through all logged instances of request frames, looking for a request frame number that
- occurred immediately prior to current frame number that has a matching function code */
- while (frame && !request_found) {
- request_data = (modbus_request_info_t *)wmem_list_frame_data(frame);
- req_frame_num = request_data->fnum;
- req_function_code = request_data->function_code;
- if ((pinfo->num > req_frame_num) && (req_function_code == function_code)) {
- request_frame_item = proto_tree_add_uint(modbus_tree, hf_modbus_request_frame, tvb, 0, 0, req_frame_num);
- reg_base = request_data->base_address;
- PROTO_ITEM_SET_GENERATED(request_frame_item);
- request_found = TRUE;
- }
- frame = wmem_list_frame_next(frame);
- }
- register_format = conv->register_format;
- } /* conv */
+ if (pkt_info->request_found == TRUE) {
+ request_frame_item = proto_tree_add_uint(modbus_tree, hf_modbus_request_frame, tvb, 0, 0, pkt_info->req_frame_num);
+ PROTO_ITEM_SET_GENERATED(request_frame_item);
+ }
switch (function_code) {
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base);
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base);
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 1, pkt_info->register_format, pkt_info->reg_base);
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 2, 2, pkt_info->register_format, pkt_info->reg_base);
break;
case READ_EXCEPT_STAT:
- dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, 1, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, 1, pkt_info->register_format, pkt_info->reg_base);
break;
case DIAGNOSTICS:
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, register_format, 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);
break;
} /* diagnostic_code */
break;
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, register_format, 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);
group_offset += (group_byte_cnt + 1);
byte_cnt -= (group_byte_cnt + 1);
ii++;
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, register_format, 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);
group_offset += group_byte_cnt;
byte_cnt -= group_byte_cnt;
ii++;
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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start + 1, byte_cnt, pkt_info->register_format, pkt_info->reg_base);
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, register_format, 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);
break;
case ENCAP_INTERFACE_TRANSP:
/* 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, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len-1, pkt_info->register_format, pkt_info->reg_base);
break;
} /* mei_code */
break;
case REPORT_SLAVE_ID:
default:
if (payload_len > 0)
- dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, register_format, reg_base);
+ dissect_modbus_data(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info->register_format, pkt_info->reg_base);
break;
} /* function code */
static int
dissect_modbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
- proto_tree *modbus_tree;
- proto_item *mi;
- int offset = 0;
- int* packet_type = (int*)data;
- gint payload_start, payload_len, len;
- guint8 function_code, exception_code;
+ proto_tree *modbus_tree;
+ proto_item *mi;
+ int offset = 0;
+ int* packet_type = (int*)data;
+ gint payload_start, payload_len, len;
+ guint8 function_code, exception_code;
+ modbus_pkt_info_t *pkt_info;
/* Reject the packet if data passed from the mbrtu or mbtcp dissector is NULL */
if (packet_type == NULL)
/* Find a conversation, create a new if no one exists */
conversation = find_or_create_conversation(pinfo);
modbus_conv_data = (modbus_conversation *)conversation_get_proto_data(conversation, proto_modbus);
+ pkt_info = wmem_new0(wmem_file_scope(), modbus_pkt_info_t);
if (modbus_conv_data == NULL){
modbus_conv_data = wmem_new(wmem_file_scope(), modbus_conversation);
modbus_conv_data->modbus_request_frame_data = wmem_list_new(wmem_file_scope());
modbus_conv_data->register_format = global_mbus_register_format;
+ pkt_info->register_format = global_mbus_register_format;
conversation_add_proto_data(conversation, proto_modbus, (void *)modbus_conv_data);
}
- p_add_proto_data(wmem_file_scope(), pinfo, proto_modbus, 0, modbus_conv_data);
if (*packet_type == QUERY_PACKET) {
/*create the modbus_request frame. It holds the request information.*/
/* load information into the modbus request frame */
frame_ptr->fnum = pinfo->num;
frame_ptr->function_code = function_code;
- frame_ptr->base_address = tvb_get_ntohs(tvb, 1);
+ pkt_info->reg_base = frame_ptr->base_address = tvb_get_ntohs(tvb, 1);
frame_ptr->num_reg = tvb_get_ntohs(tvb, 3);
wmem_list_prepend(modbus_conv_data->modbus_request_frame_data, frame_ptr);
}
+ else if (*packet_type == RESPONSE_PACKET) {
+ guint8 req_function_code;
+ guint32 req_frame_num;
+ modbus_request_info_t *request_data;
+
+ wmem_list_frame_t *frame = wmem_list_head(modbus_conv_data->modbus_request_frame_data);
+ /* Step backward through all logged instances of request frames, looking for a request frame number that
+ occurred immediately prior to current frame number that has a matching function code */
+ while (frame && !pkt_info->request_found) {
+ request_data = (modbus_request_info_t *)wmem_list_frame_data(frame);
+ req_frame_num = request_data->fnum;
+ 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->request_found = TRUE;
+ pkt_info->req_frame_num = req_frame_num;
+ }
+ frame = wmem_list_frame_next(frame);
+ }
+
+
+ }
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_modbus, 0, pkt_info);
+
+ }
+ else { /* !visited */
+ pkt_info = (modbus_pkt_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_modbus, 0);
+ }
- } /* !visited */
/* Find exception - last bit set in function code */
if (tvb_get_guint8(tvb, offset) & 0x80 ) {
/* Follow different dissection path depending on whether packet is query or response */
if (*packet_type == QUERY_PACKET) {
- dissect_modbus_request(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len);
+ dissect_modbus_request(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info);
}
else if (*packet_type == RESPONSE_PACKET) {
- dissect_modbus_response(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len);
+ dissect_modbus_response(tvb, pinfo, modbus_tree, function_code, payload_start, payload_len, pkt_info);
}
}