HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-opensafety.c
blobbf07d35d23c21238c06d5babc1d086c2b26e387f
1 /* packet-opensafety.c
3 * $Id$
5 * openSAFETY is a machine-safety protocol, encapsulated in modern fieldbus
6 * and industrial ethernet solutions.
8 * For more information see http://www.open-safety.org
10 * This dissector currently supports the following transport protocols
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
19 * By Roland Knall <roland.knall@br-automation.com>
20 * Copyright 2011-2012 Bernecker + Rainer Industrie-Elektronik Ges.m.b.H.
22 * Wireshark - Network traffic analyzer
23 * By Gerald Combs <gerald@wireshark.org>
24 * Copyright 1998 Gerald Combs
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.
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.
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.
41 #include "config.h"
43 #include <glib.h>
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>
55 #include <wsutil/crc8.h>
56 #include <wsutil/crc16.h>
58 #include <stdio.h>
59 #include <string.h>
62 /* General definitions */
64 /* openSAFETY UDP Port */
65 #ifndef UDP_PORT_OPENSAFETY
66 #define UDP_PORT_OPENSAFETY 9877
67 #endif
69 /* SercosIII UDP Port */
70 #ifndef UDP_PORT_SIII
71 #define UDP_PORT_SIII 8755
72 #endif
74 #define OPENSAFETY_DEFAULT_DOMAIN 0x1
76 /* Under linux, this get's defined in netinet/in.h */
77 #ifndef IPPROTO_UDP
78 #define IPPROTO_UDP 0x11
79 #endif
81 #ifndef OPENSAFETY_PINFO_CONST_DATA
82 #define OPENSAFETY_PINFO_CONST_DATA 0xAABBCCDD
83 #endif
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
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 }
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
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 }
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
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
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
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" },
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" },
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 }
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
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 }
187 /* Values 6-255 are reserved for future use. They will be presented as "Reserved [%d]"
188 * during dissection
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
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 }
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
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 }
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
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" };
268 #define OPENSAFETY_SPDO_CONNECTION_VALID 0x04
270 #define OPENSAFETY_SOD_DVI 0x1018
271 #define OPENSAFETY_SOD_RXMAP 0x1800
272 #define OPENSAFETY_SOD_TXMAP 0xC000
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" },
280 { 0x100D0000, "Number of Retries for Reset Guarding" },
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" },
291 { 0x10190000, "Unique Device ID" },
292 { 0x101A0000, "Parameter Download" },
293 { 0x101B0000, "SCM Parameters" },
295 { 0x12000000, "Common Communication Parameters" },
296 { 0x12000001, "Safety Domain Number" },
297 { 0x12000002, "SADR" },
298 { 0x12000003, "Consecutive Timebase" },
299 { 0x12000004, "UDID of SCM" },
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" },
315 { 0x18000000, "RxSPDO Mapping Parameters" },
317 { 0x1C000000, "TxSPDO Communication Parameters" },
318 { 0x1C000001, "SADR for broadcast" },
319 { 0x1C000002, "Refresh Prescale" },
320 { 0x1C000003, "Number of TRes" },
322 { 0x20000000, "Manufacturer Parameters" },
323 { 0x20010000, "Used Channels" },
325 { 0x21000000, "Safe Machine Options" },
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" },
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" },
348 { 0xC0000000, "TxSPDO Mapping Parameters" },
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" },
362 { 0xD0100000, "Remanent Data" },
363 { 0xD0100001, "DINT" },
365 { 0xD0110000, "Remanent Data" },
366 { 0xD0110001, "DUINT" },
368 { 0, NULL }
371 static const value_string abort_codes[] = {
373 /* SSDO abort codes */
374 { 0x05030000, "Reserved" },
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" },
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" },
387 { 0x06020000, "Object does not exist in the object dictionary" },
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" },
394 { 0x06060000, "Access failed due to a hardware error" },
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" },
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" },
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" },
412 { 0, NULL }
415 static const true_false_string opensafety_message_direction = { "Request", "Response" };
416 #define OPENSAFETY_REQUEST TRUE
417 #define OPENSAFETY_RESPONSE FALSE
419 static const true_false_string opensafety_addparam_request = { "Header only", "Header & Data" };
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
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 */
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])
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))
443 static int proto_opensafety = -1;
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;
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;
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;
483 static int hf_oss_crc_valid = -1;
484 static int hf_oss_crc2_valid = -1;
485 static int hf_oss_crc_type = -1;
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;
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;
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;
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;
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;
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;
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;
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;
560 static gint ett_opensafety_ssdo_fragment = -1;
561 static gint ett_opensafety_ssdo_fragments = -1;
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"
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;
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;
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;
607 static reassembly_table os_reassembly_table;
609 /* Resets the dissector in case the dissection is malformed and the dissector crashes */
610 static void
611 reset_dissector(void)
613 bDissector_Called_Once_Before = FALSE;
616 static void
617 setup_dissector(void)
619 if ( local_scm_udid != NULL )
620 local_scm_udid = NULL;
622 reassembly_table_init(&os_reassembly_table, &addresses_reassembly_table_functions);
625 void proto_register_opensafety(void);
626 void proto_reg_handoff_opensafety(void);
628 /* Conversation functions */
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 )
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 ) \
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 ); \
651 PROTO_ITEM_SET_GENERATED(psf_item); \
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 ) \
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 ); \
670 PROTO_ITEM_SET_GENERATED(psf_item); \
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); \
680 static guint16
681 findFrame1Position ( tvbuff_t *message_tvb, guint16 byte_offset, guint8 dataLength, gboolean checkIfSlimMistake )
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;
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
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);
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 )
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);
709 bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, byte_offset + i_wFrame1Position, dataLength + 4);
710 if ( dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
712 calcCRC = crc16_0x755B(bytes, dataLength + 4, 0);
713 if ( frameCRC != calcCRC )
714 calcCRC = crc16_0x5935(bytes, dataLength + 4, 0);
716 else
717 calcCRC = crc8_0x2F(bytes, dataLength + 4, 0);
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;
724 /* If the calculated length differs from the given length, a slim package is assumed. */
725 if ( i_calculatedLength != dataLength )
727 /* possible slim package */
728 i_wFrame1Position = 0;
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
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;
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 ) )
741 /* Slim package found */
742 i_wFrame1Position = i_offset;
746 return i_wFrame1Position;
749 static guint8 findSafetyFrame ( tvbuff_t * message_tvb, guint u_Offset, gboolean b_frame2first, guint *u_frameOffset, guint *u_frameLength )
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;
758 found = 0;
759 ctr = u_Offset;
760 rem_length = tvb_reported_length_remaining (message_tvb, ctr);
762 while ( rem_length >= OSS_MINIMUM_LENGTH)
764 /* The ID byte must ALWAYS be the second byte, therefore 0 is invalid */
765 if ( ctr != 0 )
767 *u_frameLength = 0;
768 *u_frameOffset = 0;
770 crcOffset = 0;
771 b_ID = tvb_get_guint8(message_tvb, ctr );
773 if ( b_ID != 0x0 )
775 b_Length = tvb_get_guint8(message_tvb, ctr + 1 );
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 ) )
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);
786 /* Plausability check on length */
787 if ( (guint)( b_Length * 2 ) < ( rem_length + OSS_MINIMUM_LENGTH ) )
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 ) ) )
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) )
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 ) )
804 /* Find CRC position and calculate checksum */
805 crc = tvb_get_guint8(message_tvb, ctr + 3 + b_Length );
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;
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 );
819 if ( ( crc ^ calcCrc ) == 0 )
821 /* Check if this is a Slim SSDO message */
822 if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
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 )
828 *u_frameOffset = ( ctr - 1 );
829 *u_frameLength = b_Length + 2 * crcOffset + 11;
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 )
839 found = 1;
840 break;
844 else
846 *u_frameLength = 2 * b_Length + 2 * crcOffset + 11;
847 *u_frameOffset = ( ctr - 1 );
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;
861 else
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.
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 )
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 );
882 if ( rem_length == b_Length )
884 ctr++;
885 rem_length++;
886 continue;
893 ctr++;
894 rem_length = tvb_reported_length_remaining(message_tvb, ctr);
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;
903 return (found ? 1 : 0);
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])
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;
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);
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 );
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 );
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);
934 spdo_tree = proto_item_add_subtree(item, ett_opensafety_spdo);
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);
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") );
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);
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;
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 )
959 ct = (guint16)((tvb_get_guint8(message_tvb, frameStart2 + 2) ^ scm_udid[2]) << 8) +
960 (tvb_get_guint8(message_tvb, frameStart1 + 3));
963 if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST )
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);
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);
975 else
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);
981 if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_RESPONSE )
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);
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);
992 static void dissect_ssdo_payload ( packet_info *pinfo, tvbuff_t *new_tvb, proto_tree *ssdo_payload, guint8 sacmd )
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;
1001 dataLength = tvb_length(new_tvb);
1003 ssdoIndex = tvb_get_letohs(new_tvb, 0);
1005 sodLength = tvb_get_letohl(new_tvb, 4);
1007 /* first check for extended parameter */
1008 if ( dataLength == 16 || sodLength == ( dataLength - 16 ) || ssdoIndex == 0x0101 )
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);
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 );
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 );
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 );
1027 if ( dataLength != 16 )
1029 item = proto_tree_add_item(ext_tree, hf_oss_ssdo_extpar_data, new_tvb, 16, dataLength - 16, ENC_NA );
1031 if ( ( dataLength - sodLength ) != 16 )
1032 expert_add_info ( pinfo, item, &ei_message_reassembly_size_differs_from_header );
1035 else
1037 /* If == upload, it is most likely a par upload */
1038 if ( sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END && ( dataLength % 4 == 0 ) )
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);
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);
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 )
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 );
1064 /* If != upload, it is most likely a 101A download */
1065 else
1068 /* normal parameter set */
1069 for ( ctr = 0; ctr < dataLength; ctr++ )
1071 ssdoIndex = tvb_get_letohs(new_tvb, ctr);
1072 ssdoSubIndex = tvb_get_guint8(new_tvb, ctr + 2);
1073 dispSSDOIndex = ssdoIndex;
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;
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 );
1091 if ( ssdoIndex < 0x1000 || ssdoIndex > 0xE7FF )
1092 expert_add_info ( pinfo, item, &ei_payload_unknown_format );
1094 sod_tree = proto_item_add_subtree(item, ett_opensafety_ssdo_sodentry);
1096 if ( ssdoSubIndex != 0 )
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") );
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;
1108 /* reading real size */
1109 sodLength = tvb_get_letohl ( new_tvb, ctr + 1 );
1110 if ( sodLength > (dataLength - ctr) )
1111 sodLength = 0;
1113 if ( ( sodLength + 4 + ctr ) > dataLength )
1114 break;
1116 if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x06 )
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 )
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 );
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);
1136 proto_tree_add_item(ext_tree, hf_oss_ssdo_sodmapping_bits, new_tvb, ctr + 5, 1, ENC_NA);
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);
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 );
1147 ctr += sodLength + 4;
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])
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;
1170 dataLength = tvb_get_guint8(message_tvb, OSS_FRAME_POS_LEN + frameStart1);
1171 decodePayload = FALSE;
1173 db0Offset = frameStart1 + OSS_FRAME_POS_DATA;
1174 db0 = tvb_get_guint8(message_tvb, db0Offset);
1175 sacmd = db0;
1176 ssdoIndex = 0;
1177 ssdoSubIndex = 0;
1179 if ( ( sacmd & OPENSAFETY_SSDO_SACMD_TGL ) == OPENSAFETY_SSDO_SACMD_TGL )
1180 sacmd = sacmd & ( ~OPENSAFETY_SSDO_SACMD_TGL );
1182 isResponse = ( ( OSS_FRAME_ID_T(message_tvb, frameStart1) & 0x04 ) == 0x04 );
1184 if ( validSCMUDID )
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]) ) );
1191 PACKET_SENDER_RECEIVER ( pinfo, taddr, frameStart2 + 3, OSS_FRAME_ADDR_T(message_tvb, frameStart1),
1192 frameStart1, frameStart2, sdn );
1194 else if ( ! isResponse )
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]) ) ) );
1199 else if ( isResponse )
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]) ) ) );
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);
1217 ssdo_tree = proto_item_add_subtree(item, ett_opensafety_ssdo);
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);
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") );
1230 if ( isResponse )
1232 if ( validSCMUDID )
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;
1239 else
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);
1245 else if ( ! isResponse )
1247 if ( validSCMUDID )
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;
1254 else
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);
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, " "));
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);
1273 payloadOffset = db0Offset + 1;
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));
1279 proto_tree_add_uint(ssdo_tree, hf_oss_ssdo_sano, message_tvb, frameStart1 + 3, 1, ct );
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 )
1286 ssdoIndex = tvb_get_letohs(message_tvb, db0Offset + 1);
1287 ssdoSubIndex = tvb_get_guint8(message_tvb, db0Offset + 3);
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"));
1294 /* Some SOD downloads (0x101A for instance) don't have sub-indeces */
1295 if ( ssdoSubIndex != 0x0 )
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"));
1303 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", "]" );
1304 payloadOffset += 3;
1307 if ( sacmd == OPENSAFETY_MSG_SSDO_ABORT )
1309 abortcode = tvb_get_letohl(message_tvb, frameStart1 + OSS_FRAME_POS_DATA + 4);
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"));
1317 } else {
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 ) ) )
1331 decodePayload = TRUE;
1334 if ( decodePayload )
1336 saveFragmented = pinfo->fragmented;
1337 if ( server != 0 && client != 0 )
1338 fragmentId = (guint32)((((guint32)client) << 16 ) + server );
1340 isSegmented = ( ( db0 & OPENSAFETY_SSDO_SACMD_SEG ) == OPENSAFETY_SSDO_SACMD_SEG );
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 )
1348 payloadOffset += 4;
1350 /* reading real size */
1351 payloadSize = tvb_get_letohl(message_tvb, payloadOffset - 4);
1353 calcDataLength = dataLength - (payloadOffset - db0Offset);
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);
1358 if ( fragmentId != 0 && isSegmented )
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 );
1365 if ( frag_msg != NULL )
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);
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 );
1375 if ( (gint) calcDataLength >= (gint) 0 )
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 );
1383 else
1385 isEndSegment = FALSE;
1386 if ( ( sacmd == OPENSAFETY_MSG_SSDO_DOWNLOAD_SEGMENT_END ) || ( sacmd == OPENSAFETY_MSG_SSDO_UPLOAD_SEGMENT_END ) )
1387 isEndSegment = TRUE;
1389 payloadSize = dataLength - (payloadOffset - db0Offset);
1391 if ( fragmentId != 0 && isSegmented )
1393 pinfo->fragmented = TRUE;
1395 frag_msg = fragment_add_seq_check(&os_reassembly_table, message_tvb, payloadOffset, pinfo,
1396 fragmentId, NULL,ct,
1397 payloadSize, isEndSegment ? FALSE : TRUE );
1400 if ( frag_msg )
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);
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 )
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);
1415 col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)" );
1416 dissect_ssdo_payload ( pinfo, new_tvb, ssdo_payload, sacmd );
1419 else
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);
1425 if ( ssdoIndex == OPENSAFETY_SOD_DVI && ssdoSubIndex == 0x06 )
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 )
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 );
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 );
1445 pinfo->fragmented = saveFragmented;
1450 static void
1451 dissect_opensafety_snmt_message(tvbuff_t *message_tvb, packet_info *pinfo , proto_tree *opensafety_tree,
1452 guint16 frameStart1, guint16 frameStart2 )
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;
1462 dataLength = OSS_FRAME_LENGTH_T(message_tvb, frameStart1);
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;
1471 db0 = -1;
1472 if (dataLength > 0)
1473 db0 = tvb_get_guint8(message_tvb, frameStart1 + OSS_FRAME_POS_DATA);
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 ) )
1478 PACKET_RECEIVER( pinfo, addr, OSS_FRAME_POS_ADDR + frameStart1, frameStart2, sdn );
1480 else
1482 PACKET_SENDER_RECEIVER ( pinfo, taddr, OSS_FRAME_POS_ADDR + frameStart1, addr, frameStart2 + 3,
1483 frameStart2, sdn );
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);
1491 snmt_tree = proto_item_add_subtree(item, ett_opensafety_snmt);
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);
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") );
1504 if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SN_RESET_GUARDING_SCM) == 0 )
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);
1509 else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SERVICE_RESPONSE) == 0 )
1511 byte = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1);
1513 if ( ! ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 && byte == OPENSAFETY_ERROR_GROUP_ADD_PARAMETER ) )
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"));
1518 else
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"));
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);
1528 if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_FAIL) == 0 )
1530 /* Handle a normal SN Fail */
1531 if ( byte != OPENSAFETY_ERROR_GROUP_ADD_PARAMETER )
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]" ) ) );
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 );
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" )
1545 else
1547 errcode = tvb_get_guint8(message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 2);
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 );
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 ) );
1557 else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_UDID_SCM) == 0 )
1559 item = proto_tree_add_item(snmt_tree, hf_oss_snmt_udid, message_tvb, OSS_FRAME_POS_DATA + frameStart1 + 1, 6, ENC_NA);
1561 if ( global_scm_udid_autoset == TRUE )
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 )
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);
1574 else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGNED_ADDITIONAL_SADR) == 0 )
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));
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));
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));
1587 else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SERVICE_REQUEST) == 0 )
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"));
1592 if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_STOP) == 0 || (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SCM_SET_TO_OP) == 0 )
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);
1597 else if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_ASSIGN_UDID_SCM) == 0 )
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);
1603 if ( global_scm_udid_autoset == TRUE )
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 )
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);
1616 else
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);
1621 if ( (db0 ^ OPENSAFETY_MSG_SNMT_EXT_SN_SET_TO_OP) == 0 )
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 );
1627 else if ( ( db0 ^ OPENSAFETY_MSG_SNMT_EXT_ASSIGN_ADDITIONAL_SADR) == 0 )
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));
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));
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));
1642 else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_SADR_ASSIGNED) == 0 )
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);
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);
1650 else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_ASSIGN_SADR) == 0 )
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);
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);
1659 else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_RESPONSE_UDID) == 0 )
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);
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);
1668 else if ( (OSS_FRAME_ID_T(message_tvb, frameStart1) ^ OPENSAFETY_MSG_SNMT_REQUEST_UDID) == 0 )
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);
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 )
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;
1690 dataLength = OSS_FRAME_LENGTH_T(message_tvb, frameStart1);
1691 start = OSS_FRAME_POS_DATA + dataLength + frameStart1;
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);
1698 if ( type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
1699 isSlim = TRUE;
1701 frame2Length = (isSlim ? 0 : dataLength) + 5;
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);
1707 checksum_tree = proto_item_add_subtree(item, ett_opensafety_checksum);
1709 bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, frameStart1, dataLength + 4);
1710 if ( dataLength > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
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 )
1717 calc1_crc = crc16_0x5935(bytes, dataLength + 4, 0);
1718 if ( frame1_crc == calc1_crc )
1720 crcType = OPENSAFETY_CHECKSUM_CRC16SLIM;
1721 if ( ! isSlim )
1722 expert_add_info(pinfo, item, &ei_crc_slimssdo_instead_of_spdo );
1726 else
1727 calc1_crc = crc8_0x2F(bytes, dataLength + 4, 0);
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 );
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);
1741 /* 0xFFFF is an invalid CRC16 value, therefore valid for initialization */
1742 calc2_crc = 0xFFFF;
1744 if ( global_calculate_crc2 )
1746 bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, frameStart2, frame2Length + length);
1748 /* SLIM SSDO messages, do not contain a payload in frame2 */
1749 if ( isSlim == TRUE )
1750 dataLength = 0;
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 )
1755 if ( type != OPENSAFETY_SNMT_MESSAGE_TYPE )
1757 for ( ctr = 0; ctr < 6; ctr++ )
1758 bytes[ctr] = bytes[ctr] ^ (guint8)(scmUDID->data[ctr]);
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.
1765 if ( dataLength == 0 )
1766 frame2_crc = ( ( isSlim && length == 2 ) ? ( ( bytes[6] << 8 ) + bytes[5] ) : bytes[5] );
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);
1772 checksum_tree = proto_item_add_subtree(item, ett_opensafety_checksum);
1774 if ( OSS_FRAME_LENGTH_T(message_tvb, frameStart1) > OSS_PAYLOAD_MAXSIZE_FOR_CRC8 )
1776 calc2_crc = crc16_0x755B(bytes, frame2Length, 0);
1777 if ( frame2_crc != calc2_crc )
1778 calc2_crc = crc16_0x5935(bytes, frame2Length, 0);
1780 else
1781 calc2_crc = crc8_0x2F(bytes, frame2Length, 0);
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);
1787 if ( frame2_crc != calc2_crc )
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 );
1795 else
1796 expert_add_info(pinfo, item, &ei_crc_frame_2_unknown_scm_udid );
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);
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)
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;
1817 messageTypeUnknown = FALSE;
1819 for ( ctr = 0; ctr < 6; ctr++ )
1820 scm_udid[ctr] = 0;
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;
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) "));
1831 if ( type == OPENSAFETY_SNMT_MESSAGE_TYPE )
1833 dissect_opensafety_snmt_message ( message_tvb, pinfo, opensafety_tree, frameStart1, frameStart2 );
1835 else
1837 validSCMUDID = FALSE;
1838 scmUDID = g_byte_array_new();
1840 if ( hex_str_to_bytes((local_scm_udid != NULL ? local_scm_udid : global_scm_udid), scmUDID, TRUE) && scmUDID->len == 6 )
1842 validSCMUDID = TRUE;
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]);
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];
1854 if ( strlen ( (local_scm_udid != NULL ? local_scm_udid : global_scm_udid) ) > 0 && scmUDID->len == 6 )
1856 if ( local_scm_udid != NULL )
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 );
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);
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);
1872 g_byte_array_free( scmUDID, TRUE);
1874 if ( type == OPENSAFETY_SSDO_MESSAGE_TYPE || type == OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE )
1876 dissect_opensafety_ssdo_message ( message_tvb, pinfo, opensafety_tree, frameStart1, frameStart2, validSCMUDID, scm_udid );
1878 else if ( type == OPENSAFETY_SPDO_MESSAGE_TYPE )
1880 dissect_opensafety_spdo_message ( message_tvb, pinfo, opensafety_tree, frameStart1, frameStart2, validSCMUDID, scm_udid );
1882 else
1884 messageTypeUnknown = TRUE;
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 )
1893 expert_add_info(pinfo, item, &ei_message_unknown_type );
1895 else
1897 crcValid = dissect_opensafety_checksum ( message_tvb, pinfo, opensafety_tree, type, frameStart1, frameStart2 );
1900 if ( ! crcValid )
1902 expert_add_info(pinfo, opensafety_item, &ei_crc_frame_1_invalid );
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 )
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 );
1915 return TRUE;
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 )
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;
1934 handled = FALSE;
1935 dissectorCalled = FALSE;
1936 call_sub_dissector = FALSE;
1937 markAsMalformed = FALSE;
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);
1943 length = tvb_reported_length(given_tvb);
1944 /* Minimum package length is 11 */
1945 if ( length < OSS_MINIMUM_LENGTH )
1946 return FALSE;
1948 if ( strlen( sub_diss_handle ) > 0 )
1950 call_sub_dissector = TRUE;
1951 protocol_dissector = find_dissector ( sub_diss_handle );
1952 if ( protocol_dissector == NULL )
1953 protocol_dissector = find_dissector ( "data" );
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);
1960 if ( do_byte_swap == TRUE && global_mbtcp_big_endian == TRUE )
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++ )
1967 tempByte = bytes [ 2 * i ]; bytes [ 2 * i ] = bytes [ 2 * i + 1 ]; bytes [ 2 * i + 1 ] = tempByte;
1970 message_tvb = tvb_new_real_data(bytes, length, reported_len);
1971 } else {
1972 message_tvb = given_tvb;
1975 frameOffset = 0;
1976 frameLength = 0;
1977 found = 0;
1978 packageCounter = 0;
1980 while ( frameOffset < length )
1982 /* Smallest possible frame size is 11 */
1983 if ( tvb_length_remaining(message_tvb, frameOffset ) < OSS_MINIMUM_LENGTH )
1984 break;
1986 /* Finding the start of the first possible safety frame */
1987 if ( findSafetyFrame(message_tvb, frameOffset, b_frame2First, &frameOffset, &frameLength) )
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;
1994 found++;
1996 byte_offset = ( b_frame2First ? 0 : frameOffset );
1997 /* We determine a possible position for frame 1 and frame 2 */
1998 if ( b_frame2First )
2000 frameStart1 = findFrame1Position (message_tvb, byte_offset, frameLength, FALSE );
2001 frameStart2 = 0;
2003 else
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));
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)
2014 found--;
2015 frameOffset += frameLength ;
2016 continue;
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
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 )
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;
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;
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;
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 )
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 )
2078 frameOffset += 2;
2079 found--;
2080 continue;
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)) )
2086 frameOffset += 2;
2087 found--;
2088 continue;
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 )
2096 nodeAddress = OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1);
2097 if ( nodeAddress > 1024 ) {
2098 markAsMalformed = TRUE;
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.
2106 if ( ( (gint)frameLength - (gint)( frameStart2 > frameStart1 ? frameStart2 : frameLength - frameStart1 ) ) < 0 )
2107 return FALSE;
2109 /* From here on, the package should be correct, therefore adding second frame */
2110 if ( do_byte_swap == TRUE && global_mbtcp_big_endian == TRUE )
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)");
2116 else
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");
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 )
2126 found = force_nr_in_package + 1;
2127 dissectorCalled = TRUE;
2128 col_set_str(pinfo->cinfo, COL_PROTOCOL, protocolName);
2131 if ( ! dissectorCalled )
2133 if ( call_sub_dissector )
2134 call_dissector(protocol_dissector, message_tvb, pinfo, tree);
2135 dissectorCalled = TRUE;
2137 col_set_str(pinfo->cinfo, COL_PROTOCOL, protocolName);
2138 col_clear(pinfo->cinfo,COL_INFO);
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 )
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;
2153 if ( dissect_opensafety_message(frameStart1, frameStart2, type, next_tvb, pinfo, opensafety_item, opensafety_tree, found) == TRUE )
2154 packageCounter++;
2155 else
2156 markAsMalformed = TRUE;
2158 if ( tree && markAsMalformed )
2160 if ( OSS_FRAME_ADDR_T(message_tvb, byte_offset + frameStart1) > 1024 )
2161 expert_add_info(pinfo, opensafety_item, &ei_message_spdo_address_invalid );
2163 handled = TRUE;
2165 else
2166 break;
2168 frameOffset += frameLength;
2171 if ( handled == TRUE && packageCounter == 0 )
2172 handled = FALSE;
2174 if ( ! handled )
2176 if ( call_sub_dissector )
2177 call_dissector(protocol_dissector, message_tvb, pinfo, tree);
2178 handled = TRUE;
2181 return ( handled ? TRUE : FALSE );
2184 static gboolean
2185 dissect_opensafety_epl(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2187 gboolean result = FALSE;
2188 guint8 firstByte;
2190 if ( ! global_enable_plk )
2191 return result;
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 )
2198 bDissector_Called_Once_Before = TRUE;
2200 firstByte = ( tvb_get_guint8(message_tvb, 0) << 1 );
2202 /* No frames can be sent in SoA and SoC messages, therefore those get filtered right away */
2203 if ( ( firstByte != 0x02 ) && ( firstByte != 0x0A ) )
2205 result = opensafety_package_dissector("openSAFETY/Powerlink", "epl",
2206 FALSE, FALSE, 0, message_tvb, pinfo, tree);
2209 bDissector_Called_Once_Before = FALSE;
2212 return result;
2216 static gboolean
2217 dissect_opensafety_siii(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2219 gboolean result = FALSE;
2220 guint8 firstByte;
2222 if ( ! global_enable_siii )
2223 return result;
2225 if ( pinfo->ipproto == IPPROTO_UDP )
2227 return opensafety_package_dissector("openSAFETY/SercosIII UDP", "", FALSE, FALSE, 0, message_tvb, pinfo, tree);
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 */
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 )
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 )
2243 result = opensafety_package_dissector("openSAFETY/SercosIII", "sercosiii",
2244 FALSE, FALSE, 0, message_tvb, pinfo, tree);
2246 bDissector_Called_Once_Before = FALSE;
2249 return result;
2252 static gboolean
2253 dissect_opensafety_pn_io(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2255 gboolean result = FALSE;
2257 if ( ! global_enable_pnio )
2258 return result;
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 )
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;
2271 return result;
2274 static gboolean
2275 dissect_opensafety_mbtcp(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree, void *data _U_ )
2277 if ( ! global_enable_mbtcp )
2278 return FALSE;
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 ));
2287 static gboolean
2288 dissect_opensafety_udpdata(tvbuff_t *message_tvb , packet_info *pinfo , proto_tree *tree , void *data _U_ )
2290 gboolean result = FALSE;
2291 static guint32 frameNum = 0;
2292 static guint32 frameIdx = 0;
2294 if ( ! global_enable_udp )
2295 return result;
2297 /* An openSAFETY frame has at least OSS_MINIMUM_LENGTH bytes */
2298 if ( tvb_length ( message_tvb ) < OSS_MINIMUM_LENGTH )
2299 return result;
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 )
2305 frameIdx = 0;
2306 frameNum = pinfo->fd->num;
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);
2313 if ( result )
2314 frameIdx++;
2316 return result;
2319 static void
2320 apply_prefs ( void )
2322 static gboolean opensafety_init = FALSE;
2323 static guint opensafety_udp_port_number;
2324 static guint opensafety_udp_siii_port_number;
2326 /* It only should delete dissectors, if run for any time except the first */
2327 if ( opensafety_init )
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"));
2334 opensafety_init = TRUE;
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;
2340 /* Default UDP only based dissector */
2341 dissector_add_uint("udp.port", opensafety_udp_port_number, find_dissector("opensafety_udpdata"));
2343 /* Sercos III dissector does not handle UDP transport, has to be handled
2344 * separately, everything else should be caught by the heuristic dissector
2346 dissector_add_uint("udp.port", opensafety_udp_siii_port_number, find_dissector("opensafety_siii"));
2350 void
2351 proto_register_opensafety(void)
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 } },
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 } },
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 } },
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 } },
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 } },
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 } },
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 } },
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 } },
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 } },
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 } },
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 } },
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,
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 } },
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 } },
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 } },
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 } },
2674 module_t *opensafety_module;
2675 expert_module_t *expert_opensafety;
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);
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));
2685 expert_opensafety = expert_register_protocol ( proto_opensafety );
2686 expert_register_field_array ( expert_opensafety, ei, array_length (ei ) );
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);
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);
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);
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);
2749 void
2750 proto_reg_handoff_opensafety(void)
2752 static int opensafety_inited = FALSE;
2754 if ( !opensafety_inited )
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);
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);
2765 /* Modbus TCP dissector registration */
2766 dissector_add_string("modbus.data", "data", find_dissector("opensafety_mbtcp"));
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
2772 if ( find_dissector("pn_io") != NULL )
2774 heur_dissector_add("pn_io", dissect_opensafety_pn_io, proto_opensafety);
2776 else
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.
2782 dissector_add_uint("ethertype", ETHERTYPE_PROFINET, find_dissector("opensafety_pnio"));
2785 register_init_routine ( setup_dissector );
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); */
2795 * Editor modelines - http://www.wireshark.org/tools/modelines.html
2797 * Local variables:
2798 * c-basic-offset: 8
2799 * tab-width: 8
2800 * indent-tabs-mode: t
2801 * End:
2803 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2804 * :indentSize=8:tabSize=8:noTabs=false: