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