diff options
author | Stig Bjørlykke <stig@bjorlykke.org> | 2009-07-07 11:13:22 +0000 |
---|---|---|
committer | Stig Bjørlykke <stig@bjorlykke.org> | 2009-07-07 11:13:22 +0000 |
commit | 09218f73384cc2bf7544476c4c8f70d069619475 (patch) | |
tree | 3bfe9c40048cfa003ec352e32c7c038284a94e65 /plugins/ethercat/packet-esl.c | |
parent | 3f625c283e4ece33e6444f449496ef220f49f0c6 (diff) |
From Richard Kummel:
- New dissector for EtherCAT Switch Link Header added to EtherCAT plugin
- Changed filtering of EtherCAT commands to the abbreviated form:
e.g. ecat.cmd = APWR
From me:
- Mark unused variables
- Fixed a string warning
- Do not initialize a static struct
- Use tfs_yes_no
- Reorder files in Makefile
svn path=/trunk/; revision=28976
Diffstat (limited to 'plugins/ethercat/packet-esl.c')
-rw-r--r-- | plugins/ethercat/packet-esl.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/plugins/ethercat/packet-esl.c b/plugins/ethercat/packet-esl.c new file mode 100644 index 0000000000..063f9ccae5 --- /dev/null +++ b/plugins/ethercat/packet-esl.c @@ -0,0 +1,283 @@ +/* packet-esl.c + * Routines for EtherCAT Switch Link disassembly + * + * $Id$ + * + * Copyright (c) 2007 by Beckhoff Automation GmbH + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Include files */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/tfs.h> + +#include "packet-esl.h" + +static dissector_handle_t eth_withoutfcs_handle = NULL; +static int esl_enable_dissector = FALSE; + +void proto_reg_handoff_esl(void); + +/* Define the esl proto */ +int proto_esl = -1; + +static int ett_esl = -1; + +static int hf_esl_timestamp = -1; +static int hf_esl_port = -1; +static int hf_esl_crcerror = -1; +static int hf_esl_alignerror = -1; + +static guint16 flags_to_port(guint16 flagsValue) { + EslFlagsUnion flagsUnion; + flagsUnion.flags = flagsValue; + if ( flagsUnion.d.port0 ) + return 0; + else if ( flagsUnion.d.port1 ) + return 1; + else if ( flagsUnion.d.port2 ) + return 2; + else if ( flagsUnion.d.port3 ) + return 3; + else if ( flagsUnion.d.port4 ) + return 4; + else if ( flagsUnion.d.port5 ) + return 5; + else if ( flagsUnion.d.port6 ) + return 6; + else if ( flagsUnion.d.port7 ) + return 7; + else if ( flagsUnion.d.port8 ) + return 8; + else if ( flagsUnion.d.port9 ) + return 9; + + return -1; +} + + +/*esl*/ +static void +dissect_esl_header(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree) { + + proto_item *ti = NULL; + proto_tree *esl_header_tree; + gint offset = 0; + + guint esl_length = tvb_reported_length(tvb); + if ( esl_length >= SIZEOF_ESLHEADER ) + { + if (tree) + { + guint16 flags; + + ti = proto_tree_add_item(tree, proto_esl, tvb, 0, SIZEOF_ESLHEADER, TRUE); + esl_header_tree = proto_item_add_subtree(ti, ett_esl); + offset+=6; + + flags = tvb_get_letohs(tvb, offset); + proto_tree_add_uint(esl_header_tree, hf_esl_port, tvb, offset, 2, flags_to_port(flags)); + + proto_tree_add_item(esl_header_tree, hf_esl_crcerror, tvb, offset, 2, TRUE); + proto_tree_add_item(esl_header_tree, hf_esl_alignerror, tvb, offset, 2, TRUE); + offset+=2; + + proto_tree_add_item(esl_header_tree, hf_esl_timestamp, tvb, offset, 8, TRUE); + } + } +} + +typedef struct _ref_time_frame_info +{ + frame_data *fd; + guint64 esl_ts; + nstime_t abs_ts; + guint32 num; +} ref_time_frame_info; + +static ref_time_frame_info ref_time_frame; + +gboolean is_esl_header(tvbuff_t *tvb, gint offset) +{ + return tvb_get_guint8(tvb, offset) == 0x01 && + tvb_get_guint8(tvb, offset+1) == 0x01 && + tvb_get_guint8(tvb, offset+2) == 0x05 && + tvb_get_guint8(tvb, offset+3) == 0x10 && + tvb_get_guint8(tvb, offset+4) == 0x00 && + tvb_get_guint8(tvb, offset+5) == 0x00; +} + +void modify_times(tvbuff_t *tvb, gint offset, packet_info *pinfo) +{ + if ( ref_time_frame.fd == NULL ) + { + ref_time_frame.esl_ts = tvb_get_letoh64(tvb, offset+8); + ref_time_frame.fd = pinfo->fd; + ref_time_frame.num = pinfo->fd->num; + ref_time_frame.abs_ts = pinfo->fd->abs_ts; + } + else if ( !pinfo->fd->flags.visited ) + { + guint64 nsecs = tvb_get_letoh64(tvb, offset+8) - ref_time_frame.esl_ts; + guint64 secs = nsecs/1000000000; + nstime_t ts; + nstime_t ts_delta; + + ts.nsecs = ref_time_frame.abs_ts.nsecs + (int)(nsecs-(secs*1000000000)); + if ( ts.nsecs > 1000000000 ) + { + ts.nsecs-=1000000000; + secs++; + } + + ts.secs = ref_time_frame.abs_ts.secs+(int)secs; + nstime_delta(&ts_delta, &ts, &pinfo->fd->abs_ts); + + pinfo->fd->abs_ts = ts; + nstime_add(&pinfo->fd->rel_ts, &ts_delta); + nstime_add(&pinfo->fd->del_dis_ts, &ts_delta); + nstime_add(&pinfo->fd->del_cap_ts, &ts_delta); + } +} + +static gboolean +dissect_esl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + static gboolean in_heur = FALSE; + gboolean result; + tvbuff_t *next_tvb; + guint esl_length = tvb_length(tvb); + + if ( in_heur ) + return FALSE; + + in_heur = TRUE; + /*TRY */ + { + if ( ref_time_frame.fd != NULL && !pinfo->fd->flags.visited && pinfo->fd->num <= ref_time_frame.num ) + ref_time_frame.fd = NULL; + + /* Check that there's enough data */ + if ( tvb_length(tvb) < SIZEOF_ESLHEADER ) + return FALSE; + + /* check for Esl frame, this has a unique destination MAC from Beckhoff range + First 6 bytes must be: 01 01 05 10 00 00 */ + if ( is_esl_header(tvb, 0) ) + { + dissect_esl_header(tvb, pinfo, tree); + if ( eth_withoutfcs_handle != NULL ) + { + next_tvb = tvb_new_subset(tvb, SIZEOF_ESLHEADER, -1, -1); + call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, tree); + } + modify_times(tvb, 0, pinfo); + result = TRUE; + } + else if ( is_esl_header(tvb, esl_length-SIZEOF_ESLHEADER) ) + { + if ( eth_withoutfcs_handle != NULL ) + { + next_tvb = tvb_new_subset(tvb, 0, esl_length-SIZEOF_ESLHEADER, esl_length-SIZEOF_ESLHEADER); + call_dissector(eth_withoutfcs_handle, next_tvb, pinfo, tree); + } + next_tvb = tvb_new_subset(tvb, esl_length-SIZEOF_ESLHEADER, SIZEOF_ESLHEADER, SIZEOF_ESLHEADER); + dissect_esl_header(next_tvb, pinfo, tree); + modify_times(tvb, esl_length-SIZEOF_ESLHEADER, pinfo); + + result = TRUE; + } + else + { + result = FALSE; + } + } + /*CATCH_ALL{ + in_heur = FALSE; + RETHROW; + }ENDTRY;*/ + in_heur = FALSE; + return result; +} + +void +proto_register_esl(void) { + static hf_register_info hf[] = { + { &hf_esl_port, + { "Port", "esl.port", + FT_UINT16, BASE_DEC, NULL, 0x00, + NULL, 0xC0FF, 0, 0, 0, NULL, NULL } + }, + { &hf_esl_crcerror, + { "Crc Error", "esl.crcerror", + FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x1000, + NULL, HFILL } + }, + { &hf_esl_alignerror, + { "Alignment Error", "esl.alignerror", + FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x0800, + NULL, HFILL } + }, + { &hf_esl_timestamp, + { "timestamp", "esl.timestamp", + FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_esl, + }; + + module_t *esl_module; + + proto_esl = proto_register_protocol("EtherCAT Switch Link", + "ESL","esl"); + + esl_module = prefs_register_protocol(proto_esl, proto_reg_handoff_esl); + + prefs_register_bool_preference(esl_module, "enable", "Enable dissector", + "Enable this dissector (default is false)", + &esl_enable_dissector); + + + proto_register_field_array(proto_esl,hf,array_length(hf)); + proto_register_subtree_array(ett,array_length(ett)); + + register_dissector("esl", dissect_esl_header, proto_esl); +} + +void +proto_reg_handoff_esl(void) { + static dissector_handle_t esl_handle; + + esl_handle = create_dissector_handle(dissect_esl_header, proto_esl); + eth_withoutfcs_handle = find_dissector("eth_withoutfcs"); + + heur_dissector_add("eth", dissect_esl_heur, proto_esl); + proto_set_decoding(proto_esl, esl_enable_dissector); +} |