svn propset svn:keywords Id svn:eol-style native .....
authorjmayer <jmayer@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 7 Dec 2004 11:13:58 +0000 (11:13 +0000)
committerjmayer <jmayer@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 7 Dec 2004 11:13:58 +0000 (11:13 +0000)
Add $Id: $ where missing

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@12676 f5534014-38df-0310-8fa8-9805f1628bb7

epan/dissectors/packet-aoe.c
epan/dissectors/packet-dcerpc-pn-io.c
epan/dissectors/packet-pn-dcp.c
epan/dissectors/packet-pn-rt.c

index ad83929434abaabebe540ea635f93737bf44a28a..8eab2f8b65a75083e6c8a0c88a438269cb4689f6 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for dissecting the ATA over Ethernet protocol.
  *   Ronnie Sahlberg 2004
  *
- * $Id: packet-aoe.c 11410 2004-07-18 18:06:47Z gram $
+ * $Id$
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 30b039d028c2eff1b77e2965ebc0259f58c155ff..d42883c95d40412ed32f306e5c9e6b12c2265eba 100644 (file)
-/* packet-dcerpc-pn-io.c\r
- * Routines for PROFINET IO dissection\r
- * (based on DCE-RPC and PN-RT protocols)\r
- *\r
- * Ethereal - Network traffic analyzer\r
- * By Gerald Combs <gerald@ethereal.com>\r
- * Copyright 1998 Gerald Combs\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
- */\r
-\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-\r
-#ifdef HAVE_SYS_TYPES_H\r
-#include <sys/types.h>\r
-#endif\r
-\r
-#include <string.h>\r
-\r
-#include <glib.h>\r
-#include <epan/packet.h>\r
-#include "packet-dcerpc.h"\r
-\r
-\r
-\r
-static int proto_pn_io = -1;\r
-\r
-static int hf_pn_io_opnum = -1;\r
-static int hf_pn_io_reserved16 = -1;\r
-\r
-static int hf_pn_io_array = -1;\r
-static int hf_pn_io_status = -1;\r
-static int hf_pn_io_args_max = -1;\r
-static int hf_pn_io_args_len = -1;\r
-static int hf_pn_io_array_max_count = -1;\r
-static int hf_pn_io_array_offset = -1;\r
-static int hf_pn_io_array_act_count = -1;\r
-\r
-static int hf_pn_io_data = -1;\r
-\r
-static int hf_pn_io_ar_uuid = -1;\r
-static int hf_pn_io_api = -1;\r
-static int hf_pn_io_slot_nr = -1;\r
-static int hf_pn_io_subslot_nr = -1;\r
-static int hf_pn_io_index = -1;\r
-static int hf_pn_io_seq_number = -1;\r
-static int hf_pn_io_record_data_length = -1;\r
-static int hf_pn_io_padding = -1;\r
-static int hf_pn_io_add_val1 = -1;\r
-static int hf_pn_io_add_val2 = -1;\r
-\r
-static int hf_pn_io_block = -1;\r
-static int hf_pn_io_block_type = -1;\r
-static int hf_pn_io_block_length = -1;\r
-static int hf_pn_io_block_version_high = -1;\r
-static int hf_pn_io_block_version_low = -1;\r
-\r
-static int hf_pn_io_sessionkey = -1;\r
-static int hf_pn_io_control_command = -1;\r
-static int hf_pn_io_control_command_prmend = -1;\r
-static int hf_pn_io_control_command_applready = -1;\r
-static int hf_pn_io_control_command_release = -1;\r
-static int hf_pn_io_control_command_done = -1;\r
-static int hf_pn_io_control_block_properties = -1;\r
-\r
-static int hf_pn_io_error_code = -1;\r
-static int hf_pn_io_error_decode = -1;\r
-static int hf_pn_io_error_code1 = -1;\r
-static int hf_pn_io_error_code2 = -1;\r
-static int hf_pn_io_error_code1_pniorw = -1;\r
-static int hf_pn_io_error_code1_pnio = -1;\r
-\r
-static int hf_pn_io_alarm_type = -1;\r
-static int hf_pn_io_alarm_specifier = -1;\r
-static int hf_pn_io_alarm_specifier_sequence = -1;\r
-static int hf_pn_io_alarm_specifier_channel = -1;\r
-static int hf_pn_io_alarm_specifier_manufacturer = -1;\r
-static int hf_pn_io_alarm_specifier_submodule = -1;\r
-static int hf_pn_io_alarm_specifier_ardiagnosis = -1;\r
-\r
-static int hf_pn_io_alarm_dst_endpoint = -1;\r
-static int hf_pn_io_alarm_src_endpoint = -1;\r
-static int hf_pn_io_pdu_type = -1;\r
-static int hf_pn_io_pdu_type_type = -1;\r
-static int hf_pn_io_pdu_type_version = -1;\r
-static int hf_pn_io_add_flags = -1;\r
-static int hf_pn_io_window_size = -1;\r
-static int hf_pn_io_tack = -1;\r
-static int hf_pn_io_send_seq_num = -1;\r
-static int hf_pn_io_ack_seq_num = -1;\r
-static int hf_pn_io_var_part_len = -1;\r
-\r
-static int hf_pn_io_module_ident_number = -1;\r
-static int hf_pn_io_submodule_ident_number = -1;\r
-\r
-static gint ett_pn_io = -1;\r
-static gint ett_pn_io_block = -1;\r
-static gint ett_pn_io_status = -1;\r
-static gint ett_pn_io_rta = -1;\r
-static gint ett_pn_io_pdu_type = -1;\r
-static gint ett_pn_io_add_flags = -1;\r
-static gint ett_pn_io_control_command = -1;\r
-\r
-static e_uuid_t uuid_pn_io_device = { 0xDEA00001, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };\r
-static guint16  ver_pn_io_device = 1;\r
-\r
-static e_uuid_t uuid_pn_io_controller = { 0xDEA00002, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };\r
-static guint16  ver_pn_io_controller = 1;\r
-\r
-static e_uuid_t uuid_pn_io_supervisor = { 0xDEA00003, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };\r
-static guint16  ver_pn_io_supervisor = 1;\r
-\r
-static e_uuid_t uuid_pn_io_parameterserver = { 0xDEA00004, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } };\r
-static guint16  ver_pn_io_parameterserver = 1;\r
-\r
-\r
-static const value_string pn_io_block_type[] = {\r
-       { 0x0000, "Reserved" },\r
-       { 0x0001, "Alarm Notification High"},\r
-       { 0x0002, "Alarm Notification Low"},\r
-       { 0x0008, "WriteRecordReq"},\r
-       { 0x8008, "WriteRecordRes"},\r
-       { 0x0009, "ReadRecordReq"},\r
-       { 0x8009, "ReadRecordRes"},\r
-       { 0x0010, "ManufacturerSpecificDiagnosisBlock"},\r
-       { 0x0011, "ChannelDiagnosisBlock"},\r
-       { 0x0012, "ExpectedIdentificationDataBlock"},\r
-       { 0x0014, "SubstituteValue RecordDataRead"},\r
-       { 0x0015, "RecordInputDataObjectElement"},\r
-       { 0x0016, "RecordOutputDataObjectElement"},\r
-       { 0x0017, "RecordOutputDataSubstituteObjectElement"},\r
-       { 0x0018, "ARData"},\r
-       { 0x0019, "LogData"},\r
-       { 0x001A, "APIData"},\r
-       { 0x0020, "I&M0"},\r
-       { 0x0021, "I&M1"},\r
-       { 0x0022, "I&M2"},\r
-       { 0x0023, "I&M3"},\r
-       { 0x0024, "I&M4"},\r
-       { 0x8001, "Alarm Ack High"},\r
-       { 0x8002, "Alarm Ack Low"},\r
-       { 0x0101, "ARBlockReq"},\r
-       { 0x8101, "ARBlockRes"},\r
-       { 0x0102, "IOCRBlockReq"},\r
-       { 0x8102, "IOCRBlockRes"},\r
-       { 0x0103, "AlarmCRBlockReq"},\r
-       { 0x8103, "AlarmCRBlockRes"},\r
-       { 0x0104, "ExpectedSubmoduleBlockReq"},\r
-       { 0x8104, "ModuleDiffBlock"},\r
-       { 0x0105, "PrmServerBlockReq"},\r
-       { 0x8105, "PrmServerBlockRes"},\r
-       { 0x0110, "IODBlockReq"},\r
-       { 0x8110, "IODBlockRes"},\r
-       { 0x0111, "IODBlockReq"},\r
-       { 0x8111, "IODBlockRes"},\r
-       { 0x0112, "IOXBlockReq"},\r
-       { 0x8112, "IOXBlockRes"},\r
-       { 0x0113, "IOXBlockReq"},\r
-       { 0x8113, "IOXBlockRes"},\r
-       { 0x0114, "ReleaseBlockReq"},\r
-       { 0x8114, "ReleaseBlockRes"},\r
-       { 0, NULL }\r
-};\r
-\r
-static const value_string pn_io_alarm_type[] = {\r
-       { 0x0000, "Reserved" },\r
-       { 0x0001, "Diagnosis" },\r
-       { 0x0002, "Process" },\r
-       { 0x0003, "Pull" },\r
-       { 0x0004, "Plug" },\r
-       { 0x0005, "Status" },\r
-       { 0x0006, "Update" },\r
-       { 0x0007, "Redundancy" },\r
-       { 0x0008, "Controlled by supervisor" },\r
-       { 0x0009, "Released by supervisor" },\r
-       { 0x000A, "Plug wrong submodule" },\r
-       { 0x000B, "Return of submodule" },\r
-    /* 0x000C - 0x001F reserved */\r
-    /* 0x0020 - 0x007F manufacturer specific */\r
-    /* 0x0080 - 0x00FF reserved for profiles */\r
-    /* 0x0100 - 0xFFFF reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_io_pdu_type[] = {\r
-       { 0x01, "Data-RTA-PDU" },\r
-       { 0x02, "NACK-RTA-PDU" },\r
-       { 0x03, "ACK-RTA-PDU" },\r
-       { 0x04, "ERR-RTA-PDU" },\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_io_error_code[] = {\r
-       { 0x00, "OK" },\r
-       { 0x81, "PNIO" },\r
-       { 0xCF, "RTA error" },\r
-       { 0xDA, "AlarmAck" },\r
-       { 0xDB, "IODConnectRes" },\r
-       { 0xDC, "IODReleaseRes" },\r
-       { 0xDD, "IODControlRes" },\r
-       { 0xDE, "IODReadRes" },\r
-       { 0xDF, "IODWriteRes" },\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_io_error_decode[] = {\r
-       { 0x00, "OK" },\r
-       { 0x80, "PNIORW" },\r
-       { 0x81, "PNIO" },\r
-    { 0, NULL }\r
-};\r
-\r
-/*\r
-XXX: the next 2 are dependant on error_code and error_decode\r
-\r
-e.g.: CL-RPC error:\r
-error_code .. see above\r
-error_decode .. 0x81\r
-error_code1 .. 0x69\r
-error_code2 ..\r
-1 RPC_ERR_REJECTED\r
-2 RPC_ERR_FAULTED\r
-3 RPC_ERR_TIMEOUT\r
-4 RPC_ERR_IN_ARGS\r
-5 RPC_ERR_OUT_ARGS\r
-6 RPC_ERR_DECODE\r
-7 RPC_ERR_PNIO_OUT_ARGS\r
-8 Application Timeout\r
-*/\r
-\r
-/* XXX: add some more error codes here */\r
-static const value_string pn_io_error_code1[] = {\r
-       { 0x00, "OK" },\r
-    { 0, NULL }\r
-};\r
-\r
-/* XXX: add some more error codes here */\r
-static const value_string pn_io_error_code2[] = {\r
-       { 0x00, "OK" },\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_io_error_code1_pniorw[] = {\r
-       { 0x0a /* 10*/, "application" },\r
-       { 0x0b /* 11*/, "access" },\r
-       { 0x0c /* 12*/, "resource" },\r
-       { 0x0d /* 13*/, "user specific(13)" },\r
-       { 0x0e /* 14*/, "user specific(14)" },\r
-       { 0x0f /* 15*/, "user specific(15)" },\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_io_error_code1_pnio[] = {\r
-       { 0x00 /*  0*/, "Reserved" },\r
-       { 0x01 /*  1*/, "Connect: Faulty ARBlockReq" },\r
-       { 0x02 /*  2*/, "Connect: Faulty IOCRBlockReq" },\r
-       { 0x03 /*  3*/, "Connect: Faulty ExpectedSubmoduleBlockReq" },\r
-       { 0x04 /*  4*/, "Connect: Faulty AlarmCRBlockReq" },\r
-       { 0x05 /*  5*/, "Connect: Faulty PrmServerBlockReq" },\r
-\r
-       { 0x14 /* 20*/, "IODControl: Faulty ControlBlockConnect" },\r
-       { 0x15 /* 21*/, "IODControl: Faulty ControlBlockPlug" },\r
-       { 0x16 /* 22*/, "IOXControl: Faulty ControlBlock after a connect est." },\r
-       { 0x17 /* 23*/, "IOXControl: Faulty ControlBlock a plug alarm" },\r
-\r
-    { 0x28 /* 40*/, "Release: Faulty ReleaseBlock" },\r
-\r
-    { 0x3c /* 60*/, "AlarmAck Error Codes" },\r
-    { 0x3d /* 61*/, "CMDEV" },\r
-    { 0x3e /* 62*/, "CMCTL" },\r
-    { 0x3f /* 63*/, "NRPM" },\r
-    { 0x40 /* 64*/, "RMPM" },\r
-    { 0x41 /* 65*/, "ALPMI" },\r
-    { 0x42 /* 66*/, "ALPMR" },\r
-    { 0x43 /* 67*/, "LMPM" },\r
-    { 0x44 /* 68*/, "MMAC" },\r
-    { 0x45 /* 69*/, "RPC" },\r
-    { 0x46 /* 70*/, "APMR" },\r
-    { 0x47 /* 71*/, "APMS" },\r
-    { 0x48 /* 72*/, "CPM" },\r
-    { 0x49 /* 73*/, "PPM" },\r
-    { 0x4a /* 74*/, "DCPUCS" },\r
-    { 0x4b /* 75*/, "DCPUCR" },\r
-    { 0x4c /* 76*/, "DCPMCS" },\r
-    { 0x4d /* 77*/, "DCPMCR" },\r
-    { 0x4e /* 78*/, "FSPM" },\r
-       { 0xfd /*253*/, "RTA_ERR_CLS_PROTOCOL" },\r
-    { 0, NULL }\r
-};\r
-\r
-\r
-\r
-/* dissect the four status (error) fields */\r
-static int\r
-dissect_PNIO_status(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint8  u8ErrorCode;\r
-    guint8  u8ErrorDecode;\r
-    guint8  u8ErrorCode1;\r
-    guint8  u8ErrorCode2;\r
-\r
-    proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-       guint32 u32SubStart;\r
-    int bytemask = (drep[0] & 0x10) ? 3 : 0;\r
-    const value_string *error_code1_vals;\r
-\r
-\r
-\r
-    /* status */\r
-    sub_item = proto_tree_add_item(tree, hf_pn_io_status, tvb, offset, 0, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_status);\r
-    u32SubStart = offset;\r
-\r
-    /* the PNIOStatus field is existing in both the RPC and the application data,\r
-     * depending on the current PDU.\r
-     * As the byte representation of these layers are different, this has to be handled\r
-     * in a somewhat different way than elsewhere. */\r
-\r
-    dissect_dcerpc_uint8(tvb, offset+(0^bytemask), pinfo, sub_tree, drep, \r
-                        hf_pn_io_error_code, &u8ErrorCode);\r
-       dissect_dcerpc_uint8(tvb, offset+(1^bytemask), pinfo, sub_tree, drep, \r
-                        hf_pn_io_error_decode, &u8ErrorDecode);\r
-\r
-    switch(u8ErrorDecode) {\r
-    case(0x80): /* PNIORW */\r
-           dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep, \r
-                            hf_pn_io_error_code1_pniorw, &u8ErrorCode1);\r
-        error_code1_vals = pn_io_error_code1_pniorw;\r
-        break;\r
-    case(0x81): /* PNIO */\r
-           dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep, \r
-                            hf_pn_io_error_code1_pnio, &u8ErrorCode1);\r
-        error_code1_vals = pn_io_error_code1_pnio;\r
-        break;\r
-    default:\r
-           dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep, \r
-                            hf_pn_io_error_code1, &u8ErrorCode1);\r
-        error_code1_vals = pn_io_error_code1;\r
-    }\r
-\r
-    /* XXX - this has to be decode specific too */\r
-       dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, \r
-                        hf_pn_io_error_code2, &u8ErrorCode2);\r
-\r
-    offset +=4;\r
-\r
-    if(u8ErrorCode == 0 && u8ErrorDecode == 0 && u8ErrorCode1 == 0 && u8ErrorCode2 == 0) {\r
-        proto_item_append_text(sub_item, ": OK");\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_str(pinfo->cinfo, COL_INFO, ", OK");\r
-    } else {\r
-        proto_item_append_text(sub_item, ": Error Code: \"%s\", Decode: \"%s\", Code1: \"%s\" Code2: 0x%x", \r
-            val_to_str(u8ErrorCode, pn_io_error_code, "(0x%x)"),\r
-            val_to_str(u8ErrorDecode, pn_io_error_decode, "(0x%x)"),\r
-            val_to_str(u8ErrorCode1, error_code1_vals, "(0x%x)"),\r
-            u8ErrorCode2);\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", Error Code: %s, Decode: %s, Code1: 0x%x Code2: 0x%x",\r
-            val_to_str(u8ErrorCode, pn_io_error_code, "(0x%x)"),\r
-            val_to_str(u8ErrorDecode, pn_io_error_decode, "(0x%x)"),\r
-            u8ErrorCode1,\r
-            u8ErrorCode2);\r
-    }\r
-       proto_item_set_len(sub_item, offset - u32SubStart);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the alarm specifier */\r
-static int\r
-dissect_Alarm_specifier(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint16 u16AlarmSpecifierSequence;\r
-    guint16 u16AlarmSpecifierChannel;\r
-    guint16 u16AlarmSpecifierManufacturer;\r
-    guint16 u16AlarmSpecifierSubmodule;\r
-    guint16 u16AlarmSpecifierAR;\r
-    proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-\r
-    /* alarm specifier */\r
-       sub_item = proto_tree_add_item(tree, hf_pn_io_alarm_specifier, tvb, offset, 2, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_pdu_type);\r
-\r
-       dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_alarm_specifier_sequence, &u16AlarmSpecifierSequence);\r
-    u16AlarmSpecifierSequence &= 0x07FF;\r
-       dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_alarm_specifier_channel, &u16AlarmSpecifierChannel);\r
-    u16AlarmSpecifierChannel = (u16AlarmSpecifierChannel &0x0800) >> 11;\r
-       dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_alarm_specifier_manufacturer, &u16AlarmSpecifierManufacturer);\r
-    u16AlarmSpecifierManufacturer = (u16AlarmSpecifierManufacturer &0x1000) >> 12;\r
-       dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_alarm_specifier_submodule, &u16AlarmSpecifierSubmodule);\r
-    u16AlarmSpecifierSubmodule = (u16AlarmSpecifierSubmodule & 0x2000) >> 13;\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_alarm_specifier_ardiagnosis, &u16AlarmSpecifierAR);\r
-    u16AlarmSpecifierAR = (u16AlarmSpecifierAR & 0x8000) >> 15;\r
-\r
-\r
-    proto_item_append_text(sub_item, ", Sequence: %u, Channel: %u, Manuf: %u, Submodule: %u AR: %u", \r
-        u16AlarmSpecifierSequence, u16AlarmSpecifierChannel, \r
-        u16AlarmSpecifierManufacturer, u16AlarmSpecifierSubmodule, u16AlarmSpecifierAR);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the alarm header */\r
-static int\r
-dissect_Alarm_header(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint16 u16AlarmType;\r
-    guint32 u32Api;\r
-    guint16 u16SlotNr;\r
-    guint16 u16SubslotNr;\r
-\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_alarm_type, &u16AlarmType);\r
-       offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_api, &u32Api);\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_slot_nr, &u16SlotNr);\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_subslot_nr, &u16SubslotNr);\r
-\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Slot: %u/%u", \r
-        val_to_str(u16AlarmType, pn_io_alarm_type, "Unknown"),\r
-        u16SlotNr, u16SubslotNr);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the alarm note block */\r
-static int\r
-dissect_Alarm_note_block(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep, guint16 body_length)\r
-{\r
-    guint32 u32ModuleIdentNumber;\r
-    guint32 u32SubmoduleIdentNumber;\r
-\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_str(pinfo->cinfo, COL_INFO, ", Alarm Notification");\r
-\r
-    offset = dissect_Alarm_header(tvb, offset, pinfo, tree, drep);\r
-    \r
-       offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_module_ident_number, &u32ModuleIdentNumber);\r
-       offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_submodule_ident_number, &u32SubmoduleIdentNumber);\r
-\r
-    offset = dissect_Alarm_specifier(tvb, offset, pinfo, tree, drep);\r
-\r
-    /* XXX - dissect AlarmItem */\r
-    body_length -= 20;\r
-    proto_tree_add_string_format(tree, hf_pn_io_data, tvb, offset, body_length, "data", \r
-        "Alarm Item Data: %u bytes", body_length);\r
-    offset += body_length;\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the alarm acknowledge block */\r
-static int\r
-dissect_Alarm_ack_block(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_str(pinfo->cinfo, COL_INFO, ", Alarm Ack");\r
-\r
-    offset = dissect_Alarm_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_Alarm_specifier(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the read/write header */\r
-static int\r
-dissect_ReadWrite_header(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    e_uuid_t uuid;\r
-    guint32 u32Api;\r
-    guint16 u16SlotNr;\r
-    guint16 u16SubslotNr;\r
-    guint16 u16Index;\r
-    guint16 u16SeqNr;\r
-\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_seq_number, &u16SeqNr);\r
-\r
-    offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_ar_uuid, &uuid);\r
-\r
-       offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_api, &u32Api);\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_slot_nr, &u16SlotNr);\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_subslot_nr, &u16SubslotNr);\r
-    proto_tree_add_string_format(tree, hf_pn_io_padding, tvb, offset, 2, "padding", "Padding: 2 bytes");\r
-    offset += 2;\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_index, &u16Index);\r
-\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_fstr(pinfo->cinfo, COL_INFO, ", Api: %u, Slot: %u/%u",\r
-            u32Api, u16SlotNr, u16SubslotNr);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the read/write request block */\r
-static int\r
-dissect_ReadWrite_rqst_block(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint32 u32RecDataLen;\r
-\r
-\r
-    offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, drep);\r
-\r
-       offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_record_data_length, &u32RecDataLen);\r
-    /* XXX: don't know how to handle the optional TargetARUUID */\r
-\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes",\r
-            u32RecDataLen);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the read/write response block */\r
-static int\r
-dissect_ReadWrite_resp_block(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint32 u32RecDataLen;\r
-    guint16 u16AddVal1;\r
-    guint16 u16AddVal2;\r
-\r
-\r
-    offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, drep);\r
-\r
-       offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_record_data_length, &u32RecDataLen);\r
-\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_add_val1, &u16AddVal1);\r
-\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_add_val2, &u16AddVal2);\r
-\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes",\r
-            u32RecDataLen);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the control/connect block */\r
-static int\r
-dissect_ControlConnect_block(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    e_uuid_t    ar_uuid;\r
-       proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-    guint16     u16PrmEnd;\r
-    guint16     u16ApplReady;\r
-    guint16     u16Release;\r
-    guint16     u16CmdDone;\r
-\r
-\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,\r
-                        hf_pn_io_reserved16, NULL);\r
-\r
-    offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_ar_uuid, &ar_uuid);\r
-\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,\r
-                        hf_pn_io_sessionkey, NULL);\r
-\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,\r
-                        hf_pn_io_reserved16, NULL);\r
-\r
-    sub_item = proto_tree_add_item(tree, hf_pn_io_control_command, tvb, offset, 2, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_control_command);\r
-\r
-    dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,\r
-                        hf_pn_io_control_command_prmend, &u16PrmEnd);\r
-    if(u16PrmEnd & 0x0001) {\r
-        proto_item_append_text(sub_item, ", Parameter End");\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Parameter End\"");\r
-    }\r
-    dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,\r
-                        hf_pn_io_control_command_applready, &u16ApplReady);\r
-    if((u16ApplReady >> 1) & 0x0001) {\r
-        proto_item_append_text(sub_item, ", Application Ready");\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Application Ready\"");\r
-    }\r
-    dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,\r
-                        hf_pn_io_control_command_release, &u16Release);\r
-    if((u16Release >> 2) & 0x0001) {\r
-        proto_item_append_text(sub_item, ", Release");\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Release\"");\r
-    }\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep,\r
-                        hf_pn_io_control_command_done, &u16CmdDone);\r
-    if((u16CmdDone >> 3) & 0x0001) {\r
-        proto_item_append_text(sub_item, ", Done");\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", Command: \"Done\"");\r
-    }\r
-\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep,\r
-                        hf_pn_io_control_block_properties, NULL);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect one PN-IO block (depending on the block type) */\r
-static int\r
-dissect_block(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep, guint32 u32Idx)\r
-{\r
-    guint16 u16BlockType;\r
-    guint16 u16BlockLength;\r
-    guint8 u8BlockVersionHigh;\r
-    guint8 u8BlockVersionLow;\r
-       proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-       guint32 u32SubStart;\r
-    guint16 u16BodyLength;\r
-\r
-\r
-    /* from here, we only have big endian (network byte ordering) */\r
-    drep[0] &= ~0x10;\r
-\r
-    sub_item = proto_tree_add_item(tree, hf_pn_io_block, tvb, offset, 0, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_block);\r
-    u32SubStart = offset;\r
-\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_block_type, &u16BlockType);\r
-       offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_block_length, &u16BlockLength);\r
-       offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_block_version_high, &u8BlockVersionHigh);\r
-       offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_block_version_low, &u8BlockVersionLow);\r
-\r
-    /* block length is without type and length fields, but with version field */\r
-    /* as it's already dissected, remove it */\r
-    u16BodyLength = u16BlockLength - 2;\r
-\r
-    switch(u16BlockType) {\r
-    case(0x0001):\r
-    case(0x0002):\r
-        dissect_Alarm_note_block(tvb, offset, pinfo, sub_tree, drep, u16BodyLength);\r
-        break;\r
-    case(0x0110):\r
-    case(0x0112):\r
-    case(0x0114):\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",\r
-            val_to_str(u16BlockType, pn_io_block_type, "Unknown"));\r
-        dissect_ControlConnect_block(tvb, offset, pinfo, sub_tree, drep);\r
-        break;\r
-    case(0x0008):\r
-    case(0x0009):\r
-        dissect_ReadWrite_rqst_block(tvb, offset, pinfo, sub_tree, drep);\r
-        break;\r
-    case(0x8001):\r
-    case(0x8002):\r
-        dissect_Alarm_ack_block(tvb, offset, pinfo, sub_tree, drep);\r
-        break;\r
-    case(0x8008):\r
-    case(0x8009):\r
-        dissect_ReadWrite_resp_block(tvb, offset, pinfo, sub_tree, drep);\r
-        break;\r
-    case(0x8110):\r
-    case(0x8112):\r
-    case(0x8114):\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",\r
-            val_to_str(u16BlockType, pn_io_block_type, "Unknown"));\r
-        dissect_ControlConnect_block(tvb, offset, pinfo, sub_tree, drep);\r
-        break;\r
-    default:\r
-        if (check_col(pinfo->cinfo, COL_INFO) && u32Idx < 3)\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",\r
-            val_to_str(u16BlockType, pn_io_block_type, "Unknown"));\r
-       proto_tree_add_string_format(sub_tree, hf_pn_io_data, tvb, offset, u16BodyLength, "undecoded", "Undecoded Data: %d bytes", u16BodyLength);\r
-    }\r
-    offset += u16BodyLength;\r
-\r
-       proto_item_append_text(sub_item, "[%u]: Type=\"%s\" (0x%04x), Length=%u(+4), Version=%u.%u", \r
-               u32Idx, val_to_str(u16BlockType, pn_io_block_type, "Unknown"), u16BlockType,\r
-        u16BlockLength, u8BlockVersionHigh, u8BlockVersionLow);\r
-       proto_item_set_len(sub_item, offset - u32SubStart);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect any number of PN-IO blocks */\r
-static int\r
-dissect_blocks(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint32 u32Idx = 0;\r
-    \r
-\r
-    while(tvb_length(tvb) > (guint) offset) {\r
-        offset = dissect_block(tvb, offset, pinfo, tree, drep, u32Idx);\r
-        u32Idx++;\r
-    }\r
-\r
-    if(u32Idx > 3) {\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_fstr(pinfo->cinfo, COL_INFO, ", ... (%u blocks)",\r
-            u32Idx);\r
-    }\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO (DCE-RPC) request header */\r
-static int\r
-dissect_IPNIO_rqst_header(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint32 u32ArgsMax;\r
-    guint32 u32ArgsLen;\r
-    guint32 u32MaxCount;\r
-    guint32 u32Offset;\r
-    guint32 u32ArraySize;\r
-\r
-       proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-       guint32 u32SubStart;\r
-\r
-\r
-    /* args_max */\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_args_max, &u32ArgsMax);\r
-    /* args_len */\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_args_len, &u32ArgsLen);\r
-\r
-    sub_item = proto_tree_add_item(tree, hf_pn_io_array, tvb, offset, 0, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io);\r
-    u32SubStart = offset;\r
-\r
-    /* RPC array header */\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_array_max_count, &u32MaxCount);\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_array_offset, &u32Offset);\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_array_act_count, &u32ArraySize);\r
-\r
-       proto_item_append_text(sub_item, ": Max: %u, Offset: %u, Size: %u", \r
-        u32MaxCount, u32Offset, u32ArraySize);\r
-       proto_item_set_len(sub_item, offset - u32SubStart);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO (DCE-RPC) response header */\r
-static int\r
-dissect_IPNIO_resp_header(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint32 u32ArgsLen;\r
-    guint32 u32MaxCount;\r
-    guint32 u32Offset;\r
-    guint32 u32ArraySize;\r
-\r
-       proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-       guint32 u32SubStart;\r
-\r
-    offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep);\r
-\r
-    /* args_len */\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \r
-                        hf_pn_io_args_len, &u32ArgsLen);\r
-\r
-    sub_item = proto_tree_add_item(tree, hf_pn_io_array, tvb, offset, 0, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io);\r
-    u32SubStart = offset;\r
-\r
-    /* RPC array header */\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_array_max_count, &u32MaxCount);\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_array_offset, &u32Offset);\r
-       offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, drep, \r
-                        hf_pn_io_array_act_count, &u32ArraySize);\r
-\r
-    proto_item_append_text(sub_item, ": Max: %u, Offset: %u, Size: %u", \r
-        u32MaxCount, u32Offset, u32ArraySize);\r
-       proto_item_set_len(sub_item, offset - u32SubStart);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO connect request */\r
-static int\r
-dissect_IPNIO_Connect_rqst(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    \r
-    offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_blocks(tvb, offset, pinfo, tree, drep);\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO connect response */\r
-static int\r
-dissect_IPNIO_Connect_resp(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-\r
-    offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_blocks(tvb, offset, pinfo, tree, drep);\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO release request */\r
-static int\r
-dissect_IPNIO_Release_rqst(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    \r
-    offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_blocks(tvb, offset, pinfo, tree, drep);\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO release response */\r
-static int\r
-dissect_IPNIO_Release_resp(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-\r
-    offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_blocks(tvb, offset, pinfo, tree, drep);\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO control request */\r
-static int\r
-dissect_IPNIO_Control_rqst(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    \r
-    offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_blocks(tvb, offset, pinfo, tree, drep);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO control response */\r
-static int\r
-dissect_IPNIO_Control_resp(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-\r
-    offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_blocks(tvb, offset, pinfo, tree, drep);\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO read request */\r
-static int\r
-dissect_IPNIO_Read_rqst(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    \r
-    offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO read response */\r
-static int\r
-dissect_IPNIO_Read_resp(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    gint remain;\r
-\r
-    offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);\r
-\r
-    /* XXX - remaining bytes: dissection not yet implemented */\r
-    remain = tvb_length_remaining(tvb, offset);\r
-    proto_tree_add_string_format(tree, hf_pn_io_data, tvb, offset, remain, "data", "User Data: %d bytes", remain);\r
-    offset += remain;\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO write request */\r
-static int\r
-dissect_IPNIO_Write_rqst(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    gint remain;\r
-\r
-    offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);\r
-\r
-    /* XXX - remaining bytes: dissection not yet implemented */\r
-    remain = tvb_length_remaining(tvb, offset);\r
-    proto_tree_add_string_format(tree, hf_pn_io_data, tvb, offset, remain, "data", "User Data: %d bytes", remain);\r
-    offset += remain;\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO write response */\r
-static int\r
-dissect_IPNIO_Write_resp(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-\r
-    offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, drep);\r
-\r
-    offset = dissect_block(tvb, offset, pinfo, tree, drep, 0);\r
-\r
-       return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO Data PDU (on top of PN-RT protocol) */\r
-static int\r
-dissect_PNIO_Data(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    proto_item *data_item;\r
-/*     proto_tree *data_tree;*/\r
-\r
-       data_item = proto_tree_add_protocol_format(tree, proto_pn_io, tvb, 0, tvb_length(tvb),\r
-                               "PROFINET IO Data: %u bytes", tvb_length(tvb));\r
-#if 0\r
-    data_tree = proto_item_add_subtree(data_item, ett_pn_io_rta);\r
-\r
-    /* XXX - remaining bytes: dissection not yet implemented */\r
-    proto_tree_add_string_format(data_tree, hf_pn_io_data, tvb, 0, tvb_length(tvb), "data", \r
-        "PN-IO Data: %u bytes", tvb_length(tvb));\r
-#endif\r
-\r
-    if (check_col(pinfo->cinfo, COL_PROTOCOL))\r
-           col_add_str(pinfo->cinfo, COL_PROTOCOL, "PNIO");\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect a PN-IO RTA PDU (on top of PN-RT protocol) */\r
-static int\r
-dissect_PNIO_RTA(tvbuff_t *tvb, int offset,\r
-       packet_info *pinfo, proto_tree *tree, guint8 *drep)\r
-{\r
-    guint16 u16AlarmDstEndpoint;\r
-    guint16 u16AlarmSrcEndpoint;\r
-    guint8  u8PDUType;\r
-    guint8  u8PDUVersion;\r
-    guint8  u8WindowSize;\r
-    guint8  u8Tack;\r
-    guint16 u16SendSeqNum;\r
-    guint16 u16AckSeqNum;\r
-    guint16 u16VarPartLen;\r
-\r
-    proto_item *rta_item;\r
-       proto_tree *rta_tree;\r
-\r
-    proto_item *sub_item;\r
-       proto_tree *sub_tree;\r
-\r
-       rta_item = proto_tree_add_protocol_format(tree, proto_pn_io, tvb, 0, 0,\r
-                               "PROFINET IO Alarm");\r
-       rta_tree = proto_item_add_subtree(rta_item, ett_pn_io_rta);\r
-\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep, \r
-                    hf_pn_io_alarm_dst_endpoint, &u16AlarmDstEndpoint);\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep, \r
-                    hf_pn_io_alarm_src_endpoint, &u16AlarmSrcEndpoint);\r
-\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-           col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: 0x%x, Dst: 0x%x",\r
-        u16AlarmSrcEndpoint, u16AlarmDstEndpoint);\r
-\r
-    /* PDU type */\r
-       sub_item = proto_tree_add_item(rta_tree, hf_pn_io_pdu_type, tvb, offset, 1, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_pdu_type);\r
-    dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, \r
-                    hf_pn_io_pdu_type_type, &u8PDUType);\r
-    u8PDUType &= 0x0F;\r
-    offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, \r
-                    hf_pn_io_pdu_type_version, &u8PDUVersion);\r
-    u8PDUVersion >>= 4;\r
-    proto_item_append_text(sub_item, ", Type: %s, Version: %u", \r
-        val_to_str(u8PDUType, pn_io_pdu_type, "Unknown"),\r
-        u8PDUVersion);\r
-\r
-    /* additional flags */\r
-       sub_item = proto_tree_add_item(rta_tree, hf_pn_io_add_flags, tvb, offset, 1, FALSE);\r
-       sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_add_flags);\r
-    dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, \r
-                    hf_pn_io_window_size, &u8WindowSize);\r
-    u8WindowSize &= 0x0F;\r
-    offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, \r
-                    hf_pn_io_tack, &u8Tack);\r
-    u8Tack >>= 4;\r
-    proto_item_append_text(sub_item, ", Window Size: %u, Tack: %u", \r
-        u8WindowSize, u8Tack);\r
-\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep, \r
-                    hf_pn_io_send_seq_num, &u16SendSeqNum);\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep, \r
-                    hf_pn_io_ack_seq_num, &u16AckSeqNum);\r
-    offset = dissect_dcerpc_uint16(tvb, offset, pinfo, rta_tree, drep, \r
-                    hf_pn_io_var_part_len, &u16VarPartLen);\r
-\r
-    switch(u8PDUType & 0x0F) {\r
-    case(1):    /* Data-RTA */\r
-       if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_str(pinfo->cinfo, COL_INFO, ", Data-RTA");\r
-        offset = dissect_block(tvb, offset, pinfo, rta_tree, drep, 0);\r
-        break;\r
-    case(2):    /* NACK-RTA */\r
-       if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_str(pinfo->cinfo, COL_INFO, ", NACK-RTA");\r
-        /* no additional data */\r
-        break;\r
-    case(3):    /* ACK-RTA */\r
-       if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_str(pinfo->cinfo, COL_INFO, ", ACK-RTA");\r
-        /* no additional data */\r
-        break;\r
-    case(4):    /* ERR-RTA */\r
-       if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_append_str(pinfo->cinfo, COL_INFO, ", ERR-RTA");\r
-        offset = dissect_PNIO_status(tvb, offset, pinfo, rta_tree, drep);\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_io_data, tvb, 0, tvb_length(tvb), "data", \r
-            "PN-IO Alarm: unknown PDU type 0x%x", u8PDUType);    \r
-    }\r
-\r
-       if (check_col(pinfo->cinfo, COL_PROTOCOL))\r
-           col_add_str(pinfo->cinfo, COL_PROTOCOL, "PNIO-AL");\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* possibly dissect a PN-IO PN-RT packet */\r
-static gboolean\r
-dissect_PNIO_heur(tvbuff_t *tvb, \r
-       packet_info *pinfo, proto_tree *tree)\r
-{\r
-    guint8  drep_data = 0;\r
-    guint8  *drep = &drep_data;\r
-       guint8  u8CBAVersion;\r
-    guint16 u16FrameID;\r
-\r
-\r
-    /* the sub tvb will NOT contain the frame_id here! */\r
-    u16FrameID = GPOINTER_TO_INT(pinfo->private_data);\r
-\r
-    u8CBAVersion = tvb_get_guint8 (tvb, 0);\r
-\r
-    /* is this a PNIO class 2 data packet? */\r
-       /* frame id must be in valid range (cyclic Real-Time, class=2) */\r
-       if (u16FrameID >= 0x8000 && u16FrameID < 0xbf00) {\r
-        dissect_PNIO_Data(tvb, 0, pinfo, tree, drep);\r
-        return TRUE;\r
-    }\r
-\r
-    /* is this a PNIO class 1 data packet? */\r
-       /* frame id must be in valid range (cyclic Real-Time, class=1) and\r
-     * first byte (CBA version field) has to be != 0x11 */\r
-       if (u16FrameID >= 0xc000 && u16FrameID < 0xfb00 && u8CBAVersion != 0x11) {\r
-        dissect_PNIO_Data(tvb, 0, pinfo, tree, drep);\r
-        return TRUE;\r
-    }\r
-\r
-    /* is this a PNIO high priority alarm packet? */\r
-    if(u16FrameID == 0xfc01) {\r
-       if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_add_str(pinfo->cinfo, COL_INFO, "Alarm High");\r
-\r
-        dissect_PNIO_RTA(tvb, 0, pinfo, tree, drep);\r
-        return TRUE;\r
-    }\r
-\r
-    /* is this a PNIO low priority alarm packet? */\r
-    if(u16FrameID == 0xfe01) {\r
-       if (check_col(pinfo->cinfo, COL_INFO))\r
-               col_add_str(pinfo->cinfo, COL_INFO, "Alarm Low");\r
-\r
-        dissect_PNIO_RTA(tvb, 0, pinfo, tree, drep);\r
-        return TRUE;\r
-    }\r
-\r
-    /* this PN-RT packet doesn't seem to be PNIO specific */\r
-    return FALSE;\r
-}\r
-\r
-\r
-/* the PNIO dcerpc interface table */\r
-static dcerpc_sub_dissector pn_io_dissectors[] = {\r
-{ 0, "Connect", dissect_IPNIO_Connect_rqst, dissect_IPNIO_Connect_resp },\r
-{ 1, "Release", dissect_IPNIO_Release_rqst, dissect_IPNIO_Release_resp },\r
-{ 2, "Read",    dissect_IPNIO_Read_rqst,    dissect_IPNIO_Read_resp },\r
-{ 3, "Write",   dissect_IPNIO_Write_rqst,   dissect_IPNIO_Write_resp },\r
-{ 4, "Control", dissect_IPNIO_Control_rqst, dissect_IPNIO_Control_resp },\r
-       { 0, NULL, NULL, NULL }\r
-};\r
-\r
-\r
-void\r
-proto_register_pn_io (void)\r
-{\r
-       static hf_register_info hf[] = {\r
-       { &hf_pn_io_opnum,\r
-               { "Operation", "pn_io.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_reserved16,\r
-               { "Reserved", "pn_io.reserved16", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_array,\r
-        { "Array", "pn_io.array", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_status,\r
-               { "Status", "pn_io.status", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_args_max,\r
-               { "ArgsMaximum", "pn_io.args_max", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_args_len,\r
-               { "ArgsLength", "pn_io.args_len", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_array_max_count,\r
-               { "MaximumCount", "pn_io.array_max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_array_offset,\r
-               { "Offset", "pn_io.array_offset", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_io_array_act_count,\r
-               { "ActualCount", "pn_io.array_act_count", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_ar_uuid,\r
-      { "ARUUID", "pn_io.ar_uuid", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_api,\r
-      { "API", "pn_io.api", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_slot_nr,\r
-      { "SlotNumber", "pn_io.slot_nr", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_subslot_nr,\r
-      { "SubslotNumber", "pn_io.subslot_nr", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_index,\r
-      { "Index", "pn_io.index", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_seq_number,\r
-      { "SeqNumber", "pn_io.seq_number", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_record_data_length,\r
-      { "RecordDataLength", "pn_io.record_data_length", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_padding,\r
-      { "Padding", "pn_io.padding", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_add_val1,\r
-      { "AdditionalValue1", "pn_io.add_val1", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_add_val2,\r
-      { "AdditionalValue2", "pn_io.add_val2", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_block_type,\r
-      { "BlockType", "pn_io.block_type", FT_UINT16, BASE_HEX, VALS(pn_io_block_type), 0x0, "", HFILL }},\r
-    { &hf_pn_io_block_length,\r
-      { "BlockLength", "pn_io.block_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_block_version_high,\r
-      { "BlockVersionHigh", "pn_io.block_version_high", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_block_version_low,\r
-      { "BlockVersionLow", "pn_io.block_version_low", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_sessionkey,\r
-      { "SessionKey", "pn_io.session_key", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_control_command,\r
-      { "ControlCommand", "pn_io.control_command", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_control_command_prmend,\r
-      { "PrmEnd", "pn_io.control_command.prmend", FT_UINT16, BASE_DEC, NULL, 0x0001, "", HFILL }},\r
-    { &hf_pn_io_control_command_applready,\r
-      { "ApplicationReady", "pn_io.control_command.applready", FT_UINT16, BASE_DEC, NULL, 0x0002, "", HFILL }},\r
-    { &hf_pn_io_control_command_release,\r
-      { "Release", "pn_io.control_command.release", FT_UINT16, BASE_DEC, NULL, 0x0004, "", HFILL }},\r
-    { &hf_pn_io_control_command_done,\r
-      { "Done", "pn_io.control_command.done", FT_UINT16, BASE_DEC, NULL, 0x0008, "", HFILL }},\r
-    { &hf_pn_io_control_block_properties,\r
-      { "ControlBlockProperties", "pn_io.control_block_properties", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_io_error_code,\r
-      { "ErrorCode", "pn_io.error_code", FT_UINT8, BASE_HEX, VALS(pn_io_error_code), 0x0, "", HFILL }},\r
-    { &hf_pn_io_error_decode,\r
-      { "ErrorDecode", "pn_io.error_decode", FT_UINT8, BASE_HEX, VALS(pn_io_error_decode), 0x0, "", HFILL }},\r
-    { &hf_pn_io_error_code1,\r
-      { "ErrorCode1", "pn_io.error_code1", FT_UINT8, BASE_HEX, VALS(pn_io_error_code1), 0x0, "", HFILL }},\r
-    { &hf_pn_io_error_code2,\r
-      { "ErrorCode2", "pn_io.error_code2", FT_UINT8, BASE_HEX, VALS(pn_io_error_code2), 0x0, "", HFILL }},\r
-    { &hf_pn_io_error_code1_pniorw,\r
-      { "ErrorCode1 (PNIORW)", "pn_io.error_code1", FT_UINT8, BASE_HEX, VALS(pn_io_error_code1_pniorw), 0x0, "", HFILL }},\r
-    { &hf_pn_io_error_code1_pnio,\r
-      { "ErrorCode1 (PNIO)", "pn_io.error_code1", FT_UINT8, BASE_HEX, VALS(pn_io_error_code1_pnio), 0x0, "", HFILL }},\r
-       { &hf_pn_io_block,\r
-    { "Block", "pn_io.block", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_data,\r
-      { "Undecoded Data", "pn_io.data", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_io_alarm_type,\r
-      { "AlarmType", "pn_io.alarm_type", FT_UINT16, BASE_HEX, VALS(pn_io_alarm_type), 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_io_alarm_specifier,\r
-      { "AlarmSpecifier", "pn_io.alarm_specifier", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_alarm_specifier_sequence,\r
-      { "SequenceNumber", "pn_io.alarm_specifier.sequence", FT_UINT16, BASE_HEX, NULL, 0x07FF, "", HFILL }},\r
-    { &hf_pn_io_alarm_specifier_channel,\r
-      { "ChannelDiagnosis", "pn_io.alarm_specifier.channel", FT_UINT16, BASE_HEX, NULL, 0x0800, "", HFILL }},\r
-    { &hf_pn_io_alarm_specifier_manufacturer,\r
-      { "ManufacturerSpecificDiagnosis", "pn_io.alarm_specifier.manufacturer", FT_UINT16, BASE_HEX, NULL, 0x1000, "", HFILL }},\r
-    { &hf_pn_io_alarm_specifier_submodule,\r
-      { "SubmoduleDiagnosisState", "pn_io.alarm_specifier.submodule", FT_UINT16, BASE_HEX, NULL, 0x2000, "", HFILL }},\r
-    { &hf_pn_io_alarm_specifier_ardiagnosis,\r
-      { "ARDiagnosisState", "pn_io.alarm_specifier.ardiagnosis", FT_UINT16, BASE_HEX, NULL, 0x8000, "", HFILL }},\r
-\r
-    { &hf_pn_io_alarm_dst_endpoint,\r
-      { "AlarmDstEndpoint", "pn_io.alarm_dst_endpoint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_alarm_src_endpoint,\r
-      { "AlarmSrcEndpoint", "pn_io.alarm_src_endpoint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_pdu_type,\r
-      { "PDUType", "pn_io.pdu_type", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_pdu_type_type,\r
-      { "Type", "pn_io.pdu_type.type", FT_UINT8, BASE_HEX, VALS(pn_io_pdu_type), 0x0F, "", HFILL }},\r
-    { &hf_pn_io_pdu_type_version,\r
-      { "Version", "pn_io.pdu_type.version", FT_UINT8, BASE_HEX, NULL, 0xF0, "", HFILL }},\r
-    { &hf_pn_io_add_flags,\r
-      { "AddFlags", "pn_io.add_flags", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_window_size,\r
-      { "WindowSize", "pn_io.window_size", FT_UINT8, BASE_DEC, NULL, 0x0F, "", HFILL }},\r
-    { &hf_pn_io_tack,\r
-      { "TACK", "pn_io.tack", FT_UINT8, BASE_HEX, NULL, 0xF0, "", HFILL }},\r
-    { &hf_pn_io_send_seq_num,\r
-      { "SendSeqNum", "pn_io.send_seq_num", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_ack_seq_num,\r
-      { "AckSeqNum", "pn_io.ack_seq_num", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_var_part_len,\r
-      { "VarPartLen", "pn_io.var_part_len", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_module_ident_number,\r
-      { "ModuleIdentNumber", "pn_io.module_ident_number", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_io_submodule_ident_number,\r
-      { "SubmoduleIdentNumber", "pn_io.submodule_ident_number", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}\r
-    };\r
-\r
-       static gint *ett[] = {\r
-               &ett_pn_io,\r
-        &ett_pn_io_block,\r
-        &ett_pn_io_status,\r
-        &ett_pn_io_rta,\r
-               &ett_pn_io_pdu_type,\r
-        &ett_pn_io_add_flags,\r
-        &ett_pn_io_control_command\r
-       };\r
-       proto_pn_io = proto_register_protocol ("PROFINET IO", "PNIO-CM", "pn_io");\r
-       proto_register_field_array (proto_pn_io, hf, array_length (hf));\r
-       proto_register_subtree_array (ett, array_length (ett));\r
-}\r
-\r
-void\r
-proto_reg_handoff_pn_io (void)\r
-{\r
-       /* Register the protocols as dcerpc */\r
-       dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_device, ver_pn_io_device, pn_io_dissectors, hf_pn_io_opnum);\r
-       dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_controller, ver_pn_io_controller, pn_io_dissectors, hf_pn_io_opnum);\r
-       dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_supervisor, ver_pn_io_supervisor, pn_io_dissectors, hf_pn_io_opnum);\r
-       dcerpc_init_uuid (proto_pn_io, ett_pn_io, &uuid_pn_io_parameterserver, ver_pn_io_parameterserver, pn_io_dissectors, hf_pn_io_opnum);\r
-\r
-       heur_dissector_add("pn_rt", dissect_PNIO_heur, proto_pn_io);\r
-}\r
+/* packet-dcerpc-pn-io.c
+ * Routines for PROFINET IO dissection
+ * (based on DCE-RPC and PN-RT protocols)
+ *
+ * $ID: $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <epan/packet.h>
+#include "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);
+}
index 9c1cec1ef4a41d1cef616040801ae7b48c824307..442dbb4b4af056ff4aeacb4b1996445ffecc2352 100644 (file)
@@ -1,7 +1,9 @@
 /* packet-pn-dcp.c
- * Routines for PN-DCP (PROFINET Discovery and basic Configuration Protocol) \r
+ * Routines for PN-DCP (PROFINET Discovery and basic Configuration Protocol) 
  * packet dissection.
  *
+ * $Id$
+ *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1999 Gerald Combs
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-\r
-#ifdef HAVE_SYS_TYPES_H\r
-#include <sys/types.h>\r
-#endif\r
-\r
-#include <string.h>\r
-\r
-#include <glib.h>\r
-#include <epan/packet.h>\r
-#include "packet-dcerpc.h"\r
-\r
-static int proto_pn_dcp = -1;\r
-\r
-static int hf_pn_dcp = -1;\r
-\r
-static int hf_pn_dcp_service_id = -1;\r
-static int hf_pn_dcp_service_type = -1;\r
-static int hf_pn_dcp_xid = -1;\r
-static int hf_pn_dcp_reserved8 = -1;\r
-static int hf_pn_dcp_reserved16 = -1;\r
-static int hf_pn_dcp_response_delay = -1;\r
-static int hf_pn_dcp_data_length = -1;\r
-static int hf_pn_dcp_block_length = -1;\r
-\r
-static int hf_pn_dcp_block = -1;\r
-\r
-static int hf_pn_dcp_result = -1;\r
-\r
-static int hf_pn_dcp_option = -1;\r
-static int hf_pn_dcp_suboption = -1;\r
-static int hf_pn_dcp_req_status = -1;\r
-static int hf_pn_dcp_res_status = -1;\r
-\r
-static int hf_pn_dcp_suboption_ip = -1;\r
-static int hf_pn_dcp_suboption_ip_status = -1;\r
-static int hf_pn_dcp_suboption_ip_ip = -1;\r
-static int hf_pn_dcp_suboption_ip_subnetmask = -1;\r
-static int hf_pn_dcp_suboption_ip_default_router = -1;\r
-\r
-static int hf_pn_dcp_suboption_device = -1;\r
-static int hf_pn_dcp_suboption_device_typeofstation = -1;\r
-static int hf_pn_dcp_suboption_device_nameofstation = -1;\r
-static int hf_pn_dcp_suboption_vendor_id = -1;\r
-static int hf_pn_dcp_suboption_device_id = -1;\r
-static int hf_pn_dcp_suboption_device_role = -1;\r
-\r
-static int hf_pn_dcp_suboption_dhcp = -1;\r
-\r
-static int hf_pn_dcp_suboption_lldp = -1;\r
-\r
-static int hf_pn_dcp_suboption_control = -1;\r
-static int hf_pn_dcp_suboption_control_status = -1;\r
-\r
-static int hf_pn_dcp_suboption_all = -1;\r
-\r
-static int hf_pn_dcp_suboption_manuf = -1;\r
-\r
-static int hf_pn_dcp_data = -1;\r
-\r
-\r
-static gint ett_pn_dcp = -1;\r
-static gint ett_pn_dcp_block = -1;\r
-\r
-#define FRAME_ID_UC         0xfefd\r
-#define FRAME_ID_MC         0xfefe\r
-#define FRAME_ID_MC_RESP    0xfeff\r
-\r
-\r
-#define PNDCP_SERVICE_ID_GET        0x03\r
-#define PNDCP_SERVICE_ID_SET        0x04\r
-#define PNDCP_SERVICE_ID_IDENTIFY   0x05\r
-\r
-static const value_string pn_dcp_service_id[] = {\r
-       { 0x00, "reserved" },\r
-       { 0x01, "Manufacturer specific" },\r
-       { 0x02, "Manufacturer specific" },\r
-       { PNDCP_SERVICE_ID_GET, "Get" },\r
-       { PNDCP_SERVICE_ID_SET, "Set" },\r
-       { PNDCP_SERVICE_ID_IDENTIFY, "Identify" },\r
-    /* 0x06 - 0xff reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-#define PNDCP_SERVICE_TYPE_REQUEST              0\r
-#define PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS     1\r
-#define PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED 5\r
-\r
-static const value_string pn_dcp_service_type[] = {\r
-       { PNDCP_SERVICE_TYPE_REQUEST,               "Request" },\r
-       { PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS,      "Response Success" },\r
-       { PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED,  "Response - Request not supported" },\r
-    /* all others reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_result[] = {\r
-       { 0x00, "Ok" },\r
-       { 0x01, "Option unsupp." },\r
-       { 0x02, "Suboption unsupp." },\r
-       { 0x03, "Suboption not set" },\r
-       { 0x04, "Manufacturer specific" },\r
-       { 0x05, "Manufacturer specific" },\r
-       { 0x06, "Ressource Error" },\r
-    /* all others reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_req_status[] = {\r
-       { 0x0000, "Don't save data permanent" },\r
-       { 0x0001, "Save data permanent" },\r
-    /*0x0002 - 0xffff reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-\r
-#define PNDCP_OPTION_IP             0x01\r
-#define PNDCP_OPTION_DEVICE         0x02\r
-#define PNDCP_OPTION_DHCP           0x03\r
-#define PNDCP_OPTION_LLDP           0x04\r
-#define PNDCP_OPTION_CONTROL        0x05\r
-#define PNDCP_OPTION_MANUF_X80      0x80\r
-#define PNDCP_OPTION_MANUF_X81      0x81\r
-#define PNDCP_OPTION_ALLSELECTOR    0xff\r
-\r
-static const value_string pn_dcp_option[] = {\r
-       { 0x00, "reserved" },\r
-       { PNDCP_OPTION_IP,          "IP" },\r
-       { PNDCP_OPTION_DEVICE,      "Device properties" },\r
-       { PNDCP_OPTION_DHCP,        "DHCP" },\r
-       { PNDCP_OPTION_LLDP,        "LLDP" },\r
-       { PNDCP_OPTION_CONTROL,     "Control" },\r
-    /*0x06 - 0x7f reserved */\r
-    /*0x80 - 0xfe manufacturer specific */\r
-       { PNDCP_OPTION_MANUF_X80,   "Manufacturer specific" },\r
-       { PNDCP_OPTION_MANUF_X81,   "Manufacturer specific" },\r
-       { PNDCP_OPTION_ALLSELECTOR, "All Selector" },\r
-    { 0, NULL }\r
-};\r
-\r
-#define PNDCP_SUBOPTION_IP_MAC  0x01\r
-#define PNDCP_SUBOPTION_IP_IP   0x02\r
-\r
-static const value_string pn_dcp_suboption_ip[] = {\r
-       { 0x00, "Reserved" },\r
-       { PNDCP_SUBOPTION_IP_MAC,   "MAC address" },\r
-       { PNDCP_SUBOPTION_IP_IP,    "IP parameter" },\r
-    /*0x03 - 0xff reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_suboption_ip_status[] = {\r
-       { 0x0000, "IP not set" },\r
-       { 0x0001, "IP set" },\r
-       { 0x0002, "IP set by DHCP" },\r
-    /*0x0003 - 0xffff reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-#define PNDCP_SUBOPTION_DEVICE_MANUF            0x01\r
-#define PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION    0x02\r
-#define PNDCP_SUBOPTION_DEVICE_DEV_ID           0x03\r
-#define PNDCP_SUBOPTION_DEVICE_DEV_ROLE         0x04\r
-#define PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS      0x05\r
-\r
-static const value_string pn_dcp_suboption_device[] = {\r
-       { 0x00, "Reserved" },\r
-       { PNDCP_SUBOPTION_DEVICE_MANUF,         "Manufacturer specific (Type of Station)" },\r
-       { PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION, "Name of Station" },\r
-       { PNDCP_SUBOPTION_DEVICE_DEV_ID,        "Device ID" },\r
-       { PNDCP_SUBOPTION_DEVICE_DEV_ROLE,      "Device Role" },\r
-       { PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS,   "Device Options" },\r
-    /*0x06 - 0xff reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_suboption_dhcp[] = {\r
-    {  12, "Host name" },\r
-    {  43, "Vendor specific" },\r
-    {  54, "Server identifier" },\r
-    {  55, "Parameter request list" },\r
-    {  60, "Class identifier" },\r
-    {  61, "DHCP client identifier" },\r
-    {  81, "FQDN, Fully Qualified Domain Name" },\r
-    {  97, "UUID/GUID-based Client" },\r
-       { 255, "Control DHCP for address resolution" },\r
-    /*all others reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_suboption_lldp[] = {\r
-    /* currently unknown */\r
-    { 0, NULL }\r
-};\r
-\r
-#define PNDCP_SUBOPTION_CONTROL_START_TRANS 0x01\r
-#define PNDCP_SUBOPTION_CONTROL_END_TRANS   0x02\r
-#define PNDCP_SUBOPTION_CONTROL_SIGNAL      0x03\r
-#define PNDCP_SUBOPTION_CONTROL_RESPONSE    0x04\r
-\r
-static const value_string pn_dcp_suboption_control[] = {\r
-       { 0x00, "Reserved" },\r
-       { PNDCP_SUBOPTION_CONTROL_START_TRANS, "Start Transaction" },\r
-       { PNDCP_SUBOPTION_CONTROL_END_TRANS, "End Transaction" },\r
-       { PNDCP_SUBOPTION_CONTROL_SIGNAL, "Signal" },\r
-       { PNDCP_SUBOPTION_CONTROL_RESPONSE, "Response" },\r
-    /*0x05 - 0xff reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_suboption_all[] = {\r
-    { 0xff, "ALL Selector" },\r
-    /* all other reserved */\r
-    { 0, NULL }\r
-};\r
-\r
-static const value_string pn_dcp_suboption_manuf[] = {\r
-    /* none known */\r
-    { 0, NULL }\r
-};\r
-\r
-\r
-\r
-/* dissect an 8 bit unsigned integer */\r
-int\r
-dissect_pn_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,\r
-                  proto_tree *tree, int hfindex, guint8 *pdata)\r
-{\r
-    guint8 data;\r
-\r
-    data = tvb_get_guint8 (tvb, offset);\r
-    if (tree) {\r
-        proto_tree_add_uint(tree, hfindex, tvb, offset, 1, data);\r
-    }\r
-    if (pdata)\r
-        *pdata = data;\r
-    return offset + 1;\r
-}\r
-\r
-/* dissect a 16 bit unsigned integer */\r
-int\r
-dissect_pn_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,\r
-                       proto_tree *tree, int hfindex, guint16 *pdata)\r
-{\r
-    guint16 data;\r
-\r
-    data = tvb_get_ntohs (tvb, offset);\r
-\r
-    if (tree) {\r
-        proto_tree_add_uint(tree, hfindex, tvb, offset, 2, data);\r
-    }\r
-    if (pdata)\r
-        *pdata = data;\r
-    return offset + 2;\r
-}\r
-\r
-/* dissect a 32 bit unsigned integer */\r
-int\r
-dissect_pn_uint32(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,\r
-                       proto_tree *tree, int hfindex, guint32 *pdata)\r
-{\r
-    guint32 data;\r
-\r
-    data = tvb_get_ntohl (tvb, offset);\r
-\r
-    if (tree) {\r
-        proto_tree_add_uint(tree, hfindex, tvb, offset, 4, data);\r
-    }\r
-    if (pdata)\r
-        *pdata = data;\r
-    return offset+4;\r
-}\r
-\r
-/* dissect an IPv4 address */\r
-int \r
-dissect_pn_ipv4(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,\r
-                    proto_tree *tree, int hfindex, guint32 *pdata)\r
-{\r
-    guint32 data;\r
-\r
-    tvb_memcpy(tvb, (guint8 *)&data, offset, 4);\r
-    if(tree)\r
-        proto_tree_add_ipv4(tree, hfindex, tvb, offset, 4, data);\r
-\r
-    if (pdata)\r
-        *pdata = data;\r
-\r
-    return offset + 4;\r
-}\r
-\r
-/* dissect some padding data (with the given length) */\r
-int \r
-dissect_pn_padding(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,\r
-                    proto_tree *tree, int length)\r
-{\r
-    proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, length, "data", \r
-        "Padding: %u byte", length);\r
-\r
-    return offset + length;\r
-}\r
-\r
-/* append the given info text */\r
-static void\r
-pn_append_info(packet_info *pinfo, proto_item *dcp_item, char *text)\r
-{\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-        col_append_fstr(pinfo->cinfo, COL_INFO, text);\r
-\r
-    proto_item_append_text(dcp_item, text);\r
-}\r
-\r
-\r
-/* dissect the option field */\r
-static int\r
-dissect_PNDCP_Option(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                             proto_tree *tree, proto_item *block_item, int hfindex, gboolean append_col)\r
-{\r
-    guint8 option;\r
-    guint8 suboption;\r
-    const value_string *val_str;\r
-\r
-    offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hfindex, &option);\r
-    switch(option) {\r
-    case(PNDCP_OPTION_IP):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);\r
-        val_str = pn_dcp_suboption_ip;\r
-        break;\r
-    case(PNDCP_OPTION_DEVICE):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);\r
-        val_str = pn_dcp_suboption_device;\r
-        break;\r
-    case(PNDCP_OPTION_DHCP):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption);\r
-        val_str = pn_dcp_suboption_dhcp;\r
-        break;\r
-    case(PNDCP_OPTION_LLDP):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_lldp, &suboption);\r
-        val_str = pn_dcp_suboption_lldp;\r
-        break;\r
-    case(PNDCP_OPTION_CONTROL):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);\r
-        val_str = pn_dcp_suboption_control;\r
-        break;\r
-    case(PNDCP_OPTION_ALLSELECTOR):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);\r
-        val_str = pn_dcp_suboption_all;\r
-        break;\r
-    default:\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);\r
-        val_str = pn_dcp_suboption_manuf;\r
-    }\r
-\r
-    proto_item_append_text(block_item, ", Status from %s - %s", \r
-        val_to_str(option, pn_dcp_option, "Unknown"), val_to_str(suboption, val_str, "Unknown"));\r
-\r
-    if(append_col) {\r
-        if (check_col(pinfo->cinfo, COL_INFO))\r
-            col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(suboption, val_str, "Unknown"));\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the "IP" suboption */\r
-static int\r
-dissect_PNDCP_Suboption_IP(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                            proto_tree *tree, proto_item *block_item, proto_item *dcp_item,\r
-                            gboolean is_response)\r
-{\r
-    guint8 suboption;\r
-    guint16 block_length;\r
-    guint16 status;\r
-    guint16 req_status;\r
-    guint32 ip;\r
-\r
-    \r
-    offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption);\r
-    offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);\r
-\r
-    switch(suboption) {\r
-    case(PNDCP_SUBOPTION_IP_MAC):\r
-        pn_append_info(pinfo, dcp_item, ", MAC");\r
-        proto_item_append_text(block_item, "IP/MAC");\r
-\r
-        /* XXX - improve this */\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_IP, suboption, block_length);\r
-        offset += block_length;\r
-        break;\r
-    case(PNDCP_SUBOPTION_IP_IP):\r
-        pn_append_info(pinfo, dcp_item, ", IP");\r
-        proto_item_append_text(block_item, "IP/IP");\r
-\r
-        if(is_response) {\r
-            offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_status, &status);\r
-            proto_item_append_text(block_item, ", Status: %s", val_to_str(status, pn_dcp_suboption_ip_status, "Unknown"));\r
-        } else {\r
-            offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_req_status, &req_status);\r
-            proto_item_append_text(block_item, ", Status: %s", val_to_str(req_status, pn_dcp_req_status, "Unknown"));\r
-        }\r
-\r
-        /* ip address */\r
-        offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip);\r
-        proto_item_append_text(block_item, ", IP: %s", ip_to_str((guint8*)&ip));\r
-\r
-        /* subnetmask */\r
-        offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip);\r
-        proto_item_append_text(block_item, ", Subnet: %s", ip_to_str((guint8*)&ip));\r
-\r
-        /* default router */\r
-        offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_default_router, &ip);\r
-        proto_item_append_text(block_item, ", Router: %s", ip_to_str((guint8*)&ip));\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_IP, suboption, block_length);\r
-        offset += block_length;\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the "device" suboption */\r
-static int\r
-dissect_PNDCP_Suboption_Device(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                               proto_tree *tree, proto_item *block_item, proto_item *dcp_item, \r
-                               int length, gboolean is_response)\r
-{\r
-    guint8 suboption;\r
-    guint16 block_length;\r
-    gchar *info_str;\r
-    guint8 device_role;\r
-    guint16 vendor_id;\r
-    guint16 device_id;\r
-    guint8* typeofstation;\r
-    guint8* nameofstation;\r
-    guint16 status;\r
-\r
-    offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption);\r
-    length--;\r
-\r
-    if(length) {\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);\r
-        if(is_response) {\r
-            offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);\r
-            block_length -= 2;\r
-        }\r
-    }\r
-\r
-    switch(suboption) {\r
-    case(PNDCP_SUBOPTION_DEVICE_MANUF):\r
-/*        if(is_response) {*/\r
-            typeofstation = g_malloc(block_length+1);\r
-            tvb_memcpy(tvb, typeofstation, offset, block_length);\r
-            typeofstation[block_length] = '\0';\r
-            proto_tree_add_string (tree, hf_pn_dcp_suboption_device_typeofstation, tvb, offset, block_length, typeofstation);\r
-            pn_append_info(pinfo, dcp_item, ", TypeOfStation");\r
-            proto_item_append_text(block_item, "Device/Manufacturer specific");\r
-            if(is_response)\r
-                proto_item_append_text(block_item, ", Status: %u", status);\r
-            proto_item_append_text(block_item, ", TypeOfStation: \"%s\"", typeofstation);\r
-            g_free(typeofstation);\r
-            offset += block_length;\r
-/*        } else {\r
-            pn_append_info(pinfo, dcp_item, ", TypeOfStation");\r
-            proto_item_append_text(block_item, "Device/Manufacturer specific(TypeOfStation)");\r
-            offset += block_length;\r
-        }*/\r
-        break;\r
-    case(PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION):\r
-        nameofstation = g_malloc(block_length+1);\r
-        tvb_memcpy(tvb, nameofstation, offset, block_length);\r
-        nameofstation[block_length] = '\0';\r
-        proto_tree_add_string (tree, hf_pn_dcp_suboption_device_nameofstation, tvb, offset, block_length, nameofstation);\r
-        pn_append_info(pinfo, dcp_item, ", NameOfStation");\r
-        proto_item_append_text(block_item, "Device/NameOfStation");\r
-        if(is_response)\r
-            proto_item_append_text(block_item, ", Status: %u", status);\r
-        proto_item_append_text(block_item, ", \"%s\"", nameofstation);\r
-        g_free(nameofstation);\r
-        offset += block_length;\r
-        break;\r
-    case(PNDCP_SUBOPTION_DEVICE_DEV_ID):\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_vendor_id, &vendor_id);\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_id, &device_id);\r
-        pn_append_info(pinfo, dcp_item, ", Dev-ID");\r
-        proto_item_append_text(block_item, "Device/Device ID");\r
-        if(is_response)\r
-            proto_item_append_text(block_item, ", Status: %u", status);\r
-        proto_item_append_text(block_item, ", 0x%04x/0x%04x", vendor_id, device_id);\r
-        break;\r
-    case(PNDCP_SUBOPTION_DEVICE_DEV_ROLE):\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_role, &device_role);\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_reserved8, NULL);\r
-        pn_append_info(pinfo, dcp_item, ", Dev-Role");\r
-        proto_item_append_text(block_item, "Device/Device Role");\r
-        if(is_response)\r
-            proto_item_append_text(block_item, ", Status: %u", status);\r
-        if(device_role & 0x01)\r
-            proto_item_append_text(block_item, ", IO-Device");\r
-        if(device_role & 0x02)\r
-            proto_item_append_text(block_item, ", IO-Controller");\r
-        if(device_role & 0x04)\r
-            proto_item_append_text(block_item, ", IO-Multidevice");\r
-        if(device_role & 0x08)\r
-            proto_item_append_text(block_item, ", PN-Supervisor");\r
-        break;\r
-    case(PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS):\r
-        info_str = g_strdup_printf(", Dev-Options(%u)", block_length/2);\r
-        pn_append_info(pinfo, dcp_item, info_str);\r
-        g_free(info_str);\r
-        proto_item_append_text(block_item, "Device/Device Options");\r
-        if(is_response)\r
-            proto_item_append_text(block_item, ", Status: %u", status);\r
-        proto_item_append_text(block_item, ", %u options", block_length/2);\r
-        for( ; block_length != 0; block_length -= 2) {\r
-            offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, NULL /*block_item*/, hf_pn_dcp_option, \r
-                FALSE /* append_col */);\r
-        }\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_DEVICE, suboption, block_length);\r
-        offset += block_length;\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the "control" suboption */\r
-static int\r
-dissect_PNDCP_Suboption_Control(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                                proto_tree *tree, proto_item *block_item, proto_item *dcp_item, int length)\r
-{\r
-    guint8 result;\r
-    guint8 suboption;\r
-    guint16 block_length;\r
-    gchar *info_str;\r
-    guint16 status;\r
-\r
-\r
-    offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption);\r
-    length--;\r
-\r
-    if(length) {\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);\r
-    }\r
-\r
-    switch(suboption) {\r
-    case(PNDCP_SUBOPTION_CONTROL_START_TRANS):\r
-        pn_append_info(pinfo, dcp_item, ", Start-Trans");\r
-        proto_item_append_text(block_item, "Control/Start-Transaction");\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);\r
-        break;\r
-    case(PNDCP_SUBOPTION_CONTROL_END_TRANS):\r
-        pn_append_info(pinfo, dcp_item, ", End-Trans");\r
-        proto_item_append_text(block_item, "Control/End-Transaction");\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);\r
-        break;\r
-    case(PNDCP_SUBOPTION_CONTROL_SIGNAL):\r
-        pn_append_info(pinfo, dcp_item, ", Signal");\r
-        proto_item_append_text(block_item, "Control/Signal");\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_res_status, &status);\r
-        block_length -= 2;\r
-\r
-        /* XXX - improve this */\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data: %d bytes", block_length);\r
-        offset += block_length;\r
-        break;\r
-    case(PNDCP_SUBOPTION_CONTROL_RESPONSE):\r
-        proto_item_append_text(block_item, "Control/Response");\r
-        offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, block_item, hf_pn_dcp_suboption_control_status, \r
-            FALSE /* append_col */);\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_result, &result);\r
-        length = 0;\r
-        info_str = g_strdup_printf(", Response(%s)", val_to_str(result, pn_dcp_result, "Unknown"));\r
-        pn_append_info(pinfo, dcp_item, info_str);\r
-        g_free(info_str);\r
-        proto_item_append_text(block_item, ", Result: %s", val_to_str(result, pn_dcp_result, "Unknown"));\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_CONTROL, suboption, block_length);\r
-        offset += block_length;\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the "all" suboption */\r
-static int\r
-dissect_PNDCP_Suboption_All(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                            proto_tree *tree, proto_item *block_item, proto_item *dcp_item, int length)\r
-{\r
-    guint8 suboption;\r
-    guint16 block_length;\r
-\r
-    offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption);\r
-    length--;\r
-\r
-    if(length) {\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);\r
-        length-=2;\r
-    }\r
-\r
-    switch(suboption) {\r
-    case(255):    /* All */\r
-        pn_append_info(pinfo, dcp_item, ", All");\r
-        proto_item_append_text(block_item, "All/All");\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data(0x%x/0x%x): %d bytes", PNDCP_OPTION_ALLSELECTOR, suboption, block_length);\r
-        offset += block_length;\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect the "manufacturer" suboption */\r
-static int\r
-dissect_PNDCP_Suboption_Manuf(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                            proto_tree *tree, proto_item *block_item, proto_item *dcp_item, int length)\r
-{\r
-    guint8 suboption;\r
-    guint16 block_length;\r
-\r
-    offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, &suboption);\r
-    length--;\r
-\r
-    if(length) {\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length);\r
-        length-=2;\r
-    }\r
-\r
-    switch(suboption) {\r
-    default:\r
-        pn_append_info(pinfo, dcp_item, ", Manufacturer Specific");\r
-        proto_item_append_text(block_item, "Manufacturer Specific");\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, block_length, "data", \r
-            "Block data: %d bytes", block_length);\r
-        offset += block_length;\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect one DCP block */\r
-static int\r
-dissect_PNDCP_Block(tvbuff_t *tvb, int offset, packet_info *pinfo, \r
-                    proto_tree *tree, proto_item *dcp_item, \r
-                    int length, gboolean is_response)\r
-{\r
-    guint8 option;\r
-    guint8 suboption;\r
-    proto_item *block_item;\r
-    proto_tree *block_tree;\r
-    guint16 block_length;\r
-\r
-    block_length = tvb_get_ntohs(tvb, offset + 2) + 4;\r
-    if(block_length > length) \r
-        block_length = length;\r
-\r
-    /* subtree for block */\r
-       block_item = proto_tree_add_none_format(tree, hf_pn_dcp_block, \r
-               tvb, offset, block_length, "");\r
-       block_tree = proto_item_add_subtree(block_item, ett_pn_dcp_block);\r
-\r
-\r
-    offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_option, &option);\r
-    length--;\r
-\r
-    switch(option) {\r
-    case(PNDCP_OPTION_IP):\r
-        offset = dissect_PNDCP_Suboption_IP(tvb, offset, pinfo, block_tree, block_item, dcp_item, is_response);\r
-        break;\r
-    case(PNDCP_OPTION_DEVICE):\r
-        offset = dissect_PNDCP_Suboption_Device(tvb, offset, pinfo, block_tree, block_item, dcp_item, length, is_response);\r
-        break;\r
-    case(PNDCP_OPTION_DHCP):\r
-        /* XXX - improve this */\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_suboption_dhcp, &suboption);\r
-        break;\r
-    case(PNDCP_OPTION_LLDP):\r
-        /* XXX - improve this */\r
-        offset = dissect_pn_uint8(tvb, offset, pinfo, block_tree, hf_pn_dcp_suboption_lldp, &suboption);\r
-        break;\r
-    case(PNDCP_OPTION_CONTROL):\r
-        offset = dissect_PNDCP_Suboption_Control(tvb, offset, pinfo, block_tree, block_item, dcp_item, length);\r
-        break;\r
-    case(PNDCP_OPTION_ALLSELECTOR):\r
-        offset = dissect_PNDCP_Suboption_All(tvb, offset, pinfo, block_tree, block_item, dcp_item, length);\r
-        break;\r
-    case(PNDCP_OPTION_MANUF_X80):\r
-    case(PNDCP_OPTION_MANUF_X81):\r
-    default:\r
-        offset = dissect_PNDCP_Suboption_Manuf(tvb, offset, pinfo, block_tree, block_item, dcp_item, length);\r
-    }\r
-\r
-    if(block_length & 1) {\r
-        /* we have an odd number of bytes in this block, add a padding byte */\r
-        offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1);\r
-    }\r
-\r
-    return offset;\r
-}\r
-\r
-\r
-/* dissect a whole DCP PDU */\r
-static void\r
-dissect_PNDCP_PDU(tvbuff_t *tvb, \r
-       packet_info *pinfo, proto_tree *tree, proto_item *dcp_item)\r
-{\r
-    guint8 service_id;\r
-    guint8 service_type;\r
-    guint32 xid;\r
-    guint16 response_delay;\r
-    guint16 data_length;\r
-    int offset = 0;\r
-    gchar *xid_str;\r
-    gboolean is_response = FALSE;\r
-\r
-\r
-    offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_id, &service_id);\r
-    offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_service_type, &service_type);\r
-    offset = dissect_pn_uint32(tvb, offset, pinfo, tree, hf_pn_dcp_xid, &xid);\r
-    if(service_id == PNDCP_SERVICE_ID_IDENTIFY && service_type == PNDCP_SERVICE_TYPE_REQUEST) {\r
-        /* multicast header */\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_response_delay, &response_delay);\r
-    } else {\r
-        /* unicast header */\r
-        offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_reserved16, NULL);\r
-    }\r
-    offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_data_length, &data_length);\r
-\r
-    switch(service_id) {\r
-    case(PNDCP_SERVICE_ID_GET):\r
-        pn_append_info(pinfo, dcp_item, "Get");\r
-        break;\r
-    case(PNDCP_SERVICE_ID_SET):\r
-        pn_append_info(pinfo, dcp_item, "Set");\r
-        break;\r
-    case(PNDCP_SERVICE_ID_IDENTIFY):\r
-        pn_append_info(pinfo, dcp_item, "Ident");\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, tvb_length_remaining(tvb, offset), "data", \r
-            "PN-DCP Unknown service ID %u, Data: %d bytes", service_id, tvb_length_remaining(tvb, offset));\r
-        return;\r
-    }\r
-\r
-    switch(service_type) {\r
-    case(PNDCP_SERVICE_TYPE_REQUEST):\r
-        pn_append_info(pinfo, dcp_item, " Req");\r
-        break;\r
-    case(PNDCP_SERVICE_TYPE_RESPONSE_SUCCESS):\r
-        pn_append_info(pinfo, dcp_item, " Ok ");\r
-        is_response = TRUE;\r
-        break;\r
-    case(PNDCP_SERVICE_TYPE_RESPONSE_UNSUPPORTED):\r
-        pn_append_info(pinfo, dcp_item, " unsupported");\r
-        is_response = TRUE;\r
-        break;\r
-    default:\r
-        proto_tree_add_string_format(tree, hf_pn_dcp_data, tvb, offset, tvb_length_remaining(tvb, offset), "data", \r
-            "PN-DCP Unknown service type %u, Data: %d bytes", service_type, tvb_length_remaining(tvb, offset));\r
-        return;\r
-    }\r
-\r
-    xid_str = g_strdup_printf(", Xid:0x%x", xid);\r
-    pn_append_info(pinfo, dcp_item, xid_str);\r
-    g_free(xid_str);\r
-\r
-    /* dissect a number of blocks (depending on the remaining length) */\r
-    while(data_length) {\r
-        int ori_offset = offset;\r
-        if(service_id == PNDCP_SERVICE_ID_GET && service_type == PNDCP_SERVICE_TYPE_REQUEST) {\r
-            /* Selectors */\r
-            offset = dissect_PNDCP_Option(tvb, offset, pinfo, \r
-                                 tree, dcp_item, hf_pn_dcp_option, TRUE /* append_col */);\r
-        } else {\r
-            offset = dissect_PNDCP_Block(tvb, offset, pinfo, tree, dcp_item, data_length, is_response);\r
-        }\r
-        ori_offset= offset - ori_offset;\r
-        data_length -= ori_offset;\r
-    }\r
-}\r
-\r
-\r
-/* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */\r
-static gboolean\r
-dissect_PNDCP_Data_heur(tvbuff_t *tvb, \r
-       packet_info *pinfo, proto_tree *tree)\r
-{\r
-    guint16 u16FrameID;\r
-    proto_item *item = NULL;\r
-    proto_tree *dcp_tree = NULL;\r
-\r
-\r
-    /* the tvb will NOT contain the frame_id here, so get it from our private data! */\r
-    u16FrameID = GPOINTER_TO_INT(pinfo->private_data);\r
-\r
-       /* frame id must be in valid range (acyclic Real-Time, DCP) */\r
-       if (u16FrameID < FRAME_ID_UC || u16FrameID > FRAME_ID_MC_RESP) {\r
-        /* we are not interested in this packet */\r
-        return FALSE;\r
-    }\r
-\r
-       if (check_col(pinfo->cinfo, COL_PROTOCOL))\r
-           col_add_str(pinfo->cinfo, COL_PROTOCOL, "PN-DCP");\r
-    if (check_col(pinfo->cinfo, COL_INFO))\r
-      col_add_fstr(pinfo->cinfo, COL_INFO, "");\r
-\r
-    /* subtree for DCP */\r
-       item = proto_tree_add_protocol_format(tree, proto_pn_dcp, tvb, 0, tvb_get_ntohs(tvb, 8) + 10,\r
-                               "PROFINET DCP, ");\r
-       dcp_tree = proto_item_add_subtree(item, ett_pn_dcp);\r
-\r
-    /* dissect this PDU */\r
-    dissect_PNDCP_PDU(tvb, pinfo, dcp_tree, item);\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-void\r
-proto_register_pn_dcp (void)\r
-{\r
-       static hf_register_info hf[] = {\r
-       { &hf_pn_dcp,\r
-               { "PROFINET DCP", "pn_dcp", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_service_id,\r
-               { "Service-ID", "pn_dcp.service_id", FT_UINT8, BASE_DEC, VALS(pn_dcp_service_id), 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_service_type,\r
-               { "Service-Type", "pn_dcp.service_type", FT_UINT8, BASE_DEC, VALS(pn_dcp_service_type), 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_xid,\r
-               { "xid", "pn_dcp.xid", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_reserved8,\r
-               { "Reserved", "pn_dcp.reserved8", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_reserved16,\r
-               { "Reserved", "pn_dcp.reserved16", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_response_delay,\r
-               { "ResponseDelay", "pn_dcp.response_delay", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_data_length,\r
-               { "DCPDataLength", "pn_dcp.data_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_block_length,\r
-               { "DataBlockLength", "pn_dcp.block_length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_option,\r
-               { "Option", "pn_dcp.option", FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_suboption,\r
-               { "Suboption", "pn_dcp.suboption", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_result,\r
-               { "Result", "pn_dcp.result", FT_UINT8, BASE_DEC, VALS(pn_dcp_result), 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_block,\r
-               { "DCPBlock", "pn_dcp.block", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_req_status,\r
-               { "Status", "pn_dcp.req_status", FT_UINT16, BASE_DEC, VALS(pn_dcp_req_status), 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_res_status,\r
-               { "ResponseStatus", "pn_dcp.res_status", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_ip,\r
-               { "Suboption", "pn_dcp.suboption_ip", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_ip), 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_ip_status,\r
-               { "Status", "pn_dcp.suboption_ip_status", FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_ip_status), 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_suboption_ip_ip,\r
-               { "IPaddress", "pn_dcp.subobtion_ip_ip", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_suboption_ip_subnetmask,\r
-               { "Subnetmask", "pn_dcp.subobtion_ip_subnetmask", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-       { &hf_pn_dcp_suboption_ip_default_router,\r
-               { "Default-router", "pn_dcp.subobtion_ip_default_router", FT_IPv4, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_suboption_device,\r
-               { "Suboption", "pn_dcp.suboption_device", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_device), 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_device_typeofstation,\r
-               { "TypeOfStation", "pn_dcp.suboption_device_typeofstation", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_device_nameofstation,\r
-               { "NameOfStation", "pn_dcp.suboption_device_nameofstation", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_vendor_id,\r
-               { "VendorID", "pn_dcp.suboption_vendor_id", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_device_id,\r
-               { "DeviceID", "pn_dcp.suboption_device_id", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_device_role,\r
-               { "Device-role", "pn_dcp.suboption_device_role", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_suboption_dhcp,\r
-               { "Suboption", "pn_dcp.suboption_dhcp", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_dhcp), 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_suboption_lldp,\r
-               { "Suboption", "pn_dcp.suboption_lldp", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_lldp), 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_suboption_control,\r
-               { "Suboption", "pn_dcp.suboption_control", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_control), 0x0, "", HFILL }},\r
-    { &hf_pn_dcp_suboption_control_status,\r
-               { "ResponseStatus", "pn_dcp.suboption_control_status", FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_suboption_all,\r
-               { "Suboption", "pn_dcp.suboption_all", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_all), 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_suboption_manuf,\r
-               { "Suboption", "pn_dcp.suboption_manuf", FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_manuf), 0x0, "", HFILL }},\r
-\r
-    { &hf_pn_dcp_data,\r
-      { "Undecoded Data", "pn_dcp.data", FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }},\r
-       };\r
-\r
-       static gint *ett[] = {\r
-               &ett_pn_dcp,\r
-        &ett_pn_dcp_block\r
-    };\r
-       proto_pn_dcp = proto_register_protocol ("PROFINET DCP", "PN-DCP", "pn_dcp");\r
-       proto_register_field_array (proto_pn_dcp, hf, array_length (hf));\r
-       proto_register_subtree_array (ett, array_length (ett));\r
-}\r
-\r
-void\r
-proto_reg_handoff_pn_dcp (void)\r
-{\r
-    /* register ourself as an heuristic pn-rt payload dissector */\r
-       heur_dissector_add("pn_rt", dissect_PNDCP_Data_heur, proto_pn_dcp);\r
-}\r
+#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);
+}
index 367aa45cd3b663fb45ef2dcc17e602703a4d46ee..4115317120921fc8b2f622bfe69dbf701cd6bc8e 100644 (file)
@@ -1,8 +1,10 @@
 /* packet-pn-rt.c
- * Routines for pn-rt (PROFINET Real-Time) packet dissection.\r
- * This is the base for other PROFINET protocols like IO, CBA, DCP, ...\r
+ * 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)
  *
+ * $Id$
+ *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1999 Gerald Combs
@@ -52,8 +54,8 @@
 #include <epan/packet.h>
 #include <epan/addr_resolv.h>
 #include "prefs.h"
-#include <epan/strutil.h>\r
-#include <etypes.h>\r
+#include <epan/strutil.h>
+#include <etypes.h>
 
 
 #ifndef __ETHEREAL_STATIC__
@@ -96,12 +98,12 @@ static int ett_pn_rt_data_status = -1;
 /* Place summary in proto tree */
 static gboolean pn_rt_summary_in_tree = TRUE;
 
-/* heuristic to find the right pn-rt payload dissector */\r
-static heur_dissector_list_t heur_subdissector_list;\r
-\r
-/* the official "we don't know that data" dissector */\r
-static dissector_handle_t data_handle;\r
-\r
+/* 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
@@ -152,7 +154,7 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   /* build protocol tree only, if tree is really used */
   if (tree) {
         /* build some "raw" data */
-               u16FrameID = tvb_get_ntohs(tvb, 0);\r
+               u16FrameID = tvb_get_ntohs(tvb, 0);
         if (u16FrameID < 0x0100) {
                pszProtShort    = "PN-RTC0";
             pszProtAddInfo  = "Synchronization, ";
@@ -238,9 +240,9 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                pszProtComment  = "0xFF00-0xFFFF: reserved ID";
             bCyclic         = FALSE;
            }
-\r
+
         /* decode optional cyclic fields at the packet end and build the summary line */
-        if (bCyclic) {\r
+        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);
@@ -253,17 +255,17 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                                (u8DataStatus & 0x01) ? "Primary" : "Backup",
                                (u8DataStatus & 0x20) ? "Ok" : "Problem",
                                (u8DataStatus & 0x10) ? "Run" : "Stop");
-\r
-            /* user data length is packet len - frame id - optional cyclic status fields */\r
-            data_len = tvb_len - 2 - 4;\r
+
+            /* 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 */\r
+            /* acyclic transfer has no fields at the end */
                    snprintf (szFieldSummary, sizeof(szFieldSummary),
                                      "%sFrameID: 0x%04x, DataLen: %4u",
                                    pszProtAddInfo, u16FrameID, tvb_len - 2);
-\r
-            /* user data length is packet len - frame id field */\r
-            data_len = tvb_len - 2;\r
+
+            /* user data length is packet len - frame id field */
+            data_len = tvb_len - 2;
         }
 
                /* build pn_rt protocol tree with summary line */
@@ -316,23 +318,23 @@ dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                
                /* update column info now */
         if (check_col(pinfo->cinfo, COL_INFO))
-          col_add_fstr(pinfo->cinfo, COL_INFO, szFieldSummary);\r
+          col_add_fstr(pinfo->cinfo, COL_INFO, szFieldSummary);
                if (check_col(pinfo->cinfo, COL_PROTOCOL))
                col_add_str(pinfo->cinfo, COL_PROTOCOL, pszProtShort);
-\r
-        pinfo->private_data = GINT_TO_POINTER(u16FrameID);\r
-\r
-               /* get frame user data tvb (without header and footer) */\r
-               next_tvb = tvb_new_subset(tvb, 2, data_len, data_len);\r
-\r
-        /* ask heuristics, if some sub-dissector is interested in this packet payload */\r
-        if(!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {\r
-            /*if (check_col(pinfo->cinfo, COL_INFO))\r
-                  col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown");*/\r
-\r
-            /* Oh, well, we don't know this; dissect it as data. */\r
-            call_dissector(data_handle, next_tvb, pinfo, tree);\r
-        }\r
+
+        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);
+        }
     }
 }
 
@@ -361,7 +363,7 @@ proto_register_pn_rt(void)
        { &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 }},\r
+               "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,
@@ -388,10 +390,10 @@ proto_register_pn_rt(void)
   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);\r
-\r
-  /* register heuristics anchor for payload dissectors */\r
-  register_heur_dissector_list("pn_rt", &heur_subdissector_list);\r
+           &pn_rt_summary_in_tree);
+
+  /* register heuristics anchor for payload dissectors */
+  register_heur_dissector_list("pn_rt", &heur_subdissector_list);
 }
 
 
@@ -412,10 +414,10 @@ proto_reg_handoff_pn_rt(void)
     dissector_delete("ethertype", ETHERTYPE_PROFINET, pn_rt_handle);
   }
 
-  dissector_add("ethertype", ETHERTYPE_PROFINET, pn_rt_handle);\r
-\r
-       /* the official "we don't know that data" dissector */\r
-  data_handle = find_dissector("data");\r
+  dissector_add("ethertype", ETHERTYPE_PROFINET, pn_rt_handle);
+
+       /* the official "we don't know that data" dissector */
+  data_handle = find_dissector("data");
 }