1 /* packet-opensafety.c
2  *
3  *   openSAFETY is a machine-safety protocol, encapsulated in modern fieldbus
4  *   and industrial ethernet solutions.
5  *
6  *   For more information see http://www.open-safety.org
7  *
8  *   This dissector currently supports the following transport protocols
9  *
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
16  *
17  * By Roland Knall <roland.knall@br-automation.com>
18  * Copyright 2011-2012 Bernecker + Rainer Industrie-Elektronik Ges.m.b.H.
19  *
20  * Wireshark - Network traffic analyzer
21  * By Gerald Combs <gerald@wireshark.org>
22  * Copyright 1998 Gerald Combs
23  *
24  * SPDX-License-Identifier: GPL-2.0-or-later
25  */
26 
27 #include "config.h"
28 
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>
35 #include <epan/tap.h>
36 
37 #include <wsutil/crc8.h>
38 #include <wsutil/crc16.h>
39 
40 #include "packet-frame.h"
41 #include "packet-opensafety.h"
42 
43 /* General definitions */
44 
45 /* Used to clasify incoming traffic and presort the heuristic */
46 #define OPENSAFETY_ANY_TRANSPORT 0x00
47 #define OPENSAFETY_CYCLIC_DATA   0x01
48 #define OPENSAFETY_ACYCLIC_DATA  0x02
49 
50 #ifndef OPENSAFETY_PINFO_CONST_DATA
51 #define OPENSAFETY_PINFO_CONST_DATA 0xAABBCCDD
52 #endif
53 
54 #define OPENSAFETY_REQUEST  TRUE
55 #define OPENSAFETY_RESPONSE FALSE
56 
57 /* SPDO Feature Flags
58  * Because featureflags are part of the TR field (which is only 6 bit), the field get's shifted */
59 #define OPENSAFETY_SPDO_FEAT_40BIT_AVAIL   0x20
60 #define OPENSAFETY_SPDO_FEAT_40BIT_USED    0x10
61 #define OPENSAFETY_SPDO_FEATURE_FLAGS      (OPENSAFETY_SPDO_FEAT_40BIT_USED | OPENSAFETY_SPDO_FEAT_40BIT_AVAIL)
62 
63 #define OSS_FRAME_POS_ADDR   0
64 #define OSS_FRAME_POS_ID     1
65 #define OSS_FRAME_POS_LEN    2
66 #define OSS_FRAME_POS_CT     3
67 #define OSS_FRAME_POS_DATA   4
68 
69 #define OSS_PAYLOAD_MAXSIZE_FOR_CRC8        0x08
70 #define OSS_SLIM_FRAME_WITH_CRC8_MAXSIZE    0x13   /* 19 */
71 #define OSS_SLIM_FRAME2_WITH_CRC8           0x06   /*  6 */
72 #define OSS_SLIM_FRAME2_WITH_CRC16          0x07   /*  7 */
73 #define OSS_MINIMUM_LENGTH                  0x0b   /* 11 */
74 
75 #define OPENSAFETY_SPDO_CONNECTION_VALID  0x04
76 
77 #define OPENSAFETY_SOD_DVI   0x1018
78 #define OPENSAFETY_SOD_RXMAP 0x1800
79 #define OPENSAFETY_SOD_TXMAP 0xC000
80 
81 #define OSS_FRAME_ADDR(f, offset)        (f[OSS_FRAME_POS_ADDR + offset] + ((guint8)((f[OSS_FRAME_POS_ADDR + offset + 1]) << 6) << 2))
82 #define OSS_FRAME_ID(f, offset)          (f[OSS_FRAME_POS_ID + offset] & 0xFC )
83 #define OSS_FRAME_LENGTH(f, offset)      (f[OSS_FRAME_POS_LEN + offset])
84 #define OSS_FRAME_FIELD(f, position)     (f[position])
85 
86 #define OSS_FRAME_ADDR_T(f, offset)        (tvb_get_guint8(f, OSS_FRAME_POS_ADDR + offset) + ((guint8)((tvb_get_guint8( f, OSS_FRAME_POS_ADDR + offset + 1)) << 6) << 2))
87 #define OSS_FRAME_ADDR_T2(f, offset, su1, su2)        (( tvb_get_guint8(f, OSS_FRAME_POS_ADDR + offset) ^ su1) + ((guint8)(((tvb_get_guint8( f, OSS_FRAME_POS_ADDR + offset + 1) ^ su2)) << 6) << 2))
88 #define OSS_FRAME_ID_T(f, offset)          (tvb_get_guint8(f, OSS_FRAME_POS_ID + offset) & 0xFC)
89 #define OSS_FRAME_LENGTH_T(f, offset)      (tvb_get_guint8(f, OSS_FRAME_POS_LEN + offset))
90 
91 static int proto_opensafety = -1;
92 
93 static gint ett_opensafety = -1;
94 static gint ett_opensafety_checksum = -1;
95 static gint ett_opensafety_snmt = -1;
96 static gint ett_opensafety_ssdo = -1;
97 static gint ett_opensafety_spdo = -1;
98 static gint ett_opensafety_spdo_flags = -1;
99 static gint ett_opensafety_ssdo_sacmd = -1;
100 static gint ett_opensafety_ssdo_payload = -1;
101 static gint ett_opensafety_ssdo_sodentry = -1;
102 static gint ett_opensafety_ssdo_extpar = -1;
103 static gint ett_opensafety_sod_mapping = -1;
104 static gint ett_opensafety_node = -1;
105 
106 static expert_field ei_payload_length_not_positive = EI_INIT;
107 static expert_field ei_payload_unknown_format = EI_INIT;
108 static expert_field ei_crc_slimssdo_instead_of_spdo = EI_INIT;
109 static expert_field ei_crc_frame_1_invalid = EI_INIT;
110 static expert_field ei_crc_frame_1_valid_frame2_invalid = EI_INIT;
111 static expert_field ei_crc_frame_2_invalid = EI_INIT;
112 static expert_field ei_crc_frame_2_unknown_scm_udid = EI_INIT;
113 static expert_field ei_crc_frame_2_scm_udid_encoded = EI_INIT;
114 static expert_field ei_message_unknown_type = EI_INIT;
115 static expert_field ei_message_reassembly_size_differs_from_header = EI_INIT;
116 static expert_field ei_message_spdo_address_invalid = EI_INIT;
117 static expert_field ei_message_id_field_mismatch = EI_INIT;
118 static expert_field ei_scmudid_autodetected = EI_INIT;
119 static expert_field ei_scmudid_invalid_preference = EI_INIT;
120 static expert_field ei_scmudid_unknown = EI_INIT;
121 static expert_field ei_40bit_default_domain = EI_INIT;
122 
123 static int hf_oss_msg = -1;
124 static int hf_oss_msg_direction = -1;
125 static int hf_oss_msg_category = -1;
126 static int hf_oss_msg_node = -1;
127 static int hf_oss_msg_network = -1;
128 static int hf_oss_msg_sender = -1;
129 static int hf_oss_msg_receiver = -1;
130 static int hf_oss_length= -1;
131 static int hf_oss_crc = -1;
132 static int hf_oss_byte_offset = -1;
133 
134 static int hf_oss_crc_valid = -1;
135 static int hf_oss_crc2_valid = -1;
136 static int hf_oss_crc_type  = -1;
137 
138 static int hf_oss_snmt_slave = -1;
139 static int hf_oss_snmt_master = -1;
140 static int hf_oss_snmt_udid = -1;
141 static int hf_oss_snmt_scm = -1;
142 static int hf_oss_snmt_tool = -1;
143 static int hf_oss_snmt_service_id = -1;
144 static int hf_oss_snmt_error_group = -1;
145 static int hf_oss_snmt_error_code = -1;
146 static int hf_oss_snmt_param_type = -1;
147 static int hf_oss_snmt_ext_addsaddr = -1;
148 static int hf_oss_snmt_ext_addtxspdo = -1;
149 static int hf_oss_snmt_ext_initct = -1;
150 
151 static int hf_oss_ssdo_server = -1;
152 static int hf_oss_ssdo_client = -1;
153 static int hf_oss_ssdo_sano = -1;
154 static int hf_oss_ssdo_sacmd = -1;
155 static int hf_oss_ssdo_sod_index = -1;
156 static int hf_oss_ssdo_sod_subindex = -1;
157 static int hf_oss_ssdo_payload = -1;
158 static int hf_oss_ssdo_payload_size = -1;
159 static int hf_oss_ssdo_sodentry_size = -1;
160 static int hf_oss_ssdo_sodentry_data = -1;
161 static int hf_oss_ssdo_abort_code = -1;
162 static int hf_oss_ssdo_preload_queue = -1;
163 static int hf_oss_ssdo_preload_error = -1;
164 
165 static int hf_oss_sod_par_timestamp = -1;
166 static int hf_oss_sod_par_checksum = -1;
167 static int hf_oss_ssdo_sodmapping = -1;
168 static int hf_oss_ssdo_sodmapping_bits = -1;
169 
170 static int hf_oss_ssdo_sacmd_access_type = -1;
171 static int hf_oss_ssdo_sacmd_preload = -1;
172 static int hf_oss_ssdo_sacmd_abort_transfer = -1;
173 static int hf_oss_ssdo_sacmd_segmentation = -1;
174 static int hf_oss_ssdo_sacmd_toggle = -1;
175 static int hf_oss_ssdo_sacmd_initiate = -1;
176 static int hf_oss_ssdo_sacmd_end_segment = -1;
177 #if 0
178 static int hf_oss_ssdo_sacmd_reserved = -1;
179 #endif
180 
181 static int hf_oss_ssdo_extpar_parset = -1;
182 static int hf_oss_ssdo_extpar_version = -1;
183 static int hf_oss_ssdo_extpar_saddr = -1;
184 static int hf_oss_ssdo_extpar_length = -1;
185 static int hf_oss_ssdo_extpar_crc = -1;
186 static int hf_oss_ssdo_extpar_tstamp = -1;
187 static int hf_oss_ssdo_extpar_data = -1;
188 static int hf_oss_ssdo_extpar = -1;
189 
190 static int hf_oss_scm_udid = -1;
191 static int hf_oss_scm_udid_auto = -1;
192 static int hf_oss_scm_udid_valid = -1;
193 
194 static int hf_oss_spdo_direction = -1;
195 static int hf_oss_spdo_connection_valid = -1;
196 static int hf_oss_spdo_ct = -1;
197 static int hf_oss_spdo_ct_40bit = -1;
198 static int hf_oss_spdo_time_request = -1;
199 static int hf_oss_spdo_time_request_to = -1;
200 static int hf_oss_spdo_time_request_from = -1;
201 static int hf_oss_spdo_feature_flags = -1;
202 static int hf_oss_spdo_feature_flag_40bit_available = -1;
203 static int hf_oss_spdo_feature_flag_40bit_used = -1;
204 
205 static int hf_oss_fragments = -1;
206 static int hf_oss_fragment = -1;
207 static int hf_oss_fragment_overlap = -1;
208 static int hf_oss_fragment_overlap_conflicts = -1;
209 static int hf_oss_fragment_multiple_tails = -1;
210 static int hf_oss_fragment_too_long_fragment = -1;
211 static int hf_oss_fragment_error = -1;
212 static int hf_oss_fragment_count = -1;
213 static int hf_oss_reassembled_in = -1;
214 static int hf_oss_reassembled_length = -1;
215 static int hf_oss_reassembled_data = -1;
216 
217 static gint ett_opensafety_ssdo_fragment = -1;
218 static gint ett_opensafety_ssdo_fragments = -1;
219 
220 /* Definitions for the openSAFETY ov. UDP transport protocol */
221 static dissector_handle_t opensafety_udptransport_handle = NULL;
222 
223 static int proto_oss_udp_transport = -1;
224 
225 static int hf_oss_udp_transport_version = -1;
226 static int hf_oss_udp_transport_flags_type = -1;
227 static int hf_oss_udp_transport_counter = -1;
228 static int hf_oss_udp_transport_sender = -1;
229 static int hf_oss_udp_transport_datapoint = -1;
230 static int hf_oss_udp_transport_length= -1;
231 
232 static gint ett_oss_udp_transport = -1;
233 
234 static const true_false_string tfs_udp_transport_cyclic_acyclic = { "Cyclic", "ACyclic" };
235 static guint global_network_oss_udp_port = OPENSAFETY_UDP_PORT;
236 
237 static int opensafety_tap = -1;
238 
239 static const fragment_items oss_frag_items = {
240     /* Fragment subtrees */
241     &ett_opensafety_ssdo_fragment,
242     &ett_opensafety_ssdo_fragments,
243     /* Fragment fields */
244     &hf_oss_fragments,
245     &hf_oss_fragment,
246     &hf_oss_fragment_overlap,
247     &hf_oss_fragment_overlap_conflicts,
248     &hf_oss_fragment_multiple_tails,
249     &hf_oss_fragment_too_long_fragment,
250     &hf_oss_fragment_error,
251     &hf_oss_fragment_count,
252     /* Reassembled in field */
253     &hf_oss_reassembled_in,
254     /* Reassembled length field */
255     &hf_oss_reassembled_length,
256     /* Reassembled data */
257     &hf_oss_reassembled_data,
258     /* Tag */
259     "Message fragments"
260 };
261 
262 static const char *global_scm_udid = "00:00:00:00:00:00";
263 
264 static dissector_handle_t data_dissector = NULL;
265 static dissector_handle_t opensafety_udpdata_handle = NULL;
266 static dissector_handle_t opensafety_mbtcp_handle = NULL;
267 static dissector_handle_t opensafety_pnio_handle = NULL;
268 
269 static gboolean global_display_intergap_data   = FALSE;
270 static gboolean global_scm_udid_autoset        = TRUE;
271 static gboolean global_udp_frame2_first        = FALSE;
272 static gboolean global_siii_udp_frame2_first   = FALSE;
273 static gboolean global_mbtcp_big_endian        = FALSE;
274 static guint global_network_udp_port           = OPENSAFETY_UDP_PORT;
275 static guint global_network_udp_port_sercosiii = OPENSAFETY_UDP_PORT_SIII;
276 static gboolean global_classify_transport      = TRUE;
277 
278 static gboolean global_enable_udp    = TRUE;
279 static gboolean global_enable_mbtcp  = TRUE;
280 
281 static gboolean global_opensafety_debug_verbose = FALSE;
282 
283 static const char * global_filter_nodes = "";
284 static gboolean global_show_only_node_in_filter = TRUE;
285 static wmem_list_t * global_filter_list = NULL;
286 
287 static gboolean heuristic_siii_dissection_enabled = TRUE;
288 
289 static heur_dissector_list_t heur_opensafety_spdo_subdissector_list;
290 
291 static gboolean bDissector_Called_Once_Before = FALSE;
292 /* Using local_scm_udid as read variable for global_scm_udid, to
293  * enable automatic detection of scm udid */
294 static char *local_scm_udid = NULL;
295 
296 static reassembly_table os_reassembly_table;
297 
298 /* Resets the dissector in case the dissection is malformed and the dissector crashes */
299 static void
reset_dissector(void)300 reset_dissector(void)
301 {
302     bDissector_Called_Once_Before = FALSE;
303 }
304 
305 static void
setup_dissector(void)306 setup_dissector(void)
307 {
308     heur_dtbl_entry_t * heur_entry = NULL;
309 
310     /* create list if it does not exist, but clean existing elements anyway,
311      * as options might have changed */
312     global_filter_list = wmem_list_new(wmem_file_scope());
313 
314     gchar ** vector = wmem_strsplit(wmem_file_scope(), global_filter_nodes, ",", -1);
315     for (; NULL != *vector; vector++ )
316     {
317         if ( *vector && g_ascii_strtoll(*vector, NULL, 10) > 0 )
318             wmem_list_append(global_filter_list, GINT_TO_POINTER(g_ascii_strtoll(*vector, NULL, 10)));
319     }
320 
321     heur_entry = find_heur_dissector_by_unique_short_name("opensafety_sercosiii");
322     if ( heur_entry != NULL )
323         heuristic_siii_dissection_enabled = heur_entry->enabled;
324 }
325 
326 static void
cleanup_dissector(void)327 cleanup_dissector(void)
328 {
329     local_scm_udid = NULL;
330 
331     if ( global_filter_list )
332     {
333         wmem_destroy_list(global_filter_list);
334         global_filter_list = NULL;
335     }
336 }
337 
338 void proto_register_opensafety(void);
339 void proto_reg_handoff_opensafety(void);
340 
341 /* Conversation functions */
342 
343 /* This is defined by the specification. The Address field is 10 bits long, and the node with the number
344  *  1 is always the SCM, therefore ( 2 ^ 10 ) - 1 nodes can be addressed. We use 2 ^ 10 here, because the
345  *  SCM can talk to himself (Assign SADR for instance ) */
346 /* #define MAX_NUMBER_OF_SAFETY_NODES      ( 1 << 10 ) */
347 
348 /* Tracks the information that the packet pinfo has been received by receiver, and adds that information to the tree, using pos, as
349  * byte position in the PDU */
350 static void
opensafety_packet_node(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,gint hf_field,guint16 saddr,guint16 posInFrame,guint16 posSdnInFrame,guint16 sdn)351 opensafety_packet_node(tvbuff_t * message_tvb, packet_info *pinfo, proto_tree *tree,
352         gint hf_field, guint16 saddr, guint16 posInFrame, guint16 posSdnInFrame, guint16 sdn )
353 {
354     proto_item *psf_item = NULL;
355     proto_tree *psf_tree  = NULL;
356 
357     psf_item = proto_tree_add_uint(tree, hf_field, message_tvb, posInFrame, 2, saddr);
358     psf_tree = proto_item_add_subtree(psf_item, ett_opensafety_node);
359     psf_item = proto_tree_add_uint(psf_tree, hf_oss_msg_node, message_tvb, posInFrame, 2, saddr);
360     proto_item_set_generated(psf_item);
361 
362     if ( sdn > 0 )
363     {
364         psf_item = proto_tree_add_uint(psf_tree, hf_oss_msg_network, message_tvb,
365                 posSdnInFrame, 2, sdn);
366     } else if ( sdn <= 0 ) {
367         psf_item = proto_tree_add_uint(psf_tree, hf_oss_msg_network, message_tvb,
368                 posSdnInFrame, 2, sdn * -1);
369         expert_add_info(pinfo, psf_item, &ei_scmudid_unknown );
370     }
371     proto_item_set_generated(psf_item);
372 }
373 
374 static void
opensafety_packet_receiver(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,proto_item * opensafety_item,opensafety_packet_info * packet,guint16 recv,guint16 posInFrame,guint16 posSdnInFrame,guint16 sdn)375 opensafety_packet_receiver(tvbuff_t * message_tvb, packet_info *pinfo, proto_tree *tree, proto_item *opensafety_item,
376         opensafety_packet_info *packet, guint16 recv,
377         guint16 posInFrame, guint16 posSdnInFrame, guint16 sdn )
378 {
379     packet->receiver = recv;
380     if ( sdn > 0 )
381         packet->sdn = sdn;
382 
383     opensafety_packet_node (message_tvb, pinfo, tree, hf_oss_msg_receiver, recv, posInFrame, posSdnInFrame, sdn );
384     proto_item_append_text(opensafety_item, ", Dst: 0x%03X (%d)", recv, recv);
385 }
386 
387 /* Tracks the information that the packet pinfo has been sent by sender, and received by everyone else, and adds that information to
388  * the tree, using pos, as byte position in the PDU */
389 static void
opensafety_packet_sender(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,proto_item * opensafety_item,opensafety_packet_info * packet,guint16 sender,guint16 posInFrame,guint16 posSdnInFrame,guint16 sdn)390 opensafety_packet_sender(tvbuff_t * message_tvb, packet_info *pinfo, proto_tree *tree, proto_item *opensafety_item,
391         opensafety_packet_info *packet, guint16 sender,
392         guint16 posInFrame, guint16 posSdnInFrame, guint16 sdn )
393 {
394     packet->sender = sender;
395     if ( sdn > 0 )
396         packet->sdn = sdn;
397 
398     opensafety_packet_node (message_tvb, pinfo, tree, hf_oss_msg_sender, sender, posInFrame, posSdnInFrame, sdn );
399     proto_item_append_text(opensafety_item, ", Src: 0x%03X (%d)", sender, sender);
400 }
401 
402 /* Tracks the information that the packet pinfo has been sent by sender, and received by receiver, and adds that information to
403  * the tree, using pos for the sender and pos2 for the receiver, as byte position in the PDU */
404 static void
opensafety_packet_sendreceiv(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,proto_item * opensafety_item,opensafety_packet_info * packet,guint16 send,guint16 pos,guint16 recv,guint16 pos2,guint16 posnet,guint16 sdn)405 opensafety_packet_sendreceiv(tvbuff_t * message_tvb, packet_info *pinfo, proto_tree *tree, proto_item *opensafety_item,
406         opensafety_packet_info *packet, guint16 send, guint16 pos,
407         guint16 recv, guint16 pos2, guint16 posnet, guint16 sdn)
408 {
409         opensafety_packet_receiver(message_tvb, pinfo, tree, opensafety_item, packet, recv, pos2, posnet, sdn);
410         opensafety_packet_sender(message_tvb, pinfo, tree, opensafety_item, packet, send, pos, posnet, sdn);
411 }
412 
413 static proto_item *
opensafety_packet_response(tvbuff_t * message_tvb,proto_tree * sub_tree,opensafety_packet_info * packet,gboolean isResponse)414 opensafety_packet_response(tvbuff_t *message_tvb, proto_tree *sub_tree, opensafety_packet_info *packet, gboolean isResponse)
415 {
416     proto_item *item = NULL;
417     guint8 b_id = 0;
418 
419     if ( packet->msg_type != OPENSAFETY_SPDO_MESSAGE_TYPE )
420     {
421         proto_tree_add_item(sub_tree, hf_oss_msg, message_tvb,
422             OSS_FRAME_POS_ID + packet->frame.subframe1, 1, ENC_NA );
423     }
424     else
425     {
426         /* SPDOs code the connection valid bit on offset 0x04. SSDO and SNMT frames use this
427          * bit for messages. Therefore setting a bitmask on the hf-field would not work. */
428         b_id = OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) & 0xF8;
429         proto_tree_add_uint(sub_tree, hf_oss_msg, message_tvb, OSS_FRAME_POS_ID + packet->frame.subframe1, 1, b_id);
430     }
431 
432     item = proto_tree_add_item(sub_tree, packet->msg_type != OPENSAFETY_SPDO_MESSAGE_TYPE ? hf_oss_msg_direction : hf_oss_spdo_direction,
433             message_tvb, OSS_FRAME_POS_ID + packet->frame.subframe1, 1, ENC_NA);
434     if ( ! isResponse )
435         packet->is_request = TRUE;
436 
437     return item;
438 }
439 
440 static proto_tree *
opensafety_packet_payloadtree(packet_info * pinfo,tvbuff_t * message_tvb,proto_tree * opensafety_tree,opensafety_packet_info * packet,gint ett_tree)441 opensafety_packet_payloadtree(packet_info *pinfo, tvbuff_t *message_tvb, proto_tree *opensafety_tree,
442         opensafety_packet_info *packet, gint ett_tree)
443 {
444     proto_item *item = NULL;
445 
446     item = proto_tree_add_item(opensafety_tree, hf_oss_msg_category, message_tvb, OSS_FRAME_POS_ID + packet->frame.subframe1, 1, ENC_NA );
447     proto_item_set_generated(item);
448 
449     if ( packet->msg_type == OPENSAFETY_SNMT_MESSAGE_TYPE)
450         packet->payload.snmt = wmem_new0(pinfo->pool, opensafety_packet_snmt);
451     else if ( packet->msg_type == OPENSAFETY_SSDO_MESSAGE_TYPE || packet->msg_type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
452     {
453         packet->payload.ssdo = wmem_new0(pinfo->pool, opensafety_packet_ssdo);
454         if ( packet->msg_type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
455             packet->payload.ssdo->is_slim = TRUE;
456     }
457     else if ( packet->msg_type == OPENSAFETY_SPDO_MESSAGE_TYPE )
458         packet->payload.spdo = wmem_new0(pinfo->pool, opensafety_packet_spdo);
459 
460     return proto_item_add_subtree(item, ett_tree);
461 }
462 
463 static guint16
findFrame1Position(packet_info * pinfo,tvbuff_t * message_tvb,guint16 byte_offset,guint8 dataLength,gboolean checkIfSlimMistake)464 findFrame1Position ( packet_info *pinfo, tvbuff_t *message_tvb, guint16 byte_offset, guint8 dataLength, gboolean checkIfSlimMistake )
465 {
466     guint16  i_wFrame1Position                   = 0;
467     guint16  i_payloadLength, i_calculatedLength = 0;
468     guint16  i_offset                            = 0, calcCRC = 0, frameCRC = 0;
469     guint8   b_tempByte                          = 0;
470     guint8  *bytes = NULL;
471 
472     /*
473      * First, a normal package is assumed. Calculation of frame 1 position is
474      * pretty easy, because, the length of the whole package is 11 + 2*n + 2*o, which
475      * results in frame 1 start at (6 + n + o), which is length / 2 + 1
476      */
477     i_wFrame1Position = dataLength / 2 + 1;
478     i_payloadLength = tvb_get_guint8(message_tvb, byte_offset + i_wFrame1Position + 2 );
479     /* Calculating the assumed frame length, taking CRC8/CRC16 into account */
480     i_calculatedLength = i_payloadLength * 2 + 11 + 2 * (i_payloadLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? 1 : 0);
481 
482     /* To prevent miscalculations, where by chance the byte at [length / 2] + 3 is a value matching a possible payload length,
483      * but in reality the frame is a slim ssdo, the CRC of frame 1 gets checked additionally. This check
484      * is somewhat time consuming, so it will only run if the normal check led to a mistake detected along the line */
485     if ( checkIfSlimMistake && i_calculatedLength == dataLength )
486     {
487         if (dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
488             frameCRC = tvb_get_letohs(message_tvb,  byte_offset + i_wFrame1Position + dataLength + OSS_FRAME_POS_DATA);
489         else
490             frameCRC = tvb_get_guint8(message_tvb,  byte_offset + i_wFrame1Position + dataLength + OSS_FRAME_POS_DATA);
491 
492         bytes = (guint8*)tvb_memdup(pinfo->pool, message_tvb, byte_offset + i_wFrame1Position, dataLength + 4);
493         if ( dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
494         {
495             calcCRC = crc16_0x755B(bytes, dataLength + 4, 0);
496             if ( frameCRC != calcCRC )
497                 calcCRC = crc16_0x5935(bytes, dataLength + 4, 0);
498         }
499         else
500             calcCRC = crc8_0x2F(bytes, dataLength + 4, 0);
501 
502         /* if the calculated crc does not match the detected, the package is not a normal openSAFETY package */
503         if ( frameCRC != calcCRC )
504             dataLength = 0;
505     }
506 
507     /* If the calculated length differs from the given length, a slim package is assumed. */
508     if ( i_calculatedLength != dataLength )
509     {
510         /* possible slim package */
511         i_wFrame1Position = 0;
512         /*
513          * Slim packages have a fixed sublength of either 6 bytes for frame 2 in
514          * case of crc8 and 7 bytes in case of crc16
515          */
516         i_offset = OSS_SLIM_FRAME2_WITH_CRC8 + ( dataLength < (OSS_SLIM_FRAME_WITH_CRC8_MAXSIZE + 1) ? 0 : 1 );
517         /* Last 2 digits belong to addr, therefore have to be cleared */
518         b_tempByte = ( tvb_get_guint8 ( message_tvb, byte_offset + i_offset + 1 ) ) & 0xFC;
519 
520         /* If the id byte xor 0xE8 is 0, we have a slim package */
521         if ( ( ( b_tempByte ^ OPENSAFETY_MSG_SSDO_SLIM_SERVICE_REQUEST ) == 0 ) ||
522              ( ( b_tempByte ^ OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE ) == 0 ) )
523         {
524             /* Slim package found */
525             i_wFrame1Position = i_offset;
526         }
527     }
528 
529     return i_wFrame1Position;
530 }
531 
findSafetyFrame(packet_info * pinfo,tvbuff_t * message_tvb,guint u_Offset,gboolean b_frame2first,guint * u_frameOffset,guint * u_frameLength,opensafety_packet_info * packet)532 static gboolean findSafetyFrame ( packet_info *pinfo, tvbuff_t *message_tvb, guint u_Offset, gboolean b_frame2first,
533         guint *u_frameOffset, guint *u_frameLength, opensafety_packet_info *packet )
534 {
535     guint     ctr, rem_length;
536     guint16   crc, f2crc, calcCrc = 0;
537     guint8    b_Length = 0, b_CTl = 0, crcOffset = 0, crc1Type = 0;
538     guint8   *bytes;
539     guint     b_ID = 0;
540     gboolean  found;
541 
542     found = FALSE;
543     ctr = u_Offset;
544     rem_length = tvb_reported_length_remaining (message_tvb, ctr);
545 
546     /* Search will allways start at the second byte of the frame ( cause it determines )
547      * the type of package and therefore everything else. Therefore the mininmum length - 1
548      * is the correct minimum length */
549     while ( rem_length >= ( OSS_MINIMUM_LENGTH - 1 ) )
550     {
551         /* The ID byte must ALWAYS be the second byte, therefore 0 is invalid,
552          * also, the byte we want to access, must at least exist, otherwise,
553          * the frame is not detectable as an openSAFETY frame.
554          * We check for ID and length */
555         if ( ctr != 0 && tvb_bytes_exist(message_tvb, ctr, 2) )
556         {
557             *u_frameLength = 0;
558             *u_frameOffset = 0;
559 
560             crcOffset = 0;
561             b_ID = tvb_get_guint8(message_tvb, ctr );
562 
563             if ( b_ID != 0x0 )
564             {
565                 b_Length = tvb_get_guint8(message_tvb, ctr + 1 );
566 
567                 /* 0xFF is often used, but always false, otherwise start detection, if the highest
568                  *  bit is set */
569                 if ( ( b_ID != 0xFF ) && ( b_ID & 0x80 ) )
570                 {
571                     /* The rem_length value might be poluted, due to the else statement of
572                      * above if-decision (frame at end position detection). Therefore we
573                      * calculate it here again, to have a sane value */
574                     rem_length = tvb_reported_length_remaining(message_tvb, ctr);
575 
576                     /* Plausability check on length */
577                     if ( (guint)( b_Length * 2 ) < ( rem_length + OSS_MINIMUM_LENGTH ) )
578                     {
579 
580                         /* The calculated length must fit, but for the CRC16 check, also the calculated length
581                          * plus the CRC16 end position must fit in the remaining length */
582                         if ( ( b_Length <= (guint) 8 && ( b_Length <= rem_length ) ) ||
583                             ( b_Length > (guint) 8 && ( ( b_Length + (guint) 5 ) <= rem_length ) ) )
584                         {
585                             /* Ensure, that the correct length for CRC calculation
586                              * still exists in byte stream, so that we can calculate the crc */
587                             if ( tvb_bytes_exist(message_tvb, ctr - 1, b_Length + 5) )
588                             {
589                                 /* An openSAFETY command has to have a high-byte range between 0x0A and 0x0E
590                                  *  b_ID & 0x80 took care of everything underneath, we check for 0x09 and 0x0F,
591                                  *  as they remain the only values left, which are not valid */
592                                 if ( ( ( b_ID >> 4 ) != 0x09 ) && ( ( b_ID >> 4 ) != 0x0F ) )
593                                 {
594                                     /* Read CRC from position */
595                                     crc = tvb_get_guint8(message_tvb, ctr + 3 + b_Length );
596 
597                                     /* There exists some false positives, where the only possible
598                                      * data information in the frame is the ID and the ADDR fields.
599                                      * The rest of the fields in frame 1 are zeroed out. The packet
600                                      * must be filtered out and may not be used. To detect it, we
601                                      * check for the CT value, which, if zero indicates strongly
602                                      * that this is false-positive. */
603                                     b_CTl = tvb_get_guint8(message_tvb, ctr + 2 );
604 
605                                     /* If either length, crc or CTl is not zero, this may be a
606                                      * correct package. If all three are 0, this is most certainly
607                                      * an incorrect package, because the possibility of a valid
608                                      * package with all three values being zero is next to impossible */
609                                     if ( b_Length != 0x00 || crc != 0x00 || b_CTl != 0x00 )
610                                     {
611                                         /* calculate checksum */
612                                         bytes = (guint8 *)tvb_memdup(pinfo->pool, message_tvb, ctr - 1, b_Length + 5 );
613                                         if ( b_Length > 8 )
614                                         {
615                                             crc = tvb_get_letohs ( message_tvb, ctr + 3 + b_Length );
616                                             crcOffset = 1;
617 
618                                             crc1Type = OPENSAFETY_CHECKSUM_CRC16;
619                                             calcCrc = crc16_0x755B( bytes, b_Length + 4, 0 );
620                                             if ( ( crc ^ calcCrc ) != 0 )
621                                             {
622                                                 calcCrc = crc16_0x5935( bytes, b_Length + 4, 0 );
623                                                 if ( ( crc ^ calcCrc ) == 0 )
624                                                     crc1Type = OPENSAFETY_CHECKSUM_CRC16SLIM;
625                                                 else
626                                                     crc1Type = OPENSAFETY_CHECKSUM_INVALID;
627                                             }
628                                         } else {
629                                             crc1Type = OPENSAFETY_CHECKSUM_CRC8;
630                                             calcCrc = crc8_0x2F ( bytes, b_Length + 4, 0 );
631                                         }
632 
633                                         if ( ( crc ^ calcCrc ) == 0 )
634                                         {
635                                             /* Check if this is a Slim SSDO message */
636                                             if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
637                                             {
638                                                 /* Slim SSDO messages must have a length != 0, as the first byte
639                                                  * in the payload contains the SOD access command */
640                                                 if ( b_Length > 0 )
641                                                 {
642                                                     *u_frameOffset = ( ctr - 1 );
643                                                     *u_frameLength = b_Length + 2 * crcOffset + 11;
644 
645                                                     /* It is highly unlikely, that both frame 1 and frame 2 generate
646                                                      * a crc == 0 or equal crc's. Therefore we check, if both crc's are
647                                                      * equal. If so, it is a falsely detected frame. */
648                                                     f2crc = tvb_get_guint8 ( message_tvb, ctr + 3 + 5 + b_Length );
649                                                     if ( b_Length > 8 )
650                                                         f2crc = tvb_get_letohs ( message_tvb, ctr + 3 + 5 + b_Length );
651                                                     if ( crc != f2crc )
652                                                     {
653                                                         found = TRUE;
654                                                         break;
655                                                     }
656                                                 }
657                                             }
658                                             else
659                                             {
660                                                 *u_frameLength = 2 * b_Length + 2 * crcOffset + 11;
661                                                 *u_frameOffset = ( ctr - 1 );
662 
663                                                 /* If the first crc is zero, the second one must not be 0. The header
664                                                  * for each subfields differ, therefore it is impossible, that both
665                                                  * crcs are zero */
666                                                 if ( crc == 0 )
667                                                 {
668                                                     f2crc = tvb_get_guint8 ( message_tvb, ( ctr - 1 ) + 10 + ( 2 * b_Length ) );
669                                                     if ( b_Length > 8 )
670                                                         f2crc = tvb_get_letohs ( message_tvb, ( ctr - 1 ) + 11 + ( 2 * b_Length ) );
671 
672                                                     /* The crc's differ, everything is ok */
673                                                     if ( crc != f2crc )
674                                                     {
675                                                         found = TRUE;
676                                                         break;
677                                                     }
678                                                 }
679                                                 else
680                                                 {
681                                                     /* At this point frames had been checked for SoC and SoA types of
682                                                      * EPL. This is no longer necessary and leads to false-negatives.
683                                                      * SoC and SoA frames get filtered out at the EPL entry point, cause
684                                                      * EPL only provides payload, no longer complete frames. */
685                                                     found = TRUE;
686                                                     break;
687                                                 }
688                                             }
689                                         }
690                                     }
691                                 }
692                             }
693                         }
694                     }
695                 }
696                 else
697                 {
698                     /* There exist frames, where the last openSAFETY frame is sitting in the
699                      * very last bytes of the frame, and the complete frame itself contains
700                      * more than one openSAFETY frame. It so happens that in such a case, the
701                      * last openSAFETY frame will miss detection.
702                      *
703                      * If so we look at the transported length, calculate the frame length,
704                      * and take a look if the calculated frame length, might be a fit for the
705                      * remaining length. If such is the case, we increment ctr and increment
706                      * rem_length (to hit the while loop one more time) and the frame will be
707                      * detected correctly. */
708                     if ( rem_length == OSS_MINIMUM_LENGTH )
709                     {
710                         b_ID = tvb_get_guint8(message_tvb, ctr );
711                         b_Length = tvb_get_guint8(message_tvb, ctr + 2 );
712                         if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
713                             b_Length = ( 11 + ( b_Length > 8 ? 2 : 0 ) + b_Length );
714                         else
715                             b_Length = ( 11 + ( b_Length > 8 ? 2 : 0 ) + 2 * b_Length );
716 
717                         if ( rem_length == b_Length )
718                         {
719                             ctr++;
720                             rem_length++;
721                             continue;
722                         }
723                     }
724                 }
725             }
726         }
727 
728         ctr++;
729         rem_length = tvb_reported_length_remaining(message_tvb, ctr);
730 
731     }
732 
733     /* Store packet information in packet_info */
734     if ( found && packet )
735     {
736         packet->msg_id = b_ID;
737         packet->msg_len = b_Length;
738         packet->frame_len = *u_frameLength;
739 
740         /* Should be the calculated crc, which is the same as the frame crc */
741         packet->crc.frame1 = calcCrc;
742         packet->crc.type = crc1Type;
743         if ( packet->crc.type != OPENSAFETY_CHECKSUM_INVALID )
744             packet->crc.valid1 = TRUE;
745         else
746             packet->crc.valid1 = FALSE;
747     }
748 
749     /* Seem redundant if b_frame2First is false. But in this case, the function is needed for the
750      * simple detection of a possible openSAFETY frame.  */
751     if ( b_frame2first && found )
752         *u_frameOffset = u_Offset;
753 
754     return found;
755 }
756 
757 static gint
dissect_data_payload(proto_tree * epl_tree,tvbuff_t * tvb,packet_info * pinfo,gint offset,gint len,guint8 msgType)758 dissect_data_payload ( proto_tree *epl_tree, tvbuff_t *tvb, packet_info *pinfo, gint offset, gint len, guint8 msgType )
759 {
760         gint off = 0;
761         tvbuff_t * payload_tvb = NULL;
762         heur_dtbl_entry_t *hdtbl_entry = NULL;
763 
764         off = offset;
765 
766         if (len > 0)
767         {
768                 payload_tvb = tvb_new_subset_length_caplen(tvb, off, len, tvb_reported_length_remaining(tvb, offset) );
769                 if ( ! dissector_try_heuristic(heur_opensafety_spdo_subdissector_list, payload_tvb, pinfo, epl_tree, &hdtbl_entry, &msgType))
770                         call_dissector(data_dissector, payload_tvb, pinfo, epl_tree);
771 
772                 off += len;
773         }
774 
775         return off;
776 }
777 
778 static void
dissect_opensafety_spdo_message(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * opensafety_tree,opensafety_packet_info * packet,proto_item * opensafety_item)779 dissect_opensafety_spdo_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *opensafety_tree,
780         opensafety_packet_info * packet, proto_item * opensafety_item )
781 {
782     proto_item *item, *diritem;
783     proto_tree *spdo_tree, *spdo_flags_tree;
784     guint16     ct, addr;
785     guint64     ct40bit;
786     gint16      taddr, sdn;
787     guint       dataLength;
788     guint8      tr, b_ID, spdoFlags;
789 
790     dataLength = tvb_get_guint8(message_tvb, OSS_FRAME_POS_LEN + packet->frame.subframe1);
791     b_ID = tvb_get_guint8(message_tvb, packet->frame.subframe1 + 1) & 0xF8;
792 
793     /* Network address is xor'ed into the start of the second frame, but only legible, if the scm given is valid */
794     sdn = ( ( OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1) ) ^
795             ( OSS_FRAME_ADDR_T2(message_tvb, packet->frame.subframe2, packet->scm_udid[0], packet->scm_udid[1]) ) );
796     if ( ! packet->scm_udid_valid )
797         sdn = ( -1 * sdn );
798 
799     /* taddr is the 4th octet in the second frame */
800     tr = ( tvb_get_guint8(message_tvb, packet->frame.subframe2 + 4)  ^ packet->scm_udid[4] ) & 0xFC;
801 
802     /* allow only valid SPDO flags */
803     spdoFlags = ( ( tr >> 2 ) & OPENSAFETY_SPDO_FEATURE_FLAGS );
804 
805     /* An SPDO is always sent by the producer, to everybody else .
806      * For a 40bit connection OPENSAFETY_DEFAULT_DOMAIN is assumed as sdn value for now */
807     if ( (OPENSAFETY_SPDO_FEAT_40BIT_USED & spdoFlags ) == OPENSAFETY_SPDO_FEAT_40BIT_USED )
808         sdn = OPENSAFETY_DEFAULT_DOMAIN;
809 
810     /* Determine the producer and set it, as opensafety_packet_node does not */
811     addr = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1);
812     packet->sender = addr;
813 
814     opensafety_packet_node ( message_tvb, pinfo, opensafety_tree, hf_oss_msg_sender,
815             addr, OSS_FRAME_POS_ADDR + packet->frame.subframe1, packet->frame.subframe2, sdn );
816     proto_item_append_text(opensafety_item, "; Producer: 0x%03X (%d)", addr, addr);
817 
818     spdo_tree = opensafety_packet_payloadtree ( pinfo, message_tvb, opensafety_tree, packet, ett_opensafety_spdo );
819 
820     /* Determine SPDO Flags. Attention packet->payload.spdo exists ONLY AFTER opensafety_packet_payloadtree */
821     packet->payload.spdo->flags.enabled40bit = FALSE;
822     packet->payload.spdo->flags.requested40bit = FALSE;
823 
824     if ( (OPENSAFETY_SPDO_FEAT_40BIT_AVAIL & spdoFlags ) == OPENSAFETY_SPDO_FEAT_40BIT_AVAIL )
825         packet->payload.spdo->flags.requested40bit = TRUE;
826     if ( packet->payload.spdo->flags.requested40bit && ( (OPENSAFETY_SPDO_FEAT_40BIT_USED & spdoFlags ) == OPENSAFETY_SPDO_FEAT_40BIT_USED ) )
827         packet->payload.spdo->flags.enabled40bit = TRUE;
828 
829     diritem = opensafety_packet_response(message_tvb, spdo_tree, packet, b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE );
830     proto_tree_add_item(spdo_tree, hf_oss_spdo_connection_valid, message_tvb, OSS_FRAME_POS_ID + packet->frame.subframe1, 1, ENC_NA);
831 
832     packet->payload.spdo->conn_valid = (tvb_get_guint8(message_tvb, OSS_FRAME_POS_ID + packet->frame.subframe1) & 0x04) == 0x04;
833 
834     /* taddr is the 4th octet in the second frame */
835     taddr = OSS_FRAME_ADDR_T2(message_tvb, packet->frame.subframe2 + 3, packet->scm_udid[3], packet->scm_udid[4]);
836     tr = ( tvb_get_guint8(message_tvb, packet->frame.subframe2 + 4)  ^ packet->scm_udid[4] ) & 0xFC;
837 
838     /* determine the ct value. if complete it can be used for analysis of the package */
839     ct = tvb_get_guint8(message_tvb, packet->frame.subframe1 + 3);
840     if ( packet->scm_udid_valid )
841     {
842         ct = (guint16)((tvb_get_guint8(message_tvb, packet->frame.subframe2 + 2) ^ packet->scm_udid[2]) << 8) +
843             (tvb_get_guint8(message_tvb, packet->frame.subframe1 + 3));
844     }
845 
846     if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST )
847     {
848         proto_item_append_text(diritem, " (Safety Node: %03d)", taddr);
849         item = proto_tree_add_uint_format_value(spdo_tree, hf_oss_spdo_ct, message_tvb, 0, 0, ct,
850                                                 "0x%04X [%d] (%s)", ct, ct,
851                                                 (packet->scm_udid_valid ? "Complete" : "Low byte only"));
852         proto_item_set_generated(item);
853         packet->payload.spdo->counter.b16 = ct;
854 
855         packet->payload.spdo->timerequest = taddr;
856         proto_tree_add_uint(spdo_tree, hf_oss_spdo_time_request, message_tvb,
857                             OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 4, 1, tr);
858         opensafety_packet_node ( message_tvb, pinfo, spdo_tree, hf_oss_spdo_time_request_from, taddr,
859                 OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 3, packet->frame.subframe2, sdn );
860     }
861     else
862     {
863         if ( ! (b_ID == OPENSAFETY_MSG_SPDO_DATA_ONLY) || !(packet->payload.spdo->flags.enabled40bit) )
864         {
865             item = proto_tree_add_uint_format_value(spdo_tree, hf_oss_spdo_ct, message_tvb, 0, 0, ct,
866                     "0x%04X [%d] (%s)", ct, ct, (packet->scm_udid_valid ? "Complete" : "Low byte only"));
867             proto_item_set_generated(item);
868             packet->payload.spdo->counter.b16 = ct;
869         }
870         else
871         {
872             /* 40bit counter is calculated from various fields. Therefore it cannot be read
873              * directly from the frame. All fields starting after or with packet->frame.subframe2 have to
874              * be decoded using the scm udid */
875             ct40bit = (tvb_get_guint8(message_tvb, packet->frame.subframe2 + 3) ^ packet->scm_udid[3]);
876             ct40bit <<= 8;
877             ct40bit += ((guint64)(tvb_get_guint8(message_tvb, packet->frame.subframe2 + 1) ^ packet->scm_udid[1]) ^ tvb_get_guint8(message_tvb, packet->frame.subframe1 + 1));
878             ct40bit <<= 8;
879             ct40bit += (tvb_get_guint8(message_tvb, packet->frame.subframe2 + 0) ^ packet->scm_udid[0]) ^ OPENSAFETY_DEFAULT_DOMAIN ^ tvb_get_guint8(message_tvb, packet->frame.subframe1 + 0);
880             ct40bit <<= 8;
881             ct40bit += (tvb_get_guint8(message_tvb, packet->frame.subframe2 + 2) ^ packet->scm_udid[2]);
882             ct40bit <<= 8;
883             ct40bit += tvb_get_guint8(message_tvb, packet->frame.subframe1 + 3);
884 
885             item = proto_tree_add_uint64(spdo_tree, hf_oss_spdo_ct_40bit, message_tvb, 0, 0, ct40bit);
886             proto_item_set_generated(item);
887 
888             packet->payload.spdo->counter.b40 = ct40bit;
889             if ( global_opensafety_debug_verbose )
890                 expert_add_info ( pinfo, item, &ei_40bit_default_domain );
891         }
892         proto_item_set_generated(item);
893 
894         if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE )
895         {
896             proto_item_append_text(diritem, " (Safety Node: %03d)", taddr);
897             proto_tree_add_uint(spdo_tree, hf_oss_spdo_time_request, message_tvb,
898                     OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 4, 1, tr);
899             packet->payload.spdo->timerequest = taddr;
900 
901             opensafety_packet_node ( message_tvb, pinfo, spdo_tree, hf_oss_spdo_time_request_to, taddr,
902                     OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 3, packet->frame.subframe2, sdn );
903         }
904         else
905         {
906             item = proto_tree_add_uint(spdo_tree, hf_oss_spdo_feature_flags,
907                     message_tvb, OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 4, 1, spdoFlags << 2);
908 
909             spdo_flags_tree = proto_item_add_subtree(item, ett_opensafety_spdo_flags);
910 
911             proto_tree_add_boolean(spdo_flags_tree, hf_oss_spdo_feature_flag_40bit_available, message_tvb,
912                     OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 4, 1,
913                     packet->payload.spdo->flags.requested40bit ? OPENSAFETY_SPDO_FEAT_40BIT_AVAIL << 2 : 0 );
914             proto_tree_add_boolean(spdo_flags_tree, hf_oss_spdo_feature_flag_40bit_used, message_tvb,
915                     OSS_FRAME_POS_ADDR + packet->frame.subframe2 + 4, 1,
916                     packet->payload.spdo->flags.enabled40bit ? OPENSAFETY_SPDO_FEAT_40BIT_USED << 2 : 0 );
917         }
918     }
919 
920     if ( dataLength > 0 )
921     {
922         dissect_data_payload(spdo_tree, message_tvb, pinfo, OSS_FRAME_POS_ID + 3, dataLength, OPENSAFETY_SPDO_MESSAGE_TYPE);
923     }
924 }
925 
dissect_opensafety_ssdo_payload(packet_info * pinfo,tvbuff_t * new_tvb,proto_tree * ssdo_payload,guint8 sacmd)926 static void dissect_opensafety_ssdo_payload ( packet_info *pinfo, tvbuff_t *new_tvb, proto_tree *ssdo_payload, guint8 sacmd )
927 {
928     guint       dataLength   = 0, ctr = 0, n = 0, nCRCs = 0;
929     guint8      ssdoSubIndex = 0;
930     guint16     ssdoIndex    = 0, dispSSDOIndex = 0;
931     guint32     sodLength    = 0, entry = 0;
932     proto_item *item;
933     proto_tree *sod_tree, *ext_tree;
934 
935     dataLength = tvb_captured_length(new_tvb);
936 
937     ssdoIndex = tvb_get_letohs(new_tvb, 0);
938 
939     sodLength = tvb_get_letohl(new_tvb, 4);
940 
941     /* first check for extended parameter */
942     if ( dataLength == 16 || sodLength == ( dataLength - 16 ) || ssdoIndex == 0x0101 )
943     {
944         /* extended parameter header & data */
945         item = proto_tree_add_string_format(ssdo_payload, hf_oss_ssdo_extpar,
946                                             new_tvb, 0, dataLength, "", "Extended Parameter Set: %s",
947                                             (dataLength == 16 ? "Header only" : "Header & Data") );
948         ext_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_extpar);
949 
950         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_parset,  new_tvb, 0, 1, ENC_BIG_ENDIAN );
951         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_version, new_tvb, 1, 1, ENC_BIG_ENDIAN );
952         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_saddr,   new_tvb, 2, 2, ENC_LITTLE_ENDIAN );
953 
954         proto_tree_add_uint_format_value(ext_tree, hf_oss_ssdo_extpar_length,
955                                          new_tvb, 4, 4, sodLength, "0x%04X (%d octets)",
956                                          sodLength, sodLength );
957 
958         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_crc,    new_tvb,  8, 4, ENC_LITTLE_ENDIAN );
959         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_tstamp, new_tvb, 12, 4, ENC_LITTLE_ENDIAN );
960 
961         if ( dataLength != 16 )
962         {
963             item = proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_data, new_tvb, 16, dataLength - 16, ENC_NA );
964 
965             if ( ( dataLength - sodLength ) != 16 )
966                 expert_add_info ( pinfo, item, &ei_message_reassembly_size_differs_from_header );
967         }
968     }
969     else
970     {
971         /* If == upload, it is most likely a par upload */
972         if ( sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END && ( dataLength % 4 == 0 ) )
973         {
974 
975             item = proto_tree_add_uint_format_value(ssdo_payload, hf_oss_ssdo_sod_index, new_tvb,
976                                                     0, 0,  0x1018, "0x%04X (%s)", 0x1018,
977                                                     val_to_str_ext_const( ((guint32) (0x1018 << 16) ),
978                                                                           &opensafety_sod_idx_names_ext, "Unknown") );
979             sod_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_sodentry);
980             proto_item_set_generated(item);
981 
982             item = proto_tree_add_uint_format_value(sod_tree, hf_oss_ssdo_sod_subindex, new_tvb, 0, 0,
983                                                     0x06, "0x%02X (%s)", 0x06,
984                                                     val_to_str_ext_const(((guint32) (0x1018 << 16) +  0x06),
985                                                                          &opensafety_sod_idx_names_ext, "Unknown") );
986             proto_item_set_generated(item);
987 
988             proto_tree_add_item( sod_tree, hf_oss_sod_par_timestamp, new_tvb, 0, 4, ENC_LITTLE_ENDIAN );
989 
990             /* This is to avoid a compiler loop optimization warning */
991             nCRCs = dataLength / 4;
992             for ( ctr = 1; ctr < nCRCs; ctr++ )
993             {
994                 entry = tvb_get_letohl ( new_tvb, ctr * 4 );
995                 proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_checksum, new_tvb, ctr * 4,
996                         4, entry, "[#%d] 0x%08X", ctr, entry );
997             }
998         }
999         /* If != upload, it is most likely a 101A download */
1000         else
1001         {
1002 
1003             /* normal parameter set */
1004             for ( ctr = 0; ctr < dataLength; ctr++ )
1005             {
1006                 ssdoIndex = tvb_get_letohs(new_tvb, ctr);
1007                 ssdoSubIndex = tvb_get_guint8(new_tvb, ctr + 2);
1008                 dispSSDOIndex = ssdoIndex;
1009 
1010                 if ( ssdoIndex >= 0x1400 && ssdoIndex <= 0x17FE )
1011                     dispSSDOIndex = 0x1400;
1012                 else if ( ssdoIndex >= 0x1800 && ssdoIndex <= 0x1BFE )
1013                     dispSSDOIndex = 0x1800;
1014                 else if ( ssdoIndex >= 0x1C00 && ssdoIndex <= 0x1FFE )
1015                     dispSSDOIndex = 0x1C00;
1016                 else if ( ssdoIndex >= 0xC000 && ssdoIndex <= 0xC3FE )
1017                     dispSSDOIndex = 0xC000;
1018 
1019                 item = proto_tree_add_uint_format_value(ssdo_payload, hf_oss_ssdo_sod_index, new_tvb,
1020                                                         ctr, 2,  ssdoIndex, "0x%04X (%s)", ssdoIndex,
1021                                                         val_to_str_ext_const( ((guint32) (dispSSDOIndex << 16) ),
1022                                                                               &opensafety_sod_idx_names_ext, "Unknown") );
1023                 if ( ssdoIndex != dispSSDOIndex )
1024                     proto_item_set_generated ( item );
1025 
1026                 if ( ssdoIndex < 0x1000 || ssdoIndex > 0xE7FF )
1027                     expert_add_info ( pinfo, item, &ei_payload_unknown_format );
1028 
1029                 sod_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_sodentry);
1030 
1031                 if ( ssdoSubIndex != 0 )
1032                 {
1033                     proto_tree_add_uint_format_value(sod_tree, hf_oss_ssdo_sod_subindex, new_tvb, ctr + 2, 1,
1034                                                      ssdoSubIndex, "0x%02X (%s)", ssdoSubIndex,
1035                                                      val_to_str_ext_const(((guint32) (ssdoIndex << 16) + ssdoSubIndex),
1036                                                                           &opensafety_sod_idx_names_ext, "Unknown") );
1037                 }
1038                 else
1039                     proto_tree_add_uint_format_value(sod_tree, hf_oss_ssdo_sod_subindex, new_tvb, ctr + 2, 1,
1040                                                  ssdoSubIndex, "0x%02X", ssdoSubIndex );
1041                 ctr += 2;
1042 
1043                 /* reading real size */
1044                 sodLength = tvb_get_letohl ( new_tvb, ctr + 1 );
1045                 if ( sodLength > (dataLength - ctr) )
1046                     sodLength = 0;
1047 
1048                 if ( ( sodLength + 4 + ctr ) > dataLength )
1049                     break;
1050 
1051                 if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x06 )
1052                 {
1053                     proto_tree_add_item( sod_tree, hf_oss_sod_par_timestamp, new_tvb, ctr + 5, 4, ENC_LITTLE_ENDIAN );
1054 
1055                     /* This is to avoid a compiler loop optimization warning */
1056                     nCRCs = sodLength / 4;
1057                     for ( n = 1; n < nCRCs; n++ )
1058                     {
1059                         entry = tvb_get_letohl ( new_tvb, ctr + 5 + ( n * 4 ) );
1060                         proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_checksum, new_tvb,
1061                                 (ctr + 5 + ( n * 4 ) ), 4, entry, "[#%d] 0x%08X", n, entry );
1062                     }
1063                 } else if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x07 ) {
1064                     proto_tree_add_item( sod_tree, hf_oss_sod_par_timestamp, new_tvb, ctr + 5, 4, ENC_LITTLE_ENDIAN );
1065                 } else if ( ( dispSSDOIndex == OPENSAFETY_SOD_RXMAP || dispSSDOIndex == OPENSAFETY_SOD_TXMAP ) && ssdoSubIndex != 0x0 ) {
1066                     proto_tree_add_uint(sod_tree, hf_oss_ssdo_sodentry_size, new_tvb, ctr + 1, 4, sodLength );
1067                     item = proto_tree_add_item(sod_tree, hf_oss_ssdo_sodmapping, new_tvb, ctr + 5, sodLength, ENC_NA );
1068                     ext_tree = proto_item_add_subtree(item, ett_opensafety_sod_mapping);
1069 
1070                     proto_tree_add_item(ext_tree, hf_oss_ssdo_sodmapping_bits, new_tvb, ctr + 5, 1, ENC_NA);
1071 
1072                     proto_tree_add_item(ext_tree, hf_oss_ssdo_sod_index, new_tvb, ctr + 7, 2, ENC_LITTLE_ENDIAN);
1073                     proto_tree_add_item(ext_tree, hf_oss_ssdo_sod_subindex, new_tvb, ctr + 6, 1, ENC_NA);
1074 
1075                 } else {
1076                     proto_tree_add_uint(sod_tree, hf_oss_ssdo_sodentry_size, new_tvb, ctr + 1, 4, sodLength );
1077                     if ( sodLength > 0 )
1078                         proto_tree_add_item(sod_tree, hf_oss_ssdo_sodentry_data, new_tvb, ctr + 5, sodLength, ENC_NA );
1079                 }
1080                 ctr += sodLength + 4;
1081         }
1082         }
1083     }
1084 
1085 
1086 }
1087 
1088 static void
dissect_opensafety_ssdo_message(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * opensafety_tree,opensafety_packet_info * packet,proto_item * opensafety_item)1089 dissect_opensafety_ssdo_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *opensafety_tree,
1090         opensafety_packet_info * packet, proto_item * opensafety_item )
1091 {
1092     proto_item    *item;
1093     proto_tree    *ssdo_tree, *ssdo_payload;
1094     guint16        taddr                = 0, sdn = 0, server = 0, client = 0, n = 0, ct = 0;
1095     guint32        abortcode, ssdoIndex = 0, ssdoSubIndex = 0, payloadSize, fragmentId = 0, entry = 0;
1096     guint8         db0Offset, db0, payloadOffset, preload;
1097     guint          dataLength;
1098     gint           calcDataLength;
1099     gboolean       isResponse, saveFragmented;
1100     tvbuff_t      *new_tvb              = NULL;
1101     fragment_head *frag_msg             = NULL;
1102 
1103     static int * const ssdo_sacmd_flags[] = {
1104             &hf_oss_ssdo_sacmd_end_segment,
1105             &hf_oss_ssdo_sacmd_initiate,
1106             &hf_oss_ssdo_sacmd_toggle,
1107             &hf_oss_ssdo_sacmd_segmentation,
1108             &hf_oss_ssdo_sacmd_abort_transfer,
1109             &hf_oss_ssdo_sacmd_preload,
1110             &hf_oss_ssdo_sacmd_access_type,
1111             NULL
1112     };
1113 
1114     dataLength = tvb_get_guint8(message_tvb, OSS_FRAME_POS_LEN + packet->frame.subframe1);
1115 
1116     db0Offset = packet->frame.subframe1 + OSS_FRAME_POS_DATA;
1117     db0 = tvb_get_guint8(message_tvb, db0Offset);
1118     ssdoIndex = 0;
1119     ssdoSubIndex = 0;
1120 
1121     /* Response is determined by the openSAFETY message field */
1122     isResponse = ( ( OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) & 0x04 ) == 0x04 );
1123 
1124     if ( packet->scm_udid_valid )
1125     {
1126         /* taddr is the 4th octet in the second frame */
1127         taddr = OSS_FRAME_ADDR_T2(message_tvb, packet->frame.subframe2 + 3, packet->scm_udid[3], packet->scm_udid[4]);
1128         sdn =  ( OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1) ^
1129                         ( OSS_FRAME_ADDR_T2(message_tvb, packet->frame.subframe2, packet->scm_udid[0], packet->scm_udid[1]) ) );
1130 
1131         opensafety_packet_sendreceiv ( message_tvb, pinfo, opensafety_tree, opensafety_item, packet, taddr,
1132                 packet->frame.subframe2 + 3, OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1),
1133                 packet->frame.subframe1, packet->frame.subframe2, sdn );
1134     }
1135     else if ( ! isResponse )
1136     {
1137         opensafety_packet_sender ( message_tvb, pinfo, opensafety_tree, opensafety_item, packet,
1138                 OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1), packet->frame.subframe1,
1139                 packet->frame.subframe2, -1 * ( ( OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1) ) ^
1140                         ( OSS_FRAME_ADDR_T2(message_tvb, packet->frame.subframe2, packet->scm_udid[0], packet->scm_udid[1]) ) ) );
1141     }
1142     else if ( isResponse )
1143     {
1144         opensafety_packet_receiver ( message_tvb, pinfo, opensafety_tree, opensafety_item, packet,
1145                 OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1), packet->frame.subframe1,
1146                 packet->frame.subframe2, -1 * ( ( OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1) ) ^
1147                         ( OSS_FRAME_ADDR_T2(message_tvb, packet->frame.subframe2, packet->scm_udid[0], packet->scm_udid[1]) ) ) );
1148     }
1149 
1150     ssdo_tree = opensafety_packet_payloadtree ( pinfo, message_tvb, opensafety_tree, packet, ett_opensafety_ssdo );
1151 
1152     opensafety_packet_response ( message_tvb, ssdo_tree, packet, isResponse );
1153 
1154     packet->payload.ssdo->sacmd.toggle = ( db0 & OPENSAFETY_SSDO_SACMD_TGL ) == OPENSAFETY_SSDO_SACMD_TGL;
1155     packet->payload.ssdo->sacmd.abort_transfer = ( db0 & OPENSAFETY_SSDO_SACMD_ABRT ) == OPENSAFETY_SSDO_SACMD_ABRT;
1156     packet->payload.ssdo->sacmd.preload = ( db0 & OPENSAFETY_SSDO_SACMD_PRLD ) == OPENSAFETY_SSDO_SACMD_PRLD;
1157     packet->payload.ssdo->sacmd.read_access = ( db0 & OPENSAFETY_SSDO_DOWNLOAD ) == OPENSAFETY_SSDO_DOWNLOAD;
1158     packet->payload.ssdo->sacmd.initiate = ( db0 & OPENSAFETY_SSDO_SACMD_INI ) == OPENSAFETY_SSDO_SACMD_INI;
1159     packet->payload.ssdo->sacmd.segmented = ( db0 & OPENSAFETY_SSDO_SACMD_SEG ) == OPENSAFETY_SSDO_SACMD_SEG;
1160     packet->payload.ssdo->sacmd.end_segment = ( db0 & OPENSAFETY_SSDO_SACMD_ENSG ) == OPENSAFETY_SSDO_SACMD_ENSG;
1161 
1162     if ( isResponse )
1163     {
1164         opensafety_packet_node ( message_tvb, pinfo, ssdo_tree, hf_oss_ssdo_client,
1165                 OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1),
1166                 packet->frame.subframe1, packet->frame.subframe2, sdn );
1167         client = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1);
1168 
1169         if ( packet->scm_udid_valid )
1170         {
1171             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_server, message_tvb, packet->frame.subframe2 + 3, 2, taddr);
1172             server = taddr;
1173         }
1174     }
1175     else if ( ! isResponse )
1176     {
1177         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));
1178         server = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1);
1179         if ( packet->scm_udid_valid )
1180         {
1181             opensafety_packet_node ( message_tvb, pinfo, ssdo_tree, hf_oss_ssdo_client,
1182                     taddr, packet->frame.subframe2 + 3, packet->frame.subframe2, sdn );
1183             client = taddr;
1184         }
1185     }
1186 
1187     /* Toggle bit must be removed, otherwise the values cannot be displayed correctly */
1188     if ( packet->payload.ssdo->sacmd.toggle )
1189         db0 &= (~OPENSAFETY_SSDO_SACMD_TGL);
1190     proto_tree_add_bitmask(ssdo_tree, message_tvb, db0Offset, hf_oss_ssdo_sacmd,
1191             ett_opensafety_ssdo_sacmd, ssdo_sacmd_flags, ENC_NA);
1192 
1193     col_append_fstr(pinfo->cinfo, COL_INFO, ", SACMD: %s", val_to_str_const(db0, opensafety_ssdo_sacmd_values, " "));
1194 
1195     payloadOffset = db0Offset + 1;
1196 
1197     ct = tvb_get_guint8(message_tvb, packet->frame.subframe1 + 3);
1198     if ( packet->scm_udid_valid )
1199     {
1200         ct = (guint16)((tvb_get_guint8(message_tvb, packet->frame.subframe2 + 2) ^ packet->scm_udid[2]) << 8);
1201         ct += (tvb_get_guint8(message_tvb, packet->frame.subframe1 + 3));
1202     }
1203 
1204     proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_sano, message_tvb, packet->frame.subframe1 + 3, 1, ct );
1205 
1206     /* Evaluate preload field [field TR] */
1207     if ( packet->scm_udid_valid && packet->payload.ssdo->sacmd.preload && isResponse )
1208     {
1209         /* Preload info are the higher 6 bit of the TR field */
1210         preload = ( (tvb_get_guint8(message_tvb, packet->frame.subframe2 + 4) ^ packet->scm_udid[4]) & 0xFC ) >> 2;
1211 
1212         if ( packet->payload.ssdo->sacmd.initiate )
1213         {
1214             /* Use the lower 4 bits from the preload as size */
1215             proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_preload_queue, message_tvb, packet->frame.subframe2 + 4, 1,
1216                     preload & 0x0F, "%d", preload & 0x0F );
1217         }
1218         else
1219         {
1220             /* The highest 2 bits of information contain an error flag */
1221             item = proto_tree_add_item(ssdo_tree, hf_oss_ssdo_preload_error, message_tvb, packet->frame.subframe2 + 4, 1, ENC_NA );
1222             if ( (preload & 0x30) == 0x30 )
1223                 proto_item_append_text(item, " (SOD Access Request Number is last successful)" );
1224         }
1225     }
1226 
1227     /* When the following clause is met, DB1,2 contain the SOD index, and DB3 the SOD subindex */
1228     if ( packet->payload.ssdo->sacmd.initiate && !packet->payload.ssdo->sacmd.abort_transfer )
1229     {
1230         ssdoIndex = tvb_get_letohs(message_tvb, db0Offset + 1);
1231         ssdoSubIndex = tvb_get_guint8(message_tvb, db0Offset + 3);
1232 
1233         proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_sod_index, message_tvb, db0Offset + 1, 2,
1234                 ssdoIndex, "0x%04X (%s)", ssdoIndex,
1235                 val_to_str_ext_const(((guint32) (ssdoIndex << 16)), &opensafety_sod_idx_names_ext, "Unknown") );
1236         col_append_fstr(pinfo->cinfo, COL_INFO, " [%s", val_to_str_ext_const(((guint32) (ssdoIndex << 16)), &opensafety_sod_idx_names_ext, "Unknown"));
1237 
1238         /* Some SOD downloads (0x101A for instance) don't have sub-indeces */
1239         if ( ssdoSubIndex != 0x0 )
1240         {
1241             proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_sod_subindex, message_tvb, db0Offset + 3, 1,
1242                 ssdoSubIndex, "0x%02X (%s)", ssdoSubIndex,
1243                 val_to_str_ext_const(((guint32) (ssdoIndex << 16) + ssdoSubIndex), &opensafety_sod_idx_names_ext, "Unknown") );
1244             col_append_fstr(pinfo->cinfo, COL_INFO, " - %s",
1245                     val_to_str_ext_const(((guint32) (ssdoIndex << 16) + ssdoSubIndex), &opensafety_sod_idx_names_ext, "Unknown"));
1246         }
1247         col_append_str(pinfo->cinfo, COL_INFO, "]");
1248         payloadOffset += 3;
1249     }
1250 
1251     if ( packet->payload.ssdo->sacmd.abort_transfer )
1252     {
1253         abortcode = tvb_get_letohl(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 4);
1254 
1255         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,
1256                 "0x%04X %04X - %s", (guint16)(abortcode >> 16), (guint16)(abortcode),
1257                 val_to_str_ext_const(abortcode, &opensafety_abort_codes_ext, "Unknown"));
1258         col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_ext_const(abortcode, &opensafety_abort_codes_ext, "Unknown"));
1259 
1260 
1261     } else {
1262         /* Either the SSDO msg is a response, then data is sent by the server and only in uploads,
1263          * or the message is a request, then data is coming from the client and payload data is
1264          * sent in downloads. Data is only sent in initiate, segmented or end-segment messages */
1265         if ( ( packet->payload.ssdo->sacmd.initiate || packet->payload.ssdo->sacmd.segmented || packet->payload.ssdo->sacmd.end_segment ) &&
1266              ( ( isResponse && !packet->payload.ssdo->sacmd.read_access ) ||
1267                      ( !isResponse && packet->payload.ssdo->sacmd.read_access ) ) )
1268         {
1269             saveFragmented = pinfo->fragmented;
1270             if ( server != 0 && client != 0 )
1271                 fragmentId = (guint32)((((guint32)client) << 16 ) + server );
1272 
1273             /* If payload data has to be calculated, either a total size is given, or not */
1274             if ( packet->payload.ssdo->sacmd.segmented && packet->payload.ssdo->sacmd.initiate )
1275             {
1276 
1277                 payloadOffset += 4;
1278 
1279                 /* reading real size */
1280                 payloadSize = tvb_get_letohl(message_tvb, payloadOffset - 4);
1281 
1282                 calcDataLength = dataLength - (payloadOffset - db0Offset);
1283 
1284                 item = proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_payload_size, message_tvb, payloadOffset - 4, 4,
1285                         payloadSize, "%d octets total (%d octets in this frame)", payloadSize, calcDataLength);
1286 
1287                 if ( calcDataLength >= 0 )
1288                 {
1289                     if ( fragmentId != 0 && packet->payload.ssdo->sacmd.segmented )
1290                     {
1291                         pinfo->fragmented = TRUE;
1292                         frag_msg = fragment_add_seq_check(&os_reassembly_table, message_tvb, payloadOffset, pinfo,
1293                                                           fragmentId, NULL, 0, calcDataLength, TRUE );
1294                         fragment_add_seq_offset ( &os_reassembly_table, pinfo, fragmentId, NULL, ct );
1295 
1296                         if ( frag_msg != NULL )
1297                         {
1298                             item = proto_tree_add_bytes_format_value(ssdo_tree, hf_oss_ssdo_payload, message_tvb, 0, 0, NULL, "Reassembled" );
1299                             proto_item_set_generated(item);
1300 
1301                             ssdo_payload = proto_item_add_subtree(item, ett_opensafety_ssdo_payload);
1302                             process_reassembled_data(message_tvb, 0, pinfo, "Reassembled Message", frag_msg, &oss_frag_items, NULL, ssdo_payload );
1303                         }
1304                     }
1305 
1306                     proto_tree_add_item(ssdo_tree, hf_oss_ssdo_payload, message_tvb, payloadOffset, calcDataLength, ENC_NA );
1307                 } else {
1308                     if ( global_opensafety_debug_verbose )
1309                         expert_add_info_format(pinfo, item, &ei_payload_length_not_positive,
1310                                                     "Calculation for payload length yielded non-positive result [%d]", (guint) calcDataLength );
1311                 }
1312             }
1313             else
1314             {
1315                 payloadSize = dataLength - (payloadOffset - db0Offset);
1316                 if ((gint)dataLength < (payloadOffset - db0Offset))
1317                 {
1318                     if ( global_opensafety_debug_verbose )
1319                         expert_add_info_format(pinfo, opensafety_item, &ei_payload_length_not_positive,
1320                                                     "Calculation for payload length yielded non-positive result [%d]", (gint)payloadSize );
1321                     return;
1322                 }
1323 
1324                 if ( fragmentId != 0 && packet->payload.ssdo->sacmd.segmented )
1325                 {
1326                     pinfo->fragmented = TRUE;
1327 
1328                     frag_msg = fragment_add_seq_check(&os_reassembly_table, message_tvb, payloadOffset, pinfo,
1329                                                       fragmentId, NULL, ct, payloadSize,
1330                                                       packet->payload.ssdo->sacmd.end_segment ? FALSE : TRUE );
1331                 }
1332 
1333                 if ( frag_msg )
1334                 {
1335                     item = proto_tree_add_bytes_format_value(ssdo_tree, hf_oss_ssdo_payload, message_tvb,
1336                                                              0, 0, NULL, "Reassembled" );
1337                     proto_item_set_generated(item);
1338                     ssdo_payload = proto_item_add_subtree(item, ett_opensafety_ssdo_payload);
1339 
1340                     new_tvb = process_reassembled_data(message_tvb, 0, pinfo, "Reassembled Message", frag_msg,
1341                                                        &oss_frag_items, NULL, ssdo_payload );
1342                     if ( packet->payload.ssdo->sacmd.end_segment && new_tvb )
1343                     {
1344                         item = proto_tree_add_uint_format_value(ssdo_payload, hf_oss_ssdo_payload_size, message_tvb, 0, 0,
1345                                                                 payloadSize, "%d octets (over all fragments)", frag_msg->len);
1346                         proto_item_set_generated(item);
1347 
1348                         col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)" );
1349                         dissect_opensafety_ssdo_payload ( pinfo, new_tvb, ssdo_payload, db0 );
1350                     }
1351                 }
1352                 else
1353                 {
1354                     item = proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_payload_size, message_tvb, 0, 0, payloadSize,
1355                             "%d octets", payloadSize);
1356                     proto_item_set_generated(item);
1357 
1358                     if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x06 )
1359                     {
1360                         proto_tree_add_item( ssdo_tree, hf_oss_sod_par_timestamp, message_tvb, payloadOffset, 4, ENC_LITTLE_ENDIAN );
1361                         for ( n = 4; n < payloadSize; n+=4 )
1362                         {
1363                             entry = tvb_get_letohl ( message_tvb, payloadOffset + n );
1364                             proto_tree_add_uint_format_value ( ssdo_tree, hf_oss_sod_par_checksum, message_tvb, (payloadOffset + n ),
1365                                     4, entry, "[#%d] 0x%08X", ( n / 4 ), entry );
1366                         }
1367                     } else if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x07 ) {
1368                         proto_tree_add_item ( ssdo_tree, hf_oss_sod_par_timestamp, message_tvb, payloadOffset, 4, ENC_LITTLE_ENDIAN );
1369                     } else
1370                         proto_tree_add_item(ssdo_tree, hf_oss_ssdo_payload, message_tvb, payloadOffset, payloadSize, ENC_NA );
1371                 }
1372             }
1373 
1374             pinfo->fragmented = saveFragmented;
1375         }
1376     }
1377 }
1378 
1379 static void
opensafety_parse_scm_udid(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,opensafety_packet_info * packet,guint offset)1380 opensafety_parse_scm_udid ( tvbuff_t* tvb, packet_info *pinfo, proto_tree *tree,
1381         opensafety_packet_info *packet, guint offset )
1382 {
1383     proto_item * item = NULL;
1384     gchar      *scm_udid_test = NULL;
1385 
1386     item = proto_tree_add_item(tree, hf_oss_snmt_udid, tvb, offset, 6, ENC_NA);
1387 
1388     scm_udid_test = tvb_bytes_to_str_punct(pinfo->pool, tvb, offset, 6, ':' );
1389 
1390     if ( scm_udid_test != NULL && strlen( scm_udid_test ) == 17 )
1391     {
1392         if ( g_strcmp0("00:00:00:00:00:00", scm_udid_test ) != 0 )
1393         {
1394             packet->payload.snmt->scm_udid = scm_udid_test;
1395 
1396             if ( ( global_scm_udid_autoset == TRUE ) &&  ( memcmp ( global_scm_udid, scm_udid_test, 17 ) != 0 ) )
1397             {
1398                 if ( local_scm_udid == NULL || memcmp ( local_scm_udid, scm_udid_test, 17 ) != 0 )
1399                 {
1400                     local_scm_udid = wmem_strdup(wmem_file_scope(), scm_udid_test );
1401                     if ( global_opensafety_debug_verbose )
1402                         expert_add_info_format(pinfo, item, &ei_scmudid_autodetected,
1403                                 "Auto detected payload as SCM UDID [%s].", local_scm_udid);
1404                 }
1405             }
1406         }
1407     }
1408 }
1409 
1410 static void
dissect_opensafety_snmt_message(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * opensafety_tree,opensafety_packet_info * packet,proto_item * opensafety_item)1411 dissect_opensafety_snmt_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *opensafety_tree,
1412         opensafety_packet_info *packet, proto_item * opensafety_item )
1413 {
1414     proto_tree *snmt_tree;
1415     guint16     addr, taddr, sdn;
1416     guint8      db0, byte, errcode;
1417     guint       dataLength;
1418 
1419     dataLength = OSS_FRAME_LENGTH_T(message_tvb, packet->frame.subframe1);
1420 
1421     /* addr is the first field, as well as the recipient of the message */
1422     addr = packet->saddr;
1423 
1424     /* taddr is the 4th octet in the second frame */
1425     taddr = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe2 + 3);
1426     /* domain is xor'ed on the first field in the second frame. As this is also addr, it is easy to obtain */
1427     sdn = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe2) ^ addr;
1428     packet->sdn = sdn;
1429 
1430     db0 = -1;
1431     if (dataLength > 0)
1432         db0 = tvb_get_guint8(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA);
1433 
1434     packet->msg_id = OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1);
1435 
1436     if ( ( packet->msg_id == OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE ) &&
1437          ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP) == 0 ||
1438            (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP) == 0 ) )
1439     {
1440         opensafety_packet_receiver( message_tvb, pinfo, opensafety_tree, opensafety_item, packet, addr,
1441                 OSS_FRAME_POS_ADDR + packet->frame.subframe1, packet->frame.subframe2, sdn );
1442     }
1443     else
1444     {
1445         opensafety_packet_sendreceiv ( message_tvb, pinfo, opensafety_tree, opensafety_item, packet, taddr,
1446                 packet->frame.subframe2 + 3, addr, OSS_FRAME_POS_ADDR + packet->frame.subframe1,
1447                 packet->frame.subframe2, sdn );
1448     }
1449 
1450     snmt_tree = opensafety_packet_payloadtree ( pinfo, message_tvb, opensafety_tree, packet, ett_opensafety_snmt );
1451     /* Just a precaution, cause payloadtree actually sets the snmt pointer */
1452     if ( packet->payload.snmt == NULL )
1453         return;
1454 
1455     if ( ( packet->msg_id == OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE ) ||
1456          ( packet->msg_id == OPENSAFETY_MSG_SNMT_SERVICE_REQUEST ) )
1457         packet->payload.snmt->ext_msg_id = db0;
1458 
1459     opensafety_packet_response(message_tvb, snmt_tree, packet, ( packet->msg_id & 0x04 ) == 0x04 );
1460 
1461     if ( packet->is_request )
1462     {
1463         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, packet->frame.subframe2 + 3, 2, taddr);
1464         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, OSS_FRAME_POS_ADDR + packet->frame.subframe1, 2, addr);
1465     }
1466     else
1467     {
1468         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, OSS_FRAME_POS_ADDR + packet->frame.subframe1, 2, addr);
1469         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, packet->frame.subframe2 + 3, 2, taddr);
1470     }
1471 
1472     /* Handle Acknowledge and Fail specifically */
1473     if ( ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE) == 0 ) || ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 )
1474     {
1475         byte = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1);
1476 
1477         /* Handle a normal SN Fail */
1478         if ( byte != OPENSAFETY_ERROR_GROUP_ADD_PARAMETER )
1479         {
1480             if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 )
1481             {
1482                 proto_tree_add_uint(snmt_tree, hf_oss_snmt_service_id, message_tvb,
1483                         OSS_FRAME_POS_DATA + packet->frame.subframe1, 1, packet->payload.snmt->ext_msg_id);
1484                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1485                         val_to_str_const(packet->payload.snmt->ext_msg_id, opensafety_message_service_type, "Unknown"));
1486             }
1487             else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE) == 0 )
1488             {
1489                 proto_tree_add_uint(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1, 1, db0);
1490                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(db0, opensafety_message_service_type, "Unknown"));
1491             }
1492 
1493             proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_error_group, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1, 1,
1494                     byte, "%s", ( byte == 0 ? "Device" : val_to_str(byte, opensafety_sn_fail_error_group, "Reserved [%d]" ) ) );
1495 
1496             errcode = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 2);
1497             proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_error_code, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 2, 1,
1498                     errcode, "%s [%d]", ( errcode == 0 ? "Default" : "Vendor Specific" ), errcode );
1499 
1500             col_append_fstr(pinfo->cinfo, COL_INFO, " - Group: %s; Code: %s",
1501                 ( byte == 0 ? "Device" : val_to_str(byte, opensafety_sn_fail_error_group, "Reserved [%d]" ) ),
1502                 ( errcode == 0 ? "Default" : "Vendor Specific" )
1503             );
1504 
1505             packet->payload.snmt->add_param.exists = FALSE;
1506             packet->payload.snmt->error_code = errcode;
1507         }
1508         else
1509         {
1510             if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 )
1511             {
1512                 proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1, 1,
1513                         packet->payload.snmt->ext_msg_id, "%s [Request via SN Fail] (0x%02X)",
1514                         val_to_str_const(byte, opensafety_sn_fail_error_group, "Unknown"), packet->payload.snmt->ext_msg_id);
1515                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(byte, opensafety_sn_fail_error_group, "Unknown"));
1516             } else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE) == 0 )
1517             {
1518                 proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1, 1,
1519                         packet->payload.snmt->ext_msg_id, "Additional parameter missing [Response via SN Acknowledge] (0x%02X)", packet->payload.snmt->ext_msg_id);
1520                 col_append_str(pinfo->cinfo, COL_INFO, ", Additional parameter missing");
1521             }
1522 
1523             errcode = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 2);
1524             packet->payload.snmt->add_param.exists = TRUE;
1525             packet->payload.snmt->add_param.id = errcode;
1526             packet->payload.snmt->add_param.set = ( errcode & 0x0F ) + 1;
1527             packet->payload.snmt->add_param.full = ( ( errcode & 0xF0 ) == 0xF0 );
1528 
1529             /* Handle an additional parameter request */
1530             proto_tree_add_uint(snmt_tree, hf_oss_ssdo_extpar_parset, message_tvb,
1531                     OSS_FRAME_POS_DATA + packet->frame.subframe1 + 2, 1, ( errcode & 0x0F ) + 1 );
1532 
1533             proto_tree_add_boolean(snmt_tree, hf_oss_snmt_param_type, message_tvb,
1534                     OSS_FRAME_POS_DATA + packet->frame.subframe1 + 2, 1, ( ( errcode & 0xF0 ) != 0xF0 ) );
1535         }
1536     }
1537     else if ( (OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) ^ OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE) == 0 )
1538     {
1539         proto_tree_add_uint(snmt_tree, hf_oss_snmt_service_id, message_tvb,
1540                 OSS_FRAME_POS_DATA + packet->frame.subframe1, 1, packet->payload.snmt->ext_msg_id);
1541         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
1542                 val_to_str_const(packet->payload.snmt->ext_msg_id, opensafety_message_service_type, "Unknown"));
1543 
1544         if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_UDID_SCM) == 0 )
1545         {
1546             opensafety_parse_scm_udid ( message_tvb, pinfo, snmt_tree, packet, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1 );
1547         }
1548         else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_ADDITIONAL_SADR) == 0 )
1549         {
1550             packet->payload.snmt->add_saddr.actual = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1);
1551             proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addsaddr, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1, 2,
1552                     packet->payload.snmt->add_saddr.actual );
1553 
1554             packet->payload.snmt->add_saddr.additional = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 3);
1555             proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addtxspdo, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 3, 2,
1556                     packet->payload.snmt->add_saddr.additional);
1557 
1558             col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%04X => 0x%04X]",
1559                     OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1),
1560                     OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 3));
1561         }
1562         else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_ASSIGNED_INIT_CT) == 0 )
1563         {
1564             packet->payload.snmt->init_ct =
1565                     tvb_get_guint40(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1, ENC_BIG_ENDIAN);
1566             proto_tree_add_item(snmt_tree, hf_oss_snmt_ext_initct, message_tvb,
1567                     packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1, 5, ENC_BIG_ENDIAN );
1568         }
1569     }
1570     else if ( (OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) ^ OPENSAFETY_MSG_SNMT_SERVICE_REQUEST) == 0 )
1571     {
1572         proto_tree_add_uint(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1, 1, db0);
1573         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(db0, opensafety_message_service_type, "Unknown"));
1574 
1575         if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP) == 0 || (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP) == 0 )
1576         {
1577             proto_tree_add_uint(snmt_tree, hf_oss_snmt_scm, message_tvb, OSS_FRAME_POS_ADDR + packet->frame.subframe1, 2, addr);
1578             proto_tree_add_uint(snmt_tree, hf_oss_snmt_tool, message_tvb, packet->frame.subframe2 + 3, 2, taddr);
1579         }
1580         else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGN_UDID_SCM) == 0 )
1581         {
1582             opensafety_parse_scm_udid ( message_tvb, pinfo, snmt_tree, packet, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1 );
1583         }
1584         else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_ASSIGN_INIT_CT) == 0 )
1585         {
1586             packet->payload.snmt->init_ct =
1587                     tvb_get_guint40(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1, ENC_BIG_ENDIAN);
1588             proto_tree_add_item(snmt_tree, hf_oss_snmt_ext_initct, message_tvb,
1589                     packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1, 5, ENC_BIG_ENDIAN );
1590         }
1591         else
1592         {
1593             if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_OP) == 0 )
1594             {
1595                 proto_tree_add_item ( snmt_tree, hf_oss_sod_par_timestamp, message_tvb,
1596                         OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1, 4, ENC_LITTLE_ENDIAN );
1597             }
1598             else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_ASSIGN_ADDITIONAL_SADR) == 0 )
1599             {
1600                 packet->payload.snmt->add_saddr.actual = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1);
1601                 proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addsaddr, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1, 2,
1602                         packet->payload.snmt->add_saddr.actual );
1603 
1604                 packet->payload.snmt->add_saddr.additional = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 3);
1605                 proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addtxspdo, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 3, 2,
1606                         packet->payload.snmt->add_saddr.additional);
1607 
1608                 col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%04X => 0x%04X]",
1609                         OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 1),
1610                         OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1 + OSS_FRAME_POS_DATA + 3));
1611             }
1612 
1613         }
1614     }
1615     else if ( (OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) ^ OPENSAFETY_MSG_SNMT_SADR_ASSIGNED) == 0 ||
1616             (OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) ^ OPENSAFETY_MSG_SNMT_ASSIGN_SADR) == 0 ||
1617             (OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) ^ OPENSAFETY_MSG_SNMT_RESPONSE_UDID) == 0 )
1618     {
1619         if (dataLength > 0)
1620         {
1621             packet->payload.snmt->sn_udid = wmem_strdup(pinfo->pool,
1622                     tvb_bytes_to_str_punct(pinfo->pool, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1 + 1, 6, ':' ) );
1623             proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + packet->frame.subframe1, 6, ENC_NA);
1624         }
1625     }
1626 }
1627 
1628 static gboolean
dissect_opensafety_checksum(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * opensafety_tree,opensafety_packet_info * packet)1629 dissect_opensafety_checksum(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *opensafety_tree,
1630                             opensafety_packet_info *packet )
1631 {
1632     guint16     frame1_crc, frame2_crc;
1633     guint16     calc1_crc, calc2_crc;
1634     guint       dataLength, frame2Length;
1635     guint8     *bytesf2, *bytesf1, ctr = 0, crcType = OPENSAFETY_CHECKSUM_CRC8;
1636     proto_item *item;
1637     proto_tree *checksum_tree;
1638     gint        start;
1639     gint        length;
1640     gboolean    isSlim = FALSE;
1641     gboolean    isSNMT = FALSE;
1642     gboolean    isSPDO = FALSE;
1643     GByteArray *scmUDID = NULL;
1644 
1645     dataLength = OSS_FRAME_LENGTH_T(message_tvb, packet->frame.subframe1);
1646     start = OSS_FRAME_POS_DATA + dataLength + packet->frame.subframe1;
1647 
1648     if (OSS_FRAME_LENGTH_T(message_tvb, packet->frame.subframe1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
1649         frame1_crc = tvb_get_letohs(message_tvb, start);
1650     else
1651         frame1_crc = tvb_get_guint8(message_tvb, start);
1652 
1653     if ( packet->msg_type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
1654         isSlim = TRUE;
1655     if ( packet->msg_type == OPENSAFETY_SNMT_MESSAGE_TYPE )
1656         isSNMT = TRUE;
1657     if ( packet->msg_type == OPENSAFETY_SPDO_MESSAGE_TYPE )
1658         isSPDO = TRUE;
1659 
1660     frame2Length = (isSlim ? 0 : dataLength) + 5;
1661 
1662     length = (dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? OPENSAFETY_CHECKSUM_CRC16 : OPENSAFETY_CHECKSUM_CRC8);
1663     item = proto_tree_add_uint_format(opensafety_tree, hf_oss_crc, message_tvb, start, length, frame1_crc,
1664                                       "CRC for subframe #1: 0x%04X", frame1_crc);
1665 
1666     checksum_tree = proto_item_add_subtree(item, ett_opensafety_checksum);
1667 
1668     bytesf1 = (guint8*)tvb_memdup(pinfo->pool, message_tvb, packet->frame.subframe1, dataLength + 4);
1669 
1670     crcType = packet->crc.type;
1671     calc1_crc = packet->crc.frame1;
1672 
1673     if ( ! isSlim && crcType == OPENSAFETY_CHECKSUM_CRC16SLIM )
1674         expert_add_info(pinfo, item, &ei_crc_slimssdo_instead_of_spdo );
1675 
1676     item = proto_tree_add_boolean(checksum_tree, hf_oss_crc_valid, message_tvb,
1677             packet->frame.subframe1, dataLength + 4, (frame1_crc == calc1_crc));
1678     proto_item_set_generated(item);
1679     if ( crcType == OPENSAFETY_CHECKSUM_INVALID || frame1_crc != calc1_crc )
1680         expert_add_info(pinfo, item, &ei_crc_frame_1_invalid );
1681 
1682     /* using the defines, as the values can change */
1683     proto_tree_add_uint(checksum_tree, hf_oss_crc_type, message_tvb, start, length, crcType );
1684 
1685     start = packet->frame.subframe2 + (isSlim ? 5 : dataLength + OSS_FRAME_POS_DATA + 1 );
1686     if (OSS_FRAME_LENGTH_T(message_tvb, packet->frame.subframe1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
1687         frame2_crc = tvb_get_letohs(message_tvb, start);
1688     else
1689         frame2_crc = tvb_get_guint8(message_tvb, start);
1690 
1691     /* 0xFFFF is an invalid CRC16 value, therefore valid for initialization. Needed, because
1692      * otherwise this function may return without setting calc2_crc, and this does not go well
1693      * with the compiler */
1694     calc2_crc = 0xFFFF;
1695 
1696     /* Currently SPDO 40 Bit CRC2 support is broken. Will be implemented at a later state, after
1697      * the first generation of openSAFETY devices using 40 bit counter are available */
1698     if ( isSPDO && packet->payload.spdo->flags.enabled40bit == TRUE )
1699         packet->scm_udid_valid = FALSE;
1700 
1701     /* This used to be an option. But only, because otherwise there would be three different
1702      * crc calculations taking place within dissection. As we could reduce this by one, the
1703      * global option has been changed to the simple validity question, if we have enough information
1704      * to calculate the second crc, meaning, if the SCM udid is known, or if we have an SNMT msg */
1705     if ( isSNMT || packet->scm_udid_valid )
1706     {
1707         bytesf2 = (guint8*)tvb_memdup(pinfo->pool, message_tvb, packet->frame.subframe2, frame2Length + length);
1708 
1709         /* SLIM SSDO messages, do not contain a payload in frame2 */
1710         if ( isSlim == TRUE )
1711             dataLength = 0;
1712 
1713         scmUDID = g_byte_array_new();
1714         packet->crc.valid2 = FALSE;
1715         if ( isSNMT || ( hex_str_to_bytes((local_scm_udid != NULL ? local_scm_udid : global_scm_udid), scmUDID, TRUE) && scmUDID->len == 6 ) )
1716         {
1717             if ( !isSNMT )
1718             {
1719                 for ( ctr = 0; ctr < 6; ctr++ )
1720                     bytesf2[ctr] = bytesf2[ctr] ^ (guint8)(scmUDID->data[ctr]);
1721                 if ( isSPDO )
1722                 {
1723 
1724                     /* allow only valid SPDO flags */
1725                     if ( packet->msg_id == OPENSAFETY_MSG_SPDO_DATA_ONLY )
1726                     {
1727                         if ( packet->payload.spdo->flags.enabled40bit == TRUE )
1728                         {
1729                             /* we assume the OPENSAFETY_DEFAULT_DOMAIN (0x01) for 40 bit for now */
1730                             bytesf2[0] = bytesf2[0] ^ (bytesf2[0] ^ OPENSAFETY_DEFAULT_DOMAIN ^ bytesf1[0]);
1731                             bytesf2[1] = bytesf2[1] ^ (bytesf2[1] ^ bytesf1[1]);
1732                             bytesf2[3] = 0;
1733                         }
1734                     }
1735                 }
1736 
1737                 if ( isSlim || packet->frame.length == 11 )
1738                     frame2_crc ^= ((guint8)scmUDID->data[5]);
1739 
1740                 /*
1741                  * If the second frame is 6 or 7 (slim) bytes in length, we have to decode the found
1742                  * frame crc again. This must be done using the byte array, as the unxor operation
1743                  * had to take place.
1744                  */
1745                 if ( dataLength == 0 )
1746                 {
1747                     if ( isSlim && length == 2 )
1748                         frame2_crc = ( bytesf2[6] << 8 ) + bytesf2[5];
1749                 }
1750 
1751             }
1752 
1753             item = proto_tree_add_uint_format(opensafety_tree, hf_oss_crc, message_tvb, start, length, frame2_crc,
1754                     "CRC for subframe #2: 0x%04X", frame2_crc);
1755 
1756             checksum_tree = proto_item_add_subtree(item, ett_opensafety_checksum);
1757 
1758             if ( OSS_FRAME_LENGTH_T(message_tvb, packet->frame.subframe1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
1759             {
1760                 calc2_crc = crc16_0x755B(bytesf2, frame2Length, 0);
1761                 if ( frame2_crc != calc2_crc )
1762                     calc2_crc = crc16_0x5935(bytesf2, frame2Length, 0);
1763             }
1764             else
1765                 calc2_crc = crc8_0x2F(bytesf2, frame2Length, 0);
1766 
1767             item = proto_tree_add_boolean(checksum_tree, hf_oss_crc2_valid, message_tvb,
1768                     packet->frame.subframe2, frame2Length, (frame2_crc == calc2_crc));
1769             proto_item_set_generated(item);
1770 
1771             if ( frame2_crc != calc2_crc )
1772             {
1773                 item = proto_tree_add_uint_format(checksum_tree, hf_oss_crc, message_tvb,
1774                         packet->frame.subframe2, frame2Length, calc2_crc, "Calculated CRC: 0x%04X", calc2_crc);
1775                 proto_item_set_generated(item);
1776                 expert_add_info(pinfo, item, &ei_crc_frame_2_invalid );
1777             }
1778             else
1779             {
1780                 if ( global_opensafety_debug_verbose && ( isSlim || ( !isSNMT && packet->frame.length == 11 ) ) )
1781                     expert_add_info(pinfo, item, &ei_crc_frame_2_scm_udid_encoded );
1782 
1783                 packet->crc.valid2 = TRUE;
1784             }
1785         }
1786         else
1787             expert_add_info(pinfo, item, &ei_crc_frame_2_unknown_scm_udid );
1788 
1789         g_byte_array_free(scmUDID, TRUE);
1790     }
1791 
1792     /* For a correct calculation of the second crc we need to know the scm udid.
1793      * If the dissection of the second frame has been triggered, we integrate the
1794      * crc for frame2 into the result */
1795     return (gboolean) (frame1_crc == calc1_crc) &&
1796             ( ( isSNMT || packet->scm_udid_valid ) == TRUE ? (frame2_crc == calc2_crc) : TRUE);
1797 }
1798 
1799 static gint
check_scmudid_validity(opensafety_packet_info * packet,tvbuff_t * message_tvb)1800 check_scmudid_validity(opensafety_packet_info *packet, tvbuff_t *message_tvb)
1801 {
1802     guint8      b_ID, spdoFlags, udidLen;
1803     GByteArray *scmUDID = NULL;
1804 
1805     packet->scm_udid_valid = FALSE;
1806     scmUDID = g_byte_array_new();
1807 
1808     if ( hex_str_to_bytes((local_scm_udid != NULL ? local_scm_udid : global_scm_udid), scmUDID, TRUE) && scmUDID->len == 6 )
1809     {
1810         packet->scm_udid_valid = TRUE;
1811 
1812         /* Now confirm, that the xor operation was successful. The ID fields of both frames have to be the same */
1813         b_ID = tvb_get_guint8(message_tvb, packet->frame.subframe2 + 1) ^ (guint8)(scmUDID->data[OSS_FRAME_POS_ID]);;
1814         if ( ( OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) ^ b_ID ) != 0 )
1815             packet->scm_udid_valid = FALSE;
1816 
1817         /* The IDs do not match, but the SCM UDID could still be ok. This happens, if this packet
1818          * utilizes the 40 bit counter. Therefore we reduce the check here only to the feature
1819          * flags, but only if the package is a SPDO Data Only (because everything else uses 16 bit. */
1820         if ( packet->msg_id == OPENSAFETY_MSG_SPDO_DATA_ONLY )
1821         {
1822             spdoFlags = ( tvb_get_guint8(message_tvb, packet->frame.subframe2 + 4 ) ^ scmUDID->data[4] ) ;
1823             spdoFlags = ( spdoFlags >> 2 ) & OPENSAFETY_SPDO_FEATURE_FLAGS;
1824             if ( ( spdoFlags & OPENSAFETY_SPDO_FEAT_40BIT_USED ) == OPENSAFETY_SPDO_FEAT_40BIT_USED )
1825                 packet->scm_udid_valid = TRUE;
1826         }
1827 
1828         if ( packet->scm_udid_valid == TRUE )
1829             memcpy(packet->scm_udid, scmUDID->data, 6);
1830     }
1831 
1832     udidLen = scmUDID->len;
1833 
1834     g_byte_array_free( scmUDID, TRUE);
1835 
1836     return udidLen;
1837 }
1838 
1839 static gboolean
dissect_opensafety_message(opensafety_packet_info * packet,tvbuff_t * message_tvb,packet_info * pinfo,proto_item * opensafety_item,proto_tree * opensafety_tree,guint8 u_nrInPackage,guint8 previous_msg_id)1840 dissect_opensafety_message(opensafety_packet_info *packet,
1841                            tvbuff_t *message_tvb, packet_info *pinfo,
1842                            proto_item *opensafety_item, proto_tree *opensafety_tree,
1843                            guint8 u_nrInPackage, guint8 previous_msg_id)
1844 {
1845     guint8      ctr, udidLen;
1846     proto_item *item;
1847     gboolean    messageTypeUnknown, crcValid;
1848 
1849     messageTypeUnknown = FALSE;
1850 
1851     for ( ctr = 0; ctr < 6; ctr++ )
1852         packet->scm_udid[ctr] = 0;
1853 
1854     packet->saddr = OSS_FRAME_ADDR_T(message_tvb, packet->frame.subframe1);
1855     /* Sender / Receiver is determined by message type */
1856     packet->sender = 0;
1857     packet->receiver = 0;
1858 
1859     /* SPDO is handled below */
1860     if ( packet->msg_type != OPENSAFETY_SPDO_MESSAGE_TYPE )
1861     {
1862         col_append_fstr(pinfo->cinfo, COL_INFO, (u_nrInPackage > 1 ? " | %s" : "%s" ),
1863             val_to_str(packet->msg_id, opensafety_message_type_values, "Unknown Message (0x%02X) "));
1864     }
1865 
1866     item = proto_tree_add_uint(opensafety_tree, hf_oss_byte_offset, packet->frame.frame_tvb, 0, 1, packet->frame.byte_offset);
1867     proto_item_set_generated(item);
1868 
1869     if ( packet->msg_type == OPENSAFETY_SNMT_MESSAGE_TYPE )
1870     {
1871         proto_item_append_text(opensafety_item, ", SNMT");
1872         dissect_opensafety_snmt_message ( message_tvb, pinfo, opensafety_tree, packet, opensafety_item );
1873     }
1874     else
1875     {
1876         udidLen = check_scmudid_validity(packet, message_tvb);
1877 
1878         if ( strlen( (local_scm_udid != NULL ? local_scm_udid : global_scm_udid) ) > 0  && udidLen == 6 )
1879         {
1880             if ( local_scm_udid != NULL )
1881             {
1882                 item = proto_tree_add_string(opensafety_tree, hf_oss_scm_udid_auto, message_tvb, 0, 0, local_scm_udid);
1883                 if ( ! packet->scm_udid_valid )
1884                     expert_add_info(pinfo, item, &ei_message_id_field_mismatch );
1885             }
1886             else
1887                 item = proto_tree_add_string(opensafety_tree, hf_oss_scm_udid, message_tvb, 0, 0, global_scm_udid);
1888             proto_item_set_generated(item);
1889         }
1890 
1891         item = proto_tree_add_boolean(opensafety_tree, hf_oss_scm_udid_valid, message_tvb, 0, 0, packet->scm_udid_valid);
1892         if ( udidLen != 6 )
1893             expert_add_info(pinfo, item, &ei_scmudid_invalid_preference );
1894         proto_item_set_generated(item);
1895 
1896         if ( packet->msg_type == OPENSAFETY_SSDO_MESSAGE_TYPE || packet->msg_type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
1897         {
1898             proto_item_append_text(opensafety_item,
1899                     (packet->msg_type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE) ? ", Slim SSDO" : ", SSDO");
1900             dissect_opensafety_ssdo_message ( message_tvb, pinfo, opensafety_tree, packet, opensafety_item );
1901         }
1902         else if ( packet->msg_type == OPENSAFETY_SPDO_MESSAGE_TYPE )
1903         {
1904             proto_item_append_text(opensafety_item, ", SPDO" );
1905             dissect_opensafety_spdo_message ( message_tvb, pinfo, opensafety_tree, packet, opensafety_item );
1906 
1907             /* Now we know packet->sender, therefore we can add the info text */
1908             if ( previous_msg_id != packet->msg_id )
1909             {
1910                 col_append_fstr(pinfo->cinfo, COL_INFO, (u_nrInPackage > 1 ? " | %s - 0x%03X" : "%s - 0x%03X" ),
1911                             val_to_str(packet->msg_id, opensafety_message_type_values, "Unknown Message (0x%02X) "),
1912                             packet->sender );
1913             } else {
1914                 col_append_fstr(pinfo->cinfo, COL_INFO, ", 0x%03X", packet->sender );
1915             }
1916         }
1917         else
1918         {
1919             messageTypeUnknown = TRUE;
1920             proto_item_append_text(opensafety_item, ", Unknown" );
1921         }
1922     }
1923 
1924     crcValid = FALSE;
1925     item = proto_tree_add_uint(opensafety_tree, hf_oss_length,
1926                                message_tvb, OSS_FRAME_POS_LEN + packet->frame.subframe1, 1,
1927                                OSS_FRAME_LENGTH_T(message_tvb, packet->frame.subframe1));
1928     if ( messageTypeUnknown )
1929     {
1930         expert_add_info(pinfo, item, &ei_message_unknown_type );
1931     }
1932     else
1933     {
1934         crcValid = dissect_opensafety_checksum ( message_tvb, pinfo, opensafety_tree, packet );
1935     }
1936 
1937     /* with SNMT's we can check if the ID's for the frames match. Rare randomized packages do have
1938      * an issue, where an frame 1 can be valid. The id's for both frames must differ, as well as
1939      * the addresses, but addresses won't be checked yet, as there are issues with SDN xored on it. */
1940     if ( crcValid && packet->msg_type == OPENSAFETY_SNMT_MESSAGE_TYPE )
1941     {
1942         if ( OSS_FRAME_ID_T(message_tvb, packet->frame.subframe1) != OSS_FRAME_ID_T(message_tvb, packet->frame.subframe2) )
1943             expert_add_info(pinfo, opensafety_item, &ei_crc_frame_1_valid_frame2_invalid );
1944     }
1945 
1946     return TRUE;
1947 }
1948 
1949 static gboolean
opensafety_package_dissector(const gchar * protocolName,const gchar * sub_diss_handle,gboolean b_frame2First,gboolean do_byte_swap,guint8 force_nr_in_package,tvbuff_t * given_tvb,packet_info * pinfo,proto_tree * tree,guint8 transporttype)1950 opensafety_package_dissector(const gchar *protocolName, const gchar *sub_diss_handle,
1951                              gboolean b_frame2First, gboolean do_byte_swap, guint8 force_nr_in_package,
1952                              tvbuff_t *given_tvb, packet_info *pinfo, proto_tree *tree, guint8 transporttype )
1953 {
1954     tvbuff_t           *next_tvb = NULL, *gap_tvb = NULL, *message_tvb = NULL;
1955     guint               length, len, frameOffset, frameLength, nodeAddress, gapStart;
1956     guint8             *swbytes;
1957     gboolean            handled, dissectorCalled, call_sub_dissector, markAsMalformed;
1958     guint8              type, found, i, tempByte, previous_msg_id;
1959     guint16             frameStart1, frameStart2, byte_offset;
1960     gint                reported_len;
1961     dissector_handle_t  protocol_dissector = NULL;
1962     proto_item         *opensafety_item;
1963     proto_tree         *opensafety_tree;
1964 
1965     opensafety_packet_info *packet = NULL;
1966 
1967     handled            = FALSE;
1968     dissectorCalled    = FALSE;
1969     call_sub_dissector = FALSE;
1970     markAsMalformed    = FALSE;
1971     previous_msg_id    = 0;
1972 
1973     /* registering frame end routine, to prevent a malformed dissection preventing
1974      * further dissector calls (see bug #6950) */
1975     register_frame_end_routine(pinfo, reset_dissector);
1976 
1977     length = tvb_reported_length(given_tvb);
1978     /* Minimum package length is 11 */
1979     if ( length < OSS_MINIMUM_LENGTH )
1980         return FALSE;
1981 
1982     /* Determine dissector handle for sub-dissection */
1983     if ( strlen( sub_diss_handle ) > 0 )
1984     {
1985         call_sub_dissector = TRUE;
1986         protocol_dissector = find_dissector ( sub_diss_handle );
1987         if ( protocol_dissector == NULL )
1988             protocol_dissector = data_dissector;
1989     }
1990 
1991     reported_len = tvb_reported_length_remaining(given_tvb, 0);
1992 
1993     /* This will swap the bytes according to MBTCP encoding */
1994     if ( do_byte_swap == TRUE && global_mbtcp_big_endian == TRUE )
1995     {
1996         /* Because of padding bytes at the end of the frame, tvb_memdup could lead
1997          * to a "openSAFETY truncated" message. By ensuring, that we have enough
1998          * bytes to copy, this will be prevented. */
1999         if ( ! tvb_bytes_exist ( given_tvb, 0, length ) )
2000             return FALSE;
2001 
2002         swbytes = (guint8 *) tvb_memdup( pinfo->pool, given_tvb, 0, length);
2003 
2004         /* Wordswapping for modbus detection */
2005         /* Only a even number of bytes can be swapped */
2006         len = (length / 2);
2007         for ( i = 0; i < len; i++ )
2008         {
2009             tempByte = swbytes [ 2 * i ]; swbytes [ 2 * i ] = swbytes [ 2 * i + 1 ]; swbytes [ 2 * i + 1 ] = tempByte;
2010         }
2011 
2012         message_tvb = tvb_new_real_data(swbytes, length, reported_len);
2013     } else {
2014         message_tvb = given_tvb;
2015     }
2016 
2017     frameOffset = 0;
2018     frameLength = 0;
2019     found = 0;
2020 
2021     /* Counter to determine gaps between openSAFETY packages */
2022     gapStart = 0;
2023 
2024     while ( frameOffset < length )
2025     {
2026         /* Reset the next_tvb buffer */
2027         next_tvb = NULL;
2028 
2029         /* Smallest possible frame size is 11, but this check must ensure, that even the last frame
2030          * will get considered, which leads us with 10, as the first byte checked is the second one */
2031         if ( tvb_captured_length_remaining(message_tvb, frameOffset ) < ( OSS_MINIMUM_LENGTH - 1 ) )
2032             break;
2033 
2034         /* Resetting packet, to ensure, that findSafetyFrame starts with a fresh frame.
2035          * As only packet_scope is used, this will not polute memory too much and get's
2036          * cleared with the next packet anyway  */
2037         packet = wmem_new0(pinfo->pool, opensafety_packet_info);
2038 
2039         /* Finding the start of the first possible safety frame */
2040         if ( findSafetyFrame(pinfo, message_tvb, frameOffset, b_frame2First, &frameOffset, &frameLength, packet) )
2041         {
2042             /* if packet msg_id is not null, it still might be an incorrect frame, as there is no validity
2043              * check in findSafetyFrame for the msg id (this happens later in this routine)
2044              * frameLength is calculated/read directly from the dissected data. If frameLength and frameOffset together
2045              * are bigger than the reported length, the package is not really an openSAFETY package */
2046             if ( packet->msg_id == 0 || ( frameOffset + frameLength ) > (guint)reported_len )
2047                 break;
2048 
2049             found++;
2050 
2051             byte_offset = ( b_frame2First ? 0 : frameOffset );
2052             /* We determine a possible position for frame 1 and frame 2 */
2053             if ( b_frame2First )
2054             {
2055                 frameStart1 = findFrame1Position (pinfo, message_tvb, byte_offset, frameLength, FALSE );
2056                 frameStart2 = 0;
2057             }
2058             else
2059             {
2060                 frameStart1 = 0;
2061                 frameStart2 = ((OSS_FRAME_LENGTH_T(message_tvb, byte_offset + frameStart1) - 1) +
2062                         (OSS_FRAME_LENGTH_T(message_tvb, byte_offset + frameStart1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? OSS_SLIM_FRAME2_WITH_CRC16 : OSS_SLIM_FRAME2_WITH_CRC8));
2063             }
2064 
2065             /* If both frame starts are equal, something went wrong. In which case, we retract the found entry, and
2066              * also increase the search offset, just doing a continue will result in an infinite loop. */
2067             if (frameStart1 == frameStart2)
2068             {
2069                 found--;
2070                 frameOffset += frameLength;
2071                 continue;
2072             }
2073 
2074             /* We determine the possible type, and return false, if there could not be one */
2075             packet->msg_id = OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1);
2076             if ( ( packet->msg_id & OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
2077                 type = OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE;
2078             else if ( ( packet->msg_id & OPENSAFETY_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SSDO_MESSAGE_TYPE )
2079                 type = OPENSAFETY_SSDO_MESSAGE_TYPE;
2080             else if ( ( packet->msg_id & OPENSAFETY_SPDO_MESSAGE_TYPE ) == OPENSAFETY_SPDO_MESSAGE_TYPE )
2081                 type = OPENSAFETY_SPDO_MESSAGE_TYPE;
2082             else if ( ( packet->msg_id & OPENSAFETY_SNMT_MESSAGE_TYPE ) == OPENSAFETY_SNMT_MESSAGE_TYPE )
2083                 type = OPENSAFETY_SNMT_MESSAGE_TYPE;
2084             else
2085             {
2086                 /* This is an invalid openSAFETY package, but it could be an undetected slim ssdo message. This specific error
2087                  * will only occur, if findFrame1Position is in play. So we search once more, but this time calculating the CRC.
2088                  * The reason for the second run is, that calculating the CRC is time consuming.  */
2089                 if ( b_frame2First )
2090                 {
2091                     /* Now let's check again, but this time calculate the CRC */
2092                     frameStart1 = findFrame1Position(pinfo, message_tvb, ( b_frame2First ? 0 : frameOffset ), frameLength, TRUE );
2093                     frameStart2 = 0;
2094 
2095                     packet->msg_id = OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1);
2096                     if ( ( packet->msg_id & OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
2097                         type = OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE;
2098                     else if ( ( packet->msg_id & OPENSAFETY_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SSDO_MESSAGE_TYPE )
2099                         type = OPENSAFETY_SSDO_MESSAGE_TYPE;
2100                     else if ( ( packet->msg_id & OPENSAFETY_SPDO_MESSAGE_TYPE ) == OPENSAFETY_SPDO_MESSAGE_TYPE )
2101                         type = OPENSAFETY_SPDO_MESSAGE_TYPE;
2102                     else if ( ( packet->msg_id & OPENSAFETY_SNMT_MESSAGE_TYPE ) == OPENSAFETY_SNMT_MESSAGE_TYPE )
2103                         type = OPENSAFETY_SNMT_MESSAGE_TYPE;
2104                     else {
2105                         /* Skip this frame.  We cannot continue without
2106                            advancing frameOffset - just doing a continue
2107                            will result in an infinite loop. Advancing with 1 will
2108                            lead to infinite loop, advancing with frameLength might miss
2109                            some packages*/
2110                         frameOffset += 2;
2111                         found--;
2112                         continue;
2113                     }
2114                 } else {
2115                     /* As stated above, you cannot just continue
2116                        without advancing frameOffset. Advancing with 1 will
2117                        lead to infinite loop, advancing with frameLength might miss
2118                        some packages*/
2119                     frameOffset += 2;
2120                     found--;
2121                     continue;
2122                 }
2123             }
2124 
2125             /* Sorting messages for transporttype */
2126             if ( global_classify_transport && transporttype != OPENSAFETY_ANY_TRANSPORT )
2127             {
2128                 /* Cyclic data is transported via SPDOs and acyclic is transported via SNMT, SSDO. Everything
2129                  * else is misclassification */
2130                 if ( ( transporttype == OPENSAFETY_ACYCLIC_DATA && type == OPENSAFETY_SPDO_MESSAGE_TYPE ) ||
2131                         ( transporttype == OPENSAFETY_CYCLIC_DATA && type != OPENSAFETY_SPDO_MESSAGE_TYPE ) )
2132                 {
2133                     frameOffset += 2;
2134                     found--;
2135                     continue;
2136                 }
2137             }
2138 
2139             /* Some faulty packages do indeed have a valid first frame, but the second is
2140              * invalid. These checks should prevent most faulty detections */
2141             if ( type != OPENSAFETY_SPDO_MESSAGE_TYPE )
2142             {
2143                 /* Is the given type at least known? */
2144                 gint idx = -1;
2145                 try_val_to_str_idx(OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1), opensafety_message_type_values, &idx );
2146                 /* Unknown Frame Type */
2147                 if ( idx < 0 )
2148                 {
2149                     frameOffset += 2;
2150                     found--;
2151                     continue;
2152                 }
2153                 /* Frame IDs do not match */
2154                 else if ( type == OPENSAFETY_SNMT_MESSAGE_TYPE &&
2155                         (OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) != OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart2)) )
2156                 {
2157                     frameOffset += 2;
2158                     found--;
2159                     continue;
2160                 }
2161             }
2162 
2163             /* If this package is not valid, the next step, which normally occurs in unxorFrame will lead to a
2164              * frameLength bigger than the maximum data size. This is an indicator, that the package in general
2165              * is fault, and therefore we return false. Increasing the frameOffset will lead to out-of-bounds
2166              * for tvb_* functions. And frameLength errors are misidentified packages most of the times anyway */
2167             if ( ( (gint)frameLength - (gint)( frameStart2 > frameStart1 ? frameStart2 : frameLength - frameStart1 ) ) < 0 )
2168                 return FALSE;
2169 
2170             /* Some SPDO based sanity checks, still a lot of faulty SPDOs remain, because they
2171              * cannot be filtered, without throwing out too many positives. */
2172             if ( type == OPENSAFETY_SPDO_MESSAGE_TYPE )
2173             {
2174                 /* Checking if there is a node address set, or the package is invalid. Some PRes
2175                  * messages in EPL may double as valid subframes 1. If the nodeAddress is out of
2176                  * range, the package is marked as malformed */
2177                 nodeAddress = OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1);
2178                 if ( nodeAddress == 0 || nodeAddress > 1024 ) {
2179                     markAsMalformed = TRUE;
2180                 }
2181 
2182                 /* SPDO Reserved is invalid, therefore all packages using this ID can be discarded */
2183                 if ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) == OPENSAFETY_MSG_SPDO_RESERVED )
2184                 {
2185                     frameOffset += 2;
2186                     found--;
2187                     continue;
2188                 }
2189             }
2190 
2191             /* Filter node list */
2192             gint addr = OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1);
2193             if ( global_filter_list && wmem_list_count ( global_filter_list ) > 0 )
2194             {
2195                 gboolean found_in_list = wmem_list_find(global_filter_list, GINT_TO_POINTER( addr )) ? TRUE : FALSE;
2196 
2197                 if ( ( ! global_show_only_node_in_filter && found_in_list ) ||
2198                         ( global_show_only_node_in_filter && ! found_in_list ) )
2199                 {
2200                     opensafety_item = proto_tree_add_item(tree, proto_opensafety, message_tvb, frameOffset, frameLength, ENC_NA);
2201                     proto_item_append_text(opensafety_item, ", Filtered Node: 0x%03X (%d)", addr, addr);
2202                     frameOffset += 2;
2203                     found--;
2204                     continue;
2205                 }
2206             }
2207 
2208             /* From here on, the package should be correct. Even if it is not correct, it will be dissected
2209              * anyway and marked as malformed. Therefore it can be assumed, that a gap will end here.
2210              */
2211             if ( global_display_intergap_data == TRUE && gapStart != frameOffset )
2212             {
2213                 /* Storing the gap data in subset, and calling the data dissector to display it */
2214                 gap_tvb = tvb_new_subset_length_caplen(message_tvb, gapStart, (frameOffset - gapStart), reported_len);
2215                 call_dissector(data_dissector, gap_tvb, pinfo, tree);
2216             }
2217             /* Setting the gap to the next offset */
2218             gapStart = frameOffset + frameLength;
2219 
2220             /* Adding second data source */
2221             next_tvb = tvb_new_subset_length_caplen ( message_tvb, frameOffset, frameLength, reported_len );
2222 
2223             /* Adding a visual aid to the dissector tree */
2224             add_new_data_source(pinfo, next_tvb, "openSAFETY Frame");
2225 
2226             /* A new subtype for package dissection will need to set the actual nr. for the whole dissected package */
2227             if ( force_nr_in_package > 0 )
2228             {
2229                 found = force_nr_in_package + 1;
2230                 dissectorCalled = TRUE;
2231                 col_set_str(pinfo->cinfo, COL_PROTOCOL, protocolName);
2232             }
2233 
2234             if ( ! dissectorCalled )
2235             {
2236                 if ( call_sub_dissector )
2237                     call_dissector(protocol_dissector, message_tvb, pinfo, tree);
2238                 dissectorCalled = TRUE;
2239 
2240                 col_set_str(pinfo->cinfo, COL_PROTOCOL, protocolName);
2241                 col_clear(pinfo->cinfo, COL_INFO);
2242             }
2243 
2244             /* if the tree is NULL, we are called for the overview, otherwise for the
2245                more detailed view of the package */
2246             if ( tree )
2247             {
2248                 /* create the opensafety protocol tree */
2249                 opensafety_item = proto_tree_add_item(tree, proto_opensafety, message_tvb, frameOffset, frameLength, ENC_NA);
2250                 opensafety_tree = proto_item_add_subtree(opensafety_item, ett_opensafety);
2251             } else {
2252                 opensafety_item = NULL;
2253                 opensafety_tree = NULL;
2254             }
2255 
2256             /* Setting type to packet_info */
2257             packet->msg_type = type;
2258 
2259             packet->frame.frame_tvb = next_tvb;
2260             packet->frame.byte_offset = frameOffset + tvb_raw_offset(message_tvb);
2261             packet->frame.subframe1 = frameStart1;
2262             packet->frame.subframe2 = frameStart2;
2263             packet->frame.length = frameLength;
2264             packet->frame.malformed = FALSE;
2265 
2266             /* Clearing connection valid bit */
2267             if ( packet->msg_type == OPENSAFETY_SPDO_MESSAGE_TYPE )
2268                 packet->msg_id = packet->msg_id & 0xF8;
2269 
2270             if ( dissect_opensafety_message(packet, next_tvb, pinfo, opensafety_item, opensafety_tree, found, previous_msg_id) != TRUE )
2271                 markAsMalformed = TRUE;
2272 
2273             previous_msg_id = packet->msg_id;
2274 
2275             if ( markAsMalformed )
2276             {
2277                 packet->frame.malformed = TRUE;
2278                 if ( OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1) > 1024 )
2279                     expert_add_info(pinfo, opensafety_item, &ei_message_spdo_address_invalid );
2280             }
2281 
2282             tap_queue_packet(opensafety_tap, pinfo, packet);
2283 
2284             /* Something is being displayed, therefore this dissector returns true */
2285             handled = TRUE;
2286         }
2287         else
2288             break;
2289 
2290         /* findSafetyFrame starts at frameOffset with the search for the next position. But the
2291          * offset is assumed to be the ID, which can lead to scenarios, where the CRC of a previous
2292          * detected frame is assumed to be the addr of the next one. +1 prevents such a scenario.
2293          * It must be checked, if the resulting frameOffset does not scratch the max length. It
2294          * cannot exceed by adding just frameLength, as this value is a result of the heuristic, and
2295          * therefore must be within the correct length, but it can exceed if +1 is added unchecked. */
2296         frameOffset += frameLength;
2297         if ( tvb_captured_length_remaining(message_tvb, frameOffset) > 0 )
2298             frameOffset += 1;
2299     }
2300 
2301     if ( handled == TRUE )
2302     {
2303         /* There might be some undissected data at the end of the frame (e.g. SercosIII) */
2304         if ( frameOffset < length && global_display_intergap_data == TRUE && gapStart != frameOffset )
2305         {
2306             /* Storing the gap data in subset, and calling the data dissector to display it */
2307             gap_tvb = tvb_new_subset_length_caplen(message_tvb, gapStart, (length - gapStart), reported_len);
2308             call_dissector(data_dissector, gap_tvb, pinfo, tree);
2309         }
2310     }
2311 
2312     return ( handled ? TRUE : FALSE );
2313 }
2314 
2315 static gboolean
dissect_opensafety_epl(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data)2316 dissect_opensafety_epl(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void *data )
2317 {
2318     gboolean        result     = FALSE;
2319     proto_tree      *epl_tree = NULL;
2320     guint8  epl_msgtype = 0;
2321 
2322     /* We will call the epl dissector by using call_dissector(). The epl dissector will then call
2323      * the heuristic openSAFETY dissector again. By setting this information, we prevent a dissector
2324      * loop */
2325     if ( bDissector_Called_Once_Before == FALSE )
2326     {
2327         bDissector_Called_Once_Before = TRUE;
2328 
2329         /* Set the tree up, until it is par with the top-level */
2330         epl_tree = tree;
2331         while ( epl_tree != NULL && epl_tree->parent != NULL )
2332             epl_tree = epl_tree->parent;
2333 
2334         /* Ordering message type to traffic types */
2335         if ( *((guint8*)data) == 0x03 || *((guint8*)data) == 0x04 )
2336             epl_msgtype = OPENSAFETY_CYCLIC_DATA;
2337         else
2338             epl_msgtype = OPENSAFETY_ACYCLIC_DATA;
2339 
2340         /* We check if we have a asynchronous message, or a synchronous message. In case of
2341          * asynchronous messages, SPDO packages are not valid. */
2342 
2343         result = opensafety_package_dissector("openSAFETY/Powerlink", "",
2344                 FALSE, FALSE, 0, message_tvb, pinfo, epl_tree, epl_msgtype );
2345 
2346         bDissector_Called_Once_Before = FALSE;
2347     }
2348 
2349     return result;
2350 }
2351 
2352 static gboolean
dissect_opensafety_siii(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)2353 dissect_opensafety_siii(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
2354 {
2355     gboolean        result     = FALSE;
2356     gboolean        udp        = FALSE;
2357     guint8          firstByte;
2358 
2359     /* The UDP dissection is not done by a heuristic, but rather by a normal dissector. But
2360      * the customer may not expect, that if (s)he disables the SercosIII dissector, that the
2361      * SercosIII UDP packages get still dissected. This will disable them as well. */
2362     if ( ! heuristic_siii_dissection_enabled )
2363         return FALSE;
2364 
2365     /* We will call the SercosIII dissector by using call_dissector(). The SercosIII dissector will
2366      * then call the heuristic openSAFETY dissector again. By setting this information, we prevent
2367      * a dissector loop. */
2368     if ( bDissector_Called_Once_Before == FALSE )
2369     {
2370         udp = pinfo->destport == OPENSAFETY_UDP_PORT_SIII;
2371 
2372         bDissector_Called_Once_Before = TRUE;
2373         /* No frames can be sent in AT messages, therefore those get filtered right away */
2374         firstByte = ( tvb_get_guint8(message_tvb, 0) << 1 );
2375         if ( udp || ( firstByte & 0x40 ) == 0x40 )
2376         {
2377             result = opensafety_package_dissector( "openSAFETY/SercosIII",
2378                     udp ? "" : "sercosiii",
2379                     FALSE, FALSE, 0, message_tvb, pinfo, tree,
2380                     udp ? OPENSAFETY_ACYCLIC_DATA : OPENSAFETY_CYCLIC_DATA );
2381         }
2382         bDissector_Called_Once_Before = FALSE;
2383     }
2384 
2385     return result;
2386 }
2387 
2388 static gboolean
dissect_opensafety_pn_io(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)2389 dissect_opensafety_pn_io(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
2390 {
2391     gboolean        result     = FALSE;
2392 
2393     /* We will call the pn_io dissector by using call_dissector(). The epl dissector will then call
2394      * the heuristic openSAFETY dissector again. By setting this information, we prevent a dissector
2395      * loop */
2396     if ( bDissector_Called_Once_Before == FALSE )
2397     {
2398         bDissector_Called_Once_Before = TRUE;
2399         result = opensafety_package_dissector("openSAFETY/Profinet IO", "pn_io",
2400                                               FALSE, FALSE, 0, message_tvb, pinfo, tree, OPENSAFETY_ANY_TRANSPORT);
2401         bDissector_Called_Once_Before = FALSE;
2402     }
2403 
2404     return result;
2405 }
2406 
2407 static gboolean
dissect_opensafety_mbtcp(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)2408 dissect_opensafety_mbtcp(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
2409 {
2410     if ( ! global_enable_mbtcp )
2411         return FALSE;
2412 
2413     /* When Modbus/TCP gets dissected, openSAFETY would be sorted as a child protocol. Although,
2414      * this behaviour is technically correct, it differs from other implemented IEM protocol handlers.
2415      * Therefore, the openSAFETY frame gets put one up, if the parent is not NULL */
2416     return opensafety_package_dissector("openSAFETY/Modbus TCP", "", FALSE, TRUE, 0,
2417                                         message_tvb, pinfo, ( ((tree != NULL) && (tree->parent != NULL)) ? tree->parent : tree ),
2418                                         OPENSAFETY_ANY_TRANSPORT);
2419 }
2420 
2421 static gboolean
opensafety_udp_transport_dissector(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree)2422 opensafety_udp_transport_dissector(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree)
2423 {
2424     proto_item      *ti = NULL;
2425     proto_tree      *transport_tree = NULL;
2426     gint            offset = 0;
2427     tvbuff_t        *os_tvb = 0;
2428 
2429     col_set_str(pinfo->cinfo, COL_PROTOCOL, "openSAFETY over UDP");
2430     col_clear(pinfo->cinfo, COL_INFO);
2431 
2432     ti = proto_tree_add_item(tree, proto_oss_udp_transport, message_tvb, 0, -1, ENC_NA);
2433     transport_tree = proto_item_add_subtree(ti, ett_opensafety);
2434 
2435     proto_tree_add_item(transport_tree, hf_oss_udp_transport_version, message_tvb, 0, 1, ENC_BIG_ENDIAN);
2436     proto_tree_add_item(transport_tree, hf_oss_udp_transport_flags_type, message_tvb, 1, 1, ENC_BIG_ENDIAN);
2437     proto_tree_add_item(transport_tree, hf_oss_udp_transport_counter, message_tvb, 2, 2, ENC_LITTLE_ENDIAN);
2438 
2439     proto_tree_add_item(transport_tree, hf_oss_udp_transport_sender, message_tvb, 4, 4, ENC_LITTLE_ENDIAN);
2440     proto_tree_add_item(transport_tree, hf_oss_udp_transport_datapoint, message_tvb, 8, 2, ENC_LITTLE_ENDIAN);
2441     proto_tree_add_item(transport_tree, hf_oss_udp_transport_length, message_tvb, 10, 2, ENC_LITTLE_ENDIAN);
2442     offset += 12;
2443 
2444     os_tvb = tvb_new_subset_remaining(message_tvb, offset);
2445 
2446     if ( ! opensafety_package_dissector("openSAFETY/UDP", "", FALSE,
2447             FALSE, 0, os_tvb, pinfo, tree, OPENSAFETY_ANY_TRANSPORT ) )
2448         call_dissector(find_dissector("data"), os_tvb, pinfo, transport_tree);
2449 
2450     return TRUE;
2451 }
2452 
2453 static gboolean
dissect_opensafety_udpdata(tvbuff_t * message_tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)2454 dissect_opensafety_udpdata(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
2455 {
2456     gboolean       result   = FALSE;
2457     static guint32 frameNum = 0;
2458     static guint32 frameIdx = 0;
2459 
2460     gboolean frameFound = FALSE;
2461     guint    frameOffset = 0;
2462     guint    frameLength = 0;
2463 
2464     if ( pinfo->destport == OPENSAFETY_UDP_PORT_SIII )
2465         return dissect_opensafety_siii(message_tvb, pinfo, tree, data);
2466 
2467     if ( ! global_enable_udp )
2468         return result;
2469 
2470     /* An openSAFETY frame has at least OSS_MINIMUM_LENGTH bytes */
2471     if ( tvb_captured_length ( message_tvb ) < OSS_MINIMUM_LENGTH )
2472         return result;
2473 
2474     /* More than one openSAFETY package could be transported in the same frame,
2475      * in such a case, we need to establish the number of packages inside the frame */
2476     if ( pinfo->num != frameNum )
2477     {
2478         frameIdx = 0;
2479         frameNum = pinfo->num;
2480     }
2481 
2482     /* check for openSAFETY frame at beginning of data */
2483 
2484     frameFound = findSafetyFrame(pinfo, message_tvb, 0, global_udp_frame2_first, &frameOffset, &frameLength, NULL );
2485     if ( ! frameFound || ( frameOffset >= 11 ) )
2486     {
2487         dissector_handle_t udp_transport = find_dissector ( "opensafety_udp_transport" );
2488         if ( udp_transport != NULL )
2489             call_dissector(udp_transport, message_tvb, pinfo, tree);
2490         result = opensafety_udp_transport_dissector(message_tvb, pinfo, tree);
2491     }
2492     else
2493         result = opensafety_package_dissector("openSAFETY/UDP", "", global_udp_frame2_first,
2494                                           FALSE, frameIdx, message_tvb, pinfo, tree, OPENSAFETY_ACYCLIC_DATA );
2495 
2496     if ( result )
2497         frameIdx++;
2498 
2499     return result;
2500 }
2501 
2502 static void
apply_prefs(void)2503 apply_prefs ( void )
2504 {
2505     static guint    opensafety_udp_port_number;
2506     static guint    opensafety_udp_siii_port_number;
2507     static gboolean opensafety_init = FALSE;
2508 
2509     /* It only should delete dissectors, if run for any time except the first */
2510     if ( opensafety_init )
2511     {
2512         /* Delete dissectors in preparation of a changed config setting */
2513         dissector_delete_uint ("udp.port", opensafety_udp_port_number, opensafety_udptransport_handle);
2514         dissector_delete_uint ("udp.port", opensafety_udp_siii_port_number, opensafety_udpdata_handle);
2515     }
2516     opensafety_init = TRUE;
2517 
2518     /* Storing the port numbers locally, to being able to delete the old associations */
2519     opensafety_udp_port_number = global_network_udp_port;
2520     opensafety_udp_siii_port_number = global_network_udp_port_sercosiii;
2521 
2522     /* Default UDP only based dissector, will hand traffic to SIII dissector if needed */
2523     /* Preference names to specific to use "auto" preference */
2524     dissector_add_uint("udp.port", opensafety_udp_port_number, opensafety_udptransport_handle);
2525     dissector_add_uint("udp.port", opensafety_udp_siii_port_number, opensafety_udpdata_handle);
2526 }
2527 
2528 void
proto_register_opensafety(void)2529 proto_register_opensafety(void)
2530 {
2531     /* Setup list of header fields */
2532     static hf_register_info hf[] = {
2533         { &hf_oss_scm_udid,
2534           { "SCM UDID Configured",    "opensafety.scm_udid",
2535             FT_STRING,   BASE_NONE, NULL,   0x0, NULL, HFILL } },
2536         { &hf_oss_scm_udid_auto,
2537           { "SCM UDID Auto Detect",    "opensafety.scm_udid.auto",
2538             FT_STRING,   BASE_NONE, NULL,   0x0, NULL, HFILL } },
2539         { &hf_oss_scm_udid_valid,
2540           { "SCM UDID Valid",    "opensafety.scm_udid.valid",
2541             FT_BOOLEAN,   BASE_NONE, NULL,   0x0, NULL, HFILL } },
2542 
2543         { &hf_oss_byte_offset,
2544           { "Byte Offset",    "opensafety.msg.byte_offset",
2545             FT_UINT16,  BASE_HEX, NULL,   0x0, NULL, HFILL } },
2546         { &hf_oss_msg,
2547           { "Message",    "opensafety.msg.id",
2548             FT_UINT8,   BASE_HEX, VALS(opensafety_message_type_values),   0x0, NULL, HFILL } },
2549         { &hf_oss_msg_category,
2550           { "Type",  "opensafety.msg.type",
2551             FT_UINT8,   BASE_HEX, VALS(opensafety_msg_id_values),   0xE0, NULL, HFILL } },
2552         { &hf_oss_msg_direction,
2553           { "Direction",  "opensafety.msg.direction",
2554             FT_BOOLEAN,   8, TFS(&opensafety_message_direction),   0x04, NULL, HFILL } },
2555         { &hf_oss_msg_node,
2556           { "Safety Node",  "opensafety.msg.node",
2557             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2558         { &hf_oss_msg_network,
2559           { "Safety Domain",  "opensafety.msg.network",
2560             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2561         { &hf_oss_msg_sender,
2562           { "SN send from",  "opensafety.msg.sender",
2563             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2564         { &hf_oss_msg_receiver,
2565           { "SN send to",  "opensafety.msg.receiver",
2566             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2567         { &hf_oss_length,
2568           { "Length",    "opensafety.length",
2569             FT_UINT8,   BASE_DEC, NULL,     0x0, NULL, HFILL } },
2570         { &hf_oss_crc,
2571           { "CRC",       "opensafety.crc.data",
2572             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2573 
2574         { &hf_oss_crc_valid,
2575           { "Is Valid", "opensafety.crc.valid",
2576             FT_BOOLEAN, BASE_NONE, NULL,    0x0, NULL, HFILL } },
2577         { &hf_oss_crc_type,
2578           { "CRC Type",  "opensafety.crc.type",
2579             FT_UINT8,   BASE_DEC, VALS(opensafety_frame_crc_type),    0x0, NULL, HFILL } },
2580         { &hf_oss_crc2_valid,
2581           { "Is Valid", "opensafety.crc2.valid",
2582             FT_BOOLEAN, BASE_NONE, NULL,    0x0, NULL, HFILL } },
2583 
2584         /* SNMT Specific fields */
2585         { &hf_oss_snmt_slave,
2586           { "SNMT Slave",    "opensafety.snmt.slave",
2587             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2588         { &hf_oss_snmt_master,
2589           { "SNMT Master",   "opensafety.snmt.master",
2590             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2591         { &hf_oss_snmt_scm,
2592           { "SCM",    "opensafety.snmt.scm",
2593             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2594         { &hf_oss_snmt_tool,
2595           { "Tool ID",   "opensafety.snmt.tool_id",
2596             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2597         { &hf_oss_snmt_udid,
2598           { "UDID for SN",   "opensafety.snmt.udid",
2599             FT_ETHER,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2600         { &hf_oss_snmt_service_id,
2601           { "Extended Service ID",   "opensafety.snmt.service_id",
2602             FT_UINT8,  BASE_HEX, VALS(opensafety_message_service_type),    0x0, NULL, HFILL } },
2603         { &hf_oss_snmt_error_group,
2604           { "Error Group",   "opensafety.snmt.error_group",
2605             FT_UINT8,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2606         { &hf_oss_snmt_error_code,
2607           { "Error Code",   "opensafety.snmt.error_code",
2608             FT_UINT8,  BASE_DEC, NULL,   0x0, NULL, HFILL } },
2609         { &hf_oss_snmt_param_type,
2610           { "Parameter Request Type",   "opensafety.snmt.parameter_type",
2611             FT_BOOLEAN,  BASE_NONE, TFS(&opensafety_addparam_request),   0x0, NULL, HFILL } },
2612         { &hf_oss_snmt_ext_addsaddr,
2613           { "Additional SADDR",    "opensafety.snmt.additional.saddr",
2614             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2615         { &hf_oss_snmt_ext_addtxspdo,
2616           { "Additional TxSPDO",    "opensafety.snmt.additional.txspdo",
2617             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2618         { &hf_oss_snmt_ext_initct,
2619           { "Initial CT", "opensafety.snmt.initct",
2620             FT_UINT40,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2621 
2622         /* SSDO Specific fields */
2623         { &hf_oss_ssdo_server,
2624           { "SSDO Server", "opensafety.ssdo.master",
2625             FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2626         { &hf_oss_ssdo_client,
2627           { "SSDO Client", "opensafety.ssdo.client",
2628             FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2629         { &hf_oss_ssdo_sano,
2630           { "SOD Access Request Number", "opensafety.ssdo.sano",
2631             FT_UINT16,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2632         { &hf_oss_ssdo_sacmd,
2633           { "SOD Access Command", "opensafety.ssdo.sacmd",
2634             FT_UINT8,  BASE_HEX, VALS(opensafety_ssdo_sacmd_values),    0x0, NULL, HFILL } },
2635         { &hf_oss_ssdo_sod_index,
2636           { "SOD Index", "opensafety.ssdo.sodentry.index",
2637             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2638         { &hf_oss_ssdo_sod_subindex,
2639           { "SOD Sub Index", "opensafety.ssdo.sodentry.subindex",
2640             FT_UINT8,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2641         { &hf_oss_ssdo_payload,
2642           { "SOD Payload", "opensafety.ssdo.payload",
2643             FT_BYTES,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2644         { &hf_oss_ssdo_payload_size,
2645           { "SOD Payload Size", "opensafety.ssdo.payloadsize",
2646             FT_UINT32,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2647         { &hf_oss_ssdo_sodentry_size,
2648           { "SOD Entry Size", "opensafety.ssdo.sodentry.size",
2649             FT_UINT32,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2650         { &hf_oss_ssdo_sodentry_data,
2651           { "SOD Data", "opensafety.ssdo.sodentry.data",
2652             FT_BYTES,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2653         { &hf_oss_sod_par_timestamp,
2654           { "Parameter Timestamp", "opensafety.sod.parameter.timestamp",
2655             FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2656         { &hf_oss_sod_par_checksum,
2657           { "Parameter Checksum", "opensafety.sod.parameter.checksum",
2658             FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2659 
2660         { &hf_oss_ssdo_sodmapping,
2661           { "Mapping entry", "opensafety.sod.mapping",
2662             FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2663         { &hf_oss_ssdo_sodmapping_bits,
2664           { "Mapping size", "opensafety.sod.mapping.bits",
2665             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2666 
2667         { &hf_oss_ssdo_extpar_parset,
2668           { "Additional Parameter Set", "opensafety.ssdo.extpar.setnr",
2669             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2670         { &hf_oss_ssdo_extpar_version,
2671           { "Parameter Set Version", "opensafety.ssdo.extpar.version",
2672             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2673         { &hf_oss_ssdo_extpar_saddr,
2674           { "Parameter Set for SADDR", "opensafety.ssdo.extpar.saddr",
2675             FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2676         { &hf_oss_ssdo_extpar_length,
2677           { "Parameter Set Length", "opensafety.ssdo.extpar.length",
2678             FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2679         { &hf_oss_ssdo_extpar_crc,
2680           { "Parameter Set CRC", "opensafety.ssdo.extpar.crc",
2681             FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2682         { &hf_oss_ssdo_extpar_tstamp,
2683           { "Timestamp", "opensafety.ssdo.extpar.timestamp",
2684             FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2685         { &hf_oss_ssdo_extpar_data,
2686           { "Ext. Parameter Data", "opensafety.ssdo.extpar.data",
2687             FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2688         { &hf_oss_ssdo_extpar,
2689           { "Ext. Parameter", "opensafety.ssdo.extpar",
2690             FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2691 
2692         {&hf_oss_fragments,
2693          {"Message fragments", "opensafety.ssdo.fragments",
2694           FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2695         {&hf_oss_fragment,
2696          {"Message fragment", "opensafety.ssdo.fragment",
2697           FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2698         {&hf_oss_fragment_overlap,
2699          {"Message fragment overlap", "opensafety.ssdo.fragment.overlap",
2700           FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2701         {&hf_oss_fragment_overlap_conflicts,
2702          {"Message fragment overlapping with conflicting data",
2703           "opensafety.ssdo.fragment.overlap.conflicts",
2704           FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2705         {&hf_oss_fragment_multiple_tails,
2706          {"Message has multiple tail fragments", "opensafety.ssdo.fragment.multiple_tails",
2707           FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2708         {&hf_oss_fragment_too_long_fragment,
2709          {"Message fragment too long", "opensafety.ssdo.fragment.too_long_fragment",
2710           FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2711         {&hf_oss_fragment_error,
2712          {"Message defragmentation error", "opensafety.ssdo.fragment.error",
2713           FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2714         {&hf_oss_fragment_count,
2715          {"Message fragment count", "opensafety.ssdo.fragment.count",
2716           FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
2717         {&hf_oss_reassembled_in,
2718          {"Reassembled in", "opensafety.ssdo.reassembled.in",
2719           FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2720         {&hf_oss_reassembled_length,
2721          {"Reassembled length", "opensafety.ssdo.reassembled.length",
2722           FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
2723         {&hf_oss_reassembled_data,
2724          {"Reassembled Data", "opensafety.ssdo.reassembled.data",
2725           FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2726 
2727         { &hf_oss_ssdo_abort_code,
2728           { "Abort Code", "opensafety.ssdo.abortcode",
2729             FT_UINT32,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2730 
2731         { &hf_oss_ssdo_preload_error,
2732           { "Wrong/missing segment", "opensafety.ssdo.preload.error",
2733             FT_BOOLEAN, 8, NULL,    0x30, NULL, HFILL } },
2734         { &hf_oss_ssdo_preload_queue,
2735           { "Preload Queue Size", "opensafety.ssdo.preload.queuesize",
2736             FT_UINT8,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2737 
2738         /* SSDO SACmd specific fields */
2739         { &hf_oss_ssdo_sacmd_access_type,
2740           { "Access Direction", "opensafety.ssdo.sacmd.access",
2741             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_acc), OPENSAFETY_SSDO_SACMD_ACC, NULL, HFILL } },
2742         { &hf_oss_ssdo_sacmd_preload,
2743           { "Preload Transfer", "opensafety.ssdo.sacmd.preload",
2744             FT_BOOLEAN,  8, TFS(&tfs_enabled_disabled), OPENSAFETY_SSDO_SACMD_PRLD, NULL, HFILL } },
2745         { &hf_oss_ssdo_sacmd_abort_transfer,
2746           { "Abort Transfer", "opensafety.ssdo.sacmd.abort_transfer",
2747             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_abrt), OPENSAFETY_SSDO_SACMD_ABRT, NULL, HFILL } },
2748         { &hf_oss_ssdo_sacmd_segmentation,
2749           { "Segmentation", "opensafety.ssdo.sacmd.segmentation",
2750             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_seg), OPENSAFETY_SSDO_SACMD_SEG, NULL, HFILL } },
2751         { &hf_oss_ssdo_sacmd_toggle,
2752           { "Toggle Bit", "opensafety.ssdo.sacmd.toggle",
2753             FT_BOOLEAN,  8, TFS(&tfs_on_off), OPENSAFETY_SSDO_SACMD_TGL, NULL, HFILL } },
2754         { &hf_oss_ssdo_sacmd_initiate,
2755           { "Initiate Transfer", "opensafety.ssdo.sacmd.initiate",
2756             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_ini), OPENSAFETY_SSDO_SACMD_INI, NULL, HFILL } },
2757         { &hf_oss_ssdo_sacmd_end_segment,
2758           { "End Segment", "opensafety.ssdo.sacmd.end_segment",
2759             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_ensg), OPENSAFETY_SSDO_SACMD_ENSG, NULL, HFILL } },
2760 #if 0
2761         { &hf_oss_ssdo_sacmd_reserved,
2762           { "Reserved", "opensafety.ssdo.sacmd.reserved",
2763             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_res), OPENSAFETY_SSDO_SACMD_RES, NULL, HFILL } },
2764 #endif
2765 
2766         /* SPDO Specific fields */
2767         { &hf_oss_spdo_connection_valid,
2768           { "Connection Valid Bit", "opensafety.spdo.connection_valid",
2769             FT_BOOLEAN,  8, TFS(&tfs_set_notset),  0x04, NULL, HFILL } },
2770         { &hf_oss_spdo_direction,
2771           { "Send to",  "opensafety.spdo.direction",
2772             FT_BOOLEAN,   8, TFS(&opensafety_spdo_direction),   0x08, NULL, HFILL } },
2773         { &hf_oss_spdo_ct,
2774           { "Consecutive Time", "opensafety.spdo.ct",
2775             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2776         { &hf_oss_spdo_ct_40bit,
2777           { "Consecutive Time 40bit", "opensafety.spdo.ct40bit",
2778             FT_UINT40,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2779         { &hf_oss_spdo_time_request,
2780           { "Time Request Counter", "opensafety.spdo.time.request_counter",
2781             FT_UINT8,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2782         { &hf_oss_spdo_time_request_to,
2783           { "Time Request from", "opensafety.spdo.time.request_from",
2784             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2785         { &hf_oss_spdo_time_request_from,
2786           { "Time Request by", "opensafety.spdo.time.request_to",
2787             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2788         { &hf_oss_spdo_feature_flags,
2789           { "SPDO Feature Flags", "opensafety.spdo.featureflags",
2790             FT_UINT8,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2791         { &hf_oss_spdo_feature_flag_40bit_available,
2792           { "40Bit Request", "opensafety.spdo.features.40bitrequest",
2793             FT_BOOLEAN,  8, TFS(&tfs_requested_not_requested), (OPENSAFETY_SPDO_FEAT_40BIT_AVAIL << 2), NULL, HFILL } },
2794         { &hf_oss_spdo_feature_flag_40bit_used,
2795           { "40Bit Counter", "opensafety.spdo.features.40bitactive",
2796             FT_BOOLEAN,  8, TFS(&tfs_enabled_disabled), (OPENSAFETY_SPDO_FEAT_40BIT_USED << 2), NULL, HFILL } },
2797     };
2798 
2799     /* Setup list of header fields */
2800     static hf_register_info hf_oss_udp_transport[] = {
2801         /* UDP transport specific fields */
2802         { &hf_oss_udp_transport_version,
2803           { "Transport Version", "opensafety.udp_transport.version",
2804             FT_UINT8,  BASE_DEC, NULL,  0x0, NULL, HFILL } },
2805         { &hf_oss_udp_transport_flags_type,
2806           { "Data Type", "opensafety.udp_transport.flags.type",
2807             FT_BOOLEAN, 8, TFS(&tfs_udp_transport_cyclic_acyclic),  0x01, NULL, HFILL } },
2808         { &hf_oss_udp_transport_counter,
2809           { "Counter", "opensafety.udp_transport.counter",
2810             FT_UINT16,  BASE_HEX_DEC, NULL,    0x0, NULL, HFILL } },
2811         { &hf_oss_udp_transport_sender,
2812           { "Sender ID", "opensafety.udp_transport.sender",
2813             FT_UINT32,  BASE_HEX_DEC, NULL,    0x0, NULL, HFILL } },
2814         { &hf_oss_udp_transport_datapoint,
2815           { "Datapoint ID", "opensafety.udp_transport.datapoint",
2816             FT_UINT16,  BASE_HEX_DEC, NULL,    0x0, NULL, HFILL } },
2817         { &hf_oss_udp_transport_length,
2818           { "Length", "opensafety.udp_transport.length",
2819             FT_UINT16,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2820 
2821     };
2822 
2823     /* Setup protocol subtree array */
2824     static gint *ett[] = {
2825         &ett_opensafety,
2826         &ett_opensafety_node,
2827         &ett_opensafety_checksum,
2828         &ett_opensafety_snmt,
2829         &ett_opensafety_ssdo,
2830         &ett_opensafety_ssdo_sacmd,
2831         &ett_opensafety_ssdo_fragment,
2832         &ett_opensafety_ssdo_fragments,
2833         &ett_opensafety_ssdo_payload,
2834         &ett_opensafety_ssdo_sodentry,
2835         &ett_opensafety_sod_mapping,
2836         &ett_opensafety_ssdo_extpar,
2837         &ett_opensafety_spdo,
2838         &ett_opensafety_spdo_flags,
2839     };
2840 
2841     static gint *ett_oss_udp[] = {
2842         &ett_oss_udp_transport,
2843     };
2844 
2845     static ei_register_info ei[] = {
2846         { &ei_crc_frame_1_invalid,
2847           { "opensafety.crc.error.frame1_invalid", PI_PROTOCOL, PI_ERROR,
2848             "Frame 1 CRC invalid, Possible error in package", EXPFILL } },
2849         { &ei_crc_frame_1_valid_frame2_invalid,
2850           { "opensafety.crc.error.frame1_valid_frame2_invalid", PI_PROTOCOL, PI_ERROR,
2851             "Frame 1 is valid, frame 2 id is invalid", EXPFILL } },
2852         { &ei_crc_slimssdo_instead_of_spdo,
2853           { "opensafety.crc.warning.wrong_crc_for_spdo", PI_PROTOCOL, PI_WARN,
2854             "Frame 1 SPDO CRC is Slim SSDO CRC16 0x5935", EXPFILL } },
2855         { &ei_crc_frame_2_invalid,
2856           { "opensafety.crc.error.frame2_invalid", PI_PROTOCOL, PI_ERROR,
2857             "Frame 2 CRC invalid, Possible error in package or crc calculation", EXPFILL } },
2858         { &ei_crc_frame_2_unknown_scm_udid,
2859           { "opensafety.crc.error.frame2_unknown_scmudid", PI_PROTOCOL, PI_WARN,
2860             "Frame 2 CRC invalid, SCM UDID was not auto-detected", EXPFILL } },
2861         { &ei_crc_frame_2_scm_udid_encoded,
2862           { "opensafety.crc.error.crc2_scm_udid_encoded", PI_PROTOCOL, PI_NOTE,
2863             "Frame 2 CRC is encoded with byte 6 of SCM UDID due to payload length of 0 in frame 2 or SLIM SSDO", EXPFILL } },
2864 
2865         { &ei_message_reassembly_size_differs_from_header,
2866           { "opensafety.msg.warning.reassembly_size_fail", PI_PROTOCOL, PI_WARN,
2867             "Reassembled message size differs from size in header", EXPFILL } },
2868         { &ei_message_unknown_type,
2869           { "opensafety.msg.error.unknown_type", PI_MALFORMED, PI_ERROR,
2870             "Unknown openSAFETY message type", EXPFILL } },
2871         { &ei_message_spdo_address_invalid,
2872           { "opensafety.msg.error.spdo_address_invalid", PI_MALFORMED, PI_ERROR,
2873             "SPDO address is invalid", EXPFILL } },
2874         { &ei_message_id_field_mismatch,
2875           { "opensafety.msg.error.id.mismatch", PI_PROTOCOL, PI_ERROR,
2876             "ID for frame 2 is not the same as for frame 1", EXPFILL } },
2877 
2878         { &ei_scmudid_autodetected,
2879           { "opensafety.scm_udid.note.autodetected", PI_PROTOCOL, PI_NOTE,
2880             "Auto detected payload as SCM UDID", EXPFILL } },
2881         { &ei_scmudid_invalid_preference,
2882           { "opensafety.scm_udid.note.invalid_preference", PI_PROTOCOL, PI_WARN,
2883             "openSAFETY protocol settings are invalid! SCM UDID first octet will be assumed to be 00", EXPFILL } },
2884         { &ei_scmudid_unknown,
2885           { "opensafety.scm_udid.warning.assuming_first_octet", PI_PROTOCOL, PI_WARN,
2886             "SCM UDID unknown, assuming 00 as first UDID octet", EXPFILL } },
2887 
2888         { &ei_payload_unknown_format,
2889           { "opensafety.msg.warning.unknown_format", PI_PROTOCOL, PI_WARN,
2890             "Unknown payload format detected", EXPFILL } },
2891         { &ei_payload_length_not_positive,
2892           { "opensafety.msg.warning.reassembly_length_not_positive", PI_PROTOCOL, PI_NOTE,
2893             "Calculation for payload length yielded non-positive result", EXPFILL } },
2894 
2895         { &ei_40bit_default_domain,
2896           { "opensafety.msg.warning.default_domain_40bit", PI_PROTOCOL, PI_NOTE,
2897             "SDN is assumed with 1 to allow 40bit dissection", EXPFILL } },
2898 
2899     };
2900 
2901     module_t *opensafety_module, *oss_udp_module;
2902     expert_module_t *expert_opensafety;
2903 
2904     /* Register the protocol name and description */
2905     proto_opensafety = proto_register_protocol("openSAFETY", "openSAFETY",  "opensafety");
2906     opensafety_module = prefs_register_protocol(proto_opensafety, apply_prefs);
2907     proto_oss_udp_transport = proto_register_protocol("openSAFETY over UDP", "openSAFETY ov. UDP", "opensafety_udp");
2908     oss_udp_module = prefs_register_protocol(proto_oss_udp_transport, apply_prefs);
2909 
2910     /* Register data dissector */
2911     heur_opensafety_spdo_subdissector_list = register_heur_dissector_list("opensafety.spdo", proto_opensafety);
2912 
2913     /* Required function calls to register the header fields and subtrees used */
2914     proto_register_field_array(proto_opensafety, hf, array_length(hf));
2915     proto_register_subtree_array(ett, array_length(ett));
2916     proto_register_field_array(proto_oss_udp_transport, hf_oss_udp_transport, array_length(hf_oss_udp_transport));
2917     proto_register_subtree_array(ett_oss_udp, array_length(ett_oss_udp));
2918 
2919     /* Register tap */
2920     opensafety_tap = register_tap("opensafety");
2921 
2922     expert_opensafety = expert_register_protocol ( proto_opensafety );
2923     expert_register_field_array ( expert_opensafety, ei, array_length (ei ) );
2924 
2925     /* register user preferences */
2926     prefs_register_string_preference(opensafety_module, "scm_udid",
2927                  "SCM UDID (xx:xx:xx:xx:xx:xx)",
2928                  "To be able to fully dissect SSDO and SPDO packages, a valid UDID for the SCM has to be provided",
2929                  &global_scm_udid);
2930     prefs_register_bool_preference(opensafety_module, "scm_udid_autoset",
2931                  "Set SCM UDID if detected in stream",
2932                  "Automatically assign a detected SCM UDID (by reading SNMT->SNTM_assign_UDID_SCM) and set it for the file",
2933                  &global_scm_udid_autoset);
2934 
2935     prefs_register_string_preference(opensafety_module, "filter_nodes",
2936                  "Filter openSAFETY Nodes",
2937                  "A comma-separated list of nodes to be filtered during dissection",
2938                  &global_filter_nodes);
2939     prefs_register_bool_preference(opensafety_module, "filter_show_nodes_in_filterlist",
2940                  "Show nodes in filter, hide otherwise",
2941                  "If set to true, only nodes in the list will be shown, otherwise they will be hidden",
2942                  &global_show_only_node_in_filter);
2943 
2944     prefs_register_uint_preference(opensafety_module, "network_udp_port",
2945                 "Port used for Generic UDP",
2946                 "Port used by any UDP demo implementation to transport data", 10,
2947                 &global_network_udp_port);
2948     prefs_register_uint_preference(opensafety_module, "network_udp_port_sercosiii",
2949                 "Port used for SercosIII/UDP",
2950                 "UDP port used by SercosIII to transport data", 10,
2951                 &global_network_udp_port_sercosiii);
2952     prefs_register_bool_preference(opensafety_module, "network_udp_frame_first_sercosiii",
2953                 "openSAFETY frame 2 before frame 1 (SercosIII/UDP only)",
2954                 "In an SercosIII/UDP transport stream, openSAFETY frame 2 will be expected before frame 1",
2955                 &global_siii_udp_frame2_first );
2956 
2957     prefs_register_bool_preference(opensafety_module, "network_udp_frame_first",
2958                 "openSAFETY frame 2 before frame 1 (UDP only)",
2959                 "In the transport stream, openSAFETY frame 2 will be expected before frame 1",
2960                 &global_udp_frame2_first );
2961     prefs_register_bool_preference(opensafety_module, "mbtcp_big_endian",
2962                 "Big Endian Word Coding (Modbus/TCP only)",
2963                 "Modbus/TCP words can be transcoded either big- or little endian. Default will be little endian",
2964                 &global_mbtcp_big_endian);
2965     prefs_register_bool_preference(opensafety_module, "debug_verbose",
2966                 "openSAFETY print all dissection information",
2967                 "Enables additional information in the dissection for better debugging an openSAFETY trace",
2968                 &global_opensafety_debug_verbose );
2969 
2970     prefs_register_obsolete_preference(opensafety_module, "enable_plk");
2971     prefs_register_obsolete_preference(opensafety_module, "enable_siii");
2972     prefs_register_obsolete_preference(opensafety_module, "enable_pnio");
2973 
2974     prefs_register_bool_preference(opensafety_module, "enable_udp",
2975                 "Enable heuristic dissection for openSAFETY over UDP encoded traffic", "Enable heuristic dissection for openSAFETY over UDP encoded traffic",
2976                 &global_enable_udp);
2977     prefs_register_bool_preference(opensafety_module, "enable_mbtcp",
2978                 "Enable heuristic dissection for Modbus/TCP", "Enable heuristic dissection for Modbus/TCP",
2979                 &global_enable_mbtcp);
2980 
2981     prefs_register_bool_preference(opensafety_module, "display_intergap_data",
2982                 "Display the data between openSAFETY packets", "Display the data between openSAFETY packets",
2983                 &global_display_intergap_data);
2984     prefs_register_bool_preference(opensafety_module, "classify_transport",
2985                 "Dissect packet based on transport method (EPL + SercosIII only)",
2986                 "SPDOs may only be found in cyclic data, SSDOs/SNMTS only in acyclic data",
2987                 &global_classify_transport);
2988 
2989     prefs_register_uint_preference(oss_udp_module, "network_udp_port",
2990                 "Port used for UDP Transport",
2991                 "Port used by the openSAFETY over UDP data transport", 10,
2992                 &global_network_oss_udp_port);
2993 
2994     /* Registering default and ModBus/TCP dissector */
2995     opensafety_udpdata_handle = register_dissector("opensafety_udp", dissect_opensafety_udpdata, proto_opensafety );
2996     opensafety_udptransport_handle =
2997             register_dissector("opensafety_udptransport", dissect_opensafety_udpdata, proto_oss_udp_transport );
2998     opensafety_mbtcp_handle = register_dissector("opensafety_mbtcp", dissect_opensafety_mbtcp, proto_opensafety );
2999     opensafety_pnio_handle = register_dissector("opensafety_pnio", dissect_opensafety_pn_io, proto_opensafety);
3000 }
3001 
3002 void
proto_reg_handoff_opensafety(void)3003 proto_reg_handoff_opensafety(void)
3004 {
3005     /* Storing global data_dissector */
3006     data_dissector = find_dissector ( "data" );
3007 
3008     /* EPL & SercosIII dissector registration */
3009     heur_dissector_add("epl_data",  dissect_opensafety_epl, "openSAFETY over EPL", "opensafety_epl_data", proto_opensafety, HEURISTIC_ENABLE);
3010     heur_dissector_add("sercosiii", dissect_opensafety_siii, "openSAFETY over SercosIII", "opensafety_sercosiii", proto_opensafety, HEURISTIC_ENABLE);
3011 
3012     /* Modbus TCP dissector registration */
3013     dissector_add_string("modbus.data", "data", opensafety_mbtcp_handle);
3014 
3015     /* For Profinet we have to register as a heuristic dissector, as Profinet
3016      *  is implemented as a plugin, and therefore the heuristic dissector is not
3017      *  added by the time this method is being called
3018      */
3019     if ( find_dissector("pn_io") != NULL )
3020     {
3021         heur_dissector_add("pn_io", dissect_opensafety_pn_io, "openSAFETY over Profinet", "opensafety_pn_io", proto_opensafety, HEURISTIC_DISABLE);
3022     }
3023     else
3024     {
3025         /* The native dissector cannot be loaded. so we add our protocol directly to
3026          * the ethernet subdissector list. No PNIO specific data will be dissected
3027          * and a warning will be displayed, recognizing the missing dissector plugin.
3028          */
3029         dissector_add_uint("ethertype", ETHERTYPE_PROFINET, opensafety_pnio_handle);
3030     }
3031 
3032     apply_prefs();
3033 
3034     register_init_routine ( setup_dissector );
3035     register_cleanup_routine ( cleanup_dissector );
3036 
3037     reassembly_table_register(&os_reassembly_table, &addresses_reassembly_table_functions);
3038 
3039     /* registering frame end routine, to prevent a malformed dissection preventing
3040      * further dissector calls (see bug #6950) */
3041     /* register_frame_end_routine(reset_dissector); */
3042 }
3043 
3044 /*
3045  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
3046  *
3047  * Local variables:
3048  * c-basic-offset: 4
3049  * tab-width: 8
3050  * indent-tabs-mode: nil
3051  * End:
3052  *
3053  * vi: set shiftwidth=4 tabstop=8 expandtab:
3054  * :indentSize=4:tabSize=8:noTabs=true:
3055  */
3056