From Roland Knall via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9345
[metze/wireshark/wip.git] / epan / dissectors / packet-opensafety.c
1 /* packet-opensafety.c
2  *
3  * $Id$
4  *
5  *   openSAFETY is a machine-safety protocol, encapsulated in modern fieldbus
6  *   and industrial ethernet solutions.
7  *
8  *   For more information see http://www.open-safety.org
9  *
10  *   This dissector currently supports the following transport protocols
11  *
12  *   - openSAFETY using POWERLINK
13  *   - openSAFETY using SercosIII
14  *   - openSAFETY using Generic UDP
15  *   - openSAFETY using Modbus/TCP
16  *   - openSAFETY using (openSAFETY over UDP) transport
17  *   - openSAFETY using ProfiNet IO
18  *
19  * By Roland Knall <roland.knall@br-automation.com>
20  * Copyright 2011-2012 Bernecker + Rainer Industrie-Elektronik Ges.m.b.H.
21  *
22  * Wireshark - Network traffic analyzer
23  * By Gerald Combs <gerald@wireshark.org>
24  * Copyright 1998 Gerald Combs
25  *
26  * This program is free software; you can redistribute it and/or
27  * modify it under the terms of the GNU General Public License
28  * as published by the Free Software Foundation; either version 2
29  * of the License, or (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program; if not, write to the Free Software
38  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
39  */
40
41 #include "config.h"
42
43 #include <glib.h>
44
45 #include <epan/packet.h>
46 #include <epan/prefs.h>
47 #include <epan/etypes.h>
48 #include <epan/wmem/wmem.h>
49 #include <epan/expert.h>
50 #include <epan/reassemble.h>
51 #include <epan/strutil.h>
52 #include <epan/dissectors/packet-udp.h>
53 #include <epan/dissectors/packet-frame.h>
54
55 #include <wsutil/crc8.h>
56 #include <wsutil/crc16.h>
57
58 #include <stdio.h>
59 #include <string.h>
60
61
62 /* General definitions */
63
64 /* openSAFETY UDP Port */
65 #ifndef UDP_PORT_OPENSAFETY
66 #define UDP_PORT_OPENSAFETY   9877
67 #endif
68
69 /* SercosIII UDP Port */
70 #ifndef UDP_PORT_SIII
71 #define UDP_PORT_SIII         8755
72 #endif
73
74 #define OPENSAFETY_DEFAULT_DOMAIN       0x1
75
76 /* Under linux, this get's defined in netinet/in.h */
77 #ifndef IPPROTO_UDP
78 #define IPPROTO_UDP 0x11
79 #endif
80
81 #ifndef OPENSAFETY_PINFO_CONST_DATA
82 #define OPENSAFETY_PINFO_CONST_DATA 0xAABBCCDD
83 #endif
84
85 /* openSAFETY CRC types */
86 #define OPENSAFETY_CHECKSUM_CRC8        0x01
87 #define OPENSAFETY_CHECKSUM_CRC16       0x02
88 #define OPENSAFETY_CHECKSUM_CRC32       0x04
89 #define OPENSAFETY_CHECKSUM_CRC16SLIM   0x08
90
91 static const value_string message_crc_type[] = {
92     { OPENSAFETY_CHECKSUM_CRC8,         "CRC8" },
93     { OPENSAFETY_CHECKSUM_CRC16,        "CRC16" },
94     { OPENSAFETY_CHECKSUM_CRC32,        "CRC32" },
95     { OPENSAFETY_CHECKSUM_CRC16SLIM,    "CRC16 Slim" },
96     { 0, NULL }
97 };
98
99 /* openSAFETY Message Types */
100 #define OPENSAFETY_SPDO_MESSAGE_TYPE           0xC0
101 #define OPENSAFETY_SSDO_MESSAGE_TYPE           0xE0
102 #define OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE      0xE8
103 #define OPENSAFETY_SNMT_MESSAGE_TYPE           0xA0
104
105 static const value_string message_id_values[] = {
106     { OPENSAFETY_SPDO_MESSAGE_TYPE,      "openSAFETY SPDO" },
107     { OPENSAFETY_SSDO_MESSAGE_TYPE,      "openSAFETY SSDO" },
108     { OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE, "openSAFETY Slim SSDO" },
109     { OPENSAFETY_SNMT_MESSAGE_TYPE,      "openSAFETY SNMT" },
110     { 0, NULL }
111 };
112
113 /* openSAFETY Message IDs */
114 #define OPENSAFETY_MSG_SPDO_DATA_ONLY                  0xC0
115 #define OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST     0xC8
116 #define OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE    0xD0
117 #define OPENSAFETY_MSG_SPDO_RESERVED                   0xD8
118
119 #define OPENSAFETY_MSG_SSDO_SERVICE_REQUEST            0xE0
120 #define OPENSAFETY_MSG_SSDO_SERVICE_RESPONSE           0xE4
121 #define OPENSAFETY_MSG_SSDO_SLIM_SERVICE_REQUEST       0xE8
122 #define OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE      0xEC
123
124 #define OPENSAFETY_MSG_SNMT_REQUEST_UDID               0xA0
125 #define OPENSAFETY_MSG_SNMT_RESPONSE_UDID              0xA4
126 #define OPENSAFETY_MSG_SNMT_ASSIGN_SADR                0xA8
127 #define OPENSAFETY_MSG_SNMT_SADR_ASSIGNED              0xAC
128 #define OPENSAFETY_MSG_SNMT_SERVICE_REQUEST            0xB0
129 #define OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE           0xB4
130 #define OPENSAFETY_MSG_SNMT_SN_RESET_GUARDING_SCM      0xBC
131
132 static const value_string message_type_values[] = {
133     { OPENSAFETY_MSG_SPDO_DATA_ONLY,               "SPDO Data only" },
134     { OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST,  "SPDO Data with Time Request" },
135     { OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE, "SPDO Data with Time Response" },
136     { OPENSAFETY_MSG_SPDO_RESERVED,                "SPDO Reserved" },
137
138     { OPENSAFETY_MSG_SSDO_SERVICE_REQUEST,         "SSDO Service Request" },
139     { OPENSAFETY_MSG_SSDO_SERVICE_RESPONSE,        "SSDO Service Response" },
140     { OPENSAFETY_MSG_SSDO_SLIM_SERVICE_REQUEST,    "SSDO Slim Service Request" },
141     { OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE,   "SSDO Slim Service Response" },
142
143     { OPENSAFETY_MSG_SNMT_REQUEST_UDID,            "SNMT Request UDID" },
144     { OPENSAFETY_MSG_SNMT_RESPONSE_UDID,           "SNMT Response UDID" },
145     { OPENSAFETY_MSG_SNMT_ASSIGN_SADR,             "SNMT Assign SADR" },
146     { OPENSAFETY_MSG_SNMT_SADR_ASSIGNED,           "SNMT SADR Assigned" },
147     { OPENSAFETY_MSG_SNMT_SERVICE_REQUEST,         "SNMT Service Request" },
148     { OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE,        "SNMT Service Response" },
149     { OPENSAFETY_MSG_SNMT_SN_RESET_GUARDING_SCM,   "SNMT SN reset guarding SCM" },
150     {0, NULL }
151 };
152
153 /* SNTM extended Services */
154 #define OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_PRE_OP              0x00
155 #define OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_OP                  0x02
156 #define OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP               0x04
157 #define OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP                 0x06
158 #define OPENSAFETY_MSG_SNMT_EXT_SCM_GUARD_SN                  0x08
159 #define OPENSAFETY_MSG_SNMT_EXT_ASSIGN_ADDITIONAL_SADR        0x0A
160 #define OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE                0x0C
161 #define OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGN_UDID_SCM            0x0E
162 #define OPENSAFETY_MSG_SNMT_EXT_SN_STATUS_PRE_OP              0x01
163 #define OPENSAFETY_MSG_SNMT_EXT_SN_STATUS_OP                  0x03
164 #define OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_ADDITIONAL_SADR   0x05
165 #define OPENSAFETY_MSG_SNMT_EXT_SN_FAIL                       0x07
166 #define OPENSAFETY_MSG_SNMT_EXT_SN_BUSY                       0x09
167 #define OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_UDID_SCM          0x0F
168
169 static const value_string message_service_type[] = {
170     { OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_PRE_OP,             "SN set to pre Operational" },
171     { OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_OP,                 "SN set to Operational" },
172     { OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP,              "SCM set to Stop" },
173     { OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP,                "SCM set to Operational" },
174     { OPENSAFETY_MSG_SNMT_EXT_SCM_GUARD_SN,                 "SCM guard SN" },
175     { OPENSAFETY_MSG_SNMT_EXT_ASSIGN_ADDITIONAL_SADR,       "Assign additional SADR" },
176     { OPENSAFETY_MSG_SNMT_EXT_SN_ACKNOWLEDGE,               "SN Acknowledge" },
177     { OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGN_UDID_SCM,           "SN assign UDID SCM" },
178     { OPENSAFETY_MSG_SNMT_EXT_SN_STATUS_PRE_OP,             "SN status pre Operational" },
179     { OPENSAFETY_MSG_SNMT_EXT_SN_STATUS_OP,                 "SN status Operational" },
180     { OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_ADDITIONAL_SADR,  "Assigned additional SADR" },
181     { OPENSAFETY_MSG_SNMT_EXT_SN_FAIL,                      "SN Fail" },
182     { OPENSAFETY_MSG_SNMT_EXT_SN_BUSY,                      "SN Busy" },
183     { OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_UDID_SCM,         "SN assigned UDID SCM" },
184     { 0, NULL }
185 };
186
187 /* Values 6-255 are reserved for future use. They will be presented as "Reserved [%d]"
188  * during dissection
189  */
190 #define OPENSAFETY_ERROR_GROUP_APPLICATION                  0x01
191 #define OPENSAFETY_ERROR_GROUP_PARAMETER                    0x02
192 #define OPENSAFETY_ERROR_GROUP_VENDOR_SPECIFIC              0x03
193 #define OPENSAFETY_ERROR_GROUP_OPENSAFETY_STACK             0x04
194 #define OPENSAFETY_ERROR_GROUP_ADD_PARAMETER                0x05
195
196 static const value_string sn_fail_error_group[] = {
197     { OPENSAFETY_ERROR_GROUP_APPLICATION,       "Application" },
198     { OPENSAFETY_ERROR_GROUP_PARAMETER,         "Parameter" },
199     { OPENSAFETY_ERROR_GROUP_VENDOR_SPECIFIC,   "Vendor specific" },
200     { OPENSAFETY_ERROR_GROUP_OPENSAFETY_STACK,  "openSAFETY Stack" },
201     { OPENSAFETY_ERROR_GROUP_ADD_PARAMETER,     "Additional parameter needed" },
202     { 0, NULL }
203 };
204
205 /* SNTM extended Services */
206 #define OPENSAFETY_MSG_SSDO_ABORT                           0x04
207 #define OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_MIDDLE           0x08
208 #define OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_MIDDLE         0x09
209 #define OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_EXPEDITED       0x20
210 #define OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_EXPEDITED     0x21
211 #define OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_SEGMENTED       0x28
212 #define OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_SEGMENTED     0x29
213 #define OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END              0x48
214 #define OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_END            0x49
215 #if 0
216 #define OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_SEGMENT_MIDDLE     0x88
217 #define OPENSAFETY_MSG_SSDO_BLOCK_DOWNLOAD_SEGMENT_MIDDLE   0x89
218 #define OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_INITIATE           0xA8
219 #define OPENSAFETY_MSG_SSDO_BLOCK_DOWNLOAD_INITIATE         0xA9
220 #define OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_INITIATE_EXPEDITED 0xC0
221 #define OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_SEGMENT_END        0x40
222 #define OPENSAFETY_MSG_SSDO_BLOCK_DOWNLOAD_SEGMENT_END      0xC9
223 #endif
224
225 static const value_string ssdo_sacmd_values[] = {
226 #if 0
227     { OPENSAFETY_MSG_SSDO_BLOCK_DOWNLOAD_SEGMENT_END,     "Block Download Segment End" },
228     { OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_INITIATE,          "Block Upload Expedited Initiate" },
229     { OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_INITIATE_EXPEDITED,"Block Upload Initiate" },
230     { OPENSAFETY_MSG_SSDO_BLOCK_DOWNLOAD_INITIATE,        "Block Download Initiate" },
231     { OPENSAFETY_MSG_SSDO_BLOCK_DOWNLOAD_SEGMENT_MIDDLE,  "Block Download Middle Segment" },
232     { OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_SEGMENT_MIDDLE,    "Block Upload Middle Segment" },
233     { OPENSAFETY_MSG_SSDO_BLOCK_UPLOAD_SEGMENT_END,       "Block Upload End Segment" },
234 #endif
235     { OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_END,           "Download End Segment" },
236     { OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END,             "Upload End Segment" },
237     { OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_EXPEDITED,    "Download Expedited Initiate" },
238     { OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_SEGMENTED,      "Upload Initiate Segmented" },
239     { OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_SEGMENTED,    "Download Initiate Segmented" },
240     { OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_EXPEDITED,      "Upload Expedited Initiate" },
241     { OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_MIDDLE,        "Download Middle Segment" },
242     { OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_MIDDLE,          "Upload Middle Segment" },
243     { OPENSAFETY_MSG_SSDO_ABORT,                           "Abort" },
244     { 0, NULL }
245 };
246
247 #define OPENSAFETY_SSDO_SACMD_ACC  0x01
248 #define OPENSAFETY_SSDO_SACMD_RES  0x02
249 #define OPENSAFETY_SSDO_SACMD_ABRT 0x04
250 #define OPENSAFETY_SSDO_SACMD_SEG  0x08
251 #define OPENSAFETY_SSDO_SACMD_TGL  0x10
252 #define OPENSAFETY_SSDO_SACMD_INI  0x20
253 #define OPENSAFETY_SSDO_SACMD_ENSG 0x40
254 #define OPENSAFETY_SSDO_SACMD_BLK  0x80
255
256 static const true_false_string opensafety_sacmd_acc  = { "Write Access", "Read Access" };
257 #if 0
258 static const true_false_string opensafety_sacmd_res  = { "Reserved", "Reserved" };
259 #endif
260 static const true_false_string opensafety_sacmd_abrt = { "Abort Transfer", "Successful Transfer" };
261 static const true_false_string opensafety_sacmd_seg  = { "Segmented Access", "Expedited Access" };
262 static const true_false_string opensafety_on_off     = { "On", "Off" };
263 static const true_false_string opensafety_set_notset = { "Set", "Not set" };
264 static const true_false_string opensafety_sacmd_ini  = { "Initiate", "No Initiate" };
265 static const true_false_string opensafety_sacmd_ensg = { "No more segments", "More segments" };
266 static const true_false_string opensafety_sacmd_blk  = { "Block Transfer", "Normal Transfer" };
267
268 #define OPENSAFETY_SPDO_CONNECTION_VALID  0x04
269
270 #define OPENSAFETY_SOD_DVI 0x1018
271 #define OPENSAFETY_SOD_RXMAP 0x1800
272 #define OPENSAFETY_SOD_TXMAP 0xC000
273
274 static const value_string sod_idx_names[] = {
275     /* SSDO dictionary names, only names that are in common use are presented */
276     { 0x100C0000, "Life Guarding" },
277     { 0x100C0001, "Guard Time" },
278     { 0x100C0002, "LifeTimeFactor" },
279
280     { 0x100D0000, "Number of Retries for Reset Guarding" },
281
282     { 0x10180000 ,  "Device Vendor Information" },
283     { 0x10180001,  "VendorID" },
284     { 0x10180002,  "ProductCode" },
285     { 0x10180003,  "RevisionNumber" },
286     { 0x10180004,  "SerialNumber" },
287     { 0x10180005,  "FirmWareChecksum" },
288     { 0x10180006,  "Parameter Checksum" },
289     { 0x10180007,  "Parameter Timestamp" },
290
291     { 0x10190000,  "Unique Device ID" },
292     { 0x101A0000,  "Parameter Download" },
293     { 0x101B0000,  "SCM Parameters" },
294
295     { 0x12000000, "Common Communication Parameters" },
296     { 0x12000001, "Safety Domain Number" },
297     { 0x12000002, "SADR" },
298     { 0x12000003, "Consecutive Timebase" },
299     { 0x12000004, "UDID of SCM" },
300
301     { 0x14000000, "RxSPDO Communication Parameters" },
302     { 0x14000001, "SADR" },
303     { 0x14000002, "SCT" },
304     { 0x14000003, "Number of consecutive TReq" },
305     { 0x14000004, "Time delay TReq" },
306     { 0x14000005, "Time delay Sync" },
307     { 0x14000006, "Min TSync Propagation Delay" },
308     { 0x14000007, "Max TSync Propagation Delay" },
309     { 0x14000008, "Min SPDO Propagation Delay" },
310     { 0x14000009, "Max SPDO Propagation Delay" },
311     { 0x1400000A, "Best case TRes Delay" },
312     { 0x1400000B, "Time Request Cycle" },
313     { 0x1400000C, "TxSPDO No" },
314
315     { 0x18000000, "RxSPDO Mapping Parameters" },
316
317     { 0x1C000000, "TxSPDO Communication Parameters" },
318     { 0x1C000001, "SADR for broadcast" },
319     { 0x1C000002, "Refresh Prescale" },
320     { 0x1C000003, "Number of TRes" },
321
322     { 0x20000000, "Manufacturer Parameters" },
323     { 0x20010000, "Used Channels" },
324
325     { 0x21000000, "Safe Machine Options" },
326
327     { 0x21010000, "SDG CRC Configuration" },
328     { 0x21010001, "SDG CRC #1" },
329     { 0x21010002, "SDG CRC #2" },
330     { 0x21010003, "SDG CRC #3" },
331     { 0x21010004, "SDG CRC #4" },
332     { 0x21010005, "SDG CRC #5" },
333     { 0x21010006, "SDG CRC #6" },
334     { 0x21010007, "SDG CRC #7" },
335     { 0x21010008, "SDG CRC #8" },
336     { 0x21010009, "SDG CRC #9" },
337     { 0x2101000A, "SDG CRC #10" },
338
339     { 0x21120000, "Manufacturer - Module specific" },
340     { 0x21120002, "PDOmapRx" },
341     { 0x21120003, "PDOmapTx" },
342     { 0x21120004, "CycleTime min [us]" },
343     { 0x21120005, "CycleTime max [us]" },
344     { 0x21120006, "Used Channels (same as 0x2001)" },
345     { 0x21120007, "External Machine Options" },
346     { 0x21120008, "Parameter for SafeMC" },
347
348     { 0xC0000000, "TxSPDO Mapping Parameters" },
349
350     { 0xD0000000, "SCM Module Flags" },
351     { 0xD0000001, "BCM" },
352     { 0xD0000002, "Optional" },
353     { 0xD0000003, "Startup" },
354     { 0xD0000004, "EMOs" },
355     { 0xD0000005, "ext. Startup-Flags allowed" },
356     { 0xD0000006, "Remote-Ctrl allowed" },
357     { 0xD0000007, "Scans at startup" },
358     { 0xD0000008, "Not Present" },
359     { 0xD0000009, "Use Remanent Data" },
360     { 0xD000000A, "SCM-AR specific" },
361
362     { 0xD0100000, "Remanent Data" },
363     { 0xD0100001, "DINT" },
364
365     { 0xD0110000, "Remanent Data" },
366     { 0xD0110001, "DUINT" },
367
368     { 0, NULL }
369 };
370
371 static const value_string abort_codes[] = {
372
373     /* SSDO abort codes */
374     { 0x05030000,  "Reserved" },
375
376     { 0x05040000,  "SSDO protocol timed out" },
377     { 0x05040001,  "Client/server Command ID not valid or unknown" },
378     { 0x05040002,  "Invalid block size" },
379     { 0x05040003,  "Invalid sequence number" },
380     { 0x05040004,  "Reserved" },
381     { 0x05040005,  "Out of memory" },
382
383     { 0x06010000,  "Unsupported access to an object" },
384     { 0x06010001,  "Attempt to read a write-only object" },
385     { 0x06010002,  "Attempt to write a read-only object" },
386
387     { 0x06020000,  "Object does not exist in the object dictionary" },
388
389     { 0x06040041,  "Object cannot be mapped to the SPDO" },
390     { 0x06040042,  "The number and length of the objects to be mapped would exceed SPDO length" },
391     { 0x06040043,  "General parameter incompatibility" },
392     { 0x06040047,  "General internal incompatibility in the device" },
393
394     { 0x06060000,  "Access failed due to a hardware error" },
395
396     { 0x06070010,  "Data type does not match, length of service parameter does not match" },
397     { 0x06070012,  "Data type does not match, length of service parameter too high" },
398     { 0x06070013,  "Data type does not match, length of service parameter too low" },
399
400     { 0x06090011,  "Sub-index does not exist" },
401     { 0x06090030,  "Value range o parameter exceeded (only for write access)" },
402     { 0x06090031,  "Value of parameter written too high" },
403     { 0x06090032,  "Value of parameter written too low" },
404     { 0x06090036,  "Maximum value is less than minimum value" },
405
406     { 0x08000000,  "General error" },
407     { 0x08000020,  "Data cannot be transferred or stored to the application" },
408     { 0x08000021,  "Data cannot be transferred or stored to the application because of local control" },
409     { 0x08000022,  "Data cannot be transferred or stored to the application because of the present device state" },
410     { 0x08000023,  "Data cannot be transferred or stored to the application because of the object data is not available now" },
411
412     { 0, NULL }
413 };
414
415 static const true_false_string opensafety_message_direction = { "Request", "Response" };
416 #define OPENSAFETY_REQUEST  TRUE
417 #define OPENSAFETY_RESPONSE FALSE
418
419 static const true_false_string opensafety_addparam_request = { "Header only", "Header & Data" };
420
421 #define OSS_FRAME_POS_ADDR   0
422 #define OSS_FRAME_POS_ID     1
423 #define OSS_FRAME_POS_LEN    2
424 #define OSS_FRAME_POS_CT     3
425 #define OSS_FRAME_POS_DATA   4
426
427 #define OSS_PAYLOAD_MAXSIZE_FOR_CRC8        0x08
428 #define OSS_SLIM_FRAME_WITH_CRC8_MAXSIZE    0x13   /* 19 */
429 #define OSS_SLIM_FRAME2_WITH_CRC8           0x06   /*  6 */
430 #define OSS_SLIM_FRAME2_WITH_CRC16          0x07   /*  7 */
431 #define OSS_MINIMUM_LENGTH                  0x0b   /* 11 */
432
433 #define OSS_FRAME_ADDR(f, offset)        (f[OSS_FRAME_POS_ADDR + offset] + ((guint8)((f[OSS_FRAME_POS_ADDR + offset + 1]) << 6) << 2))
434 #define OSS_FRAME_ID(f, offset)          (f[OSS_FRAME_POS_ID + offset] & 0xFC )
435 #define OSS_FRAME_LENGTH(f, offset)      (f[OSS_FRAME_POS_LEN + offset])
436 #define OSS_FRAME_FIELD(f, position)       (f[position])
437
438 #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))
439 #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))
440 #define OSS_FRAME_ID_T(f, offset)          (tvb_get_guint8(f, OSS_FRAME_POS_ID + offset) & 0xFC)
441 #define OSS_FRAME_LENGTH_T(f, offset)      (tvb_get_guint8(f, OSS_FRAME_POS_LEN + offset))
442
443 static int proto_opensafety = -1;
444
445 static gint ett_opensafety = -1;
446 static gint ett_opensafety_checksum = -1;
447 static gint ett_opensafety_snmt = -1;
448 static gint ett_opensafety_ssdo = -1;
449 static gint ett_opensafety_spdo = -1;
450 static gint ett_opensafety_ssdo_sacmd = -1;
451 static gint ett_opensafety_ssdo_payload = -1;
452 static gint ett_opensafety_ssdo_sodentry = -1;
453 static gint ett_opensafety_ssdo_extpar = -1;
454 static gint ett_opensafety_sod_mapping = -1;
455 static gint ett_opensafety_sender = -1;
456 static gint ett_opensafety_receiver = -1;
457
458 static expert_field ei_payload_length_not_positive = EI_INIT;
459 static expert_field ei_payload_unknown_format = EI_INIT;
460 static expert_field ei_crc_slimssdo_instead_of_spdo = EI_INIT;
461 static expert_field ei_crc_frame_1_invalid = EI_INIT;
462 static expert_field ei_crc_frame_1_valid_frame2_invalid = EI_INIT;
463 static expert_field ei_crc_frame_2_invalid = EI_INIT;
464 static expert_field ei_crc_frame_2_unknown_scm_udid = EI_INIT;
465 static expert_field ei_message_unknown_type = EI_INIT;
466 static expert_field ei_message_reassembly_size_differs_from_header = EI_INIT;
467 static expert_field ei_message_spdo_address_invalid = EI_INIT;
468 static expert_field ei_message_id_field_mismatch = EI_INIT;
469 static expert_field ei_scmudid_autodetected = EI_INIT;
470 static expert_field ei_scmudid_invalid_preference = EI_INIT;
471 static expert_field ei_scmudid_unknown = EI_INIT;
472
473 static int hf_oss_msg = -1;
474 static int hf_oss_msg_direction = -1;
475 static int hf_oss_msg_category = -1;
476 static int hf_oss_msg_node = -1;
477 static int hf_oss_msg_network = -1;
478 static int hf_oss_msg_sender = -1;
479 static int hf_oss_msg_receiver = -1;
480 static int hf_oss_length= -1;
481 static int hf_oss_crc = -1;
482
483 static int hf_oss_crc_valid = -1;
484 static int hf_oss_crc2_valid = -1;
485 static int hf_oss_crc_type  = -1;
486
487 static int hf_oss_snmt_slave         = -1;
488 static int hf_oss_snmt_master        = -1;
489 static int hf_oss_snmt_udid          = -1;
490 static int hf_oss_snmt_scm           = -1;
491 static int hf_oss_snmt_tool          = -1;
492 static int hf_oss_snmt_service_id    = -1;
493 static int hf_oss_snmt_error_group   = -1;
494 static int hf_oss_snmt_error_code    = -1;
495 static int hf_oss_snmt_param_type    = -1;
496 static int hf_oss_snmt_ext_addsaddr  = -1;
497 static int hf_oss_snmt_ext_addtxspdo = -1;
498
499 static int hf_oss_ssdo_server        = -1;
500 static int hf_oss_ssdo_client        = -1;
501 static int hf_oss_ssdo_sano          = -1;
502 static int hf_oss_ssdo_sacmd         = -1;
503 static int hf_oss_ssdo_sod_index     = -1;
504 static int hf_oss_ssdo_sod_subindex  = -1;
505 static int hf_oss_ssdo_payload       = -1;
506 static int hf_oss_ssdo_payload_size  = -1;
507 static int hf_oss_ssdo_sodentry_size = -1;
508 static int hf_oss_ssdo_sodentry_data = -1;
509 /* static int hf_oss_ssdo_inhibit_time  = -1; */
510 static int hf_oss_ssdo_abort_code    = -1;
511
512 static int hf_oss_sod_par_timestamp = -1;
513 static int hf_oss_sod_par_checksum  = -1;
514 static int hf_oss_ssdo_sodmapping = -1;
515 static int hf_oss_ssdo_sodmapping_bits = -1;
516
517 static int hf_oss_ssdo_sacmd_access_type     = -1;
518 /* static int hf_oss_ssdo_sacmd_reserved        = -1; */
519 static int hf_oss_ssdo_sacmd_abort_transfer  = -1;
520 static int hf_oss_ssdo_sacmd_segmentation    = -1;
521 static int hf_oss_ssdo_sacmd_toggle          = -1;
522 static int hf_oss_ssdo_sacmd_initiate        = -1;
523 static int hf_oss_ssdo_sacmd_end_segment     = -1;
524 static int hf_oss_ssdo_sacmd_block_transfer  = -1;
525
526 static int hf_oss_ssdo_extpar_parset = -1;
527 static int hf_oss_ssdo_extpar_version = -1;
528 static int hf_oss_ssdo_extpar_saddr = -1;
529 static int hf_oss_ssdo_extpar_length = -1;
530 static int hf_oss_ssdo_extpar_crc = -1;
531 static int hf_oss_ssdo_extpar_tstamp = -1;
532 static int hf_oss_ssdo_extpar_data = -1;
533 static int hf_oss_ssdo_extpar = -1;
534
535 static int hf_oss_scm_udid           = -1;
536 static int hf_oss_scm_udid_auto      = -1;
537 static int hf_oss_scm_udid_valid     = -1;
538
539 static int hf_oss_spdo_connection_valid   = -1;
540 static int hf_oss_spdo_payload            = -1;
541 static int hf_oss_spdo_producer           = -1;
542 static int hf_oss_spdo_producer_time      = -1;
543 static int hf_oss_spdo_time_value_sn      = -1;
544 static int hf_oss_spdo_time_request       = -1;
545 static int hf_oss_spdo_time_request_to    = -1;
546 static int hf_oss_spdo_time_request_from  = -1;
547
548 static int hf_oss_fragments = -1;
549 static int hf_oss_fragment = -1;
550 static int hf_oss_fragment_overlap = -1;
551 static int hf_oss_fragment_overlap_conflicts = -1;
552 static int hf_oss_fragment_multiple_tails = -1;
553 static int hf_oss_fragment_too_long_fragment = -1;
554 static int hf_oss_fragment_error = -1;
555 static int hf_oss_fragment_count = -1;
556 static int hf_oss_reassembled_in = -1;
557 static int hf_oss_reassembled_length = -1;
558 static int hf_oss_reassembled_data = -1;
559
560 static gint ett_opensafety_ssdo_fragment = -1;
561 static gint ett_opensafety_ssdo_fragments = -1;
562
563 static const fragment_items oss_frag_items = {
564     /* Fragment subtrees */
565     &ett_opensafety_ssdo_fragment,
566     &ett_opensafety_ssdo_fragments,
567     /* Fragment fields */
568     &hf_oss_fragments,
569     &hf_oss_fragment,
570     &hf_oss_fragment_overlap,
571     &hf_oss_fragment_overlap_conflicts,
572     &hf_oss_fragment_multiple_tails,
573     &hf_oss_fragment_too_long_fragment,
574     &hf_oss_fragment_error,
575     &hf_oss_fragment_count,
576     /* Reassembled in field */
577     &hf_oss_reassembled_in,
578     /* Reassembled length field */
579     &hf_oss_reassembled_length,
580     /* Reassembled data */
581     &hf_oss_reassembled_data,
582     /* Tag */
583     "Message fragments"
584 };
585
586 static const char *global_scm_udid = "00:00:00:00:00:00";
587 static gboolean global_calculate_crc2 = FALSE;
588 static gboolean global_scm_udid_autoset = TRUE;
589 static gboolean global_udp_frame2_first = FALSE;
590 static gboolean global_siii_udp_frame2_first = FALSE;
591 static gboolean global_mbtcp_big_endian = FALSE;
592 static guint global_network_udp_port = UDP_PORT_OPENSAFETY;
593 static guint global_network_udp_port_sercosiii = UDP_PORT_SIII;
594
595 static gboolean global_enable_plk = TRUE;
596 static gboolean global_enable_udp = TRUE;
597 static gboolean global_enable_genudp = TRUE;
598 static gboolean global_enable_siii = TRUE;
599 static gboolean global_enable_pnio = FALSE;
600 static gboolean global_enable_mbtcp = TRUE;
601
602 static gboolean bDissector_Called_Once_Before = FALSE;
603 /* Using local_scm_udid as read variable for global_scm_udid, to
604  * enable automatic detection of scm udid */
605 static char *local_scm_udid = NULL;
606
607 static reassembly_table os_reassembly_table;
608
609 /* Resets the dissector in case the dissection is malformed and the dissector crashes */
610 static void
611 reset_dissector(void)
612 {
613     bDissector_Called_Once_Before = FALSE;
614 }
615
616 static void
617 setup_dissector(void)
618 {
619     if ( local_scm_udid != NULL )
620         local_scm_udid = NULL;
621
622     reassembly_table_init(&os_reassembly_table, &addresses_reassembly_table_functions);
623 }
624
625 void proto_register_opensafety(void);
626 void proto_reg_handoff_opensafety(void);
627
628 /* Conversation functions */
629
630 /* This is defined by the specification. The Address field is 10 bits long, and the node with the number
631  *  1 is always the SCM, therefore ( 2 ^ 10 ) - 1 nodes can be addressed. We use 2 ^ 10 here, because the
632  *  SCM can talk to himself (Assign SADR for instance ) */
633 #define MAX_NUMBER_OF_SAFETY_NODES      ( 2 ^ 10 )
634
635 /* Tracks the information that the packet pinfo has been received by receiver, and adds that information to the tree, using pos, as
636  * byte position in the PDU */
637 #define PACKET_RECEIVER(pinfo, recv, pos, posnet, sdn)                       { \
638         proto_item * psf_item = NULL; \
639         proto_tree *psf_tree = NULL; \
640         psf_item = proto_tree_add_uint(opensafety_tree, hf_oss_msg_receiver, message_tvb, pos, 2, recv); \
641         psf_tree = proto_item_add_subtree(psf_item, ett_opensafety_receiver); \
642         psf_item = proto_tree_add_uint(psf_tree, hf_oss_msg_node, message_tvb, pos, 2, recv);\
643         PROTO_ITEM_SET_GENERATED(psf_item); \
644         if ( sdn > 0 ) \
645         { \
646             psf_item = proto_tree_add_uint_format_value(psf_tree, hf_oss_msg_network, message_tvb, posnet, 2, sdn, "0x%04X", sdn); \
647         } else if ( sdn <= 0 ) { \
648             psf_item = proto_tree_add_uint_format_value(psf_tree, hf_oss_msg_network, message_tvb, posnet, 2, sdn * -1, "0x%04X", sdn * -1); \
649             expert_add_info(pinfo, psf_item, &ei_scmudid_unknown ); \
650         } \
651         PROTO_ITEM_SET_GENERATED(psf_item); \
652         }
653
654 /* Tracks the information that the packet pinfo has been sent by sender, and received by everyone else, and adds that information to
655  * the tree, using pos, as byte position in the PDU */
656 #define PACKET_SENDER(pinfo, sender, pos, posnet, sdn)                { \
657         proto_item * psf_item = NULL; \
658         proto_tree *psf_tree = NULL; \
659         psf_item = proto_tree_add_uint(opensafety_tree, hf_oss_msg_sender, message_tvb, pos, 2, sender); \
660         psf_tree = proto_item_add_subtree(psf_item, ett_opensafety_sender); \
661         psf_item = proto_tree_add_uint(psf_tree, hf_oss_msg_node, message_tvb, pos, 2, sender);\
662         PROTO_ITEM_SET_GENERATED(psf_item); \
663         if ( sdn > 0 ) \
664         { \
665             psf_item = proto_tree_add_uint_format_value(psf_tree, hf_oss_msg_network, message_tvb, posnet, 2, sdn, "0x%04X", sdn); \
666         } else if ( sdn <= 0 ) { \
667             psf_item = proto_tree_add_uint_format_value(psf_tree, hf_oss_msg_network, message_tvb, posnet, 2, sdn * -1, "0x%04X", sdn * -1); \
668             expert_add_info(pinfo, psf_item, &ei_scmudid_unknown ); \
669         } \
670         PROTO_ITEM_SET_GENERATED(psf_item); \
671         }
672
673 /* Tracks the information that the packet pinfo has been sent by sender, and received by receiver, and adds that information to
674  * the tree, using pos for the sender and pos2 for the receiver, as byte position in the PDU */
675 #define PACKET_SENDER_RECEIVER(pinfo, send, pos, recv, pos2, posnet, sdn)         { \
676         PACKET_SENDER(pinfo, send, pos, posnet, sdn); \
677         PACKET_RECEIVER(pinfo, recv, pos2, posnet, sdn); \
678         }
679
680 static guint16
681 findFrame1Position ( tvbuff_t *message_tvb, guint16 byte_offset, guint8 dataLength, gboolean checkIfSlimMistake )
682 {
683     guint16 i_wFrame1Position                   = 0;
684     guint16 i_payloadLength, i_calculatedLength = 0;
685     guint16 i_offset                            = 0, calcCRC = 0, frameCRC = 0;
686     guint8  b_tempByte                          = 0;
687     guint8 *bytes = NULL;
688
689     /*
690      * First, a normal package get's assumed. Calculation of frame 1 position is
691      * pretty easy, because, the length of the whole package is 11 + 2*n + 2*o, which
692      * results in frame 1 start at (6 + n + o), which is length / 2 + 1
693      */
694     i_wFrame1Position = dataLength / 2 + 1;
695     i_payloadLength = tvb_get_guint8(message_tvb, byte_offset + i_wFrame1Position + 2 );
696     /* Calculating the assumed frame length, taking CRC8/CRC16 into account */
697     i_calculatedLength = i_payloadLength * 2 + 11 + 2 * (i_payloadLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? 1 : 0);
698
699     /* To prevent miscalculations, where by chance the byte at [length / 2] + 3 is a value matching a possible payload length,
700      * but in reality the frame is a slim ssdo, the CRC of frame 1 get's checked additionally. This check
701      * is somewhat time consuming, so it will only run if the normal check led to a mistake detected along the line */
702     if ( checkIfSlimMistake && i_calculatedLength == dataLength )
703     {
704         if (dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
705             frameCRC = tvb_get_letohs(message_tvb,  byte_offset + i_wFrame1Position + dataLength + OSS_FRAME_POS_DATA);
706         else
707             frameCRC = tvb_get_guint8(message_tvb,  byte_offset + i_wFrame1Position + dataLength + OSS_FRAME_POS_DATA);
708
709         bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, byte_offset + i_wFrame1Position, dataLength + 4);
710         if ( dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
711         {
712             calcCRC = crc16_0x755B(bytes, dataLength + 4, 0);
713             if ( frameCRC != calcCRC )
714                 calcCRC = crc16_0x5935(bytes, dataLength + 4, 0);
715         }
716         else
717             calcCRC = crc8_0x2F(bytes, dataLength + 4, 0);
718
719         /* if the calculated crc does not match the detected, the package is not a normal openSAFETY package */
720         if ( frameCRC != calcCRC )
721             dataLength = 0;
722     }
723
724     /* If the calculated length differs from the given length, a slim package is assumed. */
725     if ( i_calculatedLength != dataLength )
726     {
727         /* possible slim package */
728         i_wFrame1Position = 0;
729         /*
730          * Slim packages have a fixed sublength of either 6 bytes for frame 2 in
731          * case of crc8 and 7 bytes in case of crc16
732          */
733         i_offset = OSS_SLIM_FRAME2_WITH_CRC8 + ( dataLength < (OSS_SLIM_FRAME_WITH_CRC8_MAXSIZE + 1) ? 0 : 1 );
734         /* Last 2 digits belong to addr, therefore have to be cleared */
735         b_tempByte = ( tvb_get_guint8 ( message_tvb, byte_offset + i_offset + 1 ) ) & 0xFC;
736
737         /* If the id byte xor 0xE8 is 0, we have a slim package */
738         if ( ( ( b_tempByte ^ OPENSAFETY_MSG_SSDO_SLIM_SERVICE_REQUEST ) == 0 ) ||
739              ( ( b_tempByte ^ OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE ) == 0 ) )
740         {
741             /* Slim package found */
742             i_wFrame1Position = i_offset;
743         }
744     }
745
746     return i_wFrame1Position;
747 }
748
749 static guint8 findSafetyFrame ( tvbuff_t * message_tvb, guint u_Offset, gboolean b_frame2first, guint *u_frameOffset, guint *u_frameLength )
750 {
751     guint    ctr, rem_length;
752     guint16  crc, f2crc, calcCrc;
753     guint8   b_Length, crcOffset;
754     guint8   *bytes;
755     guint    b_ID;
756     gboolean found;
757
758     found = 0;
759     ctr = u_Offset;
760     rem_length = tvb_reported_length_remaining (message_tvb, ctr);
761
762     while ( rem_length >= OSS_MINIMUM_LENGTH)
763     {
764         /* The ID byte must ALWAYS be the second byte, therefore 0 is invalid */
765         if ( ctr != 0 )
766         {
767             *u_frameLength = 0;
768             *u_frameOffset = 0;
769
770             crcOffset = 0;
771             b_ID = tvb_get_guint8(message_tvb, ctr );
772
773             if ( b_ID != 0x0 )
774             {
775                 b_Length = tvb_get_guint8(message_tvb, ctr + 1 );
776
777                 /* 0xFF is often used, but always false, otherwise start detection, if the highest
778                  *  bit is set */
779                 if ( ( b_ID != 0xFF ) && ( b_ID & 0x80 ) )
780                 {
781                     /* The rem_length value might be poluted, due to the else statement of
782                      * above if-decision (frame at end position detection). Therefore we
783                      * calculate it here again, to have a sane value */
784                     rem_length = tvb_reported_length_remaining(message_tvb, ctr);
785
786                     /* Plausability check on length */
787                     if ( (guint)( b_Length * 2 ) < ( rem_length + OSS_MINIMUM_LENGTH ) )
788                     {
789
790                         /* The calculated length must fit, but for the CRC16 check, also the calculated length
791                         * plus the CRC16 end position must fit in the remaining length */
792                         if ( ( b_Length <= (guint) 8 && ( b_Length <= rem_length ) ) ||
793                             ( b_Length > (guint) 8 && ( ( b_Length + (guint) 5 ) <= rem_length ) ) )
794                         {
795                             /* Ensure, that the correct length for CRC calculation
796                              * still exists in byte stream, so that we can calculate the crc */
797                             if ( tvb_bytes_exist(message_tvb, ctr - 1, b_Length + 5) )
798                             {
799                                 /* An openSAFETY command has to have a high-byte range between 0x0A and 0x0E
800                                  *  b_ID & 0x80 took care of everything underneath, we check for 0x09 and 0x0F,
801                                  *  as they remain the only values left, which are not valid */
802                                 if ( ( ( b_ID >> 4 ) != 0x09 ) && ( ( b_ID >> 4 ) != 0x0F ) )
803                                 {
804                                     /* Find CRC position and calculate checksum */
805                                     crc = tvb_get_guint8(message_tvb, ctr + 3 + b_Length );
806
807                                     bytes = (guint8 *)tvb_memdup(wmem_packet_scope(), message_tvb, ctr - 1, b_Length + 5 );
808                                     if ( b_Length > 8 ) {
809                                         crc = tvb_get_letohs ( message_tvb, ctr + 3 + b_Length );
810                                         crcOffset = 1;
811
812                                         calcCrc = crc16_0x755B( bytes, b_Length + 4, 0 );
813                                         if ( ( crc ^ calcCrc ) != 0 )
814                                             calcCrc = crc16_0x5935( bytes, b_Length + 4, 0 );
815                                     } else {
816                                         calcCrc = crc8_0x2F ( bytes, b_Length + 4, 0 );
817                                     }
818
819                                     if ( ( crc ^ calcCrc ) == 0 )
820                                     {
821                                         /* Check if this is a Slim SSDO message */
822                                         if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
823                                         {
824                                             /* Slim SSDO messages must have a length != 0, as the first byte
825                                              * in the payload contains the SOD access command */
826                                             if ( b_Length > 0 )
827                                             {
828                                                 *u_frameOffset = ( ctr - 1 );
829                                                 *u_frameLength = b_Length + 2 * crcOffset + 11;
830
831                                                 /* It is highly unlikely, that both frame 1 and frame 2 generate
832                                                  * a crc == 0 or equal crc's. Therefore we check, if both crc's are
833                                                  * equal. If so, it is a falsely detected frame. */
834                                                 f2crc = tvb_get_guint8 ( message_tvb, ctr + 3 + 5 + b_Length );
835                                                 if ( b_Length > 8 )
836                                                     f2crc = tvb_get_letohs ( message_tvb, ctr + 3 + 5 + b_Length );
837                                                 if ( crc != f2crc )
838                                                 {
839                                                     found = 1;
840                                                     break;
841                                                 }
842                                             }
843                                         }
844                                         else
845                                         {
846                                             *u_frameLength = 2 * b_Length + 2 * crcOffset + 11;
847                                             *u_frameOffset = ( ctr - 1 );
848
849                                             /* At this point frames had been checked for SoC and SoA types of
850                                              * EPL. This is no longer necessary and leads to false-negatives.
851                                              * SoC and SoA frames get filtered out at the EPL entry point. */
852                                             found = 1;
853                                             break;
854                                         }
855                                     }
856                                 }
857                             }
858                         }
859                     }
860                 }
861                 else
862                 {
863                     /* There exist frames, where the last openSAFETY frame is sitting in the
864                      * very last bytes of the frame, and the complete frame itself contains
865                      * more than one openSAFETY frame. It so happens that in such a case, the
866                      * last openSAFETY frame will miss detection.
867                      *
868                      * If so we look at the transported length, calculate the frame length,
869                      * and take a look if the calculated frame length, might be a fit for the
870                      * remaining length. If such is the case, we increment ctr and increment
871                      * rem_length (to hit the while loop one more time) and the frame will be
872                      * detected correctly. */
873                     if ( rem_length == OSS_MINIMUM_LENGTH )
874                     {
875                         b_ID = tvb_get_guint8(message_tvb, ctr );
876                         b_Length = tvb_get_guint8(message_tvb, ctr + 2 );
877                         if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
878                             b_Length = ( 11 + ( b_Length > 8 ? 2 : 0 ) + b_Length );
879                         else
880                             b_Length = ( 11 + ( b_Length > 8 ? 2 : 0 ) + 2 * b_Length );
881
882                         if ( rem_length == b_Length )
883                         {
884                             ctr++;
885                             rem_length++;
886                             continue;
887                         }
888                     }
889                 }
890             }
891         }
892
893         ctr++;
894         rem_length = tvb_reported_length_remaining(message_tvb, ctr);
895
896     }
897
898     /* Seem redundant if b_frame2First is false. But in this case, the function is needed for the
899      * simple detection of a possible openSAFETY frame.  */
900     if ( b_frame2first && found )
901         *u_frameOffset = u_Offset;
902
903     return (found ? 1 : 0);
904 }
905
906 static void
907 dissect_opensafety_spdo_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *opensafety_tree,
908         guint16 frameStart1, guint16 frameStart2 , gboolean validSCMUDID, guint8 scm_udid[6])
909 {
910     proto_item *item;
911     proto_tree *spdo_tree;
912     guint16     ct;
913     gint16      taddr;
914     guint       dataLength;
915     guint8      tr, b_ID, conn_Valid;
916
917     dataLength = tvb_get_guint8(message_tvb, OSS_FRAME_POS_LEN + frameStart1);
918     b_ID = tvb_get_guint8(message_tvb, frameStart1 + 1) & 0xF8;
919     conn_Valid = ( (tvb_get_guint8(message_tvb, frameStart1 + 1) & 0x04) == 0x04);
920
921     /* Network address is xor'ed into the start of the second frame, but only legible, if the scm given is valid */
922     taddr = ( ( OSS_FRAME_ADDR_T(message_tvb, frameStart1) ) ^ ( OSS_FRAME_ADDR_T2(message_tvb, frameStart2, scm_udid[0], scm_udid[1]) ) );
923     if ( ! validSCMUDID )
924         taddr = ( -1 * taddr );
925
926     /* An SPDO get's always send by the producer, to everybody else */
927     PACKET_SENDER( pinfo, OSS_FRAME_ADDR_T(message_tvb, frameStart1), OSS_FRAME_POS_ADDR + frameStart1, frameStart2, taddr );
928
929     item = proto_tree_add_uint_format_value(opensafety_tree, hf_oss_msg_category, message_tvb,
930                                             OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_SPDO_MESSAGE_TYPE,
931                                             "%s", val_to_str_const(OPENSAFETY_SPDO_MESSAGE_TYPE, message_id_values, "Unknown") );
932     PROTO_ITEM_SET_GENERATED(item);
933
934     spdo_tree = proto_item_add_subtree(item, ett_opensafety_spdo);
935
936     if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE )
937         proto_tree_add_boolean(spdo_tree, hf_oss_msg_direction, message_tvb,
938                                OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_RESPONSE);
939     else if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST || b_ID == OPENSAFETY_MSG_SPDO_DATA_ONLY )
940         proto_tree_add_boolean(spdo_tree, hf_oss_msg_direction, message_tvb,
941                                OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_REQUEST);
942
943     proto_tree_add_uint_format_value(spdo_tree, hf_oss_msg, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1,
944                                      b_ID, "%s", val_to_str_const(b_ID, message_type_values, "Unknown") );
945
946     proto_tree_add_uint(spdo_tree, hf_oss_spdo_producer, message_tvb,
947                         OSS_FRAME_POS_ADDR + frameStart1, 2, OSS_FRAME_ADDR_T(message_tvb, frameStart1));
948     proto_tree_add_boolean(spdo_tree, hf_oss_spdo_connection_valid, message_tvb,
949                            OSS_FRAME_POS_ID + frameStart1, 1, conn_Valid);
950
951     /* taddr is the 4th octet in the second frame */
952     taddr = OSS_FRAME_ADDR_T2(message_tvb, frameStart2 + 3, scm_udid[3], scm_udid[4]);
953     tr = ( tvb_get_guint8(message_tvb, frameStart2 + 4)  ^ scm_udid[4] ) & 0xFC;
954
955     /* determine the ct value. if complete it can be used for analysis of the package */
956     ct = tvb_get_guint8(message_tvb, frameStart1 + 3);
957     if ( validSCMUDID )
958     {
959         ct = (guint16)((tvb_get_guint8(message_tvb, frameStart2 + 2) ^ scm_udid[2]) << 8) +
960             (tvb_get_guint8(message_tvb, frameStart1 + 3));
961     }
962
963     if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST )
964     {
965         item = proto_tree_add_uint_format_value(spdo_tree, hf_oss_spdo_time_value_sn, message_tvb, 0, 0, ct,
966                                                 "0x%04X [%d] (%s)", ct, ct,
967                                                 (validSCMUDID ? "Complete" : "Low byte only"));
968         PROTO_ITEM_SET_GENERATED(item);
969
970         proto_tree_add_uint(spdo_tree, hf_oss_spdo_time_request, message_tvb,
971                             OSS_FRAME_POS_ADDR + frameStart2 + 4, 1, tr);
972         proto_tree_add_uint(spdo_tree, hf_oss_spdo_time_request_from, message_tvb,
973                             OSS_FRAME_POS_ADDR + frameStart2 + 3, 2, taddr);
974     }
975     else
976     {
977         item = proto_tree_add_uint_format_value(spdo_tree, hf_oss_spdo_producer_time, message_tvb, 0, 0, ct,
978                 "0x%04X [%d] (%s)", ct, ct, (validSCMUDID ? "Complete" : "Low byte only"));
979         PROTO_ITEM_SET_GENERATED(item);
980
981         if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE )
982         {
983             proto_tree_add_uint(spdo_tree, hf_oss_spdo_time_request, message_tvb, OSS_FRAME_POS_ADDR + frameStart2 + 4, 1, tr);
984             proto_tree_add_uint(spdo_tree, hf_oss_spdo_time_request_to, message_tvb, OSS_FRAME_POS_ADDR + frameStart2 + 3, 2, taddr);
985         }
986     }
987
988     if ( dataLength > 0 )
989         proto_tree_add_item(spdo_tree, hf_oss_spdo_payload, message_tvb, OSS_FRAME_POS_ID + 3, dataLength, ENC_NA);
990 }
991
992 static void dissect_ssdo_payload ( packet_info *pinfo, tvbuff_t *new_tvb, proto_tree *ssdo_payload, guint8 sacmd )
993 {
994     guint  dataLength = 0, ctr = 0, n = 0;
995     guint8 ssdoSubIndex = 0;
996     guint16 ssdoIndex = 0, dispSSDOIndex = 0;
997     guint32 sodLength = 0, entry = 0;
998     proto_item *item;
999     proto_tree *sod_tree, *ext_tree;
1000
1001     dataLength = tvb_length(new_tvb);
1002
1003     ssdoIndex = tvb_get_letohs(new_tvb, 0);
1004
1005     sodLength = tvb_get_letohl(new_tvb, 4);
1006
1007     /* first check for extended parameter */
1008     if ( dataLength == 16 || sodLength == ( dataLength - 16 ) || ssdoIndex == 0x0101 )
1009     {
1010         /* extended parameter header & data */
1011         item = proto_tree_add_string_format(ssdo_payload, hf_oss_ssdo_extpar,
1012                                             new_tvb, 0, dataLength, "", "Extended Parameter Set: %s",
1013                                             (dataLength == 16 ? "Header only" : "Header & Data") );
1014         ext_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_extpar);
1015
1016         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_parset, new_tvb, 0, 1, ENC_BIG_ENDIAN );
1017         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_version, new_tvb, 1, 1, ENC_BIG_ENDIAN );
1018         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_saddr, new_tvb, 2, 2, ENC_LITTLE_ENDIAN );
1019
1020         proto_tree_add_uint_format_value(ext_tree, hf_oss_ssdo_extpar_length,
1021                                          new_tvb, 4, 4, sodLength, "0x%04X (%d octets)",
1022                                          sodLength, sodLength );
1023
1024         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_crc, new_tvb, 8, 4, ENC_LITTLE_ENDIAN );
1025         proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_tstamp, new_tvb, 12, 4, ENC_LITTLE_ENDIAN );
1026
1027         if ( dataLength != 16 )
1028         {
1029             item = proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_data, new_tvb, 16, dataLength - 16, ENC_NA );
1030
1031             if ( ( dataLength - sodLength ) != 16 )
1032                 expert_add_info ( pinfo, item, &ei_message_reassembly_size_differs_from_header );
1033         }
1034     }
1035     else
1036     {
1037         /* If == upload, it is most likely a par upload */
1038         if ( sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END && ( dataLength % 4 == 0 ) )
1039         {
1040
1041             item = proto_tree_add_uint_format_value(ssdo_payload, hf_oss_ssdo_sod_index, new_tvb,
1042                                                     0, 0,  0x1018, "0x%04X (%s)", 0x1018,
1043                                                     val_to_str_const( ((guint32) (0x1018 << 16) ),
1044                                                                       sod_idx_names, "Unknown") );
1045             sod_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_sodentry);
1046             PROTO_ITEM_SET_GENERATED(item);
1047
1048             item = proto_tree_add_uint_format_value(sod_tree, hf_oss_ssdo_sod_subindex, new_tvb, 0, 0,
1049                                                              0x06, "0x%02X (%s)", 0x06,
1050                                                              val_to_str_const(((guint32) (0x1018 << 16) +  0x06),
1051                                                                                             sod_idx_names, "Unknown") );
1052             PROTO_ITEM_SET_GENERATED(item);
1053
1054             entry = tvb_get_letohl ( new_tvb, 0 );
1055             proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_timestamp, new_tvb, 0,
1056                         4, entry, "0x%08X", entry );
1057             for ( n = 4; n < dataLength; n+=4 )
1058             {
1059                 entry = tvb_get_letohl ( new_tvb, n );
1060                 proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_checksum, new_tvb, (n ),
1061                         4, entry, "[#%d] 0x%08X", ( n / 4 ), entry );
1062             }
1063         }
1064         /* If != upload, it is most likely a 101A download */
1065         else
1066         {
1067
1068             /* normal parameter set */
1069             for ( ctr = 0; ctr < dataLength; ctr++ )
1070             {
1071                 ssdoIndex = tvb_get_letohs(new_tvb, ctr);
1072                 ssdoSubIndex = tvb_get_guint8(new_tvb, ctr + 2);
1073                 dispSSDOIndex = ssdoIndex;
1074
1075                 if ( ssdoIndex >= 0x1400 && ssdoIndex <= 0x17FE )
1076                     dispSSDOIndex = 0x1400;
1077                 else if ( ssdoIndex >= 0x1800 && ssdoIndex <= 0x1BFE )
1078                     dispSSDOIndex = 0x1800;
1079                 else if ( ssdoIndex >= 0x1C00 && ssdoIndex <= 0x1FFE )
1080                     dispSSDOIndex = 0x1C00;
1081                 else if ( ssdoIndex >= 0xC000 && ssdoIndex <= 0xC3FE )
1082                     dispSSDOIndex = 0xC000;
1083
1084                 item = proto_tree_add_uint_format_value(ssdo_payload, hf_oss_ssdo_sod_index, new_tvb,
1085                                                         ctr, 2,  ssdoIndex, "0x%04X (%s)", ssdoIndex,
1086                                                         val_to_str_const( ((guint32) (dispSSDOIndex << 16) ),
1087                                                                           sod_idx_names, "Unknown") );
1088                 if ( ssdoIndex != dispSSDOIndex )
1089                     PROTO_ITEM_SET_GENERATED ( item );
1090
1091                 if ( ssdoIndex < 0x1000 || ssdoIndex > 0xE7FF )
1092                     expert_add_info ( pinfo, item, &ei_payload_unknown_format );
1093
1094                 sod_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_sodentry);
1095
1096                 if ( ssdoSubIndex != 0 )
1097                 {
1098                     proto_tree_add_uint_format_value(sod_tree, hf_oss_ssdo_sod_subindex, new_tvb, ctr + 2, 1,
1099                                                  ssdoSubIndex, "0x%02X (%s)", ssdoSubIndex,
1100                                                  val_to_str_const(((guint32) (ssdoIndex << 16) + ssdoSubIndex),
1101                                                                                 sod_idx_names, "Unknown") );
1102                 }
1103                 else
1104                     proto_tree_add_uint_format_value(sod_tree, hf_oss_ssdo_sod_subindex, new_tvb, ctr + 2, 1,
1105                                                  ssdoSubIndex, "0x%02X",ssdoSubIndex );
1106                 ctr += 2;
1107
1108                 /* reading real size */
1109                 sodLength = tvb_get_letohl ( new_tvb, ctr + 1 );
1110                 if ( sodLength > (dataLength - ctr) )
1111                     sodLength = 0;
1112
1113                 if ( ( sodLength + 4 + ctr ) > dataLength )
1114                     break;
1115
1116                 if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x06 )
1117                 {
1118                     entry = tvb_get_letohl ( new_tvb, ctr + 5 );
1119                     proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_timestamp, new_tvb, ctr + 5,
1120                                 4, entry, "0x%08X", entry );
1121                     for ( n = 4; n < sodLength; n+=4 )
1122                     {
1123                         entry = tvb_get_letohl ( new_tvb, ctr + 5 + n );
1124                         proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_checksum, new_tvb, (ctr + 5 + n ),
1125                                 4, entry, "[#%d] 0x%08X", ( n / 4 ), entry );
1126                     }
1127                 } else if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x07 ) {
1128                     entry = tvb_get_letohl ( new_tvb, ctr + 5 );
1129                     proto_tree_add_uint_format_value ( sod_tree, hf_oss_sod_par_timestamp, new_tvb, ctr + 5,
1130                                 4, entry, "0x%08X", entry );
1131                 } else if ( ( dispSSDOIndex == OPENSAFETY_SOD_RXMAP || dispSSDOIndex == OPENSAFETY_SOD_TXMAP ) && ssdoSubIndex != 0x0 ) {
1132                     proto_tree_add_uint(sod_tree, hf_oss_ssdo_sodentry_size, new_tvb, ctr + 1, 4, sodLength );
1133                     item = proto_tree_add_item(sod_tree, hf_oss_ssdo_sodmapping, new_tvb, ctr + 5, sodLength, ENC_NA );
1134                     ext_tree = proto_item_add_subtree(item, ett_opensafety_sod_mapping);
1135
1136                     proto_tree_add_item(ext_tree, hf_oss_ssdo_sodmapping_bits, new_tvb, ctr + 5, 1, ENC_NA);
1137
1138                     entry = tvb_get_letohl ( new_tvb, ctr + 7 );
1139                     proto_tree_add_item(ext_tree, hf_oss_ssdo_sod_index, new_tvb, ctr + 7, 2, entry);
1140                     proto_tree_add_item(ext_tree, hf_oss_ssdo_sod_subindex, new_tvb, ctr + 6, 1, ENC_NA);
1141
1142                 } else {
1143                     proto_tree_add_uint(sod_tree, hf_oss_ssdo_sodentry_size, new_tvb, ctr + 1, 4, sodLength );
1144                     if ( sodLength > 0 )
1145                         proto_tree_add_item(sod_tree, hf_oss_ssdo_sodentry_data, new_tvb, ctr + 5, sodLength, ENC_NA );
1146                 }
1147                 ctr += sodLength + 4;
1148         }
1149         }
1150     }
1151
1152
1153 }
1154
1155 static void
1156 dissect_opensafety_ssdo_message(tvbuff_t *message_tvb , packet_info *pinfo, proto_tree *opensafety_tree ,
1157         guint16 frameStart1, guint16 frameStart2 , gboolean validSCMUDID, guint8 scm_udid[6])
1158 {
1159     proto_item *item;
1160     proto_tree *ssdo_tree, *ssdo_payload, *ssdo_sacmd_tree;
1161     guint16     taddr = 0, sdn = 0, server = 0, client = 0, n = 0, ct = 0;
1162     guint32     abortcode, ssdoIndex = 0, ssdoSubIndex = 0, payloadSize, fragmentId = 0, entry = 0;
1163     guint8      db0Offset, db0, sacmd, payloadOffset;
1164     guint       dataLength;
1165     gint        calcDataLength;
1166     gboolean    isResponse, decodePayload, isEndSegment, isSegmented, saveFragmented;
1167     tvbuff_t* new_tvb = NULL;
1168     fragment_head *frag_msg = NULL;
1169
1170     dataLength = tvb_get_guint8(message_tvb, OSS_FRAME_POS_LEN + frameStart1);
1171     decodePayload = FALSE;
1172
1173     db0Offset = frameStart1 + OSS_FRAME_POS_DATA;
1174     db0 = tvb_get_guint8(message_tvb, db0Offset);
1175     sacmd = db0;
1176     ssdoIndex = 0;
1177     ssdoSubIndex = 0;
1178
1179     if ( ( sacmd & OPENSAFETY_SSDO_SACMD_TGL ) == OPENSAFETY_SSDO_SACMD_TGL )
1180         sacmd = sacmd & ( ~OPENSAFETY_SSDO_SACMD_TGL );
1181
1182     isResponse = ( ( OSS_FRAME_ID_T(message_tvb, frameStart1) & 0x04 ) == 0x04 );
1183
1184     if ( validSCMUDID )
1185     {
1186         /* taddr is the 4th octet in the second frame */
1187         taddr = OSS_FRAME_ADDR_T2(message_tvb, frameStart2 + 3, scm_udid[3], scm_udid[4]);
1188         sdn =  ( OSS_FRAME_ADDR_T(message_tvb, frameStart1) ^
1189                         ( OSS_FRAME_ADDR_T2(message_tvb, frameStart2, scm_udid[0], scm_udid[1]) ) );
1190
1191         PACKET_SENDER_RECEIVER ( pinfo, taddr, frameStart2 + 3, OSS_FRAME_ADDR_T(message_tvb, frameStart1),
1192                                  frameStart1, frameStart2, sdn );
1193     }
1194     else if ( ! isResponse )
1195     {
1196         PACKET_SENDER(pinfo, OSS_FRAME_ADDR_T(message_tvb, frameStart1), frameStart1, frameStart2,
1197                       -1 * ( ( OSS_FRAME_ADDR_T(message_tvb, frameStart1) ) ^ ( OSS_FRAME_ADDR_T2(message_tvb, frameStart2, scm_udid[0], scm_udid[1]) ) ) );
1198     }
1199     else if ( isResponse )
1200     {
1201         PACKET_RECEIVER(pinfo, OSS_FRAME_ADDR_T(message_tvb, frameStart1), frameStart1, frameStart2,
1202                         -1 * ( ( OSS_FRAME_ADDR_T(message_tvb, frameStart1) ) ^ ( OSS_FRAME_ADDR_T2(message_tvb, frameStart2, scm_udid[0], scm_udid[1]) ) ) );
1203     }
1204
1205     if ( ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SSDO_SLIM_SERVICE_REQUEST ) ||
1206          ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE ) )
1207         item = proto_tree_add_uint_format_value(opensafety_tree, hf_oss_msg_category, message_tvb,
1208                                                 OSS_FRAME_POS_ID + frameStart1, 1,
1209                                                 OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE,
1210                                                 "%s", val_to_str_const(OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE, message_id_values, "Unknown") );
1211     else
1212         item = proto_tree_add_uint_format_value(opensafety_tree, hf_oss_msg_category, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1,
1213                                                 OPENSAFETY_SSDO_MESSAGE_TYPE,
1214                                                 "%s", val_to_str_const(OPENSAFETY_SSDO_MESSAGE_TYPE, message_id_values, "Unknown") );
1215     PROTO_ITEM_SET_GENERATED(item);
1216
1217     ssdo_tree = proto_item_add_subtree(item, ett_opensafety_ssdo);
1218
1219     if ( ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SSDO_SERVICE_RESPONSE ) ||
1220          ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SSDO_SLIM_SERVICE_RESPONSE ) )
1221         proto_tree_add_boolean(ssdo_tree, hf_oss_msg_direction, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_RESPONSE);
1222     else
1223         proto_tree_add_boolean(ssdo_tree, hf_oss_msg_direction, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_REQUEST);
1224
1225     proto_tree_add_uint_format_value(ssdo_tree, hf_oss_msg, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1,
1226                                      OSS_FRAME_ID_T(message_tvb, frameStart1),
1227                                      "%s", val_to_str_const(OSS_FRAME_ID_T(message_tvb, frameStart1), message_type_values, "Unknown") );
1228
1229
1230     if ( isResponse )
1231     {
1232         if ( validSCMUDID )
1233         {
1234             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_client, message_tvb, frameStart1, 2, OSS_FRAME_ADDR_T(message_tvb, frameStart1));
1235             client = OSS_FRAME_ADDR_T(message_tvb, frameStart1);
1236             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_server, message_tvb, frameStart2 + 3, 2, taddr);
1237             server = taddr;
1238         }
1239         else
1240         {
1241             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_client, message_tvb, frameStart1, 2, OSS_FRAME_ADDR_T(message_tvb, frameStart1));
1242             client = OSS_FRAME_ADDR_T(message_tvb, frameStart1);
1243         }
1244     }
1245     else if ( ! isResponse )
1246     {
1247         if ( validSCMUDID )
1248         {
1249             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_server, message_tvb, frameStart1, 2, OSS_FRAME_ADDR_T(message_tvb, frameStart1));
1250             server = OSS_FRAME_ADDR_T(message_tvb, frameStart1);
1251             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_client, message_tvb, frameStart2 + 3, 2, taddr);
1252             client = taddr;
1253         }
1254         else
1255         {
1256             proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_server, message_tvb, frameStart1, 2, OSS_FRAME_ADDR_T(message_tvb, frameStart1));
1257             server = OSS_FRAME_ADDR_T(message_tvb, frameStart1);
1258         }
1259     }
1260
1261     item = proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_sacmd, message_tvb, db0Offset, 1, sacmd);
1262     col_append_fstr(pinfo->cinfo, COL_INFO, ", SACMD: %s", val_to_str_const(sacmd, ssdo_sacmd_values, " "));
1263
1264     ssdo_sacmd_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_sacmd);
1265     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_block_transfer, message_tvb, db0Offset, 1, db0);
1266     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_end_segment, message_tvb, db0Offset, 1, db0);
1267     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_initiate, message_tvb, db0Offset, 1, db0);
1268     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_toggle, message_tvb, db0Offset, 1, db0);
1269     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_segmentation, message_tvb, db0Offset, 1, db0);
1270     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_abort_transfer, message_tvb, db0Offset, 1, db0);
1271     proto_tree_add_boolean(ssdo_sacmd_tree, hf_oss_ssdo_sacmd_access_type, message_tvb, db0Offset, 1, db0);
1272
1273     payloadOffset = db0Offset + 1;
1274
1275     ct = tvb_get_guint8(message_tvb, frameStart1 + 3);
1276     if ( validSCMUDID )
1277         ct = (guint16)((tvb_get_guint8(message_tvb, frameStart2 + 2) ^ scm_udid[2]) << 8) + (tvb_get_guint8(message_tvb, frameStart1 + 3));
1278
1279     proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_sano, message_tvb, frameStart1 + 3, 1, ct );
1280
1281     /* When the following clause is met, DB1,2 contain the SOD index, and DB3 the SOD subindex */
1282     if ( ( ( sacmd & OPENSAFETY_SSDO_SACMD_INI ) == OPENSAFETY_SSDO_SACMD_INI ) &&
1283             ( sacmd != OPENSAFETY_MSG_SSDO_ABORT )
1284     )
1285     {
1286         ssdoIndex = tvb_get_letohs(message_tvb, db0Offset + 1);
1287         ssdoSubIndex = tvb_get_guint8(message_tvb, db0Offset + 3);
1288
1289         proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_sod_index, message_tvb, db0Offset + 1, 2,
1290                 ssdoIndex, "0x%04X (%s)", ssdoIndex,
1291                 val_to_str_const(((guint32) (ssdoIndex << 16)), sod_idx_names, "Unknown") );
1292         col_append_fstr(pinfo->cinfo, COL_INFO, " [%s", val_to_str_const(((guint32) (ssdoIndex << 16)), sod_idx_names, "Unknown"));
1293
1294         /* Some SOD downloads (0x101A for instance) don't have sub-indeces */
1295         if ( ssdoSubIndex != 0x0 )
1296         {
1297             proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_sod_subindex, message_tvb, db0Offset + 3, 1,
1298                 ssdoSubIndex, "0x%02X (%s)", ssdoSubIndex,
1299                 val_to_str_const(((guint32) (ssdoIndex << 16) + ssdoSubIndex), sod_idx_names, "Unknown") );
1300             col_append_fstr(pinfo->cinfo, COL_INFO, " - %s",
1301                     val_to_str_const(((guint32) (ssdoIndex << 16) + ssdoSubIndex), sod_idx_names, "Unknown"));
1302         }
1303         col_append_fstr(pinfo->cinfo, COL_INFO, "%s", "]" );
1304         payloadOffset += 3;
1305     }
1306
1307     if ( sacmd == OPENSAFETY_MSG_SSDO_ABORT )
1308     {
1309         abortcode = tvb_get_letohl(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 4);
1310
1311         proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_abort_code, message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 4, 4, abortcode,
1312                 "0x%04X %04X - %s", (guint16)(abortcode >> 16), (guint16)(abortcode),
1313                 val_to_str_const(abortcode, abort_codes, "Unknown"));
1314         col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_const(abortcode, abort_codes, "Unknown"));
1315
1316
1317     } else {
1318
1319         /* Either the SSDO msg is a response, then data is sent by the server and only in uploads,
1320          * or the message is a request, then data is coming from the client and payload data is
1321          * sent in downloads */
1322         if ( ( isResponse && (sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_SEGMENTED ||
1323                     sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_EXPEDITED ||
1324                     sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_MIDDLE ||
1325                     sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END ) )||
1326                     ( !isResponse && (sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_SEGMENTED ||
1327                     sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_EXPEDITED ||
1328                     sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_MIDDLE ||
1329                     sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_END ) ) )
1330                 {
1331                    decodePayload = TRUE;
1332                 }
1333
1334         if ( decodePayload )
1335         {
1336             saveFragmented = pinfo->fragmented;
1337             if ( server != 0 && client != 0 )
1338                 fragmentId = (guint32)((((guint32)client) << 16 ) + server );
1339
1340             isSegmented = ( ( db0 & OPENSAFETY_SSDO_SACMD_SEG ) == OPENSAFETY_SSDO_SACMD_SEG );
1341
1342             /* If payload data has to be calculated, either a total size is given, or not */
1343             if ( ( sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_INITIATE_SEGMENTED ) ||
1344                     ( sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_INITIATE_SEGMENTED )
1345                 )
1346             {
1347
1348                 payloadOffset += 4;
1349
1350                 /* reading real size */
1351                 payloadSize = tvb_get_letohl(message_tvb, payloadOffset - 4);
1352
1353                 calcDataLength = dataLength - (payloadOffset - db0Offset);
1354
1355                 item = proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_payload_size, message_tvb, payloadOffset - 4, 4,
1356                         payloadSize, "%d octets total (%d octets in this frame)", payloadSize, calcDataLength);
1357
1358                 if ( fragmentId != 0 && isSegmented )
1359                 {
1360                     pinfo->fragmented = TRUE;
1361                     frag_msg = fragment_add_seq_check(&os_reassembly_table, message_tvb, payloadOffset, pinfo,
1362                                                       fragmentId, NULL, 0, calcDataLength, TRUE );
1363                     fragment_add_seq_offset ( &os_reassembly_table, pinfo, fragmentId, NULL, ct );
1364
1365                     if ( frag_msg != NULL )
1366                     {
1367                         item = proto_tree_add_bytes_format_value(ssdo_tree, hf_oss_ssdo_payload, message_tvb, 0, 0, NULL, "Reassembled" );
1368                         PROTO_ITEM_SET_GENERATED(item);
1369
1370                         ssdo_payload = proto_item_add_subtree(item, ett_opensafety_ssdo_payload);
1371                         process_reassembled_data(message_tvb, 0, pinfo, "Reassembled Message", frag_msg, &oss_frag_items, NULL, ssdo_payload );
1372                     }
1373                 }
1374
1375                 if ( (gint) calcDataLength >= (gint) 0 )
1376                 {
1377                     proto_tree_add_item(ssdo_tree, hf_oss_ssdo_payload, message_tvb, payloadOffset, calcDataLength, ENC_NA );
1378                 } else {
1379                     expert_add_info_format(pinfo, item, &ei_payload_length_not_positive,
1380                                                 "Calculation for payload length yielded non-positive result [%d]", (guint) calcDataLength );
1381                 }
1382             }
1383             else
1384             {
1385                 isEndSegment = FALSE;
1386                 if ( ( sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_END ) || ( sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END ) )
1387                     isEndSegment = TRUE;
1388
1389                 payloadSize = dataLength - (payloadOffset - db0Offset);
1390
1391                 if ( fragmentId != 0 && isSegmented )
1392                 {
1393                     pinfo->fragmented = TRUE;
1394
1395                     frag_msg = fragment_add_seq_check(&os_reassembly_table, message_tvb, payloadOffset, pinfo,
1396                                                       fragmentId, NULL,ct,
1397                                                       payloadSize, isEndSegment ? FALSE : TRUE );
1398                 }
1399
1400                 if ( frag_msg )
1401                 {
1402                     item = proto_tree_add_bytes_format_value(ssdo_tree, hf_oss_ssdo_payload, message_tvb,
1403                                                              0, 0, NULL, "Reassembled" );
1404                     PROTO_ITEM_SET_GENERATED(item);
1405                     ssdo_payload = proto_item_add_subtree(item, ett_opensafety_ssdo_payload);
1406
1407                     new_tvb = process_reassembled_data(message_tvb, 0, pinfo, "Reassembled Message", frag_msg,
1408                                                        &oss_frag_items, NULL, ssdo_payload );
1409                     if ( isEndSegment && new_tvb )
1410                     {
1411                         item = proto_tree_add_uint_format_value(ssdo_payload, hf_oss_ssdo_payload_size, message_tvb, 0, 0,
1412                                                                 payloadSize, "%d octets (over all fragments)", frag_msg->len);
1413                         PROTO_ITEM_SET_GENERATED(item);
1414
1415                         col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)" );
1416                         dissect_ssdo_payload ( pinfo, new_tvb, ssdo_payload, sacmd );
1417                     }
1418                 }
1419                 else
1420                 {
1421                     item = proto_tree_add_uint_format_value(ssdo_tree, hf_oss_ssdo_payload_size, message_tvb, 0, 0, payloadSize,
1422                             "%d octets", payloadSize);
1423                     PROTO_ITEM_SET_GENERATED(item);
1424
1425                     if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x06 )
1426                     {
1427                         entry = tvb_get_letohl ( message_tvb, payloadOffset );
1428                         proto_tree_add_uint_format_value ( ssdo_tree, hf_oss_sod_par_timestamp, message_tvb, payloadOffset,
1429                                     4, entry, "0x%08X", entry );
1430                         for ( n = 4; n < payloadSize; n+=4 )
1431                         {
1432                             entry = tvb_get_letohl ( message_tvb, payloadOffset + n );
1433                             proto_tree_add_uint_format_value ( ssdo_tree, hf_oss_sod_par_checksum, message_tvb, (payloadOffset + n ),
1434                                     4, entry, "[#%d] 0x%08X", ( n / 4 ), entry );
1435                         }
1436                     } else if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x07 ) {
1437                         entry = tvb_get_letohl ( message_tvb, payloadOffset );
1438                         proto_tree_add_uint_format_value ( ssdo_tree, hf_oss_sod_par_timestamp, message_tvb, payloadOffset,
1439                                     4, entry, "0x%08X", entry );
1440                     } else
1441                         proto_tree_add_item(ssdo_tree, hf_oss_ssdo_payload, message_tvb, payloadOffset, payloadSize, ENC_NA );
1442                 }
1443             }
1444
1445             pinfo->fragmented = saveFragmented;
1446         }
1447     }
1448 }
1449
1450 static void
1451 dissect_opensafety_snmt_message(tvbuff_t *message_tvb, packet_info *pinfo , proto_tree *opensafety_tree,
1452         guint16 frameStart1, guint16 frameStart2 )
1453 {
1454     proto_item *item;
1455     proto_tree *snmt_tree;
1456     guint32     entry = 0;
1457     guint16     addr, taddr, sdn;
1458     guint8      db0, byte, errcode;
1459     guint       dataLength;
1460     char       *tempString;
1461
1462     dataLength = OSS_FRAME_LENGTH_T(message_tvb, frameStart1);
1463
1464     /* addr is the first field, as well as the recipient of the message */
1465     addr = OSS_FRAME_ADDR_T(message_tvb, frameStart1);
1466     /* taddr is the 4th octet in the second frame */
1467     taddr = OSS_FRAME_ADDR_T(message_tvb, frameStart2 + 3);
1468     /* domain is xor'ed on the first field in the second frame. As this is also addr, it is easy to obtain */
1469     sdn = OSS_FRAME_ADDR_T(message_tvb, frameStart2) ^ addr;
1470
1471     db0 = -1;
1472     if (dataLength > 0)
1473         db0 = tvb_get_guint8(message_tvb, frameStart1 + OSS_FRAME_POS_DATA);
1474
1475     if ( ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE) == 0 ) &&
1476          ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP) == 0 || (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP) == 0 ) )
1477     {
1478         PACKET_RECEIVER( pinfo, addr, OSS_FRAME_POS_ADDR + frameStart1, frameStart2, sdn );
1479     }
1480     else
1481     {
1482         PACKET_SENDER_RECEIVER ( pinfo, taddr, OSS_FRAME_POS_ADDR + frameStart1, addr, frameStart2 + 3,
1483                                  frameStart2, sdn );
1484     }
1485
1486     item = proto_tree_add_uint_format_value(opensafety_tree, hf_oss_msg_category, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1,
1487                                             OPENSAFETY_SNMT_MESSAGE_TYPE,
1488                                             "%s", val_to_str_const(OPENSAFETY_SNMT_MESSAGE_TYPE, message_id_values, "Unknown") );
1489     PROTO_ITEM_SET_GENERATED(item);
1490
1491     snmt_tree = proto_item_add_subtree(item, ett_opensafety_snmt);
1492
1493     if ( ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SNMT_RESPONSE_UDID ) ||
1494          ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SNMT_SADR_ASSIGNED ) ||
1495          ( OSS_FRAME_ID_T(message_tvb, frameStart1) == OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE ) )
1496         proto_tree_add_boolean(snmt_tree, hf_oss_msg_direction, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_RESPONSE);
1497     else
1498         proto_tree_add_boolean(snmt_tree, hf_oss_msg_direction, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1, OPENSAFETY_REQUEST);
1499
1500     proto_tree_add_uint_format_value(snmt_tree, hf_oss_msg, message_tvb, OSS_FRAME_POS_ID + frameStart1, 1,
1501                                      OSS_FRAME_ID_T(message_tvb, frameStart1),
1502                                      "%s", val_to_str_const(OSS_FRAME_ID_T(message_tvb, frameStart1), message_type_values, "Unknown") );
1503
1504     if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SN_RESET_GUARDING_SCM) == 0 )
1505     {
1506         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1507         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, frameStart2 + 3, 2, taddr);
1508     }
1509     else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE) == 0 )
1510     {
1511         byte = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1);
1512
1513         if ( ! ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 && byte == OPENSAFETY_ERROR_GROUP_ADD_PARAMETER ) )
1514         {
1515             proto_tree_add_uint(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + frameStart1, 1, db0);
1516             col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(db0, message_service_type, "Unknown"));
1517         }
1518         else
1519         {
1520             proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + frameStart1, 1,
1521                     db0, "%s [Request via SN Fail] (0x%02X)", val_to_str_const(byte, sn_fail_error_group, "Unknown"), db0);
1522             col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(byte, sn_fail_error_group, "Unknown"));
1523         }
1524
1525         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1526         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, frameStart2 + 3, 2, taddr);
1527
1528         if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 )
1529         {
1530             /* Handle a normal SN Fail */
1531             if ( byte != OPENSAFETY_ERROR_GROUP_ADD_PARAMETER )
1532             {
1533                 proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_error_group, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 1,
1534                         byte, "%s", ( byte == 0 ? "Device" : val_to_str(byte, sn_fail_error_group, "Reserved [%d]" ) ) );
1535
1536                 errcode = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 2);
1537                 proto_tree_add_uint_format_value(snmt_tree, hf_oss_snmt_error_code, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 2, 1,
1538                         errcode, "%s [%d]", ( errcode == 0 ? "Default" : "Vendor Specific" ), errcode );
1539
1540                 col_append_fstr(pinfo->cinfo, COL_INFO, " - Group: %s; Code: %s",
1541                     ( byte == 0 ? "Device" : val_to_str(byte, sn_fail_error_group, "Reserved [%d]" ) ),
1542                     ( errcode == 0 ? "Default" : "Vendor Specific" )
1543                 );
1544             }
1545             else
1546             {
1547                 errcode = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 2);
1548
1549                 /* Handle an additional parameter request */
1550                 proto_tree_add_uint(snmt_tree, hf_oss_ssdo_extpar_parset, message_tvb,
1551                         OSS_FRAME_POS_DATA + frameStart1 + 2, 1, ( errcode & 0x0F ) + 1 );
1552
1553                 proto_tree_add_boolean(snmt_tree, hf_oss_snmt_param_type, message_tvb,
1554                         OSS_FRAME_POS_DATA + frameStart1 + 2, 1, ( ( errcode & 0xF0 ) != 0xF0 ) );
1555             }
1556         }
1557         else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_UDID_SCM) == 0 )
1558         {
1559             item = proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 6, ENC_NA);
1560
1561             if ( global_scm_udid_autoset == TRUE )
1562             {
1563                 tempString = (char *)wmem_alloc0(wmem_packet_scope(), 128 * sizeof(char));
1564                 g_snprintf ( tempString, 18, "%s", tvb_bytes_to_str_punct(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 6, ':' ) );
1565                 if ( memcmp ( global_scm_udid, tempString, 17 ) != 0 )
1566                 {
1567                     local_scm_udid = (char *)wmem_alloc0(wmem_file_scope(), 18 * sizeof(char));
1568                     g_snprintf(local_scm_udid, 18, "%s", tempString );
1569                     expert_add_info_format(pinfo, item, &ei_scmudid_autodetected, "Auto detected payload as SCM UDID [%s].", local_scm_udid);
1570                 }
1571             }
1572
1573         }
1574         else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_ADDITIONAL_SADR) == 0 )
1575         {
1576             proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addsaddr, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 2,
1577                     OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 1));
1578
1579             proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addtxspdo, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 3, 2,
1580                     OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 3));
1581
1582             col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%04X => 0x%04X]",
1583                     OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 1),
1584                     OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 3));
1585         }
1586     }
1587     else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SERVICE_REQUEST) == 0 )
1588     {
1589         proto_tree_add_uint(snmt_tree, hf_oss_snmt_service_id, message_tvb, OSS_FRAME_POS_DATA + frameStart1, 1, db0);
1590         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str_const(db0, message_service_type, "Unknown"));
1591
1592         if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP) == 0 || (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP) == 0 )
1593         {
1594             proto_tree_add_uint(snmt_tree, hf_oss_snmt_scm, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1595             proto_tree_add_uint(snmt_tree, hf_oss_snmt_tool, message_tvb, frameStart2 + 3, 2, taddr);
1596         }
1597         else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGN_UDID_SCM) == 0 )
1598         {
1599             proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1600             proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, frameStart2 + 3, 2, taddr);
1601             item = proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 6, ENC_NA);
1602
1603             if ( global_scm_udid_autoset == TRUE )
1604             {
1605                 tempString = (char *)wmem_alloc0(wmem_packet_scope(), 18 * sizeof(char));
1606                 g_snprintf ( tempString, 18, "%s", tvb_bytes_to_str_punct(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 6, ':' ) );
1607                 if ( memcmp ( global_scm_udid, tempString, 17 ) != 0 )
1608                 {
1609                     local_scm_udid = (char *)wmem_alloc0(wmem_file_scope(), 18 * sizeof(char));
1610                     g_snprintf(local_scm_udid, 18, "%s", tempString );
1611                     expert_add_info_format(pinfo, item, &ei_scmudid_autodetected, "Auto detected payload as SCM UDID [%s].", tempString);
1612                 }
1613             }
1614
1615         }
1616         else
1617         {
1618             proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, frameStart2 + 3, 2, taddr);
1619             proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1620
1621             if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_OP) == 0 )
1622             {
1623                 entry = tvb_get_letohl ( message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 1 );
1624                 proto_tree_add_uint_format_value ( snmt_tree, hf_oss_sod_par_timestamp, message_tvb,
1625                         OSS_FRAME_POS_DATA + frameStart1 + 1, 4, entry, "0x%08X", entry );
1626             }
1627             else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_ASSIGN_ADDITIONAL_SADR) == 0 )
1628             {
1629                 proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addsaddr, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 2,
1630                         OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 1));
1631
1632                 proto_tree_add_uint(snmt_tree, hf_oss_snmt_ext_addtxspdo, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 3, 2,
1633                         OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 3));
1634
1635                 col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%04X => 0x%04X]",
1636                         OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 1),
1637                         OSS_FRAME_ADDR_T(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 3));
1638             }
1639
1640         }
1641     }
1642     else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SADR_ASSIGNED) == 0 )
1643     {
1644         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1645         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, frameStart2 + 3, 2, taddr);
1646
1647         if (dataLength > 0)
1648             proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + frameStart1, 6, ENC_NA);
1649     }
1650     else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_ASSIGN_SADR) == 0 )
1651     {
1652         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, frameStart2 + 3, 2, taddr);
1653         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1654
1655         if (dataLength > 0)
1656             proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + frameStart1, 6, ENC_NA);
1657
1658     }
1659     else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_RESPONSE_UDID) == 0 )
1660     {
1661         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1662         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, frameStart2 + 3, 2, taddr);
1663
1664         if (dataLength > 0)
1665             proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + frameStart1, 6, ENC_NA);
1666
1667     }
1668     else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_REQUEST_UDID) == 0 )
1669     {
1670         proto_tree_add_uint(snmt_tree, hf_oss_snmt_master, message_tvb, frameStart2 + 3, 2, taddr);
1671         proto_tree_add_uint(snmt_tree, hf_oss_snmt_slave, message_tvb, OSS_FRAME_POS_ADDR + frameStart1, 2, addr);
1672     }
1673 }
1674
1675 static gboolean
1676 dissect_opensafety_checksum(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *opensafety_tree,
1677                             guint8 type, guint16 frameStart1, guint16 frameStart2 )
1678 {
1679     guint16     frame1_crc, frame2_crc;
1680     guint16     calc1_crc, calc2_crc;
1681     guint       dataLength, frame2Length;
1682     guint8     *bytes, ctr = 0, crcType = OPENSAFETY_CHECKSUM_CRC8;
1683     proto_item *item;
1684     proto_tree *checksum_tree;
1685     gint        start;
1686     gint        length;
1687     gboolean    isSlim = FALSE;
1688     GByteArray *scmUDID = NULL;
1689
1690     dataLength = OSS_FRAME_LENGTH_T(message_tvb, frameStart1);
1691     start = OSS_FRAME_POS_DATA + dataLength + frameStart1;
1692
1693     if (OSS_FRAME_LENGTH_T(message_tvb, frameStart1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
1694         frame1_crc = tvb_get_letohs(message_tvb, start);
1695     else
1696         frame1_crc = tvb_get_guint8(message_tvb, start);
1697
1698     if ( type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
1699         isSlim = TRUE;
1700
1701     frame2Length = (isSlim ? 0 : dataLength) + 5;
1702
1703     length = (dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? OPENSAFETY_CHECKSUM_CRC16 : OPENSAFETY_CHECKSUM_CRC8);
1704     item = proto_tree_add_uint_format(opensafety_tree, hf_oss_crc, message_tvb, start, length, frame1_crc,
1705                                       "CRC for subframe #1: 0x%04X", frame1_crc);
1706
1707     checksum_tree = proto_item_add_subtree(item, ett_opensafety_checksum);
1708
1709     bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, frameStart1, dataLength + 4);
1710     if ( dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
1711     {
1712         calc1_crc = crc16_0x755B(bytes, dataLength + 4, 0);
1713         if ( frame1_crc == calc1_crc )
1714             crcType = OPENSAFETY_CHECKSUM_CRC16;
1715         if ( frame1_crc != calc1_crc )
1716         {
1717             calc1_crc = crc16_0x5935(bytes, dataLength + 4, 0);
1718             if ( frame1_crc == calc1_crc )
1719             {
1720                 crcType = OPENSAFETY_CHECKSUM_CRC16SLIM;
1721                 if ( ! isSlim )
1722                     expert_add_info(pinfo, item, &ei_crc_slimssdo_instead_of_spdo );
1723             }
1724         }
1725     }
1726     else
1727         calc1_crc = crc8_0x2F(bytes, dataLength + 4, 0);
1728
1729     item = proto_tree_add_boolean(checksum_tree, hf_oss_crc_valid, message_tvb,
1730             frameStart1, dataLength + 4, (frame1_crc == calc1_crc));
1731     PROTO_ITEM_SET_GENERATED(item);
1732     /* using the defines, as the values can change */
1733     proto_tree_add_uint(checksum_tree, hf_oss_crc_type, message_tvb, start, length, crcType );
1734
1735     start = frameStart2 + (isSlim ? 5 : dataLength + OSS_FRAME_POS_DATA + 1 );
1736     if (OSS_FRAME_LENGTH_T(message_tvb, frameStart1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8)
1737         frame2_crc = tvb_get_letohs(message_tvb, start);
1738     else
1739         frame2_crc = tvb_get_guint8(message_tvb, start);
1740
1741     /* 0xFFFF is an invalid CRC16 value, therefore valid for initialization */
1742     calc2_crc = 0xFFFF;
1743
1744     if ( global_calculate_crc2 )
1745     {
1746         bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, frameStart2, frame2Length + length);
1747
1748         /* SLIM SSDO messages, do not contain a payload in frame2 */
1749         if ( isSlim == TRUE )
1750             dataLength = 0;
1751
1752         scmUDID = g_byte_array_new();
1753         if ( hex_str_to_bytes((local_scm_udid != NULL ? local_scm_udid : global_scm_udid), scmUDID, TRUE) && scmUDID->len == 6 )
1754         {
1755             if ( type != OPENSAFETY_SNMT_MESSAGE_TYPE )
1756             {
1757                 for ( ctr = 0; ctr < 6; ctr++ )
1758                     bytes[ctr] = bytes[ctr] ^ (guint8)(scmUDID->data[ctr]);
1759
1760                 /*
1761                  * If the second frame is 6 or 7 (slim) bytes in length, we have to decode the found
1762                  * frame crc again. This must be done using the byte array, as the unxor operation
1763                  * had to take place.
1764                  */
1765                 if ( dataLength == 0 )
1766                     frame2_crc = ( ( isSlim && length == 2 ) ? ( ( bytes[6] << 8 ) + bytes[5] ) : bytes[5] );
1767             }
1768
1769             item = proto_tree_add_uint_format(opensafety_tree, hf_oss_crc, message_tvb, start, length, frame2_crc,
1770                     "CRC for subframe #2: 0x%04X", frame2_crc);
1771
1772             checksum_tree = proto_item_add_subtree(item, ett_opensafety_checksum);
1773
1774             if ( OSS_FRAME_LENGTH_T(message_tvb, frameStart1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
1775             {
1776                 calc2_crc = crc16_0x755B(bytes, frame2Length, 0);
1777                 if ( frame2_crc != calc2_crc )
1778                     calc2_crc = crc16_0x5935(bytes, frame2Length, 0);
1779             }
1780             else
1781                 calc2_crc = crc8_0x2F(bytes, frame2Length, 0);
1782
1783             item = proto_tree_add_boolean(checksum_tree, hf_oss_crc2_valid, message_tvb,
1784                     frameStart2, frame2Length, (frame2_crc == calc2_crc));
1785             PROTO_ITEM_SET_GENERATED(item);
1786
1787             if ( frame2_crc != calc2_crc )
1788             {
1789                 item = proto_tree_add_uint_format(checksum_tree, hf_oss_crc, message_tvb,
1790                         frameStart2, frame2Length, calc2_crc, "Calculated CRC: 0x%04X", calc2_crc);
1791                 PROTO_ITEM_SET_GENERATED(item);
1792                 expert_add_info(pinfo, item, &ei_crc_frame_2_invalid );
1793             }
1794         }
1795         else
1796             expert_add_info(pinfo, item, &ei_crc_frame_2_unknown_scm_udid );
1797     }
1798
1799     /* For a correct calculation of the second crc we need to know the scm udid.
1800      * If the dissection of the second frame has been triggered, we integrate the
1801      * crc for frame2 into the result */
1802     return (gboolean) (frame1_crc == calc1_crc) && ( global_calculate_crc2 == TRUE ? (frame2_crc == calc2_crc) : TRUE);
1803 }
1804
1805 static gboolean
1806 dissect_opensafety_message(guint16 frameStart1, guint16 frameStart2, guint8 type,
1807                            tvbuff_t *message_tvb, packet_info *pinfo,
1808                            proto_item *opensafety_item, proto_tree *opensafety_tree, guint8 u_nrInPackage)
1809 {
1810     guint8      b_ID, ctr;
1811     guint8      scm_udid[6];
1812     GByteArray *scmUDID = NULL;
1813     gboolean    validSCMUDID;
1814     proto_item *item;
1815     gboolean    messageTypeUnknown, crcValid;
1816
1817     messageTypeUnknown = FALSE;
1818
1819     for ( ctr = 0; ctr < 6; ctr++ )
1820         scm_udid[ctr] = 0;
1821
1822     b_ID = OSS_FRAME_ID_T(message_tvb, frameStart1);
1823     /* Clearing connection valid bit */
1824     if ( type == OPENSAFETY_SPDO_MESSAGE_TYPE )
1825         b_ID = b_ID & 0xF8;
1826
1827     col_append_fstr(pinfo->cinfo, COL_INFO, (u_nrInPackage > 1 ? " | %s" : "%s" ),
1828             val_to_str(b_ID, message_type_values, "Unknown Message (0x%02X) "));
1829
1830     {
1831         if ( type == OPENSAFETY_SNMT_MESSAGE_TYPE )
1832         {
1833             dissect_opensafety_snmt_message ( message_tvb, pinfo, opensafety_tree, frameStart1, frameStart2 );
1834         }
1835         else
1836         {
1837             validSCMUDID = FALSE;
1838             scmUDID = g_byte_array_new();
1839
1840             if ( hex_str_to_bytes((local_scm_udid != NULL ? local_scm_udid : global_scm_udid), scmUDID, TRUE) && scmUDID->len == 6 )
1841             {
1842                 validSCMUDID = TRUE;
1843
1844                 /* Now confirm, that the xor operation was successful. The ID fields of both frames have to be the same */
1845                 b_ID = OSS_FRAME_ID_T(message_tvb, frameStart2) ^ (guint8)(scmUDID->data[OSS_FRAME_POS_ID]);
1846
1847                 if ( ( OSS_FRAME_ID_T(message_tvb, frameStart1) ^ b_ID ) != 0 )
1848                     validSCMUDID = FALSE;
1849                 else
1850                     for ( ctr = 0; ctr < 6; ctr++ )
1851                         scm_udid[ctr] = scmUDID->data[ctr];
1852             }
1853
1854             if ( strlen ( (local_scm_udid != NULL ? local_scm_udid : global_scm_udid) ) > 0  && scmUDID->len == 6 )
1855             {
1856                 if ( local_scm_udid != NULL )
1857                 {
1858                     item = proto_tree_add_string(opensafety_tree, hf_oss_scm_udid_auto, message_tvb, 0, 0, local_scm_udid);
1859                     if ( ! validSCMUDID )
1860                         expert_add_info(pinfo, item, &ei_message_id_field_mismatch );
1861                 }
1862                 else
1863                     item = proto_tree_add_string(opensafety_tree, hf_oss_scm_udid, message_tvb, 0, 0, global_scm_udid);
1864                 PROTO_ITEM_SET_GENERATED(item);
1865             }
1866
1867             item = proto_tree_add_boolean(opensafety_tree, hf_oss_scm_udid_valid, message_tvb, 0, 0, validSCMUDID);
1868             if ( scmUDID->len != 6 )
1869                 expert_add_info(pinfo, item, &ei_scmudid_invalid_preference );
1870             PROTO_ITEM_SET_GENERATED(item);
1871
1872             g_byte_array_free( scmUDID, TRUE);
1873
1874             if ( type == OPENSAFETY_SSDO_MESSAGE_TYPE || type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
1875             {
1876                 dissect_opensafety_ssdo_message ( message_tvb, pinfo, opensafety_tree, frameStart1, frameStart2, validSCMUDID, scm_udid );
1877             }
1878             else if ( type == OPENSAFETY_SPDO_MESSAGE_TYPE )
1879             {
1880                 dissect_opensafety_spdo_message ( message_tvb, pinfo, opensafety_tree, frameStart1, frameStart2, validSCMUDID, scm_udid );
1881             }
1882             else
1883             {
1884                 messageTypeUnknown = TRUE;
1885             }
1886         }
1887
1888         crcValid = FALSE;
1889         item = proto_tree_add_uint(opensafety_tree, hf_oss_length,
1890                                    message_tvb, OSS_FRAME_POS_LEN + frameStart1, 1, OSS_FRAME_LENGTH_T(message_tvb, frameStart1));
1891         if ( messageTypeUnknown )
1892         {
1893             expert_add_info(pinfo, item, &ei_message_unknown_type );
1894         }
1895         else
1896         {
1897             crcValid = dissect_opensafety_checksum ( message_tvb, pinfo, opensafety_tree, type, frameStart1, frameStart2 );
1898         }
1899
1900         if ( ! crcValid )
1901         {
1902             expert_add_info(pinfo, opensafety_item, &ei_crc_frame_1_invalid );
1903         }
1904
1905         /* with SNMT's we can check if the ID's for the frames match. Rare randomized packages do have
1906          * an issue, where an frame 1 can be valid. The id's for both frames must differ, as well as
1907          * the addresses, but addresses won't be checked yet, as there are issues with SDN xored on it. */
1908         if ( crcValid && type == OPENSAFETY_SNMT_MESSAGE_TYPE )
1909         {
1910             if ( OSS_FRAME_ID_T(message_tvb, frameStart1) != OSS_FRAME_ID_T(message_tvb, frameStart2) )
1911                 expert_add_info(pinfo, opensafety_item, &ei_crc_frame_1_valid_frame2_invalid );
1912         }
1913     }
1914
1915     return TRUE;
1916 }
1917
1918 static gboolean
1919 opensafety_package_dissector(const gchar *protocolName, const gchar *sub_diss_handle,
1920                              gboolean b_frame2First, gboolean do_byte_swap, guint8 force_nr_in_package,
1921                              tvbuff_t *given_tvb , packet_info *pinfo , proto_tree *tree )
1922 {
1923     tvbuff_t           *next_tvb, *message_tvb = NULL;
1924     guint               length, len, frameOffset, frameLength, nodeAddress;
1925     guint8             *bytes;
1926     gboolean            handled, dissectorCalled, call_sub_dissector, markAsMalformed;
1927     guint8              type, found, packageCounter, i, tempByte;
1928     guint16             frameStart1, frameStart2, byte_offset;
1929     gint                reported_len;
1930     dissector_handle_t  protocol_dissector = NULL;
1931     proto_item         *opensafety_item;
1932     proto_tree         *opensafety_tree;
1933
1934     handled            = FALSE;
1935     dissectorCalled    = FALSE;
1936     call_sub_dissector = FALSE;
1937     markAsMalformed    = FALSE;
1938
1939     /* registering frame end routine, to prevent a malformed dissection preventing
1940      * further dissector calls (see bug #6950) */
1941     register_frame_end_routine(pinfo, reset_dissector);
1942
1943     length = tvb_reported_length(given_tvb);
1944     /* Minimum package length is 11 */
1945     if ( length < OSS_MINIMUM_LENGTH )
1946         return FALSE;
1947
1948     if ( strlen( sub_diss_handle ) > 0 )
1949     {
1950         call_sub_dissector = TRUE;
1951         protocol_dissector = find_dissector ( sub_diss_handle );
1952         if ( protocol_dissector == NULL )
1953             protocol_dissector = find_dissector ( "data" );
1954     }
1955
1956     reported_len = tvb_reported_length_remaining(given_tvb, 0);
1957     bytes = (guint8 *) wmem_alloc(pinfo->pool, length);
1958     tvb_memcpy(given_tvb, bytes, 0, length);
1959
1960     if ( do_byte_swap == TRUE && global_mbtcp_big_endian == TRUE )
1961     {
1962         /* Wordswapping for modbus detection */
1963         /* Only a even number of bytes can be swapped */
1964         len = (length / 2);
1965         for ( i = 0; i < len; i++ )
1966         {
1967             tempByte = bytes [ 2 * i ]; bytes [ 2 * i ] = bytes [ 2 * i + 1 ]; bytes [ 2 * i + 1 ] = tempByte;
1968         }
1969
1970         message_tvb = tvb_new_real_data(bytes, length, reported_len);
1971     } else {
1972         message_tvb = given_tvb;
1973     }
1974
1975     frameOffset = 0;
1976     frameLength = 0;
1977     found = 0;
1978     packageCounter = 0;
1979
1980     while ( frameOffset < length )
1981     {
1982         /* Smallest possible frame size is 11 */
1983         if ( tvb_length_remaining(message_tvb, frameOffset ) < OSS_MINIMUM_LENGTH )
1984             break;
1985
1986         /* Finding the start of the first possible safety frame */
1987         if ( findSafetyFrame(message_tvb, frameOffset, b_frame2First, &frameOffset, &frameLength) )
1988         {
1989             /* frameLength is calculated/read directly from the dissected data. If frameLenght and frameOffset together
1990              * are bigger than the reported length, the package is not really an openSAFETY package */
1991             if ( ( frameOffset + frameLength ) > (guint)reported_len )
1992                 break;
1993
1994             found++;
1995
1996             byte_offset = ( b_frame2First ? 0 : frameOffset );
1997             /* We determine a possible position for frame 1 and frame 2 */
1998             if ( b_frame2First )
1999             {
2000                 frameStart1 = findFrame1Position (message_tvb, byte_offset, frameLength, FALSE );
2001                 frameStart2 = 0;
2002             }
2003             else
2004             {
2005                 frameStart1 = 0;
2006                 frameStart2 = ((OSS_FRAME_LENGTH_T(message_tvb, byte_offset + frameStart1) - 1) +
2007                         (OSS_FRAME_LENGTH_T(message_tvb, byte_offset + frameStart1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 ? OSS_SLIM_FRAME2_WITH_CRC16 : OSS_SLIM_FRAME2_WITH_CRC8));
2008             }
2009
2010             /* If both frame starts are equal, something went wrong. In which case, we retract the found entry, and
2011              * also increase the search offset, just doing a continue will result in an infinite loop. */
2012             if (frameStart1 == frameStart2)
2013             {
2014                 found--;
2015                 frameOffset += frameLength ;
2016                 continue;
2017             }
2018
2019             /* We determine the possible type, and return false, if there could not be one */
2020             if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
2021                 type = OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE;
2022             else if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SSDO_MESSAGE_TYPE )
2023                 type = OPENSAFETY_SSDO_MESSAGE_TYPE;
2024             else if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SPDO_MESSAGE_TYPE ) == OPENSAFETY_SPDO_MESSAGE_TYPE )
2025                 type = OPENSAFETY_SPDO_MESSAGE_TYPE;
2026             else if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SNMT_MESSAGE_TYPE ) == OPENSAFETY_SNMT_MESSAGE_TYPE )
2027                 type = OPENSAFETY_SNMT_MESSAGE_TYPE;
2028             else
2029             {
2030                 /* This is an invalid openSAFETY package, but it could be an undetected slim ssdo message. This specific error
2031                  * will only occur, if findFrame1Position is in play. So we search once more, but this time calculating the CRC.
2032                  * The reason for the second run is, that calculating the CRC is time consuming.  */
2033                 if ( b_frame2First )
2034                 {
2035                     /* Now let's check again, but this time calculate the CRC */
2036                     frameStart1 = findFrame1Position(message_tvb, ( b_frame2First ? 0 : frameOffset ), frameLength, TRUE );
2037                     frameStart2 = 0;
2038
2039                     if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
2040                         type = OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE;
2041                     else if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SSDO_MESSAGE_TYPE ) == OPENSAFETY_SSDO_MESSAGE_TYPE )
2042                         type = OPENSAFETY_SSDO_MESSAGE_TYPE;
2043                     else if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SPDO_MESSAGE_TYPE ) == OPENSAFETY_SPDO_MESSAGE_TYPE )
2044                         type = OPENSAFETY_SPDO_MESSAGE_TYPE;
2045                     else if ( ( OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) & OPENSAFETY_SNMT_MESSAGE_TYPE ) == OPENSAFETY_SNMT_MESSAGE_TYPE )
2046                         type = OPENSAFETY_SNMT_MESSAGE_TYPE;
2047                     else {
2048                         /* Skip this frame.  We cannot continue without
2049                            advancing frameOffset - just doing a continue
2050                            will result in an infinite loop. Advancing with 1 will
2051                            lead to infinite loop, advancing with frameLength might miss
2052                            some packages*/
2053                         frameOffset += 2;
2054                         found--;
2055                         continue;
2056                     }
2057                 } else {
2058                     /* As stated above, you cannot just continue
2059                        without advancing frameOffset. Advancing with 1 will
2060                        lead to infinite loop, advancing with frameLength might miss
2061                        some packages*/
2062                     frameOffset += 2;
2063                     found--;
2064                     continue;
2065                 }
2066             }
2067
2068             /* Some faulty packages do indeed have a valid first frame, but the second is
2069              * invalid. These checks should prevent most faulty detections */
2070             if ( type != OPENSAFETY_SPDO_MESSAGE_TYPE )
2071             {
2072                 /* Is the given type at least known? */
2073                 gint idx = -1;
2074                 try_val_to_str_idx(OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1), message_type_values, &idx );
2075                 /* Unknown Frame Type */
2076                 if ( idx < 0 )
2077                 {
2078                     frameOffset += 2;
2079                     found--;
2080                     continue;
2081                 }
2082                 /* Frame IDs do not match */
2083                 else if ( type == OPENSAFETY_SNMT_MESSAGE_TYPE &&
2084                         (OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart1) != OSS_FRAME_ID_T(message_tvb, byte_offset + frameStart2)) )
2085                 {
2086                     frameOffset += 2;
2087                     found--;
2088                     continue;
2089                 }
2090             }
2091
2092             /* Checking if the producer for a SPDO message is valid, otherwise the opensafety package
2093              * is malformed. Instead of declining dissection, the package get's marked as malformed */
2094             if ( type == OPENSAFETY_SPDO_MESSAGE_TYPE )
2095             {
2096                 nodeAddress = OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1);
2097                 if ( nodeAddress > 1024 ) {
2098                     markAsMalformed = TRUE;
2099                 }
2100             }
2101
2102             /* If this package is not valid, the next step, which normally occurs in unxorFrame will lead to a
2103              * frameLength bigger than the maximum data size. This is an indicator, that the package in general
2104              * is fault, and therefore we return false.
2105              */
2106             if ( ( (gint)frameLength - (gint)( frameStart2 > frameStart1 ? frameStart2 : frameLength - frameStart1 ) ) < 0 )
2107                 return FALSE;
2108
2109             /* From here on, the package should be correct, therefore adding second frame */
2110             if ( do_byte_swap == TRUE && global_mbtcp_big_endian == TRUE )
2111             {
2112                 next_tvb = tvb_new_child_real_data(message_tvb, &bytes[frameOffset], (frameLength), reported_len);
2113                 /* Adding a visual aid to the dissector tree */
2114                 add_new_data_source(pinfo, next_tvb, "openSAFETY Frame (Swapped)");
2115             }
2116             else
2117             {
2118                 next_tvb = tvb_new_subset(message_tvb, frameOffset, frameLength, reported_len);
2119                 /* Adding a visual aid to the dissector tree */
2120                 add_new_data_source(pinfo, next_tvb, "openSAFETY Frame");
2121             }
2122
2123             /* A new subtype for package dissection will need to set the actual nr. for the whole dissected package */
2124             if ( force_nr_in_package > 0 )
2125             {
2126                 found = force_nr_in_package + 1;
2127                 dissectorCalled = TRUE;
2128                 col_set_str(pinfo->cinfo, COL_PROTOCOL, protocolName);
2129             }
2130
2131             if ( ! dissectorCalled )
2132             {
2133                 if ( call_sub_dissector )
2134                     call_dissector(protocol_dissector, message_tvb, pinfo, tree);
2135                 dissectorCalled = TRUE;
2136
2137                 col_set_str(pinfo->cinfo, COL_PROTOCOL, protocolName);
2138                 col_clear(pinfo->cinfo,COL_INFO);
2139             }
2140
2141             /* if the tree is NULL, we are called for the overview, otherwise for the
2142              more detailed view of the package */
2143             if ( tree )
2144             {
2145                 /* create the opensafety protocol tree */
2146                 opensafety_item = proto_tree_add_item(tree, proto_opensafety, message_tvb, frameOffset, frameLength, ENC_NA);
2147                 opensafety_tree = proto_item_add_subtree(opensafety_item, ett_opensafety);
2148             } else {
2149                 opensafety_item = NULL;
2150                 opensafety_tree = NULL;
2151             }
2152
2153             if ( dissect_opensafety_message(frameStart1, frameStart2, type, next_tvb, pinfo, opensafety_item, opensafety_tree, found) == TRUE )
2154                 packageCounter++;
2155             else
2156                 markAsMalformed = TRUE;
2157
2158             if ( tree && markAsMalformed )
2159             {
2160                 if ( OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1) > 1024 )
2161                     expert_add_info(pinfo, opensafety_item, &ei_message_spdo_address_invalid );
2162             }
2163             handled = TRUE;
2164         }
2165         else
2166             break;
2167
2168         frameOffset += frameLength;
2169     }
2170
2171     if ( handled == TRUE && packageCounter == 0 )
2172         handled = FALSE;
2173
2174     if ( ! handled )
2175     {
2176         if ( call_sub_dissector )
2177             call_dissector(protocol_dissector, message_tvb, pinfo, tree);
2178         handled = TRUE;
2179     }
2180
2181     return ( handled ? TRUE : FALSE );
2182 }
2183
2184 static gboolean
2185 dissect_opensafety_epl(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2186 {
2187     gboolean        result     = FALSE;
2188     guint8          firstByte;
2189
2190     if ( ! global_enable_plk )
2191         return result;
2192
2193     /* We will call the epl dissector by using call_dissector(). The epl dissector will then call
2194      * the heuristic openSAFETY dissector again. By setting this information, we prevent a dissector
2195      * loop */
2196     if ( bDissector_Called_Once_Before == FALSE )
2197     {
2198         bDissector_Called_Once_Before = TRUE;
2199
2200         firstByte = ( tvb_get_guint8(message_tvb, 0) << 1 );
2201
2202         /* No frames can be sent in SoA and SoC messages, therefore those get filtered right away */
2203         if ( ( firstByte != 0x02 ) && ( firstByte != 0x0A ) )
2204         {
2205             result = opensafety_package_dissector("openSAFETY/Powerlink", "epl",
2206                                                   FALSE, FALSE, 0, message_tvb, pinfo, tree);
2207         }
2208
2209         bDissector_Called_Once_Before = FALSE;
2210     }
2211
2212     return result;
2213 }
2214
2215
2216 static gboolean
2217 dissect_opensafety_siii(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2218 {
2219     gboolean        result     = FALSE;
2220     guint8          firstByte;
2221
2222     if ( ! global_enable_siii )
2223         return result;
2224
2225     if ( pinfo->ipproto == IPPROTO_UDP )
2226     {
2227         return  opensafety_package_dissector("openSAFETY/SercosIII UDP", "", FALSE, FALSE, 0, message_tvb, pinfo, tree);
2228     }
2229
2230     /* We can assume to have a SercosIII package, as the SercosIII dissector won't detect
2231      * SercosIII-UDP packages, this is most likely SercosIII-over-ethernet */
2232
2233     /* We will call the SercosIII dissector by using call_dissector(). The SercosIII dissector will
2234      * then call the heuristic openSAFETY dissector again. By setting this information, we prevent
2235      * a dissector loop. */
2236     if ( bDissector_Called_Once_Before == FALSE )
2237     {
2238         bDissector_Called_Once_Before = TRUE;
2239         /* No frames can be sent in AT messages, therefore those get filtered right away */
2240         firstByte = ( tvb_get_guint8(message_tvb, 0) << 1 );
2241         if ( ( firstByte & 0x40 ) == 0x40 )
2242         {
2243             result = opensafety_package_dissector("openSAFETY/SercosIII", "sercosiii",
2244                                                   FALSE, FALSE, 0, message_tvb, pinfo, tree);
2245         }
2246         bDissector_Called_Once_Before = FALSE;
2247     }
2248
2249     return result;
2250 }
2251
2252 static gboolean
2253 dissect_opensafety_pn_io(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2254 {
2255     gboolean        result     = FALSE;
2256
2257     if ( ! global_enable_pnio )
2258         return result;
2259
2260     /* We will call the pn_io dissector by using call_dissector(). The epl dissector will then call
2261      * the heuristic openSAFETY dissector again. By setting this information, we prevent a dissector
2262      * loop */
2263     if ( bDissector_Called_Once_Before == FALSE )
2264     {
2265         bDissector_Called_Once_Before = TRUE;
2266         result = opensafety_package_dissector("openSAFETY/Profinet IO", "pn_io",
2267                                               FALSE, FALSE, 0, message_tvb, pinfo, tree);
2268         bDissector_Called_Once_Before = FALSE;
2269     }
2270
2271     return result;
2272 }
2273
2274 static gboolean
2275 dissect_opensafety_mbtcp(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree, void *data _U_ )
2276 {
2277     if ( ! global_enable_mbtcp )
2278         return FALSE;
2279
2280     /* When Modbus/TCP get's dissected, openSAFETY would be sorted as a child protocol. Although,
2281      * this behaviour is technically correct, it differs from other implemented IEM protocol handlers.
2282      * Therefore, the openSAFETY frame get's put one up, if the parent is not NULL */
2283     return opensafety_package_dissector("openSAFETY/Modbus TCP", "", FALSE, TRUE, 0,
2284                                         message_tvb, pinfo, ( tree->parent != NULL ? tree->parent : tree ));
2285 }
2286
2287 static gboolean
2288 dissect_opensafety_udpdata(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2289 {
2290     gboolean       result   = FALSE;
2291     static guint32 frameNum = 0;
2292     static guint32 frameIdx = 0;
2293
2294     if ( ! global_enable_udp )
2295         return result;
2296
2297     /* An openSAFETY frame has at least OSS_MINIMUM_LENGTH bytes */
2298     if ( tvb_length ( message_tvb ) < OSS_MINIMUM_LENGTH )
2299         return result;
2300
2301     /* More than one openSAFETY package could be transported in the same frame,
2302         * in such a case, we need to establish the number of packages inside the frame */
2303     if ( pinfo->fd->num != frameNum )
2304     {
2305         frameIdx = 0;
2306         frameNum = pinfo->fd->num;
2307     }
2308
2309     result = opensafety_package_dissector((pinfo->destport == UDP_PORT_SIII ? "openSAFETY/SercosIII" : "openSAFETY/UDP" ),
2310                                           "", pinfo->destport == UDP_PORT_SIII ? global_siii_udp_frame2_first : global_udp_frame2_first,
2311                                           FALSE, frameIdx, message_tvb, pinfo, tree);
2312
2313     if ( result )
2314         frameIdx++;
2315
2316     return result;
2317 }
2318
2319 static void
2320 apply_prefs ( void )
2321 {
2322     static gboolean opensafety_init = FALSE;
2323     static guint    opensafety_udp_port_number;
2324     static guint    opensafety_udp_siii_port_number;
2325
2326     /* It only should delete dissectors, if run for any time except the first */
2327     if ( opensafety_init )
2328     {
2329         /* Delete dissectors in preparation of a changed config setting */
2330         dissector_delete_uint ("udp.port", opensafety_udp_port_number, find_dissector("opensafety_udpdata"));
2331         dissector_delete_uint ("udp.port", opensafety_udp_siii_port_number, find_dissector("opensafety_siii"));
2332     }
2333
2334     opensafety_init = TRUE;
2335
2336     /* Storing the port numbers locally, to being able to delete the old associations */
2337     opensafety_udp_port_number = global_network_udp_port;
2338     opensafety_udp_siii_port_number = global_network_udp_port_sercosiii;
2339
2340     /* Default UDP only based dissector */
2341     dissector_add_uint("udp.port", opensafety_udp_port_number, find_dissector("opensafety_udpdata"));
2342
2343     /* Sercos III dissector does not handle UDP transport, has to be handled
2344      *  separately, everything else should be caught by the heuristic dissector
2345      */
2346     dissector_add_uint("udp.port", opensafety_udp_siii_port_number, find_dissector("opensafety_siii"));
2347
2348 }
2349
2350 void
2351 proto_register_opensafety(void)
2352 {
2353     /* Setup list of header fields */
2354     static hf_register_info hf[] = {
2355         { &hf_oss_scm_udid,
2356             { "SCM UDID Configured",    "opensafety.scm_udid",
2357             FT_STRING,   BASE_NONE, NULL,   0x0, NULL, HFILL } },
2358         { &hf_oss_scm_udid_auto,
2359             { "SCM UDID Auto Detect",    "opensafety.scm_udid.auto",
2360             FT_STRING,   BASE_NONE, NULL,   0x0, NULL, HFILL } },
2361         { &hf_oss_scm_udid_valid,
2362             { "SCM UDID Valid",    "opensafety.scm_udid.valid",
2363             FT_BOOLEAN,   BASE_NONE, NULL,   0x0, NULL, HFILL } },
2364
2365         { &hf_oss_msg,
2366             { "Message",    "opensafety.msg.id",
2367             FT_UINT8,   BASE_HEX, VALS(message_type_values),   0x0, NULL, HFILL } },
2368         { &hf_oss_msg_category,
2369             { "Type",  "opensafety.msg.type",
2370             FT_UINT16,   BASE_HEX, VALS(message_id_values),   0x0, NULL, HFILL } },
2371         { &hf_oss_msg_direction,
2372             { "Direction",  "opensafety.msg.direction",
2373             FT_BOOLEAN,   BASE_NONE, TFS(&opensafety_message_direction),   0x0, NULL, HFILL } },
2374         { &hf_oss_msg_node,
2375             { "Safety Node",  "opensafety.msg.node",
2376             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2377         { &hf_oss_msg_network,
2378             { "Safety Domain",  "opensafety.msg.network",
2379             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2380         { &hf_oss_msg_sender,
2381             { "Sender",  "opensafety.msg.sender",
2382             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2383         { &hf_oss_msg_receiver,
2384             { "Receiver",  "opensafety.msg.receiver",
2385             FT_UINT16,   BASE_HEX, NULL,   0x0, NULL, HFILL } },
2386         { &hf_oss_length,
2387             { "Length",    "opensafety.length",
2388             FT_UINT8,   BASE_DEC, NULL,     0x0, NULL, HFILL } },
2389         { &hf_oss_crc,
2390             { "CRC",       "opensafety.crc.data",
2391             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2392
2393         { &hf_oss_crc_valid,
2394             { "Is Valid", "opensafety.crc.valid",
2395             FT_BOOLEAN, BASE_NONE, NULL,    0x0, NULL, HFILL } },
2396         { &hf_oss_crc_type,
2397             { "CRC Type",  "opensafety.crc.type",
2398             FT_UINT8,   BASE_DEC, VALS(message_crc_type),    0x0, NULL, HFILL } },
2399         { &hf_oss_crc2_valid,
2400             { "Is Valid", "opensafety.crc2.valid",
2401             FT_BOOLEAN, BASE_NONE, NULL,    0x0, NULL, HFILL } },
2402
2403         /* SNMT Specific fields */
2404         { &hf_oss_snmt_slave,
2405             { "SNMT Slave",    "opensafety.snmt.slave",
2406             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2407         { &hf_oss_snmt_master,
2408             { "SNMT Master",   "opensafety.snmt.master",
2409             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2410         { &hf_oss_snmt_scm,
2411             { "SCM",    "opensafety.snmt.scm",
2412             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2413         { &hf_oss_snmt_tool,
2414             { "Tool ID",   "opensafety.snmt.tool_id",
2415             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2416         { &hf_oss_snmt_udid,
2417             { "UDID for SN",   "opensafety.snmt.udid",
2418             FT_ETHER,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2419         { &hf_oss_snmt_service_id,
2420             { "Extended Service ID",   "opensafety.snmt.service_id",
2421             FT_UINT8,  BASE_HEX, VALS(message_service_type),    0x0, NULL, HFILL } },
2422         { &hf_oss_snmt_error_group,
2423             { "Error Group",   "opensafety.snmt.error_group",
2424             FT_UINT8,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2425         { &hf_oss_snmt_error_code,
2426             { "Error Code",   "opensafety.snmt.error_code",
2427             FT_UINT8,  BASE_DEC, NULL,   0x0, NULL, HFILL } },
2428         { &hf_oss_snmt_param_type,
2429             { "Parameter Request Type",   "opensafety.snmt.parameter_type",
2430             FT_BOOLEAN,  BASE_NONE, TFS(&opensafety_addparam_request),   0x0, NULL, HFILL } },
2431         { &hf_oss_snmt_ext_addsaddr,
2432             { "Additional SADDR",    "opensafety.snmt.additional.saddr",
2433             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2434         { &hf_oss_snmt_ext_addtxspdo,
2435             { "Additional TxSPDO",    "opensafety.snmt.additional.txspdo",
2436             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2437
2438         /* SSDO Specific fields */
2439         { &hf_oss_ssdo_server,
2440             { "SSDO Server", "opensafety.ssdo.master",
2441             FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2442         { &hf_oss_ssdo_client,
2443             { "SSDO Client", "opensafety.ssdo.client",
2444             FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2445         { &hf_oss_ssdo_sano,
2446             { "SOD Access Request Number", "opensafety.ssdo.sano",
2447             FT_UINT16,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2448         { &hf_oss_ssdo_sacmd,
2449             { "SOD Access Command", "opensafety.ssdo.sacmd",
2450             FT_UINT8,  BASE_HEX, VALS(ssdo_sacmd_values),    0x0, NULL, HFILL } },
2451         { &hf_oss_ssdo_sod_index,
2452             { "SOD Index", "opensafety.ssdo.sodentry.index",
2453             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2454         { &hf_oss_ssdo_sod_subindex,
2455             { "SOD Sub Index", "opensafety.ssdo.sodentry.subindex",
2456             FT_UINT8,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2457         { &hf_oss_ssdo_payload,
2458             { "SOD Payload", "opensafety.ssdo.payload",
2459             FT_BYTES,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2460         { &hf_oss_ssdo_payload_size,
2461             { "SOD Payload Size", "opensafety.ssdo.payloadsize",
2462             FT_UINT32,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2463         { &hf_oss_ssdo_sodentry_size,
2464             { "SOD Entry Size", "opensafety.ssdo.sodentry.size",
2465             FT_UINT32,  BASE_DEC, NULL,    0x0, NULL, HFILL } },
2466         { &hf_oss_ssdo_sodentry_data,
2467             { "SOD Data", "opensafety.ssdo.sodentry.data",
2468             FT_BYTES,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2469         { &hf_oss_sod_par_timestamp,
2470             { "Parameter Timestamp", "opensafety.sod.parameter.timestamp",
2471             FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2472         { &hf_oss_sod_par_checksum,
2473             { "Parameter Checksum", "opensafety.sod.parameter.checksum",
2474             FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2475
2476         { &hf_oss_ssdo_sodmapping,
2477             { "Mapping entry", "opensafety.sod.mapping",
2478             FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2479         { &hf_oss_ssdo_sodmapping_bits,
2480             { "Mapping size", "opensafety.sod.mapping.bits",
2481             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2482
2483         { &hf_oss_ssdo_extpar_parset,
2484             { "Additional Parameter Set", "opensafety.ssdo.extpar.setnr",
2485             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2486         { &hf_oss_ssdo_extpar_version,
2487             { "Parameter Set Version", "opensafety.ssdo.extpar.version",
2488             FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2489         { &hf_oss_ssdo_extpar_saddr,
2490             { "Parameter Set for SADDR", "opensafety.ssdo.extpar.saddr",
2491             FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2492         { &hf_oss_ssdo_extpar_length,
2493             { "Parameter Set Length", "opensafety.ssdo.extpar.length",
2494             FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2495         { &hf_oss_ssdo_extpar_crc,
2496             { "Parameter Set CRC", "opensafety.ssdo.extpar.crc",
2497             FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2498         { &hf_oss_ssdo_extpar_tstamp,
2499             { "Timestamp", "opensafety.ssdo.extpar.timestamp",
2500             FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2501         { &hf_oss_ssdo_extpar_data,
2502             { "Ext. Parameter Data", "opensafety.ssdo.extpar.data",
2503             FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2504         { &hf_oss_ssdo_extpar,
2505             { "Ext. Parameter", "opensafety.ssdo.extpar",
2506             FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2507
2508         {&hf_oss_fragments,
2509             {"Message fragments", "opensafety.ssdo.fragments",
2510             FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2511         {&hf_oss_fragment,
2512             {"Message fragment", "opensafety.ssdo.fragment",
2513             FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2514         {&hf_oss_fragment_overlap,
2515             {"Message fragment overlap", "opensafety.ssdo.fragment.overlap",
2516             FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2517         {&hf_oss_fragment_overlap_conflicts,
2518             {"Message fragment overlapping with conflicting data",
2519             "opensafety.ssdo.fragment.overlap.conflicts",
2520             FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2521         {&hf_oss_fragment_multiple_tails,
2522             {"Message has multiple tail fragments", "opensafety.ssdo.fragment.multiple_tails",
2523             FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2524         {&hf_oss_fragment_too_long_fragment,
2525             {"Message fragment too long", "opensafety.ssdo.fragment.too_long_fragment",
2526             FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
2527         {&hf_oss_fragment_error,
2528             {"Message defragmentation error", "opensafety.ssdo.fragment.error",
2529             FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2530         {&hf_oss_fragment_count,
2531             {"Message fragment count", "opensafety.ssdo.fragment.count",
2532             FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
2533         {&hf_oss_reassembled_in,
2534             {"Reassembled in", "opensafety.ssdo.reassembled.in",
2535             FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2536         {&hf_oss_reassembled_length,
2537             {"Reassembled length", "opensafety.ssdo.reassembled.length",
2538             FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
2539         {&hf_oss_reassembled_data,
2540             {"Reassembled Data", "opensafety.ssdo.reassembled.data",
2541             FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
2542
2543 #if 0
2544         { &hf_oss_ssdo_inhibit_time,
2545           { "Inhibit Time", "opensafety.ssdo.inhibittime",
2546             FT_UINT32,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2547 #endif
2548         { &hf_oss_ssdo_abort_code,
2549             { "Abort Code", "opensafety.ssdo.abortcode",
2550             FT_UINT32,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2551
2552         /* SSDO SACmd specific fields */
2553         { &hf_oss_ssdo_sacmd_access_type,
2554           { "Access Type", "opensafety.ssdo.sacmd.access",
2555             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_acc), OPENSAFETY_SSDO_SACMD_ACC, NULL, HFILL } },
2556 #if 0
2557         { &hf_oss_ssdo_sacmd_reserved,
2558           { "Reserved", "opensafety.ssdo.sacmd.reserved",
2559             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_res), OPENSAFETY_SSDO_SACMD_RES, NULL, HFILL } },
2560 #endif
2561         { &hf_oss_ssdo_sacmd_abort_transfer,
2562           { "Abort Transfer", "opensafety.ssdo.sacmd.abort_transfer",
2563             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_abrt), OPENSAFETY_SSDO_SACMD_ABRT, NULL, HFILL } },
2564         { &hf_oss_ssdo_sacmd_segmentation,
2565           { "Segmentation", "opensafety.ssdo.sacmd.segmentation",
2566             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_seg), OPENSAFETY_SSDO_SACMD_SEG, NULL, HFILL } },
2567         { &hf_oss_ssdo_sacmd_toggle,
2568           { "Toggle Bit", "opensafety.ssdo.sacmd.toggle",
2569             FT_BOOLEAN,  8, TFS(&opensafety_on_off), OPENSAFETY_SSDO_SACMD_TGL, NULL, HFILL } },
2570         { &hf_oss_ssdo_sacmd_initiate,
2571           { "Initiate Transfer", "opensafety.ssdo.sacmd.initiate",
2572             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_ini), OPENSAFETY_SSDO_SACMD_INI, NULL, HFILL } },
2573         { &hf_oss_ssdo_sacmd_end_segment,
2574           { "End Segment", "opensafety.ssdo.sacmd.end_segment",
2575             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_ensg), OPENSAFETY_SSDO_SACMD_ENSG, NULL, HFILL } },
2576         { &hf_oss_ssdo_sacmd_block_transfer,
2577           { "Block Transfer", "opensafety.ssdo.sacmd.block_transfer",
2578             FT_BOOLEAN,  8, TFS(&opensafety_sacmd_blk), OPENSAFETY_SSDO_SACMD_BLK, NULL, HFILL } },
2579
2580         /* SPDO Specific fields */
2581         { &hf_oss_spdo_connection_valid,
2582           { "Connection Valid Bit", "opensafety.spdo.connection_valid",
2583             FT_BOOLEAN,  BASE_NONE, TFS(&opensafety_set_notset),  0x0, NULL, HFILL } },
2584         { &hf_oss_spdo_payload,
2585           { "SPDO Payload", "opensafety.spdo.payload",
2586             FT_BYTES,  BASE_NONE, NULL,    0x0, NULL, HFILL } },
2587         { &hf_oss_spdo_producer,
2588           { "Producer", "opensafety.spdo.producer",
2589             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2590         { &hf_oss_spdo_producer_time,
2591           { "Internal Time Producer", "opensafety.spdo.time.producer",
2592             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2593         { &hf_oss_spdo_time_value_sn,
2594           { "Internal Time SN", "opensafety.spdo.time.sn",
2595             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2596         { &hf_oss_spdo_time_request,
2597           { "Time Request Counter", "opensafety.spdo.time.request_counter",
2598             FT_UINT8,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2599         { &hf_oss_spdo_time_request_to,
2600           { "Time Request from", "opensafety.spdo.time.request_from",
2601             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2602         { &hf_oss_spdo_time_request_from,
2603           { "Time Request by", "opensafety.spdo.time.request_to",
2604             FT_UINT16,  BASE_HEX, NULL,    0x0, NULL, HFILL } },
2605
2606     };
2607
2608     /* Setup protocol subtree array */
2609     static gint *ett[] = {
2610         &ett_opensafety,
2611         &ett_opensafety_sender,
2612         &ett_opensafety_receiver,
2613         &ett_opensafety_checksum,
2614         &ett_opensafety_snmt,
2615         &ett_opensafety_ssdo,
2616         &ett_opensafety_ssdo_sacmd,
2617         &ett_opensafety_ssdo_fragment,
2618         &ett_opensafety_ssdo_fragments,
2619         &ett_opensafety_ssdo_payload,
2620         &ett_opensafety_ssdo_sodentry,
2621         &ett_opensafety_sod_mapping,
2622         &ett_opensafety_ssdo_extpar,
2623         &ett_opensafety_spdo,
2624     };
2625
2626     static ei_register_info ei[] = {
2627         { &ei_crc_frame_1_invalid,
2628             { "opensafety.crc.error.frame1_invalid", PI_PROTOCOL, PI_ERROR,
2629               "Frame 1 CRC invalid, Possible error in package", EXPFILL } },
2630         { &ei_crc_frame_1_valid_frame2_invalid,
2631             { "opensafety.crc.error.frame1_valid_frame2_invalid", PI_PROTOCOL, PI_ERROR,
2632               "Frame 1 is valid, frame 2 id is invalid", EXPFILL } },
2633         { &ei_crc_slimssdo_instead_of_spdo,
2634             { "opensafety.crc.warning.wrong_crc_for_spdo", PI_PROTOCOL, PI_WARN,
2635               "Frame 1 SPDO CRC is Slim SSDO CRC16 0x5935", EXPFILL } },
2636         { &ei_crc_frame_2_invalid,
2637             { "opensafety.crc.error.frame2_invalid", PI_PROTOCOL, PI_ERROR,
2638               "Frame 2 CRC invalid, Possible error in package or crc calculation", EXPFILL } },
2639         { &ei_crc_frame_2_unknown_scm_udid,
2640             { "opensafety.crc.error.frame2_unknown_scmudid", PI_PROTOCOL, PI_WARN,
2641               "Frame 2 CRC invalid, SCM UDID was not auto-detected", EXPFILL } },
2642
2643         { &ei_message_reassembly_size_differs_from_header,
2644             { "opensafety.msg.warning.reassembly_size_fail", PI_PROTOCOL, PI_WARN,
2645               "Reassembled message size differs from size in header", EXPFILL } },
2646         { &ei_message_unknown_type,
2647             { "opensafety.msg.error.unknown_type", PI_MALFORMED, PI_ERROR,
2648               "Unknown openSAFETY message type", EXPFILL } },
2649         { &ei_message_spdo_address_invalid,
2650             { "opensafety.msg.error.spdo_address_invalid", PI_MALFORMED, PI_ERROR,
2651               "SPDO address is invalid", EXPFILL } },
2652         { &ei_message_id_field_mismatch,
2653             { "opensafety.msg.error.id.mismatch", PI_PROTOCOL, PI_ERROR,
2654               "ID for frame 2 is not the same as for frame 1", EXPFILL } },
2655
2656         { &ei_scmudid_autodetected,
2657             { "opensafety.scm_udid.note.autodetected", PI_PROTOCOL, PI_NOTE,
2658               "Auto detected payload as SCM UDID", EXPFILL } },
2659         { &ei_scmudid_invalid_preference,
2660             { "opensafety.scm_udid.note.invalid_preference", PI_PROTOCOL, PI_WARN,
2661               "openSAFETY protocol settings are invalid! SCM UDID first octet will be assumed to be 00", EXPFILL } },
2662         { &ei_scmudid_unknown,
2663             { "opensafety.scm_udid.warning.assuming_first_octet", PI_PROTOCOL, PI_WARN,
2664               "SCM UDID unknown, assuming 00 as first UDID octet", EXPFILL } },
2665
2666         { &ei_payload_unknown_format,
2667             { "opensafety.msg.warning.unknown_format", PI_PROTOCOL, PI_WARN,
2668               "Unknown payload format detected", EXPFILL } },
2669         { &ei_payload_length_not_positive,
2670             { "opensafety.msg.warning.reassembly_length_not_positive", PI_PROTOCOL, PI_NOTE,
2671               "Calculation for payload length yielded non-positive result", EXPFILL } },
2672     };
2673
2674     module_t *opensafety_module;
2675     expert_module_t *expert_opensafety;
2676
2677     /* Register the protocol name and description */
2678     proto_opensafety = proto_register_protocol("openSAFETY", "openSAFETY",  "opensafety");
2679     opensafety_module = prefs_register_protocol(proto_opensafety, apply_prefs);
2680
2681     /* Required function calls to register the header fields and subtrees used */
2682     proto_register_field_array(proto_opensafety, hf, array_length(hf));
2683     proto_register_subtree_array(ett, array_length(ett));
2684
2685     expert_opensafety = expert_register_protocol ( proto_opensafety );
2686     expert_register_field_array ( expert_opensafety, ei, array_length (ei ) );
2687
2688     /* register user preferences */
2689     prefs_register_string_preference(opensafety_module, "scm_udid",
2690                  "SCM UDID (xx:xx:xx:xx:xx:xx)",
2691                  "To be able to fully dissect SSDO and SPDO packages, a valid UDID for the SCM has to be provided",
2692                  &global_scm_udid);
2693     prefs_register_bool_preference(opensafety_module, "scm_udid_autoset",
2694                  "Set SCM UDID if detected in stream",
2695                  "Automatically assign a detected SCM UDID (by reading SNMT->SNTM_assign_UDID_SCM) and set it for the file",
2696                  &global_scm_udid_autoset);
2697     prefs_register_bool_preference(opensafety_module, "calculate_crc2",
2698                  "Enable CRC calculation in frame 2",
2699                  "Enable the calculation for the second CRC",
2700                  &global_calculate_crc2);
2701
2702     prefs_register_uint_preference(opensafety_module, "network_udp_port",
2703                 "Port used for Generic UDP",
2704                 "Port used by any UDP demo implementation to transport data", 10,
2705                 &global_network_udp_port);
2706     prefs_register_uint_preference(opensafety_module, "network_udp_port_sercosiii",
2707                 "Port used for SercosIII/UDP",
2708                 "UDP port used by SercosIII to transport data", 10,
2709                 &global_network_udp_port_sercosiii);
2710     prefs_register_bool_preference(opensafety_module, "network_udp_frame_first_sercosiii",
2711                 "openSAFETY frame 2 before frame 1 (SercosIII/UDP only)",
2712                 "In an SercosIII/UDP transport stream, openSAFETY frame 2 will be expected before frame 1",
2713                 &global_siii_udp_frame2_first );
2714     prefs_register_bool_preference(opensafety_module, "network_udp_frame_first",
2715                 "openSAFETY frame 2 before frame 1 (UDP only)",
2716                 "In the transport stream, openSAFETY frame 2 will be expected before frame 1",
2717                 &global_udp_frame2_first );
2718     prefs_register_bool_preference(opensafety_module, "mbtcp_big_endian",
2719                 "Big Endian Word Coding (Modbus/TCP only)",
2720                 "Modbus/TCP words can be transcoded either big- or little endian. Default will be little endian",
2721                 &global_mbtcp_big_endian);
2722
2723     prefs_register_bool_preference(opensafety_module, "enable_plk",
2724                 "Enable heuristic dissection for Ethernet POWERLINK", "Enable heuristic dissection for Ethernet POWERLINK",
2725                 &global_enable_plk);
2726     prefs_register_bool_preference(opensafety_module, "enable_udp",
2727                 "Enable heuristic dissection for openSAFETY over UDP encoded traffic", "Enable heuristic dissection for openSAFETY over UDP encoded traffic",
2728                 &global_enable_udp);
2729     prefs_register_bool_preference(opensafety_module, "enable_genudp",
2730                 "Enable heuristic dissection for generic UDP encoded traffic", "Enable heuristic dissection for generic UDP encoded traffic",
2731                 &global_enable_genudp);
2732     prefs_register_bool_preference(opensafety_module, "enable_siii",
2733                 "Enable heuristic dissection for SercosIII", "Enable heuristic dissection for SercosIII",
2734                 &global_enable_siii);
2735     prefs_register_bool_preference(opensafety_module, "enable_pnio",
2736                 "Enable heuristic dissection for Profinet IO", "Enable heuristic dissection for Profinet IO",
2737                 &global_enable_pnio);
2738     prefs_register_bool_preference(opensafety_module, "enable_mbtcp",
2739                 "Enable heuristic dissection for Modbus/TCP", "Enable heuristic dissection for Modbus/TCP",
2740                 &global_enable_mbtcp);
2741
2742     /* Registering default and ModBus/TCP dissector */
2743     new_register_dissector("opensafety_udpdata", dissect_opensafety_udpdata, proto_opensafety );
2744     new_register_dissector("opensafety_mbtcp", dissect_opensafety_mbtcp, proto_opensafety );
2745     new_register_dissector("opensafety_siii", dissect_opensafety_siii, proto_opensafety );
2746     new_register_dissector("opensafety_pnio", dissect_opensafety_pn_io, proto_opensafety);
2747 }
2748
2749 void
2750 proto_reg_handoff_opensafety(void)
2751 {
2752     static int opensafety_inited = FALSE;
2753
2754     if ( !opensafety_inited )
2755     {
2756         /* EPL & SercosIII dissector registration */
2757         heur_dissector_add("epl", dissect_opensafety_epl, proto_opensafety);
2758         heur_dissector_add("sercosiii", dissect_opensafety_siii, proto_opensafety);
2759
2760         /* If an openSAFETY UDP transport filter is present, add to its
2761          * heuristic filter list. Otherwise ignore the transport */
2762         if ( find_dissector("opensafety_udp") != NULL )
2763                 heur_dissector_add("opensafety_udp", dissect_opensafety_udpdata, proto_opensafety);
2764
2765         /* Modbus TCP dissector registration */
2766         dissector_add_string("modbus.data", "data", find_dissector("opensafety_mbtcp"));
2767
2768         /* For Profinet we have to register as a heuristic dissector, as Profinet
2769          *  is implemented as a plugin, and therefore the heuristic dissector is not
2770          *  added by the time this method is being called
2771          */
2772         if ( find_dissector("pn_io") != NULL )
2773         {
2774             heur_dissector_add("pn_io", dissect_opensafety_pn_io, proto_opensafety);
2775         }
2776         else
2777         {
2778             /* The native dissector cannot be loaded. so we add our protocol directly to
2779              * the ethernet subdissector list. No PNIO specific data will be dissected
2780              * and a warning will be displayed, recognizing the missing dissector plugin.
2781              */
2782             dissector_add_uint("ethertype", ETHERTYPE_PROFINET, find_dissector("opensafety_pnio"));
2783         }
2784
2785         register_init_routine ( setup_dissector );
2786
2787         /* registering frame end routine, to prevent a malformed dissection preventing
2788          * further dissector calls (see bug #6950) */
2789         /* register_frame_end_routine(reset_dissector); */
2790     }
2791
2792 }
2793
2794 /*
2795  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2796  *
2797  * Local variables:
2798  * c-basic-offset: 8
2799  * tab-width: 8
2800  * indent-tabs-mode: t
2801  * End:
2802  *
2803  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2804  * :indentSize=8:tabSize=8:noTabs=false:
2805  */