forked from osmocom/wireshark
From Chris Bontje via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9001 :
Some small improvements to the Modbus Dissector: - Better detection of query/response w/ serial line Modbus RTU - Smallest Modbus RTU message can actually be 6 bytes, not 8. - Only check 16/32-bit register decoding options with appropriate function codes svn path=/trunk/; revision=51083
This commit is contained in:
parent
d0cb52d0b7
commit
490f48044c
|
@ -2,7 +2,7 @@
|
|||
* Routines for Modbus/TCP and Modbus/UDP dissection
|
||||
* By Riaan Swart <rswart@cs.sun.ac.za>
|
||||
* Copyright 2001, Institute for Applied Computer Science
|
||||
* University of Stellenbosch
|
||||
* University of Stellenbosch
|
||||
*
|
||||
* See http://www.modbus.org/ for information on Modbus/TCP.
|
||||
*
|
||||
|
@ -16,6 +16,9 @@
|
|||
* - Optionally decode holding/input registers as UINT16, UINT32, 32-bit Float IEEE/Modicon
|
||||
* - Add various register address formatting options as "Raw", "Modicon 5-digit", "Modicon 6-digit"
|
||||
*
|
||||
* Updates Aug 2013 (Chris Bontje)
|
||||
* - Improved dissection support for serial Modbus RTU with detection of query or response messages
|
||||
*
|
||||
*****************************************************************************************************
|
||||
* A brief explanation of the distinction between Modbus/TCP and Modbus RTU over TCP:
|
||||
*
|
||||
|
@ -198,7 +201,7 @@ classify_mbtcp_packet(packet_info *pinfo)
|
|||
}
|
||||
|
||||
static int
|
||||
classify_mbrtu_packet(packet_info *pinfo)
|
||||
classify_mbrtu_packet(packet_info *pinfo, tvbuff_t *tvb)
|
||||
{
|
||||
/* see if nature of packets can be derived from src/dst ports */
|
||||
/* if so, return as found */
|
||||
|
@ -207,10 +210,31 @@ classify_mbrtu_packet(packet_info *pinfo)
|
|||
if (( pinfo->srcport != global_mbus_rtu_port ) && ( pinfo->destport == global_mbus_rtu_port ))
|
||||
return QUERY_PACKET;
|
||||
|
||||
/* Special case for serial-captured packets that don't have an Ethernet header */
|
||||
/* Default these to a response packet, so they at least attempt to decode a good chunk of data */
|
||||
if (!pinfo->srcport)
|
||||
return RESPONSE_PACKET;
|
||||
/* Special case for serial-captured packets that don't have an Ethernet header */
|
||||
/* Dig into these a little deeper to try to guess the message type */
|
||||
if (!pinfo->srcport) {
|
||||
/* If length is 8, this is either a query or very short response */
|
||||
if (tvb_length(tvb) == 8) {
|
||||
/* Only possible to get a response message of 8 bytes with Discrete or Coils */
|
||||
if ((tvb_get_guint8(tvb, 1) == READ_COILS) || (tvb_get_guint8(tvb, 1) == READ_DISCRETE_INPUTS)) {
|
||||
/* If this is, in fact, a response then the data byte count will be 3 */
|
||||
/* This will correctly identify all messages except for those that are discrete or coil polls */
|
||||
/* where the base address range happens to have 0x03 in the upper 16-bit address register */
|
||||
if (tvb_get_guint8(tvb, 2) == 3) {
|
||||
return RESPONSE_PACKET;
|
||||
}
|
||||
else {
|
||||
return QUERY_PACKET;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return QUERY_PACKET;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return RESPONSE_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
/* else, cannot classify */
|
||||
return CANNOT_CLASSIFY;
|
||||
|
@ -523,7 +547,7 @@ dissect_mbrtu_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|||
}
|
||||
|
||||
/* "Request" or "Response" */
|
||||
packet_type = classify_mbrtu_packet(pinfo);
|
||||
packet_type = classify_mbrtu_packet(pinfo, tvb);
|
||||
|
||||
switch ( packet_type ) {
|
||||
case QUERY_PACKET :
|
||||
|
@ -604,7 +628,7 @@ dissect_mbrtu_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|||
request_info->register_format = (guint8)global_mbus_rtu_register_format;
|
||||
p_add_proto_data(pinfo->fd, proto_modbus, 0, request_info);
|
||||
|
||||
/* Continue with dissection of Modbus data payload following Modbus/TCP frame */
|
||||
/* Continue with dissection of Modbus data payload following Modbus RTU frame */
|
||||
if( tvb_length_remaining(tvb, offset) > 0 )
|
||||
call_dissector(modbus_handle, next_tvb, pinfo, tree);
|
||||
|
||||
|
@ -673,7 +697,7 @@ dissect_mbrtu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U
|
|||
{
|
||||
|
||||
/* Make sure there's at least enough data to determine it's a Modbus packet */
|
||||
if (!tvb_bytes_exist(tvb, 0, 8))
|
||||
if (!tvb_bytes_exist(tvb, 0, 6))
|
||||
return 0;
|
||||
|
||||
/* For Modbus RTU mode, confirm that the first byte is a valid address (non-zero), */
|
||||
|
@ -714,13 +738,17 @@ dissect_modbus_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8
|
|||
return;
|
||||
}
|
||||
|
||||
/* If data type of payload is Holding or Input registers */
|
||||
/* AND */
|
||||
/* if payload length is not a multiple of 4, don't attempt to decode anything in 32-bit format */
|
||||
if ((payload_len % 4 != 0) && ( (register_format == MBTCP_PREF_REGISTER_FORMAT_UINT32) ||
|
||||
(register_format == MBTCP_PREF_REGISTER_FORMAT_IEEE_FLOAT) ||
|
||||
(register_format == MBTCP_PREF_REGISTER_FORMAT_MODICON_FLOAT) ) ) {
|
||||
register_item = proto_tree_add_item(tree, hf_modbus_data, tvb, payload_start, payload_len, ENC_NA);
|
||||
expert_add_info(pinfo, register_item, &ei_modbus_data_decode);
|
||||
return;
|
||||
if ((function_code == READ_HOLDING_REGS) || (function_code == READ_INPUT_REGS) || (function_code == WRITE_MULT_REGS)) {
|
||||
if ((payload_len % 4 != 0) && ( (register_format == MBTCP_PREF_REGISTER_FORMAT_UINT32) ||
|
||||
(register_format == MBTCP_PREF_REGISTER_FORMAT_IEEE_FLOAT) ||
|
||||
(register_format == MBTCP_PREF_REGISTER_FORMAT_MODICON_FLOAT) ) ) {
|
||||
register_item = proto_tree_add_item(tree, hf_modbus_data, tvb, payload_start, payload_len, ENC_NA);
|
||||
expert_add_info(pinfo, register_item, &ei_modbus_data_decode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a new tvb containing just the data payload */
|
||||
|
|
Loading…
Reference in New Issue