CIP Safety: Fix CRC logic when timestamp rolls over to zero

This commit is contained in:
Dylan Ulis 2022-04-21 15:02:25 +00:00 committed by A Wireshark GitLab Utility
parent d6fb90ecab
commit 2f41595382
2 changed files with 52 additions and 51 deletions

View File

@ -497,8 +497,13 @@ typedef struct cip_connection_triad {
typedef struct cip_safety_epath_info {
gboolean safety_seg;
enum cip_safety_format_type format;
guint16 running_rollover_value; /* Keep track of the rollover value over the course of the connection */
guint16 running_timestamp_value; /* Keep track of the timestamp value over the course of the connection */
// These 3x variables are only used during a first pass calculation.
guint16 running_rollover_value; /* Keep track of the rollover value over the course of the connection */
guint16 running_timestamp_value; /* Keep track of the timestamp value over the course of the connection */
gboolean seen_non_zero_timestamp; /* True if we have seen a non-zero timestamp on this connection */
// The Target CIP Connection Triad from the Forward Open Response, Safety Application Reply Data.
cip_connection_triad_t target_triad;
} cip_safety_epath_info_t;

View File

@ -318,7 +318,6 @@ static dissector_handle_t cipsafety_extended_time_coord_handle;
typedef struct cip_safety_packet_data {
guint16 rollover_value;
guint16 timestamp_value;
} cip_safety_packet_data_t;
#define MODE_BYTE_CRC_S1_MASK 0xE0
@ -1705,7 +1704,7 @@ static void dissect_extended_format_1_or_2_byte_data(packet_info* pinfo, proto_t
if (packet_data != NULL)
{
computed_crc_s5 = compute_crc_s5_short_data(compute_crc_s5_pid(connection_triad),
((timestamp != 0) ? packet_data->rollover_value : 0),
packet_data->rollover_value,
mode_byte & MODE_BYTE_CRC_S5_BASE_MASK,
timestamp,
tvb_get_ptr(tvb, 0, io_data_size),
@ -1731,7 +1730,7 @@ static void dissect_extended_format_3_to_250_byte_data(packet_info* pinfo, proto
if (packet_data != NULL)
{
guint16 computed_crc_s3 = compute_crc_s3_extended_data(compute_crc_s3_pid(connection_triad),
((timestamp != 0) ? packet_data->rollover_value : 0),
packet_data->rollover_value,
mode_byte & MODE_BYTE_CRC_S3_MASK,
tvb_get_ptr(tvb, 0, io_data_size), io_data_size);
@ -1761,7 +1760,7 @@ static void dissect_extended_format_3_to_250_byte_data(packet_info* pinfo, proto
if (packet_data != NULL)
{
computed_crc_s5 = compute_crc_s5_long_data(compute_crc_s5_pid(connection_triad),
((timestamp != 0) ? packet_data->rollover_value : 0),
packet_data->rollover_value,
mode_byte & MODE_BYTE_CRC_S5_EXTENDED_MASK,
timestamp,
/* I/O data is duplicated because it will be complemented inline */
@ -1771,6 +1770,46 @@ static void dissect_extended_format_3_to_250_byte_data(packet_info* pinfo, proto
validate_crc_s5(pinfo, tree, tvb, compute_crc, crc_s5_0, crc_s5_1, crc_s5_2, computed_crc_s5);
}
// Note: This updates the running timestamp/rollover data in safety_info during the first pass.
static cip_safety_packet_data_t* get_timestamp_packet_data(packet_info* pinfo, cip_safety_info_t* safety_info, guint16 timestamp)
{
cip_safety_packet_data_t* packet_data = NULL;
/* Determine if packet timestamp results in rollover count increment */
if (!pinfo->fd->visited)
{
packet_data = wmem_new0(wmem_file_scope(), cip_safety_packet_data_t);
if ((timestamp == 0) && !safety_info->eip_conn_info->safety.seen_non_zero_timestamp)
{
// The rollover value is zero, until the Time Coordination exchange is done.
// When the timestamp is zero, that means we haven't seen the Time Coordination message.
packet_data->rollover_value = 0;
}
else
{
safety_info->eip_conn_info->safety.seen_non_zero_timestamp = TRUE;
if (timestamp < safety_info->eip_conn_info->safety.running_timestamp_value)
{
safety_info->eip_conn_info->safety.running_rollover_value++;
}
/* Save the rollover value for CRC calculations */
packet_data->rollover_value = safety_info->eip_conn_info->safety.running_rollover_value;
safety_info->eip_conn_info->safety.running_timestamp_value = timestamp;
}
p_add_proto_data(wmem_file_scope(), pinfo, proto_cipsafety, 0, packet_data);
}
else
{
packet_data = (cip_safety_packet_data_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cipsafety, 0);
}
return packet_data;
}
static void
dissect_cip_safety_data( proto_tree *tree, proto_item *item, tvbuff_t *tvb, int item_length, packet_info *pinfo, cip_safety_info_t* safety_info)
{
@ -1781,7 +1820,6 @@ dissect_cip_safety_data( proto_tree *tree, proto_item *item, tvbuff_t *tvb, int
enum cip_safety_format_type format = CIP_SAFETY_BASE_FORMAT;
guint16 timestamp;
guint8 mode_byte;
cip_safety_packet_data_t* packet_data = NULL;
gboolean short_format = TRUE;
gboolean compute_crc = ((safety_info != NULL) && (safety_info->compute_crc == TRUE));
cip_connection_triad_t connection_triad = {0};
@ -1902,28 +1940,10 @@ dissect_cip_safety_data( proto_tree *tree, proto_item *item, tvbuff_t *tvb, int
timestamp = tvb_get_letohs(tvb, (io_data_size*2)+5);
}
cip_safety_packet_data_t* packet_data = NULL;
if (compute_crc)
{
/* Determine if packet timestamp results in rollover count increment */
if (!pinfo->fd->visited)
{
if ((timestamp != 0) && (timestamp < safety_info->eip_conn_info->safety.running_timestamp_value))
{
safety_info->eip_conn_info->safety.running_rollover_value++;
}
safety_info->eip_conn_info->safety.running_timestamp_value = timestamp;
/* Save the rollover value for CRC calculations */
packet_data = wmem_new0(wmem_file_scope(), cip_safety_packet_data_t);
packet_data->rollover_value = safety_info->eip_conn_info->safety.running_rollover_value;
p_add_proto_data(wmem_file_scope(), pinfo, proto_cipsafety, 0, packet_data);
}
else
{
packet_data = (cip_safety_packet_data_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cipsafety, 0);
}
packet_data = get_timestamp_packet_data(pinfo, safety_info, timestamp);
}
if (short_format)
@ -1945,30 +1965,6 @@ dissect_cip_safety_data( proto_tree *tree, proto_item *item, tvbuff_t *tvb, int
return;
}
if (compute_crc)
{
/* Determine if packet timestamp results in rollover count increment */
if (!pinfo->fd->visited)
{
if ((timestamp != 0) && (timestamp < safety_info->eip_conn_info->safety.running_timestamp_value))
{
safety_info->eip_conn_info->safety.running_rollover_value++;
}
safety_info->eip_conn_info->safety.running_timestamp_value = timestamp;
/* Save the rollover value for CRC calculations */
packet_data = wmem_new0(wmem_file_scope(), cip_safety_packet_data_t);
packet_data->rollover_value = safety_info->eip_conn_info->safety.running_rollover_value;
p_add_proto_data(wmem_file_scope(), pinfo, proto_cipsafety, 0, packet_data);
}
else
{
packet_data = (cip_safety_packet_data_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cipsafety, 0);
}
}
dissect_extended_format_3_to_250_byte_data(pinfo, tree, tvb, io_data_size, compute_crc, &connection_triad, packet_data);
if (multicast)