aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-opensafety.c245
1 files changed, 216 insertions, 29 deletions
diff --git a/epan/dissectors/packet-opensafety.c b/epan/dissectors/packet-opensafety.c
index e007669aed..3983d8db69 100644
--- a/epan/dissectors/packet-opensafety.c
+++ b/epan/dissectors/packet-opensafety.c
@@ -357,6 +357,11 @@ static int hf_oss_spdo_time_request_to = -1;
static int hf_oss_spdo_time_request_from = -1;
static const char *global_scm_udid = "00:00:00:00:00:00";
+static gboolean global_mbtcp_big_endian = TRUE;
+static guint global_network_udp_port = UDP_PORT_OPENSAFETY;
+static guint global_network_udp_port_sercosiii = UDP_PORT_SIII;
+
+/* Conversation functions */
/* This is defined by the specification. The Address field is 10 bits long, and the node with the number
* 1 is always the SCM, therefore ( 2 ^ 10 ) - 1 nodes can be addressed. We use 2 ^ 10 here, because the
@@ -432,11 +437,12 @@ static guint stringToBytes( const char * stringToBytes, guint8 * pBuffer, guint3
return k;
}
-static guint16 findFrame1Position ( guint8 dataLength, guint8 byteStream[] )
+static guint16
+findFrame1PositionExtended ( guint8 dataLength, guint8 byteStream[], gboolean checkIfSlimMistake )
{
guint16 i_wFrame1Position = 0;
guint16 i_payloadLength, i_calculatedLength = 0;
- guint16 i_offset = 0;
+ guint16 i_offset = 0, calcCRC = 0, frameCRC = 0;
guint8 b_tempByte = 0;
/*
@@ -449,7 +455,26 @@ static guint16 findFrame1Position ( guint8 dataLength, guint8 byteStream[] )
/* Calculating the assumed frame length, taking CRC8/CRC16 into account */
i_calculatedLength = i_payloadLength * 2 + 11 + 2 * (i_payloadLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? 1 : 0);
- /* If the calculated length differs from the given length, a slim package is assumed */
+ /* To prevent miscalculations, where by chance the byte at [length / 2] + 3 is a value matching a possible payload length,
+ * but in reality the frame is a slim ssdo, the CRC of frame 1 get's checked additionally. This check
+ * is somewhat time consuming, so it will only run if the normal check led to a mistake detected along the line */
+ if ( checkIfSlimMistake && i_calculatedLength == dataLength )
+ {
+ if ( dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
+ calcCRC = crc16_opensafety(dataLength + 4, &byteStream[i_wFrame1Position], 0);
+ else
+ calcCRC = crc8_opensafety(dataLength + 4, &byteStream[i_wFrame1Position], 0);
+
+ frameCRC = byteStream[i_wFrame1Position + dataLength + OSS_FRAME_POS_DATA];
+ if (dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
+ frameCRC += (byteStream[i_wFrame1Position + dataLength + OSS_FRAME_POS_DATA + 1] << 8);
+
+ /* if the calculated crc does not match the detected, the package is not a normal openSAFETY package */
+ if ( frameCRC != calcCRC )
+ dataLength = 0;
+ }
+
+ /* If the calculated length differs from the given length, a slim package is assumed. */
if ( i_calculatedLength != dataLength )
{
/* possible slim package */
@@ -474,6 +499,13 @@ static guint16 findFrame1Position ( guint8 dataLength, guint8 byteStream[] )
return i_wFrame1Position;
}
+static guint16
+findFrame1Position ( guint8 dataLength, guint8 byteStream[] )
+{
+ /* To safe time, the normal search, does not take the possible mistake into consideration */
+ return ( findFrame1PositionExtended(dataLength, byteStream, FALSE) );
+}
+
/*
* This function applies the given UDID to the bytestream, considering the start of frame 2
*/
@@ -606,7 +638,7 @@ static guint8 crc8_opensafety(guint32 len, guint8 * pBuffer, guint8 initCRC)
crc = initCRC;
while(len-- > 0)
{
- crc = (guint8)(*pBuffer++) ^ crc;
+ crc = (guint8)(*pBuffer++) ^ crc;
crc = crc8_opensafety_precompiled[crc];
}
@@ -624,9 +656,9 @@ static guint8 findSafetyFrame ( guint8 * pBuffer, guint32 length, guint u_Offset
DISSECTOR_ASSERT ( u_Offset < ( u_Offset + length ) );
for ( n = u_Offset; n < ( u_Offset + length ); n++)
{
- /* The ID byte must ALWAYS be the second byte, therefore 0 is invalid */
- if ( n == 0 )
- continue;
+ /* The ID byte must ALWAYS be the second byte, therefore 0 is invalid */
+ if ( n == 0 )
+ continue;
*u_frameLength = 0;
*u_frameOffset = 0;
@@ -639,8 +671,8 @@ static guint8 findSafetyFrame ( guint8 * pBuffer, guint32 length, guint u_Offset
* bit is set */
if ( ( b_ID != 0xFF ) && ( b_ID & 0x80 ) )
{
- /* If the determined size could be bigger, than the data to be dissect,
- * we have an error, return */
+ /* If the determined size could be bigger, than the data to be dissect,
+ * we have an error, return */
if ( ( b_Length + n ) > ( u_Offset + length ) )
continue;
@@ -1146,8 +1178,27 @@ dissect_opensafety_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree
type = OPENSAFETY_SNMT_MESSAGE_TYPE;
else
{
- /* This is an invalid openSAFETY package, we return */
- return FALSE;
+ /* This is an invalid openSAFETY package, but it could be an undetected slim ssdo message. This specific error
+ * will only occur, if findFrame1Position is in play. So we search once more, but this time calculating the CRC.
+ * The reason for the second run is, that calculating the CRC is time consuming. */
+ if ( b_frame2First )
+ {
+ /* Now let's check again, but this time calculate the CRC */
+ frameStart1 = findFrame1PositionExtended(length, bytes, TRUE );
+ frameStart2 = 0;
+
+ if ( ( OSS_FRAME_ID(bytes, frameStart1) & OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
+ type = OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE;
+ else if ( ( OSS_FRAME_ID(bytes, frameStart1) & OPENSAFETY_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SSDO_MESSAGE_TYPE )
+ type = OPENSAFETY_SSDO_MESSAGE_TYPE;
+ else if ( ( OSS_FRAME_ID(bytes, frameStart1) & OPENSAFETY_SPDO_MESSAGE_TYPE ) == OPENSAFETY_SPDO_MESSAGE_TYPE )
+ type = OPENSAFETY_SPDO_MESSAGE_TYPE;
+ else if ( ( OSS_FRAME_ID(bytes, frameStart1) & OPENSAFETY_SNMT_MESSAGE_TYPE ) == OPENSAFETY_SNMT_MESSAGE_TYPE )
+ type = OPENSAFETY_SNMT_MESSAGE_TYPE;
+ else
+ return FALSE;
+ } else
+ return FALSE;
}
b_ID = OSS_FRAME_ID(bytes, frameStart1);
@@ -1290,6 +1341,9 @@ dissect_opensafety_epl(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *
/* Freeing memory before dissector, as otherwise we would waste it */
next_tvb = tvb_new_subset(message_tvb, frameOffset, frameLength, reported_len);
+ /* Adding a visual aid to the dissector tree */
+ add_new_data_source(pinfo, next_tvb, "openSAFETY Frame");
+
if ( ! dissectorCalled )
{
call_dissector(epl_handle, message_tvb, pinfo, tree);
@@ -1375,12 +1429,12 @@ dissect_opensafety_siii(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree
siii_handle = find_dissector("data");
/* We can handle the packages internally, if there is no sercos iii plugin available */
if ( pinfo->ethertype == ETHERTYPE_SERCOS )
- internSIIIHandling = TRUE;
+ internSIIIHandling = TRUE;
}
if ( tree && internSIIIHandling )
{
- proto_tree_add_text(tree,message_tvb, 0, -1, "SercosIII dissector not available, openSAFETY/SercosIII native dissection.");
+ proto_tree_add_text(tree,message_tvb, 0, -1, "SercosIII dissector not available, openSAFETY/SercosIII native dissection.");
}
/* We have a SERCOS III package, whether encapsulated in UDP or
@@ -1412,6 +1466,8 @@ dissect_opensafety_siii(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree
/* Freeing memory before dissector, as otherwise we would waste it */
next_tvb = tvb_new_subset(message_tvb, frameOffset, frameLength, reported_len);
+ /* Adding a visual aid to the dissector tree */
+ add_new_data_source(pinfo, next_tvb, "openSAFETY Frame");
/* pinfo is NULL only if dissect_opensafety_message is called from dissect_error cause */
if ( ( ! udpDissectorCalled ) && ( pinfo->ipproto == IPPROTO_UDP ) && pinfo )
@@ -1425,8 +1481,8 @@ dissect_opensafety_siii(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree
/* Call the dissector */
if ( ( ! dissectorCalled ) && ( pinfo->ipproto != IPPROTO_UDP ) )
{
- if ( ! internSIIIHandling )
- call_dissector(siii_handle, message_tvb, pinfo, tree);
+ if ( ! internSIIIHandling )
+ call_dissector(siii_handle, message_tvb, pinfo, tree);
dissectorCalled = TRUE;
/* pinfo is NULL only if dissect_opensafety_message is called from dissect_error cause */
@@ -1495,6 +1551,128 @@ dissect_heur_opensafety_siii(tvbuff_t *message_tvb , packet_info *pinfo , proto_
return FALSE;
}
+static gboolean
+dissect_opensafety_mbtcp(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree )
+{
+ tvbuff_t *next_tvb;
+ guint length, frameOffset, frameLength;
+ guint8 *bytes;
+ gboolean handled, dissectorCalled;
+ guint8 found, packageCounter, i, tempByte;
+ gint len, reported_len;
+
+ length = tvb_length(message_tvb);
+ /* Minimum package length is 11 */
+ if ( length < 11 )
+ return FALSE;
+
+ handled = FALSE;
+ dissectorCalled = FALSE;
+
+ bytes = (guint8 *) ep_tvb_memdup(message_tvb, 0, length);
+
+ if ( global_mbtcp_big_endian == TRUE )
+ {
+ /* Wordswapping for modbus detection */
+ /* Only a even number of bytes can be swapped */
+ len = (length / 2);
+ for ( i = 0; i < len; i++ )
+ {
+ tempByte = bytes [ 2 * i ]; bytes [ 2 * i ] = bytes [ 2 * i + 1 ]; bytes [ 2 * i + 1 ] = tempByte;
+ }
+ }
+ len = tvb_length_remaining(message_tvb, 0);
+ reported_len = tvb_reported_length_remaining(message_tvb, 0);
+
+ frameOffset = 0;
+ frameLength = 0;
+ found = 0;
+ packageCounter = 0;
+ while ( frameOffset < length )
+ {
+ if ( findSafetyFrame(bytes, length - frameOffset, frameOffset, &frameOffset, &frameLength) )
+ {
+ if ((frameOffset + frameLength) > (guint)reported_len )
+ break;
+
+ found++;
+
+ /* Freeing memory before dissector, as otherwise we would waste it */
+ if ( global_mbtcp_big_endian == TRUE )
+ {
+ next_tvb = tvb_new_real_data(&bytes[frameOffset], (frameLength), reported_len);
+ tvb_set_child_real_data_tvbuff(message_tvb, next_tvb);
+ add_new_data_source(pinfo, next_tvb, "openSAFETY Frame (Swapped)");
+ }
+ else
+ {
+ next_tvb = tvb_new_subset(message_tvb, frameOffset, frameLength, reported_len);
+ add_new_data_source(pinfo, next_tvb, "openSAFETY Frame");
+ }
+
+ if ( ! dissectorCalled )
+ {
+ dissectorCalled = TRUE;
+
+ /* pinfo is NULL only if dissect_opensafety_message is called from dissect_error cause */
+ if (pinfo)
+ {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "openSAFETY over Modbus");
+ col_clear(pinfo->cinfo,COL_INFO);
+ }
+ }
+
+ /* Only engage, if we are not called strictly for the overview */
+ if ( tree )
+ {
+ if ( dissect_opensafety_frame(next_tvb, pinfo, tree, FALSE, found ) == TRUE )
+ packageCounter++;
+ }
+ handled = TRUE;
+ }
+ else
+ break;
+
+ frameOffset += frameLength;
+ }
+
+ if ( handled == TRUE && packageCounter == 0 )
+ handled = FALSE;
+
+ return ( handled ? TRUE : FALSE );
+}
+
+static void
+apply_prefs ( void )
+{
+ static gboolean opensafety_init = FALSE;
+ static guint opensafety_udp_port_number;
+ static guint opensafety_udp_siii_port_number;
+
+ /* It only should delete dissectors, if run for any time except the first */
+ if ( opensafety_init )
+ {
+ /* Delete dissectors in preparation of a changed config setting */
+ dissector_delete_uint ("udp.port", opensafety_udp_port_number, find_dissector("opensafety"));
+ dissector_delete_uint ("udp.port", opensafety_udp_siii_port_number, find_dissector("opensafety_siii"));
+ }
+
+ opensafety_init = TRUE;
+
+ /* Storing the port numbers locally, to being able to delete the old associations */
+ opensafety_udp_port_number = global_network_udp_port;
+ opensafety_udp_siii_port_number = global_network_udp_port_sercosiii;
+
+ /* Default UDP only based dissector */
+ dissector_add_uint("udp.port", opensafety_udp_port_number, find_dissector("opensafety"));
+
+ /* Sercos III dissector does not handle UDP transport, has to be handled
+ * separately, everything else should be caught by the heuristic dissector
+ */
+ dissector_add_uint("udp.port", opensafety_udp_siii_port_number, find_dissector("opensafety_siii"));
+
+}
+
void
proto_register_opensafety(void)
{
@@ -1575,7 +1753,7 @@ proto_register_opensafety(void)
/* Register the protocol name and description */
proto_opensafety = proto_register_protocol("openSAFETY", "openSAFETY", "opensafety");
- opensafety_module = prefs_register_protocol(proto_opensafety, NULL);
+ opensafety_module = prefs_register_protocol(proto_opensafety, apply_prefs);
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_opensafety, hf, array_length(hf));
@@ -1586,10 +1764,23 @@ proto_register_opensafety(void)
"SCM UDID (xx:xx:xx:xx:xx:xx)",
"To be able to fully dissect SSDO and SPDO packages, a valid UDID for the SCM has to be provided",
&global_scm_udid);
-
- new_register_dissector("opensafety", dissect_opensafety, proto_opensafety);
-
- new_register_dissector("opensafety_siii", dissect_opensafety_siii, proto_opensafety);
+ prefs_register_uint_preference(opensafety_module, "network_udp_port",
+ "UDP Port used for the UDP demo ",
+ "UDP port used by UDP demo implementation to transport asynchronous data", 10,
+ &global_network_udp_port);
+ prefs_register_uint_preference(opensafety_module, "network_udp_port_sercosiii",
+ "UDP Port used for SercosIII",
+ "UDP port used by SercosIII to transport asynchronous data", 10,
+ &global_network_udp_port_sercosiii);
+ prefs_register_bool_preference(opensafety_module, "mbtcp_big_endian",
+ "Modbus/TCP Big Endian Word Coding",
+ "Modbus/TCP words can be transmissioned either big- or little endian. Default will be little endian",
+ &global_mbtcp_big_endian);
+
+ /* Registering default and ModBus/TCP dissector */
+ new_register_dissector("opensafety", dissect_opensafety, proto_opensafety );
+ new_register_dissector("opensafety_mbtcp", dissect_opensafety_mbtcp, proto_opensafety );
+ new_register_dissector("opensafety_siii", dissect_opensafety_siii, proto_opensafety);
}
@@ -1600,14 +1791,6 @@ proto_reg_handoff_opensafety(void)
if ( !opensafety_inited )
{
- /* Default UDP only based dissector */
- dissector_add_uint("udp.port", UDP_PORT_OPENSAFETY, find_dissector("opensafety"));
-
- /* Sercos III dissector does not handle UDP transport, has to be handled
- * separately, everything else should be caught by the heuristic dissector
- */
- dissector_add_uint("udp.port", UDP_PORT_SIII, find_dissector("opensafety_siii"));
-
heur_dissector_add("epl", dissect_heur_opensafety_epl, proto_opensafety);
/* For SercosIII we have to register as a heuristic dissector, as SercosIII
@@ -1616,7 +1799,7 @@ proto_reg_handoff_opensafety(void)
*/
if ( find_dissector("sercosiii") != NULL )
{
- heur_dissector_add("sercosiii", dissect_heur_opensafety_siii, proto_opensafety);
+ heur_dissector_add("sercosiii", dissect_heur_opensafety_siii, proto_opensafety);
}
else
{
@@ -1627,5 +1810,9 @@ proto_reg_handoff_opensafety(void)
g_warning ( "openSAFETY - SercosIII heuristic dissector cannot be registered, openSAFETY/SercosIII native dissection." );
dissector_add_uint("ethertype", ETHERTYPE_SERCOS, find_dissector("opensafety_siii"));
}
+
+ /* Modbus TCP dissector registration */
+ dissector_add_string("mbtcp.modbus.data", "data", find_dissector("opensafety_mbtcp"));
}
+
}