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.
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>
62 /* General definitions */
64 /* openSAFETY UDP Port */
65 #ifndef UDP_PORT_OPENSAFETY
66 #define UDP_PORT_OPENSAFETY 9877
69 /* SercosIII UDP Port */
71 #define UDP_PORT_SIII 8755
74 #define OPENSAFETY_DEFAULT_DOMAIN 0x1
76 /* Under linux, this get's defined in netinet/in.h */
78 #define IPPROTO_UDP 0x11
81 #ifndef OPENSAFETY_PINFO_CONST_DATA
82 #define OPENSAFETY_PINFO_CONST_DATA 0xAABBCCDD
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" },
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" },
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" },
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" },
187 /* Values 6-255 are reserved for future use. They will be presented as "Reserved [%d]"
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" },
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
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
225 static const value_string ssdo_sacmd_values
[] = {
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" },
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" },
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" };
258 static const true_false_string opensafety_sacmd_res
= { "Reserved", "Reserved" };
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" },
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" },
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 */
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
,
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 */
611 reset_dissector(void)
613 bDissector_Called_Once_Before
= FALSE
;
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); \
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); \
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); \
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
);
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);
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
)
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
;
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 */
771 b_ID
= tvb_get_guint8(message_tvb
, ctr
);
775 b_Length
= tvb_get_guint8(message_tvb
, ctr
+ 1 );
777 /* 0xFF is often used, but always false, otherwise start detection, if the highest
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
);
812 calcCrc
= crc16_0x755B( bytes
, b_Length
+ 4, 0 );
813 if ( ( crc
^ calcCrc
) != 0 )
814 calcCrc
= crc16_0x5935( bytes
, b_Length
+ 4, 0 );
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 */
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
);
836 f2crc
= tvb_get_letohs ( message_tvb
, ctr
+ 3 + 5 + b_Length
);
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. */
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
);
880 b_Length
= ( 11 + ( b_Length
> 8 ? 2 : 0 ) + 2 * b_Length
);
882 if ( rem_length
== b_Length
)
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);
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])
911 proto_tree
*spdo_tree
;
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);
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
);
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;
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
);
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 */
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") );
1104 proto_tree_add_uint_format_value(sod_tree
, hf_oss_ssdo_sod_subindex
, new_tvb
, ctr
+ 2, 1,
1105 ssdoSubIndex
, "0x%02X",ssdoSubIndex
);
1108 /* reading real size */
1109 sodLength
= tvb_get_letohl ( new_tvb
, ctr
+ 1 );
1110 if ( sodLength
> (dataLength
- ctr
) )
1113 if ( ( sodLength
+ 4 + ctr
) > dataLength
)
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
);
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;
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])
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
;
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
);
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 );
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") );
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
);
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") );
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
);
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
)
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
);
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);
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", "]" );
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"));
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
)
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
);
1379 expert_add_info_format(pinfo
, item
, &ei_payload_length_not_positive
,
1380 "Calculation for payload length yielded non-positive result [%d]", (guint
) calcDataLength
);
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
);
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
);
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
);
1441 proto_tree_add_item(ssdo_tree
, hf_oss_ssdo_payload
, message_tvb
, payloadOffset
, payloadSize
, ENC_NA
);
1445 pinfo
->fragmented
= saveFragmented
;
1451 dissect_opensafety_snmt_message(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*opensafety_tree
,
1452 guint16 frameStart1
, guint16 frameStart2
)
1455 proto_tree
*snmt_tree
;
1457 guint16 addr
, taddr
, sdn
;
1458 guint8 db0
, byte
, errcode
;
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
;
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
);
1482 PACKET_SENDER_RECEIVER ( pinfo
, taddr
, OSS_FRAME_POS_ADDR
+ frameStart1
, addr
, frameStart2
+ 3,
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
);
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"));
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" )
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
);
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
);
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
);
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
);
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
);
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
;
1684 proto_tree
*checksum_tree
;
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
);
1696 frame1_crc
= tvb_get_guint8(message_tvb
, start
);
1698 if ( type
== OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE
)
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
;
1722 expert_add_info(pinfo
, item
, &ei_crc_slimssdo_instead_of_spdo
);
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
);
1739 frame2_crc
= tvb_get_guint8(message_tvb
, start
);
1741 /* 0xFFFF is an invalid CRC16 value, therefore valid for initialization */
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
)
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);
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
);
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
);
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
)
1812 GByteArray
*scmUDID
= NULL
;
1813 gboolean validSCMUDID
;
1815 gboolean messageTypeUnknown
, crcValid
;
1817 messageTypeUnknown
= FALSE
;
1819 for ( ctr
= 0; ctr
< 6; ctr
++ )
1822 b_ID
= OSS_FRAME_ID_T(message_tvb
, frameStart1
);
1823 /* Clearing connection valid bit */
1824 if ( type
== OPENSAFETY_SPDO_MESSAGE_TYPE
)
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
);
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
;
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
);
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
);
1884 messageTypeUnknown
= TRUE
;
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
);
1897 crcValid
= dissect_opensafety_checksum ( message_tvb
, pinfo
, opensafety_tree
, type
, frameStart1
, frameStart2
);
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
);
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
;
1926 gboolean handled
, dissectorCalled
, call_sub_dissector
, markAsMalformed
;
1927 guint8 type
, found
, packageCounter
, i
, tempByte
;
1928 guint16 frameStart1
, frameStart2
, byte_offset
;
1930 dissector_handle_t protocol_dissector
= NULL
;
1931 proto_item
*opensafety_item
;
1932 proto_tree
*opensafety_tree
;
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
)
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 */
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
);
1972 message_tvb
= given_tvb
;
1980 while ( frameOffset
< length
)
1982 /* Smallest possible frame size is 11 */
1983 if ( tvb_length_remaining(message_tvb
, frameOffset
) < OSS_MINIMUM_LENGTH
)
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
)
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
);
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
)
2015 frameOffset
+= frameLength
;
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
;
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
);
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
;
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
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
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? */
2074 try_val_to_str_idx(OSS_FRAME_ID_T(message_tvb
, byte_offset
+ frameStart1
), message_type_values
, &idx
);
2075 /* Unknown Frame Type */
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
)) )
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 )
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)");
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 */
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
);
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
)
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
);
2168 frameOffset
+= frameLength
;
2171 if ( handled
== TRUE
&& packageCounter
== 0 )
2176 if ( call_sub_dissector
)
2177 call_dissector(protocol_dissector
, message_tvb
, pinfo
, tree
);
2181 return ( handled
? TRUE
: FALSE
);
2185 dissect_opensafety_epl(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2187 gboolean result
= FALSE
;
2190 if ( ! global_enable_plk
)
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
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
;
2217 dissect_opensafety_siii(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2219 gboolean result
= FALSE
;
2222 if ( ! global_enable_siii
)
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
;
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
)
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
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
;
2275 dissect_opensafety_mbtcp(tvbuff_t
*message_tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2277 if ( ! global_enable_mbtcp
)
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
));
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
)
2297 /* An openSAFETY frame has at least OSS_MINIMUM_LENGTH bytes */
2298 if ( tvb_length ( message_tvb
) < OSS_MINIMUM_LENGTH
)
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
)
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
);
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"));
2351 proto_register_opensafety(void)
2353 /* Setup list of header fields */
2354 static hf_register_info hf
[] = {
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
} },
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
} },
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
} },
2387 { "Length", "opensafety.length",
2388 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
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
} },
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
} },
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
} },
2509 {"Message fragments", "opensafety.ssdo.fragments",
2510 FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
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
} },
2544 { &hf_oss_ssdo_inhibit_time
,
2545 { "Inhibit Time", "opensafety.ssdo.inhibittime",
2546 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
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
} },
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
} },
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
[] = {
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",
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
);
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
);
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
2800 * indent-tabs-mode: t
2803 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2804 * :indentSize=8:tabSize=8:noTabs=false: