aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/epan/profinet/packet-pn-ptcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/epan/profinet/packet-pn-ptcp.c')
-rw-r--r--plugins/epan/profinet/packet-pn-ptcp.c1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/plugins/epan/profinet/packet-pn-ptcp.c b/plugins/epan/profinet/packet-pn-ptcp.c
new file mode 100644
index 0000000000..d7771f3d06
--- /dev/null
+++ b/plugins/epan/profinet/packet-pn-ptcp.c
@@ -0,0 +1,1105 @@
+/* packet-pn-ptcp.c
+ * Routines for PN-PTCP (PROFINET Precision Time Clock Protocol)
+ * packet dissection.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/oui.h>
+#include <epan/dissectors/packet-dcerpc.h>
+
+#include "packet-pn.h"
+
+void proto_register_pn_ptcp(void);
+void proto_reg_handoff_pn_ptcp(void);
+
+static int proto_pn_ptcp = -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_byte = -1;
+static int hf_pn_ptcp_delay1ns_fup = -1;
+static int hf_pn_ptcp_delay1ns = -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_port_mac_address = -1;
+
+static int hf_pn_ptcp_t2portrxdelay = -1;
+static int hf_pn_ptcp_t3porttxdelay = -1;
+
+static int hf_pn_ptcp_t2timestamp = -1;
+
+static int hf_pn_ptcp_epoch_number = -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_currentutcoffset = -1;
+
+static int hf_pn_ptcp_master_priority1 = -1;
+static int hf_pn_ptcp_master_priority_level = -1;
+static int hf_pn_ptcp_master_priority1_res = -1;
+static int hf_pn_ptcp_master_priority1_act =-1;
+
+static int hf_pn_ptcp_master_priority2 = -1;
+static int hf_pn_ptcp_clock_class = -1;
+static int hf_pn_ptcp_clock_accuracy = -1;
+static int hf_pn_ptcp_clockvariance = -1;
+
+static int hf_pn_ptcp_oui = -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;
+
+#define OUI_PROFINET_MULTICAST 0x010ECF /* PROFIBUS Nutzerorganisation e.V. */
+
+
+#define PN_PTCP_BT_END 0x00
+#define PN_PTCP_BT_SUBDOMAIN 0x01
+#define PN_PTCP_BT_TIME 0x02
+#define PN_PTCP_BT_TIME_EXTENSION 0x03
+#define PN_PTCP_BT_MASTER 0x04
+#define PN_PTCP_BT_PORT_PARAMETER 0x05
+#define PN_PTCP_BT_DELAY_PARAMETER 0x06
+#define PN_PTCP_BT_PORT_TIME 0x07
+#define PN_PTCP_BT_OPTION 0x7F
+#define PN_PTCP_BT_RTDATA 0x7F
+
+
+static const value_string pn_ptcp_block_type[] = {
+ { PN_PTCP_BT_END, "End" },
+ { PN_PTCP_BT_SUBDOMAIN, "Subdomain"},
+ { PN_PTCP_BT_TIME, "Time"},
+ { PN_PTCP_BT_TIME_EXTENSION, "TimeExtension"},
+ { PN_PTCP_BT_MASTER, "Master"},
+ { PN_PTCP_BT_PORT_PARAMETER, "PortParameter"},
+ { PN_PTCP_BT_DELAY_PARAMETER, "DelayParameter"},
+ { PN_PTCP_BT_PORT_TIME, "PortTime"},
+ /*0x08 - 0x7E Reserved */
+ { PN_PTCP_BT_OPTION, "Organizationally Specific"},
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_oui_vals[] = {
+ { OUI_PROFINET, "PROFINET" },
+ { OUI_PROFINET_MULTICAST, "PROFINET" },
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_master_prio1_vals[] = {
+ { 0x00, "Sync slave" },
+ { 0x01, "Primary master" },
+ { 0x02, "Secondary master" },
+ { 0x03, "Reserved" },
+ { 0x04, "Reserved" },
+ { 0x05, "Reserved" },
+ { 0x06, "Reserved" },
+ { 0x07, "Reserved" },
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_master_prio1_levels[] = {
+ { 0x00, "Level 0 (highest)" },
+ { 0x01, "Level 1" },
+ { 0x02, "Level 2" },
+ { 0x03, "Level 3" },
+ { 0x04, "Level 4" },
+ { 0x05, "Level 5" },
+ { 0x06, "Level 6" },
+ { 0x07, "Level 7 (lowest)" },
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_master_prio1_vals_active[] = {
+ { 0x00, "inactive" },
+ { 0x01, "active" },
+ { 0, NULL }
+};
+
+#if 0
+static const value_string pn_ptcp_master_prio1_short_vals[] = {
+ { 0x01, "Primary" },
+ { 0x02, "Secondary" },
+ { 0, NULL }
+};
+#endif
+
+static const value_string pn_ptcp_master_prio2_vals[] = {
+ { 0xFF, "Default" },
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_clock_class_vals[] = {
+ { 0xFF, "Slave-only clock" },
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_clock_accuracy_vals[] = {
+ { 0x20, "25ns" },
+ { 0x21, "100ns (Default)" },
+ { 0x22, "250ns" },
+ { 0x23, "1us" },
+ { 0x24, "2.5us" },
+ { 0x25, "10us" },
+ { 0x26, "25us" },
+ { 0x27, "100us" },
+ { 0x28, "250us" },
+ { 0x29, "1ms" },
+ { 0xFE, "Unknown" },
+ { 0, NULL }
+};
+
+static const value_string pn_ptcp_profinet_subtype_vals[] = {
+ { 0x01, "RTData" },
+ { 0, NULL }
+};
+
+
+
+
+static int
+dissect_PNPTCP_TLVHeader(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item _U_, 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, guint16 u16FrameID)
+{
+ guint8 mac[6];
+ e_guid_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);
+
+ if ((u16FrameID == 0xff00) || (u16FrameID == 0xff01)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Master=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ }
+
+ 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 EpochNumber;
+ guint32 Seconds;
+ guint32 NanoSeconds;
+
+
+ /* EpochNumber */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_epoch_number, &EpochNumber);
+
+ /* Seconds */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_seconds, tvb, offset, 4, ENC_BIG_ENDIAN, &Seconds);
+ offset += 4;
+
+ /* NanoSeconds */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_nanoseconds, tvb, offset, 4, ENC_BIG_ENDIAN, &NanoSeconds);
+ offset += 4;
+
+ proto_item_append_text(item, ": Seconds=%u NanoSeconds=%u EpochNumber=%u",
+ Seconds, NanoSeconds, EpochNumber);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Time: %4us %09uns, Epoch: %u",
+ Seconds, NanoSeconds, EpochNumber);
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_TimeExtension(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item)
+{
+ guint16 Flags;
+ guint16 CurrentUTCOffset;
+
+
+ /* Flags */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_flags, &Flags);
+
+ /* CurrentUTCOffset */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_currentutcoffset, &CurrentUTCOffset);
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+ proto_item_append_text(item, ": Flags=0x%x, CurrentUTCOffset=%u", Flags, CurrentUTCOffset);
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_Master(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item)
+{
+ guint8 MasterPriority1;
+ guint8 MasterPriority2;
+ guint8 ClockClass;
+ guint8 ClockAccuracy;
+ gint16 ClockVariance;
+
+
+ /* MasterPriority1 is a bit field */
+ /* Bit 0 - 2: PTCP_MasterPriority1.Priority */
+ dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1, &MasterPriority1);
+ /* Bit 3 - 5: PTCP_MasterPriority1.Level */
+ dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority_level, &MasterPriority1);
+ /* Bit 6: PTCP_MasterPriority1.Reserved */
+ dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_res, &MasterPriority1);
+ /* Bit 7: PTCP_MasterPriority1.Active */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_act, &MasterPriority1);
+
+ /* MasterPriority2 */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority2, &MasterPriority2);
+
+ /* ClockClass */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_class, &ClockClass);
+
+ /* ClockAccuracy */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_accuracy, &ClockAccuracy);
+
+ /* ClockVariance */
+ offset = dissect_pn_int16(tvb, offset, pinfo, tree, hf_pn_ptcp_clockvariance, &ClockVariance);
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Prio1=\"%s\"",
+ val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"));
+
+ if ((MasterPriority1 & 0x80) == 0) {
+ proto_item_append_text(item, ": Prio1=\"%s\", Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
+ val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"),
+ val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"),
+ val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"),
+ val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"),
+ ClockVariance);
+ }
+ else {
+ col_append_str(pinfo->cinfo, COL_INFO, " active");
+ proto_item_append_text(item, ": Prio1=\"%s\" is active, Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d",
+ val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"),
+ val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"),
+ val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"),
+ val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_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)
+{
+ guint32 t2portrxdelay;
+ guint32 t3porttxdelay;
+
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+ /* T2PortRxDelay */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_t2portrxdelay, tvb, offset, 4, ENC_BIG_ENDIAN, &t2portrxdelay);
+ offset += 4;
+
+ /* T3PortTxDelay */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_t3porttxdelay, tvb, offset, 4, ENC_BIG_ENDIAN, &t3porttxdelay);
+ offset += 4;
+
+ proto_item_append_text(item, ": T2PortRxDelay=%uns, T3PortTxDelay=%uns",
+ t2portrxdelay, t3porttxdelay);
+
+ 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];
+
+
+ /* PortMACAddress */
+ offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_port_mac_address, mac);
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+
+ proto_item_append_text(item, ": PortMAC=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", PortMAC=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_PortTime(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item)
+{
+ guint32 t2timestamp;
+
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+ /* T2TimeStamp */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_t2timestamp, tvb, offset, 4, ENC_BIG_ENDIAN, &t2timestamp);
+ offset += 4;
+
+ proto_item_append_text(item, ": T2TimeStamp=%uns", t2timestamp);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", T2TS=%uns", t2timestamp);
+
+ 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;
+ e_guid_t uuid;
+
+ /* OUI already dissected! */
+
+ /* SubType */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_profinet_subtype, &subType);
+ length -= 1;
+
+ switch (subType) {
+ case 1: /* RTData */
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+ /* IRDataUUID */
+ offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_irdata_uuid, &uuid);
+ proto_item_append_text(item, ": IRDataUUID=%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]);
+
+ break;
+ default:
+ offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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;
+
+
+ /* verify remaining TLV length */
+ if (length < 4)
+ {
+ /* too short */
+ offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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:
+ case OUI_PROFINET_MULTICAST:
+ proto_item_append_text(item, ": PROFINET");
+ offset = dissect_PNPTCP_Option_PROFINET(tvb, offset, pinfo, tree, item, length);
+ break;
+ default:
+ /* SubType */
+ offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length);
+ }
+
+ return (offset);
+}
+
+
+static int
+dissect_PNPTCP_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item _U_, gboolean *end, guint16 u16FrameID)
+{
+ 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, ENC_NA);
+ 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 */, ENC_NA);
+ 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_set_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, u16FrameID);
+ 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 0x07: /* PortTime */
+ dissect_PNPTCP_PortTime(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:
+ offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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, guint16 u16FrameID)
+{
+ 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, u16FrameID);
+ }
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_FollowUpPDU(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
+ const char *name, const char *name_short)
+{
+ proto_item *header_item;
+ proto_tree *header_tree;
+ guint16 seq_id;
+ gint32 delay1ns_fup;
+
+
+ /* dissect the header */
+ header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
+ header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
+
+ /* Padding 12 bytes */
+ offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
+
+ /* SequenceID */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
+
+ /* Delay1ns_FUP */
+ proto_tree_add_item_ret_int(header_tree, hf_pn_ptcp_delay1ns_fup, tvb, offset, 4, ENC_BIG_ENDIAN, &delay1ns_fup);
+ offset += 4;
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11dns", name, seq_id, delay1ns_fup);
+ proto_item_append_text(item, "%s: Sequence=%u, Delay=%dns", name_short, seq_id, delay1ns_fup);
+ proto_item_append_text(header_item, ": Sequence=%u, Delay=%dns", seq_id, delay1ns_fup);
+
+
+ /* dissect the TLV blocks */
+ offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_RTSyncPDU(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
+ const char *name, const char *name_short)
+{
+ proto_item *header_item;
+ proto_tree *header_tree;
+ guint32 delay10ns;
+ guint16 seq_id;
+ guint8 delay1ns_8;
+ guint64 delay1ns_64;
+ guint32 delay1ns_32;
+ guint32 delayms;
+
+
+ header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
+ header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
+
+ /* Reserved_1 */
+ proto_tree_add_item(tree, hf_pn_ptcp_res1, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ /* Reserved_2 */
+ proto_tree_add_item(tree, hf_pn_ptcp_res2, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ /* Delay10ns */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_delay10ns, tvb, offset, 4, ENC_BIG_ENDIAN, &delay10ns);
+ offset += 4;
+
+ /* 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_byte, &delay1ns_8);
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
+
+ /* Delay1ns */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_delay1ns, tvb, offset, 4, ENC_BIG_ENDIAN, &delay1ns_32);
+ offset += 4;
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, tree);
+
+
+ delay1ns_64 = ((guint64) delay10ns) * 10 + delay1ns_8 + delay1ns_32;
+ delayms = (guint32) (delay1ns_64 / (1000 * 1000));
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11" G_GINT64_MODIFIER "uns",
+ name, seq_id, delay1ns_64);
+ proto_item_append_text(item, "%s: Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns",
+ name_short, seq_id, delay1ns_64);
+ proto_item_append_text(header_item, ": Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns",
+ seq_id, delay1ns_64);
+
+ if (delay1ns_64 != 0)
+ proto_item_append_text(header_item, " (%u.%03u,%03u,%03u sec)",
+ delayms / 1000,
+ delayms % 1000,
+ (delay10ns % (1000*100)) / 100,
+ delay10ns % 100 * 10 + delay1ns_8);
+
+ /* dissect the PDU */
+ offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_AnnouncePDU(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
+ const char *name, const char *name_short)
+{
+ proto_item *header_item;
+ proto_tree *header_tree;
+ guint16 seq_id;
+
+
+ /* dissect the header */
+ header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
+ header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
+
+ /* Padding 12 bytes */
+ offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
+
+ /* SequenceID */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
+
+ /* Padding 6 bytes */
+ offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 6);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u", name, seq_id);
+ proto_item_append_text(item, "%s: Sequence=%u", name_short, seq_id);
+ proto_item_append_text(header_item, ": Sequence=%u", seq_id);
+
+
+ /* dissect the PDU */
+ offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
+
+ return offset;
+}
+
+
+static int
+dissect_PNPTCP_DelayPDU(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID,
+ const char *name, const char *name_short)
+{
+ proto_item *header_item;
+ proto_tree *header_tree;
+ guint16 seq_id;
+ guint32 delay1ns;
+
+
+ /* dissect the header */
+ header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA);
+ header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header);
+
+ /* Padding 12 bytes */
+ offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12);
+
+ /* SequenceID */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id);
+
+ /* Padding */
+ offset = dissect_pn_align4(tvb, offset, pinfo, header_tree);
+
+ /* Delay1ns_FUP */
+ proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_delay1ns, tvb, offset, 4, ENC_BIG_ENDIAN, &delay1ns);
+ offset += 4;
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11uns", name, seq_id, delay1ns);
+ proto_item_append_text(item, "%s: Sequence=%u, Delay=%uns", name_short, seq_id, delay1ns);
+ proto_item_append_text(header_item, ": Sequence=%u, Delay=%uns", seq_id, delay1ns);
+
+
+ /* dissect the PDU */
+ offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID);
+
+ 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, void *data)
+{
+ /* the tvb will NOT contain the frame_id here, so get it from dissector data! */
+ guint16 u16FrameID = GPOINTER_TO_UINT(data);
+ proto_item *item;
+ proto_tree *ptcp_tree;
+ int offset = 0;
+ guint32 u32SubStart;
+
+
+ /* frame id must be in valid range (acyclic Real-Time, PTCP) */
+ /* 0x0000 - 0x007F: RTSyncPDU (with follow up) */
+ /* 0x0080 - 0x00FF: RTSyncPDU (without follow up) */
+ /* 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;
+ }
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-PTCP");
+ col_clear(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) */
+ /* 0x0000 - 0x001F reserved */
+ case 0x0020:
+ offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "RTSync FU (Clock)", "RTSync FU (Clock)");
+ break;
+ case 0x0021:
+ offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "RTSync FU (Time)", "RTSync FU (Time)");
+ break;
+ /* 0x0022 - 0x007F reserved */
+
+ /* range 2 (0x0080 - 0x00FF) */
+ case 0x0080:
+ offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "RTSync (Clock)", "RTSync (Clock)");
+ break;
+ case 0x0081:
+ offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "RTSync (Time)", "RTSync (Time)");
+ break;
+ /* 0x0081 - 0x00FF reserved */
+
+ /* range 7 (0xFF00 - 0xFF5F) */
+ case 0xff00:
+ offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "Announce (Clock)", "Announce (Clock)");
+ break;
+ case 0xff01:
+ offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "Announce (Time)", "Announce (Time)");
+ break;
+ /* 0xFF02 - 0xFF1F reserved */
+ case 0xff20:
+ offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "FollowUp (Clock)", "FollowUp (Clock)");
+ break;
+ case 0xff21:
+ offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "FollowUp (Time)", "FollowUp (Time)");
+ break;
+ /* 0xFF22 - 0xFF3F reserved */
+ case 0xff40:
+ offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "DelayReq ", "DelayReq");
+ break;
+ case 0xff41:
+ offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "DelayRes ", "DelayRes");
+ break;
+ case 0xff42:
+ offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "DelayFuRes ", "DelayFuRes");
+ break;
+ case 0xff43:
+ offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID,
+ "DelayRes ", "DelayRes");
+ break;
+ /* 0xFF44 - 0xFF5F reserved */
+ default:
+ offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset));
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Reserved FrameID 0x%04x", u16FrameID);
+
+ proto_item_append_text(item, "Reserved FrameID 0x%04x", u16FrameID);
+
+ offset += tvb_captured_length_remaining(tvb, offset);
+ break;
+ }
+
+ proto_item_set_len(item, offset - u32SubStart);
+
+ return TRUE;
+}
+
+
+void
+proto_register_pn_ptcp (void)
+{
+ static hf_register_info hf[] = {
+ { &hf_pn_ptcp_header,
+ { "Header", "pn_ptcp.header",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_block,
+ { "Block", "pn_ptcp.block",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_block_tlvheader,
+ { "TLVHeader", "pn_ptcp.tlvheader",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_res1,
+ { "Reserved 1", "pn_ptcp.res1",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_res2,
+ { "Reserved 2", "pn_ptcp.res2",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_delay10ns,
+ { "Delay10ns", "pn_ptcp.delay10ns",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_seq_id,
+ { "SequenceID", "pn_ptcp.sequence_id",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_delay1ns_byte,
+ { "Delay1ns_Byte", "pn_ptcp.delay1ns_byte",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_delay1ns,
+ { "Delay1ns", "pn_ptcp.delay1ns",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_delay1ns_fup,
+ { "Delay1ns_FUP", "pn_ptcp.delay1ns_fup",
+ FT_INT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_tl_length,
+ { "TypeLength.Length", "pn_ptcp.tl_length",
+ FT_UINT16, BASE_DEC, 0x0, 0x1FF,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_tl_type,
+ { "TypeLength.Type", "pn_ptcp.tl_type",
+ FT_UINT16, BASE_DEC, 0x0, 0xFE00,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_master_source_address,
+ { "MasterSourceAddress", "pn_ptcp.master_source_address",
+ FT_ETHER, BASE_NONE, 0x0, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_subdomain_uuid,
+ { "SubdomainUUID", "pn_ptcp.subdomain_uuid",
+ FT_GUID, BASE_NONE, 0x0, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_port_mac_address,
+ { "PortMACAddress", "pn_ptcp.port_mac_address",
+ FT_ETHER, BASE_NONE, 0x0, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_t2portrxdelay,
+ { "T2PortRxDelay (ns)", "pn_ptcp.t2portrxdelay",
+ FT_UINT32, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_t3porttxdelay,
+ { "T3PortTxDelay (ns)", "pn_ptcp.t3porttxdelay",
+ FT_UINT32, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_t2timestamp,
+ { "T2TimeStamp (ns)", "pn_ptcp.t2timestamp",
+ FT_UINT32, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_epoch_number,
+ { "EpochNumber", "pn_ptcp.epoch_number",
+ FT_UINT16, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_seconds,
+ { "Seconds", "pn_ptcp.seconds",
+ FT_UINT32, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_nanoseconds,
+ { "NanoSeconds", "pn_ptcp.nanoseconds",
+ FT_UINT32, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_flags,
+ { "Flags", "pn_ptcp.flags",
+ FT_UINT16, BASE_HEX, 0x0, 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_currentutcoffset,
+ { "CurrentUTCOffset", "pn_ptcp.currentutcoffset",
+ FT_UINT16, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_master_priority1,
+ { "MasterPriority1.Priority", "pn_ptcp.master_priority1_prio",
+ FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals), 0x07,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_master_priority_level,
+ { "MasterPriority1.Level", "pn_ptcp.master_priority1_level",
+ FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_levels), 0x38,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_master_priority1_res,
+ { "MasterPriority1.Reserved", "pn_ptcp.master_priority1_res",
+ FT_UINT8, BASE_HEX, 0x0, 0x40,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_master_priority1_act,
+ { "MasterPriority1.Active", "pn_ptcp.master_priority1_act",
+ FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals_active), 0x80,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_master_priority2,
+ { "MasterPriority2", "pn_ptcp.master_priority2",
+ FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio2_vals), 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_clock_class,
+ { "ClockClass", "pn_ptcp.clock_class",
+ FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_class_vals), 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_clock_accuracy,
+ { "ClockAccuracy", "pn_ptcp.clock_accuracy",
+ FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_accuracy_vals), 0x0,
+ NULL, HFILL }},
+
+ { &hf_pn_ptcp_clockvariance,
+ { "ClockVariance", "pn_ptcp.clockvariance",
+ FT_INT16, BASE_DEC, 0x0, 0x0,
+ NULL, HFILL }},
+
+
+ { &hf_pn_ptcp_oui,
+ { "Organizationally Unique Identifier", "pn_ptcp.oui",
+ FT_UINT24, BASE_HEX, VALS(pn_ptcp_oui_vals), 0x0,
+ NULL, 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_irdata_uuid,
+ { "IRDataUUID", "pn_ptcp.irdata_uuid",
+ FT_GUID, BASE_NONE, 0x0, 0x0,
+ NULL, 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, "PROFINET PTCP IO", "pn_ptcp_pn_rt", proto_pn_ptcp, HEURISTIC_ENABLE);
+}
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */