diff options
author | Ulf Lamping <ulf.lamping@web.de> | 2006-04-20 19:49:12 +0000 |
---|---|---|
committer | Ulf Lamping <ulf.lamping@web.de> | 2006-04-20 19:49:12 +0000 |
commit | a70e3c548c2272df6cc0b3c83bec82b78bb22686 (patch) | |
tree | efc591a5f848f28a7e9ff644152abf3262ca2c2e /plugins | |
parent | 4447785ed7b7b174d2b3236c08904d3ff708b3a0 (diff) |
(on behalf of the PROFIBUS Nutzerorganisation e.V. Deutschland):
add Precision Time Control Protocol dissector (PTCP)
svn path=/trunk/; revision=17930
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/profinet/ChangeLog | 7 | ||||
-rw-r--r-- | plugins/profinet/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/profinet/Makefile.nmake | 2 | ||||
-rw-r--r-- | plugins/profinet/moduleinfo.h | 2 | ||||
-rw-r--r-- | plugins/profinet/packet-pn-ptcp.c | 1081 | ||||
-rw-r--r-- | plugins/profinet/profinet.c | 6 |
6 files changed, 1094 insertions, 6 deletions
diff --git a/plugins/profinet/ChangeLog b/plugins/profinet/ChangeLog index 7cfcdc9193..ea88df6040 100644 --- a/plugins/profinet/ChangeLog +++ b/plugins/profinet/ChangeLog @@ -20,4 +20,9 @@ Version 0.1.1: Version 0.1.2: -* PN-DCP: dissection of "DHCP/DHCP client identifier" suboption was added
\ No newline at end of file +* PN-DCP: dissection of "DHCP/DHCP client identifier" suboption was added + +Version 0.2.0: + +* PN-PTCP: add whole new Precision Time Control Protocol dissector + diff --git a/plugins/profinet/Makefile.am b/plugins/profinet/Makefile.am index 7a162159ed..3f24e71d92 100644 --- a/plugins/profinet/Makefile.am +++ b/plugins/profinet/Makefile.am @@ -27,7 +27,7 @@ INCLUDES = -I$(top_srcdir) plugindir = @plugindir@ plugin_LTLIBRARIES = profinet.la -profinet_la_SOURCES = profinet.c packet-dcerpc-pn-io.c packet-pn-dcp.c moduleinfo.h +profinet_la_SOURCES = profinet.c packet-dcerpc-pn-io.c packet-pn-dcp.c packet-pn-ptcp.c moduleinfo.h profinet_la_LDFLAGS = -module -avoid-version profinet_la_LIBADD = @PLUGIN_LIBS@ diff --git a/plugins/profinet/Makefile.nmake b/plugins/profinet/Makefile.nmake index c6430a4ec5..7c3b086449 100644 --- a/plugins/profinet/Makefile.nmake +++ b/plugins/profinet/Makefile.nmake @@ -15,7 +15,7 @@ LDFLAGS = /NOLOGO /INCREMENTAL:no /MACHINE:I386 $(LOCAL_LDFLAGS) LINK_PLUGIN_WITH=..\..\epan\libethereal.lib CFLAGS=/DHAVE_WIN32_LIBETHEREAL_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS) -OBJECTS=profinet.obj packet-dcerpc-pn-io.obj packet-pn-dcp.obj +OBJECTS=profinet.obj packet-dcerpc-pn-io.obj packet-pn-dcp.obj packet-pn-ptcp.obj profinet.dll profinet.exp profinet.lib : $(OBJECTS) $(LINK_PLUGIN_WITH) link -dll /out:profinet.dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \ diff --git a/plugins/profinet/moduleinfo.h b/plugins/profinet/moduleinfo.h index 336667db6b..2782ab2fa4 100644 --- a/plugins/profinet/moduleinfo.h +++ b/plugins/profinet/moduleinfo.h @@ -13,5 +13,5 @@ #endif /* Version number of package */ -#define VERSION "0.1.2" +#define VERSION "0.2.0" diff --git a/plugins/profinet/packet-pn-ptcp.c b/plugins/profinet/packet-pn-ptcp.c new file mode 100644 index 0000000000..f21794caac --- /dev/null +++ b/plugins/profinet/packet-pn-ptcp.c @@ -0,0 +1,1081 @@ +/* packet-pn-ptcp.c + * Routines for PN-PTCP (PROFINET Precision Time Clock Protocol) + * packet dissection. + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include <string.h> + +#include <glib.h> +#include <epan/packet.h> +#include <epan/dissectors/packet-dcerpc.h> +#include <epan/oui.h> + +static int proto_pn_ptcp = -1; + +static int hf_pn_ptcp = -1; +static int hf_pn_ptcp_data = -1; +static int hf_pn_ptcp_header = -1; +static int hf_pn_ptcp_block = -1; +static int hf_pn_ptcp_block_tlvheader = -1; + +static int hf_pn_ptcp_res1 = -1; +static int hf_pn_ptcp_res2 = -1; +static int hf_pn_ptcp_delay10ns = -1; +static int hf_pn_ptcp_seq_id = -1; +static int hf_pn_ptcp_delay1ns = -1; +static int hf_pn_ptcp_padding8 = -1; +static int hf_pn_ptcp_padding16 = -1; +static int hf_pn_ptcp_delay1ps = -1; + +static int hf_pn_ptcp_tl_length = -1; +static int hf_pn_ptcp_tl_type = -1; + +static int hf_pn_ptcp_master_source_address = -1; +static int hf_pn_ptcp_subdomain_uuid = -1; + +static int hf_pn_ptcp_request_source_address = -1; +static int hf_pn_ptcp_request_port_id = -1; +static int hf_pn_ptcp_sync_id = -1; + +static int hf_pn_ptcp_t2portrxdelay = -1; +static int hf_pn_ptcp_t3porttxdelay = -1; + +static int hf_pn_ptcp_seconds = -1; +static int hf_pn_ptcp_nanoseconds = -1; + +static int hf_pn_ptcp_flags = -1; +static int hf_pn_ptcp_epochnumber = -1; +static int hf_pn_ptcp_currentutcoffset = -1; + +static int hf_pn_ptcp_clock_uuid = -1; +static int hf_pn_ptcp_clockstratum = -1; +static int hf_pn_ptcp_clockvariance = -1; +static int hf_pn_ptcp_clockrole = -1; + +static int hf_pn_ptcp_oui = -1; +static int hf_pn_ptcp_unknown_subtype = -1; +static int hf_pn_ptcp_profinet_subtype = -1; +static int hf_pn_ptcp_irdata_uuid = -1; + +static gint ett_pn_ptcp = -1; +static gint ett_pn_ptcp_header = -1; +static gint ett_pn_ptcp_block = -1; +static gint ett_pn_ptcp_block_header = -1; + + + +static const value_string pn_ptcp_block_type[] = { + { 0x00, "End" }, + { 0x01, "Subdomain"}, + { 0x02, "Time"}, + { 0x03, "TimeExtension"}, + { 0x04, "Master"}, + { 0x05, "PortParameter"}, + { 0x06, "DelayParameter"}, + /*0x07 - 0x7E Reserved */ + { 0x7F, "Organizationally Specific"}, + + { 0, NULL } +}; + +static const value_string pn_ptcp_clock_stratum_vals[] = { + { 0x00, "Force" }, + { 0x01, "Primary"}, + { 0x02, "Secondary"}, + { 0x03, "TimingSignal"}, + { 0x04, "NoTimingSignal"}, + /*0x05 - 0xFE Reserved */ + { 0xFF, "Default"}, + + { 0, NULL } +}; + +static const value_string pn_ptcp_clock_role_vals[] = { + { 0x00, "Reserved" }, + { 0x01, "Primary PTCP-Master"}, + { 0x02, "Secondary PTCP-Master"}, + /*0x03 - 0xFF Reserved */ + + { 0, NULL } +}; + +static const value_string pn_ptcp_oui_vals[] = { + { OUI_PROFINET, "PROFINET" }, + + { 0, NULL } +}; + +static const value_string pn_ptcp_profinet_subtype_vals[] = { + { 0x01, "RTData" }, + + { 0, NULL } +}; + + +/* XXX - use include file instead for these helpers */ +extern int dissect_pn_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint8 *pdata); + +extern int dissect_pn_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint16 *pdata); + +extern int dissect_pn_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint32 *pdata); + + + +/* dissect an 8 bit unsigned integer */ +int +dissect_pn_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint8 *pdata) +{ + guint8 data; + + data = tvb_get_guint8 (tvb, offset); + if (tree) { + proto_tree_add_uint(tree, hfindex, tvb, offset, 1, data); + } + if (pdata) + *pdata = data; + return offset + 1; +} + +/* dissect a 16 bit unsigned integer */ +int +dissect_pn_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint16 *pdata) +{ + guint16 data; + + data = tvb_get_ntohs (tvb, offset); + + if (tree) { + proto_tree_add_uint(tree, hfindex, tvb, offset, 2, data); + } + if (pdata) + *pdata = data; + return offset + 2; +} + +/* dissect a 32 bit unsigned integer */ +int +dissect_pn_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint32 *pdata) +{ + guint32 data; + + data = tvb_get_ntohl (tvb, offset); + + if (tree) { + proto_tree_add_uint(tree, hfindex, tvb, offset, 4, data); + } + if (pdata) + *pdata = data; + return offset+4; +} + +/* dissect a 16 bit signed integer */ +int +dissect_pn_int16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, gint16 *pdata) +{ + gint16 data; + + data = tvb_get_ntohs (tvb, offset); + + if (tree) { + proto_tree_add_int(tree, hfindex, tvb, offset, 2, data); + } + if (pdata) + *pdata = data; + return offset + 2; +} + +/* dissect a 24bit OUI (IEC organizational unique id) */ +int +dissect_pn_oid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint32 *pdata) +{ + guint32 data; + + data = tvb_get_ntoh24(tvb, offset); + + if (tree) { + proto_tree_add_uint(tree, hfindex, tvb, offset, 3, data); + } + if (pdata) + *pdata = data; + return offset+3; +} + +/* dissect a 6 byte MAC address */ +int +dissect_pn_mac(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint8 *pdata) +{ + guint8 data[6]; + + tvb_memcpy(tvb, data, offset, 6); + if(tree) + proto_tree_add_ether(tree, hfindex, tvb, offset, 6, data); + + if (pdata) + memcpy(pdata, data, 6); + + return offset + 6; +} + +/* dissect a 12 byte UUID address */ +int +dissect_pn_uuid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, e_uuid_t *uuid) +{ + guint8 drep[2] = { 0,0 }; + + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hfindex, uuid); + + return offset; +} + + + + +static int +dissect_PNPTCP_TLVHeader(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 *type, guint16 *length) +{ + guint16 tl_type; + guint16 tl_length; + + + /* Type */ + dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_type, &tl_type); + *type = tl_type >> 9; + + /* Length */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_length, &tl_length); + *length = tl_length & 0x1FF; + + return offset; +} + + +static int +dissect_PNPTCP_Subdomain(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint8 mac[6]; + e_uuid_t uuid; + + /* MasterSourceAddress */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_master_source_address, mac); + + /* SubdomainUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_subdomain_uuid, &uuid); + + proto_item_append_text(item, ": MasterSource=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + proto_item_append_text(item, ", Subdomain=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.Data1, uuid.Data2, uuid.Data3, + uuid.Data4[0], uuid.Data4[1], + uuid.Data4[2], uuid.Data4[3], + uuid.Data4[4], uuid.Data4[5], + uuid.Data4[6], uuid.Data4[7]); + + return offset; +} + + +static int +dissect_PNPTCP_Time(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 padding16; + guint32 Seconds; + guint32 NanoSeconds; + + + /* Padding16 */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_padding16, &padding16); + + /* Seconds */ + offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_seconds, &Seconds); + + /* NanoSeconds */ + offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_nanoseconds, &NanoSeconds); + + proto_item_append_text(item, ": Seconds=%u NanoSeconds=%u", + Seconds, NanoSeconds); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", Time: %4us %09uns", Seconds, NanoSeconds); + + return offset; +} + + +static int +dissect_PNPTCP_TimeExtension(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 Flags; + guint16 EpochNumber; + guint16 CurrentUTCOffset; + + + /* Flags */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_flags, &Flags); + + /* EpochNumber */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_epochnumber, &EpochNumber); + + /* CurrentUTCOffset */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_currentutcoffset, &CurrentUTCOffset); + + proto_item_append_text(item, ": Flags=0x%x, EpochNumber=%u, CurrentUTCOffset=%u", + Flags, EpochNumber, CurrentUTCOffset); + + return offset; +} + + +static int +dissect_PNPTCP_Master(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + e_uuid_t uuid; + guint8 ClockStratum; + gint16 ClockVariance; + gint8 ClockRole; + + /* ClockVariance */ + offset = dissect_pn_int16(tvb, offset, pinfo, tree, hf_pn_ptcp_clockvariance, &ClockVariance); + + /* ClockUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_uuid, &uuid); + + /* ClockStratum */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clockstratum, &ClockStratum); + + /* ClockRole */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clockrole, &ClockRole); + + proto_item_append_text(item, ": ClockUUID=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.Data1, uuid.Data2, uuid.Data3, + uuid.Data4[0], uuid.Data4[1], + uuid.Data4[2], uuid.Data4[3], + uuid.Data4[4], uuid.Data4[5], + uuid.Data4[6], uuid.Data4[7]); + + proto_item_append_text(item, ", ClockStratum=%s, ClockVariance=%d", + val_to_str(ClockStratum, pn_ptcp_clock_stratum_vals, "(Reserved: 0x%x)"), ClockVariance); + + return offset; +} + + +static int +dissect_PNPTCP_PortParameter(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 padding16; + guint32 t2portrxdelay; + guint32 t3porttxdelay; + + + /* Padding16 */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_padding16, &padding16); + + /* T2PortRxDelay */ + offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t2portrxdelay, &t2portrxdelay); + + /* T3PortTxDelay */ + offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_ptcp_t3porttxdelay, &t3porttxdelay); + + proto_item_append_text(item, ": T2PortRxDelay=%uns, T3PortTxDelay=%uns", + t2portrxdelay, t3porttxdelay); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", T2Rx=%uns, T3Tx=%uns", + t2portrxdelay, t3porttxdelay); + + return offset; +} + + +static int +dissect_PNPTCP_DelayParameter(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint8 mac[6]; + guint8 requestportid; + guint8 syncid; + + + /* RequestSourceAddress */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_request_source_address, mac); + + /* RequestPortID */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_request_port_id, &requestportid); + + /* SyncID */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_sync_id, &syncid); + + + proto_item_append_text(item, ": RequestSource=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + proto_item_append_text(item, ", RequestPortID=0x%02x, SyncID=0x%02x", + requestportid, syncid); + + return offset; +} + + +static int +dissect_PNPTCP_Option_PROFINET(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length) +{ + guint8 subType; + guint8 padding8; + e_uuid_t uuid; + + /* OUI already dissected! */ + + /* SubType */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_profinet_subtype, &subType); + length --; + + switch(subType) { + case 1: /* RTData */ + /* Padding8 */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_padding8, &padding8); + + /* IRDataUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_irdata_uuid, &uuid); + break; + default: + proto_tree_add_string_format(tree, hf_pn_ptcp_data, tvb, offset, length, "data", + "PROFINET Data: %d bytes", length); + break; + } + + return offset; +} + + +static int +dissect_PNPTCP_Option(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length) +{ + guint32 oui; + guint8 subType; + + + /* verify remaining TLV length */ + if (length < 4) + { + if (tree) { + proto_tree_add_string_format(tree, hf_pn_ptcp_data, tvb, offset, length, "data", + "Length: %u (too short, must be >= 4)", length); + } + return (offset); + } + + /* OUI (organizational unique id) */ + offset = dissect_pn_oid(tvb, offset, pinfo,tree, hf_pn_ptcp_oui, &oui); + length -= 3; + + switch (oui) + { + case OUI_PROFINET: + offset = dissect_PNPTCP_Option_PROFINET(tvb, offset, pinfo, tree, item, length); + break; + default: + /* SubType */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_unknown_subtype, &subType); + length --; + proto_tree_add_string_format(tree, hf_pn_ptcp_data, tvb, offset, length, "data", + "Unknown OUI Data: %d bytes", length); + } + + return (offset); +} + + +static int +dissect_PNPTCP_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, gboolean *end) +{ + guint16 type; + guint16 length; + + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *tlvheader_item; + proto_tree *tlvheader_tree; + guint32 u32SubStart; + + + *end = FALSE; + + /* block subtree */ + sub_item = proto_tree_add_item(tree, hf_pn_ptcp_block, tvb, offset, 0, FALSE); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_ptcp_block); + u32SubStart = offset; + + /* tlvheader subtree */ + tlvheader_item = proto_tree_add_item(sub_tree, hf_pn_ptcp_block_tlvheader, tvb, offset, 2 /* len */, FALSE); + tlvheader_tree = proto_item_add_subtree(tlvheader_item, ett_pn_ptcp_block_header); + + offset = dissect_PNPTCP_TLVHeader(tvb, offset, pinfo, tlvheader_tree, sub_item, &type, &length); + + proto_item_append_text(sub_item, "%s", + val_to_str(type, pn_ptcp_block_type, "Unknown")); + + proto_item_append_text(tlvheader_item, ": Type=%s (%x), Length=%u", + val_to_str(type, pn_ptcp_block_type, "Unknown"), type, length); + + switch(type) { + case(0x00): /* End, no content */ + *end = TRUE; + break; + case(0x01): /* Subdomain */ + dissect_PNPTCP_Subdomain(tvb, offset, pinfo, sub_tree, sub_item); + break; + case(0x02): /* Time */ + dissect_PNPTCP_Time(tvb, offset, pinfo, sub_tree, sub_item); + break; + case(0x03): /* TimeExtension */ + dissect_PNPTCP_TimeExtension(tvb, offset, pinfo, sub_tree, sub_item); + break; + case(0x04): /* Master */ + dissect_PNPTCP_Master(tvb, offset, pinfo, sub_tree, sub_item); + break; + case(0x05): /* PortParameter */ + dissect_PNPTCP_PortParameter(tvb, offset, pinfo, sub_tree, sub_item); + break; + case(0x06): /* DelayParameter */ + dissect_PNPTCP_DelayParameter(tvb, offset, pinfo, sub_tree, sub_item); + break; + case(0x7F): /* Organizational Specific */ + dissect_PNPTCP_Option(tvb, offset, pinfo, sub_tree, sub_item, length); + break; + default: + proto_tree_add_string_format(sub_tree, hf_pn_ptcp_data, tvb, offset, length, "data", + "PN-PTCP Unknown BlockType 0x%x, Data: %d bytes", type, length); + } + offset += length; + + proto_item_set_len(sub_item, offset - u32SubStart); + + return offset; +} + + +static int +dissect_PNPTCP_blocks(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + gboolean end = FALSE; + + /* as long as we have some bytes, try a new block */ + while(!end) { + offset = dissect_PNPTCP_block(tvb, offset, pinfo, tree, item, &end); + } + + return offset; +} + + +static int +dissect_PNPTCP_Header(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, gboolean delay_valid) +{ + proto_item *header_item; + proto_tree *header_tree; + guint32 res_1; + guint32 res_2; + guint32 delay10ns; + guint16 seq_id; + guint8 delay1ns; + guint8 padding8; + guint16 padding16; + guint16 delay1ps; + guint64 delayns; + guint32 delayms; + + + header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, FALSE); + header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header); + + /* Reserved_1 */ + offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_res1, &res_1); + + /* Reserved_2 */ + offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_res2, &res_2); + + /* Delay10ns */ + offset = dissect_pn_uint32(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay10ns, &delay10ns); + + /* SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id); + + /* Delay1ns */ + offset = dissect_pn_uint8(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns, &delay1ns); + + /* Padding8 */ + offset = dissect_pn_uint8(tvb, offset, pinfo, header_tree, hf_pn_ptcp_padding8, &padding8); + + /* Delay1ps */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ps, &delay1ps); + + /* Padding16 */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_padding16, &padding16); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "Seq=%3u", seq_id); + proto_item_append_text(item, ": Sequence=%u", seq_id); + proto_item_append_text(header_item, ": Sequence=%u", seq_id); + + /* the delay field is meaningful only in specific PDU's */ + if(delay_valid) { + delayns = ((guint64) delay10ns) * 10 + delay1ns; + delayms = (guint32) (delayns / (1000 * 1000)); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, ", Delay=%11" PRIu64 "ns", + delayns); + proto_item_append_text(item, ", Delay=%" PRIu64 "ns", delayns); + + if(delayns != 0) { + proto_item_append_text(header_item, ", Delay=%" PRIu64 "ns (%u.%03u,%03u,%03u sec)", + delayns, + delayms / 1000, + delayms % 1000, + (delay10ns % (1000*100)) / 100, + delay10ns % 100 * 10 + delay1ns); + } else { + proto_item_append_text(header_item, ", Delay=%" PRIu64 "ns", + delayns); + } + } + + return offset; +} + + +static int +dissect_PNPTCP_FollowUpPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID) +{ + + switch(u16FrameID) { + case(0xFF20): + proto_item_append_text(item, "%s", "FollowUp (Clock)"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "FollowUp (Clock), "); + break; + case(0xFF21): + proto_item_append_text(item, "%s", "FollowUp (Time)"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "FollowUp (Time) , "); + break; + default: + proto_item_append_text(item, "%s", "FollowUp"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "FollowUp, "); + } + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, FALSE /* !delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +static int +dissect_PNPTCP_RTASyncPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID) +{ + + switch(u16FrameID) { + case(0x0000): + case(0x0020): + proto_item_append_text(item, "%s", "RTASync (Clock)"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "RTASync (Clock), "); + break; + case(0x0001): + case(0x0021): + proto_item_append_text(item, "%s", "RTASync (Time)"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "RTASync (Time) , "); + break; + default: + proto_item_append_text(item, "%s", "RTASync"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "RTASync, "); + } + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, FALSE /* !delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +static int +dissect_PNPTCP_RTCSyncPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "RTCSync, "); + + proto_item_append_text(item, "%s", "RTCSync"); + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, FALSE /* !delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +static int +dissect_PNPTCP_AnnouncePDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID) +{ + + switch(u16FrameID) { + case(0xFF00): + proto_item_append_text(item, "%s", "Announce (Clock)"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Announce (Clock), "); + break; + case(0xFF01): + proto_item_append_text(item, "%s", "Announce (Time)"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Announce (Time) , "); + break; + default: + proto_item_append_text(item, "%s", "Announce"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "Announce, "); + } + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, FALSE /* !delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +static int +dissect_PNPTCP_DelayReqPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "DelayReq, "); + + proto_item_append_text(item, "%s", "DelayReq"); + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, FALSE /* !delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +static int +dissect_PNPTCP_DelayResPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "DelayRes, "); + + proto_item_append_text(item, "%s", "DelayRes"); + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, TRUE /* delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +static int +dissect_PNPTCP_DelayFuResPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, "DelayFuRes, "); + + proto_item_append_text(item, "%s", "DelayFuRes"); + + /* dissect the header */ + offset = dissect_PNPTCP_Header(tvb, offset, pinfo, tree, item, TRUE /* delay_valid*/); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item); + + return offset; +} + + +/* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */ +static gboolean +dissect_PNPTCP_Data_heur(tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree) +{ + guint16 u16FrameID; + proto_item *item = NULL; + proto_tree *ptcp_tree = NULL; + int offset = 0; + guint32 u32SubStart; + + + /* the tvb will NOT contain the frame_id here, so get it from our private data! */ + u16FrameID = GPOINTER_TO_UINT(pinfo->private_data); + + /* frame id must be in valid range (acyclic Real-Time, DCP) */ + /* 0x0000 - 0x007F: RTASyncPDU */ + /* 0x0080 - 0x00FF: RTCSyncPDU */ + /* 0xFF00 - 0xFF1F: AnnouncePDU */ + /* 0xFF20 - 0xFF3F: FollowUpPDU */ + /* 0xFF40 - 0xFF5F: Delay...PDU */ + if ( (u16FrameID > 0x0100 && u16FrameID < 0xFF00) || (u16FrameID > 0xFF5F) ) { + /* we are not interested in this packet */ + return FALSE; + } + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_add_str(pinfo->cinfo, COL_PROTOCOL, "PN-PTCP"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_str(pinfo->cinfo, COL_INFO, ""); + + /* subtree for PTCP */ + item = proto_tree_add_protocol_format(tree, proto_pn_ptcp, tvb, 0, 0, "PROFINET PTCP, "); + ptcp_tree = proto_item_add_subtree(item, ett_pn_ptcp); + u32SubStart = offset; + + switch(u16FrameID) { + /* range 1 (0x0000 - 0x007F) */ + case(0x0000): + case(0x0001): + /* Send clock and phase synchronization */ + offset = dissect_PNPTCP_RTASyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID); + break; + /* 0x0002 - 0x001F reserved */ + case(0x0020): + case(0x0021): + /* Time synchronization */ + offset = dissect_PNPTCP_RTASyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID); + break; + /* 0x0022 - 0x007F reserved */ + + /* range 2 (0x0080 - 0x00FF) */ + case(0x0080): + /* class 3 synchronization */ + offset = dissect_PNPTCP_RTCSyncPDU(tvb, offset, pinfo, ptcp_tree, item); + break; + /* 0x0081 - 0x00FF reserved */ + + /* range 7 (0xFF00 - 0xFF5F) */ + case(0xff00): + case(0xff01): + offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID); + break; + /* 0xFF02 - 0xFF1F reserved */ + case(0xff20): + case(0xff21): + offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID); + break; + /* 0xFF22 - 0xFF3F reserved */ + case(0xff40): + offset = dissect_PNPTCP_DelayReqPDU(tvb, offset, pinfo, ptcp_tree, item); + break; + case(0xff41): + offset = dissect_PNPTCP_DelayResPDU(tvb, offset, pinfo, ptcp_tree, item); + break; + case(0xff42): + offset = dissect_PNPTCP_DelayFuResPDU(tvb, offset, pinfo, ptcp_tree, item); + break; + case(0xff43): + offset = dissect_PNPTCP_DelayResPDU(tvb, offset, pinfo, ptcp_tree, item); + break; + /* 0xFF44 - 0xFF5F reserved */ + default: + proto_tree_add_string_format(ptcp_tree, hf_pn_ptcp_data, tvb, offset, tvb_length_remaining(tvb, offset), "data", + "PN-PTCP Reserved FrameID 0x%04x, Data: %d bytes", u16FrameID, tvb_length_remaining(tvb, offset)); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_fstr(pinfo->cinfo, COL_INFO, "Reserved FrameID 0x%04x", u16FrameID); + + proto_item_append_text(item, "Reserved FrameID 0x%04x", u16FrameID); + + offset += tvb_length_remaining(tvb, offset); + } + + proto_item_set_len(item, offset - u32SubStart); + + return TRUE; +} + + +void +proto_register_pn_ptcp (void) +{ + static hf_register_info hf[] = { + { &hf_pn_ptcp, + { "PROFINET PTCP", "pn_ptcp", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_data, + { "Undecoded Data", "pn_ptcp.data", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_header, + { "Header", "pn_ptcp.header", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_block, + { "", "pn_ptcp.block", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_block_tlvheader, + { "TLVHeader", "pn_ptcp.tlvheader", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }}, + + { &hf_pn_ptcp_res1, + { "Reserved 1", "pn_ptcp.res1", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_res2, + { "Reserved 2", "pn_ptcp.res2", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_delay10ns, + { "Delay10ns", "pn_ptcp.delay10ns", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_seq_id, + { "SequenceID", "pn_ptcp.sequence_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_delay1ns, + { "Delay1ns", "pn_ptcp.delay1ns", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_padding8, + { "Padding", "pn_ptcp.padding8", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_padding16, + { "Padding", "pn_ptcp.padding16", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, + { &hf_pn_ptcp_delay1ps, + { "Delay1ps", "pn_ptcp.delay1ps", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_pn_ptcp_tl_length, + { "TypeLength.Length", "pn_ptcp.tl_length", FT_UINT16, BASE_DEC, 0x0, 0x1FF, "", HFILL }}, + { &hf_pn_ptcp_tl_type, + { "TypeLength.Type", "pn_ptcp.tl_type", FT_UINT16, BASE_DEC, 0x0, 0xFE00, "", HFILL }}, + + { &hf_pn_ptcp_master_source_address, + { "MasterSourceAddress", "pn_ptcp.master_source_address", FT_ETHER, BASE_HEX, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_subdomain_uuid, + { "SubdomainUUID", "pn_ptcp.subdomain_uuid", FT_STRING, BASE_NONE, 0x0, 0x0, "", HFILL }}, + + { &hf_pn_ptcp_request_source_address, + { "RequestSourceAddress", "pn_ptcp.request_source_address", FT_ETHER, BASE_HEX, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_request_port_id, + { "RequestPortID", "pn_ptcp.request_port_id", FT_UINT8, BASE_HEX, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_sync_id, + { "SyncID", "pn_ptcp.sync_id", FT_UINT8, BASE_HEX, 0x0, 0x0, "", HFILL }}, + + { &hf_pn_ptcp_t2portrxdelay, + { "T2PortRxDelay (ns)", "pn_ptcp.t2portrxdelay", FT_UINT32, BASE_DEC, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_t3porttxdelay, + { "T3PortTxDelay (ns)", "pn_ptcp.t3porttxdelay", FT_UINT32, BASE_DEC, 0x0, 0x0, "", HFILL }}, + + { &hf_pn_ptcp_seconds, + { "Seconds", "pn_ptcp.seconds", FT_UINT32, BASE_DEC, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_nanoseconds, + { "NanoSeconds", "pn_ptcp.nanoseconds", FT_UINT32, BASE_DEC, 0x0, 0x0, "", HFILL }}, + + { &hf_pn_ptcp_flags, + { "Flags", "pn_ptcp.flags", FT_UINT16, BASE_HEX, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_epochnumber, + { "EpochNumber", "pn_ptcp.epochnumber", FT_UINT16, BASE_DEC, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_currentutcoffset, + { "CurrentUTCOffset", "pn_ptcp.currentutcoffset", FT_UINT16, BASE_DEC, 0x0, 0x0, "", HFILL }}, + + + { &hf_pn_ptcp_clock_uuid, + { "ClockUUID", "pn_ptcp.clock_uuid", FT_STRING, BASE_NONE, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_clockstratum, + { "ClockStratum", "pn_ptcp.clockstratum", FT_UINT8, BASE_HEX, VALS(pn_ptcp_clock_stratum_vals), 0x0, "", HFILL }}, + { &hf_pn_ptcp_clockvariance, + { "ClockVariance", "pn_ptcp.clockvariance", FT_INT16, BASE_DEC, 0x0, 0x0, "", HFILL }}, + { &hf_pn_ptcp_clockrole, + { "ClockRole", "pn_ptcp.clockrole", FT_UINT8, BASE_HEX, VALS(pn_ptcp_clock_role_vals), 0x0, "", HFILL }}, + + { &hf_pn_ptcp_oui, + { "Organizationally Unique Identifier", "pn_ptcp.oui", FT_UINT24, BASE_HEX, + VALS(pn_ptcp_oui_vals), 0x0, "", HFILL }}, + { &hf_pn_ptcp_profinet_subtype, + { "Subtype", "pn_ptcp.subtype", FT_UINT8, BASE_HEX, + VALS(pn_ptcp_profinet_subtype_vals), 0x0, "PROFINET Subtype", HFILL }}, + { &hf_pn_ptcp_unknown_subtype, + { "Subtype", "pn_ptcp.subtype", FT_UINT8, BASE_HEX, 0x0, 0x0, "Unkown Subtype", HFILL }}, + + { &hf_pn_ptcp_irdata_uuid, + { "IRDataUUID", "pn_ptcp.irdata_uuid", FT_STRING, BASE_NONE, 0x0, 0x0, "", HFILL }}, + }; + + static gint *ett[] = { + &ett_pn_ptcp, + &ett_pn_ptcp_header, + &ett_pn_ptcp_block, + &ett_pn_ptcp_block_header + }; + proto_pn_ptcp = proto_register_protocol ("PROFINET PTCP", "PN-PTCP", "pn_ptcp"); + proto_register_field_array (proto_pn_ptcp, hf, array_length (hf)); + proto_register_subtree_array (ett, array_length (ett)); +} + +void +proto_reg_handoff_pn_ptcp (void) +{ + /* register ourself as an heuristic pn-rt payload dissector */ + heur_dissector_add("pn_rt", dissect_PNPTCP_Data_heur, proto_pn_ptcp); +} diff --git a/plugins/profinet/profinet.c b/plugins/profinet/profinet.c index f8ca6da330..f3e6b806fa 100644 --- a/plugins/profinet/profinet.c +++ b/plugins/profinet/profinet.c @@ -46,8 +46,8 @@ extern void proto_register_pn_io (void); extern void proto_reg_handoff_pn_io (void); extern void proto_register_pn_dcp (void); extern void proto_reg_handoff_pn_dcp (void); - - +extern void proto_register_pn_ptcp (void); +extern void proto_reg_handoff_pn_ptcp (void); /* Start the functions we need for the plugin stuff */ @@ -60,6 +60,7 @@ plugin_register(void) if (plugin_registered == FALSE) { /* execute protocol initialization only once */ proto_register_pn_io(); proto_register_pn_dcp(); + proto_register_pn_ptcp(); plugin_registered = TRUE; } @@ -69,6 +70,7 @@ G_MODULE_EXPORT void plugin_reg_handoff(void){ proto_reg_handoff_pn_io(); proto_reg_handoff_pn_dcp(); + proto_reg_handoff_pn_ptcp(); } #endif |