2 * Routines for EtherCAT Switch Link disassembly
4 * Copyright (c) 2007 by Beckhoff Automation GmbH
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1999 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
18 #include <wsutil/array.h>
20 void proto_register_esl(void);
23 /* XXX: using bitfields is compiler dependent: See README.developer */
25 typedef union _EslFlagsUnion
37 uint16_t extended
: 1;
40 uint16_t alignError
: 1;
41 uint16_t crcError
: 1;
42 uint16_t timeStampEna
: 1;
49 uint8_t flagsHiPorts
: 1;
55 #define esl_port7_bitmask 0x0001
56 #define esl_port6_bitmask 0x0002
57 #define esl_port5_bitmask 0x0004
58 #define esl_port4_bitmask 0x0008
59 #define esl_port3_bitmask 0x0010
60 #define esl_port2_bitmask 0x0020
61 #define esl_port1_bitmask 0x0040
62 #define esl_port0_bitmask 0x0080
63 #define esl_extended_bitmask 0x0100
64 #define esl_port11_bitmask 0x0200
65 #define esl_port10_bitmask 0x0400
66 #define esl_alignError_bitmask 0x0800
67 #define esl_crcError_bitmask 0x1000
68 #define esl_timeStampEna_bitmask 0x2000
69 #define esl_port9_bitmask 0x4000
70 #define esl_port8_bitmask 0x8000
73 typedef struct _EslHeader
75 uint8_t eslCookie
[6]; /* 01 01 05 10 00 00 */
78 } EslHeader
, *PEslHeader
;
82 #define SIZEOF_ESLHEADER 16
84 static dissector_handle_t eth_withoutfcs_handle
;
86 void proto_reg_handoff_esl(void);
88 /* Define the esl proto */
93 static int hf_esl_timestamp
;
94 static int hf_esl_port
;
95 static int hf_esl_crcerror
;
96 static int hf_esl_alignerror
;
98 /* Note: using external tfs strings apparently doesn't work in a plugin */
99 static const true_false_string flags_yes_no
= {
105 /* XXX: using bitfields is compiler dependent: See README.developer */
106 static uint16_t flags_to_port(uint16_t flagsValue
) {
107 EslFlagsUnion flagsUnion
;
108 flagsUnion
.flags
= flagsValue
;
109 if ( flagsUnion
.d
.port0
)
111 else if ( flagsUnion
.d
.port1
)
113 else if ( flagsUnion
.d
.port2
)
115 else if ( flagsUnion
.d
.port3
)
117 else if ( flagsUnion
.d
.port4
)
119 else if ( flagsUnion
.d
.port5
)
121 else if ( flagsUnion
.d
.port6
)
123 else if ( flagsUnion
.d
.port7
)
125 else if ( flagsUnion
.d
.port8
)
127 else if ( flagsUnion
.d
.port9
)
134 static uint16_t flags_to_port(uint16_t flagsValue
) {
135 if ( (flagsValue
& esl_port0_bitmask
) != 0 )
137 else if ( (flagsValue
& esl_port1_bitmask
) != 0 )
139 else if ( (flagsValue
& esl_port2_bitmask
) != 0 )
141 else if ( (flagsValue
& esl_port3_bitmask
) != 0 )
143 else if ( (flagsValue
& esl_port4_bitmask
) != 0 )
145 else if ( (flagsValue
& esl_port5_bitmask
) != 0 )
147 else if ( (flagsValue
& esl_port6_bitmask
) != 0 )
149 else if ( (flagsValue
& esl_port7_bitmask
) != 0 )
151 else if ( (flagsValue
& esl_port8_bitmask
) != 0 )
153 else if ( (flagsValue
& esl_port9_bitmask
) != 0 )
155 else if ( (flagsValue
& esl_port10_bitmask
) != 0 )
157 else if ( (flagsValue
& esl_port11_bitmask
) != 0 )
165 dissect_esl_header(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void* data _U_
) {
167 proto_item
*ti
= NULL
;
168 proto_tree
*esl_header_tree
;
171 unsigned esl_length
= tvb_reported_length(tvb
);
172 if ( esl_length
>= SIZEOF_ESLHEADER
)
178 ti
= proto_tree_add_item(tree
, proto_esl
, tvb
, 0, SIZEOF_ESLHEADER
, ENC_NA
);
179 esl_header_tree
= proto_item_add_subtree(ti
, ett_esl
);
182 flags
= tvb_get_letohs(tvb
, offset
);
183 proto_tree_add_uint(esl_header_tree
, hf_esl_port
, tvb
, offset
, 2, flags_to_port(flags
));
185 proto_tree_add_item(esl_header_tree
, hf_esl_alignerror
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
186 proto_tree_add_item(esl_header_tree
, hf_esl_crcerror
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
190 proto_tree_add_item(esl_header_tree
, hf_esl_timestamp
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
193 return tvb_captured_length(tvb
);
196 typedef struct _ref_time_frame_info
202 } ref_time_frame_info
;
204 static ref_time_frame_info ref_time_frame
;
206 static bool is_esl_header(tvbuff_t
*tvb
, int offset
)
208 return tvb_get_uint8(tvb
, offset
) == 0x01 &&
209 tvb_get_uint8(tvb
, offset
+1) == 0x01 &&
210 tvb_get_uint8(tvb
, offset
+2) == 0x05 &&
211 (tvb_get_uint8(tvb
, offset
+3) == 0x10 ||tvb_get_uint8(tvb
, offset
+3) == 0x11)&&
212 tvb_get_uint8(tvb
, offset
+4) == 0x00 &&
213 tvb_get_uint8(tvb
, offset
+5) == 0x00;
216 static void modify_times(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
)
218 if ( ref_time_frame
.fd
== NULL
)
220 ref_time_frame
.esl_ts
= tvb_get_letoh64(tvb
, offset
+8);
221 ref_time_frame
.fd
= pinfo
->fd
;
222 ref_time_frame
.num
= pinfo
->num
;
223 ref_time_frame
.abs_ts
= pinfo
->abs_ts
;
225 else if ( !pinfo
->fd
->visited
)
227 uint64_t nsecs
= tvb_get_letoh64(tvb
, offset
+8) - ref_time_frame
.esl_ts
;
228 uint64_t secs
= nsecs
/1000000000;
232 ts
.nsecs
= ref_time_frame
.abs_ts
.nsecs
+ (int)(nsecs
-(secs
*1000000000));
233 if ( ts
.nsecs
> 1000000000 )
235 ts
.nsecs
-=1000000000;
239 ts
.secs
= ref_time_frame
.abs_ts
.secs
+(int)secs
;
240 nstime_delta(&ts_delta
, &ts
, &pinfo
->abs_ts
);
243 pinfo
->fd
->abs_ts
= ts
;
244 nstime_add(&pinfo
->rel_ts
, &ts_delta
);
249 dissect_esl_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
251 static bool in_heur
= false;
254 unsigned esl_length
= tvb_captured_length(tvb
);
262 if ( ref_time_frame
.fd
!= NULL
&& !pinfo
->fd
->visited
&& pinfo
->num
<= ref_time_frame
.num
)
263 ref_time_frame
.fd
= NULL
;
265 /* Check that there's enough data */
266 if ( esl_length
< SIZEOF_ESLHEADER
)
269 /* check for Esl frame, this has a unique destination MAC from Beckhoff range
270 First 6 bytes must be: 01 01 05 10 00 00 */
271 if ( is_esl_header(tvb
, 0) )
273 dissect_esl_header(tvb
, pinfo
, tree
, data
);
274 if ( eth_withoutfcs_handle
!= NULL
)
276 next_tvb
= tvb_new_subset_remaining(tvb
, SIZEOF_ESLHEADER
);
277 call_dissector(eth_withoutfcs_handle
, next_tvb
, pinfo
, tree
);
279 modify_times(tvb
, 0, pinfo
);
282 else if ( is_esl_header(tvb
, esl_length
-SIZEOF_ESLHEADER
) )
284 if ( eth_withoutfcs_handle
!= NULL
)
286 next_tvb
= tvb_new_subset_length(tvb
, 0, esl_length
-SIZEOF_ESLHEADER
);
287 call_dissector(eth_withoutfcs_handle
, next_tvb
, pinfo
, tree
);
289 next_tvb
= tvb_new_subset_length(tvb
, esl_length
-SIZEOF_ESLHEADER
, SIZEOF_ESLHEADER
);
290 dissect_esl_header(next_tvb
, pinfo
, tree
, data
);
291 modify_times(tvb
, esl_length
-SIZEOF_ESLHEADER
, pinfo
);
309 proto_register_esl(void) {
310 static hf_register_info hf
[] = {
312 { "Port", "esl.port",
313 FT_UINT16
, BASE_DEC
, NULL
, 0x00,
317 { "Crc Error", "esl.crcerror",
318 FT_BOOLEAN
, 16, TFS(&flags_yes_no
), esl_crcError_bitmask
,
321 { &hf_esl_alignerror
,
322 { "Alignment Error", "esl.alignerror",
323 FT_BOOLEAN
, 16, TFS(&flags_yes_no
), esl_alignError_bitmask
,
327 { "timestamp", "esl.timestamp",
328 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
333 static int *ett
[] = {
337 module_t
*esl_module
;
339 proto_esl
= proto_register_protocol("EtherCAT Switch Link",
342 esl_module
= prefs_register_protocol_obsolete(proto_esl
);
344 prefs_register_obsolete_preference(esl_module
, "enable");
346 proto_register_field_array(proto_esl
,hf
,array_length(hf
));
347 proto_register_subtree_array(ett
,array_length(ett
));
349 register_dissector("esl", dissect_esl_header
, proto_esl
);
353 proto_reg_handoff_esl(void) {
354 static bool initialized
= false;
357 eth_withoutfcs_handle
= find_dissector_add_dependency("eth_withoutfcs", proto_esl
);
358 heur_dissector_add("eth", dissect_esl_heur
, "EtherCAT over Ethernet", "esl_eth", proto_esl
, HEURISTIC_DISABLE
);
364 * Editor modelines - https://www.wireshark.org/tools/modelines.html
369 * indent-tabs-mode: nil
372 * vi: set shiftwidth=4 tabstop=8 expandtab:
373 * :indentSize=4:tabSize=8:noTabs=true: