MSWSP: add ids for another unknown Property Set
[wireshark-wip.git] / plugins / ethercat / packet-esl.c
blobe454ef659f3e7f4c06a3ab78dcc88a28566e7ffe
1 /* packet-esl.c
2 * Routines for EtherCAT Switch Link disassembly
4 * $Id$
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.
27 #include "config.h"
29 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
34 #if 0
35 /* XXX: using bitfields is compiler dependent: See README.developer */
37 typedef union _EslFlagsUnion
39 struct
41 guint16 port7 : 1;
42 guint16 port6 : 1;
43 guint16 port5 : 1;
44 guint16 port4 : 1;
45 guint16 port3 : 1;
46 guint16 port2 : 1;
47 guint16 port1 : 1;
48 guint16 port0 : 1;
49 guint16 extended : 1;
50 guint16 port11 : 1;
51 guint16 port10 : 1;
52 guint16 crcError : 1;
53 guint16 alignError : 1;
54 guint16 timeStampEna : 1;
55 guint16 port9 : 1;
56 guint16 port8 : 1;
57 }d;
58 struct
60 guint8 loPorts : 1;
61 guint8 flagsHiPorts : 1;
62 }lo_hi_flags;
63 guint flags;
64 } EslFlagsUnion;
65 #endif
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
84 #if 0
85 typedef struct _EslHeader
87 guint8 eslCookie[6]; /* 01 01 05 10 00 00 */
88 EslFlagsUnion flags;
89 guint64 timeStamp;
90 } EslHeader, *PEslHeader;
91 #endif
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 */
102 int proto_esl = -1;
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 = {
113 "yes",
114 "no"
117 #if 0
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 )
123 return 0;
124 else if ( flagsUnion.d.port1 )
125 return 1;
126 else if ( flagsUnion.d.port2 )
127 return 2;
128 else if ( flagsUnion.d.port3 )
129 return 3;
130 else if ( flagsUnion.d.port4 )
131 return 4;
132 else if ( flagsUnion.d.port5 )
133 return 5;
134 else if ( flagsUnion.d.port6 )
135 return 6;
136 else if ( flagsUnion.d.port7 )
137 return 7;
138 else if ( flagsUnion.d.port8 )
139 return 8;
140 else if ( flagsUnion.d.port9 )
141 return 9;
143 return -1;
145 #endif
147 static guint16 flags_to_port(guint16 flagsValue) {
148 if ( (flagsValue & esl_port0_bitmask) != 0 )
149 return 0;
150 else if ( (flagsValue & esl_port1_bitmask) != 0 )
151 return 1;
152 else if ( (flagsValue & esl_port2_bitmask) != 0 )
153 return 2;
154 else if ( (flagsValue & esl_port3_bitmask) != 0 )
155 return 3;
156 else if ( (flagsValue & esl_port4_bitmask) != 0 )
157 return 4;
158 else if ( (flagsValue & esl_port5_bitmask) != 0 )
159 return 5;
160 else if ( (flagsValue & esl_port6_bitmask) != 0 )
161 return 6;
162 else if ( (flagsValue & esl_port7_bitmask) != 0 )
163 return 7;
164 else if ( (flagsValue & esl_port8_bitmask) != 0 )
165 return 8;
166 else if ( (flagsValue & esl_port9_bitmask) != 0 )
167 return 9;
168 else if ( (flagsValue & esl_port10_bitmask) != 0 )
169 return 10;
170 else if ( (flagsValue & esl_port11_bitmask) != 0 )
171 return 11;
173 return -1;
176 /*esl*/
177 static void
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;
182 gint offset = 0;
184 guint esl_length = tvb_reported_length(tvb);
185 if ( esl_length >= SIZEOF_ESLHEADER )
187 if (tree)
189 guint16 flags;
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);
193 offset+=6;
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);
200 offset+=2;
202 proto_tree_add_item(esl_header_tree, hf_esl_timestamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
207 typedef struct _ref_time_frame_info
209 frame_data *fd;
210 guint64 esl_ts;
211 nstime_t abs_ts;
212 guint32 num;
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;
240 nstime_t ts;
241 nstime_t ts_delta;
243 ts.nsecs = ref_time_frame.abs_ts.nsecs + (int)(nsecs-(secs*1000000000));
244 if ( ts.nsecs > 1000000000 )
246 ts.nsecs-=1000000000;
247 secs++;
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);
258 static gboolean
259 dissect_esl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
261 static gboolean in_heur = FALSE;
262 gboolean result;
263 tvbuff_t *next_tvb;
264 guint esl_length = tvb_length(tvb);
266 if ( in_heur )
267 return FALSE;
269 in_heur = TRUE;
270 /*TRY */
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 )
277 return FALSE;
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);
290 result = TRUE;
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);
303 result = TRUE;
305 else
307 result = FALSE;
310 /*CATCH_ALL{
311 in_heur = FALSE;
312 RETHROW;
313 }ENDTRY;*/
314 in_heur = FALSE;
315 return result;
318 void
319 proto_register_esl(void) {
320 static hf_register_info hf[] = {
321 { &hf_esl_port,
322 { "Port", "esl.port",
323 FT_UINT16, BASE_DEC, NULL, 0x00,
324 NULL, HFILL }
326 { &hf_esl_crcerror,
327 { "Crc Error", "esl.crcerror",
328 FT_BOOLEAN, 16, TFS(&flags_yes_no), esl_crcError_bitmask,
329 NULL, HFILL }
331 { &hf_esl_alignerror,
332 { "Alignment Error", "esl.alignerror",
333 FT_BOOLEAN, 16, TFS(&flags_yes_no), esl_alignError_bitmask,
334 NULL, HFILL }
336 { &hf_esl_timestamp,
337 { "timestamp", "esl.timestamp",
338 FT_UINT64, BASE_HEX, NULL, 0x0,
339 NULL, HFILL }
343 static gint *ett[] = {
344 &ett_esl,
347 module_t *esl_module;
349 proto_esl = proto_register_protocol("EtherCAT Switch Link",
350 "ESL","esl");
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);
364 void
365 proto_reg_handoff_esl(void) {
366 static gboolean initialized = FALSE;
368 if (!initialized) {
369 eth_withoutfcs_handle = find_dissector("eth_withoutfcs");
370 heur_dissector_add("eth", dissect_esl_heur, proto_esl);
371 initialized = TRUE;
373 proto_set_decoding(proto_esl, esl_enable_dissector);