2 * Routines for EtherCAT Switch Link disassembly
6 * Copyright (c) 2007 by Beckhoff Automation GmbH
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1999 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
35 /* XXX: using bitfields is compiler dependent: See README.developer */
37 typedef union _EslFlagsUnion
53 guint16 alignError
: 1;
54 guint16 timeStampEna
: 1;
61 guint8 flagsHiPorts
: 1;
67 #define esl_port7_bitmask 0x0001
68 #define esl_port6_bitmask 0x0002
69 #define esl_port5_bitmask 0x0004
70 #define esl_port4_bitmask 0x0008
71 #define esl_port3_bitmask 0x0010
72 #define esl_port2_bitmask 0x0020
73 #define esl_port1_bitmask 0x0040
74 #define esl_port0_bitmask 0x0080
75 #define esl_extended_bitmask 0x0100
76 #define esl_port11_bitmask 0x0200
77 #define esl_port10_bitmask 0x0400
78 #define esl_crcError_bitmask 0x0800
79 #define esl_alignError_bitmask 0x1000
80 #define esl_timeStampEna_bitmask 0x2000
81 #define esl_port9_bitmask 0x4000
82 #define esl_port8_bitmask 0x8000
85 typedef struct _EslHeader
87 guint8 eslCookie
[6]; /* 01 01 05 10 00 00 */
90 } EslHeader
, *PEslHeader
;
94 #define SIZEOF_ESLHEADER 16
96 static dissector_handle_t eth_withoutfcs_handle
;
97 static int esl_enable_dissector
= FALSE
;
99 void proto_reg_handoff_esl(void);
101 /* Define the esl proto */
104 static int ett_esl
= -1;
106 static int hf_esl_timestamp
= -1;
107 static int hf_esl_port
= -1;
108 static int hf_esl_crcerror
= -1;
109 static int hf_esl_alignerror
= -1;
111 /* Note: using external tfs strings apparently doesn't work in a plugin */
112 static const true_false_string flags_yes_no
= {
118 /* XXX: using bitfields is compiler dependent: See README.developer */
119 static guint16
flags_to_port(guint16 flagsValue
) {
120 EslFlagsUnion flagsUnion
;
121 flagsUnion
.flags
= flagsValue
;
122 if ( flagsUnion
.d
.port0
)
124 else if ( flagsUnion
.d
.port1
)
126 else if ( flagsUnion
.d
.port2
)
128 else if ( flagsUnion
.d
.port3
)
130 else if ( flagsUnion
.d
.port4
)
132 else if ( flagsUnion
.d
.port5
)
134 else if ( flagsUnion
.d
.port6
)
136 else if ( flagsUnion
.d
.port7
)
138 else if ( flagsUnion
.d
.port8
)
140 else if ( flagsUnion
.d
.port9
)
147 static guint16
flags_to_port(guint16 flagsValue
) {
148 if ( (flagsValue
& esl_port0_bitmask
) != 0 )
150 else if ( (flagsValue
& esl_port1_bitmask
) != 0 )
152 else if ( (flagsValue
& esl_port2_bitmask
) != 0 )
154 else if ( (flagsValue
& esl_port3_bitmask
) != 0 )
156 else if ( (flagsValue
& esl_port4_bitmask
) != 0 )
158 else if ( (flagsValue
& esl_port5_bitmask
) != 0 )
160 else if ( (flagsValue
& esl_port6_bitmask
) != 0 )
162 else if ( (flagsValue
& esl_port7_bitmask
) != 0 )
164 else if ( (flagsValue
& esl_port8_bitmask
) != 0 )
166 else if ( (flagsValue
& esl_port9_bitmask
) != 0 )
168 else if ( (flagsValue
& esl_port10_bitmask
) != 0 )
170 else if ( (flagsValue
& esl_port11_bitmask
) != 0 )
178 dissect_esl_header(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
) {
180 proto_item
*ti
= NULL
;
181 proto_tree
*esl_header_tree
;
184 guint esl_length
= tvb_reported_length(tvb
);
185 if ( esl_length
>= SIZEOF_ESLHEADER
)
191 ti
= proto_tree_add_item(tree
, proto_esl
, tvb
, 0, SIZEOF_ESLHEADER
, ENC_NA
);
192 esl_header_tree
= proto_item_add_subtree(ti
, ett_esl
);
195 flags
= tvb_get_letohs(tvb
, offset
);
196 proto_tree_add_uint(esl_header_tree
, hf_esl_port
, tvb
, offset
, 2, flags_to_port(flags
));
198 proto_tree_add_item(esl_header_tree
, hf_esl_crcerror
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
199 proto_tree_add_item(esl_header_tree
, hf_esl_alignerror
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
202 proto_tree_add_item(esl_header_tree
, hf_esl_timestamp
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
207 typedef struct _ref_time_frame_info
213 } ref_time_frame_info
;
215 static ref_time_frame_info ref_time_frame
;
217 gboolean
is_esl_header(tvbuff_t
*tvb
, gint offset
)
219 return tvb_get_guint8(tvb
, offset
) == 0x01 &&
220 tvb_get_guint8(tvb
, offset
+1) == 0x01 &&
221 tvb_get_guint8(tvb
, offset
+2) == 0x05 &&
222 (tvb_get_guint8(tvb
, offset
+3) == 0x10 ||tvb_get_guint8(tvb
, offset
+3) == 0x11)&&
223 tvb_get_guint8(tvb
, offset
+4) == 0x00 &&
224 tvb_get_guint8(tvb
, offset
+5) == 0x00;
227 void modify_times(tvbuff_t
*tvb
, gint offset
, packet_info
*pinfo
)
229 if ( ref_time_frame
.fd
== NULL
)
231 ref_time_frame
.esl_ts
= tvb_get_letoh64(tvb
, offset
+8);
232 ref_time_frame
.fd
= pinfo
->fd
;
233 ref_time_frame
.num
= pinfo
->fd
->num
;
234 ref_time_frame
.abs_ts
= pinfo
->fd
->abs_ts
;
236 else if ( !pinfo
->fd
->flags
.visited
)
238 guint64 nsecs
= tvb_get_letoh64(tvb
, offset
+8) - ref_time_frame
.esl_ts
;
239 guint64 secs
= nsecs
/1000000000;
243 ts
.nsecs
= ref_time_frame
.abs_ts
.nsecs
+ (int)(nsecs
-(secs
*1000000000));
244 if ( ts
.nsecs
> 1000000000 )
246 ts
.nsecs
-=1000000000;
250 ts
.secs
= ref_time_frame
.abs_ts
.secs
+(int)secs
;
251 nstime_delta(&ts_delta
, &ts
, &pinfo
->fd
->abs_ts
);
253 pinfo
->fd
->abs_ts
= ts
;
254 nstime_add(&pinfo
->rel_ts
, &ts_delta
);
259 dissect_esl_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
261 static gboolean in_heur
= FALSE
;
264 guint esl_length
= tvb_length(tvb
);
272 if ( ref_time_frame
.fd
!= NULL
&& !pinfo
->fd
->flags
.visited
&& pinfo
->fd
->num
<= ref_time_frame
.num
)
273 ref_time_frame
.fd
= NULL
;
275 /* Check that there's enough data */
276 if ( tvb_length(tvb
) < SIZEOF_ESLHEADER
)
279 /* check for Esl frame, this has a unique destination MAC from Beckhoff range
280 First 6 bytes must be: 01 01 05 10 00 00 */
281 if ( is_esl_header(tvb
, 0) )
283 dissect_esl_header(tvb
, pinfo
, tree
);
284 if ( eth_withoutfcs_handle
!= NULL
)
286 next_tvb
= tvb_new_subset_remaining(tvb
, SIZEOF_ESLHEADER
);
287 call_dissector(eth_withoutfcs_handle
, next_tvb
, pinfo
, tree
);
289 modify_times(tvb
, 0, pinfo
);
292 else if ( is_esl_header(tvb
, esl_length
-SIZEOF_ESLHEADER
) )
294 if ( eth_withoutfcs_handle
!= NULL
)
296 next_tvb
= tvb_new_subset(tvb
, 0, esl_length
-SIZEOF_ESLHEADER
, esl_length
-SIZEOF_ESLHEADER
);
297 call_dissector(eth_withoutfcs_handle
, next_tvb
, pinfo
, tree
);
299 next_tvb
= tvb_new_subset(tvb
, esl_length
-SIZEOF_ESLHEADER
, SIZEOF_ESLHEADER
, SIZEOF_ESLHEADER
);
300 dissect_esl_header(next_tvb
, pinfo
, tree
);
301 modify_times(tvb
, esl_length
-SIZEOF_ESLHEADER
, pinfo
);
319 proto_register_esl(void) {
320 static hf_register_info hf
[] = {
322 { "Port", "esl.port",
323 FT_UINT16
, BASE_DEC
, NULL
, 0x00,
327 { "Crc Error", "esl.crcerror",
328 FT_BOOLEAN
, 16, TFS(&flags_yes_no
), esl_crcError_bitmask
,
331 { &hf_esl_alignerror
,
332 { "Alignment Error", "esl.alignerror",
333 FT_BOOLEAN
, 16, TFS(&flags_yes_no
), esl_alignError_bitmask
,
337 { "timestamp", "esl.timestamp",
338 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
343 static gint
*ett
[] = {
347 module_t
*esl_module
;
349 proto_esl
= proto_register_protocol("EtherCAT Switch Link",
352 esl_module
= prefs_register_protocol(proto_esl
, proto_reg_handoff_esl
);
354 prefs_register_bool_preference(esl_module
, "enable", "Enable dissector",
355 "Enable this dissector (default is false)",
356 &esl_enable_dissector
);
358 proto_register_field_array(proto_esl
,hf
,array_length(hf
));
359 proto_register_subtree_array(ett
,array_length(ett
));
361 register_dissector("esl", dissect_esl_header
, proto_esl
);
365 proto_reg_handoff_esl(void) {
366 static gboolean initialized
= FALSE
;
369 eth_withoutfcs_handle
= find_dissector("eth_withoutfcs");
370 heur_dissector_add("eth", dissect_esl_heur
, proto_esl
);
373 proto_set_decoding(proto_esl
, esl_enable_dissector
);