From 598b129fbcd4f55b77421e195298b241340ffb8b Mon Sep 17 00:00:00 2001 From: stig Date: Tue, 7 Jul 2009 11:13:22 +0000 Subject: [PATCH] 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 git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@28976 f5534014-38df-0310-8fa8-9805f1628bb7 --- plugins/ethercat/Makefile.common | 12 +- plugins/ethercat/packet-esl.c | 283 ++++++++++++++++++++ plugins/ethercat/packet-esl.h | 67 +++++ plugins/ethercat/packet-ethercat-datagram.c | 64 +++-- 4 files changed, 396 insertions(+), 30 deletions(-) create mode 100644 plugins/ethercat/packet-esl.c create mode 100644 plugins/ethercat/packet-esl.h diff --git a/plugins/ethercat/Makefile.common b/plugins/ethercat/Makefile.common index bbcc02ffb7..647465793c 100644 --- a/plugins/ethercat/Makefile.common +++ b/plugins/ethercat/Makefile.common @@ -28,18 +28,20 @@ PLUGIN_NAME = ethercat # the dissector sources (without any helpers) DISSECTOR_SRC = \ - packet-ethercat-frame.c \ - packet-ioraw.c \ - packet-nv.c \ packet-ams.c \ packet-ecatmb.c \ - packet-ethercat-datagram.c + packet-esl.c \ + packet-ethercat-datagram.c \ + packet-ethercat-frame.c \ + packet-ioraw.c \ + packet-nv.c # corresponding headers DISSECTOR_INCLUDES = \ packet-ams.h \ - packet-ethercat-frame.h \ packet-ecatmb.h \ + packet-esl.h \ packet-ethercat-datagram.h \ + packet-ethercat-frame.h \ packet-ioraw.h \ packet-nv.h 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 + * 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 + +#include +#include +#include + +#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); +} diff --git a/plugins/ethercat/packet-esl.h b/plugins/ethercat/packet-esl.h new file mode 100644 index 0000000000..858312debb --- /dev/null +++ b/plugins/ethercat/packet-esl.h @@ -0,0 +1,67 @@ +/* packet-esl.h + * + * $Id$ + * + * Copyright (c) 2007 by Beckhoff Automation GmbH + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 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. + */ + +#ifndef _PACKET_ESL_H_ +#define _PACKET_ESL_H_ + +typedef union _EslFlagsUnion +{ + struct + { + guint16 port7 : 1; + guint16 port6 : 1; + guint16 port5 : 1; + guint16 port4 : 1; + guint16 port3 : 1; + guint16 port2 : 1; + guint16 port1 : 1; + guint16 port0 : 1; + guint16 extended : 1; + guint16 reserved : 2; + guint16 crcError : 1; + guint16 alignError : 1; + guint16 timeStampEna: 1; + guint16 port9 : 1; + guint16 port8 : 1; + }d; + struct + { + guint8 loPorts : 1; + guint8 flagsHiPorts : 1; + }lo_hi_flags; + guint flags; +}EslFlagsUnion; + +/* +typedef struct _EslHeader +{ + guint8 eslCookie[6]; // 01 01 05 10 00 00 + EslFlagsUnion flags; + guint64 timeStamp; +} EslHeader, *PEslHeader;*/ + + +#define SIZEOF_ESLHEADER 16 +#endif /* _PACKET_ESL_H_*/ diff --git a/plugins/ethercat/packet-ethercat-datagram.c b/plugins/ethercat/packet-ethercat-datagram.c index 6daefb77e8..a737e33fec 100644 --- a/plugins/ethercat/packet-ethercat-datagram.c +++ b/plugins/ethercat/packet-ethercat-datagram.c @@ -157,20 +157,20 @@ static const value_string EcCmdShort[] = static const value_string EcCmdLong[] = { { 0, "No operation" }, - { 1, "Auto increment read" }, - { 2, "Auto increment write" }, - { 3, "Auto increment read write" }, - { 4, "Configured address read" }, - { 5, "Configured address write" }, - { 6, "Configured address read write" }, - { 7, "Broadcast read" }, - { 8, "Broadcast write" }, - { 9, "Broadcast read write" }, - { 10, "Logical memory read" }, - { 11, "Logical memory write" }, - { 12, "Logical memory read write" }, - { 13, "Auto increment read multiple write" }, - { 14, "Configured read multiple write" }, + { 1, "Auto Increment Physical Read" }, + { 2, "Auto Increment Physical Write" }, + { 3, "Auto Increment Physical ReadWrite" }, + { 4, "Configured address Physical Read" }, + { 5, "Configured address Physical Write" }, + { 6, "Configured address Physical ReadWrite" }, + { 7, "Broadcast Read" }, + { 8, "Broadcast Write" }, + { 9, "Broadcast ReadWrite" }, + { 10, "Logical Read" }, + { 11, "Logical Write" }, + { 12, "Logical ReadWrite" }, + { 13, "Auto Increment Physical Read Multiple Write" }, + { 14, "Configured Address Physical Read Multiple Write" }, { 255, "EXT" }, { 0, NULL } }; @@ -393,6 +393,18 @@ static void EcSummaryFormater(guint32 datalength, tvbuff_t *tvb, gint offset, ch nSub, nLen, convertEcCmdToText(ecFirst.cmd, EcCmdShort)); } +static void EcCmdFormatter(guint8 cmd, char *szText, gint nMax) +{ + gint idx=0; + const gchar *szCmd = match_strval_idx((guint32)cmd, EcCmdLong, &idx); + + if ( idx != -1 ) + g_snprintf(szText, nMax, "Cmd : %d (%s)", cmd, szCmd); + else + g_snprintf(szText, nMax, "Cmd : %d (Unknown command)", cmd); +} + + static void EcSubFormatter(tvbuff_t *tvb, gint offset, char *szText, gint nMax) { EcParserHDR ecParser; @@ -548,7 +560,9 @@ static void dissect_ecat_datagram(tvbuff_t *tvb, packet_info *pinfo, proto_tree aitem = proto_tree_add_text(ecat_datagram_tree, tvb, offset, EcParserHDR_Len, "Header"); ecat_header_tree = proto_item_add_subtree(aitem, ett_ecat_header); + EcCmdFormatter(ecHdr.cmd, szText, nMax); aitem = proto_tree_add_item(ecat_header_tree, hf_ecat_cmd, tvb, suboffset, sizeof(ecHdr.cmd), TRUE); + proto_item_set_text(aitem, "%s", szText); if( subCount < 10 ){ aitem = proto_tree_add_item(ecat_header_tree, hf_ecat_sub_cmd[subCount], tvb, suboffset, sizeof(ecHdr.cmd), TRUE); PROTO_ITEM_SET_HIDDEN(aitem); @@ -969,47 +983,47 @@ void proto_register_ecat(void) }, { &hf_ecat_cmd, { "Command", "ecat.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[0], { "Command", "ecat.sub1.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[1], { "Command", "ecat.sub2.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[2], { "Command", "ecat.sub3.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[3], { "Command", "ecat.sub4.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[4], { "Command", "ecat.sub5.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[5], { "Command", "ecat.sub6.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[6], { "Command", "ecat.sub7.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[7], { "Command", "ecat.sub8.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[8], { "Command", "ecat.sub9.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_sub_cmd[9], { "Command", "ecat.sub10.cmd", - FT_UINT8, BASE_HEX, VALS(EcCmdLong), 0x0, NULL, HFILL } + FT_UINT8, BASE_HEX, VALS(EcCmdShort), 0x0, NULL, HFILL } }, { &hf_ecat_idx, { "Index", "ecat.idx", -- 2.34.1