3 * openSAFETY is a machine-safety protocol, encapsulated in modern fieldbus
4 * and industrial ethernet solutions.
6 * For more information see http://www.open-safety.org
8 * This dissector currently supports the following transport protocols
10 * - openSAFETY using POWERLINK
11 * - openSAFETY using SercosIII
12 * - openSAFETY using Generic UDP
13 * - openSAFETY using Modbus/TCP
14 * - openSAFETY using (openSAFETY over UDP) transport
15 * - openSAFETY using ProfiNet IO
17 * By Roland Knall <roland.knall@br-automation.com>
18 * Copyright 2011-2012 Bernecker + Rainer Industrie-Elektronik Ges.m.b.H.
20 * Wireshark - Network traffic analyzer
21 * By Gerald Combs <gerald@wireshark.org>
22 * Copyright 1998 Gerald Combs
24 * SPDX-License-Identifier: GPL-2.0-or-later
29 #include <epan/packet.h>
30 #include <epan/prefs.h>
31 #include <epan/etypes.h>
32 #include <epan/expert.h>
33 #include <epan/reassemble.h>
34 #include <epan/strutil.h>
36 #include <epan/conversation_table.h>
38 #include <wsutil/crc8.h>
39 #include <wsutil/crc16.h>
41 #include "packet-frame.h"
42 #include "packet-opensafety.h"
44 /* General definitions */
46 /* Used to classify incoming traffic and presort the heuristic */
47 #define OPENSAFETY_ANY_TRANSPORT 0x00
48 #define OPENSAFETY_CYCLIC_DATA 0x01
49 #define OPENSAFETY_ACYCLIC_DATA 0x02
51 #ifndef OPENSAFETY_PINFO_CONST_DATA
52 #define OPENSAFETY_PINFO_CONST_DATA 0xAABBCCDD
55 #define OPENSAFETY_REQUEST true
56 #define OPENSAFETY_RESPONSE false
59 * Because featureflags are part of the TR field (which is only 6 bit), the field get's shifted */
60 #define OPENSAFETY_SPDO_FEAT_40BIT_AVAIL 0x20
61 #define OPENSAFETY_SPDO_FEAT_40BIT_USED 0x10
62 #define OPENSAFETY_SPDO_FEATURE_FLAGS (OPENSAFETY_SPDO_FEAT_40BIT_USED | OPENSAFETY_SPDO_FEAT_40BIT_AVAIL)
64 #define OSS_FRAME_POS_ADDR 0
65 #define OSS_FRAME_POS_ID 1
66 #define OSS_FRAME_POS_LEN 2
67 #define OSS_FRAME_POS_CT 3
68 #define OSS_FRAME_POS_DATA 4
70 #define OSS_PAYLOAD_MAXSIZE_FOR_CRC8 0x08
71 #define OSS_SLIM_FRAME_WITH_CRC8_MAXSIZE 0x13 /* 19 */
72 #define OSS_SLIM_FRAME2_WITH_CRC8 0x06 /* 6 */
73 #define OSS_SLIM_FRAME2_WITH_CRC16 0x07 /* 7 */
74 #define OSS_MINIMUM_LENGTH 0x0b /* 11 */
75 #define OSS_BROADCAST_ADDRESS 0x3ff
77 #define OPENSAFETY_SPDO_CONNECTION_VALID 0x04
79 #define OPENSAFETY_SOD_DVI 0x1018
80 #define OPENSAFETY_SOD_RXMAP 0x1800
81 #define OPENSAFETY_SOD_TXMAP 0xC000
83 #define OSS_FRAME_ADDR(f, offset) (f[OSS_FRAME_POS_ADDR + offset] + ((uint8_t)((f[OSS_FRAME_POS_ADDR + offset + 1]) << 6) << 2))
84 #define OSS_FRAME_ID(f, offset) (f[OSS_FRAME_POS_ID + offset] & 0xFC )
85 #define OSS_FRAME_LENGTH(f, offset) (f[OSS_FRAME_POS_LEN + offset])
86 #define OSS_FRAME_FIELD(f, position) (f[position])
88 #define OSS_FRAME_ADDR_T(f, offset) (tvb_get_uint8(f, OSS_FRAME_POS_ADDR + offset) + ((uint8_t)((tvb_get_uint8( f, OSS_FRAME_POS_ADDR + offset + 1)) << 6) << 2))
89 #define OSS_FRAME_ADDR_T2(f, offset, su1, su2) (( tvb_get_uint8(f, OSS_FRAME_POS_ADDR + offset) ^ su1) + ((uint8_t)(((tvb_get_uint8( f, OSS_FRAME_POS_ADDR + offset + 1) ^ su2)) << 6) << 2))
90 #define OSS_FRAME_ID_T(f, offset) (tvb_get_uint8(f, OSS_FRAME_POS_ID + offset) & 0xFC)
91 #define OSS_FRAME_LENGTH_T(f, offset) (tvb_get_uint8(f, OSS_FRAME_POS_LEN + offset))
93 static int proto_opensafety
;
95 static int ett_opensafety
;
96 static int ett_opensafety_checksum
;
97 static int ett_opensafety_snmt
;
98 static int ett_opensafety_ssdo
;
99 static int ett_opensafety_spdo
;
100 static int ett_opensafety_spdo_flags
;
101 static int ett_opensafety_ssdo_sacmd
;
102 static int ett_opensafety_ssdo_payload
;
103 static int ett_opensafety_ssdo_sodentry
;
104 static int ett_opensafety_ssdo_extpar
;
105 static int ett_opensafety_sod_mapping
;
106 static int ett_opensafety_node
;
108 static expert_field ei_payload_length_not_positive
;
109 static expert_field ei_payload_unknown_format
;
110 static expert_field ei_crc_slimssdo_instead_of_spdo
;
111 static expert_field ei_crc_frame_1_invalid
;
112 static expert_field ei_crc_frame_1_valid_frame2_invalid
;
113 static expert_field ei_crc_frame_2_invalid
;
114 static expert_field ei_crc_frame_2_unknown_scm_udid
;
115 static expert_field ei_crc_frame_2_scm_udid_encoded
;
116 static expert_field ei_message_unknown_type
;
117 static expert_field ei_message_reassembly_size_differs_from_header
;
118 static expert_field ei_message_spdo_address_invalid
;
119 static expert_field ei_message_id_field_mismatch
;
120 static expert_field ei_scmudid_autodetected
;
121 static expert_field ei_scmudid_invalid_preference
;
122 static expert_field ei_scmudid_unknown
;
123 static expert_field ei_40bit_default_domain
;
125 static int hf_oss_msg
;
126 static int hf_oss_msg_direction
;
127 static int hf_oss_msg_category
;
128 static int hf_oss_msg_node
;
129 static int hf_oss_msg_network
;
130 static int hf_oss_msg_sender
;
131 static int hf_oss_msg_receiver
;
132 static int hf_oss_length
;
133 static int hf_oss_crc
;
134 static int hf_oss_byte_offset
;
136 static int hf_oss_crc_valid
;
137 static int hf_oss_crc2_valid
;
138 static int hf_oss_crc_type
;
140 static int hf_oss_snmt_slave
;
141 static int hf_oss_snmt_master
;
142 static int hf_oss_snmt_udid
;
143 static int hf_oss_snmt_scm
;
144 static int hf_oss_snmt_tool
;
145 static int hf_oss_snmt_service_id
;
146 static int hf_oss_snmt_error_group
;
147 static int hf_oss_snmt_error_code
;
148 static int hf_oss_snmt_param_type
;
149 static int hf_oss_snmt_ext_addsaddr
;
150 static int hf_oss_snmt_ext_addtxspdo
;
151 static int hf_oss_snmt_ext_initct
;
153 static int hf_oss_ssdo_server
;
154 static int hf_oss_ssdo_client
;
155 static int hf_oss_ssdo_sano
;
156 static int hf_oss_ssdo_sacmd
;
157 static int hf_oss_ssdo_sod_index
;
158 static int hf_oss_ssdo_sod_subindex
;
159 static int hf_oss_ssdo_payload
;
160 static int hf_oss_ssdo_payload_size
;
161 static int hf_oss_ssdo_sodentry_size
;
162 static int hf_oss_ssdo_sodentry_data
;
163 static int hf_oss_ssdo_abort_code
;
164 static int hf_oss_ssdo_preload_queue
;
165 static int hf_oss_ssdo_preload_error
;
167 static int hf_oss_sod_par_timestamp
;
168 static int hf_oss_sod_par_checksum
;
169 static int hf_oss_ssdo_sodmapping
;
170 static int hf_oss_ssdo_sodmapping_bits
;
172 static int hf_oss_ssdo_sacmd_access_type
;
173 static int hf_oss_ssdo_sacmd_preload
;
174 static int hf_oss_ssdo_sacmd_abort_transfer
;
175 static int hf_oss_ssdo_sacmd_segmentation
;
176 static int hf_oss_ssdo_sacmd_toggle
;
177 static int hf_oss_ssdo_sacmd_initiate
;
178 static int hf_oss_ssdo_sacmd_end_segment
;
180 static int hf_oss_ssdo_sacmd_reserved
;
183 static int hf_oss_ssdo_extpar_parset
;
184 static int hf_oss_ssdo_extpar_version
;
185 static int hf_oss_ssdo_extpar_saddr
;
186 static int hf_oss_ssdo_extpar_length
;
187 static int hf_oss_ssdo_extpar_crc
;
188 static int hf_oss_ssdo_extpar_tstamp
;
189 static int hf_oss_ssdo_extpar_data
;
190 static int hf_oss_ssdo_extpar
;
192 static int hf_oss_scm_udid
;
193 static int hf_oss_scm_udid_auto
;
194 static int hf_oss_scm_udid_valid
;
196 static int hf_oss_spdo_direction
;
197 static int hf_oss_spdo_connection_valid
;
198 static int hf_oss_spdo_ct
;
199 static int hf_oss_spdo_ct_40bit
;
200 static int hf_oss_spdo_time_request
;
201 static int hf_oss_spdo_time_request_to
;
202 static int hf_oss_spdo_time_request_from
;
203 static int hf_oss_spdo_feature_flags
;
204 static int hf_oss_spdo_feature_flag_40bit_available
;
205 static int hf_oss_spdo_feature_flag_40bit_used
;
207 static int hf_oss_fragments
;
208 static int hf_oss_fragment
;
209 static int hf_oss_fragment_overlap
;
210 static int hf_oss_fragment_overlap_conflicts
;
211 static int hf_oss_fragment_multiple_tails
;
212 static int hf_oss_fragment_too_long_fragment
;
213 static int hf_oss_fragment_error
;
214 static int hf_oss_fragment_count
;
215 static int hf_oss_reassembled_in
;
216 static int hf_oss_reassembled_length
;
217 static int hf_oss_reassembled_data
;
219 static int ett_opensafety_ssdo_fragment
;
220 static int ett_opensafety_ssdo_fragments
;
222 /* Definitions for the openSAFETY ov. UDP transport protocol */
223 static dissector_handle_t opensafety_udptransport_handle
;
225 static int proto_oss_udp_transport
;
227 static int hf_oss_udp_transport_version
;
228 static int hf_oss_udp_transport_flags_type
;
229 static int hf_oss_udp_transport_counter
;
230 static int hf_oss_udp_transport_sender
;
231 static int hf_oss_udp_transport_datapoint
;
232 static int hf_oss_udp_transport_length
;
234 static int ett_oss_udp_transport
;
236 static const true_false_string tfs_udp_transport_cyclic_acyclic
= { "Cyclic", "ACyclic" };
237 static unsigned global_network_oss_udp_port
= OPENSAFETY_UDP_PORT
;
239 static int opensafety_tap
;
241 static const fragment_items oss_frag_items
= {
242 /* Fragment subtrees */
243 &ett_opensafety_ssdo_fragment
,
244 &ett_opensafety_ssdo_fragments
,
245 /* Fragment fields */
248 &hf_oss_fragment_overlap
,
249 &hf_oss_fragment_overlap_conflicts
,
250 &hf_oss_fragment_multiple_tails
,
251 &hf_oss_fragment_too_long_fragment
,
252 &hf_oss_fragment_error
,
253 &hf_oss_fragment_count
,
254 /* Reassembled in field */
255 &hf_oss_reassembled_in
,
256 /* Reassembled length field */
257 &hf_oss_reassembled_length
,
258 /* Reassembled data */
259 &hf_oss_reassembled_data
,
264 static const char *global_scm_udid
= "00:00:00:00:00:00";
266 static dissector_handle_t data_dissector
;
267 static dissector_handle_t opensafety_udpdata_handle
;
268 static dissector_handle_t opensafety_mbtcp_handle
;
269 static dissector_handle_t opensafety_pnio_handle
;
271 static bool global_display_intergap_data
;
272 static bool global_scm_udid_autoset
= true;
273 static bool global_udp_frame2_first
;
274 static bool global_siii_udp_frame2_first
;
275 static bool global_mbtcp_big_endian
;
276 static unsigned global_network_udp_port
= OPENSAFETY_UDP_PORT
;
277 static unsigned global_network_udp_port_sercosiii
= OPENSAFETY_UDP_PORT_SIII
;
278 static bool global_classify_transport
= true;
280 static bool global_enable_udp
= true;
281 static bool global_enable_mbtcp
= true;
283 static bool global_opensafety_debug_verbose
;
285 static const char * global_filter_nodes
= "";
286 static bool global_show_only_node_in_filter
= true;
287 static wmem_list_t
* global_filter_list
;
289 static bool heuristic_siii_dissection_enabled
= true;
291 static heur_dissector_list_t heur_opensafety_spdo_subdissector_list
;
293 static bool bDissector_Called_Once_Before
;
294 /* Using local_scm_udid as read variable for global_scm_udid, to
295 * enable automatic detection of scm udid */
296 static char *local_scm_udid
;
298 static reassembly_table os_reassembly_table
;
300 /* Resets the dissector in case the dissection is malformed and the dissector crashes */
302 reset_dissector(void)
304 bDissector_Called_Once_Before
= false;
308 setup_dissector(void)
310 heur_dtbl_entry_t
* heur_entry
= NULL
;
312 /* create list if it does not exist, but clean existing elements anyway,
313 * as options might have changed */
314 global_filter_list
= wmem_list_new(wmem_file_scope());
316 char ** vector
= wmem_strsplit(wmem_file_scope(), global_filter_nodes
, ",", -1);
317 for (; NULL
!= *vector
; vector
++ )
319 if ( *vector
&& g_ascii_strtoll(*vector
, NULL
, 10) > 0 )
320 wmem_list_append(global_filter_list
, GINT_TO_POINTER(g_ascii_strtoll(*vector
, NULL
, 10)));
323 heur_entry
= find_heur_dissector_by_unique_short_name("opensafety_sercosiii");
324 if ( heur_entry
!= NULL
)
325 heuristic_siii_dissection_enabled
= heur_entry
->enabled
;
329 cleanup_dissector(void)
331 local_scm_udid
= NULL
;
333 if ( global_filter_list
)
335 wmem_destroy_list(global_filter_list
);
336 global_filter_list
= NULL
;
340 void proto_register_opensafety(void);
341 void proto_reg_handoff_opensafety(void);
343 /* Conversation functions */
345 /* This is defined by the specification. The Address field is 10 bits long, and the node with the number
346 * 1 is always the SCM, therefore ( 2 ^ 10 ) - 1 nodes can be addressed. We use 2 ^ 10 here, because the
347 * SCM can talk to himself (Assign SADR for instance ) */
348 /* #define MAX_NUMBER_OF_SAFETY_NODES ( 1 << 10 ) */
350 /* Tracks the information that the packet pinfo has been received by receiver, and adds that information to the tree, using pos, as
351 * byte position in the PDU */
353 opensafety_packet_node(tvbuff_t
* message_tvb
, packet_info
*pinfo
, proto_tree
*tree
,
354 int hf_field
, uint16_t saddr
, uint16_t posInFrame
, uint16_t posSdnInFrame
, uint16_t sdn
)
356 proto_item
*psf_item
= NULL
;
357 proto_tree
*psf_tree
= NULL
;
359 psf_item
= proto_tree_add_uint(tree
, hf_field
, message_tvb
, posInFrame
, 2, saddr
);
360 psf_tree
= proto_item_add_subtree(psf_item
, ett_opensafety_node
);
361 psf_item
= proto_tree_add_uint(psf_tree
, hf_oss_msg_node
, message_tvb
, posInFrame
, 2, saddr
);
362 proto_item_set_generated(psf_item
);
366 psf_item
= proto_tree_add_uint(psf_tree
, hf_oss_msg_network
, message_tvb
,
367 posSdnInFrame
, 2, sdn
);
368 } else if ( sdn
<= 0 ) {
369 psf_item
= proto_tree_add_uint(psf_tree
, hf_oss_msg_network
, message_tvb
,
370 posSdnInFrame
, 2, sdn
* -1);
371 expert_add_info(pinfo
, psf_item
, &ei_scmudid_unknown
);
373 proto_item_set_generated(psf_item
);
377 opensafety_packet_receiver(tvbuff_t
* message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, proto_item
*opensafety_item
,
378 opensafety_packet_info
*packet
, uint16_t recv
,
379 uint16_t posInFrame
, uint16_t posSdnInFrame
, uint16_t sdn
)
381 packet
->receiver
= recv
;
385 opensafety_packet_node (message_tvb
, pinfo
, tree
, hf_oss_msg_receiver
, recv
, posInFrame
, posSdnInFrame
, sdn
);
386 proto_item_append_text(opensafety_item
, ", Dst: 0x%03X (%d)", recv
, recv
);
389 /* Tracks the information that the packet pinfo has been sent by sender, and received by everyone else, and adds that information to
390 * the tree, using pos, as byte position in the PDU */
392 opensafety_packet_sender(tvbuff_t
* message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, proto_item
*opensafety_item
,
393 opensafety_packet_info
*packet
, uint16_t sender
,
394 uint16_t posInFrame
, uint16_t posSdnInFrame
, uint16_t sdn
)
396 packet
->sender
= sender
;
400 opensafety_packet_node (message_tvb
, pinfo
, tree
, hf_oss_msg_sender
, sender
, posInFrame
, posSdnInFrame
, sdn
);
401 proto_item_append_text(opensafety_item
, ", Src: 0x%03X (%d)", sender
, sender
);
404 /* Tracks the information that the packet pinfo has been sent by sender, and received by receiver, and adds that information to
405 * the tree, using pos for the sender and pos2 for the receiver, as byte position in the PDU */
407 opensafety_packet_sendreceiv(tvbuff_t
* message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, proto_item
*opensafety_item
,
408 opensafety_packet_info
*packet
, uint16_t send
, uint16_t pos
,
409 uint16_t recv
, uint16_t pos2
, uint16_t posnet
, uint16_t sdn
)
411 opensafety_packet_receiver(message_tvb
, pinfo
, tree
, opensafety_item
, packet
, recv
, pos2
, posnet
, sdn
);
412 opensafety_packet_sender(message_tvb
, pinfo
, tree
, opensafety_item
, packet
, send
, pos
, posnet
, sdn
);
416 opensafety_packet_response(tvbuff_t
*message_tvb
, proto_tree
*sub_tree
, opensafety_packet_info
*packet
, bool isResponse
)
418 proto_item
*item
= NULL
;
421 if ( packet
->msg_type
!= OPENSAFETY_SPDO_MESSAGE_TYPE
)
423 proto_tree_add_item(sub_tree
, hf_oss_msg
, message_tvb
,
424 OSS_FRAME_POS_ID
+ packet
->frame
.subframe1
, 1, ENC_NA
);
428 /* SPDOs code the connection valid bit on offset 0x04. SSDO and SNMT frames use this
429 * bit for messages. Therefore setting a bitmask on the hf-field would not work. */
430 b_id
= OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) & 0xF8;
431 proto_tree_add_uint(sub_tree
, hf_oss_msg
, message_tvb
, OSS_FRAME_POS_ID
+ packet
->frame
.subframe1
, 1, b_id
);
434 item
= proto_tree_add_item(sub_tree
, packet
->msg_type
!= OPENSAFETY_SPDO_MESSAGE_TYPE
? hf_oss_msg_direction
: hf_oss_spdo_direction
,
435 message_tvb
, OSS_FRAME_POS_ID
+ packet
->frame
.subframe1
, 1, ENC_NA
);
437 packet
->is_request
= true;
443 opensafety_packet_payloadtree(packet_info
*pinfo
, tvbuff_t
*message_tvb
, proto_tree
*opensafety_tree
,
444 opensafety_packet_info
*packet
, int ett_tree
)
446 proto_item
*item
= NULL
;
448 item
= proto_tree_add_item(opensafety_tree
, hf_oss_msg_category
, message_tvb
, OSS_FRAME_POS_ID
+ packet
->frame
.subframe1
, 1, ENC_NA
);
449 proto_item_set_generated(item
);
451 if ( packet
->msg_type
== OPENSAFETY_SNMT_MESSAGE_TYPE
)
452 packet
->payload
.snmt
= wmem_new0(pinfo
->pool
, opensafety_packet_snmt
);
453 else if ( packet
->msg_type
== OPENSAFETY_SSDO_MESSAGE_TYPE
|| packet
->msg_type
== OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
455 packet
->payload
.ssdo
= wmem_new0(pinfo
->pool
, opensafety_packet_ssdo
);
456 if ( packet
->msg_type
== OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
457 packet
->payload
.ssdo
->is_slim
= true;
459 else if ( packet
->msg_type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
460 packet
->payload
.spdo
= wmem_new0(pinfo
->pool
, opensafety_packet_spdo
);
462 return proto_item_add_subtree(item
, ett_tree
);
466 findFrame1Position ( packet_info
*pinfo
, tvbuff_t
*message_tvb
, uint16_t byte_offset
, uint8_t dataLength
, bool checkIfSlimMistake
)
468 uint16_t i_wFrame1Position
= 0;
469 uint16_t i_payloadLength
, i_calculatedLength
= 0;
470 uint16_t i_offset
= 0, calcCRC
= 0, frameCRC
= 0;
471 uint8_t b_tempByte
= 0;
472 uint8_t *bytes
= NULL
;
475 * First, a normal package is assumed. Calculation of frame 1 position is
476 * pretty easy, because, the length of the whole package is 11 + 2*n + 2*o, which
477 * results in frame 1 start at (6 + n + o), which is length / 2 + 1
479 i_wFrame1Position
= dataLength
/ 2 + 1;
480 i_payloadLength
= tvb_get_uint8(message_tvb
, byte_offset
+ i_wFrame1Position
+ 2 );
481 /* Calculating the assumed frame length, taking CRC8/CRC16 into account */
482 i_calculatedLength
= i_payloadLength
* 2 + 11 + 2 * (i_payloadLength
> OSS_PAYLOAD_MAXSIZE_FOR_CRC8
? 1 : 0);
484 /* To prevent miscalculations, where by chance the byte at [length / 2] + 3 is a value matching a possible payload length,
485 * but in reality the frame is a slim ssdo, the CRC of frame 1 gets checked additionally. This check
486 * is somewhat time consuming, so it will only run if the normal check led to a mistake detected along the line */
487 if ( checkIfSlimMistake
&& i_calculatedLength
== dataLength
)
489 if (dataLength
> OSS_PAYLOAD_MAXSIZE_FOR_CRC8
)
490 frameCRC
= tvb_get_letohs(message_tvb
, byte_offset
+ i_wFrame1Position
+ dataLength
+ OSS_FRAME_POS_DATA
);
492 frameCRC
= tvb_get_uint8(message_tvb
, byte_offset
+ i_wFrame1Position
+ dataLength
+ OSS_FRAME_POS_DATA
);
494 bytes
= (uint8_t*)tvb_memdup(pinfo
->pool
, message_tvb
, byte_offset
+ i_wFrame1Position
, dataLength
+ 4);
495 if ( dataLength
> OSS_PAYLOAD_MAXSIZE_FOR_CRC8
)
497 calcCRC
= crc16_0x755B(bytes
, dataLength
+ 4, 0);
498 if ( frameCRC
!= calcCRC
)
499 calcCRC
= crc16_0x5935(bytes
, dataLength
+ 4, 0);
502 calcCRC
= crc8_0x2F(bytes
, dataLength
+ 4, 0);
504 /* if the calculated crc does not match the detected, the package is not a normal openSAFETY package */
505 if ( frameCRC
!= calcCRC
)
509 /* If the calculated length differs from the given length, a slim package is assumed. */
510 if ( i_calculatedLength
!= dataLength
)
512 /* possible slim package */
513 i_wFrame1Position
= 0;
515 * Slim packages have a fixed sublength of either 6 bytes for frame 2 in
516 * case of crc8 and 7 bytes in case of crc16
518 i_offset
= OSS_SLIM_FRAME2_WITH_CRC8
+ ( dataLength
< (OSS_SLIM_FRAME_WITH_CRC8_MAXSIZE
+ 1) ? 0 : 1 );
519 /* Last 2 digits belong to addr, therefore have to be cleared */
520 b_tempByte
= ( tvb_get_uint8 ( message_tvb
, byte_offset
+ i_offset
+ 1 ) ) & 0xFC;
522 /* If the id byte xor 0xE8 is 0, we have a slim package */
523 if ( ( ( b_tempByte
^ OPENSAFETY_MSG_SSDO_SLIM_SERVICE_REQUEST
) == 0 ) ||
524 ( ( b_tempByte
^ OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE
) == 0 ) )
526 /* Slim package found */
527 i_wFrame1Position
= i_offset
;
531 return i_wFrame1Position
;
534 static bool findSafetyFrame ( packet_info
*pinfo
, tvbuff_t
*message_tvb
, unsigned u_Offset
, bool b_frame2first
,
535 unsigned *u_frameOffset
, unsigned *u_frameLength
, opensafety_packet_info
*packet
)
537 unsigned ctr
, rem_length
;
538 uint16_t crc
, f2crc
, calcCrc
= 0;
539 uint8_t b_Length
= 0, b_CTl
= 0, crcOffset
= 0, crc1Type
= 0;
546 rem_length
= tvb_reported_length_remaining (message_tvb
, ctr
);
548 /* Search will allways start at the second byte of the frame ( cause it determines )
549 * the type of package and therefore everything else. Therefore the mininmum length - 1
550 * is the correct minimum length */
551 while ( rem_length
>= ( OSS_MINIMUM_LENGTH
- 1 ) )
553 /* The ID byte must ALWAYS be the second byte, therefore 0 is invalid,
554 * also, the byte we want to access, must at least exist, otherwise,
555 * the frame is not detectable as an openSAFETY frame.
556 * We check for ID and length */
557 if ( ctr
!= 0 && tvb_bytes_exist(message_tvb
, ctr
, 2) )
563 b_ID
= tvb_get_uint8(message_tvb
, ctr
);
567 b_Length
= tvb_get_uint8(message_tvb
, ctr
+ 1 );
569 /* 0xFF is often used, but always false, otherwise start detection, if the highest
571 if ( ( b_ID
!= 0xFF ) && ( b_ID
& 0x80 ) )
573 /* The rem_length value might be polluted, due to the else statement of
574 * above if-decision (frame at end position detection). Therefore we
575 * calculate it here again, to have a sane value */
576 rem_length
= tvb_reported_length_remaining(message_tvb
, ctr
);
578 /* Plausibility check on length */
579 if ( (unsigned)( b_Length
* 2 ) < ( rem_length
+ OSS_MINIMUM_LENGTH
) )
582 /* The calculated length must fit, but for the CRC16 check, also the calculated length
583 * plus the CRC16 end position must fit in the remaining length */
584 if ( ( b_Length
<= (unsigned) 8 && ( b_Length
<= rem_length
) ) ||
585 ( b_Length
> (unsigned) 8 && ( ( b_Length
+ (unsigned) 5 ) <= rem_length
) ) )
587 /* Ensure, that the correct length for CRC calculation
588 * still exists in byte stream, so that we can calculate the crc */
589 if ( tvb_bytes_exist(message_tvb
, ctr
- 1, b_Length
+ 5) )
591 /* An openSAFETY command has to have a high-byte range between 0x0A and 0x0E
592 * b_ID & 0x80 took care of everything underneath, we check for 0x09 and 0x0F,
593 * as they remain the only values left, which are not valid */
594 if ( ( ( b_ID
>> 4 ) != 0x09 ) && ( ( b_ID
>> 4 ) != 0x0F ) )
596 /* Read CRC from position */
597 crc
= tvb_get_uint8(message_tvb
, ctr
+ 3 + b_Length
);
599 /* There exists some false positives, where the only possible
600 * data information in the frame is the ID and the ADDR fields.
601 * The rest of the fields in frame 1 are zeroed out. The packet
602 * must be filtered out and may not be used. To detect it, we
603 * check for the CT value, which, if zero indicates strongly
604 * that this is false-positive. */
605 b_CTl
= tvb_get_uint8(message_tvb
, ctr
+ 2 );
607 /* If either length, crc or CTl is not zero, this may be a
608 * correct package. If all three are 0, this is most certainly
609 * an incorrect package, because the possibility of a valid
610 * package with all three values being zero is next to impossible */
611 if ( b_Length
!= 0x00 || crc
!= 0x00 || b_CTl
!= 0x00 )
613 /* calculate checksum */
614 bytes
= (uint8_t *)tvb_memdup(pinfo
->pool
, message_tvb
, ctr
- 1, b_Length
+ 5 );
617 crc
= tvb_get_letohs ( message_tvb
, ctr
+ 3 + b_Length
);
620 crc1Type
= OPENSAFETY_CHECKSUM_CRC16
;
621 calcCrc
= crc16_0x755B( bytes
, b_Length
+ 4, 0 );
622 if ( ( crc
^ calcCrc
) != 0 )
624 calcCrc
= crc16_0x5935( bytes
, b_Length
+ 4, 0 );
625 if ( ( crc
^ calcCrc
) == 0 )
626 crc1Type
= OPENSAFETY_CHECKSUM_CRC16SLIM
;
628 crc1Type
= OPENSAFETY_CHECKSUM_INVALID
;
631 crc1Type
= OPENSAFETY_CHECKSUM_CRC8
;
632 calcCrc
= crc8_0x2F ( bytes
, b_Length
+ 4, 0 );
635 if ( ( crc
^ calcCrc
) == 0 )
637 /* Check if this is a Slim SSDO message */
638 if ( ( b_ID
>> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
>> 3 ) )
640 /* Slim SSDO messages must have a length != 0, as the first byte
641 * in the payload contains the SOD access command */
644 *u_frameOffset
= ( ctr
- 1 );
645 *u_frameLength
= b_Length
+ 2 * crcOffset
+ 11;
647 /* It is highly unlikely, that both frame 1 and frame 2 generate
648 * a crc == 0 or equal crc's. Therefore we check, if both crc's are
649 * equal. If so, it is a falsely detected frame. */
650 f2crc
= tvb_get_uint8 ( message_tvb
, ctr
+ 3 + 5 + b_Length
);
652 f2crc
= tvb_get_letohs ( message_tvb
, ctr
+ 3 + 5 + b_Length
);
662 *u_frameLength
= 2 * b_Length
+ 2 * crcOffset
+ 11;
663 *u_frameOffset
= ( ctr
- 1 );
665 /* If the first crc is zero, the second one must not be 0. The header
666 * for each subfields differ, therefore it is impossible, that both
670 f2crc
= tvb_get_uint8 ( message_tvb
, ( ctr
- 1 ) + 10 + ( 2 * b_Length
) );
672 f2crc
= tvb_get_letohs ( message_tvb
, ( ctr
- 1 ) + 11 + ( 2 * b_Length
) );
674 /* The crc's differ, everything is ok */
683 /* At this point frames had been checked for SoC and SoA types of
684 * EPL. This is no longer necessary and leads to false-negatives.
685 * SoC and SoA frames get filtered out at the EPL entry point, cause
686 * EPL only provides payload, no longer complete frames. */
700 /* There exist frames, where the last openSAFETY frame is sitting in the
701 * very last bytes of the frame, and the complete frame itself contains
702 * more than one openSAFETY frame. It so happens that in such a case, the
703 * last openSAFETY frame will miss detection.
705 * If so we look at the transported length, calculate the frame length,
706 * and take a look if the calculated frame length, might be a fit for the
707 * remaining length. If such is the case, we increment ctr and increment
708 * rem_length (to hit the while loop one more time) and the frame will be
709 * detected correctly. */
710 if ( rem_length
== OSS_MINIMUM_LENGTH
)
712 b_ID
= tvb_get_uint8(message_tvb
, ctr
);
713 b_Length
= tvb_get_uint8(message_tvb
, ctr
+ 2 );
714 if ( ( b_ID
>> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
>> 3 ) )
715 b_Length
= ( 11 + ( b_Length
> 8 ? 2 : 0 ) + b_Length
);
717 b_Length
= ( 11 + ( b_Length
> 8 ? 2 : 0 ) + 2 * b_Length
);
719 if ( rem_length
== b_Length
)
731 rem_length
= tvb_reported_length_remaining(message_tvb
, ctr
);
735 /* Store packet information in packet_info */
736 if ( found
&& packet
)
738 packet
->msg_id
= b_ID
;
739 packet
->msg_len
= b_Length
;
740 packet
->frame_len
= *u_frameLength
;
742 /* Should be the calculated crc, which is the same as the frame crc */
743 packet
->crc
.frame1
= calcCrc
;
744 packet
->crc
.type
= crc1Type
;
745 if ( packet
->crc
.type
!= OPENSAFETY_CHECKSUM_INVALID
)
746 packet
->crc
.valid1
= true;
748 packet
->crc
.valid1
= false;
751 /* Seem redundant if b_frame2First is false. But in this case, the function is needed for the
752 * simple detection of a possible openSAFETY frame. */
753 if ( b_frame2first
&& found
)
754 *u_frameOffset
= u_Offset
;
760 dissect_data_payload ( proto_tree
*epl_tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, int len
, uint8_t msgType
)
763 tvbuff_t
* payload_tvb
= NULL
;
764 heur_dtbl_entry_t
*hdtbl_entry
= NULL
;
770 payload_tvb
= tvb_new_subset_length_caplen(tvb
, off
, len
, tvb_reported_length_remaining(tvb
, offset
) );
771 if ( ! dissector_try_heuristic(heur_opensafety_spdo_subdissector_list
, payload_tvb
, pinfo
, epl_tree
, &hdtbl_entry
, &msgType
))
772 call_dissector(data_dissector
, payload_tvb
, pinfo
, epl_tree
);
781 dissect_opensafety_spdo_message(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*opensafety_tree
,
782 opensafety_packet_info
* packet
, proto_item
* opensafety_item
)
784 proto_item
*item
, *diritem
;
785 proto_tree
*spdo_tree
, *spdo_flags_tree
;
790 uint8_t tr
, b_ID
, spdoFlags
;
792 dataLength
= tvb_get_uint8(message_tvb
, OSS_FRAME_POS_LEN
+ packet
->frame
.subframe1
);
793 b_ID
= tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 1) & 0xF8;
795 /* Network address is xor'ed into the start of the second frame, but only legible, if the scm given is valid */
796 sdn
= ( ( OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
) ) ^
797 ( OSS_FRAME_ADDR_T2(message_tvb
, packet
->frame
.subframe2
, packet
->scm_udid
[0], packet
->scm_udid
[1]) ) );
798 if ( ! packet
->scm_udid_valid
)
801 /* taddr is the 4th octet in the second frame */
802 tr
= ( tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 4) ^ packet
->scm_udid
[4] ) & 0xFC;
804 /* allow only valid SPDO flags */
805 spdoFlags
= ( ( tr
>> 2 ) & OPENSAFETY_SPDO_FEATURE_FLAGS
);
807 /* An SPDO is always sent by the producer, to everybody else .
808 * For a 40bit connection OPENSAFETY_DEFAULT_DOMAIN is assumed as sdn value for now */
809 if ( (OPENSAFETY_SPDO_FEAT_40BIT_USED
& spdoFlags
) == OPENSAFETY_SPDO_FEAT_40BIT_USED
)
810 sdn
= OPENSAFETY_DEFAULT_DOMAIN
;
812 /* Determine the producer and set it, as opensafety_packet_node does not */
813 addr
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
);
814 packet
->sender
= addr
;
816 opensafety_packet_node ( message_tvb
, pinfo
, opensafety_tree
, hf_oss_msg_sender
,
817 addr
, OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe1
, packet
->frame
.subframe2
, sdn
);
818 proto_item_append_text(opensafety_item
, "; Producer: 0x%03X (%d)", addr
, addr
);
820 spdo_tree
= opensafety_packet_payloadtree ( pinfo
, message_tvb
, opensafety_tree
, packet
, ett_opensafety_spdo
);
822 /* Determine SPDO Flags. Attention packet->payload.spdo exists ONLY AFTER opensafety_packet_payloadtree */
823 packet
->payload
.spdo
->flags
.enabled40bit
= false;
824 packet
->payload
.spdo
->flags
.requested40bit
= false;
826 if ( (OPENSAFETY_SPDO_FEAT_40BIT_AVAIL
& spdoFlags
) == OPENSAFETY_SPDO_FEAT_40BIT_AVAIL
)
827 packet
->payload
.spdo
->flags
.requested40bit
= true;
828 if ( packet
->payload
.spdo
->flags
.requested40bit
&& ( (OPENSAFETY_SPDO_FEAT_40BIT_USED
& spdoFlags
) == OPENSAFETY_SPDO_FEAT_40BIT_USED
) )
829 packet
->payload
.spdo
->flags
.enabled40bit
= true;
831 diritem
= opensafety_packet_response(message_tvb
, spdo_tree
, packet
, b_ID
== OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE
);
832 proto_tree_add_item(spdo_tree
, hf_oss_spdo_connection_valid
, message_tvb
, OSS_FRAME_POS_ID
+ packet
->frame
.subframe1
, 1, ENC_NA
);
834 packet
->payload
.spdo
->conn_valid
= (tvb_get_uint8(message_tvb
, OSS_FRAME_POS_ID
+ packet
->frame
.subframe1
) & 0x04) == 0x04;
836 /* taddr is the 4th octet in the second frame */
837 taddr
= OSS_FRAME_ADDR_T2(message_tvb
, packet
->frame
.subframe2
+ 3, packet
->scm_udid
[3], packet
->scm_udid
[4]);
838 tr
= ( tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 4) ^ packet
->scm_udid
[4] ) & 0xFC;
840 /* determine the ct value. if complete it can be used for analysis of the package */
841 ct
= tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 3);
842 if ( packet
->scm_udid_valid
)
844 ct
= (uint16_t)((tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 2) ^ packet
->scm_udid
[2]) << 8) +
845 (tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 3));
848 if ( b_ID
== OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST
)
850 proto_item_append_text(diritem
, " (Safety Node: %03d)", taddr
);
851 item
= proto_tree_add_uint_format_value(spdo_tree
, hf_oss_spdo_ct
, message_tvb
, 0, 0, ct
,
852 "0x%04X [%d] (%s)", ct
, ct
,
853 (packet
->scm_udid_valid
? "Complete" : "Low byte only"));
854 proto_item_set_generated(item
);
855 packet
->payload
.spdo
->counter
.b16
= ct
;
857 packet
->payload
.spdo
->timerequest
= taddr
;
858 proto_tree_add_uint(spdo_tree
, hf_oss_spdo_time_request
, message_tvb
,
859 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 4, 1, tr
);
860 opensafety_packet_node ( message_tvb
, pinfo
, spdo_tree
, hf_oss_spdo_time_request_from
, taddr
,
861 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 3, packet
->frame
.subframe2
, sdn
);
865 if ( ! (b_ID
== OPENSAFETY_MSG_SPDO_DATA_ONLY
) || !(packet
->payload
.spdo
->flags
.enabled40bit
) )
867 item
= proto_tree_add_uint_format_value(spdo_tree
, hf_oss_spdo_ct
, message_tvb
, 0, 0, ct
,
868 "0x%04X [%d] (%s)", ct
, ct
, (packet
->scm_udid_valid
? "Complete" : "Low byte only"));
869 proto_item_set_generated(item
);
870 packet
->payload
.spdo
->counter
.b16
= ct
;
874 /* 40bit counter is calculated from various fields. Therefore it cannot be read
875 * directly from the frame. All fields starting after or with packet->frame.subframe2 have to
876 * be decoded using the scm udid */
877 ct40bit
= (tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 3) ^ packet
->scm_udid
[3]);
879 ct40bit
+= ((uint64_t)(tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 1) ^ packet
->scm_udid
[1]) ^ tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 1));
881 ct40bit
+= (tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 0) ^ packet
->scm_udid
[0]) ^ OPENSAFETY_DEFAULT_DOMAIN
^ tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 0);
883 ct40bit
+= (tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 2) ^ packet
->scm_udid
[2]);
885 ct40bit
+= tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 3);
887 item
= proto_tree_add_uint64(spdo_tree
, hf_oss_spdo_ct_40bit
, message_tvb
, 0, 0, ct40bit
);
888 proto_item_set_generated(item
);
890 packet
->payload
.spdo
->counter
.b40
= ct40bit
;
891 if ( global_opensafety_debug_verbose
)
892 expert_add_info ( pinfo
, item
, &ei_40bit_default_domain
);
894 proto_item_set_generated(item
);
896 if ( b_ID
== OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE
)
898 proto_item_append_text(diritem
, " (Safety Node: %03d)", taddr
);
899 proto_tree_add_uint(spdo_tree
, hf_oss_spdo_time_request
, message_tvb
,
900 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 4, 1, tr
);
901 packet
->payload
.spdo
->timerequest
= taddr
;
903 opensafety_packet_node ( message_tvb
, pinfo
, spdo_tree
, hf_oss_spdo_time_request_to
, taddr
,
904 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 3, packet
->frame
.subframe2
, sdn
);
908 item
= proto_tree_add_uint(spdo_tree
, hf_oss_spdo_feature_flags
,
909 message_tvb
, OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 4, 1, spdoFlags
<< 2);
911 spdo_flags_tree
= proto_item_add_subtree(item
, ett_opensafety_spdo_flags
);
913 proto_tree_add_boolean(spdo_flags_tree
, hf_oss_spdo_feature_flag_40bit_available
, message_tvb
,
914 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 4, 1,
915 packet
->payload
.spdo
->flags
.requested40bit
? OPENSAFETY_SPDO_FEAT_40BIT_AVAIL
<< 2 : 0 );
916 proto_tree_add_boolean(spdo_flags_tree
, hf_oss_spdo_feature_flag_40bit_used
, message_tvb
,
917 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe2
+ 4, 1,
918 packet
->payload
.spdo
->flags
.enabled40bit
? OPENSAFETY_SPDO_FEAT_40BIT_USED
<< 2 : 0 );
922 if ( dataLength
> 0 )
924 dissect_data_payload(spdo_tree
, message_tvb
, pinfo
, OSS_FRAME_POS_ID
+ 3, dataLength
, OPENSAFETY_SPDO_MESSAGE_TYPE
);
928 static void dissect_opensafety_ssdo_payload ( packet_info
*pinfo
, tvbuff_t
*new_tvb
, proto_tree
*ssdo_payload
, uint8_t sacmd
)
930 unsigned dataLength
= 0, ctr
= 0, n
= 0, nCRCs
= 0;
931 uint8_t ssdoSubIndex
= 0;
932 uint16_t ssdoIndex
= 0, dispSSDOIndex
= 0;
933 uint32_t sodLength
= 0, entry
= 0;
935 proto_tree
*sod_tree
, *ext_tree
;
937 dataLength
= tvb_captured_length(new_tvb
);
939 ssdoIndex
= tvb_get_letohs(new_tvb
, 0);
941 sodLength
= tvb_get_letohl(new_tvb
, 4);
943 /* first check for extended parameter */
944 if ( dataLength
== 16 || sodLength
== ( dataLength
- 16 ) || ssdoIndex
== 0x0101 )
946 /* extended parameter header & data */
947 item
= proto_tree_add_string_format(ssdo_payload
, hf_oss_ssdo_extpar
,
948 new_tvb
, 0, dataLength
, "", "Extended Parameter Set: %s",
949 (dataLength
== 16 ? "Header only" : "Header & Data") );
950 ext_tree
= proto_item_add_subtree(item
, ett_opensafety_ssdo_extpar
);
952 proto_tree_add_item(ext_tree
, hf_oss_ssdo_extpar_parset
, new_tvb
, 0, 1, ENC_BIG_ENDIAN
);
953 proto_tree_add_item(ext_tree
, hf_oss_ssdo_extpar_version
, new_tvb
, 1, 1, ENC_BIG_ENDIAN
);
954 proto_tree_add_item(ext_tree
, hf_oss_ssdo_extpar_saddr
, new_tvb
, 2, 2, ENC_LITTLE_ENDIAN
);
956 proto_tree_add_uint_format_value(ext_tree
, hf_oss_ssdo_extpar_length
,
957 new_tvb
, 4, 4, sodLength
, "0x%04X (%d octets)",
958 sodLength
, sodLength
);
960 proto_tree_add_item(ext_tree
, hf_oss_ssdo_extpar_crc
, new_tvb
, 8, 4, ENC_LITTLE_ENDIAN
);
961 proto_tree_add_item(ext_tree
, hf_oss_ssdo_extpar_tstamp
, new_tvb
, 12, 4, ENC_LITTLE_ENDIAN
);
963 if ( dataLength
!= 16 )
965 item
= proto_tree_add_item(ext_tree
, hf_oss_ssdo_extpar_data
, new_tvb
, 16, dataLength
- 16, ENC_NA
);
967 if ( ( dataLength
- sodLength
) != 16 )
968 expert_add_info ( pinfo
, item
, &ei_message_reassembly_size_differs_from_header
);
973 /* If == upload, it is most likely a par upload */
974 if ( sacmd
== OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END
&& ( dataLength
% 4 == 0 ) )
977 item
= proto_tree_add_uint_format_value(ssdo_payload
, hf_oss_ssdo_sod_index
, new_tvb
,
978 0, 0, 0x1018, "0x%04X (%s)", 0x1018,
979 val_to_str_ext_const( ((uint32_t) (0x1018 << 16) ),
980 &opensafety_sod_idx_names_ext
, "Unknown") );
981 sod_tree
= proto_item_add_subtree(item
, ett_opensafety_ssdo_sodentry
);
982 proto_item_set_generated(item
);
984 item
= proto_tree_add_uint_format_value(sod_tree
, hf_oss_ssdo_sod_subindex
, new_tvb
, 0, 0,
985 0x06, "0x%02X (%s)", 0x06,
986 val_to_str_ext_const(((uint32_t) (0x1018 << 16) + 0x06),
987 &opensafety_sod_idx_names_ext
, "Unknown") );
988 proto_item_set_generated(item
);
990 proto_tree_add_item( sod_tree
, hf_oss_sod_par_timestamp
, new_tvb
, 0, 4, ENC_LITTLE_ENDIAN
);
992 /* This is to avoid a compiler loop optimization warning */
993 nCRCs
= dataLength
/ 4;
994 for ( ctr
= 1; ctr
< nCRCs
; ctr
++ )
996 entry
= tvb_get_letohl ( new_tvb
, ctr
* 4 );
997 proto_tree_add_uint_format_value ( sod_tree
, hf_oss_sod_par_checksum
, new_tvb
, ctr
* 4,
998 4, entry
, "[#%d] 0x%08X", ctr
, entry
);
1001 /* If != upload, it is most likely a 101A download */
1005 /* normal parameter set */
1006 for ( ctr
= 0; ctr
< dataLength
; ctr
++ )
1008 ssdoIndex
= tvb_get_letohs(new_tvb
, ctr
);
1009 ssdoSubIndex
= tvb_get_uint8(new_tvb
, ctr
+ 2);
1010 dispSSDOIndex
= ssdoIndex
;
1012 if ( ssdoIndex
>= 0x1400 && ssdoIndex
<= 0x17FE )
1013 dispSSDOIndex
= 0x1400;
1014 else if ( ssdoIndex
>= 0x1800 && ssdoIndex
<= 0x1BFE )
1015 dispSSDOIndex
= 0x1800;
1016 else if ( ssdoIndex
>= 0x1C00 && ssdoIndex
<= 0x1FFE )
1017 dispSSDOIndex
= 0x1C00;
1018 else if ( ssdoIndex
>= 0xC000 && ssdoIndex
<= 0xC3FE )
1019 dispSSDOIndex
= 0xC000;
1021 item
= proto_tree_add_uint_format_value(ssdo_payload
, hf_oss_ssdo_sod_index
, new_tvb
,
1022 ctr
, 2, ssdoIndex
, "0x%04X (%s)", ssdoIndex
,
1023 val_to_str_ext_const( ((uint32_t) (dispSSDOIndex
<< 16) ),
1024 &opensafety_sod_idx_names_ext
, "Unknown") );
1025 if ( ssdoIndex
!= dispSSDOIndex
)
1026 proto_item_set_generated ( item
);
1028 if ( ssdoIndex
< 0x1000 || ssdoIndex
> 0xE7FF )
1029 expert_add_info ( pinfo
, item
, &ei_payload_unknown_format
);
1031 sod_tree
= proto_item_add_subtree(item
, ett_opensafety_ssdo_sodentry
);
1033 if ( ssdoSubIndex
!= 0 )
1035 proto_tree_add_uint_format_value(sod_tree
, hf_oss_ssdo_sod_subindex
, new_tvb
, ctr
+ 2, 1,
1036 ssdoSubIndex
, "0x%02X (%s)", ssdoSubIndex
,
1037 val_to_str_ext_const(((uint32_t) (ssdoIndex
<< 16) + ssdoSubIndex
),
1038 &opensafety_sod_idx_names_ext
, "Unknown") );
1041 proto_tree_add_uint_format_value(sod_tree
, hf_oss_ssdo_sod_subindex
, new_tvb
, ctr
+ 2, 1,
1042 ssdoSubIndex
, "0x%02X", ssdoSubIndex
);
1045 /* reading real size */
1046 sodLength
= tvb_get_letohl ( new_tvb
, ctr
+ 1 );
1047 if ( sodLength
> (dataLength
- ctr
) )
1050 if ( ( sodLength
+ 4 + ctr
) > dataLength
)
1053 if ( ssdoIndex
== OPENSAFETY_SOD_DVI
&& ssdoSubIndex
== 0x06 )
1055 proto_tree_add_item( sod_tree
, hf_oss_sod_par_timestamp
, new_tvb
, ctr
+ 5, 4, ENC_LITTLE_ENDIAN
);
1057 /* This is to avoid a compiler loop optimization warning */
1058 nCRCs
= sodLength
/ 4;
1059 for ( n
= 1; n
< nCRCs
; n
++ )
1061 entry
= tvb_get_letohl ( new_tvb
, ctr
+ 5 + ( n
* 4 ) );
1062 proto_tree_add_uint_format_value ( sod_tree
, hf_oss_sod_par_checksum
, new_tvb
,
1063 (ctr
+ 5 + ( n
* 4 ) ), 4, entry
, "[#%d] 0x%08X", n
, entry
);
1065 } else if ( ssdoIndex
== OPENSAFETY_SOD_DVI
&& ssdoSubIndex
== 0x07 ) {
1066 proto_tree_add_item( sod_tree
, hf_oss_sod_par_timestamp
, new_tvb
, ctr
+ 5, 4, ENC_LITTLE_ENDIAN
);
1067 } else if ( ( dispSSDOIndex
== OPENSAFETY_SOD_RXMAP
|| dispSSDOIndex
== OPENSAFETY_SOD_TXMAP
) && ssdoSubIndex
!= 0x0 ) {
1068 proto_tree_add_uint(sod_tree
, hf_oss_ssdo_sodentry_size
, new_tvb
, ctr
+ 1, 4, sodLength
);
1069 item
= proto_tree_add_item(sod_tree
, hf_oss_ssdo_sodmapping
, new_tvb
, ctr
+ 5, sodLength
, ENC_NA
);
1070 ext_tree
= proto_item_add_subtree(item
, ett_opensafety_sod_mapping
);
1072 proto_tree_add_item(ext_tree
, hf_oss_ssdo_sodmapping_bits
, new_tvb
, ctr
+ 5, 1, ENC_NA
);
1074 proto_tree_add_item(ext_tree
, hf_oss_ssdo_sod_index
, new_tvb
, ctr
+ 7, 2, ENC_LITTLE_ENDIAN
);
1075 proto_tree_add_item(ext_tree
, hf_oss_ssdo_sod_subindex
, new_tvb
, ctr
+ 6, 1, ENC_NA
);
1078 proto_tree_add_uint(sod_tree
, hf_oss_ssdo_sodentry_size
, new_tvb
, ctr
+ 1, 4, sodLength
);
1079 if ( sodLength
> 0 )
1080 proto_tree_add_item(sod_tree
, hf_oss_ssdo_sodentry_data
, new_tvb
, ctr
+ 5, sodLength
, ENC_NA
);
1082 ctr
+= sodLength
+ 4;
1091 dissect_opensafety_ssdo_message(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*opensafety_tree
,
1092 opensafety_packet_info
* packet
, proto_item
* opensafety_item
)
1095 proto_tree
*ssdo_tree
, *ssdo_payload
;
1096 uint16_t taddr
= 0, sdn
= 0, server
= 0, client
= 0, n
= 0, ct
= 0;
1097 uint32_t abortcode
, ssdoIndex
= 0, ssdoSubIndex
= 0, payloadSize
, fragmentId
= 0, entry
= 0;
1098 uint8_t db0Offset
, db0
, payloadOffset
, preload
;
1099 unsigned dataLength
;
1101 bool isResponse
, saveFragmented
;
1102 tvbuff_t
*new_tvb
= NULL
;
1103 fragment_head
*frag_msg
= NULL
;
1105 static int * const ssdo_sacmd_flags
[] = {
1106 &hf_oss_ssdo_sacmd_end_segment
,
1107 &hf_oss_ssdo_sacmd_initiate
,
1108 &hf_oss_ssdo_sacmd_toggle
,
1109 &hf_oss_ssdo_sacmd_segmentation
,
1110 &hf_oss_ssdo_sacmd_abort_transfer
,
1111 &hf_oss_ssdo_sacmd_preload
,
1112 &hf_oss_ssdo_sacmd_access_type
,
1116 dataLength
= tvb_get_uint8(message_tvb
, OSS_FRAME_POS_LEN
+ packet
->frame
.subframe1
);
1118 db0Offset
= packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
;
1119 db0
= tvb_get_uint8(message_tvb
, db0Offset
);
1123 /* Response is determined by the openSAFETY message field */
1124 isResponse
= ( ( OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) & 0x04 ) == 0x04 );
1126 if ( packet
->scm_udid_valid
)
1128 /* taddr is the 4th octet in the second frame */
1129 taddr
= OSS_FRAME_ADDR_T2(message_tvb
, packet
->frame
.subframe2
+ 3, packet
->scm_udid
[3], packet
->scm_udid
[4]);
1130 sdn
= ( OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
) ^
1131 ( OSS_FRAME_ADDR_T2(message_tvb
, packet
->frame
.subframe2
, packet
->scm_udid
[0], packet
->scm_udid
[1]) ) );
1133 opensafety_packet_sendreceiv ( message_tvb
, pinfo
, opensafety_tree
, opensafety_item
, packet
, taddr
,
1134 packet
->frame
.subframe2
+ 3, OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
),
1135 packet
->frame
.subframe1
, packet
->frame
.subframe2
, sdn
);
1137 else if ( ! isResponse
)
1139 opensafety_packet_sender ( message_tvb
, pinfo
, opensafety_tree
, opensafety_item
, packet
,
1140 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
), packet
->frame
.subframe1
,
1141 packet
->frame
.subframe2
, -1 * ( ( OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
) ) ^
1142 ( OSS_FRAME_ADDR_T2(message_tvb
, packet
->frame
.subframe2
, packet
->scm_udid
[0], packet
->scm_udid
[1]) ) ) );
1144 else if ( isResponse
)
1146 opensafety_packet_receiver ( message_tvb
, pinfo
, opensafety_tree
, opensafety_item
, packet
,
1147 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
), packet
->frame
.subframe1
,
1148 packet
->frame
.subframe2
, -1 * ( ( OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
) ) ^
1149 ( OSS_FRAME_ADDR_T2(message_tvb
, packet
->frame
.subframe2
, packet
->scm_udid
[0], packet
->scm_udid
[1]) ) ) );
1152 ssdo_tree
= opensafety_packet_payloadtree ( pinfo
, message_tvb
, opensafety_tree
, packet
, ett_opensafety_ssdo
);
1154 opensafety_packet_response ( message_tvb
, ssdo_tree
, packet
, isResponse
);
1156 packet
->payload
.ssdo
->sacmd
.toggle
= ( db0
& OPENSAFETY_SSDO_SACMD_TGL
) == OPENSAFETY_SSDO_SACMD_TGL
;
1157 packet
->payload
.ssdo
->sacmd
.abort_transfer
= ( db0
& OPENSAFETY_SSDO_SACMD_ABRT
) == OPENSAFETY_SSDO_SACMD_ABRT
;
1158 packet
->payload
.ssdo
->sacmd
.preload
= ( db0
& OPENSAFETY_SSDO_SACMD_PRLD
) == OPENSAFETY_SSDO_SACMD_PRLD
;
1159 packet
->payload
.ssdo
->sacmd
.read_access
= ( db0
& OPENSAFETY_SSDO_DOWNLOAD
) == OPENSAFETY_SSDO_DOWNLOAD
;
1160 packet
->payload
.ssdo
->sacmd
.initiate
= ( db0
& OPENSAFETY_SSDO_SACMD_INI
) == OPENSAFETY_SSDO_SACMD_INI
;
1161 packet
->payload
.ssdo
->sacmd
.segmented
= ( db0
& OPENSAFETY_SSDO_SACMD_SEG
) == OPENSAFETY_SSDO_SACMD_SEG
;
1162 packet
->payload
.ssdo
->sacmd
.end_segment
= ( db0
& OPENSAFETY_SSDO_SACMD_ENSG
) == OPENSAFETY_SSDO_SACMD_ENSG
;
1166 opensafety_packet_node ( message_tvb
, pinfo
, ssdo_tree
, hf_oss_ssdo_client
,
1167 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
),
1168 packet
->frame
.subframe1
, packet
->frame
.subframe2
, sdn
);
1169 client
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
);
1171 if ( packet
->scm_udid_valid
)
1173 proto_tree_add_uint(ssdo_tree
, hf_oss_ssdo_server
, message_tvb
, packet
->frame
.subframe2
+ 3, 2, taddr
);
1177 else if ( ! isResponse
)
1179 proto_tree_add_uint(ssdo_tree
, hf_oss_ssdo_server
, message_tvb
, packet
->frame
.subframe1
, 2, OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
));
1180 server
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
);
1181 if ( packet
->scm_udid_valid
)
1183 opensafety_packet_node ( message_tvb
, pinfo
, ssdo_tree
, hf_oss_ssdo_client
,
1184 taddr
, packet
->frame
.subframe2
+ 3, packet
->frame
.subframe2
, sdn
);
1189 /* Toggle bit must be removed, otherwise the values cannot be displayed correctly */
1190 if ( packet
->payload
.ssdo
->sacmd
.toggle
)
1191 db0
&= (~OPENSAFETY_SSDO_SACMD_TGL
);
1192 proto_tree_add_bitmask(ssdo_tree
, message_tvb
, db0Offset
, hf_oss_ssdo_sacmd
,
1193 ett_opensafety_ssdo_sacmd
, ssdo_sacmd_flags
, ENC_NA
);
1195 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", SACMD: %s", val_to_str_const(db0
, opensafety_ssdo_sacmd_values
, " "));
1197 payloadOffset
= db0Offset
+ 1;
1199 ct
= tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 3);
1200 if ( packet
->scm_udid_valid
)
1202 ct
= (uint16_t)((tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 2) ^ packet
->scm_udid
[2]) << 8);
1203 ct
+= (tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ 3));
1206 proto_tree_add_uint(ssdo_tree
, hf_oss_ssdo_sano
, message_tvb
, packet
->frame
.subframe1
+ 3, 1, ct
);
1208 /* Evaluate preload field [field TR] */
1209 if ( packet
->scm_udid_valid
&& packet
->payload
.ssdo
->sacmd
.preload
&& isResponse
)
1211 /* Preload info are the higher 6 bit of the TR field */
1212 preload
= ( (tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 4) ^ packet
->scm_udid
[4]) & 0xFC ) >> 2;
1214 if ( packet
->payload
.ssdo
->sacmd
.initiate
)
1216 /* Use the lower 4 bits from the preload as size */
1217 proto_tree_add_uint_format_value(ssdo_tree
, hf_oss_ssdo_preload_queue
, message_tvb
, packet
->frame
.subframe2
+ 4, 1,
1218 preload
& 0x0F, "%d", preload
& 0x0F );
1222 /* The highest 2 bits of information contain an error flag */
1223 item
= proto_tree_add_item(ssdo_tree
, hf_oss_ssdo_preload_error
, message_tvb
, packet
->frame
.subframe2
+ 4, 1, ENC_NA
);
1224 if ( (preload
& 0x30) == 0x30 )
1225 proto_item_append_text(item
, " (SOD Access Request Number is last successful)" );
1229 /* When the following clause is met, DB1,2 contain the SOD index, and DB3 the SOD subindex */
1230 if ( packet
->payload
.ssdo
->sacmd
.initiate
&& !packet
->payload
.ssdo
->sacmd
.abort_transfer
)
1232 ssdoIndex
= tvb_get_letohs(message_tvb
, db0Offset
+ 1);
1233 ssdoSubIndex
= tvb_get_uint8(message_tvb
, db0Offset
+ 3);
1235 proto_tree_add_uint_format_value(ssdo_tree
, hf_oss_ssdo_sod_index
, message_tvb
, db0Offset
+ 1, 2,
1236 ssdoIndex
, "0x%04X (%s)", ssdoIndex
,
1237 val_to_str_ext_const(((uint32_t) (ssdoIndex
<< 16)), &opensafety_sod_idx_names_ext
, "Unknown") );
1238 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [%s", val_to_str_ext_const(((uint32_t) (ssdoIndex
<< 16)), &opensafety_sod_idx_names_ext
, "Unknown"));
1240 /* Some SOD downloads (0x101A for instance) don't have sub-indices */
1241 if ( ssdoSubIndex
!= 0x0 )
1243 proto_tree_add_uint_format_value(ssdo_tree
, hf_oss_ssdo_sod_subindex
, message_tvb
, db0Offset
+ 3, 1,
1244 ssdoSubIndex
, "0x%02X (%s)", ssdoSubIndex
,
1245 val_to_str_ext_const(((uint32_t) (ssdoIndex
<< 16) + ssdoSubIndex
), &opensafety_sod_idx_names_ext
, "Unknown") );
1246 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " - %s",
1247 val_to_str_ext_const(((uint32_t) (ssdoIndex
<< 16) + ssdoSubIndex
), &opensafety_sod_idx_names_ext
, "Unknown"));
1249 col_append_str(pinfo
->cinfo
, COL_INFO
, "]");
1253 if ( packet
->payload
.ssdo
->sacmd
.abort_transfer
)
1255 abortcode
= tvb_get_letohl(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 4);
1257 proto_tree_add_uint_format_value(ssdo_tree
, hf_oss_ssdo_abort_code
, message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 4, 4, abortcode
,
1258 "0x%04X %04X - %s", (uint16_t)(abortcode
>> 16), (uint16_t)(abortcode
),
1259 val_to_str_ext_const(abortcode
, &opensafety_abort_codes_ext
, "Unknown"));
1260 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " - %s", val_to_str_ext_const(abortcode
, &opensafety_abort_codes_ext
, "Unknown"));
1264 /* Either the SSDO msg is a response, then data is sent by the server and only in uploads,
1265 * or the message is a request, then data is coming from the client and payload data is
1266 * sent in downloads. Data is only sent in initiate, segmented or end-segment messages */
1267 if ( ( packet
->payload
.ssdo
->sacmd
.initiate
|| packet
->payload
.ssdo
->sacmd
.segmented
|| packet
->payload
.ssdo
->sacmd
.end_segment
) &&
1268 ( ( isResponse
&& !packet
->payload
.ssdo
->sacmd
.read_access
) ||
1269 ( !isResponse
&& packet
->payload
.ssdo
->sacmd
.read_access
) ) )
1271 saveFragmented
= pinfo
->fragmented
;
1272 if ( server
!= 0 && client
!= 0 )
1273 fragmentId
= (uint32_t)((((uint32_t)client
) << 16 ) + server
);
1275 /* If payload data has to be calculated, either a total size is given, or not */
1276 if ( packet
->payload
.ssdo
->sacmd
.segmented
&& packet
->payload
.ssdo
->sacmd
.initiate
)
1281 /* reading real size */
1282 payloadSize
= tvb_get_letohl(message_tvb
, payloadOffset
- 4);
1284 calcDataLength
= dataLength
- (payloadOffset
- db0Offset
);
1286 item
= proto_tree_add_uint_format_value(ssdo_tree
, hf_oss_ssdo_payload_size
, message_tvb
, payloadOffset
- 4, 4,
1287 payloadSize
, "%d octets total (%d octets in this frame)", payloadSize
, calcDataLength
);
1289 if ( calcDataLength
>= 0 )
1291 if ( fragmentId
!= 0 && packet
->payload
.ssdo
->sacmd
.segmented
)
1293 pinfo
->fragmented
= true;
1294 frag_msg
= fragment_add_seq_check(&os_reassembly_table
, message_tvb
, payloadOffset
, pinfo
,
1295 fragmentId
, NULL
, 0, calcDataLength
, true );
1296 fragment_add_seq_offset ( &os_reassembly_table
, pinfo
, fragmentId
, NULL
, ct
);
1298 if ( frag_msg
!= NULL
)
1300 item
= proto_tree_add_bytes_format_value(ssdo_tree
, hf_oss_ssdo_payload
, message_tvb
, 0, 0, NULL
, "Reassembled" );
1301 proto_item_set_generated(item
);
1303 ssdo_payload
= proto_item_add_subtree(item
, ett_opensafety_ssdo_payload
);
1304 process_reassembled_data(message_tvb
, 0, pinfo
, "Reassembled Message", frag_msg
, &oss_frag_items
, NULL
, ssdo_payload
);
1308 proto_tree_add_item(ssdo_tree
, hf_oss_ssdo_payload
, message_tvb
, payloadOffset
, calcDataLength
, ENC_NA
);
1310 if ( global_opensafety_debug_verbose
)
1311 expert_add_info_format(pinfo
, item
, &ei_payload_length_not_positive
,
1312 "Calculation for payload length yielded non-positive result [%d]", (unsigned) calcDataLength
);
1317 payloadSize
= dataLength
- (payloadOffset
- db0Offset
);
1318 if ((int)dataLength
< (payloadOffset
- db0Offset
))
1320 if ( global_opensafety_debug_verbose
)
1321 expert_add_info_format(pinfo
, opensafety_item
, &ei_payload_length_not_positive
,
1322 "Calculation for payload length yielded non-positive result [%d]", (int)payloadSize
);
1326 if ( fragmentId
!= 0 && packet
->payload
.ssdo
->sacmd
.segmented
)
1328 pinfo
->fragmented
= true;
1330 frag_msg
= fragment_add_seq_check(&os_reassembly_table
, message_tvb
, payloadOffset
, pinfo
,
1331 fragmentId
, NULL
, ct
, payloadSize
,
1332 packet
->payload
.ssdo
->sacmd
.end_segment
? false : true );
1337 item
= proto_tree_add_bytes_format_value(ssdo_tree
, hf_oss_ssdo_payload
, message_tvb
,
1338 0, 0, NULL
, "Reassembled" );
1339 proto_item_set_generated(item
);
1340 ssdo_payload
= proto_item_add_subtree(item
, ett_opensafety_ssdo_payload
);
1342 new_tvb
= process_reassembled_data(message_tvb
, 0, pinfo
, "Reassembled Message", frag_msg
,
1343 &oss_frag_items
, NULL
, ssdo_payload
);
1344 if ( packet
->payload
.ssdo
->sacmd
.end_segment
&& new_tvb
)
1346 item
= proto_tree_add_uint_format_value(ssdo_payload
, hf_oss_ssdo_payload_size
, message_tvb
, 0, 0,
1347 payloadSize
, "%d octets (over all fragments)", frag_msg
->len
);
1348 proto_item_set_generated(item
);
1350 col_append_str(pinfo
->cinfo
, COL_INFO
, " (Message Reassembled)" );
1351 dissect_opensafety_ssdo_payload ( pinfo
, new_tvb
, ssdo_payload
, db0
);
1356 item
= proto_tree_add_uint_format_value(ssdo_tree
, hf_oss_ssdo_payload_size
, message_tvb
, 0, 0, payloadSize
,
1357 "%d octets", payloadSize
);
1358 proto_item_set_generated(item
);
1360 if ( ssdoIndex
== OPENSAFETY_SOD_DVI
&& ssdoSubIndex
== 0x06 )
1362 proto_tree_add_item( ssdo_tree
, hf_oss_sod_par_timestamp
, message_tvb
, payloadOffset
, 4, ENC_LITTLE_ENDIAN
);
1363 for ( n
= 4; n
< payloadSize
; n
+=4 )
1365 entry
= tvb_get_letohl ( message_tvb
, payloadOffset
+ n
);
1366 proto_tree_add_uint_format_value ( ssdo_tree
, hf_oss_sod_par_checksum
, message_tvb
, (payloadOffset
+ n
),
1367 4, entry
, "[#%d] 0x%08X", ( n
/ 4 ), entry
);
1369 } else if ( ssdoIndex
== OPENSAFETY_SOD_DVI
&& ssdoSubIndex
== 0x07 ) {
1370 proto_tree_add_item ( ssdo_tree
, hf_oss_sod_par_timestamp
, message_tvb
, payloadOffset
, 4, ENC_LITTLE_ENDIAN
);
1372 proto_tree_add_item(ssdo_tree
, hf_oss_ssdo_payload
, message_tvb
, payloadOffset
, payloadSize
, ENC_NA
);
1376 pinfo
->fragmented
= saveFragmented
;
1382 opensafety_parse_scm_udid ( tvbuff_t
* tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1383 opensafety_packet_info
*packet
, unsigned offset
)
1385 proto_item
* item
= NULL
;
1386 char *scm_udid_test
= NULL
;
1388 item
= proto_tree_add_item(tree
, hf_oss_snmt_udid
, tvb
, offset
, 6, ENC_NA
);
1390 scm_udid_test
= tvb_bytes_to_str_punct(pinfo
->pool
, tvb
, offset
, 6, ':' );
1392 if ( scm_udid_test
!= NULL
&& strlen( scm_udid_test
) == 17 )
1394 if ( g_strcmp0("00:00:00:00:00:00", scm_udid_test
) != 0 )
1396 packet
->payload
.snmt
->scm_udid
= scm_udid_test
;
1398 if ( ( global_scm_udid_autoset
== true ) && ( memcmp ( global_scm_udid
, scm_udid_test
, 17 ) != 0 ) )
1400 if ( local_scm_udid
== NULL
|| memcmp ( local_scm_udid
, scm_udid_test
, 17 ) != 0 )
1402 local_scm_udid
= wmem_strdup(wmem_file_scope(), scm_udid_test
);
1403 if ( global_opensafety_debug_verbose
)
1404 expert_add_info_format(pinfo
, item
, &ei_scmudid_autodetected
,
1405 "Auto detected payload as SCM UDID [%s].", local_scm_udid
);
1413 dissect_opensafety_snmt_message(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*opensafety_tree
,
1414 opensafety_packet_info
*packet
, proto_item
* opensafety_item
)
1416 proto_tree
*snmt_tree
;
1417 uint16_t addr
, taddr
, sdn
;
1418 uint8_t db0
, byte
, errcode
;
1419 unsigned dataLength
;
1421 dataLength
= OSS_FRAME_LENGTH_T(message_tvb
, packet
->frame
.subframe1
);
1423 /* addr is the first field, as well as the recipient of the message */
1424 addr
= packet
->saddr
;
1426 /* taddr is the 4th octet in the second frame */
1427 taddr
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe2
+ 3);
1428 /* domain is xor'ed on the first field in the second frame. As this is also addr, it is easy to obtain */
1429 sdn
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe2
) ^ addr
;
1434 db0
= tvb_get_uint8(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
);
1436 packet
->msg_id
= OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
);
1438 if ( ( packet
->msg_id
== OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE
) &&
1439 ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP
) == 0 ||
1440 (db0
^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP
) == 0 ) )
1442 opensafety_packet_receiver( message_tvb
, pinfo
, opensafety_tree
, opensafety_item
, packet
, addr
,
1443 OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe1
, packet
->frame
.subframe2
, sdn
);
1447 opensafety_packet_sendreceiv ( message_tvb
, pinfo
, opensafety_tree
, opensafety_item
, packet
, taddr
,
1448 packet
->frame
.subframe2
+ 3, addr
, OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe1
,
1449 packet
->frame
.subframe2
, sdn
);
1452 snmt_tree
= opensafety_packet_payloadtree ( pinfo
, message_tvb
, opensafety_tree
, packet
, ett_opensafety_snmt
);
1453 /* Just a precaution, cause payloadtree actually sets the snmt pointer */
1454 if ( packet
->payload
.snmt
== NULL
)
1457 if ( ( packet
->msg_id
== OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE
) ||
1458 ( packet
->msg_id
== OPENSAFETY_MSG_SNMT_SERVICE_REQUEST
) )
1459 packet
->payload
.snmt
->ext_msg_id
= db0
;
1461 opensafety_packet_response(message_tvb
, snmt_tree
, packet
, ( packet
->msg_id
& 0x04 ) == 0x04 );
1463 if ( packet
->is_request
)
1465 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_master
, message_tvb
, packet
->frame
.subframe2
+ 3, 2, taddr
);
1466 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_slave
, message_tvb
, OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe1
, 2, addr
);
1470 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_master
, message_tvb
, OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe1
, 2, addr
);
1471 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_slave
, message_tvb
, packet
->frame
.subframe2
+ 3, 2, taddr
);
1474 /* Handle Acknowledge and Fail specifically */
1475 if ( ( ( db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE
) == 0 ) || ( db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL
) == 0 )
1477 byte
= tvb_get_uint8(message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1);
1479 /* Handle a normal SN Fail */
1480 if ( byte
!= OPENSAFETY_ERROR_GROUP_ADD_PARAMETER
)
1482 if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL
) == 0 )
1484 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_service_id
, message_tvb
,
1485 OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 1, packet
->payload
.snmt
->ext_msg_id
);
1486 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
1487 val_to_str_const(packet
->payload
.snmt
->ext_msg_id
, opensafety_message_service_type
, "Unknown"));
1489 else if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE
) == 0 )
1491 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_service_id
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 1, db0
);
1492 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", val_to_str_const(db0
, opensafety_message_service_type
, "Unknown"));
1495 proto_tree_add_uint_format_value(snmt_tree
, hf_oss_snmt_error_group
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1, 1,
1496 byte
, "%s", ( byte
== 0 ? "Device" : val_to_str(byte
, opensafety_sn_fail_error_group
, "Reserved [%d]" ) ) );
1498 errcode
= tvb_get_uint8(message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 2);
1499 proto_tree_add_uint_format_value(snmt_tree
, hf_oss_snmt_error_code
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 2, 1,
1500 errcode
, "%s [%d]", ( errcode
== 0 ? "Default" : "Vendor Specific" ), errcode
);
1502 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " - Group: %s; Code: %s",
1503 ( byte
== 0 ? "Device" : val_to_str(byte
, opensafety_sn_fail_error_group
, "Reserved [%d]" ) ),
1504 ( errcode
== 0 ? "Default" : "Vendor Specific" )
1507 packet
->payload
.snmt
->add_param
.exists
= false;
1508 packet
->payload
.snmt
->error_code
= errcode
;
1512 if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL
) == 0 )
1514 proto_tree_add_uint_format_value(snmt_tree
, hf_oss_snmt_service_id
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 1,
1515 packet
->payload
.snmt
->ext_msg_id
, "%s [Request via SN Fail] (0x%02X)",
1516 val_to_str_const(byte
, opensafety_sn_fail_error_group
, "Unknown"), packet
->payload
.snmt
->ext_msg_id
);
1517 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", val_to_str_const(byte
, opensafety_sn_fail_error_group
, "Unknown"));
1518 } else if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE
) == 0 )
1520 proto_tree_add_uint_format_value(snmt_tree
, hf_oss_snmt_service_id
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 1,
1521 packet
->payload
.snmt
->ext_msg_id
, "Additional parameter missing [Response via SN Acknowledge] (0x%02X)", packet
->payload
.snmt
->ext_msg_id
);
1522 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Additional parameter missing");
1525 errcode
= tvb_get_uint8(message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 2);
1526 packet
->payload
.snmt
->add_param
.exists
= true;
1527 packet
->payload
.snmt
->add_param
.id
= errcode
;
1528 packet
->payload
.snmt
->add_param
.set
= ( errcode
& 0x0F ) + 1;
1529 packet
->payload
.snmt
->add_param
.full
= ( ( errcode
& 0xF0 ) == 0xF0 );
1531 /* Handle an additional parameter request */
1532 proto_tree_add_uint(snmt_tree
, hf_oss_ssdo_extpar_parset
, message_tvb
,
1533 OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 2, 1, ( errcode
& 0x0F ) + 1 );
1535 proto_tree_add_boolean(snmt_tree
, hf_oss_snmt_param_type
, message_tvb
,
1536 OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 2, 1, ( ( errcode
& 0xF0 ) != 0xF0 ) );
1539 else if ( (OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) ^ OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE
) == 0 )
1541 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_service_id
, message_tvb
,
1542 OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 1, packet
->payload
.snmt
->ext_msg_id
);
1543 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
1544 val_to_str_const(packet
->payload
.snmt
->ext_msg_id
, opensafety_message_service_type
, "Unknown"));
1546 if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_UDID_SCM
) == 0 )
1548 opensafety_parse_scm_udid ( message_tvb
, pinfo
, snmt_tree
, packet
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1 );
1550 else if ( ( db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_ADDITIONAL_SADR
) == 0 )
1552 packet
->payload
.snmt
->add_saddr
.actual
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1);
1553 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_ext_addsaddr
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1, 2,
1554 packet
->payload
.snmt
->add_saddr
.actual
);
1556 packet
->payload
.snmt
->add_saddr
.additional
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 3);
1557 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_ext_addtxspdo
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 3, 2,
1558 packet
->payload
.snmt
->add_saddr
.additional
);
1560 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [0x%04X => 0x%04X]",
1561 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1),
1562 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 3));
1564 else if ( ( db0
^ OPENSAFETY_MSG_SNMT_EXT_ASSIGNED_INIT_CT
) == 0 )
1566 packet
->payload
.snmt
->init_ct
=
1567 tvb_get_uint40(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1, ENC_BIG_ENDIAN
);
1568 proto_tree_add_item(snmt_tree
, hf_oss_snmt_ext_initct
, message_tvb
,
1569 packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1, 5, ENC_BIG_ENDIAN
);
1572 else if ( (OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) ^ OPENSAFETY_MSG_SNMT_SERVICE_REQUEST
) == 0 )
1574 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_service_id
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 1, db0
);
1575 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s", val_to_str_const(db0
, opensafety_message_service_type
, "Unknown"));
1577 if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP
) == 0 || (db0
^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP
) == 0 )
1579 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_scm
, message_tvb
, OSS_FRAME_POS_ADDR
+ packet
->frame
.subframe1
, 2, addr
);
1580 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_tool
, message_tvb
, packet
->frame
.subframe2
+ 3, 2, taddr
);
1582 else if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGN_UDID_SCM
) == 0 )
1584 opensafety_parse_scm_udid ( message_tvb
, pinfo
, snmt_tree
, packet
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1 );
1586 else if ( ( db0
^ OPENSAFETY_MSG_SNMT_EXT_ASSIGN_INIT_CT
) == 0 )
1588 packet
->payload
.snmt
->init_ct
=
1589 tvb_get_uint40(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1, ENC_BIG_ENDIAN
);
1590 proto_tree_add_item(snmt_tree
, hf_oss_snmt_ext_initct
, message_tvb
,
1591 packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1, 5, ENC_BIG_ENDIAN
);
1595 if ( (db0
^ OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_OP
) == 0 )
1597 proto_tree_add_item ( snmt_tree
, hf_oss_sod_par_timestamp
, message_tvb
,
1598 OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1, 4, ENC_LITTLE_ENDIAN
);
1600 else if ( ( db0
^ OPENSAFETY_MSG_SNMT_EXT_ASSIGN_ADDITIONAL_SADR
) == 0 )
1602 packet
->payload
.snmt
->add_saddr
.actual
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1);
1603 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_ext_addsaddr
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1, 2,
1604 packet
->payload
.snmt
->add_saddr
.actual
);
1606 packet
->payload
.snmt
->add_saddr
.additional
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 3);
1607 proto_tree_add_uint(snmt_tree
, hf_oss_snmt_ext_addtxspdo
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 3, 2,
1608 packet
->payload
.snmt
->add_saddr
.additional
);
1610 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [0x%04X => 0x%04X]",
1611 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 1),
1612 OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
+ OSS_FRAME_POS_DATA
+ 3));
1617 else if ( (OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) ^ OPENSAFETY_MSG_SNMT_SADR_ASSIGNED
) == 0 ||
1618 (OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) ^ OPENSAFETY_MSG_SNMT_ASSIGN_SADR
) == 0 ||
1619 (OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) ^ OPENSAFETY_MSG_SNMT_RESPONSE_UDID
) == 0 )
1623 packet
->payload
.snmt
->sn_udid
= wmem_strdup(pinfo
->pool
,
1624 tvb_bytes_to_str_punct(pinfo
->pool
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
+ 1, 6, ':' ) );
1625 proto_tree_add_item(snmt_tree
, hf_oss_snmt_udid
, message_tvb
, OSS_FRAME_POS_DATA
+ packet
->frame
.subframe1
, 6, ENC_NA
);
1631 dissect_opensafety_checksum(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*opensafety_tree
,
1632 opensafety_packet_info
*packet
)
1634 uint16_t frame1_crc
, frame2_crc
;
1635 uint16_t calc1_crc
, calc2_crc
;
1636 unsigned dataLength
, frame2Length
;
1637 uint8_t *bytesf2
, *bytesf1
, ctr
= 0, crcType
= OPENSAFETY_CHECKSUM_CRC8
;
1639 proto_tree
*checksum_tree
;
1642 bool isSlim
= false;
1643 bool isSNMT
= false;
1644 bool isSPDO
= false;
1645 GByteArray
*scmUDID
= NULL
;
1647 dataLength
= OSS_FRAME_LENGTH_T(message_tvb
, packet
->frame
.subframe1
);
1648 start
= OSS_FRAME_POS_DATA
+ dataLength
+ packet
->frame
.subframe1
;
1650 if (OSS_FRAME_LENGTH_T(message_tvb
, packet
->frame
.subframe1
) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8
)
1651 frame1_crc
= tvb_get_letohs(message_tvb
, start
);
1653 frame1_crc
= tvb_get_uint8(message_tvb
, start
);
1655 if ( packet
->msg_type
== OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
1657 if ( packet
->msg_type
== OPENSAFETY_SNMT_MESSAGE_TYPE
)
1659 if ( packet
->msg_type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
1662 frame2Length
= (isSlim
? 0 : dataLength
) + 5;
1664 length
= (dataLength
> OSS_PAYLOAD_MAXSIZE_FOR_CRC8
? OPENSAFETY_CHECKSUM_CRC16
: OPENSAFETY_CHECKSUM_CRC8
);
1665 item
= proto_tree_add_uint_format(opensafety_tree
, hf_oss_crc
, message_tvb
, start
, length
, frame1_crc
,
1666 "CRC for subframe #1: 0x%04X", frame1_crc
);
1668 checksum_tree
= proto_item_add_subtree(item
, ett_opensafety_checksum
);
1670 bytesf1
= (uint8_t*)tvb_memdup(pinfo
->pool
, message_tvb
, packet
->frame
.subframe1
, dataLength
+ 4);
1672 crcType
= packet
->crc
.type
;
1673 calc1_crc
= packet
->crc
.frame1
;
1675 if ( ! isSlim
&& crcType
== OPENSAFETY_CHECKSUM_CRC16SLIM
)
1676 expert_add_info(pinfo
, item
, &ei_crc_slimssdo_instead_of_spdo
);
1678 item
= proto_tree_add_boolean(checksum_tree
, hf_oss_crc_valid
, message_tvb
,
1679 packet
->frame
.subframe1
, dataLength
+ 4, (frame1_crc
== calc1_crc
));
1680 proto_item_set_generated(item
);
1681 if ( crcType
== OPENSAFETY_CHECKSUM_INVALID
|| frame1_crc
!= calc1_crc
)
1682 expert_add_info(pinfo
, item
, &ei_crc_frame_1_invalid
);
1684 /* using the defines, as the values can change */
1685 proto_tree_add_uint(checksum_tree
, hf_oss_crc_type
, message_tvb
, start
, length
, crcType
);
1687 start
= packet
->frame
.subframe2
+ (isSlim
? 5 : dataLength
+ OSS_FRAME_POS_DATA
+ 1 );
1688 if (OSS_FRAME_LENGTH_T(message_tvb
, packet
->frame
.subframe1
) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8
)
1689 frame2_crc
= tvb_get_letohs(message_tvb
, start
);
1691 frame2_crc
= tvb_get_uint8(message_tvb
, start
);
1693 /* 0xFFFF is an invalid CRC16 value, therefore valid for initialization. Needed, because
1694 * otherwise this function may return without setting calc2_crc, and this does not go well
1695 * with the compiler */
1698 /* Currently SPDO 40 Bit CRC2 support is broken. Will be implemented at a later state, after
1699 * the first generation of openSAFETY devices using 40 bit counter are available */
1700 if ( isSPDO
&& packet
->payload
.spdo
->flags
.enabled40bit
== true )
1701 packet
->scm_udid_valid
= false;
1703 /* This used to be an option. But only, because otherwise there would be three different
1704 * crc calculations taking place within dissection. As we could reduce this by one, the
1705 * global option has been changed to the simple validity question, if we have enough information
1706 * to calculate the second crc, meaning, if the SCM udid is known, or if we have an SNMT msg */
1707 if ( isSNMT
|| packet
->scm_udid_valid
)
1709 bytesf2
= (uint8_t*)tvb_memdup(pinfo
->pool
, message_tvb
, packet
->frame
.subframe2
, frame2Length
+ length
);
1711 /* SLIM SSDO messages, do not contain a payload in frame2 */
1712 if ( isSlim
== true )
1715 scmUDID
= g_byte_array_new();
1716 packet
->crc
.valid2
= false;
1717 if ( isSNMT
|| ( hex_str_to_bytes((local_scm_udid
!= NULL
? local_scm_udid
: global_scm_udid
), scmUDID
, true) && scmUDID
->len
== 6 ) )
1721 for ( ctr
= 0; ctr
< 6; ctr
++ )
1722 bytesf2
[ctr
] = bytesf2
[ctr
] ^ (uint8_t)(scmUDID
->data
[ctr
]);
1726 /* allow only valid SPDO flags */
1727 if ( packet
->msg_id
== OPENSAFETY_MSG_SPDO_DATA_ONLY
)
1729 if ( packet
->payload
.spdo
->flags
.enabled40bit
== true )
1731 /* we assume the OPENSAFETY_DEFAULT_DOMAIN (0x01) for 40 bit for now */
1732 bytesf2
[0] = bytesf2
[0] ^ (bytesf2
[0] ^ OPENSAFETY_DEFAULT_DOMAIN
^ bytesf1
[0]);
1733 bytesf2
[1] = bytesf2
[1] ^ (bytesf2
[1] ^ bytesf1
[1]);
1739 if ( isSlim
|| packet
->frame
.length
== 11 )
1740 frame2_crc
^= ((uint8_t)scmUDID
->data
[5]);
1743 * If the second frame is 6 or 7 (slim) bytes in length, we have to decode the found
1744 * frame crc again. This must be done using the byte array, as the unxor operation
1745 * had to take place.
1747 if ( dataLength
== 0 )
1749 if ( isSlim
&& length
== 2 )
1750 frame2_crc
= ( bytesf2
[6] << 8 ) + bytesf2
[5];
1755 item
= proto_tree_add_uint_format(opensafety_tree
, hf_oss_crc
, message_tvb
, start
, length
, frame2_crc
,
1756 "CRC for subframe #2: 0x%04X", frame2_crc
);
1758 checksum_tree
= proto_item_add_subtree(item
, ett_opensafety_checksum
);
1760 if ( OSS_FRAME_LENGTH_T(message_tvb
, packet
->frame
.subframe1
) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8
)
1762 calc2_crc
= crc16_0x755B(bytesf2
, frame2Length
, 0);
1763 if ( frame2_crc
!= calc2_crc
)
1764 calc2_crc
= crc16_0x5935(bytesf2
, frame2Length
, 0);
1767 calc2_crc
= crc8_0x2F(bytesf2
, frame2Length
, 0);
1769 item
= proto_tree_add_boolean(checksum_tree
, hf_oss_crc2_valid
, message_tvb
,
1770 packet
->frame
.subframe2
, frame2Length
, (frame2_crc
== calc2_crc
));
1771 proto_item_set_generated(item
);
1773 if ( frame2_crc
!= calc2_crc
)
1775 item
= proto_tree_add_uint_format(checksum_tree
, hf_oss_crc
, message_tvb
,
1776 packet
->frame
.subframe2
, frame2Length
, calc2_crc
, "Calculated CRC: 0x%04X", calc2_crc
);
1777 proto_item_set_generated(item
);
1778 expert_add_info(pinfo
, item
, &ei_crc_frame_2_invalid
);
1782 if ( global_opensafety_debug_verbose
&& ( isSlim
|| ( !isSNMT
&& packet
->frame
.length
== 11 ) ) )
1783 expert_add_info(pinfo
, item
, &ei_crc_frame_2_scm_udid_encoded
);
1785 packet
->crc
.valid2
= true;
1789 expert_add_info(pinfo
, item
, &ei_crc_frame_2_unknown_scm_udid
);
1791 g_byte_array_free(scmUDID
, true);
1794 /* For a correct calculation of the second crc we need to know the scm udid.
1795 * If the dissection of the second frame has been triggered, we integrate the
1796 * crc for frame2 into the result */
1797 return (bool) (frame1_crc
== calc1_crc
) &&
1798 ( ( isSNMT
|| packet
->scm_udid_valid
) == true ? (frame2_crc
== calc2_crc
) : true);
1802 check_scmudid_validity(opensafety_packet_info
*packet
, tvbuff_t
*message_tvb
)
1804 uint8_t b_ID
, spdoFlags
, udidLen
;
1805 GByteArray
*scmUDID
= NULL
;
1807 packet
->scm_udid_valid
= false;
1808 scmUDID
= g_byte_array_new();
1810 if ( hex_str_to_bytes((local_scm_udid
!= NULL
? local_scm_udid
: global_scm_udid
), scmUDID
, true) && scmUDID
->len
== 6 )
1812 packet
->scm_udid_valid
= true;
1814 /* Now confirm, that the xor operation was successful. The ID fields of both frames have to be the same */
1815 b_ID
= tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 1) ^ (uint8_t)(scmUDID
->data
[OSS_FRAME_POS_ID
]);
1816 if ( ( OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) ^ (b_ID
& 0xFC)) != 0 )
1817 packet
->scm_udid_valid
= false;
1819 /* The IDs do not match, but the SCM UDID could still be ok. This happens, if this packet
1820 * utilizes the 40 bit counter. Therefore we reduce the check here only to the feature
1821 * flags, but only if the package is a SPDO Data Only (because everything else uses 16 bit. */
1822 if ( packet
->msg_id
== OPENSAFETY_MSG_SPDO_DATA_ONLY
)
1824 spdoFlags
= ( tvb_get_uint8(message_tvb
, packet
->frame
.subframe2
+ 4 ) ^ scmUDID
->data
[4] ) ;
1825 spdoFlags
= ( spdoFlags
>> 2 ) & OPENSAFETY_SPDO_FEATURE_FLAGS
;
1826 if ( ( spdoFlags
& OPENSAFETY_SPDO_FEAT_40BIT_USED
) == OPENSAFETY_SPDO_FEAT_40BIT_USED
)
1827 packet
->scm_udid_valid
= true;
1830 if ( packet
->scm_udid_valid
== true )
1831 memcpy(packet
->scm_udid
, scmUDID
->data
, 6);
1834 udidLen
= scmUDID
->len
;
1836 g_byte_array_free( scmUDID
, true);
1842 dissect_opensafety_message(opensafety_packet_info
*packet
,
1843 tvbuff_t
*message_tvb
, packet_info
*pinfo
,
1844 proto_item
*opensafety_item
, proto_tree
*opensafety_tree
,
1845 uint8_t u_nrInPackage
, uint8_t previous_msg_id
)
1847 uint8_t ctr
, udidLen
;
1849 bool messageTypeUnknown
, crcValid
;
1851 messageTypeUnknown
= false;
1853 for ( ctr
= 0; ctr
< 6; ctr
++ )
1854 packet
->scm_udid
[ctr
] = 0;
1856 packet
->saddr
= OSS_FRAME_ADDR_T(message_tvb
, packet
->frame
.subframe1
);
1857 /* Sender / Receiver is determined by message type */
1859 packet
->receiver
= 0;
1861 /* SPDO is handled below */
1862 if ( packet
->msg_type
!= OPENSAFETY_SPDO_MESSAGE_TYPE
)
1864 col_append_fstr(pinfo
->cinfo
, COL_INFO
, (u_nrInPackage
> 1 ? " | %s" : "%s" ),
1865 val_to_str(packet
->msg_id
, opensafety_message_type_values
, "Unknown Message (0x%02X) "));
1868 item
= proto_tree_add_uint(opensafety_tree
, hf_oss_byte_offset
, packet
->frame
.frame_tvb
, 0, 1, packet
->frame
.byte_offset
);
1869 proto_item_set_generated(item
);
1871 if ( packet
->msg_type
== OPENSAFETY_SNMT_MESSAGE_TYPE
)
1873 proto_item_append_text(opensafety_item
, ", SNMT");
1874 dissect_opensafety_snmt_message ( message_tvb
, pinfo
, opensafety_tree
, packet
, opensafety_item
);
1878 udidLen
= check_scmudid_validity(packet
, message_tvb
);
1880 if ( strlen( (local_scm_udid
!= NULL
? local_scm_udid
: global_scm_udid
) ) > 0 && udidLen
== 6 )
1882 if ( local_scm_udid
!= NULL
)
1884 item
= proto_tree_add_string(opensafety_tree
, hf_oss_scm_udid_auto
, message_tvb
, 0, 0, local_scm_udid
);
1885 if ( ! packet
->scm_udid_valid
)
1886 expert_add_info(pinfo
, item
, &ei_message_id_field_mismatch
);
1889 item
= proto_tree_add_string(opensafety_tree
, hf_oss_scm_udid
, message_tvb
, 0, 0, global_scm_udid
);
1890 proto_item_set_generated(item
);
1893 item
= proto_tree_add_boolean(opensafety_tree
, hf_oss_scm_udid_valid
, message_tvb
, 0, 0, packet
->scm_udid_valid
);
1895 expert_add_info(pinfo
, item
, &ei_scmudid_invalid_preference
);
1896 proto_item_set_generated(item
);
1898 if ( packet
->msg_type
== OPENSAFETY_SSDO_MESSAGE_TYPE
|| packet
->msg_type
== OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
1900 proto_item_append_text(opensafety_item
,
1901 (packet
->msg_type
== OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
) ? ", Slim SSDO" : ", SSDO");
1902 dissect_opensafety_ssdo_message ( message_tvb
, pinfo
, opensafety_tree
, packet
, opensafety_item
);
1904 else if ( packet
->msg_type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
1906 proto_item_append_text(opensafety_item
, ", SPDO" );
1907 dissect_opensafety_spdo_message ( message_tvb
, pinfo
, opensafety_tree
, packet
, opensafety_item
);
1909 /* Now we know packet->sender, therefore we can add the info text */
1910 if ( previous_msg_id
!= packet
->msg_id
)
1912 col_append_fstr(pinfo
->cinfo
, COL_INFO
, (u_nrInPackage
> 1 ? " | %s - 0x%03X" : "%s - 0x%03X" ),
1913 val_to_str(packet
->msg_id
, opensafety_message_type_values
, "Unknown Message (0x%02X) "),
1916 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", 0x%03X", packet
->sender
);
1921 messageTypeUnknown
= true;
1922 proto_item_append_text(opensafety_item
, ", Unknown" );
1927 item
= proto_tree_add_uint(opensafety_tree
, hf_oss_length
,
1928 message_tvb
, OSS_FRAME_POS_LEN
+ packet
->frame
.subframe1
, 1,
1929 OSS_FRAME_LENGTH_T(message_tvb
, packet
->frame
.subframe1
));
1930 if ( messageTypeUnknown
)
1932 expert_add_info(pinfo
, item
, &ei_message_unknown_type
);
1936 crcValid
= dissect_opensafety_checksum ( message_tvb
, pinfo
, opensafety_tree
, packet
);
1939 /* with SNMT's we can check if the ID's for the frames match. Rare randomized packages do have
1940 * an issue, where an frame 1 can be valid. The id's for both frames must differ, as well as
1941 * the addresses, but addresses won't be checked yet, as there are issues with SDN xored on it. */
1942 if ( crcValid
&& packet
->msg_type
== OPENSAFETY_SNMT_MESSAGE_TYPE
)
1944 if ( OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe1
) != OSS_FRAME_ID_T(message_tvb
, packet
->frame
.subframe2
) )
1945 expert_add_info(pinfo
, opensafety_item
, &ei_crc_frame_1_valid_frame2_invalid
);
1951 static const char* opensafety_conv_get_filter_type(conv_item_t
* conv
, conv_filter_type_e filter
)
1953 if (filter
== CONV_FT_SRC_ADDRESS
) {
1954 if (conv
->src_address
.type
== AT_NUMERIC
)
1955 return "opensafety.msg.sender";
1958 if (filter
== CONV_FT_DST_ADDRESS
) {
1959 if (conv
->dst_address
.type
== AT_NUMERIC
)
1960 return "opensafety.msg.receiver";
1963 if (filter
== CONV_FT_ANY_ADDRESS
) {
1964 if (conv
->src_address
.type
== AT_NUMERIC
&& conv
->dst_address
.type
== AT_NUMERIC
)
1965 return "opensafety.msg.node";
1968 return CONV_FILTER_INVALID
;
1971 static ct_dissector_info_t opensafety_ct_dissector_info
= {&opensafety_conv_get_filter_type
};
1973 static const char* opensafety_get_filter_type(endpoint_item_t
* endpoint
, conv_filter_type_e filter
)
1975 if (endpoint
->myaddress
.type
== AT_NUMERIC
) {
1976 if (filter
== CONV_FT_ANY_ADDRESS
)
1977 return "opensafety.msg.node";
1978 else if (filter
== CONV_FT_SRC_ADDRESS
)
1979 return "opensafety.msg.sender";
1980 else if (filter
== CONV_FT_DST_ADDRESS
)
1981 return "opensafety.msg.receiver";
1984 return CONV_FILTER_INVALID
;
1987 static et_dissector_info_t opensafety_dissector_info
= {&opensafety_get_filter_type
};
1989 static tap_packet_status
1990 opensafety_conversation_packet(void *pct
, packet_info
*pinfo
,
1991 epan_dissect_t
*edt _U_
, const void *vip
, tap_flags_t flags
)
1993 address
*src
= wmem_new0(pinfo
->pool
, address
);
1994 address
*dst
= wmem_new0(pinfo
->pool
, address
);
1995 conv_hash_t
*hash
= (conv_hash_t
*) pct
;
1996 const opensafety_packet_info
*osinfo
= (const opensafety_packet_info
*)vip
;
1997 uint16_t receiver
= GUINT16_FROM_LE(osinfo
->receiver
);
1998 if (osinfo
->msg_type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
1999 receiver
= OSS_BROADCAST_ADDRESS
;
2000 uint16_t sender
= GUINT16_FROM_LE(osinfo
->sender
);
2002 hash
->flags
= flags
;
2004 alloc_address_wmem(pinfo
->pool
, src
, AT_NUMERIC
, (int) sizeof(uint16_t), &sender
);
2005 alloc_address_wmem(pinfo
->pool
, dst
, AT_NUMERIC
, (int) sizeof(uint16_t), &receiver
);
2007 add_conversation_table_data(hash
, src
, dst
, 0, 0, 1, osinfo
->msg_len
, &pinfo
->rel_ts
, &pinfo
->abs_ts
,
2008 &opensafety_ct_dissector_info
, CONVERSATION_NONE
);
2010 return TAP_PACKET_REDRAW
;
2013 static tap_packet_status
2014 opensafety_endpoint_packet(void *pit
, packet_info
*pinfo
,
2015 epan_dissect_t
*edt _U_
, const void *vip
, tap_flags_t flags
)
2017 address
*src
= wmem_new0(pinfo
->pool
, address
);
2018 address
*dst
= wmem_new0(pinfo
->pool
, address
);
2019 conv_hash_t
*hash
= (conv_hash_t
*) pit
;
2020 const opensafety_packet_info
*osinfo
= (const opensafety_packet_info
*)vip
;
2021 uint16_t receiver
= GUINT16_FROM_LE(osinfo
->receiver
);
2022 if (osinfo
->msg_type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
2023 receiver
= OSS_BROADCAST_ADDRESS
;
2024 uint16_t sender
= GUINT16_FROM_LE(osinfo
->sender
);
2026 hash
->flags
= flags
;
2028 alloc_address_wmem(pinfo
->pool
, src
, AT_NUMERIC
, (int) sizeof(uint16_t), &sender
);
2029 alloc_address_wmem(pinfo
->pool
, dst
, AT_NUMERIC
, (int) sizeof(uint16_t), &receiver
);
2031 add_endpoint_table_data(hash
, src
, 0, true, 1, osinfo
->msg_len
, &opensafety_dissector_info
, ENDPOINT_NONE
);
2032 add_endpoint_table_data(hash
, dst
, 0, false, 1, osinfo
->msg_len
, &opensafety_dissector_info
, ENDPOINT_NONE
);
2034 return TAP_PACKET_REDRAW
;
2038 opensafety_package_dissector(const char *protocolName
, const char *sub_diss_handle
,
2039 bool b_frame2First
, bool do_byte_swap
, uint8_t force_nr_in_package
,
2040 tvbuff_t
*given_tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint8_t transporttype
)
2042 tvbuff_t
*next_tvb
= NULL
, *gap_tvb
= NULL
, *message_tvb
= NULL
;
2043 unsigned length
, len
, frameOffset
, frameLength
, nodeAddress
, gapStart
;
2045 bool handled
, dissectorCalled
, call_sub_dissector
, markAsMalformed
;
2046 uint8_t type
, found
, i
, tempByte
, previous_msg_id
;
2047 uint16_t frameStart1
, frameStart2
, byte_offset
;
2049 dissector_handle_t protocol_dissector
= NULL
;
2050 proto_item
*opensafety_item
;
2051 proto_tree
*opensafety_tree
;
2053 opensafety_packet_info
*packet
= NULL
;
2056 dissectorCalled
= false;
2057 call_sub_dissector
= false;
2058 markAsMalformed
= false;
2059 previous_msg_id
= 0;
2061 /* registering frame end routine, to prevent a malformed dissection preventing
2062 * further dissector calls (see bug #6950) */
2063 register_frame_end_routine(pinfo
, reset_dissector
);
2065 length
= tvb_reported_length(given_tvb
);
2066 /* Minimum package length is 11 */
2067 if ( length
< OSS_MINIMUM_LENGTH
)
2070 /* Determine dissector handle for sub-dissection */
2071 if ( strlen( sub_diss_handle
) > 0 )
2073 call_sub_dissector
= true;
2074 protocol_dissector
= find_dissector ( sub_diss_handle
);
2075 if ( protocol_dissector
== NULL
)
2076 protocol_dissector
= data_dissector
;
2079 reported_len
= tvb_reported_length_remaining(given_tvb
, 0);
2081 /* This will swap the bytes according to MBTCP encoding */
2082 if ( do_byte_swap
== true && global_mbtcp_big_endian
== true )
2084 /* Because of padding bytes at the end of the frame, tvb_memdup could lead
2085 * to a "openSAFETY truncated" message. By ensuring, that we have enough
2086 * bytes to copy, this will be prevented. */
2087 if ( ! tvb_bytes_exist ( given_tvb
, 0, length
) )
2090 swbytes
= (uint8_t *) tvb_memdup( pinfo
->pool
, given_tvb
, 0, length
);
2092 /* Wordswapping for modbus detection */
2093 /* Only a even number of bytes can be swapped */
2095 for ( i
= 0; i
< len
; i
++ )
2097 tempByte
= swbytes
[ 2 * i
]; swbytes
[ 2 * i
] = swbytes
[ 2 * i
+ 1 ]; swbytes
[ 2 * i
+ 1 ] = tempByte
;
2100 message_tvb
= tvb_new_real_data(swbytes
, length
, reported_len
);
2102 message_tvb
= given_tvb
;
2109 /* Counter to determine gaps between openSAFETY packages */
2112 while ( frameOffset
< length
)
2114 /* Reset the next_tvb buffer */
2117 /* Smallest possible frame size is 11, but this check must ensure, that even the last frame
2118 * will get considered, which leads us with 10, as the first byte checked is the second one */
2119 if ( tvb_captured_length_remaining(message_tvb
, frameOffset
) < ( OSS_MINIMUM_LENGTH
- 1 ) )
2122 /* Resetting packet, to ensure, that findSafetyFrame starts with a fresh frame.
2123 * As only packet_scope is used, this will not pollute memory too much and get's
2124 * cleared with the next packet anyway */
2125 packet
= wmem_new0(pinfo
->pool
, opensafety_packet_info
);
2127 /* Finding the start of the first possible safety frame */
2128 if ( findSafetyFrame(pinfo
, message_tvb
, frameOffset
, b_frame2First
, &frameOffset
, &frameLength
, packet
) )
2130 /* if packet msg_id is not null, it still might be an incorrect frame, as there is no validity
2131 * check in findSafetyFrame for the msg id (this happens later in this routine)
2132 * frameLength is calculated/read directly from the dissected data. If frameLength and frameOffset together
2133 * are bigger than the reported length, the package is not really an openSAFETY package */
2134 if ( packet
->msg_id
== 0 || ( frameOffset
+ frameLength
) > (unsigned)reported_len
)
2139 byte_offset
= ( b_frame2First
? 0 : frameOffset
);
2140 /* We determine a possible position for frame 1 and frame 2 */
2141 if ( b_frame2First
)
2143 frameStart1
= findFrame1Position (pinfo
, message_tvb
, byte_offset
, frameLength
, false );
2149 frameStart2
= ((OSS_FRAME_LENGTH_T(message_tvb
, byte_offset
+ frameStart1
) - 1) +
2150 (OSS_FRAME_LENGTH_T(message_tvb
, byte_offset
+ frameStart1
) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8
? OSS_SLIM_FRAME2_WITH_CRC16
: OSS_SLIM_FRAME2_WITH_CRC8
));
2153 /* If both frame starts are equal, something went wrong. In which case, we retract the found entry, and
2154 * also increase the search offset, just doing a continue will result in an infinite loop. */
2155 if (frameStart1
== frameStart2
)
2158 frameOffset
+= frameLength
;
2162 /* We determine the possible type, and return false, if there could not be one */
2163 packet
->msg_id
= OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart1
);
2164 if ( ( packet
->msg_id
& OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
2165 type
= OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
;
2166 else if ( ( packet
->msg_id
& OPENSAFETY_SSDO_MESSAGE_TYPE
) == OPENSAFETY_SSDO_MESSAGE_TYPE
)
2167 type
= OPENSAFETY_SSDO_MESSAGE_TYPE
;
2168 else if ( ( packet
->msg_id
& OPENSAFETY_SPDO_MESSAGE_TYPE
) == OPENSAFETY_SPDO_MESSAGE_TYPE
)
2169 type
= OPENSAFETY_SPDO_MESSAGE_TYPE
;
2170 else if ( ( packet
->msg_id
& OPENSAFETY_SNMT_MESSAGE_TYPE
) == OPENSAFETY_SNMT_MESSAGE_TYPE
)
2171 type
= OPENSAFETY_SNMT_MESSAGE_TYPE
;
2174 /* This is an invalid openSAFETY package, but it could be an undetected slim ssdo message. This specific error
2175 * will only occur, if findFrame1Position is in play. So we search once more, but this time calculating the CRC.
2176 * The reason for the second run is, that calculating the CRC is time consuming. */
2177 if ( b_frame2First
)
2179 /* Now let's check again, but this time calculate the CRC */
2180 frameStart1
= findFrame1Position(pinfo
, message_tvb
, ( b_frame2First
? 0 : frameOffset
), frameLength
, true );
2183 packet
->msg_id
= OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart1
);
2184 if ( ( packet
->msg_id
& OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
2185 type
= OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
;
2186 else if ( ( packet
->msg_id
& OPENSAFETY_SSDO_MESSAGE_TYPE
) == OPENSAFETY_SSDO_MESSAGE_TYPE
)
2187 type
= OPENSAFETY_SSDO_MESSAGE_TYPE
;
2188 else if ( ( packet
->msg_id
& OPENSAFETY_SPDO_MESSAGE_TYPE
) == OPENSAFETY_SPDO_MESSAGE_TYPE
)
2189 type
= OPENSAFETY_SPDO_MESSAGE_TYPE
;
2190 else if ( ( packet
->msg_id
& OPENSAFETY_SNMT_MESSAGE_TYPE
) == OPENSAFETY_SNMT_MESSAGE_TYPE
)
2191 type
= OPENSAFETY_SNMT_MESSAGE_TYPE
;
2193 /* Skip this frame. We cannot continue without
2194 advancing frameOffset - just doing a continue
2195 will result in an infinite loop. Advancing with 1 will
2196 lead to infinite loop, advancing with frameLength might miss
2203 /* As stated above, you cannot just continue
2204 without advancing frameOffset. Advancing with 1 will
2205 lead to infinite loop, advancing with frameLength might miss
2213 /* Sorting messages for transporttype */
2214 if ( global_classify_transport
&& transporttype
!= OPENSAFETY_ANY_TRANSPORT
)
2216 /* Cyclic data is transported via SPDOs and acyclic is transported via SNMT, SSDO. Everything
2217 * else is misclassification */
2218 if ( ( transporttype
== OPENSAFETY_ACYCLIC_DATA
&& type
== OPENSAFETY_SPDO_MESSAGE_TYPE
) ||
2219 ( transporttype
== OPENSAFETY_CYCLIC_DATA
&& type
!= OPENSAFETY_SPDO_MESSAGE_TYPE
) )
2227 /* Some faulty packages do indeed have a valid first frame, but the second is
2228 * invalid. These checks should prevent most faulty detections */
2229 if ( type
!= OPENSAFETY_SPDO_MESSAGE_TYPE
)
2231 /* Is the given type at least known? */
2233 try_val_to_str_idx(OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart1
), opensafety_message_type_values
, &idx
);
2234 /* Unknown Frame Type */
2241 /* Frame IDs do not match */
2242 else if ( type
== OPENSAFETY_SNMT_MESSAGE_TYPE
&&
2243 (OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart1
) != OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart2
)) )
2251 /* If this package is not valid, the next step, which normally occurs in unxorFrame will lead to a
2252 * frameLength bigger than the maximum data size. This is an indicator, that the package in general
2253 * is fault, and therefore we return false. Increasing the frameOffset will lead to out-of-bounds
2254 * for tvb_* functions. And frameLength errors are misidentified packages most of the times anyway */
2255 if ( ( (int)frameLength
- (int)( frameStart2
> frameStart1
? frameStart2
: frameLength
- frameStart1
) ) < 0 )
2258 /* Some SPDO based sanity checks, still a lot of faulty SPDOs remain, because they
2259 * cannot be filtered, without throwing out too many positives. */
2260 if ( type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
2262 /* Checking if there is a node address set, or the package is invalid. Some PRes
2263 * messages in EPL may double as valid subframes 1. If the nodeAddress is out of
2264 * range, the package is marked as malformed */
2265 nodeAddress
= OSS_FRAME_ADDR_T(message_tvb
, byte_offset
+ frameStart1
);
2266 if ( nodeAddress
== 0 || nodeAddress
> 1024 ) {
2267 markAsMalformed
= true;
2270 /* SPDO Reserved is invalid, therefore all packages using this ID can be discarded */
2271 if ( OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart1
) == OPENSAFETY_MSG_SPDO_RESERVED
)
2279 /* Filter node list */
2280 int addr
= OSS_FRAME_ADDR_T(message_tvb
, byte_offset
+ frameStart1
);
2281 if ( global_filter_list
&& wmem_list_count ( global_filter_list
) > 0 )
2283 bool found_in_list
= wmem_list_find(global_filter_list
, GINT_TO_POINTER( addr
)) ? true : false;
2285 if ( ( ! global_show_only_node_in_filter
&& found_in_list
) ||
2286 ( global_show_only_node_in_filter
&& ! found_in_list
) )
2288 opensafety_item
= proto_tree_add_item(tree
, proto_opensafety
, message_tvb
, frameOffset
, frameLength
, ENC_NA
);
2289 proto_item_append_text(opensafety_item
, ", Filtered Node: 0x%03X (%d)", addr
, addr
);
2296 /* From here on, the package should be correct. Even if it is not correct, it will be dissected
2297 * anyway and marked as malformed. Therefore it can be assumed, that a gap will end here.
2299 if ( global_display_intergap_data
== true && gapStart
!= frameOffset
)
2301 /* Storing the gap data in subset, and calling the data dissector to display it */
2302 gap_tvb
= tvb_new_subset_length_caplen(message_tvb
, gapStart
, (frameOffset
- gapStart
), reported_len
);
2303 call_dissector(data_dissector
, gap_tvb
, pinfo
, tree
);
2305 /* Setting the gap to the next offset */
2306 gapStart
= frameOffset
+ frameLength
;
2308 /* Adding second data source */
2309 next_tvb
= tvb_new_subset_length_caplen ( message_tvb
, frameOffset
, frameLength
, reported_len
);
2311 /* Adding a visual aid to the dissector tree */
2312 add_new_data_source(pinfo
, next_tvb
, "openSAFETY Frame");
2314 /* A new subtype for package dissection will need to set the actual nr. for the whole dissected package */
2315 if ( force_nr_in_package
> 0 )
2317 found
= force_nr_in_package
+ 1;
2318 dissectorCalled
= true;
2319 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, protocolName
);
2322 if ( ! dissectorCalled
)
2324 if ( call_sub_dissector
)
2325 call_dissector(protocol_dissector
, message_tvb
, pinfo
, tree
);
2326 dissectorCalled
= true;
2328 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, protocolName
);
2329 col_clear(pinfo
->cinfo
, COL_INFO
);
2332 /* if the tree is NULL, we are called for the overview, otherwise for the
2333 more detailed view of the package */
2336 /* create the opensafety protocol tree */
2337 opensafety_item
= proto_tree_add_item(tree
, proto_opensafety
, message_tvb
, frameOffset
, frameLength
, ENC_NA
);
2338 opensafety_tree
= proto_item_add_subtree(opensafety_item
, ett_opensafety
);
2340 opensafety_item
= NULL
;
2341 opensafety_tree
= NULL
;
2344 /* Setting type to packet_info */
2345 packet
->msg_type
= type
;
2347 packet
->frame
.frame_tvb
= next_tvb
;
2348 packet
->frame
.byte_offset
= frameOffset
+ tvb_raw_offset(message_tvb
);
2349 packet
->frame
.subframe1
= frameStart1
;
2350 packet
->frame
.subframe2
= frameStart2
;
2351 packet
->frame
.length
= frameLength
;
2352 packet
->frame
.malformed
= false;
2354 /* Clearing connection valid bit */
2355 if ( packet
->msg_type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
2356 packet
->msg_id
= packet
->msg_id
& 0xF8;
2358 if ( dissect_opensafety_message(packet
, next_tvb
, pinfo
, opensafety_item
, opensafety_tree
, found
, previous_msg_id
) != true )
2359 markAsMalformed
= true;
2361 previous_msg_id
= packet
->msg_id
;
2363 if ( markAsMalformed
)
2365 packet
->frame
.malformed
= true;
2366 if ( OSS_FRAME_ADDR_T(message_tvb
, byte_offset
+ frameStart1
) > 1024 )
2367 expert_add_info(pinfo
, opensafety_item
, &ei_message_spdo_address_invalid
);
2370 tap_queue_packet(opensafety_tap
, pinfo
, packet
);
2372 /* Something is being displayed, therefore this dissector returns true */
2378 /* findSafetyFrame starts at frameOffset with the search for the next position. But the
2379 * offset is assumed to be the ID, which can lead to scenarios, where the CRC of a previous
2380 * detected frame is assumed to be the addr of the next one. +1 prevents such a scenario.
2381 * It must be checked, if the resulting frameOffset does not scratch the max length. It
2382 * cannot exceed by adding just frameLength, as this value is a result of the heuristic, and
2383 * therefore must be within the correct length, but it can exceed if +1 is added unchecked. */
2384 frameOffset
+= frameLength
;
2385 if ( tvb_captured_length_remaining(message_tvb
, frameOffset
) > 0 )
2389 if ( handled
== true )
2391 /* There might be some undissected data at the end of the frame (e.g. SercosIII) */
2392 if ( frameOffset
< length
&& global_display_intergap_data
== true && gapStart
!= frameOffset
)
2394 /* Storing the gap data in subset, and calling the data dissector to display it */
2395 gap_tvb
= tvb_new_subset_length_caplen(message_tvb
, gapStart
, (length
- gapStart
), reported_len
);
2396 call_dissector(data_dissector
, gap_tvb
, pinfo
, tree
);
2400 return ( handled
? TRUE
: FALSE
);
2404 dissect_opensafety_epl(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2406 bool result
= false;
2407 proto_tree
*epl_tree
= NULL
;
2408 uint8_t epl_msgtype
= 0;
2410 /* We will call the epl dissector by using call_dissector(). The epl dissector will then call
2411 * the heuristic openSAFETY dissector again. By setting this information, we prevent a dissector
2413 if ( bDissector_Called_Once_Before
== false )
2415 bDissector_Called_Once_Before
= true;
2417 /* Set the tree up, until it is par with the top-level */
2419 while ( epl_tree
!= NULL
&& epl_tree
->parent
!= NULL
)
2420 epl_tree
= epl_tree
->parent
;
2422 /* Ordering message type to traffic types */
2423 if ( *((uint8_t*)data
) == 0x03 || *((uint8_t*)data
) == 0x04 )
2424 epl_msgtype
= OPENSAFETY_CYCLIC_DATA
;
2426 epl_msgtype
= OPENSAFETY_ACYCLIC_DATA
;
2428 /* We check if we have a asynchronous message, or a synchronous message. In case of
2429 * asynchronous messages, SPDO packages are not valid. */
2431 result
= (bool)opensafety_package_dissector("openSAFETY/Powerlink", "",
2432 false, false, 0, message_tvb
, pinfo
, epl_tree
, epl_msgtype
);
2434 bDissector_Called_Once_Before
= false;
2441 dissect_opensafety_siii(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2443 bool result
= false;
2447 /* The UDP dissection is not done by a heuristic, but rather by a normal dissector. But
2448 * the customer may not expect, that if (s)he disables the SercosIII dissector, that the
2449 * SercosIII UDP packages get still dissected. This will disable them as well. */
2450 if ( ! heuristic_siii_dissection_enabled
)
2453 /* We will call the SercosIII dissector by using call_dissector(). The SercosIII dissector will
2454 * then call the heuristic openSAFETY dissector again. By setting this information, we prevent
2455 * a dissector loop. */
2456 if ( bDissector_Called_Once_Before
== false )
2458 udp
= pinfo
->destport
== OPENSAFETY_UDP_PORT_SIII
;
2460 bDissector_Called_Once_Before
= true;
2461 /* No frames can be sent in AT messages, therefore those get filtered right away */
2462 firstByte
= ( tvb_get_uint8(message_tvb
, 0) << 1 );
2463 if ( udp
|| ( firstByte
& 0x40 ) == 0x40 )
2465 result
= opensafety_package_dissector( "openSAFETY/SercosIII",
2466 udp
? "" : "sercosiii",
2467 false, false, 0, message_tvb
, pinfo
, tree
,
2468 udp
? OPENSAFETY_ACYCLIC_DATA
: OPENSAFETY_CYCLIC_DATA
);
2470 bDissector_Called_Once_Before
= false;
2477 dissect_opensafety_siii_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2479 return (bool)dissect_opensafety_siii(tvb
, pinfo
, tree
, data
);
2483 dissect_opensafety_pn_io(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2485 gboolean result
= FALSE
;
2487 /* We will call the pn_io dissector by using call_dissector(). The epl dissector will then call
2488 * the heuristic openSAFETY dissector again. By setting this information, we prevent a dissector
2490 if ( bDissector_Called_Once_Before
== false )
2492 bDissector_Called_Once_Before
= true;
2493 result
= opensafety_package_dissector("openSAFETY/Profinet IO", "pn_io",
2494 false, false, 0, message_tvb
, pinfo
, tree
, OPENSAFETY_ANY_TRANSPORT
);
2495 bDissector_Called_Once_Before
= false;
2502 dissect_opensafety_pn_io_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2504 return (bool)dissect_opensafety_pn_io(tvb
, pinfo
, tree
, data
);
2509 dissect_opensafety_mbtcp(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2511 if ( ! global_enable_mbtcp
)
2514 /* When Modbus/TCP gets dissected, openSAFETY would be sorted as a child protocol. Although,
2515 * this behaviour is technically correct, it differs from other implemented IEM protocol handlers.
2516 * Therefore, the openSAFETY frame gets put one up, if the parent is not NULL */
2517 return opensafety_package_dissector("openSAFETY/Modbus TCP", "", false, true, 0,
2518 message_tvb
, pinfo
, ( ((tree
!= NULL
) && (tree
->parent
!= NULL
)) ? tree
->parent
: tree
),
2519 OPENSAFETY_ANY_TRANSPORT
);
2523 opensafety_udp_transport_dissector(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2525 proto_item
*ti
= NULL
;
2526 proto_tree
*transport_tree
= NULL
;
2528 tvbuff_t
*os_tvb
= 0;
2530 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "openSAFETY over UDP");
2531 col_clear(pinfo
->cinfo
, COL_INFO
);
2533 ti
= proto_tree_add_item(tree
, proto_oss_udp_transport
, message_tvb
, 0, -1, ENC_NA
);
2534 transport_tree
= proto_item_add_subtree(ti
, ett_opensafety
);
2536 proto_tree_add_item(transport_tree
, hf_oss_udp_transport_version
, message_tvb
, 0, 1, ENC_BIG_ENDIAN
);
2537 proto_tree_add_item(transport_tree
, hf_oss_udp_transport_flags_type
, message_tvb
, 1, 1, ENC_BIG_ENDIAN
);
2538 proto_tree_add_item(transport_tree
, hf_oss_udp_transport_counter
, message_tvb
, 2, 2, ENC_LITTLE_ENDIAN
);
2540 proto_tree_add_item(transport_tree
, hf_oss_udp_transport_sender
, message_tvb
, 4, 4, ENC_LITTLE_ENDIAN
);
2541 proto_tree_add_item(transport_tree
, hf_oss_udp_transport_datapoint
, message_tvb
, 8, 2, ENC_LITTLE_ENDIAN
);
2542 proto_tree_add_item(transport_tree
, hf_oss_udp_transport_length
, message_tvb
, 10, 2, ENC_LITTLE_ENDIAN
);
2545 os_tvb
= tvb_new_subset_remaining(message_tvb
, offset
);
2547 if ( ! opensafety_package_dissector("openSAFETY/UDP", "", false,
2548 false, 0, os_tvb
, pinfo
, tree
, OPENSAFETY_ANY_TRANSPORT
) )
2549 call_dissector(find_dissector("data"), os_tvb
, pinfo
, transport_tree
);
2555 dissect_opensafety_udpdata(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2557 gboolean result
= FALSE
;
2558 static uint32_t frameNum
= 0;
2559 static uint32_t frameIdx
= 0;
2561 bool frameFound
= false;
2562 unsigned frameOffset
= 0;
2563 unsigned frameLength
= 0;
2565 if ( pinfo
->destport
== OPENSAFETY_UDP_PORT_SIII
)
2566 return dissect_opensafety_siii(message_tvb
, pinfo
, tree
, data
);
2568 if ( ! global_enable_udp
)
2571 /* An openSAFETY frame has at least OSS_MINIMUM_LENGTH bytes */
2572 if ( tvb_captured_length ( message_tvb
) < OSS_MINIMUM_LENGTH
)
2575 /* More than one openSAFETY package could be transported in the same frame,
2576 * in such a case, we need to establish the number of packages inside the frame */
2577 if ( pinfo
->num
!= frameNum
)
2580 frameNum
= pinfo
->num
;
2583 /* check for openSAFETY frame at beginning of data */
2585 frameFound
= findSafetyFrame(pinfo
, message_tvb
, 0, global_udp_frame2_first
, &frameOffset
, &frameLength
, NULL
);
2586 if ( ! frameFound
|| ( frameOffset
>= 11 ) )
2588 dissector_handle_t udp_transport
= find_dissector ( "opensafety_udp_transport" );
2589 if ( udp_transport
!= NULL
)
2590 call_dissector(udp_transport
, message_tvb
, pinfo
, tree
);
2591 result
= opensafety_udp_transport_dissector(message_tvb
, pinfo
, tree
);
2594 result
= opensafety_package_dissector("openSAFETY/UDP", "", global_udp_frame2_first
,
2595 false, frameIdx
, message_tvb
, pinfo
, tree
, OPENSAFETY_ACYCLIC_DATA
);
2604 apply_prefs ( void )
2606 static unsigned opensafety_udp_port_number
;
2607 static unsigned opensafety_udp_siii_port_number
;
2608 static bool opensafety_init
= false;
2610 /* It only should delete dissectors, if run for any time except the first */
2611 if ( opensafety_init
)
2613 /* Delete dissectors in preparation of a changed config setting */
2614 dissector_delete_uint ("udp.port", opensafety_udp_port_number
, opensafety_udptransport_handle
);
2615 dissector_delete_uint ("udp.port", opensafety_udp_siii_port_number
, opensafety_udpdata_handle
);
2617 opensafety_init
= true;
2619 /* Storing the port numbers locally, to being able to delete the old associations */
2620 opensafety_udp_port_number
= global_network_udp_port
;
2621 opensafety_udp_siii_port_number
= global_network_udp_port_sercosiii
;
2623 /* Default UDP only based dissector, will hand traffic to SIII dissector if needed */
2624 /* Preference names to specific to use "auto" preference */
2625 dissector_add_uint("udp.port", opensafety_udp_port_number
, opensafety_udptransport_handle
);
2626 dissector_add_uint("udp.port", opensafety_udp_siii_port_number
, opensafety_udpdata_handle
);
2630 proto_register_opensafety(void)
2632 /* Setup list of header fields */
2633 static hf_register_info hf
[] = {
2635 { "SCM UDID Configured", "opensafety.scm_udid",
2636 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2637 { &hf_oss_scm_udid_auto
,
2638 { "SCM UDID Auto Detect", "opensafety.scm_udid.auto",
2639 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2640 { &hf_oss_scm_udid_valid
,
2641 { "SCM UDID Valid", "opensafety.scm_udid.valid",
2642 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2644 { &hf_oss_byte_offset
,
2645 { "Byte Offset", "opensafety.msg.byte_offset",
2646 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2648 { "Message", "opensafety.msg.id",
2649 FT_UINT8
, BASE_HEX
, VALS(opensafety_message_type_values
), 0x0, NULL
, HFILL
} },
2650 { &hf_oss_msg_category
,
2651 { "Type", "opensafety.msg.type",
2652 FT_UINT8
, BASE_HEX
, VALS(opensafety_msg_id_values
), 0xE0, NULL
, HFILL
} },
2653 { &hf_oss_msg_direction
,
2654 { "Direction", "opensafety.msg.direction",
2655 FT_BOOLEAN
, 8, TFS(&opensafety_message_direction
), 0x04, NULL
, HFILL
} },
2657 { "Safety Node", "opensafety.msg.node",
2658 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2659 { &hf_oss_msg_network
,
2660 { "Safety Domain", "opensafety.msg.network",
2661 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2662 { &hf_oss_msg_sender
,
2663 { "SN send from", "opensafety.msg.sender",
2664 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2665 { &hf_oss_msg_receiver
,
2666 { "SN send to", "opensafety.msg.receiver",
2667 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2669 { "Length", "opensafety.length",
2670 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2672 { "CRC", "opensafety.crc.data",
2673 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2675 { &hf_oss_crc_valid
,
2676 { "Is Valid", "opensafety.crc.valid",
2677 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2679 { "CRC Type", "opensafety.crc.type",
2680 FT_UINT8
, BASE_DEC
, VALS(opensafety_frame_crc_type
), 0x0, NULL
, HFILL
} },
2681 { &hf_oss_crc2_valid
,
2682 { "Is Valid", "opensafety.crc2.valid",
2683 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2685 /* SNMT Specific fields */
2686 { &hf_oss_snmt_slave
,
2687 { "SNMT Slave", "opensafety.snmt.slave",
2688 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2689 { &hf_oss_snmt_master
,
2690 { "SNMT Master", "opensafety.snmt.master",
2691 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2693 { "SCM", "opensafety.snmt.scm",
2694 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2695 { &hf_oss_snmt_tool
,
2696 { "Tool ID", "opensafety.snmt.tool_id",
2697 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2698 { &hf_oss_snmt_udid
,
2699 { "UDID for SN", "opensafety.snmt.udid",
2700 FT_ETHER
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2701 { &hf_oss_snmt_service_id
,
2702 { "Extended Service ID", "opensafety.snmt.service_id",
2703 FT_UINT8
, BASE_HEX
, VALS(opensafety_message_service_type
), 0x0, NULL
, HFILL
} },
2704 { &hf_oss_snmt_error_group
,
2705 { "Error Group", "opensafety.snmt.error_group",
2706 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2707 { &hf_oss_snmt_error_code
,
2708 { "Error Code", "opensafety.snmt.error_code",
2709 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2710 { &hf_oss_snmt_param_type
,
2711 { "Parameter Request Type", "opensafety.snmt.parameter_type",
2712 FT_BOOLEAN
, BASE_NONE
, TFS(&opensafety_addparam_request
), 0x0, NULL
, HFILL
} },
2713 { &hf_oss_snmt_ext_addsaddr
,
2714 { "Additional SADDR", "opensafety.snmt.additional.saddr",
2715 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2716 { &hf_oss_snmt_ext_addtxspdo
,
2717 { "Additional TxSPDO", "opensafety.snmt.additional.txspdo",
2718 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2719 { &hf_oss_snmt_ext_initct
,
2720 { "Initial CT", "opensafety.snmt.initct",
2721 FT_UINT40
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2723 /* SSDO Specific fields */
2724 { &hf_oss_ssdo_server
,
2725 { "SSDO Server", "opensafety.ssdo.master",
2726 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2727 { &hf_oss_ssdo_client
,
2728 { "SSDO Client", "opensafety.ssdo.client",
2729 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2730 { &hf_oss_ssdo_sano
,
2731 { "SOD Access Request Number", "opensafety.ssdo.sano",
2732 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2733 { &hf_oss_ssdo_sacmd
,
2734 { "SOD Access Command", "opensafety.ssdo.sacmd",
2735 FT_UINT8
, BASE_HEX
, VALS(opensafety_ssdo_sacmd_values
), 0x0, NULL
, HFILL
} },
2736 { &hf_oss_ssdo_sod_index
,
2737 { "SOD Index", "opensafety.ssdo.sodentry.index",
2738 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2739 { &hf_oss_ssdo_sod_subindex
,
2740 { "SOD Sub Index", "opensafety.ssdo.sodentry.subindex",
2741 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2742 { &hf_oss_ssdo_payload
,
2743 { "SOD Payload", "opensafety.ssdo.payload",
2744 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2745 { &hf_oss_ssdo_payload_size
,
2746 { "SOD Payload Size", "opensafety.ssdo.payloadsize",
2747 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2748 { &hf_oss_ssdo_sodentry_size
,
2749 { "SOD Entry Size", "opensafety.ssdo.sodentry.size",
2750 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2751 { &hf_oss_ssdo_sodentry_data
,
2752 { "SOD Data", "opensafety.ssdo.sodentry.data",
2753 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2754 { &hf_oss_sod_par_timestamp
,
2755 { "Parameter Timestamp", "opensafety.sod.parameter.timestamp",
2756 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2757 { &hf_oss_sod_par_checksum
,
2758 { "Parameter Checksum", "opensafety.sod.parameter.checksum",
2759 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2761 { &hf_oss_ssdo_sodmapping
,
2762 { "Mapping entry", "opensafety.sod.mapping",
2763 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2764 { &hf_oss_ssdo_sodmapping_bits
,
2765 { "Mapping size", "opensafety.sod.mapping.bits",
2766 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2768 { &hf_oss_ssdo_extpar_parset
,
2769 { "Additional Parameter Set", "opensafety.ssdo.extpar.setnr",
2770 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2771 { &hf_oss_ssdo_extpar_version
,
2772 { "Parameter Set Version", "opensafety.ssdo.extpar.version",
2773 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2774 { &hf_oss_ssdo_extpar_saddr
,
2775 { "Parameter Set for SADDR", "opensafety.ssdo.extpar.saddr",
2776 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2777 { &hf_oss_ssdo_extpar_length
,
2778 { "Parameter Set Length", "opensafety.ssdo.extpar.length",
2779 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2780 { &hf_oss_ssdo_extpar_crc
,
2781 { "Parameter Set CRC", "opensafety.ssdo.extpar.crc",
2782 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2783 { &hf_oss_ssdo_extpar_tstamp
,
2784 { "Timestamp", "opensafety.ssdo.extpar.timestamp",
2785 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2786 { &hf_oss_ssdo_extpar_data
,
2787 { "Ext. Parameter Data", "opensafety.ssdo.extpar.data",
2788 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2789 { &hf_oss_ssdo_extpar
,
2790 { "Ext. Parameter", "opensafety.ssdo.extpar",
2791 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
2794 {"Message fragments", "opensafety.ssdo.fragments",
2795 FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2797 {"Message fragment", "opensafety.ssdo.fragment",
2798 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2799 {&hf_oss_fragment_overlap
,
2800 {"Message fragment overlap", "opensafety.ssdo.fragment.overlap",
2801 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2802 {&hf_oss_fragment_overlap_conflicts
,
2803 {"Message fragment overlapping with conflicting data",
2804 "opensafety.ssdo.fragment.overlap.conflicts",
2805 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2806 {&hf_oss_fragment_multiple_tails
,
2807 {"Message has multiple tail fragments", "opensafety.ssdo.fragment.multiple_tails",
2808 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2809 {&hf_oss_fragment_too_long_fragment
,
2810 {"Message fragment too long", "opensafety.ssdo.fragment.too_long_fragment",
2811 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2812 {&hf_oss_fragment_error
,
2813 {"Message defragmentation error", "opensafety.ssdo.fragment.error",
2814 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2815 {&hf_oss_fragment_count
,
2816 {"Message fragment count", "opensafety.ssdo.fragment.count",
2817 FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
2818 {&hf_oss_reassembled_in
,
2819 {"Reassembled in", "opensafety.ssdo.reassembled.in",
2820 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2821 {&hf_oss_reassembled_length
,
2822 {"Reassembled length", "opensafety.ssdo.reassembled.length",
2823 FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
2824 {&hf_oss_reassembled_data
,
2825 {"Reassembled Data", "opensafety.ssdo.reassembled.data",
2826 FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
2828 { &hf_oss_ssdo_abort_code
,
2829 { "Abort Code", "opensafety.ssdo.abortcode",
2830 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2832 { &hf_oss_ssdo_preload_error
,
2833 { "Wrong/missing segment", "opensafety.ssdo.preload.error",
2834 FT_BOOLEAN
, 8, NULL
, 0x30, NULL
, HFILL
} },
2835 { &hf_oss_ssdo_preload_queue
,
2836 { "Preload Queue Size", "opensafety.ssdo.preload.queuesize",
2837 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2839 /* SSDO SACmd specific fields */
2840 { &hf_oss_ssdo_sacmd_access_type
,
2841 { "Access Direction", "opensafety.ssdo.sacmd.access",
2842 FT_BOOLEAN
, 8, TFS(&opensafety_sacmd_acc
), OPENSAFETY_SSDO_SACMD_ACC
, NULL
, HFILL
} },
2843 { &hf_oss_ssdo_sacmd_preload
,
2844 { "Preload Transfer", "opensafety.ssdo.sacmd.preload",
2845 FT_BOOLEAN
, 8, TFS(&tfs_enabled_disabled
), OPENSAFETY_SSDO_SACMD_PRLD
, NULL
, HFILL
} },
2846 { &hf_oss_ssdo_sacmd_abort_transfer
,
2847 { "Abort Transfer", "opensafety.ssdo.sacmd.abort_transfer",
2848 FT_BOOLEAN
, 8, TFS(&opensafety_sacmd_abrt
), OPENSAFETY_SSDO_SACMD_ABRT
, NULL
, HFILL
} },
2849 { &hf_oss_ssdo_sacmd_segmentation
,
2850 { "Segmentation", "opensafety.ssdo.sacmd.segmentation",
2851 FT_BOOLEAN
, 8, TFS(&opensafety_sacmd_seg
), OPENSAFETY_SSDO_SACMD_SEG
, NULL
, HFILL
} },
2852 { &hf_oss_ssdo_sacmd_toggle
,
2853 { "Toggle Bit", "opensafety.ssdo.sacmd.toggle",
2854 FT_BOOLEAN
, 8, TFS(&tfs_on_off
), OPENSAFETY_SSDO_SACMD_TGL
, NULL
, HFILL
} },
2855 { &hf_oss_ssdo_sacmd_initiate
,
2856 { "Initiate Transfer", "opensafety.ssdo.sacmd.initiate",
2857 FT_BOOLEAN
, 8, TFS(&opensafety_sacmd_ini
), OPENSAFETY_SSDO_SACMD_INI
, NULL
, HFILL
} },
2858 { &hf_oss_ssdo_sacmd_end_segment
,
2859 { "End Segment", "opensafety.ssdo.sacmd.end_segment",
2860 FT_BOOLEAN
, 8, TFS(&opensafety_sacmd_ensg
), OPENSAFETY_SSDO_SACMD_ENSG
, NULL
, HFILL
} },
2862 { &hf_oss_ssdo_sacmd_reserved
,
2863 { "Reserved", "opensafety.ssdo.sacmd.reserved",
2864 FT_BOOLEAN
, 8, TFS(&opensafety_sacmd_res
), OPENSAFETY_SSDO_SACMD_RES
, NULL
, HFILL
} },
2867 /* SPDO Specific fields */
2868 { &hf_oss_spdo_connection_valid
,
2869 { "Connection Valid Bit", "opensafety.spdo.connection_valid",
2870 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x04, NULL
, HFILL
} },
2871 { &hf_oss_spdo_direction
,
2872 { "Send to", "opensafety.spdo.direction",
2873 FT_BOOLEAN
, 8, TFS(&opensafety_spdo_direction
), 0x08, NULL
, HFILL
} },
2875 { "Consecutive Time", "opensafety.spdo.ct",
2876 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2877 { &hf_oss_spdo_ct_40bit
,
2878 { "Consecutive Time 40bit", "opensafety.spdo.ct40bit",
2879 FT_UINT40
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2880 { &hf_oss_spdo_time_request
,
2881 { "Time Request Counter", "opensafety.spdo.time.request_counter",
2882 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2883 { &hf_oss_spdo_time_request_to
,
2884 { "Time Request from", "opensafety.spdo.time.request_from",
2885 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2886 { &hf_oss_spdo_time_request_from
,
2887 { "Time Request by", "opensafety.spdo.time.request_to",
2888 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2889 { &hf_oss_spdo_feature_flags
,
2890 { "SPDO Feature Flags", "opensafety.spdo.featureflags",
2891 FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
2892 { &hf_oss_spdo_feature_flag_40bit_available
,
2893 { "40Bit Request", "opensafety.spdo.features.40bitrequest",
2894 FT_BOOLEAN
, 8, TFS(&tfs_requested_not_requested
), (OPENSAFETY_SPDO_FEAT_40BIT_AVAIL
<< 2), NULL
, HFILL
} },
2895 { &hf_oss_spdo_feature_flag_40bit_used
,
2896 { "40Bit Counter", "opensafety.spdo.features.40bitactive",
2897 FT_BOOLEAN
, 8, TFS(&tfs_enabled_disabled
), (OPENSAFETY_SPDO_FEAT_40BIT_USED
<< 2), NULL
, HFILL
} },
2900 /* Setup list of header fields */
2901 static hf_register_info hf_oss_udp_transport
[] = {
2902 /* UDP transport specific fields */
2903 { &hf_oss_udp_transport_version
,
2904 { "Transport Version", "opensafety.udp_transport.version",
2905 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2906 { &hf_oss_udp_transport_flags_type
,
2907 { "Data Type", "opensafety.udp_transport.flags.type",
2908 FT_BOOLEAN
, 8, TFS(&tfs_udp_transport_cyclic_acyclic
), 0x01, NULL
, HFILL
} },
2909 { &hf_oss_udp_transport_counter
,
2910 { "Counter", "opensafety.udp_transport.counter",
2911 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2912 { &hf_oss_udp_transport_sender
,
2913 { "Sender ID", "opensafety.udp_transport.sender",
2914 FT_UINT32
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2915 { &hf_oss_udp_transport_datapoint
,
2916 { "Datapoint ID", "opensafety.udp_transport.datapoint",
2917 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2918 { &hf_oss_udp_transport_length
,
2919 { "Length", "opensafety.udp_transport.length",
2920 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
2924 /* Setup protocol subtree array */
2925 static int *ett
[] = {
2927 &ett_opensafety_node
,
2928 &ett_opensafety_checksum
,
2929 &ett_opensafety_snmt
,
2930 &ett_opensafety_ssdo
,
2931 &ett_opensafety_ssdo_sacmd
,
2932 &ett_opensafety_ssdo_fragment
,
2933 &ett_opensafety_ssdo_fragments
,
2934 &ett_opensafety_ssdo_payload
,
2935 &ett_opensafety_ssdo_sodentry
,
2936 &ett_opensafety_sod_mapping
,
2937 &ett_opensafety_ssdo_extpar
,
2938 &ett_opensafety_spdo
,
2939 &ett_opensafety_spdo_flags
,
2942 static int *ett_oss_udp
[] = {
2943 &ett_oss_udp_transport
,
2946 static ei_register_info ei
[] = {
2947 { &ei_crc_frame_1_invalid
,
2948 { "opensafety.crc.error.frame1_invalid", PI_PROTOCOL
, PI_ERROR
,
2949 "Frame 1 CRC invalid, Possible error in package", EXPFILL
} },
2950 { &ei_crc_frame_1_valid_frame2_invalid
,
2951 { "opensafety.crc.error.frame1_valid_frame2_invalid", PI_PROTOCOL
, PI_ERROR
,
2952 "Frame 1 is valid, frame 2 id is invalid", EXPFILL
} },
2953 { &ei_crc_slimssdo_instead_of_spdo
,
2954 { "opensafety.crc.warning.wrong_crc_for_spdo", PI_PROTOCOL
, PI_WARN
,
2955 "Frame 1 SPDO CRC is Slim SSDO CRC16 0x5935", EXPFILL
} },
2956 { &ei_crc_frame_2_invalid
,
2957 { "opensafety.crc.error.frame2_invalid", PI_PROTOCOL
, PI_ERROR
,
2958 "Frame 2 CRC invalid, Possible error in package or crc calculation", EXPFILL
} },
2959 { &ei_crc_frame_2_unknown_scm_udid
,
2960 { "opensafety.crc.error.frame2_unknown_scmudid", PI_PROTOCOL
, PI_WARN
,
2961 "Frame 2 CRC invalid, SCM UDID was not auto-detected", EXPFILL
} },
2962 { &ei_crc_frame_2_scm_udid_encoded
,
2963 { "opensafety.crc.error.crc2_scm_udid_encoded", PI_PROTOCOL
, PI_NOTE
,
2964 "Frame 2 CRC is encoded with byte 6 of SCM UDID due to payload length of 0 in frame 2 or SLIM SSDO", EXPFILL
} },
2966 { &ei_message_reassembly_size_differs_from_header
,
2967 { "opensafety.msg.warning.reassembly_size_fail", PI_PROTOCOL
, PI_WARN
,
2968 "Reassembled message size differs from size in header", EXPFILL
} },
2969 { &ei_message_unknown_type
,
2970 { "opensafety.msg.error.unknown_type", PI_MALFORMED
, PI_ERROR
,
2971 "Unknown openSAFETY message type", EXPFILL
} },
2972 { &ei_message_spdo_address_invalid
,
2973 { "opensafety.msg.error.spdo_address_invalid", PI_MALFORMED
, PI_ERROR
,
2974 "SPDO address is invalid", EXPFILL
} },
2975 { &ei_message_id_field_mismatch
,
2976 { "opensafety.msg.error.id.mismatch", PI_PROTOCOL
, PI_ERROR
,
2977 "ID for frame 2 is not the same as for frame 1", EXPFILL
} },
2979 { &ei_scmudid_autodetected
,
2980 { "opensafety.scm_udid.note.autodetected", PI_PROTOCOL
, PI_NOTE
,
2981 "Auto detected payload as SCM UDID", EXPFILL
} },
2982 { &ei_scmudid_invalid_preference
,
2983 { "opensafety.scm_udid.note.invalid_preference", PI_PROTOCOL
, PI_WARN
,
2984 "openSAFETY protocol settings are invalid! SCM UDID first octet will be assumed to be 00", EXPFILL
} },
2985 { &ei_scmudid_unknown
,
2986 { "opensafety.scm_udid.warning.assuming_first_octet", PI_PROTOCOL
, PI_WARN
,
2987 "SCM UDID unknown, assuming 00 as first UDID octet", EXPFILL
} },
2989 { &ei_payload_unknown_format
,
2990 { "opensafety.msg.warning.unknown_format", PI_PROTOCOL
, PI_WARN
,
2991 "Unknown payload format detected", EXPFILL
} },
2992 { &ei_payload_length_not_positive
,
2993 { "opensafety.msg.warning.reassembly_length_not_positive", PI_PROTOCOL
, PI_NOTE
,
2994 "Calculation for payload length yielded non-positive result", EXPFILL
} },
2996 { &ei_40bit_default_domain
,
2997 { "opensafety.msg.warning.default_domain_40bit", PI_PROTOCOL
, PI_NOTE
,
2998 "SDN is assumed with 1 to allow 40bit dissection", EXPFILL
} },
3002 module_t
*opensafety_module
, *oss_udp_module
;
3003 expert_module_t
*expert_opensafety
;
3005 /* Register the protocol name and description */
3006 proto_opensafety
= proto_register_protocol("openSAFETY", "openSAFETY", "opensafety");
3007 opensafety_module
= prefs_register_protocol(proto_opensafety
, apply_prefs
);
3008 proto_oss_udp_transport
= proto_register_protocol("openSAFETY over UDP", "openSAFETY ov. UDP", "opensafety_udp");
3009 oss_udp_module
= prefs_register_protocol(proto_oss_udp_transport
, apply_prefs
);
3011 /* Register data dissector */
3012 heur_opensafety_spdo_subdissector_list
= register_heur_dissector_list_with_description("opensafety.spdo", "openSAFETY data", proto_opensafety
);
3014 /* Required function calls to register the header fields and subtrees used */
3015 proto_register_field_array(proto_opensafety
, hf
, array_length(hf
));
3016 proto_register_subtree_array(ett
, array_length(ett
));
3017 proto_register_field_array(proto_oss_udp_transport
, hf_oss_udp_transport
, array_length(hf_oss_udp_transport
));
3018 proto_register_subtree_array(ett_oss_udp
, array_length(ett_oss_udp
));
3021 opensafety_tap
= register_tap("opensafety");
3023 expert_opensafety
= expert_register_protocol ( proto_opensafety
);
3024 expert_register_field_array ( expert_opensafety
, ei
, array_length (ei
) );
3026 /* register user preferences */
3027 prefs_register_string_preference(opensafety_module
, "scm_udid",
3028 "SCM UDID (xx:xx:xx:xx:xx:xx)",
3029 "To be able to fully dissect SSDO and SPDO packages, a valid UDID for the SCM has to be provided",
3031 prefs_register_bool_preference(opensafety_module
, "scm_udid_autoset",
3032 "Set SCM UDID if detected in stream",
3033 "Automatically assign a detected SCM UDID (by reading SNMT->SNTM_assign_UDID_SCM) and set it for the file",
3034 &global_scm_udid_autoset
);
3036 prefs_register_string_preference(opensafety_module
, "filter_nodes",
3037 "Filter openSAFETY Nodes",
3038 "A comma-separated list of nodes to be filtered during dissection",
3039 &global_filter_nodes
);
3040 prefs_register_bool_preference(opensafety_module
, "filter_show_nodes_in_filterlist",
3041 "Show nodes in filter, hide otherwise",
3042 "If set to true, only nodes in the list will be shown, otherwise they will be hidden",
3043 &global_show_only_node_in_filter
);
3045 prefs_register_uint_preference(opensafety_module
, "network_udp_port",
3046 "Port used for Generic UDP",
3047 "Port used by any UDP demo implementation to transport data", 10,
3048 &global_network_udp_port
);
3049 prefs_register_uint_preference(opensafety_module
, "network_udp_port_sercosiii",
3050 "Port used for SercosIII/UDP",
3051 "UDP port used by SercosIII to transport data", 10,
3052 &global_network_udp_port_sercosiii
);
3053 prefs_register_bool_preference(opensafety_module
, "network_udp_frame_first_sercosiii",
3054 "openSAFETY frame 2 before frame 1 (SercosIII/UDP only)",
3055 "In an SercosIII/UDP transport stream, openSAFETY frame 2 will be expected before frame 1",
3056 &global_siii_udp_frame2_first
);
3058 prefs_register_bool_preference(opensafety_module
, "network_udp_frame_first",
3059 "openSAFETY frame 2 before frame 1 (UDP only)",
3060 "In the transport stream, openSAFETY frame 2 will be expected before frame 1",
3061 &global_udp_frame2_first
);
3062 prefs_register_bool_preference(opensafety_module
, "mbtcp_big_endian",
3063 "Big Endian Word Coding (Modbus/TCP only)",
3064 "Modbus/TCP words can be transcoded either big- or little endian. Default will be little endian",
3065 &global_mbtcp_big_endian
);
3066 prefs_register_bool_preference(opensafety_module
, "debug_verbose",
3067 "openSAFETY print all dissection information",
3068 "Enables additional information in the dissection for better debugging an openSAFETY trace",
3069 &global_opensafety_debug_verbose
);
3071 prefs_register_obsolete_preference(opensafety_module
, "enable_plk");
3072 prefs_register_obsolete_preference(opensafety_module
, "enable_siii");
3073 prefs_register_obsolete_preference(opensafety_module
, "enable_pnio");
3075 prefs_register_bool_preference(opensafety_module
, "enable_udp",
3076 "Enable heuristic dissection for openSAFETY over UDP encoded traffic", "Enable heuristic dissection for openSAFETY over UDP encoded traffic",
3077 &global_enable_udp
);
3078 prefs_register_bool_preference(opensafety_module
, "enable_mbtcp",
3079 "Enable heuristic dissection for Modbus/TCP", "Enable heuristic dissection for Modbus/TCP",
3080 &global_enable_mbtcp
);
3082 prefs_register_bool_preference(opensafety_module
, "display_intergap_data",
3083 "Display the data between openSAFETY packets", "Display the data between openSAFETY packets",
3084 &global_display_intergap_data
);
3085 prefs_register_bool_preference(opensafety_module
, "classify_transport",
3086 "Dissect packet based on transport method (EPL + SercosIII only)",
3087 "SPDOs may only be found in cyclic data, SSDOs/SNMTS only in acyclic data",
3088 &global_classify_transport
);
3090 prefs_register_uint_preference(oss_udp_module
, "network_udp_port",
3091 "Port used for UDP Transport",
3092 "Port used by the openSAFETY over UDP data transport", 10,
3093 &global_network_oss_udp_port
);
3095 /* Registering default and ModBus/TCP dissector */
3096 opensafety_udpdata_handle
= register_dissector("opensafety_udp", dissect_opensafety_udpdata
, proto_opensafety
);
3097 opensafety_udptransport_handle
=
3098 register_dissector("opensafety_udptransport", dissect_opensafety_udpdata
, proto_oss_udp_transport
);
3099 opensafety_mbtcp_handle
= register_dissector("opensafety_mbtcp", dissect_opensafety_mbtcp
, proto_opensafety
);
3100 opensafety_pnio_handle
= register_dissector("opensafety_pnio", dissect_opensafety_pn_io
, proto_opensafety
);
3102 register_conversation_table(proto_opensafety
, true, opensafety_conversation_packet
, opensafety_endpoint_packet
);
3106 proto_reg_handoff_opensafety(void)
3108 /* Storing global data_dissector */
3109 data_dissector
= find_dissector ( "data" );
3111 /* EPL & SercosIII dissector registration */
3112 heur_dissector_add("epl_data", dissect_opensafety_epl
, "openSAFETY over EPL", "opensafety_epl_data", proto_opensafety
, HEURISTIC_ENABLE
);
3113 heur_dissector_add("sercosiii", dissect_opensafety_siii_heur
, "openSAFETY over SercosIII", "opensafety_sercosiii", proto_opensafety
, HEURISTIC_ENABLE
);
3115 /* Modbus TCP dissector registration */
3116 dissector_add_string("modbus.data", "data", opensafety_mbtcp_handle
);
3118 /* For Profinet we have to register as a heuristic dissector, as Profinet
3119 * is implemented as a plugin, and therefore the heuristic dissector is not
3120 * added by the time this method is being called
3122 if ( find_dissector("pn_io") != NULL
)
3124 heur_dissector_add("pn_io", dissect_opensafety_pn_io_heur
, "openSAFETY over Profinet", "opensafety_pn_io", proto_opensafety
, HEURISTIC_DISABLE
);
3128 /* The native dissector cannot be loaded. so we add our protocol directly to
3129 * the ethernet subdissector list. No PNIO specific data will be dissected
3130 * and a warning will be displayed, recognizing the missing dissector plugin.
3132 dissector_add_uint("ethertype", ETHERTYPE_PROFINET
, opensafety_pnio_handle
);
3137 register_init_routine ( setup_dissector
);
3138 register_cleanup_routine ( cleanup_dissector
);
3140 reassembly_table_register(&os_reassembly_table
, &addresses_reassembly_table_functions
);
3142 /* registering frame end routine, to prevent a malformed dissection preventing
3143 * further dissector calls (see bug #6950) */
3144 /* register_frame_end_routine(reset_dissector); */
3148 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3153 * indent-tabs-mode: nil
3156 * vi: set shiftwidth=4 tabstop=8 expandtab:
3157 * :indentSize=4:tabSize=8:noTabs=true: