epan/dissectors/pidl/ C99 drsuapi
[wireshark-sm.git] / plugins / epan / ethercat / packet-esl.c
blobb67902cbe81704b9c3300a618bfe938730774f88
1 /* packet-esl.c
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
13 #include "config.h"
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/tfs.h>
18 #include <wsutil/array.h>
20 void proto_register_esl(void);
22 #if 0
23 /* XXX: using bitfields is compiler dependent: See README.developer */
25 typedef union _EslFlagsUnion
27 struct
29 uint16_t port7 : 1;
30 uint16_t port6 : 1;
31 uint16_t port5 : 1;
32 uint16_t port4 : 1;
33 uint16_t port3 : 1;
34 uint16_t port2 : 1;
35 uint16_t port1 : 1;
36 uint16_t port0 : 1;
37 uint16_t extended : 1;
38 uint16_t port11 : 1;
39 uint16_t port10 : 1;
40 uint16_t alignError : 1;
41 uint16_t crcError : 1;
42 uint16_t timeStampEna : 1;
43 uint16_t port9 : 1;
44 uint16_t port8 : 1;
45 }d;
46 struct
48 uint8_t loPorts : 1;
49 uint8_t flagsHiPorts : 1;
50 }lo_hi_flags;
51 unsigned flags;
52 } EslFlagsUnion;
53 #endif
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
72 #if 0
73 typedef struct _EslHeader
75 uint8_t eslCookie[6]; /* 01 01 05 10 00 00 */
76 EslFlagsUnion flags;
77 uint64_t timeStamp;
78 } EslHeader, *PEslHeader;
79 #endif
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 */
89 int proto_esl;
91 static int ett_esl;
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 = {
100 "yes",
101 "no"
104 #if 0
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 )
110 return 0;
111 else if ( flagsUnion.d.port1 )
112 return 1;
113 else if ( flagsUnion.d.port2 )
114 return 2;
115 else if ( flagsUnion.d.port3 )
116 return 3;
117 else if ( flagsUnion.d.port4 )
118 return 4;
119 else if ( flagsUnion.d.port5 )
120 return 5;
121 else if ( flagsUnion.d.port6 )
122 return 6;
123 else if ( flagsUnion.d.port7 )
124 return 7;
125 else if ( flagsUnion.d.port8 )
126 return 8;
127 else if ( flagsUnion.d.port9 )
128 return 9;
130 return -1;
132 #endif
134 static uint16_t flags_to_port(uint16_t flagsValue) {
135 if ( (flagsValue & esl_port0_bitmask) != 0 )
136 return 0;
137 else if ( (flagsValue & esl_port1_bitmask) != 0 )
138 return 1;
139 else if ( (flagsValue & esl_port2_bitmask) != 0 )
140 return 2;
141 else if ( (flagsValue & esl_port3_bitmask) != 0 )
142 return 3;
143 else if ( (flagsValue & esl_port4_bitmask) != 0 )
144 return 4;
145 else if ( (flagsValue & esl_port5_bitmask) != 0 )
146 return 5;
147 else if ( (flagsValue & esl_port6_bitmask) != 0 )
148 return 6;
149 else if ( (flagsValue & esl_port7_bitmask) != 0 )
150 return 7;
151 else if ( (flagsValue & esl_port8_bitmask) != 0 )
152 return 8;
153 else if ( (flagsValue & esl_port9_bitmask) != 0 )
154 return 9;
155 else if ( (flagsValue & esl_port10_bitmask) != 0 )
156 return 10;
157 else if ( (flagsValue & esl_port11_bitmask) != 0 )
158 return 11;
160 return -1;
163 /*esl*/
164 static int
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;
169 int offset = 0;
171 unsigned esl_length = tvb_reported_length(tvb);
172 if ( esl_length >= SIZEOF_ESLHEADER )
174 if (tree)
176 uint16_t flags;
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);
180 offset+=6;
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);
188 offset+=2;
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
198 frame_data *fd;
199 uint64_t esl_ts;
200 nstime_t abs_ts;
201 uint32_t num;
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;
229 nstime_t ts;
230 nstime_t ts_delta;
232 ts.nsecs = ref_time_frame.abs_ts.nsecs + (int)(nsecs-(secs*1000000000));
233 if ( ts.nsecs > 1000000000 )
235 ts.nsecs-=1000000000;
236 secs++;
239 ts.secs = ref_time_frame.abs_ts.secs+(int)secs;
240 nstime_delta(&ts_delta, &ts, &pinfo->abs_ts);
242 pinfo->abs_ts = ts;
243 pinfo->fd->abs_ts = ts;
244 nstime_add(&pinfo->rel_ts, &ts_delta);
248 static bool
249 dissect_esl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
251 static bool in_heur = false;
252 bool result;
253 tvbuff_t *next_tvb;
254 unsigned esl_length = tvb_captured_length(tvb);
256 if ( in_heur )
257 return false;
259 in_heur = true;
260 /*TRY */
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 )
267 return false;
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);
280 result = true;
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);
293 result = true;
295 else
297 result = false;
300 /*CATCH_ALL{
301 in_heur = false;
302 RETHROW;
303 }ENDTRY;*/
304 in_heur = false;
305 return result;
308 void
309 proto_register_esl(void) {
310 static hf_register_info hf[] = {
311 { &hf_esl_port,
312 { "Port", "esl.port",
313 FT_UINT16, BASE_DEC, NULL, 0x00,
314 NULL, HFILL }
316 { &hf_esl_crcerror,
317 { "Crc Error", "esl.crcerror",
318 FT_BOOLEAN, 16, TFS(&flags_yes_no), esl_crcError_bitmask,
319 NULL, HFILL }
321 { &hf_esl_alignerror,
322 { "Alignment Error", "esl.alignerror",
323 FT_BOOLEAN, 16, TFS(&flags_yes_no), esl_alignError_bitmask,
324 NULL, HFILL }
326 { &hf_esl_timestamp,
327 { "timestamp", "esl.timestamp",
328 FT_UINT64, BASE_HEX, NULL, 0x0,
329 NULL, HFILL }
333 static int *ett[] = {
334 &ett_esl,
337 module_t *esl_module;
339 proto_esl = proto_register_protocol("EtherCAT Switch Link",
340 "ESL","esl");
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);
352 void
353 proto_reg_handoff_esl(void) {
354 static bool initialized = false;
356 if (!initialized) {
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);
359 initialized = true;
364 * Editor modelines - https://www.wireshark.org/tools/modelines.html
366 * Local variables:
367 * c-basic-offset: 4
368 * tab-width: 8
369 * indent-tabs-mode: nil
370 * End:
372 * vi: set shiftwidth=4 tabstop=8 expandtab:
373 * :indentSize=4:tabSize=8:noTabs=true: