aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Lamping <ulf.lamping@web.de>2004-12-06 18:05:14 +0000
committerUlf Lamping <ulf.lamping@web.de>2004-12-06 18:05:14 +0000
commitc87fb7a01034b085ae1feed2c0a799f5291c56a1 (patch)
tree701b7b4f44e82af0cb8bbf81e034a9750b33da72
parentc20df95fd58e7ae78efaa129b4c0629e710156c0 (diff)
(on behalf of the PROFIBUS Nutzerorganisation e.V. Deutschland):
first part of the PROFINET dissectors (PN-RT, PN-DCP and PN-IO) still some work to be done ... svn path=/trunk/; revision=12670
-rw-r--r--epan/dissectors/Makefile.common3
-rw-r--r--epan/dissectors/packet-dcerpc-pn-io.c1339
-rw-r--r--epan/dissectors/packet-pn-dcp.c952
-rw-r--r--epan/dissectors/packet-pn-rt.c449
4 files changed, 2743 insertions, 0 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 822e287705..adaee132cd 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -154,6 +154,7 @@ DISSECTOR_SRC = \
packet-dcerpc-netlogon.c \
packet-dcerpc-nspi.c \
packet-dcerpc-oxid.c \
+ packet-dcerpc-pn-io.c \
packet-dcerpc-rdaclif.c \
packet-dcerpc-reg.c \
packet-dcerpc-remact.c \
@@ -392,6 +393,8 @@ DISSECTOR_SRC = \
packet-pflog.c \
packet-pgm.c \
packet-pim.c \
+ packet-pn-dcp.c \
+ packet-pn-rt.c \
packet-pkcs1.c \
packet-pkix1explicit.c \
packet-pkix1implicit.c \
diff --git a/epan/dissectors/packet-dcerpc-pn-io.c b/epan/dissectors/packet-dcerpc-pn-io.c
new file mode 100644
index 0000000000..30b039d028
--- /dev/null
+++ b/epan/dissectors/packet-dcerpc-pn-io.c
@@ -0,0 +1,1339 @@
+/* packet-dcerpc-pn-io.c
+ * Routines for PROFINET IO dissection
+ * (based on DCE-RPC and PN-RT protocols)
+ *
+ * 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 "packet-dcerpc.h"
+
+
+
+static int proto_pn_io = -1;
+
+static int hf_pn_io_opnum = -1;
+static int hf_pn_io_reserved16 = -1;
+
+static int hf_pn_io_array = -1;
+static int hf_pn_io_status = -1;
+static int hf_pn_io_args_max = -1;
+static int hf_pn_io_args_len = -1;
+static int hf_pn_io_array_max_count = -1;
+static int hf_pn_io_array_offset = -1;
+static int hf_pn_io_array_act_count = -1;
+
+static int hf_pn_io_data = -1;
+
+static int hf_pn_io_ar_uuid = -1;
+static int hf_pn_io_api = -1;
+static int hf_pn_io_slot_nr = -1;
+static int hf_pn_io_subslot_nr = -1;
+static int hf_pn_io_index = -1;
+static int hf_pn_io_seq_number = -1;
+static int hf_pn_io_record_data_length = -1;
+static int hf_pn_io_padding = -1;
+static int hf_pn_io_add_val1 = -1;
+static int hf_pn_io_add_val2 = -1;
+
+static int hf_pn_io_block = -1;
+static int hf_pn_io_block_type = -1;
+static int hf_pn_io_block_length = -1;
+static int hf_pn_io_block_version_high = -1;
+static int hf_pn_io_block_version_low = -1;
+
+static int hf_pn_io_sessionkey = -1;
+static int hf_pn_io_control_command = -1;
+static int hf_pn_io_control_command_prmend = -1;
+static int hf_pn_io_control_command_applready = -1;
+static int hf_pn_io_control_command_release = -1;
+static int hf_pn_io_control_command_done = -1;
+static int hf_pn_io_control_block_properties = -1;
+
+static int hf_pn_io_error_code = -1;
+static int hf_pn_io_error_decode = -1;
+static int hf_pn_io_error_code1 = -1;
+static int hf_pn_io_error_code2 = -1;
+static int hf_pn_io_error_code1_pniorw = -1;
+static int hf_pn_io_error_code1_pnio = -1;
+
+static int hf_pn_io_alarm_type = -1;
+static int hf_pn_io_alarm_specifier = -1;
+static int hf_pn_io_alarm_specifier_sequence = -1;
+static int hf_pn_io_alarm_specifier_channel = -1;
+static int hf_pn_io_alarm_specifier_manufacturer = -1;
+static int hf_pn_io_alarm_specifier_submodule = -1;
+static int hf_pn_io_alarm_specifier_ardiagnosis = -1;
+
+static int hf_pn_io_alarm_dst_endpoint = -1;
+static int hf_pn_io_alarm_src_endpoint = -1;
+static int hf_pn_io_pdu_type = -1;
+static int hf_pn_io_pdu_type_type = -1;
+static int hf_pn_io_pdu_type_version = -1;
+static int hf_pn_io_add_flags = -1;
+static int hf_pn_io_window_size = -1;
+static int hf_pn_io_tack = -1;
+static int hf_pn_io_send_seq_num = -1;
+static int hf_pn_io_ack_seq_num = -1;
+static int hf_pn_io_var_part_len = -1;
+
+static int hf_pn_io_module_ident_number = -1;
+static int hf_pn_io_submodule_ident_number = -1;
+
+static gint ett_pn_io = -1;
+static gint ett_pn_io_block = -1;
+static gint ett_pn_io_status = -1;
+static gint ett_pn_io_rta = -1;
+static gint ett_pn_io_pdu_type = -1;
+static gint ett_pn_io_add_flags = -1;
+static gint ett_pn_io_control_command = -1;
+
+static e_uuid_t uuid_pn_io_device = { 0xDEA00001, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };
+static guint16 ver_pn_io_device = 1;
+
+static e_uuid_t uuid_pn_io_controller = { 0xDEA00002, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };
+static guint16 ver_pn_io_controller = 1;
+
+static e_uuid_t uuid_pn_io_supervisor = { 0xDEA00003, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };
+static guint16 ver_pn_io_supervisor = 1;
+
+static e_uuid_t uuid_pn_io_parameterserver = { 0xDEA00004, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };
+static guint16 ver_pn_io_parameterserver = 1;
+
+
+static const value_string pn_io_block_type[] = {
+ { 0x0000, "Reserved" },
+ { 0x0001, "Alarm Notification High"},
+ { 0x0002, "Alarm Notification Low"},
+ { 0x0008, "WriteRecordReq"},
+ { 0x8008, "WriteRecordRes"},
+ { 0x0009, "ReadRecordReq"},
+ { 0x8009, "ReadRecordRes"},
+ { 0x0010, "ManufacturerSpecificDiagnosisBlock"},
+ { 0x0011, "ChannelDiagnosisBlock"},
+ { 0x0012, "ExpectedIdentificationDataBlock"},
+ { 0x0014, "SubstituteValue RecordDataRead"},
+ { 0x0015, "RecordInputDataObjectElement"},
+ { 0x0016, "RecordOutputDataObjectElement"},
+ { 0x0017, "RecordOutputDataSubstituteObjectElement"},
+ { 0x0018, "ARData"},
+ { 0x0019, "LogData"},
+ { 0x001A, "APIData"},
+ { 0x0020, "I&M0"},
+ { 0x0021, "I&M1"},
+ { 0x0022, "I&M2"},
+ { 0x0023, "I&M3"},
+ { 0x0024, "I&M4"},
+ { 0x8001, "Alarm Ack High"},
+ { 0x8002, "Alarm Ack Low"},
+ { 0x0101, "ARBlockReq"},
+ { 0x8101, "ARBlockRes"},
+ { 0x0102, "IOCRBlockReq"},
+ { 0x8102, "IOCRBlockRes"},
+ { 0x0103, "AlarmCRBlockReq"},
+ { 0x8103, "AlarmCRBlockRes"},
+ { 0x0104, "ExpectedSubmoduleBlockReq"},
+ { 0x8104, "ModuleDiffBlock"},
+ { 0x0105, "PrmServerBlockReq"},
+ { 0x8105, "PrmServerBlockRes"},
+ { 0x0110, "IODBlockReq"},
+ { 0x8110, "IODBlockRes"},
+ { 0x0111, "IODBlockReq"},
+ { 0x8111, "IODBlockRes"},
+ { 0x0112, "IOXBlockReq"},
+ { 0x8112, "IOXBlockRes"},
+ { 0x0113, "IOXBlockReq"},
+ { 0x8113, "IOXBlockRes"},
+ { 0x0114, "ReleaseBlockReq"},
+ { 0x8114, "ReleaseBlockRes"},
+ { 0, NULL }
+};
+
+static const value_string pn_io_alarm_type[] = {
+ { 0x0000, "Reserved" },
+ { 0x0001, "Diagnosis" },
+ { 0x0002, "Process" },
+ { 0x0003, "Pull" },
+ { 0x0004, "Plug" },
+ { 0x0005, "Status" },
+ { 0x0006, "Update" },
+ { 0x0007, "Redundancy" },
+ { 0x0008, "Controlled by supervisor" },
+ { 0x0009, "Released by supervisor" },
+ { 0x000A, "Plug wrong submodule" },
+ { 0x000B, "Return of submodule" },
+ /* 0x000C - 0x001F reserved */
+ /* 0x0020 - 0x007F manufacturer specific */
+ /* 0x0080 - 0x00FF reserved for profiles */
+ /* 0x0100 - 0xFFFF reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_io_pdu_type[] = {
+ { 0x01, "Data-RTA-PDU" },
+ { 0x02, "NACK-RTA-PDU" },
+ { 0x03, "ACK-RTA-PDU" },
+ { 0x04, "ERR-RTA-PDU" },
+ { 0, NULL }
+};
+
+static const value_string pn_io_error_code[] = {
+ { 0x00, "OK" },
+ { 0x81, "PNIO" },
+ { 0xCF, "RTA error" },
+ { 0xDA, "AlarmAck" },
+ { 0xDB, "IODConnectRes" },
+ { 0xDC, "IODReleaseRes" },
+ { 0xDD, "IODControlRes" },
+ { 0xDE, "IODReadRes" },
+ { 0xDF, "IODWriteRes" },
+ { 0, NULL }
+};
+
+static const value_string pn_io_error_decode[] = {
+ { 0x00, "OK" },
+ { 0x80, "PNIORW" },
+ { 0x81, "PNIO" },
+ { 0, NULL }
+};
+
+/*
+XXX: the next 2 are dependant on error_code and error_decode
+
+e.g.: CL-RPC error:
+error_code .. see above
+error_decode .. 0x81
+error_code1 .. 0x69
+error_code2 ..
+1 RPC_ERR_REJECTED
+2 RPC_ERR_FAULTED
+3 RPC_ERR_TIMEOUT
+4 RPC_ERR_IN_ARGS
+5 RPC_ERR_OUT_ARGS
+6 RPC_ERR_DECODE
+7 RPC_ERR_PNIO_OUT_ARGS
+8 Application Timeout
+*/
+
+/* XXX: add some more error codes here */
+static const value_string pn_io_error_code1[] = {
+ { 0x00, "OK" },
+ { 0, NULL }
+};
+
+/* XXX: add some more error codes here */
+static const value_string pn_io_error_code2[] = {
+ { 0x00, "OK" },
+ { 0, NULL }
+};
+
+static const value_string pn_io_error_code1_pniorw[] = {
+ { 0x0a /* 10*/, "application" },
+ { 0x0b /* 11*/, "access" },
+ { 0x0c /* 12*/, "resource" },
+ { 0x0d /* 13*/, "user specific(13)" },
+ { 0x0e /* 14*/, "user specific(14)" },
+ { 0x0f /* 15*/, "user specific(15)" },
+ { 0, NULL }
+};
+
+static const value_string pn_io_error_code1_pnio[] = {
+ { 0x00 /* 0*/, "Reserved" },
+ { 0x01 /* 1*/, "Connect: Faulty ARBlockReq" },
+ { 0x02 /* 2*/, "Connect: Faulty IOCRBlockReq" },
+ { 0x03 /* 3*/, "Connect: Faulty ExpectedSubmoduleBlockReq" },
+ { 0x04 /* 4*/, "Connect: Faulty AlarmCRBlockReq" },
+ { 0x05 /* 5*/, "Connect: Faulty PrmServerBlockReq" },
+
+ { 0x14 /* 20*/, "IODControl: Faulty ControlBlockConnect" },
+ { 0x15 /* 21*/, "IODControl: Faulty ControlBlockPlug" },
+ { 0x16 /* 22*/, "IOXControl: Faulty ControlBlock after a connect est." },
+ { 0x17 /* 23*/, "IOXControl: Faulty ControlBlock a plug alarm" },
+
+ { 0x28 /* 40*/, "Release: Faulty ReleaseBlock" },
+
+ { 0x3c /* 60*/, "AlarmAck Error Codes" },
+ { 0x3d /* 61*/, "CMDEV" },
+ { 0x3e /* 62*/, "CMCTL" },
+ { 0x3f /* 63*/, "NRPM" },
+ { 0x40 /* 64*/, "RMPM" },
+ { 0x41 /* 65*/, "ALPMI" },
+ { 0x42 /* 66*/, "ALPMR" },
+ { 0x43 /* 67*/, "LMPM" },
+ { 0x44 /* 68*/, "MMAC" },
+ { 0x45 /* 69*/, "RPC" },
+ { 0x46 /* 70*/, "APMR" },
+ { 0x47 /* 71*/, "APMS" },
+ { 0x48 /* 72*/, "CPM" },
+ { 0x49 /* 73*/, "PPM" },
+ { 0x4a /* 74*/, "DCPUCS" },
+ { 0x4b /* 75*/, "DCPUCR" },
+ { 0x4c /* 76*/, "DCPMCS" },
+ { 0x4d /* 77*/, "DCPMCR" },
+ { 0x4e /* 78*/, "FSPM" },
+ { 0xfd /*253*/, "RTA_ERR_CLS_PROTOCOL" },
+ { 0, NULL }
+};
+
+
+
+/* dissect the four status (error) fields */
+static int
+dissect_PNIO_status(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint8 u8ErrorCode;
+ guint8 u8ErrorDecode;
+ guint8 u8ErrorCode1;
+ guint8 u8ErrorCode2;
+
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+ guint32 u32SubStart;
+ int bytemask = (drep[0] & 0x10) ? 3 : 0;
+ const value_string *error_code1_vals;
+
+
+
+ /* status */
+ sub_item = proto_tree_add_item(tree, hf_pn_io_status, tvb, offset, 0, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_status);
+ u32SubStart = offset;
+
+ /* the PNIOStatus field is existing in both the RPC and the application data,
+ * depending on the current PDU.
+ * As the byte representation of these layers are different, this has to be handled
+ * in a somewhat different way than elsewhere. */
+
+ dissect_dcerpc_uint8(tvb, offset+(0^bytemask), pinfo, sub_tree, drep,
+ hf_pn_io_error_code, &u8ErrorCode);
+ dissect_dcerpc_uint8(tvb, offset+(1^bytemask), pinfo, sub_tree, drep,
+ hf_pn_io_error_decode, &u8ErrorDecode);
+
+ switch(u8ErrorDecode) {
+ case(0x80): /* PNIORW */
+ dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep,
+ hf_pn_io_error_code1_pniorw, &u8ErrorCode1);
+ error_code1_vals = pn_io_error_code1_pniorw;
+ break;
+ case(0x81): /* PNIO */
+ dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep,
+ hf_pn_io_error_code1_pnio, &u8ErrorCode1);
+ error_code1_vals = pn_io_error_code1_pnio;
+ break;
+ default:
+ dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep,
+ hf_pn_io_error_code1, &u8ErrorCode1);
+ error_code1_vals = pn_io_error_code1;
+ }
+
+ /* XXX - this has to be decode specific too */
+ dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep,
+ hf_pn_io_error_code2, &u8ErrorCode2);
+
+ offset +=4;
+
+ if(u8ErrorCode == 0 && u8ErrorDecode == 0 && u8ErrorCode1 == 0 && u8ErrorCode2 == 0) {
+ proto_item_append_text(sub_item, ": OK");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", OK");
+ } else {
+ proto_item_append_text(sub_item, ": Error Code: \"%s\", Decode: \"%s\", Code1: \"%s\" Code2: 0x%x",
+ val_to_str(u8ErrorCode, pn_io_error_code, "(0x%x)"),
+ val_to_str(u8ErrorDecode, pn_io_error_decode, "(0x%x)"),
+ val_to_str(u8ErrorCode1, error_code1_vals, "(0x%x)"),
+ u8ErrorCode2);
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Error Code: %s, Decode: %s, Code1: 0x%x Code2: 0x%x",
+ val_to_str(u8ErrorCode, pn_io_error_code, "(0x%x)"),
+ val_to_str(u8ErrorDecode, pn_io_error_decode, "(0x%x)"),
+ u8ErrorCode1,
+ u8ErrorCode2);
+ }
+ proto_item_set_len(sub_item, offset - u32SubStart);
+
+ return offset;
+}
+
+
+/* dissect the alarm specifier */
+static int
+dissect_Alarm_specifier(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint16 u16AlarmSpecifierSequence;
+ guint16 u16AlarmSpecifierChannel;
+ guint16 u16AlarmSpecifierManufacturer;
+ guint16 u16AlarmSpecifierSubmodule;
+ guint16 u16AlarmSpecifierAR;
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+
+ /* alarm specifier */
+ sub_item = proto_tree_add_item(tree, hf_pn_io_alarm_specifier, tvb, offset, 2, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_pdu_type);
+
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_alarm_specifier_sequence, &u16AlarmSpecifierSequence);
+ u16AlarmSpecifierSequence &= 0x07FF;
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_alarm_specifier_channel, &u16AlarmSpecifierChannel);
+ u16AlarmSpecifierChannel = (u16AlarmSpecifierChannel &0x0800) >> 11;
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_alarm_specifier_manufacturer, &u16AlarmSpecifierManufacturer);
+ u16AlarmSpecifierManufacturer = (u16AlarmSpecifierManufacturer &0x1000) >> 12;
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_alarm_specifier_submodule, &u16AlarmSpecifierSubmodule);
+ u16AlarmSpecifierSubmodule = (u16AlarmSpecifierSubmodule & 0x2000) >> 13;
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_alarm_specifier_ardiagnosis, &u16AlarmSpecifierAR);
+ u16AlarmSpecifierAR = (u16AlarmSpecifierAR & 0x8000) >> 15;
+
+
+ proto_item_append_text(sub_item, ", Sequence: %u, Channel: %u, Manuf: %u, Submodule: %u AR: %u",
+ u16AlarmSpecifierSequence, u16AlarmSpecifierChannel,
+ u16AlarmSpecifierManufacturer, u16AlarmSpecifierSubmodule, u16AlarmSpecifierAR);
+
+ return offset;
+}
+
+
+/* dissect the alarm header */
+static int
+dissect_Alarm_header(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint16 u16AlarmType;
+ guint32 u32Api;
+ guint16 u16SlotNr;
+ guint16 u16SubslotNr;
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_alarm_type, &u16AlarmType);
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_api, &u32Api);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_slot_nr, &u16SlotNr);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_subslot_nr, &u16SubslotNr);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Slot: %u/%u",
+ val_to_str(u16AlarmType, pn_io_alarm_type, "Unknown"),
+ u16SlotNr, u16SubslotNr);
+
+ return offset;
+}
+
+
+/* dissect the alarm note block */
+static int
+dissect_Alarm_note_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep, guint16 body_length)
+{
+ guint32 u32ModuleIdentNumber;
+ guint32 u32SubmoduleIdentNumber;
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", Alarm Notification");
+
+ offset = dissect_Alarm_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_module_ident_number, &u32ModuleIdentNumber);
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_submodule_ident_number, &u32SubmoduleIdentNumber);
+
+ offset = dissect_Alarm_specifier(tvb, offset, pinfo, tree, drep);
+
+ /* XXX - dissect AlarmItem */
+ body_length -= 20;
+ proto_tree_add_string_format(tree, hf_pn_io_data, tvb, offset, body_length, "data",
+ "Alarm Item Data: %u bytes", body_length);
+ offset += body_length;
+
+ return offset;
+}
+
+
+/* dissect the alarm acknowledge block */
+static int
+dissect_Alarm_ack_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", Alarm Ack");
+
+ offset = dissect_Alarm_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_Alarm_specifier(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect the read/write header */
+static int
+dissect_ReadWrite_header(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ e_uuid_t uuid;
+ guint32 u32Api;
+ guint16 u16SlotNr;
+ guint16 u16SubslotNr;
+ guint16 u16Index;
+ guint16 u16SeqNr;
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_seq_number, &u16SeqNr);
+
+ offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_ar_uuid, &uuid);
+
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_api, &u32Api);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_slot_nr, &u16SlotNr);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_subslot_nr, &u16SubslotNr);
+ proto_tree_add_string_format(tree, hf_pn_io_padding, tvb, offset, 2, "padding", "Padding: 2 bytes");
+ offset += 2;
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_index, &u16Index);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Api: %u, Slot: %u/%u",
+ u32Api, u16SlotNr, u16SubslotNr);
+
+ return offset;
+}
+
+
+/* dissect the read/write request block */
+static int
+dissect_ReadWrite_rqst_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint32 u32RecDataLen;
+
+
+ offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_record_data_length, &u32RecDataLen);
+ /* XXX: don't know how to handle the optional TargetARUUID */
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes",
+ u32RecDataLen);
+
+ return offset;
+}
+
+
+/* dissect the read/write response block */
+static int
+dissect_ReadWrite_resp_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint32 u32RecDataLen;
+ guint16 u16AddVal1;
+ guint16 u16AddVal2;
+
+
+ offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_record_data_length, &u32RecDataLen);
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_add_val1, &u16AddVal1);
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_add_val2, &u16AddVal2);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes",
+ u32RecDataLen);
+
+ return offset;
+}
+
+
+/* dissect the control/connect block */
+static int
+dissect_ControlConnect_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ e_uuid_t ar_uuid;
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+ guint16 u16PrmEnd;
+ guint16 u16ApplReady;
+ guint16 u16Release;
+ guint16 u16CmdDone;
+
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_reserved16, NULL);
+
+ offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_ar_uuid, &ar_uuid);
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_sessionkey, NULL);
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_reserved16, NULL);
+
+ sub_item = proto_tree_add_item(tree, hf_pn_io_control_command, tvb, offset, 2, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_control_command);
+
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_control_command_prmend, &u16PrmEnd);
+ if(u16PrmEnd & 0x0001) {
+ proto_item_append_text(sub_item, ", Parameter End");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Parameter End\"");
+ }
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_control_command_applready, &u16ApplReady);
+ if((u16ApplReady >> 1) & 0x0001) {
+ proto_item_append_text(sub_item, ", Application Ready");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Application Ready\"");
+ }
+ dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_control_command_release, &u16Release);
+ if((u16Release >> 2) & 0x0001) {
+ proto_item_append_text(sub_item, ", Release");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Release\"");
+ }
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_control_command_done, &u16CmdDone);
+ if((u16CmdDone >> 3) & 0x0001) {
+ proto_item_append_text(sub_item, ", Done");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Done\"");
+ }
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_control_block_properties, NULL);
+
+ return offset;
+}
+
+
+/* dissect one PN-IO block (depending on the block type) */
+static int
+dissect_block(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep, guint32 u32Idx)
+{
+ guint16 u16BlockType;
+ guint16 u16BlockLength;
+ guint8 u8BlockVersionHigh;
+ guint8 u8BlockVersionLow;
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+ guint32 u32SubStart;
+ guint16 u16BodyLength;
+
+
+ /* from here, we only have big endian (network byte ordering) */
+ drep[0] &= ~0x10;
+
+ sub_item = proto_tree_add_item(tree, hf_pn_io_block, tvb, offset, 0, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_block);
+ u32SubStart = offset;
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_block_type, &u16BlockType);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_block_length, &u16BlockLength);
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_block_version_high, &u8BlockVersionHigh);
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_block_version_low, &u8BlockVersionLow);
+
+ /* block length is without type and length fields, but with version field */
+ /* as it's already dissected, remove it */
+ u16BodyLength = u16BlockLength - 2;
+
+ switch(u16BlockType) {
+ case(0x0001):
+ case(0x0002):
+ dissect_Alarm_note_block(tvb, offset, pinfo, sub_tree, drep, u16BodyLength);
+ break;
+ case(0x0110):
+ case(0x0112):
+ case(0x0114):
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ val_to_str(u16BlockType, pn_io_block_type, "Unknown"));
+ dissect_ControlConnect_block(tvb, offset, pinfo, sub_tree, drep);
+ break;
+ case(0x0008):
+ case(0x0009):
+ dissect_ReadWrite_rqst_block(tvb, offset, pinfo, sub_tree, drep);
+ break;
+ case(0x8001):
+ case(0x8002):
+ dissect_Alarm_ack_block(tvb, offset, pinfo, sub_tree, drep);
+ break;
+ case(0x8008):
+ case(0x8009):
+ dissect_ReadWrite_resp_block(tvb, offset, pinfo, sub_tree, drep);
+ break;
+ case(0x8110):
+ case(0x8112):
+ case(0x8114):
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ val_to_str(u16BlockType, pn_io_block_type, "Unknown"));
+ dissect_ControlConnect_block(tvb, offset, pinfo, sub_tree, drep);
+ break;
+ default:
+ if (check_col(pinfo->cinfo, COL_INFO) && u32Idx < 3)
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
+ val_to_str(u16BlockType, pn_io_block_type, "Unknown"));
+ proto_tree_add_string_format(sub_tree, hf_pn_io_data, tvb, offset, u16BodyLength, "undecoded", "Undecoded Data: %d bytes", u16BodyLength);
+ }
+ offset += u16BodyLength;
+
+ proto_item_append_text(sub_item, "[%u]: Type=\"%s\" (0x%04x), Length=%u(+4), Version=%u.%u",
+ u32Idx, val_to_str(u16BlockType, pn_io_block_type, "Unknown"), u16BlockType,
+ u16BlockLength, u8BlockVersionHigh, u8BlockVersionLow);
+ proto_item_set_len(sub_item, offset - u32SubStart);
+
+ return offset;
+}
+
+
+/* dissect any number of PN-IO blocks */
+static int
+dissect_blocks(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint32 u32Idx = 0;
+
+
+ while(tvb_length(tvb) > (guint) offset) {
+ offset = dissect_block(tvb, offset, pinfo, tree, drep, u32Idx);
+ u32Idx++;
+ }
+
+ if(u32Idx > 3) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", ... (%u blocks)",
+ u32Idx);
+ }
+ return offset;
+}
+
+
+/* dissect a PN-IO (DCE-RPC) request header */
+static int
+dissect_IPNIO_rqst_header(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint32 u32ArgsMax;
+ guint32 u32ArgsLen;
+ guint32 u32MaxCount;
+ guint32 u32Offset;
+ guint32 u32ArraySize;
+
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+ guint32 u32SubStart;
+
+
+ /* args_max */
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_args_max, &u32ArgsMax);
+ /* args_len */
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_args_len, &u32ArgsLen);
+
+ sub_item = proto_tree_add_item(tree, hf_pn_io_array, tvb, offset, 0, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io);
+ u32SubStart = offset;
+
+ /* RPC array header */
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_array_max_count, &u32MaxCount);
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_array_offset, &u32Offset);
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_array_act_count, &u32ArraySize);
+
+ proto_item_append_text(sub_item, ": Max: %u, Offset: %u, Size: %u",
+ u32MaxCount, u32Offset, u32ArraySize);
+ proto_item_set_len(sub_item, offset - u32SubStart);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO (DCE-RPC) response header */
+static int
+dissect_IPNIO_resp_header(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint32 u32ArgsLen;
+ guint32 u32MaxCount;
+ guint32 u32Offset;
+ guint32 u32ArraySize;
+
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+ guint32 u32SubStart;
+
+ offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep);
+
+ /* args_len */
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
+ hf_pn_io_args_len, &u32ArgsLen);
+
+ sub_item = proto_tree_add_item(tree, hf_pn_io_array, tvb, offset, 0, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io);
+ u32SubStart = offset;
+
+ /* RPC array header */
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_array_max_count, &u32MaxCount);
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_array_offset, &u32Offset);
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_array_act_count, &u32ArraySize);
+
+ proto_item_append_text(sub_item, ": Max: %u, Offset: %u, Size: %u",
+ u32MaxCount, u32Offset, u32ArraySize);
+ proto_item_set_len(sub_item, offset - u32SubStart);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO connect request */
+static int
+dissect_IPNIO_Connect_rqst(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_blocks(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO connect response */
+static int
+dissect_IPNIO_Connect_resp(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_blocks(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO release request */
+static int
+dissect_IPNIO_Release_rqst(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_blocks(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO release response */
+static int
+dissect_IPNIO_Release_resp(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_blocks(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO control request */
+static int
+dissect_IPNIO_Control_rqst(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_blocks(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO control response */
+static int
+dissect_IPNIO_Control_resp(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_blocks(tvb, offset, pinfo, tree, drep);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO read request */
+static int
+dissect_IPNIO_Read_rqst(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO read response */
+static int
+dissect_IPNIO_Read_resp(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ gint remain;
+
+ offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);
+
+ /* XXX - remaining bytes: dissection not yet implemented */
+ remain = tvb_length_remaining(tvb, offset);
+ proto_tree_add_string_format(tree, hf_pn_io_data, tvb, offset, remain, "data", "User Data: %d bytes", remain);
+ offset += remain;
+
+ return offset;
+}
+
+
+/* dissect a PN-IO write request */
+static int
+dissect_IPNIO_Write_rqst(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ gint remain;
+
+ offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);
+
+ /* XXX - remaining bytes: dissection not yet implemented */
+ remain = tvb_length_remaining(tvb, offset);
+ proto_tree_add_string_format(tree, hf_pn_io_data, tvb, offset, remain, "data", "User Data: %d bytes", remain);
+ offset += remain;
+
+ return offset;
+}
+
+
+/* dissect a PN-IO write response */
+static int
+dissect_IPNIO_Write_resp(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+
+ offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);
+
+ offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);
+
+ return offset;
+}
+
+
+/* dissect a PN-IO Data PDU (on top of PN-RT protocol) */
+static int
+dissect_PNIO_Data(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ proto_item *data_item;
+/* proto_tree *data_tree;*/
+
+ data_item = proto_tree_add_protocol_format(tree, proto_pn_io, tvb, 0, tvb_length(tvb),
+ "PROFINET IO Data: %u bytes", tvb_length(tvb));
+#if 0
+ data_tree = proto_item_add_subtree(data_item, ett_pn_io_rta);
+
+ /* XXX - remaining bytes: dissection not yet implemented */
+ proto_tree_add_string_format(data_tree, hf_pn_io_data, tvb, 0, tvb_length(tvb), "data",
+ "PN-IO Data: %u bytes", tvb_length(tvb));
+#endif
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_add_str(pinfo->cinfo, COL_PROTOCOL, "PNIO");
+
+ return offset;
+}
+
+
+/* dissect a PN-IO RTA PDU (on top of PN-RT protocol) */
+static int
+dissect_PNIO_RTA(tvbuff_t *tvb, int offset,
+ packet_info *pinfo, proto_tree *tree, guint8 *drep)
+{
+ guint16 u16AlarmDstEndpoint;
+ guint16 u16AlarmSrcEndpoint;
+ guint8 u8PDUType;
+ guint8 u8PDUVersion;
+ guint8 u8WindowSize;
+ guint8 u8Tack;
+ guint16 u16SendSeqNum;
+ guint16 u16AckSeqNum;
+ guint16 u16VarPartLen;
+
+ proto_item *rta_item;
+ proto_tree *rta_tree;
+
+ proto_item *sub_item;
+ proto_tree *sub_tree;
+
+ rta_item = proto_tree_add_protocol_format(tree, proto_pn_io, tvb, 0, 0,
+ "PROFINET IO Alarm");
+ rta_tree = proto_item_add_subtree(rta_item, ett_pn_io_rta);
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep,
+ hf_pn_io_alarm_dst_endpoint, &u16AlarmDstEndpoint);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep,
+ hf_pn_io_alarm_src_endpoint, &u16AlarmSrcEndpoint);
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: 0x%x, Dst: 0x%x",
+ u16AlarmSrcEndpoint, u16AlarmDstEndpoint);
+
+ /* PDU type */
+ sub_item = proto_tree_add_item(rta_tree, hf_pn_io_pdu_type, tvb, offset, 1, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_pdu_type);
+ dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_pdu_type_type, &u8PDUType);
+ u8PDUType &= 0x0F;
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_pdu_type_version, &u8PDUVersion);
+ u8PDUVersion >>= 4;
+ proto_item_append_text(sub_item, ", Type: %s, Version: %u",
+ val_to_str(u8PDUType, pn_io_pdu_type, "Unknown"),
+ u8PDUVersion);
+
+ /* additional flags */
+ sub_item = proto_tree_add_item(rta_tree, hf_pn_io_add_flags, tvb, offset, 1, FALSE);
+ sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_add_flags);
+ dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_window_size, &u8WindowSize);
+ u8WindowSize &= 0x0F;
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep,
+ hf_pn_io_tack, &u8Tack);
+ u8Tack >>= 4;
+ proto_item_append_text(sub_item, ", Window Size: %u, Tack: %u",
+ u8WindowSize, u8Tack);
+
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep,
+ hf_pn_io_send_seq_num, &u16SendSeqNum);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep,
+ hf_pn_io_ack_seq_num, &u16AckSeqNum);
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep,
+ hf_pn_io_var_part_len, &u16VarPartLen);
+
+ switch(u8PDUType & 0x0F) {
+ case(1): /* Data-RTA */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", Data-RTA");
+ offset = dissect_block(tvb, offset, pinfo, rta_tree, drep, 0);
+ break;
+ case(2): /* NACK-RTA */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", NACK-RTA");
+ /* no additional data */
+ break;
+ case(3): /* ACK-RTA */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", ACK-RTA");
+ /* no additional data */
+ break;
+ case(4): /* ERR-RTA */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, ", ERR-RTA");
+ offset = dissect_PNIO_status(tvb, offset, pinfo, rta_tree, drep);
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_io_data, tvb, 0, tvb_length(tvb), "data",
+ "PN-IO Alarm: unknown PDU type 0x%x", u8PDUType);
+ }
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_add_str(pinfo->cinfo, COL_PROTOCOL, "PNIO-AL");
+
+ return offset;
+}
+
+
+/* possibly dissect a PN-IO PN-RT packet */
+static gboolean
+dissect_PNIO_heur(tvbuff_t *tvb,
+ packet_info *pinfo, proto_tree *tree)
+{
+ guint8 drep_data = 0;
+ guint8 *drep = &drep_data;
+ guint8 u8CBAVersion;
+ guint16 u16FrameID;
+
+
+ /* the sub tvb will NOT contain the frame_id here! */
+ u16FrameID = GPOINTER_TO_INT(pinfo->private_data);
+
+ u8CBAVersion = tvb_get_guint8 (tvb, 0);
+
+ /* is this a PNIO class 2 data packet? */
+ /* frame id must be in valid range (cyclic Real-Time, class=2) */
+ if (u16FrameID >= 0x8000 && u16FrameID < 0xbf00) {
+ dissect_PNIO_Data(tvb, 0, pinfo, tree, drep);
+ return TRUE;
+ }
+
+ /* is this a PNIO class 1 data packet? */
+ /* frame id must be in valid range (cyclic Real-Time, class=1) and
+ * first byte (CBA version field) has to be != 0x11 */
+ if (u16FrameID >= 0xc000 && u16FrameID < 0xfb00 && u8CBAVersion != 0x11) {
+ dissect_PNIO_Data(tvb, 0, pinfo, tree, drep);
+ return TRUE;
+ }
+
+ /* is this a PNIO high priority alarm packet? */
+ if(u16FrameID == 0xfc01) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_str(pinfo->cinfo, COL_INFO, "Alarm High");
+
+ dissect_PNIO_RTA(tvb, 0, pinfo, tree, drep);
+ return TRUE;
+ }
+
+ /* is this a PNIO low priority alarm packet? */
+ if(u16FrameID == 0xfe01) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_str(pinfo->cinfo, COL_INFO, "Alarm Low");
+
+ dissect_PNIO_RTA(tvb, 0, pinfo, tree, drep);
+ return TRUE;
+ }
+
+ /* this PN-RT packet doesn't seem to be PNIO specific */
+ return FALSE;
+}
+
+
+/* the PNIO dcerpc interface table */
+static dcerpc_sub_dissector pn_io_dissectors[] = {
+{ 0, "Connect", dissect_IPNIO_Connect_rqst, dissect_IPNIO_Connect_resp },
+{ 1, "Release", dissect_IPNIO_Release_rqst, dissect_IPNIO_Release_resp },
+{ 2, "Read", dissect_IPNIO_Read_rqst, dissect_IPNIO_Read_resp },
+{ 3, "Write", dissect_IPNIO_Write_rqst, dissect_IPNIO_Write_resp },
+{ 4, "Control", dissect_IPNIO_Control_rqst, dissect_IPNIO_Control_resp },
+ { 0, NULL, NULL, NULL }
+};
+
+
+void
+proto_register_pn_io (void)
+{
+ static hf_register_info hf[] = {
+ { &hf_pn_io_opnum,
+ { "Operation", "pn_io.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_reserved16,
+ { "Reserved", "pn_io.reserved16", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_array,
+ { "Array", "pn_io.array", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_status,
+ { "Status", "pn_io.status", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_args_max,
+ { "ArgsMaximum", "pn_io.args_max", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_args_len,
+ { "ArgsLength", "pn_io.args_len", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_array_max_count,
+ { "MaximumCount", "pn_io.array_max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_array_offset,
+ { "Offset", "pn_io.array_offset", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_array_act_count,
+ { "ActualCount", "pn_io.array_act_count", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_ar_uuid,
+ { "ARUUID", "pn_io.ar_uuid", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_api,
+ { "API", "pn_io.api", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_slot_nr,
+ { "SlotNumber", "pn_io.slot_nr", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_subslot_nr,
+ { "SubslotNumber", "pn_io.subslot_nr", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_index,
+ { "Index", "pn_io.index", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_seq_number,
+ { "SeqNumber", "pn_io.seq_number", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_record_data_length,
+ { "RecordDataLength", "pn_io.record_data_length", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_padding,
+ { "Padding", "pn_io.padding", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_add_val1,
+ { "AdditionalValue1", "pn_io.add_val1", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_add_val2,
+ { "AdditionalValue2", "pn_io.add_val2", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_block_type,
+ { "BlockType", "pn_io.block_type", FT_UINT16, BASE_HEX, VALS(pn_io_block_type), 0x0, "", HFILL }},
+ { &hf_pn_io_block_length,
+ { "BlockLength", "pn_io.block_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_block_version_high,
+ { "BlockVersionHigh", "pn_io.block_version_high", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_block_version_low,
+ { "BlockVersionLow", "pn_io.block_version_low", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_sessionkey,
+ { "SessionKey", "pn_io.session_key", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_control_command,
+ { "ControlCommand", "pn_io.control_command", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_control_command_prmend,
+ { "PrmEnd", "pn_io.control_command.prmend", FT_UINT16, BASE_DEC, NULL, 0x0001, "", HFILL }},
+ { &hf_pn_io_control_command_applready,
+ { "ApplicationReady", "pn_io.control_command.applready", FT_UINT16, BASE_DEC, NULL, 0x0002, "", HFILL }},
+ { &hf_pn_io_control_command_release,
+ { "Release", "pn_io.control_command.release", FT_UINT16, BASE_DEC, NULL, 0x0004, "", HFILL }},
+ { &hf_pn_io_control_command_done,
+ { "Done", "pn_io.control_command.done", FT_UINT16, BASE_DEC, NULL, 0x0008, "", HFILL }},
+ { &hf_pn_io_control_block_properties,
+ { "ControlBlockProperties", "pn_io.control_block_properties", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+
+ { &hf_pn_io_error_code,
+ { "ErrorCode", "pn_io.error_code", FT_UINT8, BASE_HEX, VALS(pn_io_error_code), 0x0, "", HFILL }},
+ { &hf_pn_io_error_decode,
+ { "ErrorDecode", "pn_io.error_decode", FT_UINT8, BASE_HEX, VALS(pn_io_error_decode), 0x0, "", HFILL }},
+ { &hf_pn_io_error_code1,
+ { "ErrorCode1", "pn_io.error_code1", FT_UINT8, BASE_HEX, VALS(pn_io_error_code1), 0x0, "", HFILL }},
+ { &hf_pn_io_error_code2,
+ { "ErrorCode2", "pn_io.error_code2", FT_UINT8, BASE_HEX, VALS(pn_io_error_code2), 0x0, "", HFILL }},
+ { &hf_pn_io_error_code1_pniorw,
+ { "ErrorCode1 (PNIORW)", "pn_io.error_code1", FT_UINT8, BASE_HEX, VALS(pn_io_error_code1_pniorw), 0x0, "", HFILL }},
+ { &hf_pn_io_error_code1_pnio,
+ { "ErrorCode1 (PNIO)", "pn_io.error_code1", FT_UINT8, BASE_HEX, VALS(pn_io_error_code1_pnio), 0x0, "", HFILL }},
+ { &hf_pn_io_block,
+ { "Block", "pn_io.block", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_data,
+ { "Undecoded Data", "pn_io.data", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},
+
+ { &hf_pn_io_alarm_type,
+ { "AlarmType", "pn_io.alarm_type", FT_UINT16, BASE_HEX, VALS(pn_io_alarm_type), 0x0, "", HFILL }},
+
+ { &hf_pn_io_alarm_specifier,
+ { "AlarmSpecifier", "pn_io.alarm_specifier", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_alarm_specifier_sequence,
+ { "SequenceNumber", "pn_io.alarm_specifier.sequence", FT_UINT16, BASE_HEX, NULL, 0x07FF, "", HFILL }},
+ { &hf_pn_io_alarm_specifier_channel,
+ { "ChannelDiagnosis", "pn_io.alarm_specifier.channel", FT_UINT16, BASE_HEX, NULL, 0x0800, "", HFILL }},
+ { &hf_pn_io_alarm_specifier_manufacturer,
+ { "ManufacturerSpecificDiagnosis", "pn_io.alarm_specifier.manufacturer", FT_UINT16, BASE_HEX, NULL, 0x1000, "", HFILL }},
+ { &hf_pn_io_alarm_specifier_submodule,
+ { "SubmoduleDiagnosisState", "pn_io.alarm_specifier.submodule", FT_UINT16, BASE_HEX, NULL, 0x2000, "", HFILL }},
+ { &hf_pn_io_alarm_specifier_ardiagnosis,
+ { "ARDiagnosisState", "pn_io.alarm_specifier.ardiagnosis", FT_UINT16, BASE_HEX, NULL, 0x8000, "", HFILL }},
+
+ { &hf_pn_io_alarm_dst_endpoint,
+ { "AlarmDstEndpoint", "pn_io.alarm_dst_endpoint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_alarm_src_endpoint,
+ { "AlarmSrcEndpoint", "pn_io.alarm_src_endpoint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_pdu_type,
+ { "PDUType", "pn_io.pdu_type", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_pdu_type_type,
+ { "Type", "pn_io.pdu_type.type", FT_UINT8, BASE_HEX, VALS(pn_io_pdu_type), 0x0F, "", HFILL }},
+ { &hf_pn_io_pdu_type_version,
+ { "Version", "pn_io.pdu_type.version", FT_UINT8, BASE_HEX, NULL, 0xF0, "", HFILL }},
+ { &hf_pn_io_add_flags,
+ { "AddFlags", "pn_io.add_flags", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_window_size,
+ { "WindowSize", "pn_io.window_size", FT_UINT8, BASE_DEC, NULL, 0x0F, "", HFILL }},
+ { &hf_pn_io_tack,
+ { "TACK", "pn_io.tack", FT_UINT8, BASE_HEX, NULL, 0xF0, "", HFILL }},
+ { &hf_pn_io_send_seq_num,
+ { "SendSeqNum", "pn_io.send_seq_num", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_ack_seq_num,
+ { "AckSeqNum", "pn_io.ack_seq_num", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_var_part_len,
+ { "VarPartLen", "pn_io.var_part_len", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_module_ident_number,
+ { "ModuleIdentNumber", "pn_io.module_ident_number", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_io_submodule_ident_number,
+ { "SubmoduleIdentNumber", "pn_io.submodule_ident_number", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}
+ };
+
+ static gint *ett[] = {
+ &ett_pn_io,
+ &ett_pn_io_block,
+ &ett_pn_io_status,
+ &ett_pn_io_rta,
+ &ett_pn_io_pdu_type,
+ &ett_pn_io_add_flags,
+ &ett_pn_io_control_command
+ };
+ proto_pn_io = proto_register_protocol ("PROFINET IO", "PNIO-CM", "pn_io");
+ proto_register_field_array (proto_pn_io, hf, array_length (hf));
+ proto_register_subtree_array (ett, array_length (ett));
+}
+
+void
+proto_reg_handoff_pn_io (void)
+{
+ /* Register the protocols as dcerpc */
+ dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_device, ver_pn_io_device, pn_io_dissectors, hf_pn_io_opnum);
+ dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_controller, ver_pn_io_controller, pn_io_dissectors, hf_pn_io_opnum);
+ dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_supervisor, ver_pn_io_supervisor, pn_io_dissectors, hf_pn_io_opnum);
+ dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_parameterserver, ver_pn_io_parameterserver, pn_io_dissectors, hf_pn_io_opnum);
+
+ heur_dissector_add("pn_rt", dissect_PNIO_heur, proto_pn_io);
+}
diff --git a/epan/dissectors/packet-pn-dcp.c b/epan/dissectors/packet-pn-dcp.c
new file mode 100644
index 0000000000..9c1cec1ef4
--- /dev/null
+++ b/epan/dissectors/packet-pn-dcp.c
@@ -0,0 +1,952 @@
+/* packet-pn-dcp.c
+ * Routines for PN-DCP (PROFINET Discovery and basic Configuration Protocol)
+ * packet dissection.
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * 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.
+ */
+
+#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 "packet-dcerpc.h"
+
+static int proto_pn_dcp = -1;
+
+static int hf_pn_dcp = -1;
+
+static int hf_pn_dcp_service_id = -1;
+static int hf_pn_dcp_service_type = -1;
+static int hf_pn_dcp_xid = -1;
+static int hf_pn_dcp_reserved8 = -1;
+static int hf_pn_dcp_reserved16 = -1;
+static int hf_pn_dcp_response_delay = -1;
+static int hf_pn_dcp_data_length = -1;
+static int hf_pn_dcp_block_length = -1;
+
+static int hf_pn_dcp_block = -1;
+
+static int hf_pn_dcp_result = -1;
+
+static int hf_pn_dcp_option = -1;
+static int hf_pn_dcp_suboption = -1;
+static int hf_pn_dcp_req_status = -1;
+static int hf_pn_dcp_res_status = -1;
+
+static int hf_pn_dcp_suboption_ip = -1;
+static int hf_pn_dcp_suboption_ip_status = -1;
+static int hf_pn_dcp_suboption_ip_ip = -1;
+static int hf_pn_dcp_suboption_ip_subnetmask = -1;
+static int hf_pn_dcp_suboption_ip_default_router = -1;
+
+static int hf_pn_dcp_suboption_device = -1;
+static int hf_pn_dcp_suboption_device_typeofstation = -1;
+static int hf_pn_dcp_suboption_device_nameofstation = -1;
+static int hf_pn_dcp_suboption_vendor_id = -1;
+static int hf_pn_dcp_suboption_device_id = -1;
+static int hf_pn_dcp_suboption_device_role = -1;
+
+static int hf_pn_dcp_suboption_dhcp = -1;
+
+static int hf_pn_dcp_suboption_lldp = -1;
+
+static int hf_pn_dcp_suboption_control = -1;
+static int hf_pn_dcp_suboption_control_status = -1;
+
+static int hf_pn_dcp_suboption_all = -1;
+
+static int hf_pn_dcp_suboption_manuf = -1;
+
+static int hf_pn_dcp_data = -1;
+
+
+static gint ett_pn_dcp = -1;
+static gint ett_pn_dcp_block = -1;
+
+#define FRAME_ID_UC 0xfefd
+#define FRAME_ID_MC 0xfefe
+#define FRAME_ID_MC_RESP 0xfeff
+
+
+#define PNDCP_SERVICE_ID_GET 0x03
+#define PNDCP_SERVICE_ID_SET 0x04
+#define PNDCP_SERVICE_ID_IDENTIFY 0x05
+
+static const value_string pn_dcp_service_id[] = {
+ { 0x00, "reserved" },
+ { 0x01, "Manufacturer specific" },
+ { 0x02, "Manufacturer specific" },
+ { PNDCP_SERVICE_ID_GET, "Get" },
+ { PNDCP_SERVICE_ID_SET, "Set" },
+ { PNDCP_SERVICE_ID_IDENTIFY, "Identify" },
+ /* 0x06 - 0xff reserved */
+ { 0, NULL }
+};
+
+#define PNDCP_SERVICE_TYPE_REQUEST 0
+#define PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS 1
+#define PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED 5
+
+static const value_string pn_dcp_service_type[] = {
+ { PNDCP_SERVICE_TYPE_REQUEST, "Request" },
+ { PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS, "Response Success" },
+ { PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED, "Response - Request not supported" },
+ /* all others reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_result[] = {
+ { 0x00, "Ok" },
+ { 0x01, "Option unsupp." },
+ { 0x02, "Suboption unsupp." },
+ { 0x03, "Suboption not set" },
+ { 0x04, "Manufacturer specific" },
+ { 0x05, "Manufacturer specific" },
+ { 0x06, "Ressource Error" },
+ /* all others reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_req_status[] = {
+ { 0x0000, "Don't save data permanent" },
+ { 0x0001, "Save data permanent" },
+ /*0x0002 - 0xffff reserved */
+ { 0, NULL }
+};
+
+
+#define PNDCP_OPTION_IP 0x01
+#define PNDCP_OPTION_DEVICE 0x02
+#define PNDCP_OPTION_DHCP 0x03
+#define PNDCP_OPTION_LLDP 0x04
+#define PNDCP_OPTION_CONTROL 0x05
+#define PNDCP_OPTION_MANUF_X80 0x80
+#define PNDCP_OPTION_MANUF_X81 0x81
+#define PNDCP_OPTION_ALLSELECTOR 0xff
+
+static const value_string pn_dcp_option[] = {
+ { 0x00, "reserved" },
+ { PNDCP_OPTION_IP, "IP" },
+ { PNDCP_OPTION_DEVICE, "Device properties" },
+ { PNDCP_OPTION_DHCP, "DHCP" },
+ { PNDCP_OPTION_LLDP, "LLDP" },
+ { PNDCP_OPTION_CONTROL, "Control" },
+ /*0x06 - 0x7f reserved */
+ /*0x80 - 0xfe manufacturer specific */
+ { PNDCP_OPTION_MANUF_X80, "Manufacturer specific" },
+ { PNDCP_OPTION_MANUF_X81, "Manufacturer specific" },
+ { PNDCP_OPTION_ALLSELECTOR, "All Selector" },
+ { 0, NULL }
+};
+
+#define PNDCP_SUBOPTION_IP_MAC 0x01
+#define PNDCP_SUBOPTION_IP_IP 0x02
+
+static const value_string pn_dcp_suboption_ip[] = {
+ { 0x00, "Reserved" },
+ { PNDCP_SUBOPTION_IP_MAC, "MAC address" },
+ { PNDCP_SUBOPTION_IP_IP, "IP parameter" },
+ /*0x03 - 0xff reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_suboption_ip_status[] = {
+ { 0x0000, "IP not set" },
+ { 0x0001, "IP set" },
+ { 0x0002, "IP set by DHCP" },
+ /*0x0003 - 0xffff reserved */
+ { 0, NULL }
+};
+
+#define PNDCP_SUBOPTION_DEVICE_MANUF 0x01
+#define PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION 0x02
+#define PNDCP_SUBOPTION_DEVICE_DEV_ID 0x03
+#define PNDCP_SUBOPTION_DEVICE_DEV_ROLE 0x04
+#define PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS 0x05
+
+static const value_string pn_dcp_suboption_device[] = {
+ { 0x00, "Reserved" },
+ { PNDCP_SUBOPTION_DEVICE_MANUF, "Manufacturer specific (Type of Station)" },
+ { PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION, "Name of Station" },
+ { PNDCP_SUBOPTION_DEVICE_DEV_ID, "Device ID" },
+ { PNDCP_SUBOPTION_DEVICE_DEV_ROLE, "Device Role" },
+ { PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS, "Device Options" },
+ /*0x06 - 0xff reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_suboption_dhcp[] = {
+ { 12, "Host name" },
+ { 43, "Vendor specific" },
+ { 54, "Server identifier" },
+ { 55, "Parameter request list" },
+ { 60, "Class identifier" },
+ { 61, "DHCP client identifier" },
+ { 81, "FQDN, Fully Qualified Domain Name" },
+ { 97, "UUID/GUID-based Client" },
+ { 255, "Control DHCP for address resolution" },
+ /*all others reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_suboption_lldp[] = {
+ /* currently unknown */
+ { 0, NULL }
+};
+
+#define PNDCP_SUBOPTION_CONTROL_START_TRANS 0x01
+#define PNDCP_SUBOPTION_CONTROL_END_TRANS 0x02
+#define PNDCP_SUBOPTION_CONTROL_SIGNAL 0x03
+#define PNDCP_SUBOPTION_CONTROL_RESPONSE 0x04
+
+static const value_string pn_dcp_suboption_control[] = {
+ { 0x00, "Reserved" },
+ { PNDCP_SUBOPTION_CONTROL_START_TRANS, "Start Transaction" },
+ { PNDCP_SUBOPTION_CONTROL_END_TRANS, "End Transaction" },
+ { PNDCP_SUBOPTION_CONTROL_SIGNAL, "Signal" },
+ { PNDCP_SUBOPTION_CONTROL_RESPONSE, "Response" },
+ /*0x05 - 0xff reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_suboption_all[] = {
+ { 0xff, "ALL Selector" },
+ /* all other reserved */
+ { 0, NULL }
+};
+
+static const value_string pn_dcp_suboption_manuf[] = {
+ /* none known */
+ { 0, NULL }
+};
+
+
+
+/* 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 an IPv4 address */
+int
+dissect_pn_ipv4(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, int hfindex, guint32 *pdata)
+{
+ guint32 data;
+
+ tvb_memcpy(tvb, (guint8 *)&data, offset, 4);
+ if(tree)
+ proto_tree_add_ipv4(tree, hfindex, tvb, offset, 4, data);
+
+ if (pdata)
+ *pdata = data;
+
+ return offset + 4;
+}
+
+/* dissect some padding data (with the given length) */
+int
+dissect_pn_padding(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
+ proto_tree *tree, int length)
+{
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, length, "data",
+ "Padding: %u byte", length);
+
+ return offset + length;
+}
+
+/* append the given info text */
+static void
+pn_append_info(packet_info *pinfo, proto_item *dcp_item, char *text)
+{
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, text);
+
+ proto_item_append_text(dcp_item, text);
+}
+
+
+/* dissect the option field */
+static int
+dissect_PNDCP_Option(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *block_item, int hfindex, gboolean append_col)
+{
+ guint8 option;
+ guint8 suboption;
+ const value_string *val_str;
+
+ offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hfindex, &option);
+ switch(option) {
+ case(PNDCP_OPTION_IP):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);
+ val_str = pn_dcp_suboption_ip;
+ break;
+ case(PNDCP_OPTION_DEVICE):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);
+ val_str = pn_dcp_suboption_device;
+ break;
+ case(PNDCP_OPTION_DHCP):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption);
+ val_str = pn_dcp_suboption_dhcp;
+ break;
+ case(PNDCP_OPTION_LLDP):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_lldp, &suboption);
+ val_str = pn_dcp_suboption_lldp;
+ break;
+ case(PNDCP_OPTION_CONTROL):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);
+ val_str = pn_dcp_suboption_control;
+ break;
+ case(PNDCP_OPTION_ALLSELECTOR):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);
+ val_str = pn_dcp_suboption_all;
+ break;
+ default:
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);
+ val_str = pn_dcp_suboption_manuf;
+ }
+
+ proto_item_append_text(block_item, ", Status from %s - %s",
+ val_to_str(option, pn_dcp_option, "Unknown"), val_to_str(suboption, val_str, "Unknown"));
+
+ if(append_col) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(suboption, val_str, "Unknown"));
+ }
+
+ return offset;
+}
+
+
+/* dissect the "IP" suboption */
+static int
+dissect_PNDCP_Suboption_IP(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
+ gboolean is_response)
+{
+ guint8 suboption;
+ guint16 block_length;
+ guint16 status;
+ guint16 req_status;
+ guint32 ip;
+
+
+ offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
+
+ switch(suboption) {
+ case(PNDCP_SUBOPTION_IP_MAC):
+ pn_append_info(pinfo, dcp_item, ", MAC");
+ proto_item_append_text(block_item, "IP/MAC");
+
+ /* XXX - improve this */
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_IP, suboption, block_length);
+ offset += block_length;
+ break;
+ case(PNDCP_SUBOPTION_IP_IP):
+ pn_append_info(pinfo, dcp_item, ", IP");
+ proto_item_append_text(block_item, "IP/IP");
+
+ if(is_response) {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_status, &status);
+ proto_item_append_text(block_item, ", Status: %s", val_to_str(status, pn_dcp_suboption_ip_status, "Unknown"));
+ } else {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_req_status, &req_status);
+ proto_item_append_text(block_item, ", Status: %s", val_to_str(req_status, pn_dcp_req_status, "Unknown"));
+ }
+
+ /* ip address */
+ offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip);
+ proto_item_append_text(block_item, ", IP: %s", ip_to_str((guint8*)&ip));
+
+ /* subnetmask */
+ offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip);
+ proto_item_append_text(block_item, ", Subnet: %s", ip_to_str((guint8*)&ip));
+
+ /* default router */
+ offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_default_router, &ip);
+ proto_item_append_text(block_item, ", Router: %s", ip_to_str((guint8*)&ip));
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_IP, suboption, block_length);
+ offset += block_length;
+ }
+
+ return offset;
+}
+
+
+/* dissect the "device" suboption */
+static int
+dissect_PNDCP_Suboption_Device(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *block_item, proto_item *dcp_item,
+ int length, gboolean is_response)
+{
+ guint8 suboption;
+ guint16 block_length;
+ gchar *info_str;
+ guint8 device_role;
+ guint16 vendor_id;
+ guint16 device_id;
+ guint8* typeofstation;
+ guint8* nameofstation;
+ guint16 status;
+
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);
+ length--;
+
+ if(length) {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
+ if(is_response) {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);
+ block_length -= 2;
+ }
+ }
+
+ switch(suboption) {
+ case(PNDCP_SUBOPTION_DEVICE_MANUF):
+/* if(is_response) {*/
+ typeofstation = g_malloc(block_length+1);
+ tvb_memcpy(tvb, typeofstation, offset, block_length);
+ typeofstation[block_length] = '\0';
+ proto_tree_add_string (tree, hf_pn_dcp_suboption_device_typeofstation, tvb, offset, block_length, typeofstation);
+ pn_append_info(pinfo, dcp_item, ", TypeOfStation");
+ proto_item_append_text(block_item, "Device/Manufacturer specific");
+ if(is_response)
+ proto_item_append_text(block_item, ", Status: %u", status);
+ proto_item_append_text(block_item, ", TypeOfStation: \"%s\"", typeofstation);
+ g_free(typeofstation);
+ offset += block_length;
+/* } else {
+ pn_append_info(pinfo, dcp_item, ", TypeOfStation");
+ proto_item_append_text(block_item, "Device/Manufacturer specific(TypeOfStation)");
+ offset += block_length;
+ }*/
+ break;
+ case(PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION):
+ nameofstation = g_malloc(block_length+1);
+ tvb_memcpy(tvb, nameofstation, offset, block_length);
+ nameofstation[block_length] = '\0';
+ proto_tree_add_string (tree, hf_pn_dcp_suboption_device_nameofstation, tvb, offset, block_length, nameofstation);
+ pn_append_info(pinfo, dcp_item, ", NameOfStation");
+ proto_item_append_text(block_item, "Device/NameOfStation");
+ if(is_response)
+ proto_item_append_text(block_item, ", Status: %u", status);
+ proto_item_append_text(block_item, ", \"%s\"", nameofstation);
+ g_free(nameofstation);
+ offset += block_length;
+ break;
+ case(PNDCP_SUBOPTION_DEVICE_DEV_ID):
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_vendor_id, &vendor_id);
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_id, &device_id);
+ pn_append_info(pinfo, dcp_item, ", Dev-ID");
+ proto_item_append_text(block_item, "Device/Device ID");
+ if(is_response)
+ proto_item_append_text(block_item, ", Status: %u", status);
+ proto_item_append_text(block_item, ", 0x%04x/0x%04x", vendor_id, device_id);
+ break;
+ case(PNDCP_SUBOPTION_DEVICE_DEV_ROLE):
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_role, &device_role);
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_reserved8, NULL);
+ pn_append_info(pinfo, dcp_item, ", Dev-Role");
+ proto_item_append_text(block_item, "Device/Device Role");
+ if(is_response)
+ proto_item_append_text(block_item, ", Status: %u", status);
+ if(device_role & 0x01)
+ proto_item_append_text(block_item, ", IO-Device");
+ if(device_role & 0x02)
+ proto_item_append_text(block_item, ", IO-Controller");
+ if(device_role & 0x04)
+ proto_item_append_text(block_item, ", IO-Multidevice");
+ if(device_role & 0x08)
+ proto_item_append_text(block_item, ", PN-Supervisor");
+ break;
+ case(PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS):
+ info_str = g_strdup_printf(", Dev-Options(%u)", block_length/2);
+ pn_append_info(pinfo, dcp_item, info_str);
+ g_free(info_str);
+ proto_item_append_text(block_item, "Device/Device Options");
+ if(is_response)
+ proto_item_append_text(block_item, ", Status: %u", status);
+ proto_item_append_text(block_item, ", %u options", block_length/2);
+ for( ; block_length != 0; block_length -= 2) {
+ offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, NULL /*block_item*/, hf_pn_dcp_option,
+ FALSE /* append_col */);
+ }
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_DEVICE, suboption, block_length);
+ offset += block_length;
+ }
+
+ return offset;
+}
+
+
+/* dissect the "control" suboption */
+static int
+dissect_PNDCP_Suboption_Control(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *block_item, proto_item *dcp_item, int length)
+{
+ guint8 result;
+ guint8 suboption;
+ guint16 block_length;
+ gchar *info_str;
+ guint16 status;
+
+
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);
+ length--;
+
+ if(length) {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
+ }
+
+ switch(suboption) {
+ case(PNDCP_SUBOPTION_CONTROL_START_TRANS):
+ pn_append_info(pinfo, dcp_item, ", Start-Trans");
+ proto_item_append_text(block_item, "Control/Start-Transaction");
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);
+ break;
+ case(PNDCP_SUBOPTION_CONTROL_END_TRANS):
+ pn_append_info(pinfo, dcp_item, ", End-Trans");
+ proto_item_append_text(block_item, "Control/End-Transaction");
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);
+ break;
+ case(PNDCP_SUBOPTION_CONTROL_SIGNAL):
+ pn_append_info(pinfo, dcp_item, ", Signal");
+ proto_item_append_text(block_item, "Control/Signal");
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);
+ block_length -= 2;
+
+ /* XXX - improve this */
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data: %d bytes", block_length);
+ offset += block_length;
+ break;
+ case(PNDCP_SUBOPTION_CONTROL_RESPONSE):
+ proto_item_append_text(block_item, "Control/Response");
+ offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, block_item, hf_pn_dcp_suboption_control_status,
+ FALSE /* append_col */);
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_result, &result);
+ length = 0;
+ info_str = g_strdup_printf(", Response(%s)", val_to_str(result, pn_dcp_result, "Unknown"));
+ pn_append_info(pinfo, dcp_item, info_str);
+ g_free(info_str);
+ proto_item_append_text(block_item, ", Result: %s", val_to_str(result, pn_dcp_result, "Unknown"));
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_CONTROL, suboption, block_length);
+ offset += block_length;
+ }
+
+ return offset;
+}
+
+
+/* dissect the "all" suboption */
+static int
+dissect_PNDCP_Suboption_All(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *block_item, proto_item *dcp_item, int length)
+{
+ guint8 suboption;
+ guint16 block_length;
+
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);
+ length--;
+
+ if(length) {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
+ length-=2;
+ }
+
+ switch(suboption) {
+ case(255): /* All */
+ pn_append_info(pinfo, dcp_item, ", All");
+ proto_item_append_text(block_item, "All/All");
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_ALLSELECTOR, suboption, block_length);
+ offset += block_length;
+ }
+
+ return offset;
+}
+
+
+/* dissect the "manufacturer" suboption */
+static int
+dissect_PNDCP_Suboption_Manuf(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *block_item, proto_item *dcp_item, int length)
+{
+ guint8 suboption;
+ guint16 block_length;
+
+ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);
+ length--;
+
+ if(length) {
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);
+ length-=2;
+ }
+
+ switch(suboption) {
+ default:
+ pn_append_info(pinfo, dcp_item, ", Manufacturer Specific");
+ proto_item_append_text(block_item, "Manufacturer Specific");
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data",
+ "Block data: %d bytes", block_length);
+ offset += block_length;
+ }
+
+ return offset;
+}
+
+
+/* dissect one DCP block */
+static int
+dissect_PNDCP_Block(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, proto_item *dcp_item,
+ int length, gboolean is_response)
+{
+ guint8 option;
+ guint8 suboption;
+ proto_item *block_item;
+ proto_tree *block_tree;
+ guint16 block_length;
+
+ block_length = tvb_get_ntohs(tvb, offset + 2) + 4;
+ if(block_length > length)
+ block_length = length;
+
+ /* subtree for block */
+ block_item = proto_tree_add_none_format(tree, hf_pn_dcp_block,
+ tvb, offset, block_length, "");
+ block_tree = proto_item_add_subtree(block_item, ett_pn_dcp_block);
+
+
+ offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_option, &option);
+ length--;
+
+ switch(option) {
+ case(PNDCP_OPTION_IP):
+ offset = dissect_PNDCP_Suboption_IP(tvb, offset, pinfo, block_tree, block_item, dcp_item, is_response);
+ break;
+ case(PNDCP_OPTION_DEVICE):
+ offset = dissect_PNDCP_Suboption_Device(tvb, offset, pinfo, block_tree, block_item, dcp_item, length, is_response);
+ break;
+ case(PNDCP_OPTION_DHCP):
+ /* XXX - improve this */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_suboption_dhcp, &suboption);
+ break;
+ case(PNDCP_OPTION_LLDP):
+ /* XXX - improve this */
+ offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_suboption_lldp, &suboption);
+ break;
+ case(PNDCP_OPTION_CONTROL):
+ offset = dissect_PNDCP_Suboption_Control(tvb, offset, pinfo, block_tree, block_item, dcp_item, length);
+ break;
+ case(PNDCP_OPTION_ALLSELECTOR):
+ offset = dissect_PNDCP_Suboption_All(tvb, offset, pinfo, block_tree, block_item, dcp_item, length);
+ break;
+ case(PNDCP_OPTION_MANUF_X80):
+ case(PNDCP_OPTION_MANUF_X81):
+ default:
+ offset = dissect_PNDCP_Suboption_Manuf(tvb, offset, pinfo, block_tree, block_item, dcp_item, length);
+ }
+
+ if(block_length & 1) {
+ /* we have an odd number of bytes in this block, add a padding byte */
+ offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1);
+ }
+
+ return offset;
+}
+
+
+/* dissect a whole DCP PDU */
+static void
+dissect_PNDCP_PDU(tvbuff_t *tvb,
+ packet_info *pinfo, proto_tree *tree, proto_item *dcp_item)
+{
+ guint8 service_id;
+ guint8 service_type;
+ guint32 xid;
+ guint16 response_delay;
+ guint16 data_length;
+ int offset = 0;
+ gchar *xid_str;
+ gboolean is_response = FALSE;
+
+
+ offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_id, &service_id);
+ offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_type, &service_type);
+ offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_dcp_xid, &xid);
+ if(service_id == PNDCP_SERVICE_ID_IDENTIFY && service_type == PNDCP_SERVICE_TYPE_REQUEST) {
+ /* multicast header */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_response_delay, &response_delay);
+ } else {
+ /* unicast header */
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_reserved16, NULL);
+ }
+ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_data_length, &data_length);
+
+ switch(service_id) {
+ case(PNDCP_SERVICE_ID_GET):
+ pn_append_info(pinfo, dcp_item, "Get");
+ break;
+ case(PNDCP_SERVICE_ID_SET):
+ pn_append_info(pinfo, dcp_item, "Set");
+ break;
+ case(PNDCP_SERVICE_ID_IDENTIFY):
+ pn_append_info(pinfo, dcp_item, "Ident");
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, tvb_length_remaining(tvb, offset), "data",
+ "PN-DCP Unknown service ID %u, Data: %d bytes", service_id, tvb_length_remaining(tvb, offset));
+ return;
+ }
+
+ switch(service_type) {
+ case(PNDCP_SERVICE_TYPE_REQUEST):
+ pn_append_info(pinfo, dcp_item, " Req");
+ break;
+ case(PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS):
+ pn_append_info(pinfo, dcp_item, " Ok ");
+ is_response = TRUE;
+ break;
+ case(PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED):
+ pn_append_info(pinfo, dcp_item, " unsupported");
+ is_response = TRUE;
+ break;
+ default:
+ proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, tvb_length_remaining(tvb, offset), "data",
+ "PN-DCP Unknown service type %u, Data: %d bytes", service_type, tvb_length_remaining(tvb, offset));
+ return;
+ }
+
+ xid_str = g_strdup_printf(", Xid:0x%x", xid);
+ pn_append_info(pinfo, dcp_item, xid_str);
+ g_free(xid_str);
+
+ /* dissect a number of blocks (depending on the remaining length) */
+ while(data_length) {
+ int ori_offset = offset;
+ if(service_id == PNDCP_SERVICE_ID_GET && service_type == PNDCP_SERVICE_TYPE_REQUEST) {
+ /* Selectors */
+ offset = dissect_PNDCP_Option(tvb, offset, pinfo,
+ tree, dcp_item, hf_pn_dcp_option, TRUE /* append_col */);
+ } else {
+ offset = dissect_PNDCP_Block(tvb, offset, pinfo, tree, dcp_item, data_length, is_response);
+ }
+ ori_offset= offset - ori_offset;
+ data_length -= ori_offset;
+ }
+}
+
+
+/* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */
+static gboolean
+dissect_PNDCP_Data_heur(tvbuff_t *tvb,
+ packet_info *pinfo, proto_tree *tree)
+{
+ guint16 u16FrameID;
+ proto_item *item = NULL;
+ proto_tree *dcp_tree = NULL;
+
+
+ /* the tvb will NOT contain the frame_id here, so get it from our private data! */
+ u16FrameID = GPOINTER_TO_INT(pinfo->private_data);
+
+ /* frame id must be in valid range (acyclic Real-Time, DCP) */
+ if (u16FrameID < FRAME_ID_UC || u16FrameID > FRAME_ID_MC_RESP) {
+ /* we are not interested in this packet */
+ return FALSE;
+ }
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_add_str(pinfo->cinfo, COL_PROTOCOL, "PN-DCP");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "");
+
+ /* subtree for DCP */
+ item = proto_tree_add_protocol_format(tree, proto_pn_dcp, tvb, 0, tvb_get_ntohs(tvb, 8) + 10,
+ "PROFINET DCP, ");
+ dcp_tree = proto_item_add_subtree(item, ett_pn_dcp);
+
+ /* dissect this PDU */
+ dissect_PNDCP_PDU(tvb, pinfo, dcp_tree, item);
+
+ return TRUE;
+}
+
+
+void
+proto_register_pn_dcp (void)
+{
+ static hf_register_info hf[] = {
+ { &hf_pn_dcp,
+ { "PROFINET DCP", "pn_dcp", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_service_id,
+ { "Service-ID", "pn_dcp.service_id", FT_UINT8, BASE_DEC, VALS(pn_dcp_service_id), 0x0, "", HFILL }},
+ { &hf_pn_dcp_service_type,
+ { "Service-Type", "pn_dcp.service_type", FT_UINT8, BASE_DEC, VALS(pn_dcp_service_type), 0x0, "", HFILL }},
+ { &hf_pn_dcp_xid,
+ { "xid", "pn_dcp.xid", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_reserved8,
+ { "Reserved", "pn_dcp.reserved8", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_reserved16,
+ { "Reserved", "pn_dcp.reserved16", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_response_delay,
+ { "ResponseDelay", "pn_dcp.response_delay", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_data_length,
+ { "DCPDataLength", "pn_dcp.data_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_block_length,
+ { "DataBlockLength", "pn_dcp.block_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_option,
+ { "Option", "pn_dcp.option", FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption,
+ { "Suboption", "pn_dcp.suboption", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_result,
+ { "Result", "pn_dcp.result", FT_UINT8, BASE_DEC, VALS(pn_dcp_result), 0x0, "", HFILL }},
+ { &hf_pn_dcp_block,
+ { "DCPBlock", "pn_dcp.block", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_req_status,
+ { "Status", "pn_dcp.req_status", FT_UINT16, BASE_DEC, VALS(pn_dcp_req_status), 0x0, "", HFILL }},
+ { &hf_pn_dcp_res_status,
+ { "ResponseStatus", "pn_dcp.res_status", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_ip,
+ { "Suboption", "pn_dcp.suboption_ip", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_ip), 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_ip_status,
+ { "Status", "pn_dcp.suboption_ip_status", FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_ip_status), 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_ip_ip,
+ { "IPaddress", "pn_dcp.subobtion_ip_ip", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_ip_subnetmask,
+ { "Subnetmask", "pn_dcp.subobtion_ip_subnetmask", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_ip_default_router,
+ { "Default-router", "pn_dcp.subobtion_ip_default_router", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_suboption_device,
+ { "Suboption", "pn_dcp.suboption_device", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_device), 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_device_typeofstation,
+ { "TypeOfStation", "pn_dcp.suboption_device_typeofstation", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_device_nameofstation,
+ { "NameOfStation", "pn_dcp.suboption_device_nameofstation", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_vendor_id,
+ { "VendorID", "pn_dcp.suboption_vendor_id", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_device_id,
+ { "DeviceID", "pn_dcp.suboption_device_id", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_device_role,
+ { "Device-role", "pn_dcp.suboption_device_role", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_suboption_dhcp,
+ { "Suboption", "pn_dcp.suboption_dhcp", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_dhcp), 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_suboption_lldp,
+ { "Suboption", "pn_dcp.suboption_lldp", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_lldp), 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_suboption_control,
+ { "Suboption", "pn_dcp.suboption_control", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_control), 0x0, "", HFILL }},
+ { &hf_pn_dcp_suboption_control_status,
+ { "ResponseStatus", "pn_dcp.suboption_control_status", FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_suboption_all,
+ { "Suboption", "pn_dcp.suboption_all", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_all), 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_suboption_manuf,
+ { "Suboption", "pn_dcp.suboption_manuf", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_manuf), 0x0, "", HFILL }},
+
+ { &hf_pn_dcp_data,
+ { "Undecoded Data", "pn_dcp.data", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},
+ };
+
+ static gint *ett[] = {
+ &ett_pn_dcp,
+ &ett_pn_dcp_block
+ };
+ proto_pn_dcp = proto_register_protocol ("PROFINET DCP", "PN-DCP", "pn_dcp");
+ proto_register_field_array (proto_pn_dcp, hf, array_length (hf));
+ proto_register_subtree_array (ett, array_length (ett));
+}
+
+void
+proto_reg_handoff_pn_dcp (void)
+{
+ /* register ourself as an heuristic pn-rt payload dissector */
+ heur_dissector_add("pn_rt", dissect_PNDCP_Data_heur, proto_pn_dcp);
+}
diff --git a/epan/dissectors/packet-pn-rt.c b/epan/dissectors/packet-pn-rt.c
new file mode 100644
index 0000000000..367aa45cd3
--- /dev/null
+++ b/epan/dissectors/packet-pn-rt.c
@@ -0,0 +1,449 @@
+/* packet-pn-rt.c
+ * Routines for pn-rt (PROFINET Real-Time) packet dissection.
+ * This is the base for other PROFINET protocols like IO, CBA, DCP, ...
+ * (the "content subdissectors" will register themselves using a heuristic)
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* we do not use this dissector as a plugin any longer... */
+#define __ETHEREAL_STATIC__
+
+#ifndef __ETHEREAL_STATIC__
+#include "plugins/plugin_api.h"
+#include "moduleinfo.h"
+#endif
+
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmodule.h>
+#include <ctype.h>
+#include <time.h>
+#include <string.h>
+#include <epan/packet.h>
+#include <epan/addr_resolv.h>
+#include "prefs.h"
+#include <epan/strutil.h>
+#include <etypes.h>
+
+
+#ifndef __ETHEREAL_STATIC__
+#include "plugins/plugin_api_defs.h"
+
+G_MODULE_EXPORT const gchar version[] = VERSION;
+#endif
+
+void proto_reg_handoff_pn_rt(void);
+
+/* Define the pn-rt proto */
+static int proto_pn_rt = -1;
+
+/* Define many header fields for pn-rt */
+static int hf_pn_rt_id = -1;
+static int hf_pn_rt_data = -1;
+static int hf_pn_rt_cycle_counter = -1;
+static int hf_pn_rt_transfer_status = -1;
+static int hf_pn_rt_data_status = -1;
+static int hf_pn_rt_data_status_res67 = -1;
+static int hf_pn_rt_data_status_ok = -1;
+static int hf_pn_rt_data_status_operate = -1;
+static int hf_pn_rt_data_status_res3 = -1;
+static int hf_pn_rt_data_status_valid = -1;
+static int hf_pn_rt_data_status_res1 = -1;
+static int hf_pn_rt_data_status_primary = -1;
+static int hf_pn_rt_malformed = -1;
+
+/*
+ * Define the trees for pn-rt
+ * We need one tree for pn-rt itself and one for the pn-rt data status subtree
+ */
+static int ett_pn_rt = -1;
+static int ett_pn_rt_data_status = -1;
+
+/*
+ * Here are the global variables associated with
+ * the various user definable characteristics of the dissection
+ */
+/* Place summary in proto tree */
+static gboolean pn_rt_summary_in_tree = TRUE;
+
+/* heuristic to find the right pn-rt payload dissector */
+static heur_dissector_list_t heur_subdissector_list;
+
+/* the official "we don't know that data" dissector */
+static dissector_handle_t data_handle;
+
+
+/*
+ * dissect_pn_rt - The dissector for the Soft-Real-Time protocol
+ */
+static void
+dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ gint tvb_len;
+ gint data_len;
+ guint16 u16FrameID;
+ guint8 u8DataStatus;
+ guint8 u8TransferStatus;
+ guint16 u16CycleCounter;
+ gchar *pszProtAddInfo;
+ gchar *pszProtShort;
+ gchar *pszProtSummary;
+ gchar *pszProtComment;
+ proto_item *item = NULL;
+ proto_tree *ds_tree = NULL;
+ proto_tree *pn_rt_tree, *ti;
+ gchar szFieldSummary[100];
+ tvbuff_t *next_tvb;
+ gboolean bCyclic;
+
+
+ /* Initialize variables */
+ tvb_len = tvb_length(tvb);
+ pn_rt_tree = NULL;
+ ds_tree = NULL;
+ ti = NULL;
+
+ /*
+ * Set the columns now, so that they'll be set correctly if we throw
+ * an exception. We can set them (or append things) later again ....
+ */
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_add_str(pinfo->cinfo, COL_PROTOCOL, "PN-RT");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_str(pinfo->cinfo, COL_INFO, "PROFINET Real-Time");
+
+ if (tvb_len < 6) {
+ /* packet is too short, mark it as malformed */
+ proto_tree_add_bytes(tree, hf_pn_rt_malformed, tvb, 0, 10000,
+ tvb_get_ptr(tvb, 0, 10000));
+ return;
+ }
+
+ /* build protocol tree only, if tree is really used */
+ if (tree) {
+ /* build some "raw" data */
+ u16FrameID = tvb_get_ntohs(tvb, 0);
+ if (u16FrameID < 0x0100) {
+ pszProtShort = "PN-RTC0";
+ pszProtAddInfo = "Synchronization, ";
+ pszProtSummary = "Isochronous-Real-Time";
+ pszProtComment = "0x0000-0x00FF: Isochronous-Real-Time: Time-sync";
+ bCyclic = TRUE;
+ } else if (u16FrameID < 0x8000){
+ pszProtShort = "PN-RTC3";
+ pszProtAddInfo = "RTC3, ";
+ pszProtSummary = "Isochronous-Real-Time";
+ pszProtComment = "0x0100-0x7FFF: Isochronous-Real-Time(class=3): Cyclic";
+ bCyclic = TRUE;
+ } else if (u16FrameID < 0xbf00){
+ pszProtShort = "PN-RTC2";
+ pszProtAddInfo = "RTC2, ";
+ pszProtSummary = "cyclic Real-Time";
+ pszProtComment = "0x8000-0xBEFF: Real-Time(class=2): Cyclic";
+ bCyclic = TRUE;
+ } else if (u16FrameID < 0xc000){
+ pszProtShort = "PN-RTC2";
+ pszProtAddInfo = "Multicast, ";
+ pszProtSummary = "cyclic Real-Time";
+ pszProtComment = "0xBF00-0xBFFF: Real-Time(class=2 multicast): Cyclic";
+ bCyclic = TRUE;
+ } else if (u16FrameID < 0xfb00){
+ pszProtShort = "PN-RTC1";
+ pszProtAddInfo = "RTC1, ";
+ pszProtSummary = "cyclic Real-Time";
+ pszProtComment = "0xC000-0xFAFF: Real-Time(class=1): Cyclic";
+ bCyclic = TRUE;
+ } else if (u16FrameID < 0xfc00){
+ pszProtShort = "PN-RTC1";
+ pszProtAddInfo = "Multicast, ";
+ pszProtSummary = "cyclic Real-Time";
+ pszProtComment = "0xFB00-0xFBFF: Real-Time(class=1 multicast): Cyclic";
+ bCyclic = TRUE;
+ } else if (u16FrameID < 0xfe00){
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "Reserved, ";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "0xFC00-0xFDFF: Real-Time: Acyclic high priority";
+ bCyclic = FALSE;
+ if (u16FrameID == 0xfc01) {
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "Alarm High, ";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "Real-Time: Acyclic PN-IO Alarm high priority";
+ }
+ } else if (u16FrameID < 0xff00){
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "Reserved, ";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "0xFE00-0xFEFF: Real-Time: Acyclic low priority";
+ bCyclic = FALSE;
+ if (u16FrameID == 0xfe01) {
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "Alarm Low, ";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "Real-Time: Acyclic PN-IO Alarm low priority";
+ }
+ if (u16FrameID == 0xfefd) {
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol)";
+ }
+ if (u16FrameID == 0xfefe) {
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol) multicast response";
+ }
+ if (u16FrameID == 0xfeff) {
+ pszProtShort = "PN-RTA";
+ pszProtAddInfo = "";
+ pszProtSummary = "acyclic Real-Time";
+ pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol) multicast";
+ }
+ } else {
+ pszProtShort = "PN-RT";
+ pszProtAddInfo = "Reserved";
+ pszProtSummary = "Real-Time";
+ pszProtComment = "0xFF00-0xFFFF: reserved ID";
+ bCyclic = FALSE;
+ }
+
+ /* decode optional cyclic fields at the packet end and build the summary line */
+ if (bCyclic) {
+ /* cyclic transfer has cycle counter, data status and transfer status fields at the end */
+ u16CycleCounter = tvb_get_ntohs(tvb, tvb_len - 4);
+ u8DataStatus = tvb_get_guint8(tvb, tvb_len - 2);
+ u8TransferStatus = tvb_get_guint8(tvb, tvb_len - 1);
+
+ snprintf (szFieldSummary, sizeof(szFieldSummary),
+ "%sFrameID: 0x%04x, DataLen: %4u, Cycle: %5u (%s,%s,%s,%s)",
+ pszProtAddInfo, u16FrameID, tvb_len - 2 - 4, u16CycleCounter,
+ (u8DataStatus & 0x04) ? "Valid" : "Invalid",
+ (u8DataStatus & 0x01) ? "Primary" : "Backup",
+ (u8DataStatus & 0x20) ? "Ok" : "Problem",
+ (u8DataStatus & 0x10) ? "Run" : "Stop");
+
+ /* user data length is packet len - frame id - optional cyclic status fields */
+ data_len = tvb_len - 2 - 4;
+ } else {
+ /* acyclic transfer has no fields at the end */
+ snprintf (szFieldSummary, sizeof(szFieldSummary),
+ "%sFrameID: 0x%04x, DataLen: %4u",
+ pszProtAddInfo, u16FrameID, tvb_len - 2);
+
+ /* user data length is packet len - frame id field */
+ data_len = tvb_len - 2;
+ }
+
+ /* build pn_rt protocol tree with summary line */
+ if (pn_rt_summary_in_tree) {
+ ti = proto_tree_add_protocol_format(tree, proto_pn_rt, tvb, 0, -1,
+ "PROFINET %s, %s", pszProtSummary, szFieldSummary);
+ } else {
+ ti = proto_tree_add_item(tree, proto_pn_rt, tvb, 0, -1, FALSE);
+ }
+ pn_rt_tree = proto_item_add_subtree(ti, ett_pn_rt);
+
+ /* add frame ID */
+ proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_id, tvb,
+ 0, 2, u16FrameID, "FrameID: 0x%04x (%s)", u16FrameID, pszProtComment);
+
+ if (bCyclic) {
+ /* add cycle counter */
+ proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_cycle_counter, tvb,
+ tvb_len - 4, 2, u16CycleCounter, "CycleCounter: %u", u16CycleCounter);
+
+ /* add data status subtree */
+ item = proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_data_status,
+ tvb, tvb_len - 2, 1, u8DataStatus,
+ "DataStatus: 0x%02x (Frame: %s and %s, Provider: %s and %s)",
+ u8DataStatus,
+ (u8DataStatus & 0x04) ? "Valid" : "Invalid",
+ (u8DataStatus & 0x01) ? "Primary" : "Backup",
+ (u8DataStatus & 0x20) ? "Ok" : "Problem",
+ (u8DataStatus & 0x10) ? "Run" : "Stop");
+ ds_tree = proto_item_add_subtree(item, ett_pn_rt_data_status);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_res67, tvb, tvb_len - 2, 1, u8DataStatus);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_ok, tvb, tvb_len - 2, 1, u8DataStatus);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_operate, tvb, tvb_len - 2, 1, u8DataStatus);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_res3, tvb, tvb_len - 2, 1, u8DataStatus);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_valid, tvb, tvb_len - 2, 1, u8DataStatus);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_res1, tvb, tvb_len - 2, 1, u8DataStatus);
+ proto_tree_add_uint(ds_tree, hf_pn_rt_data_status_primary, tvb, tvb_len - 2, 1, u8DataStatus);
+
+ /* add transfer status */
+ if (u8TransferStatus) {
+ proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_transfer_status, tvb,
+ tvb_len - 1, 1, u8TransferStatus,
+ "TransferStatus: 0x%02x (ignore this frame)", u8TransferStatus);
+ } else {
+ proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_transfer_status, tvb,
+ tvb_len - 1, 1, u8TransferStatus,
+ "TransferStatus: 0x%02x (OK)", u8TransferStatus);
+ }
+ }
+
+ /* update column info now */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, szFieldSummary);
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_add_str(pinfo->cinfo, COL_PROTOCOL, pszProtShort);
+
+ pinfo->private_data = GINT_TO_POINTER(u16FrameID);
+
+ /* get frame user data tvb (without header and footer) */
+ next_tvb = tvb_new_subset(tvb, 2, data_len, data_len);
+
+ /* ask heuristics, if some sub-dissector is interested in this packet payload */
+ if(!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
+ /*if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown");*/
+
+ /* Oh, well, we don't know this; dissect it as data. */
+ call_dissector(data_handle, next_tvb, pinfo, tree);
+ }
+ }
+}
+
+
+/* Register all the bits needed by the filtering engine */
+void
+proto_register_pn_rt(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_pn_rt_id,
+ { "FrameID", "pn_rt.frame_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_rt_data,
+ { "Data", "pn_rt.data", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
+ { &hf_pn_rt_cycle_counter, {
+ "CycleCounter", "pn_rt.cycle_counter", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_rt_data_status, {
+ "DataStatus", "pn_rt.ds", FT_UINT8, BASE_HEX, 0, 0x0, "", HFILL }},
+ { &hf_pn_rt_data_status_res67, {
+ "Reserved (should be zero)", "pn_rt.ds_res67", FT_UINT8, BASE_HEX, 0, 0xc0, "", HFILL }},
+ { &hf_pn_rt_data_status_ok, {
+ "StationProblemIndicator: 1:Ok/0:Problem", "pn_rt.ds_ok", FT_UINT8, BASE_HEX, 0, 0x20, "", HFILL }},
+ { &hf_pn_rt_data_status_operate, {
+ "ProviderState: 1:Run/0:Stop", "pn_rt.ds_operate", FT_UINT8, BASE_HEX, 0, 0x10, "", HFILL }},
+ { &hf_pn_rt_data_status_res3, {
+ "Reserved (should be zero)", "pn_rt.ds_res3", FT_UINT8, BASE_HEX, 0, 0x08, "", HFILL }},
+ { &hf_pn_rt_data_status_valid, {
+ "DataValid: 1:Valid/0:Invalid", "pn_rt.ds_valid", FT_UINT8, BASE_HEX, 0, 0x04, "", HFILL }},
+ { &hf_pn_rt_data_status_res1, {
+ "Reserved (should be zero)", "pn_rt.ds_res1", FT_UINT8, BASE_HEX, 0, 0x02, "", HFILL }},
+ { &hf_pn_rt_data_status_primary, {
+ "State: 1:Primary/0:Backup", "pn_rt.ds_primary", FT_UINT8, BASE_HEX, 0, 0x01, "", HFILL }},
+ { &hf_pn_rt_transfer_status,
+ { "TransferStatus", "pn_rt.transfer_status", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_pn_rt_malformed,
+ { "Malformed", "pn_rt.malformed", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}
+ };
+ static gint *ett[] = {
+ &ett_pn_rt,
+ &ett_pn_rt_data_status,
+ };
+ module_t *pn_rt_module;
+
+ proto_pn_rt = proto_register_protocol("PROFINET Real-Time Protocol",
+ "PN-RT", "pn_rt");
+
+ proto_register_field_array(proto_pn_rt, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ /* Register our configuration options */
+
+ pn_rt_module = prefs_register_protocol(proto_pn_rt, proto_reg_handoff_pn_rt);
+
+ prefs_register_bool_preference(pn_rt_module, "summary_in_tree",
+ "Show PN-RT summary in protocol tree",
+ "Whether the PN-RT summary line should be shown in the protocol tree",
+ &pn_rt_summary_in_tree);
+
+ /* register heuristics anchor for payload dissectors */
+ register_heur_dissector_list("pn_rt", &heur_subdissector_list);
+}
+
+
+/* The registration hand-off routine
+ * Is called at startup, and everytime the preferences of this protocol changed. */
+void
+proto_reg_handoff_pn_rt(void)
+{
+ static int pn_rt_prefs_initialized = FALSE;
+ static dissector_handle_t pn_rt_handle;
+
+
+ if (!pn_rt_prefs_initialized) {
+ pn_rt_handle = create_dissector_handle(dissect_pn_rt, proto_pn_rt);
+ pn_rt_prefs_initialized = TRUE;
+ }
+ else {
+ dissector_delete("ethertype", ETHERTYPE_PROFINET, pn_rt_handle);
+ }
+
+ dissector_add("ethertype", ETHERTYPE_PROFINET, pn_rt_handle);
+
+ /* the official "we don't know that data" dissector */
+ data_handle = find_dissector("data");
+}
+
+
+
+
+/* Start the functions we need for the plugin stuff */
+
+#ifndef __ETHEREAL_STATIC__
+
+G_MODULE_EXPORT void
+plugin_reg_handoff(void){
+ proto_reg_handoff_pn_rt();
+}
+
+G_MODULE_EXPORT void
+plugin_init(plugin_address_table_t *pat
+#ifndef PLUGINS_NEED_ADDRESS_TABLE
+_U_
+#endif
+){
+ /* initialise the table of pointers needed in Win32 DLLs */
+ plugin_address_table_init(pat);
+ /* register the new protocol, protocol fields, and subtrees */
+ if (proto_pn_rt == -1) { /* execute protocol initialization only once */
+ proto_register_pn_rt();
+ }
+}
+
+#endif /* __ETHEREAL_STATIC__ */
+
+/* End the functions we need for plugin stuff */