diff options
author | João Valverde <joao.valverde@tecnico.ulisboa.pt> | 2018-01-15 12:40:55 +0000 |
---|---|---|
committer | João Valverde <j@v6e.pt> | 2018-01-16 08:51:37 +0000 |
commit | 5352ef42f94b5c14a24eb2e5559440c71fdcae8f (patch) | |
tree | 22901b1d228d76360b22af10021564bcee36390e /plugins/epan/profinet | |
parent | a069a4f856c29b25bae05f2a91d7b2b71e1905f3 (diff) |
plugins: Add source tree subfolder for plugin library
This allows some simplification and makes things more consistent,
particularly for loading plugins from the build dir.
Also fixes the issue reported here:
https://www.wireshark.org/lists/wireshark-dev/201801/msg00061.html
Change-Id: I0d8a000ee679172bccad546a3b0c47a79486f44d
Reviewed-on: https://code.wireshark.org/review/25329
Petri-Dish: João Valverde <j@v6e.pt>
Reviewed-by: João Valverde <j@v6e.pt>
Diffstat (limited to 'plugins/epan/profinet')
-rw-r--r-- | plugins/epan/profinet/AUTHORS | 4 | ||||
-rw-r--r-- | plugins/epan/profinet/CMakeLists.txt | 94 | ||||
-rw-r--r-- | plugins/epan/profinet/ChangeLog | 33 | ||||
-rw-r--r-- | plugins/epan/profinet/Makefile.am | 76 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-dcerpc-pn-io.c | 15169 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-dcom-cba-acco.c | 5170 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-dcom-cba-acco.h | 71 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-dcom-cba.c | 1742 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn-dcp.c | 1400 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn-mrp.c | 680 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn-mrrt.c | 259 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn-ptcp.c | 1105 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn-rt.c | 1171 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn-rtc-one.c | 1103 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn.c | 394 | ||||
-rw-r--r-- | plugins/epan/profinet/packet-pn.h | 174 |
16 files changed, 28645 insertions, 0 deletions
diff --git a/plugins/epan/profinet/AUTHORS b/plugins/epan/profinet/AUTHORS new file mode 100644 index 0000000000..4979d26040 --- /dev/null +++ b/plugins/epan/profinet/AUTHORS @@ -0,0 +1,4 @@ +Author : +Ulf Lamping <ulf.lamping@web.de> +Tobias Scholz <scholzt234@googlemail.com> +Birol Capa <birol.capa@gmail.com>
\ No newline at end of file diff --git a/plugins/epan/profinet/CMakeLists.txt b/plugins/epan/profinet/CMakeLists.txt new file mode 100644 index 0000000000..86798676f1 --- /dev/null +++ b/plugins/epan/profinet/CMakeLists.txt @@ -0,0 +1,94 @@ +# CMakeLists.txt +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 1998 Gerald Combs +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +include(WiresharkPlugin) + +# Plugin name and version info (major minor micro extra) +set_module_info(profinet 0 2 4 0) + +set(DISSECTOR_SRC + packet-dcerpc-pn-io.c + packet-dcom-cba.c + packet-dcom-cba-acco.c + packet-pn-dcp.c + packet-pn-mrp.c + packet-pn-mrrt.c + packet-pn-ptcp.c + packet-pn-rt.c + packet-pn-rtc-one.c +) + +set(DISSECTOR_SUPPORT_SRC + packet-pn.c +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} +) + +set(CLEAN_FILES + ${PLUGIN_FILES} +) + +set_source_files_properties( + ${CLEAN_FILES} + PROPERTIES + COMPILE_FLAGS "${WERROR_COMMON_FLAGS}" +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +register_plugin_files(plugin.c + plugin + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} +) + +add_plugin_library(profinet epan) + +install_plugin(profinet epan) + +file(GLOB DISSECTOR_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.h") +CHECKAPI( + NAME + profinet + SWITCHES + -g abort -g termoutput -build + SOURCES + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} + ${DISSECTOR_HEADERS} +) + +# +# Editor modelines - http://www.wireshark.org/tools/modelines.html +# +# Local variables: +# c-basic-offset: 8 +# tab-width: 8 +# indent-tabs-mode: t +# End: +# +# vi: set shiftwidth=8 tabstop=8 noexpandtab: +# :indentSize=8:tabSize=8:noTabs=false: +# diff --git a/plugins/epan/profinet/ChangeLog b/plugins/epan/profinet/ChangeLog new file mode 100644 index 0000000000..5298f56783 --- /dev/null +++ b/plugins/epan/profinet/ChangeLog @@ -0,0 +1,33 @@ +Overview of changes in Art-Net Ethereal plugin: + +Version 0.0.0: + +* initial implementation + +Version 0.0.1: + +* some experiments + +Version 0.1.0: + +* first official plugin + +Version 0.1.1: + +* fixed some bugs in the PN-IO dissection found with fuzz-test.sh + +Version 0.1.2: + +* PN-DCP: dissection of "DHCP/DHCP client identifier" suboption was added + +Version 0.2.0: + +* PN-PTCP: add whole new Precision Time Control Protocol dissector + +Version 0.2.1: + +* PN-MRP and PN-MRRT: add new Media Redundancy Protocol and Media Redundacy for RealTime Protocol dissector + +Version 0.2.2: + +* PN-IO: RT class 3 packets and some more blocks diff --git a/plugins/epan/profinet/Makefile.am b/plugins/epan/profinet/Makefile.am new file mode 100644 index 0000000000..ce0888690c --- /dev/null +++ b/plugins/epan/profinet/Makefile.am @@ -0,0 +1,76 @@ +# Makefile.am +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 1998 Gerald Combs +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +include $(top_srcdir)/Makefile.am.inc +include $(top_srcdir)/plugins/Makefile.am.inc + +# the name of the plugin +PLUGIN_NAME = profinet + +PLUGIN_VERSION = 0.2.4 + +BUILT_SOURCES = \ + plugin.c + +# Non-generated sources to be scanned for registration routines +NONGENERATED_REGISTER_C_FILES = \ + packet-dcerpc-pn-io.c \ + packet-dcom-cba.c \ + packet-dcom-cba-acco.c \ + packet-pn-dcp.c \ + packet-pn-mrp.c \ + packet-pn-mrrt.c \ + packet-pn-ptcp.c \ + packet-pn-rt.c \ + packet-pn-rtc-one.c + +# Non-generated sources +NONGENERATED_C_FILES = \ + $(NONGENERATED_REGISTER_C_FILES) \ + packet-pn.c + +# Headers. +CLEAN_HEADER_FILES = \ + packet-dcom-cba-acco.h \ + packet-pn.h + +HEADER_FILES = \ + $(CLEAN_HEADER_FILES) + +epan_plugin_LTLIBRARIES = profinet.la + +profinet_la_SOURCES = \ + $(SRC_FILES) \ + $(HEADER_FILES) + +nodist_profinet_la_SOURCES = \ + plugin.c + +profinet_la_CPPFLAGS = $(AM_CPPFLAGS) $(PLUGIN_CPPFLAGS) + +profinet_la_CFLAGS = $(AM_CFLAGS) $(PLUGIN_CFLAGS) + +profinet_la_LDFLAGS = $(PLUGIN_LDFLAGS) + +DISTCLEANFILES = \ + plugin.c + +EXTRA_DIST = \ + CMakeLists.txt diff --git a/plugins/epan/profinet/packet-dcerpc-pn-io.c b/plugins/epan/profinet/packet-dcerpc-pn-io.c new file mode 100644 index 0000000000..44aa77d092 --- /dev/null +++ b/plugins/epan/profinet/packet-dcerpc-pn-io.c @@ -0,0 +1,15169 @@ +/* packet-dcerpc-pn-io.c + * Routines for PROFINET IO dissection. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * The PN-IO protocol is a field bus protocol related to decentralized + * periphery and is developed by the PROFIBUS Nutzerorganisation e.V. (PNO), + * see: www.profibus.com + * + * + * PN-IO is based on the common DCE-RPC and the "lightweight" PN-RT + * (ethernet type 0x8892) protocols. + * + * The context manager (CM) part is handling context information + * (like establishing, ...) and is using DCE-RPC as its underlying + * protocol. + * + * The actual cyclic data transfer and acyclic notification uses the + * "lightweight" PN-RT protocol. + * + * There are some other related PROFINET protocols (e.g. PN-DCP, which is + * handling addressing topics). + * + * Please note: the PROFINET CBA protocol is independent of the PN-IO protocol! + */ + +/* + * Cyclic PNIO RTC1 Data Dissection: + * + * To dissect cyclic PNIO RTC1 frames, this plug-in has to collect important module + * information out of "Ident OK", "Connect Request" and "Write Response" + * frames first. This information will be used within "packet-pn-rtc-one.c" to + * dissect PNIO and PROFIsafe RTC1 frames. + * + * The data of Stationname-, -type and -id will be gained out of + * packet-pn-dcp.c. The header packet-pn.h will save those data. + * + * Overview for cyclic PNIO RTC1 data dissection functions: + * -> dissect_IOCRBlockReq_block (Save amount of IODataObjects, IOCS) + * -> dissect_DataDescription (Save important values for cyclic data) + * -> dissect_ExpectedSubmoduleBlockReq_block (Get GSD information) + * -> dissect_ModuleDiffBlock_block (Module has different ID) + * -> dissect_ProfiSafeParameterRequest (Save PROFIsafe parameters) + * -> dissect_RecordDataWrite (Call ProfiSafeParameterRequest) + * -> pnio_rtc1_cleanup (Reset routine of saved RTC1 information) + */ + + +#include "config.h" + +#include <string.h> +#include <glib.h> + +#include <epan/packet.h> +#include <epan/to_str.h> +#include <epan/wmem/wmem.h> +#include <epan/dissectors/packet-dcerpc.h> +#include <epan/expert.h> +#include <epan/dissector_filters.h> +#include <epan/proto_data.h> + +#include <wsutil/file_util.h> +#include <epan/prefs.h> + +#include "packet-pn.h" + +#include <stdio.h> +#include <stdlib.h> + +void proto_register_pn_io(void); +void proto_reg_handoff_pn_io(void); + + +#define MAX_NAMELENGTH 200 /* max. length of the given paths */ +#define F_MESSAGE_TRAILER_4BYTE 4 /* PROFIsafe: Defines the Amount of Bytes for CRC and Status-/Controlbyte */ +#define PN_INPUT_CR 1 /* PROFINET Input Connect Request value */ +#define PN_INPUT_DATADESCRITPION 1 /* PROFINET Input Data Description value */ + + +static int proto_pn_io = -1; +static int proto_pn_io_device = -1; +static int proto_pn_io_controller = -1; +static int proto_pn_io_supervisor = -1; +static int proto_pn_io_parameterserver = -1; +static int proto_pn_io_implicitar = -1; +int proto_pn_io_apdu_status = -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_ar_type = -1; +static int hf_pn_io_artype_req = -1; +static int hf_pn_io_cminitiator_macadd = -1; +static int hf_pn_io_cminitiator_objectuuid = -1; +static int hf_pn_io_parameter_server_objectuuid = -1; +static int hf_pn_io_ar_data = -1; +static int hf_pn_io_ar_properties = -1; +static int hf_pn_io_ar_properties_state = -1; +static int hf_pn_io_ar_properties_supervisor_takeover_allowed = -1; +static int hf_pn_io_ar_properties_parametrization_server = -1; +/* removed within 2.3 +static int hf_pn_io_ar_properties_data_rate = -1; +*/ +static int hf_pn_io_ar_properties_reserved_1 = -1; +static int hf_pn_io_ar_properties_device_access = -1; +static int hf_pn_io_ar_properties_companion_ar = -1; +static int hf_pn_io_ar_properties_achnowledge_companion_ar = -1; +static int hf_pn_io_ar_properties_reserved = -1; +static int hf_pn_io_ar_properties_combined_object_container_with_legacy_startupmode = -1; +static int hf_pn_io_ar_properties_combined_object_container_with_advanced_startupmode = -1; +static int hf_pn_io_ar_properties_pull_module_alarm_allowed = -1; + +static int hf_pn_RedundancyInfo = -1; +static int hf_pn_RedundancyInfo_reserved = -1; +static int hf_pn_io_number_of_ARDATAInfo = -1; + +static int hf_pn_io_cminitiator_activitytimeoutfactor = -1; +static int hf_pn_io_cminitiator_udprtport = -1; +static int hf_pn_io_station_name_length = -1; +static int hf_pn_io_cminitiator_station_name = -1; +/* static int hf_pn_io_responder_station_name = -1; */ +static int hf_pn_io_arproperties_StartupMode = -1; + +static int hf_pn_io_parameter_server_station_name = -1; + +static int hf_pn_io_cmresponder_macadd = -1; +static int hf_pn_io_cmresponder_udprtport = -1; + +static int hf_pn_io_number_of_iocrs = -1; +static int hf_pn_io_iocr_tree = -1; +static int hf_pn_io_iocr_type = -1; +static int hf_pn_io_iocr_reference = -1; +static int hf_pn_io_iocr_SubframeOffset = -1; +static int hf_pn_io_iocr_SubframeData =-1; +/* static int hf_pn_io_iocr_txports_port = -1; */ +/* static int hf_pn_io_iocr_txports_redundantport = -1; */ +static int hf_pn_io_sr_properties_Reserved_1 = -1; +static int hf_pn_io_sr_properties_Mode = -1; +static int hf_pn_io_sr_properties_Reserved_2 = -1; +static int hf_pn_io_sr_properties_Reserved_3 = -1; +static int hf_pn_io_RedundancyDataHoldFactor = -1; +static int hf_pn_io_sr_properties = -1; +static int hf_pn_io_sr_properties_InputValidOnBackupAR_with_SRProperties_Mode_0 = -1; +static int hf_pn_io_sr_properties_InputValidOnBackupAR_with_SRProperties_Mode_1 = -1; + +static int hf_pn_io_arvendor_strucidentifier_if0_low = -1; +static int hf_pn_io_arvendor_strucidentifier_if0_high = -1; +static int hf_pn_io_arvendor_strucidentifier_if0_is8000= -1; +static int hf_pn_io_arvendor_strucidentifier_not0 = -1; + +static int hf_pn_io_lt = -1; +static int hf_pn_io_iocr_properties = -1; +static int hf_pn_io_iocr_properties_rtclass = -1; +static int hf_pn_io_iocr_properties_reserved_1 = -1; +static int hf_pn_io_iocr_properties_media_redundancy = -1; +static int hf_pn_io_iocr_properties_reserved_2 = -1; +static int hf_pn_io_iocr_properties_reserved_3 = -1; +static int hf_pn_io_iocr_properties_fast_forwarding_mac_adr = -1; +static int hf_pn_io_iocr_properties_distributed_subframe_watchdog = -1; +static int hf_pn_io_iocr_properties_full_subframe_structure = -1; + + +static int hf_pn_io_data_length = -1; +static int hf_pn_io_ir_frame_data = -1; +static int hf_pn_io_frame_id = -1; +static int hf_pn_io_send_clock_factor = -1; +static int hf_pn_io_reduction_ratio = -1; +static int hf_pn_io_phase = -1; +static int hf_pn_io_sequence = -1; +static int hf_pn_io_frame_send_offset = -1; +static int hf_pn_io_frame_data_properties = -1; +static int hf_pn_io_frame_data_properties_forwarding_Mode = -1; +static int hf_pn_io_frame_data_properties_FastForwardingMulticastMACAdd = -1; +static int hf_pn_io_frame_data_properties_FragmentMode = -1; +static int hf_pn_io_frame_data_properties_reserved_1 = -1; +static int hf_pn_io_frame_data_properties_reserved_2 = -1; +static int hf_pn_io_watchdog_factor = -1; +static int hf_pn_io_data_hold_factor = -1; +static int hf_pn_io_iocr_tag_header = -1; +static int hf_pn_io_iocr_multicast_mac_add = -1; +static int hf_pn_io_number_of_apis = -1; +static int hf_pn_io_number_of_io_data_objects = -1; +static int hf_pn_io_io_data_object_frame_offset = -1; +static int hf_pn_io_number_of_iocs = -1; +static int hf_pn_io_iocs_frame_offset = -1; + +static int hf_pn_io_SFIOCRProperties = -1; +static int hf_pn_io_DistributedWatchDogFactor = -1; +static int hf_pn_io_RestartFactorForDistributedWD = -1; +static int hf_pn_io_SFIOCRProperties_DFPmode = -1; +static int hf_pn_io_SFIOCRProperties_reserved_1 = -1; +static int hf_pn_io_SFIOCRProperties_reserved_2 = -1; +static int hf_pn_io_SFIOCRProperties_DFPType =-1; +static int hf_pn_io_SFIOCRProperties_DFPRedundantPathLayout = -1; +static int hf_pn_io_SFIOCRProperties_SFCRC16 = -1; + +static int hf_pn_io_subframe_data = -1; +static int hf_pn_io_subframe_data_reserved1 = -1; +static int hf_pn_io_subframe_data_reserved2 = -1; + +static int hf_pn_io_subframe_data_position = -1; +static int hf_pn_io_subframe_reserved1 = -1; +static int hf_pn_io_subframe_data_length = -1; +static int hf_pn_io_subframe_reserved2 = -1; + +static int hf_pn_io_alarmcr_type = -1; +static int hf_pn_io_alarmcr_properties = -1; +static int hf_pn_io_alarmcr_properties_priority = -1; +static int hf_pn_io_alarmcr_properties_transport = -1; +static int hf_pn_io_alarmcr_properties_reserved = -1; + +static int hf_pn_io_rta_timeoutfactor = -1; +static int hf_pn_io_rta_retries = -1; +static int hf_pn_io_localalarmref = -1; +static int hf_pn_io_remotealarmref = -1; +static int hf_pn_io_maxalarmdatalength = -1; +static int hf_pn_io_alarmcr_tagheaderhigh = -1; +static int hf_pn_io_alarmcr_tagheaderlow = -1; + +static int hf_pn_io_IRData_uuid = -1; +static int hf_pn_io_ar_uuid = -1; +static int hf_pn_io_target_ar_uuid = -1; +static int hf_pn_io_ar_discriminator = -1; +static int hf_pn_io_ar_configid = -1; +static int hf_pn_io_ar_arnumber = -1; +static int hf_pn_io_ar_arresource = -1; +static int hf_pn_io_ar_arreserved = -1; +static int hf_pn_io_ar_selector = -1; +static int hf_pn_io_api_tree = -1; +static int hf_pn_io_module_tree = -1; +static int hf_pn_io_submodule_tree = -1; +static int hf_pn_io_io_data_object = -1; +/* General module information */ +static int hf_pn_io_io_cs = -1; + +static int hf_pn_io_substitutionmode = -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_add_val1 = -1; +static int hf_pn_io_add_val2 = -1; + +static int hf_pn_io_block = -1; +static int hf_pn_io_block_header = -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_command_ready_for_companion = -1; +static int hf_pn_io_control_command_ready_for_rt_class3 = -1; +static int hf_pn_io_control_command_prmbegin = -1; +static int hf_pn_io_control_command_reserved_7_15 = -1; +static int hf_pn_io_control_block_properties = -1; +static int hf_pn_io_control_block_properties_applready = -1; +static int hf_pn_io_control_block_properties_applready0 = -1; + +/* static int hf_pn_io_AlarmSequenceNumber = -1; */ +static int hf_pn_io_control_command_reserved = -1; +static int hf_pn_io_SubmoduleListEntries = -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_code1_pniorw = -1; +static int hf_pn_io_error_code1_pnio = -1; +static int hf_pn_io_error_code2 = -1; +static int hf_pn_io_error_code2_pniorw = -1; +static int hf_pn_io_error_code2_pnio_1 = -1; +static int hf_pn_io_error_code2_pnio_2 = -1; +static int hf_pn_io_error_code2_pnio_3 = -1; +static int hf_pn_io_error_code2_pnio_4 = -1; +static int hf_pn_io_error_code2_pnio_5 = -1; +static int hf_pn_io_error_code2_pnio_6 = -1; +static int hf_pn_io_error_code2_pnio_7 = -1; +static int hf_pn_io_error_code2_pnio_8 = -1; +static int hf_pn_io_error_code2_pnio_13 = -1; +static int hf_pn_io_error_code2_pnio_20 = -1; +static int hf_pn_io_error_code2_pnio_21 = -1; +static int hf_pn_io_error_code2_pnio_22 = -1; +static int hf_pn_io_error_code2_pnio_23 = -1; +static int hf_pn_io_error_code2_pnio_40 = -1; +static int hf_pn_io_error_code2_pnio_60 = -1; +static int hf_pn_io_error_code2_pnio_61 = -1; +static int hf_pn_io_error_code2_pnio_62 = -1; +static int hf_pn_io_error_code2_pnio_63 = -1; +static int hf_pn_io_error_code2_pnio_64 = -1; +static int hf_pn_io_error_code2_pnio_65 = -1; +static int hf_pn_io_error_code2_pnio_66 = -1; +static int hf_pn_io_error_code2_pnio_70 = -1; +static int hf_pn_io_error_code2_pnio_71 = -1; +static int hf_pn_io_error_code2_pnio_72 = -1; +static int hf_pn_io_error_code2_pnio_73 = -1; +static int hf_pn_io_error_code2_pnio_74 = -1; +static int hf_pn_io_error_code2_pnio_75 = -1; +static int hf_pn_io_error_code2_pnio_76 = -1; +static int hf_pn_io_error_code2_pnio_77 = -1; +static int hf_pn_io_error_code2_pnio_253 = -1; +static int hf_pn_io_error_code2_pnio_255 = -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_number_of_modules = -1; +static int hf_pn_io_module_ident_number = -1; +static int hf_pn_io_module_properties = -1; +static int hf_pn_io_module_state = -1; +static int hf_pn_io_number_of_submodules = -1; +static int hf_pn_io_submodule_ident_number = -1; +static int hf_pn_io_submodule_properties = -1; +static int hf_pn_io_submodule_properties_type = -1; +static int hf_pn_io_submodule_properties_shared_input = -1; +static int hf_pn_io_submodule_properties_reduce_input_submodule_data_length = -1; +static int hf_pn_io_submodule_properties_reduce_output_submodule_data_length = -1; +static int hf_pn_io_submodule_properties_discard_ioxs = -1; +static int hf_pn_io_submodule_properties_reserved = -1; + +static int hf_pn_io_submodule_state = -1; +static int hf_pn_io_submodule_state_format_indicator = -1; +static int hf_pn_io_submodule_state_add_info = -1; +static int hf_pn_io_submodule_state_qualified_info = -1; +static int hf_pn_io_submodule_state_maintenance_required = -1; +static int hf_pn_io_submodule_state_maintenance_demanded = -1; +static int hf_pn_io_submodule_state_diag_info = -1; +static int hf_pn_io_submodule_state_ar_info = -1; +static int hf_pn_io_submodule_state_ident_info = -1; +static int hf_pn_io_submodule_state_detail = -1; + +static int hf_pn_io_data_description_tree = -1; +static int hf_pn_io_data_description = -1; +static int hf_pn_io_submodule_data_length = -1; +static int hf_pn_io_length_iocs = -1; +static int hf_pn_io_length_iops = -1; + +static int hf_pn_io_iocs = -1; +static int hf_pn_io_iops = -1; +static int hf_pn_io_ioxs_extension = -1; +static int hf_pn_io_ioxs_res14 = -1; +static int hf_pn_io_ioxs_instance = -1; +static int hf_pn_io_ioxs_datastate = -1; + +static int hf_pn_io_address_resolution_properties = -1; +static int hf_pn_io_mci_timeout_factor = -1; +static int hf_pn_io_provider_station_name = -1; + +static int hf_pn_io_user_structure_identifier = -1; +static int hf_pn_io_user_structure_identifier_manf = -1; + +static int hf_pn_io_channel_number = -1; +static int hf_pn_io_channel_properties = -1; +static int hf_pn_io_channel_properties_type = -1; +static int hf_pn_io_channel_properties_accumulative = -1; +static int hf_pn_io_channel_properties_maintenance = -1; + + +static int hf_pn_io_NumberOfSubframeBlocks = -1; +static int hf_pn_io_channel_properties_specifier = -1; +static int hf_pn_io_channel_properties_direction = -1; + +static int hf_pn_io_channel_error_type = -1; +static int hf_pn_io_ext_channel_error_type0 = -1; +static int hf_pn_io_ext_channel_error_type0x8000 = -1; +static int hf_pn_io_ext_channel_error_type0x8001 = -1; +static int hf_pn_io_ext_channel_error_type0x8002 = -1; +static int hf_pn_io_ext_channel_error_type0x8003 = -1; +static int hf_pn_io_ext_channel_error_type0x8004 = -1; +static int hf_pn_io_ext_channel_error_type0x8005 = -1; +static int hf_pn_io_ext_channel_error_type0x8007 = -1; +static int hf_pn_io_ext_channel_error_type0x8008 = -1; +static int hf_pn_io_ext_channel_error_type0x800A = -1; +static int hf_pn_io_ext_channel_error_type0x800B = -1; +static int hf_pn_io_ext_channel_error_type0x800C = -1; + +static int hf_pn_io_ext_channel_error_type = -1; + +static int hf_pn_io_ext_channel_add_value = -1; + +static int hf_pn_io_ptcp_subdomain_id = -1; +static int hf_pn_io_ir_data_id = -1; +static int hf_pn_io_max_bridge_delay = -1; +static int hf_pn_io_number_of_ports = -1; +static int hf_pn_io_max_port_tx_delay = -1; +static int hf_pn_io_max_port_rx_delay = -1; + +static int hf_pn_io_max_line_rx_delay = -1; +static int hf_pn_io_yellowtime = -1; +static int hf_pn_io_reserved_interval_begin = -1; +static int hf_pn_io_reserved_interval_end = -1; +static int hf_pn_io_pllwindow = -1; +static int hf_pn_io_sync_send_factor = -1; +static int hf_pn_io_sync_properties = -1; +static int hf_pn_io_sync_frame_address = -1; +static int hf_pn_io_ptcp_timeout_factor = -1; +static int hf_pn_io_ptcp_takeover_timeout_factor = -1; +static int hf_pn_io_ptcp_master_startup_time = -1; +static int hf_pn_io_ptcp_master_priority_1 = -1; +static int hf_pn_io_ptcp_master_priority_2 = -1; +static int hf_pn_io_ptcp_length_subdomain_name = -1; +static int hf_pn_io_ptcp_subdomain_name = -1; + +static int hf_pn_io_MultipleInterfaceMode_NameOfDevice = -1; +static int hf_pn_io_MultipleInterfaceMode_reserved_1 = -1; +static int hf_pn_io_MultipleInterfaceMode_reserved_2 = -1; +/* added Portstatistics */ +static int hf_pn_io_pdportstatistic_counter_status = -1; +static int hf_pn_io_pdportstatistic_counter_status_ifInOctets = -1; +static int hf_pn_io_pdportstatistic_counter_status_ifOutOctets = -1; +static int hf_pn_io_pdportstatistic_counter_status_ifInDiscards = -1; +static int hf_pn_io_pdportstatistic_counter_status_ifOutDiscards = -1; +static int hf_pn_io_pdportstatistic_counter_status_ifInErrors = -1; +static int hf_pn_io_pdportstatistic_counter_status_ifOutErrors = -1; +static int hf_pn_io_pdportstatistic_counter_status_reserved = -1; +static int hf_pn_io_pdportstatistic_ifInOctets = -1; +static int hf_pn_io_pdportstatistic_ifOutOctets = -1; +static int hf_pn_io_pdportstatistic_ifInDiscards = -1; +static int hf_pn_io_pdportstatistic_ifOutDiscards = -1; +static int hf_pn_io_pdportstatistic_ifInErrors = -1; +static int hf_pn_io_pdportstatistic_ifOutErrors = -1; +/* end of port statistics */ + +static int hf_pn_io_domain_boundary = -1; +static int hf_pn_io_domain_boundary_ingress = -1; +static int hf_pn_io_domain_boundary_egress = -1; +static int hf_pn_io_multicast_boundary = -1; +static int hf_pn_io_adjust_properties = -1; +static int hf_pn_io_PreambleLength = -1; +static int hf_pn_io_mau_type = -1; +static int hf_pn_io_mau_type_mode = -1; +static int hf_pn_io_port_state = -1; +static int hf_pn_io_line_delay = -1; +static int hf_pn_io_line_delay_value = -1; +static int hf_pn_io_cable_delay_value = -1; +static int hf_pn_io_line_delay_format_indicator = -1; +static int hf_pn_io_number_of_peers = -1; +static int hf_pn_io_length_peer_port_id = -1; +static int hf_pn_io_peer_port_id = -1; +static int hf_pn_io_length_peer_chassis_id = -1; +static int hf_pn_io_peer_chassis_id = -1; +static int hf_pn_io_length_own_port_id = -1; +static int hf_pn_io_own_port_id = -1; +static int hf_pn_io_peer_macadd = -1; +static int hf_pn_io_media_type = -1; +static int hf_pn_io_macadd = -1; +static int hf_pn_io_length_own_chassis_id = -1; +static int hf_pn_io_own_chassis_id = -1; + +static int hf_pn_io_ethertype = -1; +static int hf_pn_io_rx_port = -1; +static int hf_pn_io_frame_details = -1; +static int hf_pn_io_frame_details_sync_frame = -1; +static int hf_pn_io_frame_details_meaning_frame_send_offset = -1; +static int hf_pn_io_frame_details_reserved = -1; +static int hf_pn_io_nr_of_tx_port_groups = -1; +static int hf_pn_io_TxPortGroupProperties = -1; +static int hf_pn_io_TxPortGroupProperties_bit0 = -1; +static int hf_pn_io_TxPortGroupProperties_bit1 = -1; +static int hf_pn_io_TxPortGroupProperties_bit2 = -1; +static int hf_pn_io_TxPortGroupProperties_bit3 = -1; +static int hf_pn_io_TxPortGroupProperties_bit4 = -1; +static int hf_pn_io_TxPortGroupProperties_bit5 = -1; +static int hf_pn_io_TxPortGroupProperties_bit6 = -1; +static int hf_pn_io_TxPortGroupProperties_bit7 = -1; + +static int hf_pn_io_start_of_red_frame_id = -1; +static int hf_pn_io_end_of_red_frame_id = -1; +static int hf_pn_io_ir_begin_end_port = -1; +static int hf_pn_io_number_of_assignments = -1; +static int hf_pn_io_number_of_phases = -1; +static int hf_pn_io_red_orange_period_begin_tx = -1; +static int hf_pn_io_orange_period_begin_tx = -1; +static int hf_pn_io_green_period_begin_tx = -1; +static int hf_pn_io_red_orange_period_begin_rx = -1; +static int hf_pn_io_orange_period_begin_rx = -1; +static int hf_pn_io_green_period_begin_rx = -1; +/* static int hf_pn_io_tx_phase_assignment = -1; */ +static int hf_pn_ir_tx_phase_assignment = -1; +static int hf_pn_ir_rx_phase_assignment = -1; +static int hf_pn_io_tx_phase_assignment_begin_value = -1; +static int hf_pn_io_tx_phase_assignment_orange_begin = -1; +static int hf_pn_io_tx_phase_assignment_end_reserved = -1; +static int hf_pn_io_tx_phase_assignment_reserved = -1; +/* static int hf_pn_io_rx_phase_assignment = -1; */ + +static int hf_pn_io_slot = -1; +static int hf_pn_io_subslot = -1; +static int hf_pn_io_number_of_slots = -1; +static int hf_pn_io_number_of_subslots = -1; + +/* static int hf_pn_io_maintenance_required_drop_budget = -1; */ +/* static int hf_pn_io_maintenance_demanded_drop_budget = -1; */ +/* static int hf_pn_io_error_drop_budget = -1; */ + +static int hf_pn_io_maintenance_required_power_budget = -1; +static int hf_pn_io_maintenance_demanded_power_budget = -1; +static int hf_pn_io_error_power_budget = -1; + +static int hf_pn_io_fiber_optic_type = -1; +static int hf_pn_io_fiber_optic_cable_type = -1; + +static int hf_pn_io_controller_appl_cycle_factor = -1; +static int hf_pn_io_time_data_cycle = -1; +static int hf_pn_io_time_io_input = -1; +static int hf_pn_io_time_io_output = -1; +static int hf_pn_io_time_io_input_valid = -1; +static int hf_pn_io_time_io_output_valid = -1; + +static int hf_pn_io_maintenance_status = -1; +static int hf_pn_io_maintenance_status_required = -1; +static int hf_pn_io_maintenance_status_demanded = -1; + +static int hf_pn_io_vendor_id_high = -1; +static int hf_pn_io_vendor_id_low = -1; +static int hf_pn_io_vendor_block_type = -1; +static int hf_pn_io_order_id = -1; +static int hf_pn_io_im_serial_number = -1; +static int hf_pn_io_im_hardware_revision = -1; +static int hf_pn_io_im_revision_prefix = -1; +static int hf_pn_io_im_sw_revision_functional_enhancement = -1; +static int hf_pn_io_im_revision_bugfix = -1; +static int hf_pn_io_im_sw_revision_internal_change = -1; +static int hf_pn_io_im_revision_counter = -1; +static int hf_pn_io_im_profile_id = -1; +static int hf_pn_io_im_profile_specific_type = -1; +static int hf_pn_io_im_version_major = -1; +static int hf_pn_io_im_version_minor = -1; +static int hf_pn_io_im_supported = -1; +static int hf_pn_io_im_numberofentries = -1; +static int hf_pn_io_im_annotation = -1; +static int hf_pn_io_im_order_id = -1; + +static int hf_pn_io_number_of_ars = -1; + +static int hf_pn_io_cycle_counter = -1; +static int hf_pn_io_data_status = -1; +static int hf_pn_io_data_status_res67 = -1; +static int hf_pn_io_data_status_ok = -1; +static int hf_pn_io_data_status_operate = -1; +static int hf_pn_io_data_status_res3 = -1; +static int hf_pn_io_data_status_valid = -1; +static int hf_pn_io_data_status_res1 = -1; +static int hf_pn_io_data_status_primary = -1; +static int hf_pn_io_transfer_status = -1; + +static int hf_pn_io_actual_local_time_stamp = -1; +static int hf_pn_io_number_of_log_entries = -1; +static int hf_pn_io_local_time_stamp = -1; +static int hf_pn_io_entry_detail = -1; + +static int hf_pn_io_ip_address = -1; +static int hf_pn_io_subnetmask = -1; +static int hf_pn_io_standard_gateway = -1; + +static int hf_pn_io_mrp_domain_uuid = -1; +static int hf_pn_io_mrp_role = -1; +static int hf_pn_io_mrp_length_domain_name = -1; +static int hf_pn_io_mrp_domain_name = -1; +static int hf_pn_io_mrp_instances = -1; +static int hf_pn_io_mrp_instance = -1; + +static int hf_pn_io_mrp_prio = -1; +static int hf_pn_io_mrp_topchgt = -1; +static int hf_pn_io_mrp_topnrmax = -1; +static int hf_pn_io_mrp_tstshortt = -1; +static int hf_pn_io_mrp_tstdefaultt = -1; +static int hf_pn_io_mrp_tstnrmax = -1; +static int hf_pn_io_mrp_check = -1; +static int hf_pn_io_mrp_check_mrm = -1; +static int hf_pn_io_mrp_check_mrpdomain = -1; +static int hf_pn_io_mrp_check_reserved_1 = -1; +static int hf_pn_io_mrp_check_reserved_2 = -1; + +static int hf_pn_io_mrp_rtmode = -1; +static int hf_pn_io_mrp_rtmode_rtclass12 = -1; +static int hf_pn_io_mrp_rtmode_rtclass3 = -1; +static int hf_pn_io_mrp_rtmode_reserved1 = -1; +static int hf_pn_io_mrp_rtmode_reserved2 = -1; + +static int hf_pn_io_mrp_lnkdownt = -1; +static int hf_pn_io_mrp_lnkupt = -1; +static int hf_pn_io_mrp_lnknrmax = -1; +static int hf_pn_io_mrp_version = -1; + +static int hf_pn_io_substitute_active_flag = -1; +static int hf_pn_io_length_data = -1; + +static int hf_pn_io_mrp_ring_state = -1; +static int hf_pn_io_mrp_rt_state = -1; + +static int hf_pn_io_im_tag_function = -1; +static int hf_pn_io_im_tag_location = -1; +static int hf_pn_io_im_date = -1; +static int hf_pn_io_im_descriptor = -1; + +static int hf_pn_io_fs_hello_mode = -1; +static int hf_pn_io_fs_hello_interval = -1; +static int hf_pn_io_fs_hello_retry = -1; +static int hf_pn_io_fs_hello_delay = -1; + +static int hf_pn_io_fs_parameter_mode = -1; +static int hf_pn_io_fs_parameter_uuid = -1; + + +static int hf_pn_io_check_sync_mode = -1; +static int hf_pn_io_check_sync_mode_reserved = -1; +static int hf_pn_io_check_sync_mode_sync_master = -1; +static int hf_pn_io_check_sync_mode_cable_delay = -1; + +/* PROFIsafe fParameters */ +static int hf_pn_io_ps_f_prm_flag1 = -1; +static int hf_pn_io_ps_f_prm_flag1_chck_seq = -1; +static int hf_pn_io_ps_f_prm_flag1_chck_ipar = -1; +static int hf_pn_io_ps_f_prm_flag1_sil = -1; +static int hf_pn_io_ps_f_prm_flag1_crc_len = -1; +static int hf_pn_io_ps_f_prm_flag1_crc_seed = -1; +static int hf_pn_io_ps_f_prm_flag1_reserved = -1; +static int hf_pn_io_ps_f_prm_flag2 = -1; +static int hf_pn_io_ps_f_wd_time = -1; +static int hf_pn_io_ps_f_ipar_crc = -1; +static int hf_pn_io_ps_f_par_crc = -1; +static int hf_pn_io_ps_f_src_adr = -1; +static int hf_pn_io_ps_f_dest_adr = -1; +static int hf_pn_io_ps_f_prm_flag2_reserved = -1; +static int hf_pn_io_ps_f_prm_flag2_f_block_id = -1; +static int hf_pn_io_ps_f_prm_flag2_f_par_version = -1; + +static int hf_pn_io_profidrive_request_reference = -1; +static int hf_pn_io_profidrive_request_id = -1; +static int hf_pn_io_profidrive_do_id = -1; +static int hf_pn_io_profidrive_no_of_parameters = -1; +static int hf_pn_io_profidrive_response_id = -1; +static int hf_pn_io_profidrive_param_attribute = -1; +static int hf_pn_io_profidrive_param_no_of_elems = -1; +static int hf_pn_io_profidrive_param_number = -1; +static int hf_pn_io_profidrive_param_subindex = -1; +static int hf_pn_io_profidrive_param_format = -1; +static int hf_pn_io_profidrive_param_no_of_values = -1; +static int hf_pn_io_profidrive_param_value_byte = -1; +static int hf_pn_io_profidrive_param_value_word = -1; +static int hf_pn_io_profidrive_param_value_dword = -1; +static int hf_pn_io_profidrive_param_value_float = -1; +static int hf_pn_io_profidrive_param_value_string = -1; + +/* Sequence of Events - Reporting System Alarm/Event Information */ +static int hf_pn_io_rs_alarm_info_reserved_0_7 = -1; +static int hf_pn_io_rs_alarm_info_reserved_8_15 = -1; +static int hf_pn_io_rs_alarm_info = -1; +static int hf_pn_io_rs_event_info = -1; +static int hf_pn_io_rs_event_block = -1; +static int hf_pn_io_rs_adjust_block = -1; +static int hf_pn_io_rs_event_data_extension = -1; +static int hf_pn_io_number_of_rs_event_info = -1; +static int hf_pn_io_rs_block_type = -1; +static int hf_pn_io_rs_block_length = -1; +static int hf_pn_io_rs_specifier = -1; +static int hf_pn_io_rs_specifier_sequence = -1; +static int hf_pn_io_rs_specifier_reserved = -1; +static int hf_pn_io_rs_specifier_specifier = -1; +static int hf_pn_io_rs_time_stamp = -1; +static int hf_pn_io_rs_time_stamp_status = -1; +static int hf_pn_io_rs_time_stamp_value = -1; +static int hf_pn_io_rs_minus_error = -1; +static int hf_pn_io_rs_plus_error = -1; +static int hf_pn_io_rs_extension_block_type = -1; +static int hf_pn_io_rs_extension_block_length = -1; +static int hf_pn_io_rs_reason_code = -1; +static int hf_pn_io_rs_reason_code_reason = -1; +static int hf_pn_io_rs_reason_code_detail = -1; +static int hf_pn_io_rs_domain_identification = -1; +static int hf_pn_io_rs_master_identification = -1; +static int hf_pn_io_soe_digital_input_current_value = -1; +static int hf_pn_io_soe_digital_input_current_value_value = -1; +static int hf_pn_io_soe_digital_input_current_value_reserved = -1; +static int hf_pn_io_am_device_identification = -1; +static int hf_pn_io_am_device_identification_device_sub_id = -1; +static int hf_pn_io_am_device_identification_device_id = -1; +static int hf_pn_io_am_device_identification_vendor_id = -1; +static int hf_pn_io_am_device_identification_organization = -1; +static int hf_pn_io_rs_adjust_info = -1; +static int hf_pn_io_soe_max_scan_delay = -1; +static int hf_pn_io_soe_adjust_specifier = -1; +static int hf_pn_io_soe_adjust_specifier_reserved = -1; +static int hf_pn_io_soe_adjust_specifier_incident = -1; +static int hf_pn_io_rs_properties = -1; +static int hf_pn_io_rs_properties_alarm_transport = -1; +static int hf_pn_io_rs_properties_reserved1 = -1; +static int hf_pn_io_rs_properties_reserved2 = -1; + +static int hf_pn_io_asset_management_info = -1; +static int hf_pn_io_number_of_asset_management_info = -1; +static int hf_pn_io_im_uniqueidentifier = -1; +static int hf_pn_io_am_location_structure = -1; +static int hf_pn_io_am_location_level_0 = -1; +static int hf_pn_io_am_location_level_1 = -1; +static int hf_pn_io_am_location_level_2 = -1; +static int hf_pn_io_am_location_level_3 = -1; +static int hf_pn_io_am_location_level_4 = -1; +static int hf_pn_io_am_location_level_5 = -1; +static int hf_pn_io_am_location_level_6 = -1; +static int hf_pn_io_am_location_level_7 = -1; +static int hf_pn_io_am_location_level_8 = -1; +static int hf_pn_io_am_location_level_9 = -1; +static int hf_pn_io_am_location_level_10 = -1; +static int hf_pn_io_am_location_level_11 = -1; +static int hf_pn_io_am_location = -1; +static int hf_pn_io_am_location_reserved1 = -1; +static int hf_pn_io_am_location_reserved2 = -1; +static int hf_pn_io_am_location_reserved3 = -1; +static int hf_pn_io_am_location_reserved4 = -1; +static int hf_pn_io_am_software_revision = -1; +static int hf_pn_io_am_hardware_revision = -1; +static int hf_pn_io_am_type_identification = -1; + +static int hf_pn_io_dcp_boundary_value = -1; +static int hf_pn_io_dcp_boundary_value_bit0 = -1; +static int hf_pn_io_dcp_boundary_value_bit1 = -1; +static int hf_pn_io_dcp_boundary_value_otherbits = -1; + +static int hf_pn_io_peer_to_peer_boundary_value = -1; +static int hf_pn_io_peer_to_peer_boundary_value_bit0 = -1; +static int hf_pn_io_peer_to_peer_boundary_value_bit1 = -1; +static int hf_pn_io_peer_to_peer_boundary_value_bit2 = -1; +static int hf_pn_io_peer_to_peer_boundary_value_otherbits = -1; + +static int hf_pn_io_mau_type_extension = -1; + +/* static int hf_pn_io_packedframe_SFCRC = -1; */ +static gint ett_pn_io = -1; +static gint ett_pn_io_block = -1; +static gint ett_pn_io_block_header = -1; +static gint ett_pn_io_status = -1; +static gint ett_pn_io_rtc = -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 gint ett_pn_io_ioxs = -1; +static gint ett_pn_io_api = -1; +static gint ett_pn_io_data_description = -1; +static gint ett_pn_io_module = -1; +static gint ett_pn_io_submodule = -1; +static gint ett_pn_io_io_data_object = -1; +static gint ett_pn_io_io_cs = -1; +static gint ett_pn_io_ar_properties = -1; +static gint ett_pn_io_iocr_properties = -1; +static gint ett_pn_io_submodule_properties = -1; +static gint ett_pn_io_alarmcr_properties = -1; +static gint ett_pn_io_submodule_state = -1; +static gint ett_pn_io_channel_properties = -1; +static gint ett_pn_io_slot = -1; +static gint ett_pn_io_subslot = -1; +static gint ett_pn_io_maintenance_status = -1; +static gint ett_pn_io_data_status = -1; +static gint ett_pn_io_iocr = -1; +static gint ett_pn_io_mrp_rtmode = -1; +static gint ett_pn_io_control_block_properties = -1; +static gint ett_pn_io_check_sync_mode = -1; +static gint ett_pn_io_ir_frame_data = -1; +static gint ett_pn_FrameDataProperties = -1; +static gint ett_pn_io_ar_info = -1; +static gint ett_pn_io_ar_data = -1; +static gint ett_pn_io_ir_begin_end_port = -1; +static gint ett_pn_io_ir_tx_phase = -1; +static gint ett_pn_io_ir_rx_phase = -1; +static gint ett_pn_io_subframe_data =-1; +static gint ett_pn_io_SFIOCRProperties = -1; +static gint ett_pn_io_frame_defails = -1; +static gint ett_pn_io_profisafe_f_parameter = -1; +static gint ett_pn_io_profisafe_f_parameter_prm_flag1 = -1; +static gint ett_pn_io_profisafe_f_parameter_prm_flag2 = -1; +static gint ett_pn_io_profidrive_parameter_request = -1; +static gint ett_pn_io_profidrive_parameter_response = -1; +static gint ett_pn_io_profidrive_parameter_address = -1; +static gint ett_pn_io_profidrive_parameter_value = -1; +static gint ett_pn_io_rs_alarm_info = -1; +static gint ett_pn_io_rs_event_info = -1; +static gint ett_pn_io_rs_event_block = -1; +static gint ett_pn_io_rs_adjust_block = -1; +static gint ett_pn_io_rs_event_data_extension = -1; +static gint ett_pn_io_rs_specifier = -1; +static gint ett_pn_io_rs_time_stamp = -1; +static gint ett_pn_io_am_device_identification = -1; +static gint ett_pn_io_rs_reason_code = -1; +static gint ett_pn_io_soe_digital_input_current_value = -1; +static gint ett_pn_io_rs_adjust_info = -1; +static gint ett_pn_io_soe_adjust_specifier = -1; +static gint ett_pn_io_sr_properties = -1; +static gint ett_pn_io_line_delay = -1; +static gint ett_pn_io_counter_status = -1; + +static gint ett_pn_io_GroupProperties = -1; + +static gint ett_pn_io_asset_management_info = -1; +static gint ett_pn_io_asset_management_block = -1; +static gint ett_pn_io_am_location = -1; + +static gint ett_pn_io_dcp_boundary = -1; +static gint ett_pn_io_peer_to_peer_boundary = -1; + +static gint ett_pn_io_mau_type_extension = -1; + +#define PD_SUB_FRAME_BLOCK_FIOCR_PROPERTIES_LENGTH 4 +#define PD_SUB_FRAME_BLOCK_FRAME_ID_LENGTH 2 +#define PD_SUB_FRAME_BLOCK_SUB_FRAME_DATA_LENGTH 4 + +static expert_field ei_pn_io_block_version = EI_INIT; +static expert_field ei_pn_io_block_length = EI_INIT; +static expert_field ei_pn_io_unsupported = EI_INIT; +static expert_field ei_pn_io_error_code1 = EI_INIT; +static expert_field ei_pn_io_localalarmref = EI_INIT; +static expert_field ei_pn_io_mrp_instances = EI_INIT; +static expert_field ei_pn_io_error_code2 = EI_INIT; +static expert_field ei_pn_io_ar_info_not_found = EI_INIT; +static expert_field ei_pn_io_iocr_type = EI_INIT; +static expert_field ei_pn_io_frame_id = EI_INIT; +static expert_field ei_pn_io_nr_of_tx_port_groups = EI_INIT; +static expert_field ei_pn_io_max_recursion_depth_reached = EI_INIT; + +static e_guid_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_guid_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_guid_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_guid_t uuid_pn_io_parameterserver = { 0xDEA00004, 0x6C97, 0x11D1, { 0x82, 0x71, 0x00, 0xA0, 0x24, 0x42, 0xDF, 0x7D } }; +static guint16 ver_pn_io_parameterserver = 1; + +/* According to specification: + * Value(UUID): 00000000-0000-0000-0000-000000000000 + * Meaning: Reserved + * Use: The value NIL indicates the usage of the implicit AR. + */ +static e_guid_t uuid_pn_io_implicitar = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; +static guint16 ver_pn_io_implicitar = 1; + +/* PNIO Preference Variables */ +gboolean pnio_ps_selection = TRUE; +static const char *pnio_ps_networkpath = ""; + + +/* Allow heuristic dissection */ +static heur_dissector_list_t heur_pn_subdissector_list; + +static const value_string pn_io_block_type[] = { + { 0x0000, "Reserved" }, + { 0x0001, "Alarm Notification High"}, + { 0x0002, "Alarm Notification Low"}, + { 0x0008, "IODWriteReqHeader"}, + { 0x8008, "IODWriteResHeader"}, + { 0x0009, "IODReadReqHeader"}, + { 0x8009, "IODReadResHeader"}, + { 0x0010, "DiagnosisData"}, + { 0x0011, "Reserved"}, + { 0x0012, "ExpectedIdentificationData"}, + { 0x0013, "RealIdentificationData"}, + { 0x0014, "SubstituteValue"}, + { 0x0015, "RecordInputDataObjectElement"}, + { 0x0016, "RecordOutputDataObjectElement"}, + { 0x0017, "reserved"}, + { 0x0018, "ARData"}, + { 0x0019, "LogData"}, + { 0x001A, "APIData"}, + { 0x001b, "SRLData"}, + { 0x0020, "I&M0"}, + { 0x0021, "I&M1"}, + { 0x0022, "I&M2"}, + { 0x0023, "I&M3"}, + { 0x0024, "I&M4"}, + { 0x0025, "I&M5"}, + { 0x0026, "I&M6"}, + { 0x0027, "I&M7"}, + { 0x0028, "I&M8"}, + { 0x0029, "I&M9"}, + { 0x002A, "I&M10"}, + { 0x002B, "I&M11"}, + { 0x002C, "I&M12"}, + { 0x002D, "I&M13"}, + { 0x002E, "I&M14"}, + { 0x002F, "I&M15"}, + { 0x0030, "I&M0FilterDataSubmodul"}, + { 0x0031, "I&M0FilterDataModul"}, + { 0x0032, "I&M0FilterDataDevice"}, + { 0x0033, "Reserved" }, + { 0x0034, "I&M5Data"}, + { 0x0035, "AssetManagementData"}, + { 0x0036, "AM_FullInformation"}, + { 0x0037, "AM_HardwareOnlyInformation"}, + { 0x0038, "AM_FirmwareOnlyInformation" }, + { 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"}, + { 0x0106, "MCRBlockReq"}, + { 0x8106, "ARServerBlock"}, + { 0x0107, "SubFrameBlock"}, + { 0x0108, "ARVendorBlockReq"}, + { 0x8108, "ARVendorBlockRes"}, + { 0x0109, "IRInfoBlock"}, + { 0x010A, "SRInfoBlock"}, + { 0x010B, "ARFSUBlock"}, + { 0x010C, "RSInfoBlock"}, + { 0x0110, "IODControlReq Prm End.req"}, + { 0x8110, "IODControlRes Prm End.rsp"}, + { 0x0111, "IODControlReq Prm End.req"}, + { 0x8111, "IODControlRes Prm End.rsp"}, + { 0x0112, "IOXBlockReq Application Ready.req"}, + { 0x8112, "IOXBlockRes Application Ready.rsp"}, + { 0x0113, "IOXBlockReq Application Ready.req"}, + { 0x8113, "IOXBlockRes Application Ready.rsp"}, + { 0x0114, "IODReleaseReq"}, + { 0x8114, "IODReleaseRes"}, + { 0x0115, "ARRPCServerBlockReq"}, + { 0x8115, "ARRPCServerBlockRes"}, + { 0x0116, "IOXControlReq Ready for Companion.req"}, + { 0x8116, "IOXControlRes Ready for Companion.rsp"}, + { 0x0117, "IOXControlReq Ready for RT_CLASS_3.req"}, + { 0x8117, "IOXControlRes Ready for RT_CLASS_3.rsp"}, + { 0x0118, "ControlBlockPrmBegin"}, + { 0x0119, "SubmoduleListBlock"}, + { 0x8118, "ControlBlockPrmBeginRes"}, + + { 0x0200, "PDPortDataCheck"}, + { 0x0201, "PDevData"}, + { 0x0202, "PDPortDataAdjust"}, + { 0x0203, "PDSyncData"}, + { 0x0204, "IsochronousModeData"}, + { 0x0205, "PDIRData"}, + { 0x0206, "PDIRGlobalData"}, + { 0x0207, "PDIRFrameData"}, + { 0x0208, "PDIRBeginEndData"}, + { 0x0209, "AdjustDomainBoundary"}, + { 0x020A, "CheckPeers"}, + { 0x020B, "CheckLineDelay"}, + { 0x020C, "Checking MAUType"}, + { 0x020E, "Adjusting MAUType"}, + { 0x020F, "PDPortDataReal"}, + { 0x0210, "AdjustMulticastBoundary"}, + { 0x0211, "PDInterfaceMrpDataAdjust"}, + { 0x0212, "PDInterfaceMrpDataReal"}, + { 0x0213, "PDInterfaceMrpDataCheck"}, + { 0x0214, "PDPortMrpDataAdjust"}, + { 0x0215, "PDPortMrpDataReal"}, + { 0x0216, "Media redundancy manager parameters"}, + { 0x0217, "Media redundancy client parameters"}, + { 0x0218, "Media redundancy RT mode for manager"}, + { 0x0219, "Media redundancy ring state data"}, + { 0x021A, "Media redundancy RT ring state data"}, + { 0x021B, "Adjust LinkState"}, + { 0x021C, "Checking LinkState"}, + { 0x021D, "Media redundancy RT mode for clients"}, + { 0x021E, "CheckSyncDifference"}, + { 0x021F, "CheckMAUTypeDifference"}, + { 0x0220, "PDPortFODataReal"}, + { 0x0221, "Reading real fiber optic manufacturerspecific data"}, + { 0x0222, "PDPortFODataAdjust"}, + { 0x0223, "PDPortFODataCheck"}, + { 0x0224, "Adjust PeerToPeerBoundary"}, + { 0x0225, "Adjust DCPBoundary"}, + { 0x0226, "Adjust PreambleLength"}, + { 0x0227, "CheckMAUType-Extension"}, + { 0x0228, "Reading real fiber optic diagnosis data"}, + { 0x0229, "AdjustMAUType-Extension"}, + { 0x022A, "PDIRSubframeData"}, + { 0x022B, "SubframeBlock"}, + { 0x0230, "PDNCDataCheck"}, + { 0x0231, "MrpInstanceDataAdjust"}, + { 0x0232, "MrpInstanceDataReal"}, + { 0x0233, "MrpInstanceDataCheck"}, + { 0x0240, "PDInterfaceDataReal"}, + { 0x0250, "PDInterfaceAdjust"}, + { 0x0251, "PDPortStatistic"}, + { 0x0400, "MultipleBlockHeader"}, + { 0x0401, "COContainerContent"}, + { 0x0500, "RecordDataReadQuery"}, + { 0x0600, "FSHello"}, + { 0x0601, "FSParameterBlock"}, + { 0x0608, "PDInterfaceFSUDataAdjust"}, + { 0x0609, "ARFSUDataAdjust"}, + { 0x0700, "AutoConfiguration"}, + { 0x0701, "AutoConfiguration Communication"}, + { 0x0702, "AutoConfiguration Configuration"}, + { 0x0900, "RS_AdjustObserver" }, + { 0x0901, "RS_GetEvent" }, + { 0x0902, "RS_AckEvent" }, + { 0xB050, "Ext-PLL Control / RTC+RTA SyncID 0 (EDD)" }, + { 0xB051, "Ext-PLL Control / RTA SyncID 1 (GSY)" }, + + { 0xB060, "EDD Trace Unit (EDD)" }, + { 0xB061, "EDD Trace Unit (EDD)" }, + + { 0xB070, "OHA Info (OHA)" }, + + { 0x0F00, "MaintenanceItem"}, + { 0x0F01, "Upload selected Records within Upload&RetrievalItem"}, + { 0x0F02, "iParameterItem"}, + { 0x0F03, "Retrieve selected Records within Upload&RetrievalItem"}, + { 0x0F04, "Retrieve all Records within Upload&RetrievalItem"}, + { 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" }, + { 0x000A, "Plug wrong submodule" }, + { 0x000B, "Return of submodule" }, + { 0x000C, "Diagnosis disappears" }, + { 0x000D, "Multicast communication mismatch notification" }, + { 0x000E, "Port data change notification" }, + { 0x000F, "Sync data changed notification" }, + { 0x0010, "Isochronous mode problem notification" }, + { 0x0011, "Network component problem notification" }, + { 0x0012, "Time data changed notification" }, + { 0x0013, "Dynamic Frame Packing problem notification" }, + /*0x0014 - 0x001D reserved */ + { 0x001E, "Upload and retrieval notification" }, + { 0x001F, "Pull module" }, + /*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 hf_pn_io_frame_data_properties_forwardingMode[] = { + { 0x00, "absolute mode" }, + { 0x01, "relative mode"}, + { 0, NULL } +}; +static const value_string hf_pn_io_frame_data_properties_FFMulticastMACAdd[] = { + { 0x00, "Use interface MAC destination unicast address" }, + { 0x01, "Use RT_CLASS_3 destination multicast address"}, + { 0x02, "Use FastForwardingMulticastMACAdd"}, + { 0x03, "reserved"}, + { 0, NULL }}; + +static const value_string hf_pn_io_frame_data_properties_FragMode[] = { + { 0x00, "No fragmentation" }, + { 0x01, "Fragmentation enabled maximum size for static fragmentation 128 bytes"}, + { 0x02, "Fragmentation enabled maximum size for static fragmentation 256 bytes"}, + { 0x03, "reserved"}, + { 0, NULL }}; + +static const value_string pn_io_SFIOCRProperties_DFPType_vals[] = { + { 0x00, "DFP_INBOUND" }, + { 0x01, "DFP_OUTBOUND" }, + { 0, NULL } +}; + +static const value_string pn_io_DFPRedundantPathLayout_decode[] = { + { 0x00, "The Frame for the redundant path contains the ordering shown by SubframeData" }, + { 0x01, "The Frame for the redundant path contains the inverse ordering shown by SubframeData" }, + { 0, NULL } +}; + +static const value_string pn_io_SFCRC16_Decode[] = { + { 0x00, "SFCRC16 and SFCycleCounter shall be created or set to zero by the sender and not checked by the receiver" }, + { 0x01, "SFCRC16 and SFCycleCounter shall be created by the sender and checked by the receiver." }, + { 0, NULL } +}; + +static const value_string pn_io_txgroup_state[] = { + { 0x00, "Transmission off" }, + { 0x01, "Transmission on " }, + { 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 } +}; + +/* dummy for unknown decode */ +static const value_string pn_io_error_code1[] = { + { 0x00, "OK" }, + { 0, NULL } +}; + +/* dummy for unknown decode/code1 combination */ +static const value_string pn_io_error_code2[] = { + { 0x00, "OK" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code1_pniorw[] = { + /* high nibble 0-9 not specified -> legacy codes */ + { 0xa0, "application: read error" }, + { 0xa1, "application: write error" }, + { 0xa2, "application: module failure" }, + { 0xa3, "application: not specified" }, + { 0xa4, "application: not specified" }, + { 0xa5, "application: not specified" }, + { 0xa6, "application: not specified" }, + { 0xa7, "application: busy" }, + { 0xa8, "application: version conflict" }, + { 0xa9, "application: feature not supported" }, + { 0xaa, "application: User specific 1" }, + { 0xab, "application: User specific 2" }, + { 0xac, "application: User specific 3" }, + { 0xad, "application: User specific 4" }, + { 0xae, "application: User specific 5" }, + { 0xaf, "application: User specific 6" }, + { 0xb0, "access: invalid index" }, + { 0xb1, "access: write length error" }, + { 0xb2, "access: invalid slot/subslot" }, + { 0xb3, "access: type conflict" }, + { 0xb4, "access: invalid area" }, + { 0xb5, "access: state conflict" }, + { 0xb6, "access: access denied" }, + { 0xb7, "access: invalid range" }, + { 0xb8, "access: invalid parameter" }, + { 0xb9, "access: invalid type" }, + { 0xba, "access: backup" }, + { 0xbb, "access: User specific 7" }, + { 0xbc, "access: User specific 8" }, + { 0xbd, "access: User specific 9" }, + { 0xbe, "access: User specific 10" }, + { 0xbf, "access: User specific 11" }, + { 0xc0, "resource: read constrain conflict" }, + { 0xc1, "resource: write constrain conflict" }, + { 0xc2, "resource: resource busy" }, + { 0xc3, "resource: resource unavailable" }, + { 0xc4, "resource: not specified" }, + { 0xc5, "resource: not specified" }, + { 0xc6, "resource: not specified" }, + { 0xc7, "resource: not specified" }, + { 0xc8, "resource: User specific 12" }, + { 0xc9, "resource: User specific 13" }, + { 0xca, "resource: User specific 14" }, + { 0xcb, "resource: User specific 15" }, + { 0xcc, "resource: User specific 16" }, + { 0xcd, "resource: User specific 17" }, + { 0xce, "resource: User specific 18" }, + { 0xcf, "resource: User specific 19" }, + /* high nibble d-f user specific */ + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pniorw[] = { + /* all values are user specified */ + { 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" }, + { 0x06 /* 6*/, "Connect: Faulty MCRBlockReq" }, + { 0x07 /* 7*/, "Connect: Faulty ARRPCBlockReq" }, + { 0x08 /* 8*/, "Read/Write Record: Faulty Record" }, + { 0x09 /* 9*/, "Connect: Faulty SubFrameBlock" }, + { 0x0A /* 10*/, "Connect: Faulty IRTFrameBlock" }, + { 0x0D /* 13*/, "Connect: Faulty RSInfoBlock" }, + { 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" }, + + { 0x32 /* 50*/, "Response: Faulty ARBlockRes" }, + { 0x33 /* 51*/, "Response: Faulty IOCRBlockRes" }, + { 0x34 /* 52*/, "Response: Faulty AlarmCRBlockRes" }, + { 0x35 /* 53*/, "Response: Faulty ModuleDifflock" }, + { 0x36 /* 54*/, "Response: Faulty ARRPCBlockRes" }, + + { 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" }, + { 0xff /*255*/, "User specific" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_1[] = { + /* CheckingRules for ARBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter ARType" }, + { 5, "Error in Parameter ARUUID" }, + { 7, "Error in Parameter CMInitiatorMACAddress" }, + { 8, "Error in Parameter CMInitiatorObjectUUID" }, + { 9, "Error in Parameter ARProperties" }, + { 10, "Error in Parameter CMInitiatorActivityTimeoutFactor" }, + { 11, "Error in Parameter InitiatorUDPRTPort" }, + { 12, "Error in Parameter StationNameLength" }, + { 13, "Error in Parameter CMInitiatorStationName" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_2[] = { + /* CheckingRules for IOCRBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter IOCRType" }, + { 5, "Error in Parameter IOCRReference" }, + { 6, "Error in Parameter LT" }, + { 7, "Error in Parameter IOCRProperties" }, + { 8, "Error in Parameter DataLength" }, + { 9, "Error in Parameter FrameID" }, + { 10, "Error in Parameter SendClockFactor" }, + { 11, "Error in Parameter ReductionRatio" }, + { 12, "Error in Parameter Phase" }, + { 14, "Error in Parameter FrameSendOffset" }, + { 15, "Error in Parameter WatchdogFactor" }, + { 16, "Error in Parameter DataHoldFactor" }, + { 17, "Error in Parameter IOCRTagHeader" }, + { 18, "Error in Parameter IOCRMulticastMacAddress" }, + { 19, "Error in Parameter NumberOfAPI" }, + { 20, "Error in Parameter API" }, + { 21, "Error in Parameter NumberOfIODataObjects" }, + { 22, "Error in Parameter SlotNumber" }, + { 23, "Error in Parameter SubslotNumber" }, + { 24, "Error in Parameter IODataObjectFrameOffset" }, + { 25, "Error in Parameter NumberOfIOCS" }, + { 26, "Error in Parameter SlotNumber" }, + { 27, "Error in Parameter SubslotNumber" }, + { 28, "Error in Parameter IOCSFrameOffset" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_3[] = { + /* CheckingRules for ExpectedSubmoduleBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter NumberOfAPI" }, + { 5, "Error in Parameter API" }, + { 6, "Error in Parameter SlotNumber" }, + { 7, "Error in Parameter ModuleIdentNumber" }, + { 8, "Error in Parameter ModuleProperties" }, + { 9, "Error in Parameter NumberOfSubmodules" }, + { 10, "Error in Parameter SubslotNumber" }, + { 12, "Error in Parameter SubmoduleProperties" }, + { 13, "Error in Parameter DataDescription" }, + { 14, "Error in Parameter SubmoduleDataLength" }, + { 15, "Error in Parameter LengthIOPS" }, + { 16, "Error in Parameter LengthIOCS" }, + { 0, NULL } +}; + + +static const value_string pn_io_error_code2_pnio_4[] = { + /* CheckingRules for AlarmCRBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter AlarmCRType" }, + { 5, "Error in Parameter LT" }, + { 6, "Error in Parameter AlarmCRProperties" }, + { 7, "Error in Parameter RTATimeoutFactor" }, + { 8, "Error in Parameter RTARetries" }, + { 10, "Error in Parameter MaxAlarmDataLength" }, + { 11, "Error in Parameter AlarmCRTagHeaderHigh" }, + { 12, "Error in Parameter AlarmCRTagHeaderLow" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_5[] = { + /* CheckingRules for PrmServerBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 6, "Error in Parameter CMInitiatorActivityTimeoutFactor" }, + { 7, "Error in Parameter StationNameLength" }, + { 8, "Error in Parameter ParameterServerStationName" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_6[] = { + /* CheckingRules for MCRBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter IOCRReference" }, + { 5, "Error in Parameter AddressResolutionProperties" }, + { 6, "Error in Parameter MCITimeoutFactor" }, + { 7, "Error in Parameter StationNameLength" }, + { 8, "Error in Parameter ProviderStationName" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_7[] = { + /* CheckingRules for MCRBlockReq */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter InitiatorRPCServerPort" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_8[] = { + /* CheckingRules for Read/Write ParameterReqHeader */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 5, "Error in Parameter ARUUID" }, + { 6, "Error in Parameter API" }, + { 7, "Error in Parameter SlotNumber" }, + { 8, "Error in Parameter SubslotNumber" }, + { 9, "Error in Parameter Padding" }, + { 10, "Error in Parameter Index" }, + { 11, "Error in Parameter RecordDataLength" }, + { 12, "Error in Parameter TargetARUUID" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_13[] = { + /* CheckingRules for RSInfoBlock */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter Padding" }, + { 5, "Error in Parameter RSProperties" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_20[] = { + /* CheckingRules for ControlBlockConnect */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter Padding" }, + { 6, "Error in Parameter SessionKey" }, + { 7, "Error in Parameter Padding" }, + { 8, "Error in Parameter ControlCommand" }, + { 9, "Error in Parameter ControlBlockProperties" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_21[] = { + /* CheckingRules for ControlBlockPlug */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter Padding" }, + { 6, "Error in Parameter SessionKey" }, + { 7, "Error in Parameter AlarmSequenceNumber" }, + { 8, "Error in Parameter ControlCommand" }, + { 9, "Error in Parameter ControlBlockProperties" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_22[] = { + /* CheckingRule for ControlBlockConnect */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter Padding" }, + { 6, "Error in Parameter SessionKey" }, + { 7, "Error in Parameter Padding" }, + { 8, "Error in Parameter ControlCommand" }, + { 9, "Error in Parameter ControlBlockProperties" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_23[] = { + /* CheckingRules for ControlBlockPlug */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter Padding" }, + { 6, "Error in Parameter SessionKey" }, + { 7, "Error in Parameter AlarmSequenceNumber" }, + { 8, "Error in Parameter ControlCommand" }, + { 9, "Error in Parameter ControlBlockProperties" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_40[] = { + /* CheckingRules for ReleaseBlock */ + { 0, "Error in Parameter BlockType" }, + { 1, "Error in Parameter BlockLength" }, + { 2, "Error in Parameter BlockVersionHigh" }, + { 3, "Error in Parameter BlockVersionLow" }, + { 4, "Error in Parameter Padding" }, + { 6, "Error in Parameter SessionKey" }, + { 7, "Error in Parameter Padding" }, + { 8, "Error in Parameter ControlCommand" }, + { 9, "Error in Parameter ControlBlockProperties" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_60[] = { + /* AlarmAck Error Codes */ + { 0, "Alarm Type Not Supported" }, + { 1, "Wrong Submodule State" }, + { 2, "IOCARSR Backup - Alarm not executed" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_61[] = { + /* CMDEV */ + { 0, "State Conflict" }, + { 1, "Resources" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_62[] = { + /* CMCTL */ + { 0, "State Conflict" }, + { 1, "Timeout" }, + { 2, "No data send" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_63[] = { + /* NRPM */ + { 0, "No DCP active" }, + { 1, "DNS Unknown_RealStationName" }, + { 2, "DCP No_RealStationName" }, + { 3, "DCP Multiple_RealStationName" }, + { 4, "DCP No_StationName" }, + { 5, "No_IP_Addr" }, + { 6, "DCP_Set_Error" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_64[] = { + /* RMPM */ + { 0, "ArgsLength invalid" }, + { 1, "Unknown Blocks" }, + { 2, "IOCR Missing" }, + { 3, "Wrong AlarmCRBlock count" }, + { 4, "Out of AR Resources" }, + { 5, "AR UUID unknown" }, + { 6, "State conflict" }, + { 7, "Out of Provider, Consumer or Alarm Resources" }, + { 8, "Out of Memory" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_65[] = { + /* ALPMI */ + { 0, "Invalid State" }, + { 1, "Wrong ACK-PDU" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_66[] = { + /* ALPMR */ + { 0, "Invalid State" }, + { 1, "Wrong Notification PDU" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_70[] = { + /* APMR */ + { 0, "Invalid State" }, + { 1, "LMPM signaled error" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_71[] = { + /* APMS */ + { 0, "Invalid State" }, + { 1, "LMPM signaled error" }, + { 2, "Timeout" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_72[] = { + /* CPM */ + { 1, "Invalid State" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_73[] = { + /* PPM */ + { 1, "Invalid State" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_74[] = { + /* DCPUCS */ + { 0, "Invalid State" }, + { 1, "LMPM signaled an error" }, + { 2, "Timeout" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_75[] = { + /* DCPUCR */ + { 0, "Invalid State" }, + { 1, "LMPM signaled an error" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_76[] = { + /* DCPMCS */ + { 0, "Invalid State" }, + { 1, "LMPM signaled an error" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_77[] = { + /* DCPMCR */ + { 0, "Invalid State" }, + { 1, "LMPM signaled an error" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_253[] = { + { 0, "reserved" }, + { 1, "Error within the coordination of sequence numbers (RTA_ERR_CODE_SEQ) error" }, + { 2, "Instance closed (RTA_ERR_ABORT)" }, + { 3, "AR out of memory (RTA_ERR_ABORT)" }, + { 4, "AR add provider or consumer failed (RTA_ERR_ABORT)" }, + { 5, "AR consumer DHT/WDT expired (RTA_ERR_ABORT)" }, + { 6, "AR cmi timeout (RTA_ERR_ABORT)" }, + { 7, "AR alarm-open failed (RTA_ERR_ABORT)" }, + { 8, "AR alarm-send.cnf(-) (RTA_ERR_ABORT)" }, + { 9, "AR alarm-ack-send.cnf(-) (RTA_ERR_ABORT)" }, + { 10, "AR alarm data too long (RTA_ERR_ABORT)" }, + { 11, "AR alarm.ind(err) (RTA_ERR_ABORT)" }, + { 12, "AR rpc-client call.cnf(-) (RTA_ERR_ABORT)" }, + { 13, "AR abort.req (RTA_ERR_ABORT)" }, + { 14, "AR re-run aborts existing (RTA_ERR_ABORT)" }, + { 15, "AR release.ind received (RTA_ERR_ABORT)" }, + { 16, "AR device deactivated (RTA_ERR_ABORT)" }, + { 17, "AR removed (RTA_ERR_ABORT)" }, + { 18, "AR protocol violation (RTA_ERR_ABORT)" }, + { 19, "AR name resolution error (RTA_ERR_ABORT)" }, + { 20, "AR RPC-Bind error (RTA_ERR_ABORT)" }, + { 21, "AR RPC-Connect error (RTA_ERR_ABORT)" }, + { 22, "AR RPC-Read error (RTA_ERR_ABORT)" }, + { 23, "AR RPC-Write error (RTA_ERR_ABORT)" }, + { 24, "AR RPC-Control error (RTA_ERR_ABORT)" }, + { 25, "AR forbidden pull or plug after check.rsp and before in-data.ind (RTA_ERR_ABORT)" }, + { 26, "AR AP removed (RTA_ERR_ABORT)" }, + { 27, "AR link down (RTA_ERR_ABORT)" }, + { 28, "AR could not register multicast-mac address (RTA_ERR_ABORT)" }, + { 29, "not synchronized (cannot start companion-ar) (RTA_ERR_ABORT)" }, + { 30, "wrong topology (cannot start companion-ar) (RTA_ERR_ABORT)" }, + { 31, "dcp, station-name changed (RTA_ERR_ABORT)" }, + { 32, "dcp, reset to factory-settings (RTA_ERR_ABORT)" }, + { 33, "cannot start companion-AR because a 0x8ipp submodule in the first AR... (RTA_ERR_ABORT)" }, + { 34, "no irdata record yet (RTA_ERR_ABORT)" }, + { 35, "PDEV (RTA_ERROR_ABORT)" }, + { 36, "PDEV, no port offers required speed/duplexity (RTA_ERROR_ABORT)" }, + { 37, "IP-Suite [of the IOC] changed by means of DCP_Set(IPParameter) or local engineering (RTA_ERROR_ABORT)" }, + { 0, NULL } +}; + +static const value_string pn_io_error_code2_pnio_255[] = { + /* User specific */ + { 255, "User abort" }, + { 0, NULL } +}; + +static const value_string pn_io_ioxs[] = { + { 0x00 /* 0*/, "detected by subslot" }, + { 0x01 /* 1*/, "detected by slot" }, + { 0x02 /* 2*/, "detected by IO device" }, + { 0x03 /* 3*/, "detected by IO controller" }, + { 0, NULL } +}; + + +static const value_string pn_io_ar_type[] = { + { 0x0000, "reserved" }, + { 0x0001, "IO Controller AR"}, + { 0x0002, "reserved" }, + { 0x0003, "IOCARCIR" }, + { 0x0004, "reserved" }, + { 0x0005, "reserved" }, + { 0x0006, "IO Supervisor AR / DeviceAccess AR" }, + /*0x0007 - 0x000F reserved */ + { 0x0010, "IO Controller AR (RT_CLASS_3)" }, + /*0x0011 - 0x001F reserved */ + { 0x0020, "IO Controller AR (sysred/CiR)" }, + /*0x0007 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_iocr_type[] = { + { 0x0000, "reserved" }, + { 0x0001, "Input CR" }, + { 0x0002, "Output CR" }, + { 0x0003, "Multicast Provider CR" }, + { 0x0004, "Multicast Consumer CR" }, + /*0x0005 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_data_description[] = { + { 0x0000, "reserved" }, + { 0x0001, "Input" }, + { 0x0002, "Output" }, + { 0x0003, "reserved" }, + /*0x0004 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_module_state[] = { + { 0x0000, "no module" }, + { 0x0001, "wrong module" }, + { 0x0002, "proper module" }, + { 0x0003, "substitute" }, + /*0x0004 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_arproperties_state[] = { + { 0x00000000, "Reserved" }, + { 0x00000001, "Active" }, + { 0x00000002, "reserved" }, + { 0x00000003, "reserved" }, + { 0x00000004, "reserved" }, + { 0x00000005, "reserved" }, + { 0x00000006, "reserved" }, + { 0x00000007, "reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_arproperties_supervisor_takeover_allowed[] = { + { 0x00000000, "not allowed" }, + { 0x00000001, "allowed" }, + { 0, NULL } +}; + +static const value_string pn_io_arproperties_parametrization_server[] = { + { 0x00000000, "External PrmServer" }, + { 0x00000001, "CM Initiator" }, + { 0, NULL } +}; +/* BIT 8 */ +static const value_string pn_io_arproperties_DeviceAccess[] = { + { 0x00000000, "Only the submodules from the ExpectedSubmoduleBlock are accessible" }, + { 0x00000001, "Submodule access is controlled by IO device application" }, + { 0, NULL } +}; + +/* Bit 9 - 10 */ +static const value_string pn_io_arproperties_companion_ar[] = { + { 0x00000000, "Single AR" }, + { 0x00000001, "First AR of a companion pair and a companion AR shall follow" }, + { 0x00000002, "Companion AR" }, + { 0x00000003, "Reserved" }, + { 0, NULL } +}; +/* REMOVED with 2.3 +static const value_string pn_io_arproperties_data_rate[] = { + { 0x00000000, "at least 100 MB/s or more" }, + { 0x00000001, "100 MB/s" }, + { 0x00000002, "1 GB/s" }, + { 0x00000003, "10 GB/s" }, + { 0, NULL } +}; +*/ + +/* BIT 11 */ +static const value_string pn_io_arproperties_acknowldege_companion_ar[] = { + { 0x00000000, "No companion AR or no acknowledge for the companion AR required" }, + { 0x00000001, "Companion AR with acknowledge" }, + { 0, NULL } +}; + +/* bit 29 for legacy startup mode*/ +static const value_string pn_io_arproperties_combined_object_container_with_legacy_startupmode[] = { + { 0x00000000, "CombinedObjectContainer not used" }, + { 0x00000001, "Reserved" }, + { 0, NULL } +}; + +/* bit 29 for advanced statup mode*/ +static const value_string pn_io_arproperties_combined_object_container_with_advanced_startupmode[] = { + { 0x00000000, "CombinedObjectContainer not used" }, + { 0x00000001, "Usage of CombinedObjectContainer required" }, + { 0, NULL } +}; + +/* bit 30 */ +static const value_string pn_io_arpropertiesStartupMode[] = { + { 0x00000000, "Legacy" }, + { 0x00000001, "Advanced" }, + { 0, NULL } +}; + +/* bit 31 */ +static const value_string pn_io_arproperties_pull_module_alarm_allowed[] = { + { 0x00000000, "AlarmType(=Pull) shall signal pulling of submodule and module" }, + { 0x00000001, "AlarmType(=Pull) shall signal pulling of submodule" }, + { 0, NULL } +}; + +static const value_string pn_io_RedundancyInfo[] = { + { 0x00000000, "Reserved" }, + { 0x00000001, "The delivering node is the left or below one" }, + { 0x00000002, "The delivering node is the right or above one" }, + { 0x00000003, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_iocr_properties_rtclass[] = { + { 0x00000000, "reserved" }, + { 0x00000001, "RT_CLASS_1" }, + { 0x00000002, "RT_CLASS_2" }, + { 0x00000003, "RT_CLASS_3" }, + { 0x00000004, "RT_CLASS_UDP" }, + /*0x00000005 - 0x00000007 reserved */ + { 0, NULL } +}; + +static const value_string pn_io_MultipleInterfaceMode_NameOfDevice[] = { + { 0x00000000, "PortID of LLDP contains name of port (Default)" }, + { 0x00000001, "PortID of LLDP contains name of port and NameOfStation" }, + { 0, NULL } +}; + +static const true_false_string tfs_pn_io_sr_properties_BackupAR_with_SRProperties_Mode_0 = + { "The device shall deliver valid input data", "The IO controller shall not evaluate the input data." }; + +static const true_false_string tfs_pn_io_sr_properties_BackupAR_with_SRProperties_Mode_1 = + { "The device shall deliver valid input data", "The IO device shall mark the data as invalid using APDU_Status.DataStatus.DataValid == Invalid." }; + +static const true_false_string tfs_pn_io_sr_properties_Mode = + { "Default The IO device shall use APDU_Status.DataStatus.DataValid == Invalid if input data is request as not valid.", + "The IO controller do not support APDU_Status.DataStatus.DataValid == Invalid if input data is request as not valid." }; + +static const true_false_string tfs_pn_io_sr_properties_Reserved1 = + { "Legacy mode", "Shall be set to zero for this standard." }; + +static const value_string pn_io_iocr_properties_media_redundancy[] = { + { 0x00000000, "No media redundant frame transfer" }, + { 0x00000001, "Media redundant frame transfer" }, + { 0, NULL } +}; + + +static const value_string pn_io_submodule_properties_type[] = { + { 0x0000, "no input and no output data" }, + { 0x0001, "input data" }, + { 0x0002, "output data" }, + { 0x0003, "input and output data" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_properties_shared_input[] = { + { 0x0000, "IO controller" }, + { 0x0001, "IO controller shared" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_properties_reduce_input_submodule_data_length[] = { + { 0x0000, "Expected" }, + { 0x0001, "Zero" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_properties_reduce_output_submodule_data_length[] = { + { 0x0000, "Expected" }, + { 0x0001, "Zero" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_properties_discard_ioxs[] = { + { 0x0000, "Expected" }, + { 0x0001, "Zero" }, + { 0, NULL } +}; + +static const value_string pn_io_alarmcr_properties_priority[] = { + { 0x0000, "user priority (default)" }, + { 0x0001, "use only low priority" }, + { 0, NULL } +}; + +static const value_string pn_io_alarmcr_properties_transport[] = { + { 0x0000, "RTA_CLASS_1" }, + { 0x0001, "RTA_CLASS_UDP" }, + { 0, NULL } +}; + + +static const value_string pn_io_submodule_state_format_indicator[] = { + { 0x0000, "Coding uses Detail" }, + { 0x0001, "Coding uses .IdentInfo, ..." }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_add_info[] = { + { 0x0000, "None" }, + { 0x0001, "Takeover not allowed" }, + /*0x0002 - 0x0007 reserved */ + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_qualified_info[] = { + { 0x0000, "No QualifiedInfo available" }, + { 0x0001, "QualifiedInfo available" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_maintenance_required[] = { + { 0x0000, "No MaintenanceRequired available" }, + { 0x0001, "MaintenanceRequired available" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_maintenance_demanded[] = { + { 0x0000, "No MaintenanceDemanded available" }, + { 0x0001, "MaintenanceDemanded available" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_diag_info[] = { + { 0x0000, "No DiagnosisData available" }, + { 0x0001, "DiagnosisData available" }, + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_ar_info[] = { + { 0x0000, "Own" }, + { 0x0001, "ApplicationReadyPending (ARP)" }, + { 0x0002, "Superordinated Locked (SO)" }, + { 0x0003, "Locked By IO Controller (IOC)" }, + { 0x0004, "Locked By IO Supervisor (IOS)" }, + /*0x0005 - 0x000F reserved */ + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_ident_info[] = { + { 0x0000, "OK" }, + { 0x0001, "Substitute (SU)" }, + { 0x0002, "Wrong (WR)" }, + { 0x0003, "NoSubmodule (NO)" }, + /*0x0004 - 0x000F reserved */ + { 0, NULL } +}; + +static const value_string pn_io_submodule_state_detail[] = { + { 0x0000, "no submodule" }, + { 0x0001, "wrong submodule" }, + { 0x0002, "locked by IO controller" }, + { 0x0003, "reserved" }, + { 0x0004, "application ready pending" }, + { 0x0005, "reserved" }, + { 0x0006, "reserved" }, + { 0x0007, "Substitute" }, + /*0x0008 - 0x7FFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_substitutionmode[] = { + { 0x0000, "ZERO" }, + { 0x0001, "Last value" }, + { 0x0002, "Replacement value" }, + /*0x0003 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_index[] = { + /*0x0008 - 0x7FFF user specific */ + + /* PROFISafe */ + { 0x0100, "PROFISafe" }, + + /* subslot specific */ + { 0x8000, "ExpectedIdentificationData for one subslot" }, + { 0x8001, "RealIdentificationData for one subslot" }, + /*0x8002 - 0x8009 reserved */ + { 0x800A, "Diagnosis in channel coding for one subslot" }, + { 0x800B, "Diagnosis in all codings for one subslot" }, + { 0x800C, "Diagnosis, Maintenance, Qualified and Status for one subslot" }, + /*0x800D - 0x800F reserved */ + { 0x8010, "Maintenance required in channel coding for one subslot" }, + { 0x8011, "Maintenance demanded in channel coding for one subslot" }, + { 0x8012, "Maintenance required in all codings for one subslot" }, + { 0x8013, "Maintenance demanded in all codings for one subslot" }, + /*0x8014 - 0x801D reserved */ + { 0x801E, "SubstituteValues for one subslot" }, + /*0x801F - 0x8027 reserved */ + { 0x8028, "RecordInputDataObjectElement for one subslot" }, + { 0x8029, "RecordOutputDataObjectElement for one subslot" }, + { 0x802A, "PDPortDataReal for one subslot" }, + { 0x802B, "PDPortDataCheck for one subslot" }, + { 0x802C, "PDIRData for one subslot" }, + { 0x802D, "Expected PDSyncData for one subslot with SyncID value 0" }, + /*0x802E reserved */ + { 0x802F, "PDPortDataAdjust for one subslot" }, + { 0x8030, "IsochronousModeData for one subslot" }, + { 0x8031, "Expected PDSyncData for one subslot with SyncID value 1" }, + { 0x8032, "Expected PDSyncData for one subslot with SyncID value 2" }, + { 0x8033, "Expected PDSyncData for one subslot with SyncID value 3" }, + { 0x8034, "Expected PDSyncData for one subslot with SyncID value 4" }, + { 0x8035, "Expected PDSyncData for one subslot with SyncID value 5" }, + { 0x8036, "Expected PDSyncData for one subslot with SyncID value 6" }, + { 0x8037, "Expected PDSyncData for one subslot with SyncID value 7" }, + { 0x8038, "Expected PDSyncData for one subslot with SyncID value 8" }, + { 0x8039, "Expected PDSyncData for one subslot with SyncID value 9" }, + { 0x803A, "Expected PDSyncData for one subslot with SyncID value 10" }, + { 0x803B, "Expected PDSyncData for one subslot with SyncID value 11" }, + { 0x803C, "Expected PDSyncData for one subslot with SyncID value 12" }, + { 0x803D, "Expected PDSyncData for one subslot with SyncID value 13" }, + { 0x803E, "Expected PDSyncData for one subslot with SyncID value 14" }, + { 0x803F, "Expected PDSyncData for one subslot with SyncID value 15" }, + { 0x8040, "Expected PDSyncData for one subslot with SyncID value 16" }, + { 0x8041, "Expected PDSyncData for one subslot with SyncID value 17" }, + { 0x8042, "Expected PDSyncData for one subslot with SyncID value 18" }, + { 0x8043, "Expected PDSyncData for one subslot with SyncID value 19" }, + { 0x8044, "Expected PDSyncData for one subslot with SyncID value 20" }, + { 0x8045, "Expected PDSyncData for one subslot with SyncID value 21" }, + { 0x8046, "Expected PDSyncData for one subslot with SyncID value 22" }, + { 0x8047, "Expected PDSyncData for one subslot with SyncID value 23" }, + { 0x8048, "Expected PDSyncData for one subslot with SyncID value 24" }, + { 0x8049, "Expected PDSyncData for one subslot with SyncID value 25" }, + { 0x804A, "Expected PDSyncData for one subslot with SyncID value 26" }, + { 0x804B, "Expected PDSyncData for one subslot with SyncID value 27" }, + { 0x804C, "Expected PDSyncData for one subslot with SyncID value 28" }, + { 0x804D, "Expected PDSyncData for one subslot with SyncID value 29" }, + { 0x804E, "Expected PDSyncData for one subslot with SyncID value 30" }, + { 0x804F, "Expected PDSyncData for one subslot with SyncID value 31" }, + { 0x8050, "PDInterfaceMrpDataReal for one subslot" }, + { 0x8051, "PDInterfaceMrpDataCheck for one subslot" }, + { 0x8052, "PDInterfaceMrpDataAdjust for one subslot" }, + { 0x8053, "PDPortMrpDataAdjust for one subslot" }, + { 0x8054, "PDPortMrpDataReal for one subslot" }, + /*0x8055 - 0x805F reserved */ + { 0x8060, "PDPortFODataReal for one subslot" }, + { 0x8061, "PDPortFODataCheck for one subslot" }, + { 0x8062, "PDPortFODataAdjust for one subslot" }, + /*0x8063 - 0x806F reserved */ + { 0x8070, "PDNCDataCheck for one subslot" }, + { 0x8071, "PDInterfaceAdjust for one subslot" }, + { 0x8072, "PDPortStatistic for one subslot" }, + /*0x8071 - 0x807F reserved */ + { 0x8080, "PDInterfaceDataReal" }, + /*0x8081 - 0x808F reserved */ + { 0x8090, "Expected PDInterfaceFSUDataAdjust" }, + /*0x8091 - 0xAFEF reserved except 0x80B0*/ + { 0x80B0, "CombinedObjectContainer" }, + { 0x80CF, "RS_AdjustObserver" }, + { 0xAFF0, "I&M0" }, + { 0xAFF1, "I&M1" }, + { 0xAFF2, "I&M2" }, + { 0xAFF3, "I&M3" }, + { 0xAFF4, "I&M4" }, + { 0xAFF5, "I&M5" }, + { 0xAFF6, "I&M6" }, + { 0xAFF7, "I&M7" }, + { 0xAFF8, "I&M8" }, + { 0xAFF9, "I&M9" }, + { 0xAFFA, "I&M10" }, + { 0xAFFB, "I&M11" }, + { 0xAFFC, "I&M12" }, + { 0xAFFD, "I&M13" }, + { 0xAFFE, "I&M14" }, + { 0xAFFF, "I&M15" }, + /*0xB000 - 0xB02D reserved for profiles */ + { 0xB000, "Sync-Log / RTA SyncID 0 (GSY)" }, + { 0xB001, "Sync-Log / RTA SyncID 1 (GSY)" }, + { 0xB002, "reserved for profiles" }, + { 0xB003, "reserved for profiles" }, + { 0xB004, "reserved for profiles" }, + { 0xB005, "reserved for profiles" }, + { 0xB006, "reserved for profiles" }, + { 0xB007, "reserved for profiles" }, + { 0xB008, "reserved for profiles" }, + { 0xB009, "reserved for profiles" }, + { 0xB00A, "reserved for profiles" }, + { 0xB00B, "reserved for profiles" }, + { 0xB00C, "reserved for profiles" }, + { 0xB00D, "reserved for profiles" }, + { 0xB00E, "reserved for profiles" }, + { 0xB00F, "reserved for profiles" }, + { 0xB010, "reserved for profiles" }, + { 0xB011, "reserved for profiles" }, + { 0xB012, "reserved for profiles" }, + { 0xB013, "reserved for profiles" }, + { 0xB014, "reserved for profiles" }, + { 0xB015, "reserved for profiles" }, + { 0xB016, "reserved for profiles" }, + { 0xB017, "reserved for profiles" }, + { 0xB018, "reserved for profiles" }, + { 0xB019, "reserved for profiles" }, + { 0xB01A, "reserved for profiles" }, + { 0xB01B, "reserved for profiles" }, + { 0xB01C, "reserved for profiles" }, + { 0xB01D, "reserved for profiles" }, + { 0xB01E, "reserved for profiles" }, + { 0xB01F, "reserved for profiles" }, + { 0xB020, "reserved for profiles" }, + { 0xB021, "reserved for profiles" }, + { 0xB022, "reserved for profiles" }, + { 0xB023, "reserved for profiles" }, + { 0xB024, "reserved for profiles" }, + { 0xB025, "reserved for profiles" }, + { 0xB026, "reserved for profiles" }, + { 0xB027, "reserved for profiles" }, + { 0xB028, "reserved for profiles" }, + { 0xB029, "reserved for profiles" }, + { 0xB02A, "reserved for profiles" }, + { 0xB02B, "reserved for profiles" }, + { 0xB02C, "reserved for profiles" }, + { 0xB02D, "reserved for profiles" }, + /* PROFIDrive */ + { 0xB02E, "PROFIDrive Parameter Access - Local"}, + { 0xB02F, "PROFIDrive Parameter Access - Global"}, + + /*0xB030 - 0xBFFF reserved for profiles */ + { 0xB050, "Ext-PLL Control / RTC+RTA SyncID 0 (EDD)" }, + { 0xB051, "Ext-PLL Control / RTA SyncID 1 (GSY)" }, + + { 0xB060, "EDD Trace Unit (EDD" }, + { 0xB061, "EDD Trace Unit (EDD" }, + + { 0xB070, "OHA Info (OHA)" }, + + + /* slot specific */ + { 0xC000, "ExpectedIdentificationData for one slot" }, + { 0xC001, "RealIdentificationData for one slot" }, + /*0xC002 - 0xC009 reserved */ + { 0xC00A, "Diagnosis in channel coding for one slot" }, + { 0xC00B, "Diagnosis in all codings for one slot" }, + { 0xC00C, "Diagnosis, Maintenance, Qualified and Status for one slot" }, + /*0xC00D - 0xC00F reserved */ + { 0xC010, "Maintenance required in channel coding for one slot" }, + { 0xC011, "Maintenance demanded in channel coding for one slot" }, + { 0xC012, "Maintenance required in all codings for one slot" }, + { 0xC013, "Maintenance demanded in all codings for one slot" }, + /*0xC014 - 0xCFFF reserved */ + /*0xD000 - 0xDFFF reserved for profiles */ + + /* AR specific */ + { 0xE000, "ExpectedIdentificationData for one AR" }, + { 0xE001, "RealIdentificationData for one AR" }, + { 0xE002, "ModuleDiffBlock for one AR" }, + /*0xE003 - 0xE009 reserved */ + { 0xE00A, "Diagnosis in channel coding for one AR" }, + { 0xE00B, "Diagnosis in all codings for one AR" }, + { 0xE00C, "Diagnosis, Maintenance, Qualified and Status for one AR" }, + /*0xE00D - 0xE00F reserved */ + { 0xE010, "Maintenance required in channel coding for one AR" }, + { 0xE011, "Maintenance demanded in channel coding for one AR" }, + { 0xE012, "Maintenance required in all codings for one AR" }, + { 0xE013, "Maintenance demanded in all codings for one AR" }, + /*0xE014 - 0xE02F reserved */ + { 0xE030, "IsochronousModeData for one AR" }, + /*0xE031 - 0xE03F reserved */ + { 0xE040, "MultipleWrite" }, + /*0xE041 - 0xE04F reserved */ + { 0xE050, "ARFSUDataAdjust data for one AR" }, + /*0xE051 - 0xE05F reserved */ + { 0xE060, "RS_GetEvent (using RecordDataRead service)" }, + { 0xE061, "RS_AckEvent (using RecordDataWrite service)" }, + /*0xEC00 - 0xEFFF reserved */ + + /* API specific */ + { 0xF000, "RealIdentificationData for one API" }, + /*0xF001 - 0xF009 reserved */ + { 0xF00A, "Diagnosis in channel coding for one API" }, + { 0xF00B, "Diagnosis in all codings for one API" }, + { 0xF00C, "Diagnosis, Maintenance, Qualified and Status for one API" }, + /*0xF00D - 0xF00F reserved */ + { 0xF010, "Maintenance required in channel coding for one API" }, + { 0xF011, "Maintenance demanded in channel coding for one API" }, + { 0xF012, "Maintenance required in all codings for one API" }, + { 0xF013, "Maintenance demanded in all codings for one API" }, + /*0xF014 - 0xF01F reserved */ + { 0xF020, "ARData for one API" }, + /*0xF021 - 0xF3FF reserved */ + /*0xF400 - 0xF7FF reserved */ + + /* device specific */ + /*0xF800 - 0xF80B reserved */ + { 0xF80C, "Diagnosis, Maintenance, Qualified and Status for one device" }, + /*0xF80D - 0xF81F reserved */ + { 0xF820, "ARData" }, + { 0xF821, "APIData" }, + /*0xF822 - 0xF82F reserved */ + { 0xF830, "LogData" }, + { 0xF831, "PDevData" }, + /*0xF832 - 0xF83F reserved */ + { 0xF840, "I&M0FilterData" }, + { 0xF841, "PDRealData" }, + { 0xF842, "PDExpectedData" }, + /*0xF843 - 0xF84F reserved */ + { 0xF850, "AutoConfigurarion" }, + { 0xF880, "AssetManagementData" }, + /*0xF851 - 0xFBFF reserved */ + /*0xFC00 - 0xFFFF reserved for profiles */ + { 0, NULL } +}; + +static const value_string pn_io_user_structure_identifier[] = { + /*0x0000 - 0x7FFF manufacturer specific */ + { 0x8000, "ChannelDiagnosis" }, + { 0x8001, "Multiple" }, + { 0x8002, "ExtChannelDiagnosis" }, + { 0x8003, "QualifiedChannelDiagnosis" }, + /*0x8004 - 0x80FF reserved */ + { 0x8100, "Maintenance" }, + /*0x8101 - 0x8FFF reserved except 8300, 8301, 8302, 8303 */ + { 0x8300, "Sequence of events RS_LowWatermark" }, + { 0x8301, "Sequence of events RS_Timeout" }, + { 0x8302, "Sequence of events RS_Overflow" }, + { 0x8303, "Sequence of events RS_Event" }, + /*0x9000 - 0x9FFF reserved for profiles */ + /*0xA000 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_channel_error_type[] = { + { 0x0000, "reserved" }, + { 0x0001, "short circuit" }, + { 0x0002, "Undervoltage" }, + { 0x0003, "Overvoltage" }, + { 0x0004, "Overload" }, + { 0x0005, "Overtemperature" }, + { 0x0006, "line break" }, + { 0x0007, "upper limit value exceeded" }, + { 0x0008, "lower limit value exceeded" }, + { 0x0009, "Error" }, + /*0x000A - 0x000F reserved */ + { 0x0010, "parametrization fault" }, + { 0x0011, "power supply fault" }, + { 0x0012, "fuse blown / open" }, + { 0x0013, "Manufacturer specific" }, + { 0x0014, "ground fault" }, + { 0x0015, "reference point lost" }, + { 0x0016, "process event lost / sampling error" }, + { 0x0017, "threshold warning" }, + { 0x0018, "output disabled" }, + { 0x0019, "safety event" }, + { 0x001A, "external fault" }, + /*0x001B - 0x001F manufacturer specific */ + /*0x0020 - 0x00FF reserved for common profiles */ + /*0x0100 - 0x7FFF manufacturer specific */ + { 0x8000, "Data transmission impossible" }, + { 0x8001, "Remote mismatch" }, + { 0x8002, "Media redundancy mismatch" }, + { 0x8003, "Sync mismatch" }, + { 0x8004, "IsochronousMode mismatch" }, + { 0x8005, "Multicast CR mismatch" }, + { 0x8006, "reserved" }, + { 0x8007, "Fiber optic mismatch" }, + { 0x8008, "Network component function mismatch" }, + { 0x8009, "Time mismatch" }, + /* added values for IEC version 2.3: */ + { 0x800A, "Dynamic frame packing function mismatch" }, + { 0x800B, "Media redundancy with planned duplication mismatch"}, + { 0x800C, "System redundancy mismatch"}, + /* ends */ + /*0x800D - 0x8FFF reserved */ + /*0x9000 - 0x9FFF reserved for profile */ + /*0xA000 - 0xFFFF reserved */ + { 0, NULL } +}; + /* ExtChannelErrorType for ChannelErrorType 0 - 0x7FFF */ + +static const value_string pn_io_ext_channel_error_type0[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Accumulative Info"}, + /* 0x8001 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + + /* ExtChannelErrorType for ChannelErrorType "Data transmission impossible" */ +static const value_string pn_io_ext_channel_error_type0x8000[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Link State mismatch - Link down"}, + { 0x8001, "MAUType mismatch"}, + { 0x8002, "Line Delay mismatch"}, + /* 0x8003 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Remote mismatch" */ +static const value_string pn_io_ext_channel_error_type0x8001[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Peer Chassis ID mismatch"}, + { 0x8001, "Peer Port ID mismatch"}, + { 0x8002, "Peer RT_CLASS_3 mismatch a"}, + { 0x8003, "Peer MAUType mismatch"}, + { 0x8004, "Peer MRP domain mismatch"}, + { 0x8005, "No peer detected"}, + { 0x8006, "Reserved"}, + { 0x8007, "Peer Line Delay mismatch"}, + { 0x8008, "Peer PTCP mismatch b"}, + { 0x8009, "Peer Preamble Length mismatch"}, + { 0x800A, "Peer Fragmentation mismatch"}, + /* 0x800B - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Media redundancy mismatch" 0x8002 */ +static const value_string pn_io_ext_channel_error_type0x8002[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Manager role fail MRP-instance 1"}, + { 0x8001, "MRP-instance 1 ring open"}, + { 0x8002, "Reserved"}, + { 0x8003, "Multiple manager MRP-instance 1"}, + { 0x8010, "Manager role fail MRP-instance 2"}, + { 0x8011, "MRP-instance 2 ring open"}, + { 0x8012, "Reserved"}, + { 0x8013, "Multiple manager MRP-instance 2"}, + { 0x8020, "Manager role fail MRP-instance 3"}, + { 0x8021, "MRP-instance 3 ring open"}, + { 0x8023, "Multiple manager MRP-instance 3"}, + { 0x8030, "Manager role fail MRP-instance 4"}, + { 0x8031, "MRP-instance 4 ring open"}, + { 0x8033, "Multiple manager MRP-instance 4"}, + { 0x8040, "Manager role fail MRP-instance 5"}, + { 0x8041, "MRP-instance 5 ring open"}, + { 0x8043, "Multiple manager MRP-instance 5"}, + { 0x8050, "Manager role fail MRP-instance 6"}, + { 0x8051, "MRP-instance 6 ring open"}, + { 0x8053, "Multiple manager MRP-instance 6"}, + { 0x8060, "Manager role fail MRP-instance 7"}, + { 0x8061, "MRP-instance 7 ring open"}, + { 0x8063, "Multiple manager MRP-instance 7"}, + { 0x8070, "Manager role fail MRP-instance 8"}, + { 0x8071, "MRP-instance 8 ring open"}, + { 0x8073, "Multiple manager MRP-instance 8"}, + { 0x8080, "Manager role fail MRP-instance 9"}, + { 0x8081, "MRP-instance 9 ring open"}, + { 0x8083, "Multiple manager MRP-instance 9"}, + { 0x8090, "Manager role fail MRP-instance 10"}, + { 0x8091, "MRP-instance 10 ring open"}, + { 0x8093, "Multiple manager MRP-instance 10"}, + { 0x80A0, "Manager role fail MRP-instance 11"}, + { 0x80A1, "MRP-instance 11 ring open"}, + { 0x80A3, "Multiple manager MRP-instance 11"}, + { 0x80B0, "Manager role fail MRP-instance 12"}, + { 0x80B1, "MRP-instance 12 ring open"}, + { 0x80B3, "Multiple manager MRP-instance 12"}, + { 0x80C0, "Manager role fail MRP-instance 13"}, + { 0x80C1, "MRP-instance 13 ring open"}, + { 0x80C3, "Multiple manager MRP-instance 13"}, + { 0x80D0, "Manager role fail MRP-instance 14"}, + { 0x80D1, "MRP-instance 14 ring open"}, + { 0x80D3, "Multiple manager MRP-instance 14"}, + { 0x80E0, "Manager role fail MRP-instance 15"}, + { 0x80E1, "MRP-instance 15 ring open"}, + { 0x80E3, "Multiple manager MRP-instance 15"}, + { 0x80F0, "Manager role fail MRP-instance 16"}, + { 0x80F1, "MRP-instance 16 ring open"}, + { 0x80F3, "Multiple manager MRP-instance 16"}, + /* 0x8004 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Sync mismatch" and for ChannelErrorType "Time mismatch" 0x8003 and 0x8009*/ +static const value_string pn_io_ext_channel_error_type0x8003[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "No sync message received"}, + { 0x8001, "- 0x8002 Reserved"}, + { 0x8003, "Jitter out of boundary"}, + /* 0x8004 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /*ExtChannelErrorType for ChannelErrorType "Isochronous mode mismatch" 0x8004 */ +static const value_string pn_io_ext_channel_error_type0x8004[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Output Time Failure - Output update missing or out of order"}, + { 0x8001, "Input Time Failure"}, + { 0x8002, "Master Life Sign Failure - Error in MLS update detected"}, + /* 0x8003 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Multicast CR mismatch" 0x8005 */ +static const value_string pn_io_ext_channel_error_type0x8005[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Multicast Consumer CR timed out"}, + { 0x8001, "Address resolution failed"}, + /* 0x8002 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Fiber optic mismatch" 0x8007*/ +static const value_string pn_io_ext_channel_error_type0x8007[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Power Budget"}, + /* 0x8001 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Network component function mismatch" 0x8008 */ +static const value_string pn_io_ext_channel_error_type0x8008[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "Frame dropped - no resource"}, + /* 0x8001 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Dynamic Frame Packing function mismatch" 0x800A */ +static const value_string pn_io_ext_channel_error_type0x800A[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + /* 0x8000 - 0x80FF Reserved */ + { 0x8100, "Frame late error for FrameID (0x0100)"}, + /* 0x8101 + 0x8FFE See Equation (56) */ + { 0x8FFF, "Frame late error for FrameID (0x0FFF)"}, + /* 0x8001 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "Media redundancy with planned duplication mismatch" 0x800B */ +static const value_string pn_io_ext_channel_error_type0x800B[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + /* 0x8000 - 0x86FF Reserved */ + { 0x8700, "MRPD duplication void for FrameID (0x0700)"}, + /* 0x8701 + 0x8FFE See Equation (57) */ + { 0x8FFF, "MRPD duplication void for FrameID (0x0FFF)"}, + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + + /* ExtChannelErrorType for ChannelErrorType "System redundancy mismatch" 0x800C */ +static const value_string pn_io_ext_channel_error_type0x800C[] = { + /* 0x0000 Reserved */ + /* 0x0001 - 0x7FFF Manufacturer specific */ + { 0x8000, "System redundancy event"}, + /* 0x8001 - 0x8FFF Reserved */ + /* 0x9000 - 0x9FFF Reserved for profiles */ + /* 0xA000 - 0xFFFF Reserved */ + { 0, NULL } +}; + +static const value_string pn_io_channel_properties_type[] = { + { 0x0000, "submodule or unspecified" }, + { 0x0001, "1 Bit" }, + { 0x0002, "2 Bit" }, + { 0x0003, "4 Bit" }, + { 0x0004, "8 Bit" }, + { 0x0005, "16 Bit" }, + { 0x0006, "32 Bit" }, + { 0x0007, "64 Bit" }, + /*0x0008 - 0x00FF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_channel_properties_accumulative_vals[] = { + { 0x0000, "Channel" }, + { 0x0001, "ChannelGroup" }, + { 0, NULL } +}; + +/* We are reading this as a two bit value, but the spec specifies each bit + * separately. Beware endianness when reading spec + */ +static const value_string pn_io_channel_properties_maintenance[] = { + { 0x0000, "Failure" }, + { 0x0001, "Maintenance required" }, + { 0x0002, "Maintenance demanded" }, + { 0x0003, "see QualifiedChannelQualifier" }, + { 0, NULL } +}; + +static const value_string pn_io_channel_properties_specifier[] = { + { 0x0000, "All subsequent disappears" }, + { 0x0001, "Appears" }, + { 0x0002, "Disappears" }, + { 0x0003, "Disappears but others remain" }, + { 0, NULL } +}; + +static const value_string pn_io_channel_properties_direction[] = { + { 0x0000, "Manufacturer-specific" }, + { 0x0001, "Input" }, + { 0x0002, "Output" }, + { 0x0003, "Input/Output" }, + /*0x0004 - 0x0007 reserved */ + { 0, NULL } +}; + +static const value_string pn_io_alarmcr_type[] = { + { 0x0000, "reserved" }, + { 0x0001, "Alarm CR" }, + /*0x0002 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_mau_type[] = { + /*0x0000 - 0x0004 reserved */ + { 0x0005, "10BASET" }, + /*0x0006 - 0x0009 reserved */ + { 0x000A, "10BASETXHD" }, + { 0x000B, "10BASETXFD" }, + { 0x000C, "10BASEFLHD" }, + { 0x000D, "10BASEFLFD" }, + { 0x000F, "100BASETXHD" }, + { 0x0010, "100BASETXFD" }, + { 0x0011, "100BASEFXHD" }, + { 0x0012, "100BASEFXFD" }, + /*0x0013 - 0x0014 reserved */ + { 0x0015, "1000BASEXHD" }, + { 0x0016, "1000BASEXFD" }, + { 0x0017, "1000BASELXHD" }, + { 0x0018, "1000BASELXFD" }, + { 0x0019, "1000BASESXHD" }, + { 0x001A, "1000BASESXFD" }, + /*0x001B - 0x001C reserved */ + { 0x001D, "1000BASETHD" }, + { 0x001E, "1000BASETFD" }, + { 0x001F, "10GigBASEFX" }, + /*0x0020 - 0x002D reserved */ + { 0x002E, "100BASELX10" }, + /*0x002F - 0x0035 reserved */ + { 0x0036, "100BASEPXFD" }, + /*0x0037 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_preamble_length[] = { + { 0x0000, "Seven octets Preamble shall be used" }, + { 0x0001, "One octet Preamble shall be used" }, + /*0x0002 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_mau_type_mode[] = { + { 0x0000, "OFF" }, + { 0x0001, "ON" }, + /*0x0002 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_dcp_boundary_value_bit0[] = { + { 0x00, "Do not block the multicast MAC address 01-0E-CF-00-00-00" }, + { 0x01, "Block an outgoing DCP_Identify frame (egress filter) with the multicast MAC address 01-0E-CF-00-00-00" }, + { 0, NULL } +}; + +static const value_string pn_io_dcp_boundary_value_bit1[] = { + { 0x00, "Do not block the multicast MAC address 01-0E-CF-00-00-01" }, + { 0x01, "Block an outgoing DCP_Hello frame (egress filter) with the multicast MAC address 01-0E-CF-00-00-01" }, + { 0, NULL } +}; + +static const value_string pn_io_peer_to_peer_boundary_value_bit0[] = { + { 0x00, "The LLDP agent shall send LLDP frames for this port." }, + { 0x01, "The LLDP agent shall not send LLDP frames (egress filter)." }, + { 0, NULL } +}; + +static const value_string pn_io_peer_to_peer_boundary_value_bit1[] = { + { 0x00, "The PTCP ASE shall send PTCP_DELAY request frames for this port." }, + { 0x01, "The PTCP ASE shall not send PTCP_DELAY request frames (egress filter)." }, + { 0, NULL } +}; + +static const value_string pn_io_peer_to_peer_boundary_value_bit2[] = { + { 0x00, "The Time ASE shall send PATH_DELAY request frames for this port." }, + { 0x01, "The Time ASE shall not send PATH_DELAY request frames (egress filter)." }, + { 0, NULL } +}; + +static const range_string pn_io_mau_type_extension[] = { + { 0x0000, 0x0000, "No SubMAUType" }, + { 0x0001, 0x00FF, "Reserved" }, + { 0x0100, 0x0100, "POF" }, + { 0x0101, 0xFFEF, "Reserved for SubMAUType" }, + { 0xFFF0, 0xFFFF, "Reserved" }, + { 0, 0, NULL } +}; + + +static const value_string pn_io_port_state[] = { + { 0x0000, "reserved" }, + { 0x0001, "up" }, + { 0x0002, "down" }, + { 0x0003, "testing" }, + { 0x0004, "unknown" }, + /*0x0005 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_media_type[] = { + { 0x0000, "Unknown" }, + { 0x0001, "Copper cable" }, + { 0x0002, "Fiber optic cable" }, + { 0x0003, "Radio communication" }, + /*0x0004 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_fiber_optic_type[] = { + { 0x0000, "No fiber type adjusted" }, + { 0x0001, "9 um single mode fiber" }, + { 0x0002, "50 um multi mode fiber" }, + { 0x0003, "62,5 um multi mode fiber" }, + { 0x0004, "SI-POF, NA=0.5" }, + { 0x0005, "SI-PCF, NA=0.36" }, + { 0x0006, "LowNA-POF, NA=0.3" }, + { 0x0007, "GI-POF" }, + /*0x0008 - 0xFFFF reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_fiber_optic_cable_type[] = { + { 0x0000, "No cable specified" }, + { 0x0001, "Inside/outside cable, fixed installation" }, + { 0x0002, "Inside/outside cable, flexible installation" }, + { 0x0003, "Outdoor cable, fixed installation" }, + /*0x0004 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_im_revision_prefix_vals[] = { + { 'V', "V - Officially released version" }, + { 'R', "R - Revision" }, + { 'P', "P - Prototype" }, + { 'U', "U - Under Test (Field Test)" }, + { 'T', "T - Test Device" }, + /*all others reserved */ + { 0, NULL } +}; + + +static const value_string pn_io_mrp_role_vals[] = { + { 0x0000, "Media Redundancy disabled" }, + { 0x0001, "Media Redundancy Client" }, + { 0x0002, "Media Redundancy Manager" }, + /*all others reserved */ + { 0, NULL } +}; + +static const value_string pn_io_mrp_instance_no[] = { + { 0x0000, "MRP_Instance 1" }, + { 0x0001, "MRP_Instance 2" }, + { 0x0002, "MRP_Instance 3" }, + { 0x0003, "MRP_Instance 4" }, + { 0x0004, "MRP_Instance 5" }, + { 0x0005, "MRP_Instance 6" }, + { 0x0006, "MRP_Instance 7" }, + { 0x0007, "MRP_Instance 8" }, + { 0x0008, "MRP_Instance 9" }, + { 0x0009, "MRP_Instance 10" }, + { 0x000A, "MRP_Instance 11" }, + { 0x000B, "MRP_Instance 12" }, + { 0x000C, "MRP_Instance 13" }, + { 0x000D, "MRP_Instance 14" }, + { 0x000E, "MRP_Instance 15" }, + { 0x000F, "MRP_Instance 16" }, + /*all others reserved */ + { 0, NULL } +}; + +static const value_string pn_io_mrp_mrm_on[] = { + { 0x0000, "Disable MediaRedundancyManager diagnosis" }, + { 0x0001, "Enable MediaRedundancyManager diagnosis"}, + { 0, NULL } +}; +static const value_string pn_io_mrp_checkUUID[] = { + { 0x0000, "Disable the check of the MRP_DomainUUID" }, + { 0x0001, "Enable the check of the MRP_DomainUUID"}, + { 0, NULL } +}; + +static const value_string pn_io_mrp_prio_vals[] = { + { 0x0000, "Highest priority redundancy manager" }, + /* 0x1000 - 0x7000 High priorities */ + { 0x8000, "Default priority for redundancy manager" }, + /* 0x9000 - 0xE000 Low priorities */ + { 0xF000, "Lowest priority redundancy manager" }, + /*all others reserved */ + { 0, NULL } +}; + +static const value_string pn_io_mrp_rtmode_rtclass12_vals[] = { + { 0x0000, "RT_CLASS_1 and RT_CLASS_2 redundancy mode deactivated" }, + { 0x0001, "RT_CLASS_1 and RT_CLASS_2 redundancy mode activated" }, + { 0, NULL } +}; + +static const value_string pn_io_mrp_rtmode_rtclass3_vals[] = { + { 0x0000, "RT_CLASS_3 redundancy mode deactivated" }, + { 0x0001, "RT_CLASS_3 redundancy mode activated" }, + { 0, NULL } +}; + +static const value_string pn_io_mrp_ring_state_vals[] = { + { 0x0000, "Ring open" }, + { 0x0001, "Ring closed" }, + { 0, NULL } +}; + +static const value_string pn_io_mrp_rt_state_vals[] = { + { 0x0000, "RT media redundancy lost" }, + { 0x0001, "RT media redundancy available" }, + { 0, NULL } +}; + +static const value_string pn_io_control_properties_vals[] = { + { 0x0000, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_control_properties_prmbegin_vals[] = { + { 0x0000, "No PrmBegin" }, + { 0x0001, "The IO controller starts the transmisson of the stored start-up parameter" }, + { 0, NULL } +}; +static const value_string pn_io_control_properties_application_ready_vals[] = { + { 0x0000, "Wait for explicit ControlCommand.ReadyForCompanion" }, + { 0x0001, "Implicit ControlCommand.ReadyForCompanion" }, + { 0, NULL } +}; + +static const value_string pn_io_fs_hello_mode_vals[] = { + { 0x0000, "OFF" }, + { 0x0001, "Send req on LinkUp" }, + { 0x0002, "Send req on LinkUp after HelloDelay" }, + { 0, NULL } +}; + +static const value_string pn_io_fs_parameter_mode_vals[] = { + { 0x0000, "OFF" }, + { 0x0001, "ON" }, + { 0x0002, "Reserved" }, + { 0x0003, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_frame_details_sync_master_vals[] = { + { 0x0000, "No Sync Frame" }, + { 0x0001, "Primary sync frame" }, + { 0x0002, "Secondary sync frame" }, + { 0x0003, "Reserved" }, + { 0, NULL } +}; +static const value_string pn_io_frame_details_meaning_frame_send_offset_vals[] = { + { 0x0000, "Field FrameSendOffset specifies the point of time for receiving or transmitting a frame " }, + { 0x0001, "Field FrameSendOffset specifies the beginning of the RT_CLASS_3 interval within a phase" }, + { 0x0002, "Field FrameSendOffset specifies the ending of the RT_CLASS_3 interval within a phase" }, + { 0x0003, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_f_check_seqnr[] = { + { 0x00, "consecutive number not included in crc" }, + { 0x01, "consecutive number included in crc" }, + { 0, NULL } +}; + +static const value_string pn_io_f_check_ipar[] = { + { 0x00, "no check" }, + { 0x01, "check" }, + { 0, NULL } +}; + +static const value_string pn_io_f_sil[] = { + { 0x00, "SIL1" }, + { 0x01, "SIL2" }, + { 0x02, "SIL3" }, + { 0x03, "NoSIL" }, + { 0, NULL } +}; + +static const value_string pn_io_f_crc_len[] = { + { 0x00, "3 octet CRC" }, + { 0x01, "2 octet CRC" }, + { 0x02, "4 octet CRC" }, + { 0x03, "reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_f_crc_seed[] = { + { 0x00, "CRC-FP as seed value and counter" }, + { 0x01, "'1' as seed value and CRC-FP+/MNR" }, + { 0, NULL } +}; + +/* F_Block_ID dissection due to ver2.6 specifikation of PI */ +static const value_string pn_io_f_block_id[] = { + { 0x00, "No F_WD_Time_2, no F_iPar_CRC" }, + { 0x01, "No F_WD_Time_2, F_iPar_CRC" }, + { 0x02, "F_WD_Time_2, no F_iPar_CRC" }, + { 0x03, "F_WD_Time_2, F_iPar_CRC" }, + /* 0x04..0x07 reserved */ + /* { 0x00, "Parameter set for F-Host/F-Device relationship" }, */ + /* { 0x01, "Additional F_Address parameter block" }, */ + /* 0x02..0x07 reserved */ + { 0, NULL } +}; + +static const value_string pn_io_f_par_version[] = { + { 0x00, "Valid for V1-mode" }, + { 0x01, "Valid for V2-mode" }, + /* 0x02..0x03 reserved */ + { 0, NULL } +}; + +static const value_string pn_io_profidrive_request_id_vals[] = { + { 0x00, "Reserved" }, + { 0x01, "Read request" }, + { 0x02, "Change request" }, + { 0, NULL } +}; + +static const value_string pn_io_profidrive_response_id_vals[] = { + { 0x00, "Reserved" }, + { 0x01, "Positive read response" }, + { 0x02, "Positive change response" }, + { 0x81, "Negative read response" }, + { 0x82, "Negative change response" }, + { 0, NULL } +}; + +static const value_string pn_io_profidrive_attribute_vals[] = { + { 0x00, "Reserved" }, + { 0x10, "Value" }, + { 0x20, "Description" }, + { 0x30, "Text" }, + { 0, NULL } +}; + +static const value_string pn_io_profidrive_format_vals[] = { + {0x01, "Boolean" }, + {0x02, "Integer8" }, + {0x03, "Integer16" }, + {0x04, "Integer32" }, + {0x05, "Unsigned8" }, + {0x06, "Unsigned16" }, + {0x07, "Unsigned32" }, + {0x08, "Float32" }, + {0x09, "VisibleString" }, + {0x0A, "OctetString" }, + {0x0C, "TimeOfDay" }, + {0x0D, "TimeDifference" }, + {0x32, "Date" }, + {0x34, "TimeOfDay" }, + {0x35, "TimeDifference" }, + {0x36, "TimeDifference" }, + { 0, NULL } +}; + +static const range_string pn_io_rs_block_type[] = { + /* Following ranges are used for events */ + { 0x0000, 0x0000, "reserved" }, + { 0x0001, 0x3FFF, "Manufacturer specific" }, + { 0x4000, 0x4000, "Stop observer - Observer Status Observer" }, + { 0x4001, 0x4001, "Buffer observer - RS_BufferObserver" }, + { 0x4002, 0x4002, "Time status observer - RS_TimeStatus" }, + { 0x4003, 0x4003, "System redundancy layer observer - RS_SRLObserver" }, + { 0x4004, 0x4004, "Source identification observer - RS_SourceIdentification" }, + { 0x4005, 0x400F, "reserved" }, + { 0x4010, 0x4010, "Digital input observer - SoE_DigitalInputObserver" }, + { 0x4011, 0x6FFF, "Reserved for normative usage" }, + { 0x7000, 0x7FFF, "Reserved for profile usage" }, + /* Following ranges are used for adjust */ + { 0x8000, 0x8000, "reserved" }, + { 0x8001, 0xBFFF, "Manufacturer specific" }, + { 0xC000, 0xC00F, "Reserved for normative usage" }, + { 0xC010, 0xC010, "Digital input observer - SoE_DigitalInputObserver" }, + { 0xC011, 0xEFFF, "Reserved for normative usage"}, + { 0xF000, 0xFFFF, "Reserved for profile usage"}, + { 0, 0, NULL } +}; + +static const value_string pn_io_rs_specifier_specifier[] = { + { 0x0, "Current value" }, + { 0x1, "Appears" }, + { 0x2, "Disappears" }, + { 0x3, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_rs_time_stamp_status[] = { + { 0x0, "TimeStamp related to global synchronized time" }, + { 0x1, "TimeStamp related to local time" }, + { 0x2, "TimeStamp related to local (arbitrary timescale) time" }, + { 0, NULL } +}; + +static const value_string pn_io_rs_reason_code_reason[] = { + { 0x00000000, "Reserved" }, + { 0x00000001, "Observed data status unclear" }, + { 0x00000002, "Buffer overrun" }, + /* 0x0003 - 0xFFFF Reserved */ + { 0, NULL } +}; + +static const value_string pn_io_rs_reason_code_detail[] = { + { 0x00000000, "No Detail" }, + /* 0x0001 - 0xFFFF Reserved */ + { 0, NULL } +}; + +static const value_string pn_io_soe_digital_input_current_value_value[] = { + { 0x0, "Digital input is zero" }, + { 0x1, "Digital input is one" }, + { 0, NULL } +}; + +static const value_string pn_io_soe_adjust_specifier_incident[] = { + { 0x00, "Reserved" }, + { 0x01, "Rising edge" }, + { 0x02, "Falling edge" }, + { 0x03, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_io_rs_properties_alarm_transport[] = { + { 0x00000000, "Default Reporting system events need to be read by record " }, + { 0x00000001, "Reporting system events shall be forwarded to the IOC using the alarm transport" }, + { 0, NULL } +}; + +static const value_string pn_io_am_location_structure_vals[] = { + { 0x00, "Reserved" }, + { 0x01, "Twelve level tree format" }, + { 0x02, "Slot - and SubslotNumber format" }, + { 0, NULL } +}; + +static const range_string pn_io_am_location_level_vals[] = { + { 0x0000, 0x03FE, "Address information to identify a reported node" }, + { 0x03FF, 0x03FF, "Level not used" }, + { 0, 0, NULL } +}; + +static const value_string pn_io_am_location_reserved_vals[] = { + { 0x00, "Reserved" }, + { 0, NULL } +}; + +static const range_string pn_io_RedundancyDataHoldFactor[] = { + { 0x0000, 0x0002, "Reserved" }, + { 0x0003, 0x00C7, "Optional - An expiration of the time leads to an AR termination." }, + { 0x00C8, 0xFFFF, "Mandatory - An expiration of the time leads to an AR termination." }, + { 0, 0, NULL } +}; + +static const value_string pn_io_ar_arnumber[] = { + { 0x0000, "reserved" }, + { 0x0001, "1st AR of an ARset" }, + { 0x0002, "2nd AR of an ARset" }, + { 0x0003, "3rd AR of an ARset" }, + { 0x0004, "4th AR of an ARset" }, + /*0x0005 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const value_string pn_io_ar_arresource[] = { + { 0x0000, "reserved" }, + { 0x0002, "Communication endpoint shall allocate two ARs for the ARset" }, + /*0x0001 and 0x0003 - 0xFFFF reserved */ + { 0, NULL } +}; + +static const range_string pn_io_line_delay_value[] = { + { 0x00000000, 0x00000000, "Line delay and cable delay unknown" }, + { 0x00000001, 0x7FFFFFFF, "Line delay in nanoseconds" }, + { 0, 0, NULL } +}; + +static const range_string pn_io_cable_delay_value[] = { + { 0x00000000, 0x00000000, "Reserved" }, + { 0x00000001, 0x7FFFFFFF, "Cable delay in nanoseconds" }, + { 0, 0, NULL } +}; + +static const true_false_string pn_io_pdportstatistic_counter_status_contents = { + "The contents of the field are invalid. They shall be set to zero.", + "The contents of the field are valid" +}; + +static const value_string pn_io_pdportstatistic_counter_status_reserved[] = { + { 0x00, "Reserved" }, + { 0, NULL } +}; + +static int +dissect_profidrive_value(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep, guint8 format_val) +{ + guint32 value32; + guint16 value16; + guint8 value8; + + switch(format_val) + { + case 1: + case 2: + case 5: + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_profidrive_param_value_byte, &value8); + break; + case 3: + case 6: + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_profidrive_param_value_word, &value16); + break; + case 4: + case 7: + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_profidrive_param_value_dword, &value32); + break; + case 8: + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_profidrive_param_value_float, &value32); + break; + case 9: + case 0x0A: + { + gint sLen; + sLen = (gint)tvb_strnlen( tvb, offset, -1); + proto_tree_add_item(tree, hf_pn_io_profidrive_param_value_string, tvb, offset, sLen, ENC_ASCII|ENC_NA); + offset = (offset + sLen); + break; + } + default: + offset = offset + 1; + expert_add_info_format(pinfo, tree, &ei_pn_io_unsupported, "Not supported or invalid format %u!", format_val); + break; + } + return(offset); +} + +static GList *pnio_ars; + +typedef struct pnio_ar_s { + /* generic */ + e_guid_t aruuid; + guint16 inputframeid; + guint16 outputframeid; + + /* controller only */ + /*const char controllername[33];*/ + const guint8 controllermac[6]; + guint16 controlleralarmref; + + /* device only */ + const guint8 devicemac[6]; + guint16 devicealarmref; + guint16 arType; +} pnio_ar_t; + + + +static void +pnio_ar_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pnio_ar_t *ar) +{ + p_add_proto_data(wmem_file_scope(), pinfo, proto_pn_io, 0, ar ); + p_add_proto_data(pinfo->pool, pinfo, proto_pn_io, 0, GUINT_TO_POINTER(10)); + + if (tree) { + proto_item *item; + proto_item *sub_item; + proto_tree *sub_tree; + address controllermac_addr, devicemac_addr; + + set_address(&controllermac_addr, AT_ETHER, 6, ar->controllermac); + set_address(&devicemac_addr, AT_ETHER, 6, ar->devicemac); + + sub_tree = proto_tree_add_subtree_format(tree, tvb, 0, 0, ett_pn_io_ar_info, &sub_item, + "ARUUID:%s ContrMAC:%s ContrAlRef:0x%x DevMAC:%s DevAlRef:0x%x InCR:0x%x OutCR=0x%x", + guid_to_str(wmem_packet_scope(), (const e_guid_t*) &ar->aruuid), + address_to_str(wmem_packet_scope(), &controllermac_addr), ar->controlleralarmref, + address_to_str(wmem_packet_scope(), &devicemac_addr), ar->devicealarmref, + ar->inputframeid, ar->outputframeid); + PROTO_ITEM_SET_GENERATED(sub_item); + + item = proto_tree_add_guid(sub_tree, hf_pn_io_ar_uuid, tvb, 0, 0, (e_guid_t *) &ar->aruuid); + PROTO_ITEM_SET_GENERATED(item); + + item = proto_tree_add_ether(sub_tree, hf_pn_io_cminitiator_macadd, tvb, 0, 0, ar->controllermac); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_pn_io_localalarmref, tvb, 0, 0, ar->controlleralarmref); + PROTO_ITEM_SET_GENERATED(item); + + item = proto_tree_add_ether(sub_tree, hf_pn_io_cmresponder_macadd, tvb, 0, 0, ar->devicemac); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_pn_io_localalarmref, tvb, 0, 0, ar->devicealarmref); + PROTO_ITEM_SET_GENERATED(item); + + item = proto_tree_add_uint(sub_tree, hf_pn_io_frame_id, tvb, 0, 0, ar->inputframeid); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_pn_io_frame_id, tvb, 0, 0, ar->outputframeid); + PROTO_ITEM_SET_GENERATED(item); + } +} + + + + +static int dissect_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, guint16 *u16Index, guint32 *u32RecDataLen, pnio_ar_t **ar); + +static int dissect_a_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep); + +static int dissect_blocks(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep); + +static int dissect_PNIO_IOxS(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, int hfindex); + + + + + +static pnio_ar_t * +pnio_ar_find_by_aruuid(packet_info *pinfo _U_, e_guid_t *aruuid) +{ + GList *ars; + pnio_ar_t *ar; + + + /* find pdev */ + for(ars = pnio_ars; ars != NULL; ars = g_list_next(ars)) { + ar = (pnio_ar_t *)ars->data; + + if (memcmp(&ar->aruuid, aruuid, sizeof(e_guid_t)) == 0) { + return ar; + } + } + + return NULL; +} + + +static pnio_ar_t * +pnio_ar_new(e_guid_t *aruuid) +{ + pnio_ar_t *ar; + + + ar = (pnio_ar_t *)wmem_alloc0(wmem_file_scope(), sizeof(pnio_ar_t)); + + memcpy(&ar->aruuid, aruuid, sizeof(e_guid_t)); + + ar->controlleralarmref = 0xffff; + ar->devicealarmref = 0xffff; + + pnio_ars = g_list_append(pnio_ars, ar); + + return ar; +} + + + +/* 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] & DREP_LITTLE_ENDIAN) ? 3 : 0; + + const value_string *error_code1_vals; + const value_string *error_code2_vals = pn_io_error_code2; /* defaults */ + + + + /* status */ + sub_item = proto_tree_add_item(tree, hf_pn_io_status, tvb, offset, 0, ENC_NA); + 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; + + /* u8ErrorCode2 for PNIORW is always user specific */ + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pniorw, &u8ErrorCode2); + + error_code2_vals = pn_io_error_code2_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; + + switch (u8ErrorCode1) { + case(1): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_1, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_1; + break; + case(2): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_2, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_2; + break; + case(3): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_3, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_3; + break; + case(4): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_4, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_4; + break; + case(5): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_5, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_5; + break; + case(6): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_6, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_6; + break; + case(7): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_7, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_7; + break; + case(8): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_8, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_8; + break; + case(13): + dissect_dcerpc_uint8(tvb, offset + (3 ^ bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_13, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_13; + break; + case(20): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_20, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_20; + break; + case(21): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_21, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_21; + break; + case(22): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_22, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_22; + break; + case(23): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_23, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_23; + break; + case(40): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_40, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_40; + break; + case(60) : + dissect_dcerpc_uint8(tvb, offset + (3 ^ bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_60, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_60; + break; + case(61): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_61, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_61; + break; + case(62): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_62, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_62; + break; + case(63): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_63, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_63; + break; + case(64): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_64, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_64; + break; + case(65): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_65, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_65; + break; + case(66): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_66, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_66; + break; + case(70): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_70, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_70; + break; + case(71): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_71, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_71; + break; + case(72): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_72, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_72; + break; + case(73): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_73, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_73; + break; + case(74): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_74, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_74; + break; + case(75): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_75, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_75; + break; + case(76): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_76, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_76; + break; + case(77): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_77, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_77; + break; + case(253): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_253, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_253; + break; + case(255): + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2_pnio_255, &u8ErrorCode2); + error_code2_vals = pn_io_error_code2_pnio_255; + break; + default: + /* don't know this u8ErrorCode1 for PNIO, use defaults */ + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2, &u8ErrorCode2); + expert_add_info_format(pinfo, sub_item, &ei_pn_io_error_code1, "Unknown ErrorCode1 0x%x (for ErrorDecode==PNIO)", u8ErrorCode1); + break; + } + break; + default: + dissect_dcerpc_uint8(tvb, offset+(2^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code1, &u8ErrorCode1); + if (u8ErrorDecode!=0) { + expert_add_info_format(pinfo, sub_item, &ei_pn_io_error_code1, "Unknown ErrorDecode 0x%x", u8ErrorDecode); + } + error_code1_vals = pn_io_error_code1; + + /* don't know this u8ErrorDecode, use defaults */ + dissect_dcerpc_uint8(tvb, offset+(3^bytemask), pinfo, sub_tree, drep, + hf_pn_io_error_code2, &u8ErrorCode2); + if (u8ErrorDecode != 0) { + expert_add_info_format(pinfo, sub_item, &ei_pn_io_error_code2, "Unknown ErrorDecode 0x%x", u8ErrorDecode); + } + } + + offset += 4; + + if ((u8ErrorCode == 0) && (u8ErrorDecode == 0) && (u8ErrorCode1 == 0) && (u8ErrorCode2 == 0)) { + proto_item_append_text(sub_item, ": OK"); + col_append_str(pinfo->cinfo, COL_INFO, ", OK"); + } else { + proto_item_append_text(sub_item, ": Error: \"%s\", \"%s\", \"%s\", \"%s\"", + 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)"), + val_to_str(u8ErrorCode2, error_code2_vals, "(0x%x)")); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Error: \"%s\", \"%s\", \"%s\", \"%s\"", + 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)"), + val_to_str(u8ErrorCode2, error_code2_vals, "(0x%x)")); + } + 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, ENC_NA); + 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, proto_item *item, 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); + + proto_item_append_text(item, ", %s, API:%u, Slot:0x%x/0x%x", + val_to_str(u16AlarmType, pn_io_alarm_type, "(0x%x)"), + u32Api, u16SlotNr, u16SubslotNr); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Slot: 0x%x/0x%x", + val_to_str(u16AlarmType, pn_io_alarm_type, "(0x%x)"), + u16SlotNr, u16SubslotNr); + + return offset; +} + + +static int +dissect_ChannelProperties(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16ChannelProperties; + + + sub_item = proto_tree_add_item(tree, hf_pn_io_channel_properties, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_channel_properties); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_channel_properties_direction, &u16ChannelProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_channel_properties_specifier, &u16ChannelProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_channel_properties_maintenance, &u16ChannelProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_channel_properties_accumulative, &u16ChannelProperties); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_channel_properties_type, &u16ChannelProperties); + + return offset; +} + +/* dissect the RS_BlockHeader */ +static int +dissect_RS_BlockHeader(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item, guint8 *drep, + guint16 *u16RSBodyLength, guint16 *u16RSBlockType) +{ + guint16 u16RSBlockLength; + guint8 u8BlockVersionHigh; + guint8 u8BlockVersionLow; + + /* u16RSBlockType is needed for further dissection */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_block_type, u16RSBlockType); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_block_length, &u16RSBlockLength); + + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_block_version_high, &u8BlockVersionHigh); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_block_version_low, &u8BlockVersionLow); + + proto_item_append_text(item, ": Type=%s, Length=%u(+4), Version=%u.%u", + rval_to_str(*u16RSBlockType, pn_io_rs_block_type, "Unknown (0x%04x)"), + u16RSBlockLength, u8BlockVersionHigh, u8BlockVersionLow); + + /* Block length is without type and length fields, but with version field */ + /* as it's already dissected, remove it */ + *u16RSBodyLength = u16RSBlockLength - 2; + + /* Padding 2 + 2 + 1 + 1 = 6 */ + /* Therefore we need 2 byte padding to make the block u32 aligned */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* remove padding */ + *u16RSBodyLength -= 2; + return offset; +} + +static int +dissect_RS_AddressInfo(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep, guint16 *u16RSBodyLength) +{ + e_guid_t IM_UniqueIdentifier; + guint32 u32Api; + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint16 u16ChannelNumber; + + /* IM_UniqueIdentifier */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_uuid, &IM_UniqueIdentifier); + *u16RSBodyLength -= 16; + + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_api, &u32Api); + *u16RSBodyLength -= 4; + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + *u16RSBodyLength -= 2; + + /* SubSlotNumber*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + *u16RSBodyLength -= 2; + + /* Channel Number*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_channel_number, &u16ChannelNumber); + *u16RSBodyLength -= 2; + + return offset; +} + +/* dissect the RS_EventDataCommon */ +static int +dissect_RS_EventDataCommon(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep, guint16 *u16RSBodyLength) +{ + guint16 u16RSSpecifierSequenceNumber; + guint16 u16RSSpecifierReserved; + guint16 u16RSSpecifierSpecifier; + guint16 u16RSMinorError; + guint16 u16RSPlusError; + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *sub_item_time_stamp; + proto_tree *sub_tree_time_stamp; + nstime_t timestamp; + guint16 u16RSTimeStampStatus; + + /* RS_AddressInfo */ + offset = dissect_RS_AddressInfo(tvb, offset, pinfo, tree, drep, u16RSBodyLength); + + /* RS_Specifier */ + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_specifier, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_specifier); + + /* RS_Specifier.SequenceNumber */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_specifier_sequence, &u16RSSpecifierSequenceNumber); + + /* RS_Specifier.Reserved */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_specifier_reserved, &u16RSSpecifierReserved); + + /* RS_Specifier.Specifier */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_specifier_specifier, &u16RSSpecifierSpecifier); + *u16RSBodyLength -= 2; + + /* RS_TimeStamp */ + sub_item_time_stamp = proto_tree_add_item(tree, hf_pn_io_rs_time_stamp, tvb, offset, 12, ENC_NA); + sub_tree_time_stamp = proto_item_add_subtree(sub_item_time_stamp, ett_pn_io_rs_time_stamp); + + /* RS_TimeStamp.Status */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree_time_stamp, drep, + hf_pn_io_rs_time_stamp_status, &u16RSTimeStampStatus); + + /* RS_TimeStamp.TimeStamp */ + + /* Start after from 2 bytes Status */ + timestamp.secs = (time_t)tvb_get_ntoh48(tvb, offset + 2); + + /* Start after from 4 bytes timestamp.secs */ + timestamp.nsecs = (int)tvb_get_ntohl(tvb, offset + 8); + + /* Start after from 2 bytes Status and get all 10 bytes */ + proto_tree_add_time(sub_tree_time_stamp, hf_pn_io_rs_time_stamp_value, tvb, offset + 2, 10, ×tamp); + *u16RSBodyLength -= 12; + offset += 12; + + /* RS_MinusError */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_minus_error, &u16RSMinorError); + *u16RSBodyLength -= 2; + + /* RS_PlusError */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_plus_error, &u16RSPlusError); + *u16RSBodyLength -= 2; + + return offset; +} + +/* dissect the RS_IdentificationInfo */ +static int +dissect_RS_IdentificationInfo(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + dcerpc_info di; /* fake dcerpc_info struct */ + dcerpc_call_value dcv; /* fake dcerpc_call_value struct */ + guint64 u64AMDeviceIdentificationDeviceSubID; + guint64 u64AMDeviceIdentificationDeviceID; + guint64 u64AMDeviceIdentificationVendorID; + guint64 u64AM_DeviceIdentificationOrganization; + + proto_item *sub_item; + proto_tree *sub_tree; + + di.call_data = &dcv; + + sub_item = proto_tree_add_item(tree, hf_pn_io_am_device_identification, tvb, offset, 8, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_am_device_identification); + + /* AM_DeviceIdentification */ + dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_device_sub_id, &u64AMDeviceIdentificationDeviceSubID); + dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_device_id, &u64AMDeviceIdentificationDeviceID); + dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_vendor_id, &u64AMDeviceIdentificationVendorID); + offset = dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_organization, &u64AM_DeviceIdentificationOrganization); + + /* IM_Tag_Function [32] */ + proto_tree_add_item(tree, hf_pn_io_im_tag_function, tvb, offset, 32, ENC_ASCII|ENC_NA); + offset += 32; + + /* IM_Tag_Location [22] */ + proto_tree_add_item(tree, hf_pn_io_im_tag_location, tvb, offset, 22, ENC_ASCII|ENC_NA); + offset += 22; + + return offset; +} + +/* dissect the RS_EventDataExtension_Data */ +static int +dissect_RS_EventDataExtension_Data(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, + guint8 *u8RSExtensionBlockLength, guint16 *u16RSBlockType) +{ + guint32 u32RSReasonCodeReason; + guint32 u32RSReasonCodeDetail; + guint8 u8LengthRSDomainIdentification = 16; + guint8 u8LengthRSMasterIdentification = 8; + guint16 u16SoE_DigitalInputCurrentValueValue; + guint16 u16SoE_DigitalInputCurrentValueReserved; + + proto_item *sub_item; + proto_tree *sub_tree; + nstime_t timestamp; + guint16 u16RSTimeStampStatus; + proto_item *sub_item_time_stamp; + proto_tree *sub_tree_time_stamp; + + switch (*u16RSBlockType) { + case(0x4000): /* RS_StopObserver */ + + /* RS_BlockType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_block_type, u16RSBlockType); + + /* RS_ReasonCode */ + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_reason_code, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_reason_code); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_reason_code_reason, &u32RSReasonCodeReason); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_reason_code_detail, &u32RSReasonCodeDetail); + *u8RSExtensionBlockLength -= 6; + break; + case(0x4001): /* RS_BufferObserver */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, *u8RSExtensionBlockLength, "UserData"); + *u8RSExtensionBlockLength = 0; + break; + case(0x4002): /* RS_TimeStatus */ + + /* Padding 1 + 1 + 16 + 8 = 26 or 1 + 1 + 16 + 8 + 12 = 38 */ + /* Therefore we need 2 byte padding to make the block u32 aligned */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + *u8RSExtensionBlockLength -= 2; + + /* RS_DomainIdentification */ + proto_tree_add_item(tree, hf_pn_io_rs_domain_identification, tvb, offset, u8LengthRSDomainIdentification, ENC_NA); + offset += u8LengthRSDomainIdentification; + *u8RSExtensionBlockLength -= 16; + + /* RS_MasterIdentification */ + proto_tree_add_item(tree, hf_pn_io_rs_master_identification, tvb, offset, u8LengthRSMasterIdentification, ENC_NA); + offset += u8LengthRSMasterIdentification; + *u8RSExtensionBlockLength -= 8; + + if (*u8RSExtensionBlockLength > 2) + { + /* RS_TimeStamp */ + sub_item_time_stamp = proto_tree_add_item(tree, hf_pn_io_rs_time_stamp, tvb, offset, 12, ENC_NA); + sub_tree_time_stamp = proto_item_add_subtree(sub_item_time_stamp, ett_pn_io_rs_time_stamp); + + /* RS_TimeStamp.Status */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree_time_stamp, drep, + hf_pn_io_rs_time_stamp_status, &u16RSTimeStampStatus); + + /* RS_TimeStamp.TimeStamp */ + timestamp.secs = (time_t)tvb_get_ntoh48(tvb, offset + 2); // Start after from 2 bytes Status + timestamp.nsecs = (int)tvb_get_ntohl(tvb, offset + 8); // Start after from 4 bytes timestamp.secs + // Start after from 2 bytes Status and get all 10 bytes + proto_tree_add_time(sub_tree_time_stamp, hf_pn_io_rs_time_stamp_value, tvb, offset + 2, 10, ×tamp); + offset += 12; + } + break; + case(0x4003): /* RS_SRLObserver */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, *u8RSExtensionBlockLength, "UserData"); + *u8RSExtensionBlockLength = 0; + break; + case(0x4004): /* RS_SourceIdentification */ + offset = dissect_RS_IdentificationInfo(tvb, offset, pinfo, tree, drep); + *u8RSExtensionBlockLength = 0; + break; + case(0x4010): /* SoE_DigitalInputObserver */ + /* SoE_DigitalInputCurrentValue */ + sub_item = proto_tree_add_item(tree, hf_pn_io_soe_digital_input_current_value, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_soe_digital_input_current_value); + + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_soe_digital_input_current_value_value, &u16SoE_DigitalInputCurrentValueValue); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_soe_digital_input_current_value_reserved, &u16SoE_DigitalInputCurrentValueReserved); + *u8RSExtensionBlockLength -= 2; + break; + default: + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, *u8RSExtensionBlockLength, "UserData"); + *u8RSExtensionBlockLength = 0; + break; + } + return offset; +} + +/* dissect the RS_EventDataExtension */ +static int +dissect_RS_EventDataExtension(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint8 *drep, guint16 *u16RSBlockLength, guint16 *u16RSBlockType) +{ + guint8 u8RSExtensionBlockType; + guint8 u8RSExtensionBlockLength; + + /* RS_ExtensionBlockType */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_extension_block_type, &u8RSExtensionBlockType); + *u16RSBlockLength -= 1; + + /* RS_ExtensionBlockLength */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_extension_block_length, &u8RSExtensionBlockLength); + *u16RSBlockLength -= 1; + + /* Data*[Padding] * a*/ + while (u8RSExtensionBlockLength) { + *u16RSBlockLength -= u8RSExtensionBlockLength; + offset = dissect_RS_EventDataExtension_Data(tvb, offset, pinfo, tree, drep, + &u8RSExtensionBlockLength, u16RSBlockType); + } + + return offset; +} + +/* dissect the RS_EventData */ +static int +dissect_RS_EventData(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep, + guint16 *u16RSBodyLength, guint16 *u16RSBlockType) +{ + proto_item *sub_item; + proto_tree *sub_tree; + + /* RS_EventDataCommon */ + offset = dissect_RS_EventDataCommon(tvb, offset, pinfo, tree, drep, u16RSBodyLength); + + /* optional: RS_EventDataExtension */ + while (*u16RSBodyLength > 0) { + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_event_data_extension, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_event_data_extension); + offset = dissect_RS_EventDataExtension(tvb, offset, pinfo, sub_tree, drep, + u16RSBodyLength, u16RSBlockType); + } + + return offset; +} + +/* dissect the RS_EventBlock */ +static int +dissect_RS_EventBlock(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + + guint16 u16RSBodyLength; + guint16 u16RSBlockType; + + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_event_block, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_event_block); + + /* RS_BlockHeader */ + offset = dissect_RS_BlockHeader(tvb, offset, pinfo, sub_tree, sub_item, drep, + &u16RSBodyLength, &u16RSBlockType); + + /* RS_EventData */ + offset = dissect_RS_EventData(tvb, offset, pinfo, sub_tree, drep, + &u16RSBodyLength, &u16RSBlockType); + return offset; +} + +/* dissect the RS_AlarmInfo */ +static int +dissect_RS_AlarmInfo(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16RSAlarmInfo; + + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_alarm_info, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_alarm_info); + + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_alarm_info_reserved_0_7, &u16RSAlarmInfo); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_rs_alarm_info_reserved_8_15, &u16RSAlarmInfo); + + return offset; +} + +/* dissect the RS_EventInfo */ +static int +dissect_RS_EventInfo(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16NumberofEntries; + + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_event_info, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_event_info); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_number_of_rs_event_info, &u16NumberofEntries); + + while (u16NumberofEntries > 0) { + u16NumberofEntries--; + offset = dissect_RS_EventBlock(tvb, offset, pinfo, sub_tree, drep); + } + return offset; +} + +static int +dissect_AlarmUserStructure(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, + guint16 *body_length, guint16 u16UserStructureIdentifier) +{ + guint16 u16ChannelNumber; + guint16 u16ChannelErrorType; + guint16 u16ExtChannelErrorType; + guint32 u32ExtChannelAddValue; + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + + switch (u16UserStructureIdentifier) { + case(0x8000): /* ChannelDiagnosisData */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_channel_number, &u16ChannelNumber); + offset = dissect_ChannelProperties(tvb, offset, pinfo, tree, item, drep); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_channel_error_type, &u16ChannelErrorType); + *body_length -= 6; + break; + case(0x8002): /* ExtChannelDiagnosisData */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_channel_number, &u16ChannelNumber); + + offset = dissect_ChannelProperties(tvb, offset, pinfo, tree, item, drep); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_channel_error_type, &u16ChannelErrorType); + + if (u16ChannelErrorType < 0x7fff) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8000) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8000, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8001) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8001, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8002) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8002, &u16ExtChannelErrorType); + } + else if ((u16ChannelErrorType == 0x8003)||(u16ChannelErrorType == 0x8009)) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8003, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8004) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8004, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8005) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8005, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8007) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8007, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x8008) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x8008, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x800A) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x800A, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x800B) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x800B, &u16ExtChannelErrorType); + } + else if (u16ChannelErrorType == 0x800C) + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type0x800C, &u16ExtChannelErrorType); + } + else + { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_error_type, &u16ExtChannelErrorType); + } + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_ext_channel_add_value, &u32ExtChannelAddValue); + *body_length -= 12; + break; + case(0x8100): /* MaintenanceItem */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + *body_length -= 12; + break; + case(0x8300): /* RS_AlarmInfo (Reporting System Alarm Information) */ + case(0x8301): /* RS_AlarmInfo */ + case(0x8302): /* RS_AlarmInfo */ + offset = dissect_RS_AlarmInfo(tvb, offset, pinfo, tree, drep); + *body_length = 0; + break; + case(0x8303): /* RS_EventInfo (Reporting System Event Information) */ + offset = dissect_RS_EventInfo(tvb, offset, pinfo, tree, drep); + *body_length = 0; + break; + /* XXX - dissect remaining user structures of [AlarmItem] */ + case(0x8001): /* DiagnosisData */ + case(0x8003): /* QualifiedChannelDiagnosisData */ + default: + if (u16UserStructureIdentifier >= 0x8000) { + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, *body_length); + } else { + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, *body_length, "UserData"); + } + + *body_length = 0; + } + + return offset; +} + + + +/* dissect the alarm notification block */ +static int +dissect_AlarmNotification_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 body_length) +{ + guint32 u32ModuleIdentNumber; + guint32 u32SubmoduleIdentNumber; + guint16 u16UserStructureIdentifier; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_Alarm_header(tvb, offset, pinfo, tree, item, 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); + + proto_item_append_text(item, ", Ident:0x%x, SubIdent:0x%x", + u32ModuleIdentNumber, u32SubmoduleIdentNumber); + + body_length -= 20; + + /* the rest of the block contains optional: [MaintenanceItem] and/or [AlarmItem] */ + while (body_length) { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_user_structure_identifier, &u16UserStructureIdentifier); + proto_item_append_text(item, ", USI:0x%x", u16UserStructureIdentifier); + body_length -= 2; + + offset = dissect_AlarmUserStructure(tvb, offset, pinfo, tree, item, drep, &body_length, u16UserStructureIdentifier); + } + + return offset; +} + + +static int +dissect_IandM0_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint8 u8VendorIDHigh; + guint8 u8VendorIDLow; + char *pOrderID; + char *pIMSerialNumber; + guint16 u16IMHardwareRevision; + guint8 u8SWRevisionPrefix; + guint8 u8IMSWRevisionFunctionalEnhancement; + guint8 u8IMSWRevisionBugFix; + guint8 u8IMSWRevisionInternalChange; + guint16 u16IMRevisionCounter; + guint16 u16IMProfileID; + guint16 u16IMProfileSpecificType; + guint8 u8IMVersionMajor; + guint8 u8IMVersionMinor; + guint16 u16IMSupported; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* x8 VendorIDHigh */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_id_high, &u8VendorIDHigh); + /* x8 VendorIDLow */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_id_low, &u8VendorIDLow); + /* c8[20] OrderID */ + pOrderID = (char *)wmem_alloc(wmem_packet_scope(), 20+1); + tvb_memcpy(tvb, (guint8 *) pOrderID, offset, 20); + pOrderID[20] = '\0'; + proto_tree_add_string (tree, hf_pn_io_order_id, tvb, offset, 20, pOrderID); + offset += 20; + + /* c8[16] IM_Serial_Number */ + pIMSerialNumber = (char *)wmem_alloc(wmem_packet_scope(), 16+1); + tvb_memcpy(tvb, (guint8 *) pIMSerialNumber, offset, 16); + pIMSerialNumber[16] = '\0'; + proto_tree_add_string (tree, hf_pn_io_im_serial_number, tvb, offset, 16, pIMSerialNumber); + offset += 16; + + /* x16 IM_Hardware_Revision */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_hardware_revision, &u16IMHardwareRevision); + /* c8 SWRevisionPrefix */ + offset = dissect_dcerpc_char(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_prefix, &u8SWRevisionPrefix); + /* x8 IM_SWRevision_Functional_Enhancement */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_sw_revision_functional_enhancement, &u8IMSWRevisionFunctionalEnhancement); + /* x8 IM_SWRevision_Bug_Fix */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_bugfix, &u8IMSWRevisionBugFix); + /* x8 IM_SWRevision_Internal_Change */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_sw_revision_internal_change, &u8IMSWRevisionInternalChange); + /* x16 IM_Revision_Counter */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_counter, &u16IMRevisionCounter); + /* x16 IM_Profile_ID */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_profile_id, &u16IMProfileID); + /* x16 IM_Profile_Specific_Type */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_profile_specific_type, &u16IMProfileSpecificType); + /* x8 IM_Version_Major (values) */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_version_major, &u8IMVersionMajor); + /* x8 IM_Version_Minor (values) */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_version_minor, &u8IMVersionMinor); + /* x16 IM_Supported (bitfield) */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_supported, &u16IMSupported); + + return offset; +} + + +static int +dissect_IandM1_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + char *pTagFunction; + char *pTagLocation; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* IM_Tag_Function [32] */ + pTagFunction = (char *)wmem_alloc(wmem_packet_scope(), 32+1); + tvb_memcpy(tvb, (guint8 *) pTagFunction, offset, 32); + pTagFunction[32] = '\0'; + proto_tree_add_string (tree, hf_pn_io_im_tag_function, tvb, offset, 32, pTagFunction); + offset += 32; + + /* IM_Tag_Location [22] */ + pTagLocation = (char *)wmem_alloc(wmem_packet_scope(), 22+1); + tvb_memcpy(tvb, (guint8 *) pTagLocation, offset, 22); + pTagLocation[22] = '\0'; + proto_tree_add_string (tree, hf_pn_io_im_tag_location, tvb, offset, 22, pTagLocation); + offset += 22; + + proto_item_append_text(item, ": TagFunction:\"%s\", TagLocation:\"%s\"", pTagFunction, pTagLocation); + + return offset; +} + + +static int +dissect_IandM2_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + char *pDate; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* IM_Date [16] */ + pDate = (char *)wmem_alloc(wmem_packet_scope(), 16+1); + tvb_memcpy(tvb, (guint8 *) pDate, offset, 16); + pDate[16] = '\0'; + proto_tree_add_string (tree, hf_pn_io_im_date, tvb, offset, 16, pDate); + offset += 16; + + proto_item_append_text(item, ": Date:\"%s\"", pDate); + + return offset; +} + + +static int +dissect_IandM3_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + char *pDescriptor; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* IM_Descriptor [54] */ + pDescriptor = (char *)wmem_alloc(wmem_packet_scope(), 54+1); + tvb_memcpy(tvb, (guint8 *) pDescriptor, offset, 54); + pDescriptor[54] = '\0'; + proto_tree_add_string (tree, hf_pn_io_im_descriptor, tvb, offset, 54, pDescriptor); + offset += 54; + + proto_item_append_text(item, ": Descriptor:\"%s\"", pDescriptor); + + return offset; +} + + +static int +dissect_IandM4_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + dissect_pn_user_data(tvb, offset, pinfo, tree, 54, "IM Signature"); + + return offset; +} + +static int +dissect_IandM5_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberofEntries; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_im_numberofentries, &u16NumberofEntries); + + while(u16NumberofEntries > 0) { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + u16NumberofEntries--; + } + return offset; +} + +static int +dissect_IandM0FilterData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberOfAPIs; + guint32 u32Api; + guint16 u16NumberOfModules; + guint16 u16SlotNr; + guint32 u32ModuleIdentNumber; + guint16 u16NumberOfSubmodules; + guint16 u16SubslotNr; + guint32 u32SubmoduleIdentNumber; + proto_item *subslot_item; + proto_tree *subslot_tree; + proto_item *module_item; + proto_tree *module_tree; + guint32 u32ModuleStart; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* NumberOfAPIs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + + while (u16NumberOfAPIs--) { + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_api, &u32Api); + /* NumberOfModules */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_modules, &u16NumberOfModules); + + while (u16NumberOfModules--) { + module_item = proto_tree_add_item(tree, hf_pn_io_subslot, tvb, offset, 6, ENC_NA); + module_tree = proto_item_add_subtree(module_item, ett_pn_io_module); + + u32ModuleStart = offset; + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* ModuleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_module_ident_number, &u32ModuleIdentNumber); + /* NumberOfSubmodules */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_number_of_submodules, &u16NumberOfSubmodules); + + proto_item_append_text(module_item, ": Slot:%u, Ident:0x%x Submodules:%u", + u16SlotNr, u32ModuleIdentNumber, u16NumberOfSubmodules); + + while (u16NumberOfSubmodules--) { + subslot_item = proto_tree_add_item(module_tree, hf_pn_io_subslot, tvb, offset, 6, ENC_NA); + subslot_tree = proto_item_add_subtree(subslot_item, ett_pn_io_subslot); + + /* SubslotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, subslot_tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* SubmoduleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, subslot_tree, drep, + hf_pn_io_submodule_ident_number, &u32SubmoduleIdentNumber); + + proto_item_append_text(subslot_item, ": Number:0x%x, Ident:0x%x", + u16SubslotNr, u32SubmoduleIdentNumber); + } + + proto_item_set_len(module_item, offset-u32ModuleStart); + } + } + + return offset; +} + + +static int +dissect_IandM5Data_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep) +{ + char *pIMAnnotation; + char *pIMOrderID; + guint8 u8VendorIDHigh; + guint8 u8VendorIDLow; + char *pIMSerialNumber; + guint16 u16IMHardwareRevision; + guint8 u8SWRevisionPrefix; + guint8 u8IMSWRevisionFunctionalEnhancement; + guint8 u8IMSWRevisionBugFix; + guint8 u8IMSWRevisionInternalChange; + + /* c8[64] IM Annotation */ + pIMAnnotation = (char *)wmem_alloc(wmem_packet_scope(), 64+1); + tvb_memcpy(tvb, (guint8 *) pIMAnnotation, offset, 64); + pIMAnnotation[64] = '\0'; + proto_tree_add_string(tree, hf_pn_io_im_annotation, tvb, offset, 64, pIMAnnotation); + offset += 64; + + /* c8[64] IM Order ID */ + pIMOrderID = (char *)wmem_alloc(wmem_packet_scope(), 64+1); + tvb_memcpy(tvb, (guint8 *) pIMOrderID, offset, 64); + pIMOrderID[64] = '\0'; + proto_tree_add_string(tree, hf_pn_io_im_order_id, tvb, offset, 64, pIMOrderID); + offset += 64; + + /* x8 VendorIDHigh */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_id_high, &u8VendorIDHigh); + /* x8 VendorIDLow */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_id_low, &u8VendorIDLow); + + /* c8[16] IM Serial Number */ + pIMSerialNumber = (char *)wmem_alloc(wmem_packet_scope(), 16+1); + tvb_memcpy(tvb, (guint8 *) pIMSerialNumber, offset, 16); + pIMSerialNumber[16] = '\0'; + proto_tree_add_string(tree, hf_pn_io_im_serial_number, tvb, offset, 16, pIMSerialNumber); + offset += 16; + + /* x16 IM_Hardware_Revision */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_hardware_revision, &u16IMHardwareRevision); + /* c8 SWRevisionPrefix */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_prefix, &u8SWRevisionPrefix); + /* x8 IM_SWRevision_Functional_Enhancement */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_sw_revision_functional_enhancement, &u8IMSWRevisionFunctionalEnhancement); + /* x8 IM_SWRevision_Bug_Fix */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_bugfix, &u8IMSWRevisionBugFix); + + /* x8 IM_SWRevision_Internal_Change */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_sw_revision_internal_change, &u8IMSWRevisionInternalChange); + + return offset; +} + +static int +dissect_AM_Location(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint8 am_location_structtype; + int bit_offset; + guint8 am_location_reserved1; + guint16 am_location_begin_slot_number; + guint16 am_location_begin_subslot_number; + guint16 am_location_end_slot_number; + guint16 am_location_end_subslot_number; + guint16 am_location_reserved2; + guint16 am_location_reserved3; + guint16 am_location_reserved4; + sub_item = proto_tree_add_item(tree, hf_pn_io_am_location, tvb, offset, 16, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_am_location); + offset = dissect_dcerpc_char(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_am_location_structure, + &am_location_structtype); + + bit_offset = offset << 3; + switch (am_location_structtype) + { + case (0x01): + /* level 0 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_0, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 1 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_1, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 2 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_2, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 3 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_3, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 4 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_4, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 5 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_5, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 6 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_6, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 7 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_7, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 8 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_8, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 9 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_9, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 10 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_10, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + /* level 11 */ + proto_tree_add_bits_item(sub_tree, hf_pn_io_am_location_level_11, tvb, bit_offset, 10, ENC_BIG_ENDIAN); + bit_offset += 10; + offset = bit_offset >> 3; + break; + case (0x02): + /* Reserved1 */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_am_location_reserved1, &am_location_reserved1); + + /* BeginSlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_slot_nr, &am_location_begin_slot_number); + + /* BeginSubslotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subslot_nr, &am_location_begin_subslot_number); + + /* EndSlotNumber*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_slot_nr, &am_location_end_slot_number); + + /* EndSubSlotNumber*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subslot_nr, &am_location_end_subslot_number); + + /* Reserved 2 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_am_location_reserved2, &am_location_reserved2); + + /* Reserved 3 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_am_location_reserved3, &am_location_reserved3); + + /* Reserved 4 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_am_location_reserved4, &am_location_reserved4); + break; + default: /* will not execute because of the line preceding the switch */ + offset += 15; + break; + } + + return offset; +} + +static int +dissect_IM_software_revision(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + guint8 u8SWRevisionPrefix; + guint8 u8IMSWRevisionFunctionalEnhancement; + guint8 u8IMSWRevisionBugFix; + guint8 u8IMSWRevisionInternalChange; + + /* SWRevisionPrefix */ + offset = dissect_dcerpc_char(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_prefix, &u8SWRevisionPrefix); + + /* IM_SWRevision_Functional_Enhancement */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_sw_revision_functional_enhancement, &u8IMSWRevisionFunctionalEnhancement); + + /* IM_SWRevision_Bug_Fix */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_revision_bugfix, &u8IMSWRevisionBugFix); + + /* IM_SWRevision_Internal_Change */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_sw_revision_internal_change, &u8IMSWRevisionInternalChange); + + return offset; +} + +static int +dissect_AM_device_identification(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + dcerpc_info di; /* fake dcerpc_info struct */ + dcerpc_call_value dcv; /* fake dcerpc_call_value struct */ + guint64 u64AMDeviceIdentificationDeviceSubID; + guint64 u64AMDeviceIdentificationDeviceID; + guint64 u64AMDeviceIdentificationVendorID; + guint64 u64AM_DeviceIdentificationOrganization; + + proto_item *sub_item; + proto_tree *sub_tree; + + di.call_data = &dcv; + + sub_item = proto_tree_add_item(tree, hf_pn_io_am_device_identification, tvb, offset, 8, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_am_device_identification); + dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_device_sub_id, &u64AMDeviceIdentificationDeviceSubID); + dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_device_id, &u64AMDeviceIdentificationDeviceID); + dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_vendor_id, &u64AMDeviceIdentificationVendorID); + offset = dissect_dcerpc_uint64(tvb, offset, pinfo, sub_tree, &di, drep, + hf_pn_io_am_device_identification_organization, &u64AM_DeviceIdentificationOrganization); + + return offset; +} + +static int +dissect_AM_FullInformation_block(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, +guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + e_guid_t IM_UniqueIdentifier; + guint16 u16AM_TypeIdentification; + guint16 u16IMHardwareRevision; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* align padding */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* IM_UniqueIdentifier */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_uniqueidentifier, &IM_UniqueIdentifier); + + /* AM_Location */ + offset = dissect_AM_Location(tvb, offset, pinfo, tree, drep); + + /* IM_Annotation */ + proto_tree_add_item(tree, hf_pn_io_im_annotation, tvb, offset, 64, ENC_ASCII|ENC_NA); + offset += 64; + + /* IM_OrderID */ + proto_tree_add_item(tree, hf_pn_io_im_order_id, tvb, offset, 64, ENC_ASCII|ENC_NA); + offset += 64; + + /* AM_SoftwareRevision */ + proto_tree_add_item(tree, hf_pn_io_am_software_revision, tvb, offset, 64, ENC_ASCII|ENC_NA); + offset += 64; + + /* AM_HardwareRevision */ + proto_tree_add_item(tree, hf_pn_io_am_hardware_revision, tvb, offset, 64, ENC_ASCII|ENC_NA); + offset += 64; + + /* IM_Serial_Number */ + proto_tree_add_item(tree, hf_pn_io_im_serial_number, tvb, offset, 16, ENC_ASCII|ENC_NA); + offset += 16; + + /* IM_Software_Revision */ + offset = dissect_IM_software_revision(tvb, offset, pinfo, tree, drep); + + /* AM_DeviceIdentification */ + offset = dissect_AM_device_identification(tvb, offset, pinfo, tree, drep); + + /* AM_TypeIdentification */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_am_type_identification, &u16AM_TypeIdentification); + + /* IM_Hardware_Revision */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_hardware_revision, &u16IMHardwareRevision); + + return offset; +} + +static int +dissect_AM_HardwareOnlyInformation_block(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, +guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + e_guid_t IM_UniqueIdentifier; + guint16 u16AM_TypeIdentification; + guint16 u16IMHardwareRevision; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* align padding */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* IM_UniqueIdentifier */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_uniqueidentifier, &IM_UniqueIdentifier); + + /* AM_Location */ + offset = dissect_AM_Location(tvb, offset, pinfo, tree, drep); + + /* IM_Annotation */ + proto_tree_add_item(tree, hf_pn_io_im_annotation, tvb, offset, 64, ENC_ASCII | ENC_NA); + offset += 64; + + /* IM_OrderID */ + proto_tree_add_item(tree, hf_pn_io_im_order_id, tvb, offset, 64, ENC_ASCII | ENC_NA); + offset += 64; + + /* AM_HardwareRevision */ + proto_tree_add_item(tree, hf_pn_io_am_hardware_revision, tvb, offset, 64, ENC_ASCII | ENC_NA); + offset += 64; + + /* IM_Serial_Number */ + proto_tree_add_item(tree, hf_pn_io_im_serial_number, tvb, offset, 16, ENC_ASCII | ENC_NA); + offset += 16; + + /* AM_DeviceIdentification */ + offset = dissect_AM_device_identification(tvb, offset, pinfo, tree, drep); + + /* AM_TypeIdentification */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_am_type_identification, &u16AM_TypeIdentification); + + /* IM_Hardware_Revision */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_hardware_revision, &u16IMHardwareRevision); + + return offset; +} + +static int +dissect_AM_FirmwareOnlyInformation_block(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, +guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + e_guid_t IM_UniqueIdentifier; + guint16 u16AM_TypeIdentification; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* IM_UniqueIdentifier */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_im_uniqueidentifier, &IM_UniqueIdentifier); + + /* AM_Location */ + offset = dissect_AM_Location(tvb, offset, pinfo, tree, drep); + + /* IM_Annotation */ + proto_tree_add_item(tree, hf_pn_io_im_annotation, tvb, offset, 64, ENC_ASCII | ENC_NA); + offset += 64; + + /* IM_OrderID */ + proto_tree_add_item(tree, hf_pn_io_im_order_id, tvb, offset, 64, ENC_ASCII | ENC_NA); + offset += 64; + + /* AM_SoftwareRevision */ + proto_tree_add_item(tree, hf_pn_io_am_software_revision, tvb, offset, 64, ENC_ASCII | ENC_NA); + offset += 64; + + /* IM_Serial_Number */ + proto_tree_add_item(tree, hf_pn_io_im_serial_number, tvb, offset, 16, ENC_ASCII | ENC_NA); + offset += 16; + + /* IM_Software_Revision */ + offset = dissect_IM_software_revision(tvb, offset, pinfo, tree, drep); + + /* AM_DeviceIdentification */ + offset = dissect_AM_device_identification(tvb, offset, pinfo, tree, drep); + + /* AM_TypeIdentification */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_am_type_identification, &u16AM_TypeIdentification); + + return offset; +} + +/* dissect the AssetManagementInfo */ +static int +dissect_AssetManagementInfo(tvbuff_t *tvb, int offset, +packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16NumberofEntries; + + sub_item = proto_tree_add_item(tree, hf_pn_io_asset_management_info, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_asset_management_info); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_number_of_asset_management_info, &u16NumberofEntries); + + while (u16NumberofEntries > 0) { + u16NumberofEntries--; + offset = dissect_a_block(tvb, offset, pinfo, sub_tree, drep); + } + return offset; +} + +/* dissect the AssetManagementData block */ +static int +dissect_AssetManagementData_block(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, +guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_AssetManagementInfo(tvb, offset, pinfo, tree, drep); + return offset; +} + +/* dissect the IdentificationData block */ +static int +dissect_IdentificationData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberOfAPIs = 1; + guint32 u32Api; + guint16 u16NumberOfSlots; + guint16 u16SlotNr; + guint32 u32ModuleIdentNumber; + guint16 u16NumberOfSubslots; + guint32 u32SubmoduleIdentNumber; + guint16 u16SubslotNr; + proto_item *slot_item; + proto_tree *slot_tree; + guint32 u32SlotStart; + proto_item *subslot_item; + proto_tree *subslot_tree; + + + if (u8BlockVersionHigh != 1 || (u8BlockVersionLow != 0 && u8BlockVersionLow != 1)) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + if (u8BlockVersionLow == 1) { + /* NumberOfAPIs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + } + + proto_item_append_text(item, ": APIs:%u", u16NumberOfAPIs); + + while (u16NumberOfAPIs--) { + if (u8BlockVersionLow == 1) { + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_api, &u32Api); + } + + /* NumberOfSlots */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_slots, &u16NumberOfSlots); + + proto_item_append_text(item, ", Slots:%u", u16NumberOfSlots); + + while (u16NumberOfSlots--) { + slot_item = proto_tree_add_item(tree, hf_pn_io_slot, tvb, offset, 0, ENC_NA); + slot_tree = proto_item_add_subtree(slot_item, ett_pn_io_slot); + u32SlotStart = offset; + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, slot_tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* ModuleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, slot_tree, drep, + hf_pn_io_module_ident_number, &u32ModuleIdentNumber); + /* NumberOfSubslots */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, slot_tree, drep, + hf_pn_io_number_of_subslots, &u16NumberOfSubslots); + + proto_item_append_text(slot_item, ": SlotNr:%u Ident:0x%x Subslots:%u", + u16SlotNr, u32ModuleIdentNumber, u16NumberOfSubslots); + + while (u16NumberOfSubslots--) { + subslot_item = proto_tree_add_item(slot_tree, hf_pn_io_subslot, tvb, offset, 6, ENC_NA); + subslot_tree = proto_item_add_subtree(subslot_item, ett_pn_io_subslot); + + /* SubslotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, subslot_tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* SubmoduleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, subslot_tree, drep, + hf_pn_io_submodule_ident_number, &u32SubmoduleIdentNumber); + + proto_item_append_text(subslot_item, ": Number:0x%x, Ident:0x%x", + u16SubslotNr, u32SubmoduleIdentNumber); + } + + proto_item_set_len(slot_item, offset-u32SlotStart); + } + } + + return offset; +} + + +/* dissect the substitute value block */ +static int +dissect_SubstituteValue_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint16 u16SubstitutionMode; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* SubstitutionMode */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_substitutionmode, &u16SubstitutionMode); + + + /* SubstituteDataItem */ + /* IOCS */ + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, tree, drep, hf_pn_io_iocs); + u16BodyLength -= 3; + /* SubstituteDataObjectElement */ + dissect_pn_user_data_bytes(tvb, offset, pinfo, tree, u16BodyLength, SUBST_DATA); + + return offset; +} + + +/* dissect the RecordInputDataObjectElement block */ +static int +dissect_RecordInputDataObjectElement_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint8 u8LengthIOCS; + guint8 u8LengthIOPS; + guint16 u16LengthData; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* LengthIOCS */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_iocs, &u8LengthIOCS); + /* IOCS */ + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, tree, drep, hf_pn_io_iocs); + /* LengthIOPS */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_iops, &u8LengthIOPS); + /* IOPS */ + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, tree, drep, hf_pn_io_iops); + /* LengthData */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_data, &u16LengthData); + /* Data */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u16LengthData, "Data"); + + return offset; +} + + +/* dissect the RecordOutputDataObjectElement block */ +static int +dissect_RecordOutputDataObjectElement_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16SubstituteActiveFlag; + guint8 u8LengthIOCS; + guint8 u8LengthIOPS; + guint16 u16LengthData; + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* SubstituteActiveFlag */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_substitute_active_flag, &u16SubstituteActiveFlag); + + /* LengthIOCS */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_iocs, &u8LengthIOCS); + /* LengthIOPS */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_iops, &u8LengthIOPS); + /* LengthData */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_data, &u16LengthData); + /* DataItem (IOCS, Data, IOPS) */ + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, tree, drep, hf_pn_io_iocs); + + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u16LengthData, "Data"); + + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, tree, drep, hf_pn_io_iops); + + /* SubstituteValue */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + + return offset; +} + + +/* dissect the alarm acknowledge block */ +static int +dissect_Alarm_ack_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + col_append_str(pinfo->cinfo, COL_INFO, ", Alarm Ack"); + + offset = dissect_Alarm_header(tvb, offset, pinfo, tree, item, drep); + + offset = dissect_Alarm_specifier(tvb, offset, pinfo, tree, drep); + + offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep); + + return offset; +} + + +/* dissect the maintenance block */ +static int +dissect_Maintenance_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32MaintenanceStatus; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + sub_item = proto_tree_add_item(tree, hf_pn_io_maintenance_status, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_maintenance_status); + + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_maintenance_status_demanded, &u32MaintenanceStatus); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_maintenance_status_required, &u32MaintenanceStatus); + + if (u32MaintenanceStatus & 0x0002) { + proto_item_append_text(item, ", Demanded"); + proto_item_append_text(sub_item, ", Demanded"); + } + + if (u32MaintenanceStatus & 0x0001) { + proto_item_append_text(item, ", Required"); + proto_item_append_text(sub_item, ", Required"); + } + + return offset; +} + + +/* dissect the read/write header */ +static int +dissect_ReadWrite_header(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint16 *u16Index, e_guid_t *aruuid) +{ + guint32 u32Api; + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint16 u16SeqNr; + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_seq_number, &u16SeqNr); + + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_uuid, aruuid); + + 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); + /* padding doesn't match offset required for align4 */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_index, u16Index); + + proto_item_append_text(item, ": Seq:%u, Api:0x%x, Slot:0x%x/0x%x", + u16SeqNr, u32Api, u16SlotNr, u16SubslotNr); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Api:0x%x, Slot:0x%x/0x%x, Index:%s", + u32Api, u16SlotNr, u16SubslotNr, + val_to_str(*u16Index, pn_io_index, "(0x%x)")); + + return offset; +} + + +/* dissect the write request block */ +static int +dissect_IODWriteReqHeader_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 *u16Index, guint32 *u32RecDataLen, pnio_ar_t ** ar) +{ + e_guid_t aruuid; + e_guid_t null_uuid; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, item, drep, u16Index, &aruuid); + + /* The value NIL indicates the usage of the implicit AR*/ + *ar = pnio_ar_find_by_aruuid(pinfo, &aruuid); + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_record_data_length, u32RecDataLen); + + memset(&null_uuid, 0, sizeof(e_guid_t)); + if (memcmp(&aruuid, &null_uuid, sizeof (e_guid_t)) == 0) { + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_target_ar_uuid, &aruuid); + } + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 24); + + proto_item_append_text(item, ", Len:%u", *u32RecDataLen); + + if (*u32RecDataLen != 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes", + *u32RecDataLen); + + return offset; +} + + +/* dissect the read request block */ +static int +dissect_IODReadReqHeader_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 *u16Index, guint32 *u32RecDataLen, pnio_ar_t **ar) +{ + e_guid_t aruuid; + e_guid_t null_uuid; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, item, drep, u16Index, &aruuid); + + /* The value NIL indicates the usage of the implicit AR*/ + *ar = pnio_ar_find_by_aruuid(pinfo, &aruuid); + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_record_data_length, u32RecDataLen); + + memset(&null_uuid, 0, sizeof(e_guid_t)); + if (memcmp(&aruuid, &null_uuid, sizeof (e_guid_t)) == 0) { + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_target_ar_uuid, &aruuid); + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 8); + } else { + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 24); + } + + proto_item_append_text(item, ", Len:%u", *u32RecDataLen); + + if (*u32RecDataLen != 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes", + *u32RecDataLen); + + return offset; +} + + +/* dissect the write response block */ +static int +dissect_IODWriteResHeader_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 *u16Index, guint32 *u32RecDataLen, pnio_ar_t **ar) +{ + e_guid_t aruuid; + guint16 u16AddVal1; + guint16 u16AddVal2; + guint32 u32Status; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, item, drep, u16Index, &aruuid); + + /* The value NIL indicates the usage of the implicit AR*/ + *ar = pnio_ar_find_by_aruuid(pinfo, &aruuid); + + 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); + + u32Status = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohl (tvb, offset) + : tvb_get_ntohl (tvb, offset)); + + offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep); + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 16); + + proto_item_append_text(item, ", Len:%u, Index:0x%x, Status:0x%x, Val1:%u, Val2:%u", + *u32RecDataLen, *u16Index, u32Status, u16AddVal1, u16AddVal2); + + if (*u32RecDataLen != 0) + col_append_fstr(pinfo->cinfo, COL_INFO, ", %u bytes", + *u32RecDataLen); + + return offset; +} + + +/* dissect the read response block */ +static int +dissect_IODReadResHeader_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 *u16Index, guint32 *u32RecDataLen, pnio_ar_t **ar) +{ + e_guid_t aruuid; + guint16 u16AddVal1; + guint16 u16AddVal2; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_ReadWrite_header(tvb, offset, pinfo, tree, item, drep, u16Index, &aruuid); + + /* The value NIL indicates the usage of the implicit AR*/ + *ar = pnio_ar_find_by_aruuid(pinfo, &aruuid); + + 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); + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 20); + + proto_item_append_text(item, ", Len:%u, AddVal1:%u, AddVal2:%u", + *u32RecDataLen, u16AddVal1, u16AddVal2); + + if (*u32RecDataLen != 0) + 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, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t **ar) +{ + e_guid_t ar_uuid; + guint16 u16SessionKey; + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16Command; + guint16 u16Properties; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_reserved16, NULL); + + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_uuid, &ar_uuid); + + /* The value NIL indicates the usage of the implicit AR*/ + *ar = pnio_ar_find_by_aruuid(pinfo, &ar_uuid); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sessionkey, &u16SessionKey); + + 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, ENC_BIG_ENDIAN); + 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, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_applready, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_release, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_done, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_ready_for_companion, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_ready_for_rt_class3, &u16Command); + /* Prm.Begin */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_prmbegin, &u16Command); + + if (u16Command & 0x0002) { + /* ApplicationReady: special decode */ + sub_item = proto_tree_add_item(tree, hf_pn_io_control_block_properties_applready, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_control_block_properties); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_block_properties_applready0, &u16Properties); + } else { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_control_block_properties, &u16Properties); + } + + proto_item_append_text(item, ": Session:%u, Command:", u16SessionKey); + + if (u16Command & 0x0001) { + proto_item_append_text(sub_item, ", ParameterEnd"); + proto_item_append_text(item, " ParameterEnd"); + col_append_str(pinfo->cinfo, COL_INFO, ", Command: ParameterEnd"); + } + if (u16Command & 0x0002) { + proto_item_append_text(sub_item, ", ApplicationReady"); + proto_item_append_text(item, " ApplicationReady"); + col_append_str(pinfo->cinfo, COL_INFO, ", Command: ApplicationReady"); + } + if (u16Command & 0x0004) { + proto_item_append_text(sub_item, ", Release"); + proto_item_append_text(item, " Release"); + col_append_str(pinfo->cinfo, COL_INFO, ", Command: Release"); + } + if (u16Command & 0x0008) { + proto_item_append_text(sub_item, ", Done"); + proto_item_append_text(item, ", Done"); + col_append_str(pinfo->cinfo, COL_INFO, ", Command: Done"); + } + + proto_item_append_text(item, ", Properties:0x%x", u16Properties); + + return offset; +} + +/* dissect the ControlBlockPrmBegin block */ +static int +dissect_ControlBlockPrmBegin(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint32 u32RecDataLen, + pnio_ar_t **ar) +{ + e_guid_t ar_uuid; + guint16 u16SessionKey; + guint16 u16Command; + proto_item *sub_item; + proto_tree *sub_tree; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + if (u32RecDataLen != 28-2) /* must be 28 see specification (version already dissected) */ + { + expert_add_info_format(pinfo, item, &ei_pn_io_block_length, "Block length of %u is invalid!", u32RecDataLen); + return offset; + } + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* ARUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, hf_pn_io_ar_uuid, &ar_uuid); + + /* The value NIL indicates the usage of the implicit AR*/ + *ar = pnio_ar_find_by_aruuid(pinfo, &ar_uuid); + + /* SessionKey */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_sessionkey, &u16SessionKey); + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* ControlCommand */ + sub_item = proto_tree_add_item(tree, hf_pn_io_control_command, tvb, offset, 2, ENC_BIG_ENDIAN); + 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, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_applready, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_release, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_done, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_ready_for_companion, &u16Command); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_ready_for_rt_class3, &u16Command); + /* Prm.Begin */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_prmbegin, &u16Command); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_control_command_reserved_7_15, &u16Command); + + /* ControlBlockProperties.reserved */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_control_command_reserved, NULL); + return offset; +} + +/* dissect the SubmoduleListBlock block */ +static int +dissect_SubmoduleListBlock(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint32 u32RecDataLen _U_, + pnio_ar_t **ar _U_) +{ + guint16 u16Entries; + guint32 u32API; + guint16 u16SlotNumber; + guint16 u16SubSlotNumber; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_SubmoduleListEntries, &u16Entries); + + while (u16Entries --) + { + /*API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pn_io_api, &u32API); + /*SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_slot_nr, &u16SlotNumber); + /* SubSlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_subslot_nr, &u16SubSlotNumber); + } + return offset; +} + + +/* dissect the PDevData block */ +static int +dissect_PDevData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + offset = dissect_blocks(tvb, offset, pinfo, tree, drep); + + return offset; +} + +/* dissect the AdjustPreambleLength block */ +static int +dissect_AdjustPreambleLength_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16AdjustProperties; + guint16 u16PreambleLength; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* PreambleLength */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_PreambleLength, &u16PreambleLength); + + + /* AdjustProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + return offset; +} + +/* dissect the dissect_CheckMAUTypeExtension_block block */ +static int +dissect_CheckMAUTypeExtension_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16MauTypeExtension; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MauTypeExtension */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_mau_type_extension, &u16MauTypeExtension); + + return offset; +} + +/* dissect the PDPortDataAdjust block */ +static int +dissect_PDPortData_Adjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint16 u16SlotNr; + guint16 u16SubslotNr; + tvbuff_t *new_tvb; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + + proto_item_append_text(item, ": Slot:0x%x/0x%x", u16SlotNr, u16SubslotNr); + + u16BodyLength -= 6; + + new_tvb = tvb_new_subset_length(tvb, offset, u16BodyLength); + dissect_blocks(new_tvb, 0, pinfo, tree, drep); + offset += u16BodyLength; + + /* XXX - do we have to free the new_tvb somehow? */ + + return offset; +} + + +/* dissect the PDPortDataCheck blocks */ +static int +dissect_PDPortData_Check_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint16 u16SlotNr; + guint16 u16SubslotNr; + tvbuff_t *new_tvb; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + + proto_item_append_text(item, ": Slot:0x%x/0x%x", u16SlotNr, u16SubslotNr); + + u16BodyLength -= 6; + + new_tvb = tvb_new_subset_length(tvb, offset, u16BodyLength); + dissect_blocks(new_tvb, 0, pinfo, tree, drep); + offset += u16BodyLength; + + /* XXX - do we have to free the new_tvb somehow? */ + + return offset; +} + +/* dissect the Line Delay */ +static int +dissect_Line_Delay(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, + guint32 *u32LineDelayValue) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32FormatIndicator; + guint8 isFormatIndicatorEnabled; + + sub_item = proto_tree_add_item(tree, hf_pn_io_line_delay, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_line_delay); + + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_line_delay_format_indicator, &u32FormatIndicator); + + isFormatIndicatorEnabled = (guint8)((u32FormatIndicator >> 31) & 0x01); + if (isFormatIndicatorEnabled) + { + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_cable_delay_value, u32LineDelayValue); + } + else + { + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_line_delay_value, u32LineDelayValue); + } + + return offset; +} + +/* dissect the PDPortDataReal blocks */ +static int +dissect_PDPortDataReal_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint8 u8LengthOwnPortID; + char *pOwnPortID; + guint8 u8NumberOfPeers; + guint8 u8I; + guint8 u8LengthPeerPortID; + char *pPeerPortID; + guint8 u8LengthPeerChassisID; + char *pPeerChassisID; + guint8 mac[6]; + guint16 u16MAUType; + guint32 u32DomainBoundary; + guint32 u32MulticastBoundary; + guint16 u16PortState; + guint32 u32MediaType; + guint32 u32LineDelayValue; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + + /* LengthOwnPortID */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_own_port_id, &u8LengthOwnPortID); + /* OwnPortID */ + pOwnPortID = (char *)wmem_alloc(wmem_packet_scope(), u8LengthOwnPortID+1); + tvb_memcpy(tvb, (guint8 *) pOwnPortID, offset, u8LengthOwnPortID); + pOwnPortID[u8LengthOwnPortID] = '\0'; + proto_tree_add_string (tree, hf_pn_io_own_port_id, tvb, offset, u8LengthOwnPortID, pOwnPortID); + offset += u8LengthOwnPortID; + + /* NumberOfPeers */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_peers, &u8NumberOfPeers); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + u8I = u8NumberOfPeers; + while (u8I--) { + /* LengthPeerPortID */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_peer_port_id, &u8LengthPeerPortID); + /* PeerPortID */ + pPeerPortID = (char *)wmem_alloc(wmem_packet_scope(), u8LengthPeerPortID+1); + tvb_memcpy(tvb, (guint8 *) pPeerPortID, offset, u8LengthPeerPortID); + pPeerPortID[u8LengthPeerPortID] = '\0'; + proto_tree_add_string (tree, hf_pn_io_peer_port_id, tvb, offset, u8LengthPeerPortID, pPeerPortID); + offset += u8LengthPeerPortID; + + /* LengthPeerChassisID */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_peer_chassis_id, &u8LengthPeerChassisID); + /* PeerChassisID */ + pPeerChassisID = (char *)wmem_alloc(wmem_packet_scope(), u8LengthPeerChassisID+1); + tvb_memcpy(tvb, (guint8 *) pPeerChassisID, offset, u8LengthPeerChassisID); + pPeerChassisID[u8LengthPeerChassisID] = '\0'; + proto_tree_add_string (tree, hf_pn_io_peer_chassis_id, tvb, offset, u8LengthPeerChassisID, pPeerChassisID); + offset += u8LengthPeerChassisID; + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* LineDelay */ + offset = dissect_Line_Delay(tvb, offset, pinfo, tree, drep, &u32LineDelayValue); + + /* PeerMACAddress */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, + hf_pn_io_peer_macadd, mac); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + } + + /* MAUType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mau_type, &u16MAUType); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* DomainBoundary */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_domain_boundary, &u32DomainBoundary); + /* MulticastBoundary */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_multicast_boundary, &u32MulticastBoundary); + /* PortState */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_port_state, &u16PortState); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MediaType */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_media_type, &u32MediaType); + + proto_item_append_text(item, ": Slot:0x%x/0x%x, OwnPortID:%s, Peers:%u PortState:%s MediaType:%s", + u16SlotNr, u16SubslotNr, pOwnPortID, u8NumberOfPeers, + val_to_str(u16PortState, pn_io_port_state, "0x%x"), + val_to_str(u32MediaType, pn_io_media_type, "0x%x")); + + return offset; +} + + +static int +dissect_PDInterfaceMrpDataAdjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BodyLength) +{ + e_guid_t uuid; + guint16 u16Role; + guint8 u8LengthDomainName; + guint8 u8NumberOfMrpInstances; + char *pDomainName; + int iStartOffset = offset; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow > 1) { /* added low version == 1 */ + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + if (u8BlockVersionLow == 0) /*dissect LowVersion == 0 */ + { + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + /* MRP_Role */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_role, &u16Role); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MRP_LengthDomainName */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_length_domain_name, &u8LengthDomainName); + /* MRP_DomainName */ + pDomainName = (char *)wmem_alloc(wmem_packet_scope(), u8LengthDomainName+1); + tvb_memcpy(tvb, (guint8 *) pDomainName, offset, u8LengthDomainName); + pDomainName[u8LengthDomainName] = '\0'; + proto_tree_add_string (tree, hf_pn_io_mrp_domain_name, tvb, offset, u8LengthDomainName, pDomainName); + offset += u8LengthDomainName; + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + if ((offset - iStartOffset) < u16BodyLength) + { + offset = dissect_blocks(tvb, offset, pinfo, tree, drep); + } + } + else if (u8BlockVersionLow == 1) /*dissect LowVersion == 1 */ + { + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Number of Mrp Instances */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instances, &u8NumberOfMrpInstances); + if (u8NumberOfMrpInstances > 0xf) { + expert_add_info_format(pinfo, item, &ei_pn_io_mrp_instances, "Number of MrpInstances greater 0x0f is (0x%x)", u8NumberOfMrpInstances); + return offset; + } + while(u8NumberOfMrpInstances > 0) + { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + u8NumberOfMrpInstances--; + } + } + return offset; +} + + +static int +dissect_PDInterfaceMrpDataReal_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BodyLength) +{ + e_guid_t uuid; + guint16 u16Role; + guint16 u16Version; + guint8 u8LengthDomainName; + guint8 u8NumberOfMrpInstances; + char *pDomainName; + int endoffset = offset + u16BodyLength; + + /* added blockversion 1 */ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow > 2) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + if (u8BlockVersionLow < 2) /* dissect low versions 0 and 1 */ + { + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + /* MRP_Role */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_role, &u16Role); + + if (u8BlockVersionLow == 1) { + /* MRP_Version */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_version, &u16Version); + } + /* MRP_LengthDomainName */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_length_domain_name, &u8LengthDomainName); + /* MRP_DomainName */ + pDomainName = (char *)wmem_alloc(wmem_packet_scope(), u8LengthDomainName+1); + tvb_memcpy(tvb, (guint8 *) pDomainName, offset, u8LengthDomainName); + pDomainName[u8LengthDomainName] = '\0'; + proto_tree_add_string (tree, hf_pn_io_mrp_domain_name, tvb, offset, u8LengthDomainName, pDomainName); + offset += u8LengthDomainName; + + if (u8BlockVersionLow == 0) { + /* MRP_Version */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_version, &u16Version); + } + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + while(endoffset > offset) + { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + } + } + else if (u8BlockVersionLow == 2) + { + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Number of Mrp Instances */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instances, &u8NumberOfMrpInstances); + if (u8NumberOfMrpInstances > 0xf) { + expert_add_info_format(pinfo, item, &ei_pn_io_mrp_instances, "Number of MrpInstances greater 0x0f is (0x%x)", u8NumberOfMrpInstances); + return offset; + } + while(u8NumberOfMrpInstances > 0) + { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + u8NumberOfMrpInstances--; + } + } + return offset; +} + + +static int +dissect_PDInterfaceMrpDataCheck_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + e_guid_t uuid; + guint32 u32Check; + guint8 u8NumberOfMrpInstances; + + /* BlockVersionLow == 1 added */ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow > 1) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + if (u8BlockVersionLow == 0) + { + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + + /* MRP_Check */ + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_mrm, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_mrpdomain, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_reserved_1, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_reserved_2, &u32Check); + offset +=4; /* MRP_Check (32 bit) done */ + } + else if (u8BlockVersionLow == 1) + { + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Number of Mrp Instances */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instances, &u8NumberOfMrpInstances); + if (u8NumberOfMrpInstances > 0xf) { + expert_add_info_format(pinfo, item, &ei_pn_io_mrp_instances, "Number of MrpInstances greater 0x0f is (0x%x)", u8NumberOfMrpInstances); + return offset; + } + while(u8NumberOfMrpInstances > 0) + { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + u8NumberOfMrpInstances--; + } + } + + return offset; +} + + +static int +dissect_PDPortMrpData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + e_guid_t uuid; + guint8 u8MrpInstance; + + /* added BlockVersionLow == 1 */ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow > 1) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + if (u8BlockVersionLow == 0) { + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + } + else /*if (u8BlockVersionLow == 1) */ + { + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Mrp Instance */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instance, &u8MrpInstance); + } + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + return offset; +} + + +static int +dissect_MrpManagerParams_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16Prio; + guint16 u16TOPchgT; + guint16 u16TOPNRmax; + guint16 u16TSTshortT; + guint16 u16TSTdefaultT; + guint16 u16TSTNRmax; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MRP_Prio */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_prio, &u16Prio); + /* MRP_TOPchgT */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_topchgt, &u16TOPchgT); + /* MRP_TOPNRmax */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_topnrmax, &u16TOPNRmax); + /* MRP_TSTshortT */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_tstshortt, &u16TSTshortT); + /* MRP_TSTdefaultT */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_tstdefaultt, &u16TSTdefaultT); + /* MSP_TSTNRmax */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_tstnrmax, &u16TSTNRmax); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + return offset; +} + + +static int +dissect_MrpRTMode(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32RTMode; + + + /* MRP_RTMode */ + sub_item = proto_tree_add_item(tree, hf_pn_io_mrp_rtmode, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_mrp_rtmode); + + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_mrp_rtmode_reserved2, &u32RTMode); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_mrp_rtmode_reserved1, &u32RTMode); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_mrp_rtmode_rtclass3, &u32RTMode); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_mrp_rtmode_rtclass12, &u32RTMode); + + return offset; +} + + +static int +dissect_MrpRTModeManagerData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16TSTNRmax; + guint16 u16TSTdefaultT; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MSP_TSTNRmax */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_tstnrmax, &u16TSTNRmax); + /* MRP_TSTdefaultT */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_tstdefaultt, &u16TSTdefaultT); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MRP_RTMode */ + offset = dissect_MrpRTMode(tvb, offset, pinfo, tree, item, drep); + + return offset; +} + + +static int +dissect_MrpRingStateData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16RingState; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MRP_RingState */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_ring_state, &u16RingState); + + return offset; +} + + +static int +dissect_MrpRTStateData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16RTState; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MRP_RTState */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_rt_state, &u16RTState); + + return offset; +} + + +static int +dissect_MrpClientParams_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16MRP_LNKdownT; + guint16 u16MRP_LNKupT; + guint16 u16MRP_LNKNRmax; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MRP_LNKdownT */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_lnkdownt, &u16MRP_LNKdownT); + /* MRP_LNKupT */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_lnkupt, &u16MRP_LNKupT); + /* MRP_LNKNRmax u16 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_lnknrmax, &u16MRP_LNKNRmax); + + return offset; +} + + +static int +dissect_MrpRTModeClientData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MRP_RTMode */ + offset = dissect_MrpRTMode(tvb, offset, pinfo, tree, item, drep); + + return offset; +} + + +static int +dissect_CheckSyncDifference_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16CheckSyncMode; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + sub_item = proto_tree_add_item(tree, hf_pn_io_check_sync_mode, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_check_sync_mode); + + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_check_sync_mode_reserved, &u16CheckSyncMode); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_check_sync_mode_sync_master, &u16CheckSyncMode); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_check_sync_mode_cable_delay, &u16CheckSyncMode); + + + proto_item_append_text(sub_item, "CheckSyncMode: SyncMaster:%d, CableDelay:%d", + (u16CheckSyncMode >> 1) & 1, u16CheckSyncMode & 1); + + proto_item_append_text(item, " : SyncMaster:%d, CableDelay:%d", + (u16CheckSyncMode >> 1) & 1, u16CheckSyncMode & 1); + + return offset; +} + + +static int +dissect_CheckMAUTypeDifference_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16MAUTypeMode; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mau_type_mode, &u16MAUTypeMode); + + proto_item_append_text(item, ": MAUTypeMode:%s", + val_to_str(u16MAUTypeMode, pn_io_mau_type_mode, "0x%x")); + + return offset; +} + + +/* dissect the AdjustDomainBoundary blocks */ +static int +dissect_AdjustDomainBoundary_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32DomainBoundary; + guint32 u32DomainBoundaryIngress; + guint32 u32DomainBoundaryEgress; + guint16 u16AdjustProperties; + + + if (u8BlockVersionHigh != 1 || (u8BlockVersionLow != 0 && u8BlockVersionLow != 1)) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + switch (u8BlockVersionLow) { + case(0): + /* DomainBoundary */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_domain_boundary, &u32DomainBoundary); + /* AdjustProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + proto_item_append_text(item, ": Boundary:0x%x, Properties:0x%x", + u32DomainBoundary, u16AdjustProperties); + + break; + case(1): + /* DomainBoundaryIngress */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_domain_boundary_ingress, &u32DomainBoundaryIngress); + /* DomainBoundaryEgress */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_domain_boundary_egress, &u32DomainBoundaryEgress); + /* AdjustProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + proto_item_append_text(item, ": BoundaryIngress:0x%x, BoundaryEgress:0x%x, Properties:0x%x", + u32DomainBoundaryIngress, u32DomainBoundaryEgress, u16AdjustProperties); + + break; + default: + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + return offset; +} + + +/* dissect the AdjustMulticastBoundary blocks */ +static int +dissect_AdjustMulticastBoundary_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32MulticastBoundary; + guint16 u16AdjustProperties; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* Boundary */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_multicast_boundary, &u32MulticastBoundary); + /* AdjustProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + proto_item_append_text(item, ": Boundary:0x%x, Properties:0x%x", + u32MulticastBoundary, u16AdjustProperties); + + return offset; +} + + +/* dissect the AdjustMAUType block */ +static int +dissect_AdjustMAUType_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16MAUType; + guint16 u16AdjustProperties; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MAUType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mau_type, &u16MAUType); + /* AdjustProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + proto_item_append_text(item, ": MAUType:%s, Properties:0x%x", + val_to_str(u16MAUType, pn_io_mau_type, "0x%x"), + u16AdjustProperties); + + return offset; +} + + +/* dissect the CheckMAUType block */ +static int +dissect_CheckMAUType_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16MAUType; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* MAUType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mau_type, &u16MAUType); + + proto_item_append_text(item, ": MAUType:%s", + val_to_str(u16MAUType, pn_io_mau_type, "0x%x")); + + return offset; +} + + +/* dissect the CheckLineDelay block */ +static int +dissect_CheckLineDelay_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32LineDelay; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* LineDelay */ + offset = dissect_Line_Delay(tvb, offset, pinfo, tree, drep, &u32LineDelay); + + proto_item_append_text(item, ": LineDelay:%uns", u32LineDelay); + + return offset; +} + + +/* dissect the CheckPeers block */ +static int +dissect_CheckPeers_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint8 u8NumberOfPeers; + guint8 u8I; + guint8 u8LengthPeerPortID; + char *pPeerPortID; + guint8 u8LengthPeerChassisID; + char *pPeerChassisID; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* NumberOfPeers */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_peers, &u8NumberOfPeers); + + u8I = u8NumberOfPeers; + while (u8I--) { + /* LengthPeerPortID */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_peer_port_id, &u8LengthPeerPortID); + /* PeerPortID */ + pPeerPortID = (char *)wmem_alloc(wmem_packet_scope(), u8LengthPeerPortID+1); + tvb_memcpy(tvb, (guint8 *) pPeerPortID, offset, u8LengthPeerPortID); + pPeerPortID[u8LengthPeerPortID] = '\0'; + proto_tree_add_string (tree, hf_pn_io_peer_port_id, tvb, offset, u8LengthPeerPortID, pPeerPortID); + offset += u8LengthPeerPortID; + + /* LengthPeerChassisID */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_peer_chassis_id, &u8LengthPeerChassisID); + /* PeerChassisID */ + pPeerChassisID = (char *)wmem_alloc(wmem_packet_scope(), u8LengthPeerChassisID+1); + tvb_memcpy(tvb, (guint8 *) pPeerChassisID, offset, u8LengthPeerChassisID); + pPeerChassisID[u8LengthPeerChassisID] = '\0'; + proto_tree_add_string (tree, hf_pn_io_peer_chassis_id, tvb, offset, u8LengthPeerChassisID, pPeerChassisID); + offset += u8LengthPeerChassisID; + } + + proto_item_append_text(item, ": NumberOfPeers:%u", u8NumberOfPeers); + + return offset; +} + + +/* dissect the AdjustPortState block */ +static int +dissect_AdjustPortState_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16PortState; + guint16 u16AdjustProperties; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* PortState */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_port_state, &u16PortState); + /* AdjustProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + proto_item_append_text(item, ": PortState:%s, Properties:0x%x", + val_to_str(u16PortState, pn_io_port_state, "0x%x"), + u16AdjustProperties); + + return offset; +} + + +/* dissect the CheckPortState block */ +static int +dissect_CheckPortState_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16PortState; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* PortState */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_port_state, &u16PortState); + + proto_item_append_text(item, ": %s", + val_to_str(u16PortState, pn_io_port_state, "0x%x")); + return offset; +} + + +/* dissect the PDPortFODataReal block */ +static int +dissect_PDPortFODataReal_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint32 u32FiberOpticType; + guint32 u32FiberOpticCableType; + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* FiberOpticType */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fiber_optic_type, &u32FiberOpticType); + + /* FiberOpticCableType */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fiber_optic_cable_type, &u32FiberOpticCableType); + + /* optional: FiberOpticManufacturerSpecific */ + if (u16BodyLength != 10) { + dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + } + + return offset; +} + + +/* dissect the FiberOpticManufacturerSpecific block */ +static int +dissect_FiberOpticManufacturerSpecific_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint8 u8VendorIDHigh; + guint8 u8VendorIDLow; + guint16 u16VendorBlockType; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* x8 VendorIDHigh */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_id_high, &u8VendorIDHigh); + /* x8 VendorIDLow */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_id_low, &u8VendorIDLow); + + /* VendorBlockType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_vendor_block_type, &u16VendorBlockType); + /* Data */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u16BodyLength-4, "Data"); + + return offset; +} + + +/* dissect the FiberOpticDiagnosisInfo block */ +static int +dissect_FiberOpticDiagnosisInfo_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32FiberOpticPowerBudget; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* decode the u32FiberOpticPowerBudget better */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_maintenance_required_power_budget, &u32FiberOpticPowerBudget); + + return offset; +} + +/* dissect the AdjustMAUTypeExtension block */ +static int +dissect_AdjustMAUTypeExtension_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16MauTypeExtension; + guint16 u16AdjustProperties; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MauTypeExtension */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_mau_type_extension, &u16MauTypeExtension); + + /* Properties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + return offset; +} + +/* dissect the PDPortFODataAdjust block */ +static int +dissect_PDPortFODataAdjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32FiberOpticType; + guint32 u32FiberOpticCableType; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* FiberOpticType */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fiber_optic_type, &u32FiberOpticType); + + /* FiberOpticCableType */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fiber_optic_cable_type, &u32FiberOpticCableType); + +/* + proto_item_append_text(item, ": %s", + val_to_str(u16PortState, pn_io_port_state, "0x%x"));*/ + + return offset; +} + + +/* dissect the PDPortFODataCheck block */ +static int +dissect_PDPortFODataCheck_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32FiberOpticPowerBudget; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MaintenanceRequiredPowerBudget */ + /* XXX - decode the u32FiberOpticPowerBudget better */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_maintenance_required_power_budget, &u32FiberOpticPowerBudget); + + /* MaintenanceDemandedPowerBudget */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_maintenance_demanded_power_budget, &u32FiberOpticPowerBudget); + + /* ErrorPowerBudget */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_error_power_budget, &u32FiberOpticPowerBudget); + +/* + proto_item_append_text(item, ": %s", + val_to_str(u16PortState, pn_io_port_state, "0x%x"));*/ + + return offset; +} + +/* dissect the AdjustPeerToPeerBoundary block */ +static int +dissect_AdjustPeerToPeerBoundary_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32PeerToPeerBoundary; + guint16 u16AdjustProperties; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + sub_item = proto_tree_add_item(tree, hf_pn_io_peer_to_peer_boundary_value, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_peer_to_peer_boundary); + + /* PeerToPeerBoundary.Bit0 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_peer_to_peer_boundary_value_bit0, &u32PeerToPeerBoundary); + + /* PeerToPeerBoundary.Bit1 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_peer_to_peer_boundary_value_bit1, &u32PeerToPeerBoundary); + + /* PeerToPeerBoundary.Bit2 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_peer_to_peer_boundary_value_bit2, &u32PeerToPeerBoundary); + + /* PeerToPeerBoundary.OtherBits */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_peer_to_peer_boundary_value_otherbits, &u32PeerToPeerBoundary); + + /* Properties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + return offset; +} + + +/* dissect the AdjustDCPBoundary block */ +static int +dissect_AdjustDCPBoundary_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32DcpBoundary; + guint16 u16AdjustProperties; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + sub_item = proto_tree_add_item(tree, hf_pn_io_dcp_boundary_value, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_dcp_boundary); + + /* DcpBoundary.Bit0 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_dcp_boundary_value_bit0, &u32DcpBoundary); + + /* DcpBoundary.Bit1 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_dcp_boundary_value_bit1, &u32DcpBoundary); + + /* DcpBoundary.OtherBits */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_dcp_boundary_value_otherbits, &u32DcpBoundary); + + /* Properties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_adjust_properties, &u16AdjustProperties); + + return offset; +} + +static int +dissect_MrpInstanceDataAdjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BodyLength) +{ + guint8 u8MrpInstance; + e_guid_t uuid; + guint16 u16Role; + guint8 u8LengthDomainName; + char* pDomainName; + int endoffset = offset + u16BodyLength; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Mrp Instance */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instance, &u8MrpInstance); + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + /* MRP_Role */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_role, &u16Role); + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + /* MRP_LengthDomainName */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_length_domain_name, &u8LengthDomainName); + /* MRP_DomainName */ + pDomainName = (char *)wmem_alloc(wmem_packet_scope(), u8LengthDomainName+1); + tvb_memcpy(tvb, (guint8 *) pDomainName, offset, u8LengthDomainName); + pDomainName[u8LengthDomainName] = '\0'; + proto_tree_add_string (tree, hf_pn_io_mrp_domain_name, tvb, offset, u8LengthDomainName, pDomainName); + offset += u8LengthDomainName; + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + while(endoffset > offset) + { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + } + + return offset; +} + +static int +dissect_MrpInstanceDataReal_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BodyLength) +{ + guint8 u8MrpInstance; + e_guid_t uuid; + guint16 u16Role; + guint16 u16Version; + guint8 u8LengthDomainName; + char* pDomainName; + int endoffset = offset + u16BodyLength; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Mrp Instance */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instance, &u8MrpInstance); + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + /* MRP_Role */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_role, &u16Role); + /* MRP_Version */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_version, &u16Version); + /* MRP_LengthDomainName */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_length_domain_name, &u8LengthDomainName); + /* MRP_DomainName */ + pDomainName = (char *)wmem_alloc(wmem_packet_scope(), u8LengthDomainName+1); + tvb_memcpy(tvb, (guint8 *) pDomainName, offset, u8LengthDomainName); + pDomainName[u8LengthDomainName] = '\0'; + proto_tree_add_string (tree, hf_pn_io_mrp_domain_name, tvb, offset, u8LengthDomainName, pDomainName); + offset += u8LengthDomainName; + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + while(endoffset > offset) + { + offset = dissect_a_block(tvb, offset, pinfo, tree, drep); + } + return offset; +} + +static int +dissect_MrpInstanceDataCheck_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BodyLength _U_) +{ + guint8 u8MrpInstance; + guint32 u32Check; + e_guid_t uuid; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + /* Padding one byte */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 1); + /* Mrp Instance */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_instance, &u8MrpInstance); + /* MRP_DomainUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_domain_uuid, &uuid); + + /* MRP_Check */ + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_mrm, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_mrpdomain, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_reserved_1, &u32Check); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_mrp_check_reserved_2, &u32Check); + offset +=4; /* MRP_Check (32 bit) done */ + + return offset; +} + +/* PDInterfaceAdjust */ +static int +dissect_PDInterfaceAdjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32SMultipleInterfaceMode; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; +} + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); +/* MultipleInterfaceMode */ + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_MultipleInterfaceMode_NameOfDevice, &u32SMultipleInterfaceMode); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_MultipleInterfaceMode_reserved_1, &u32SMultipleInterfaceMode); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_MultipleInterfaceMode_reserved_2, &u32SMultipleInterfaceMode); + return offset; +} + +/* PDPortStatistic for one subslot */ +static int +dissect_PDPortStatistic_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32StatValue; + guint16 u16CounterStatus; + proto_item *sub_item; + proto_tree *sub_tree; + if (u8BlockVersionHigh != 1 || (u8BlockVersionLow != 0 && u8BlockVersionLow != 1)) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + switch (u8BlockVersionLow) { + case(0): + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + break; + case(1): + sub_item = proto_tree_add_item(tree, hf_pn_io_pdportstatistic_counter_status, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_counter_status); + /* bit 0 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_ifInOctets, &u16CounterStatus); + /* bit 1 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_ifOutOctets, &u16CounterStatus); + /* bit 2 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_ifInDiscards, &u16CounterStatus); + /* bit 3 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_ifOutDiscards, &u16CounterStatus); + /* bit 4 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_ifInErrors, &u16CounterStatus); + /* bit 5 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_ifOutErrors, &u16CounterStatus); + /* bit 6-15 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_pdportstatistic_counter_status_reserved, &u16CounterStatus); + break; + default: /* will not execute because of the line preceding the switch */ + break; + } + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pdportstatistic_ifInOctets, &u32StatValue); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pdportstatistic_ifOutOctets, &u32StatValue); + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pdportstatistic_ifInDiscards, &u32StatValue); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pdportstatistic_ifOutDiscards, &u32StatValue); + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pdportstatistic_ifInErrors, &u32StatValue); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pdportstatistic_ifOutErrors, &u32StatValue); + + return offset; +} + + +/* dissect the PDInterfaceDataReal block */ +static int +dissect_PDInterfaceDataReal_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint8 u8LengthOwnChassisID; + char *pOwnChassisID; + guint8 mac[6]; + guint32 ip; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* LengthOwnChassisID */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_length_own_chassis_id, &u8LengthOwnChassisID); + /* OwnChassisID */ + pOwnChassisID = (char *)wmem_alloc(wmem_packet_scope(), u8LengthOwnChassisID+1); + tvb_memcpy(tvb, (guint8 *) pOwnChassisID, offset, u8LengthOwnChassisID); + pOwnChassisID[u8LengthOwnChassisID] = '\0'; + proto_tree_add_string (tree, hf_pn_io_own_chassis_id, tvb, offset, u8LengthOwnChassisID, pOwnChassisID); + offset += u8LengthOwnChassisID; + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* MACAddressValue */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_io_macadd, mac); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* IPAddress */ + offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_io_ip_address, &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_io_subnetmask, &ip); + /*proto_item_append_text(block_item, ", Subnet: %s", ip_to_str((guint8*)&ip));*/ + + /* StandardGateway */ + offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_io_standard_gateway, &ip); + /*proto_item_append_text(block_item, ", Router: %s", ip_to_str((guint8*)&ip));*/ + + + return offset; +} + + +/* dissect the PDSyncData block */ +static int +dissect_PDSyncData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16SlotNr; + guint16 u16SubslotNr; + e_guid_t uuid; + guint32 u32ReservedIntervalBegin; + guint32 u32ReservedIntervalEnd; + guint32 u32PLLWindow; + guint32 u32SyncSendFactor; + guint16 u16SendClockFactor; + guint16 u16SyncProperties; + guint16 u16SyncFrameAddress; + guint16 u16PTCPTimeoutFactor; + guint16 u16PTCPTakeoverTimeoutFactor; + guint16 u16PTCPMasterStartupTime; + guint8 u8MasterPriority1; + guint8 u8MasterPriority2; + guint8 u8LengthSubdomainName; + char *pSubdomainName; + + + if (u8BlockVersionHigh != 1) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + switch (u8BlockVersionLow) { + case(0): + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* PTCPSubdomainID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_subdomain_id, &uuid); + /* IRDataID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ir_data_id, &uuid); + /* ReservedIntervalBegin */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_reserved_interval_begin, &u32ReservedIntervalBegin); + /* ReservedIntervalEnd */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_reserved_interval_end, &u32ReservedIntervalEnd); + /* PLLWindow enum */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pllwindow, &u32PLLWindow); + /* SyncSendFactor 32 enum */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_sync_send_factor, &u32SyncSendFactor); + /* SendClockFactor 16 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_send_clock_factor, &u16SendClockFactor); + /* SyncProperties 16 bitfield */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sync_properties, &u16SyncProperties); + /* SyncFrameAddress 16 bitfield */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sync_frame_address, &u16SyncFrameAddress); + /* PTCPTimeoutFactor 16 enum */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_timeout_factor, &u16PTCPTimeoutFactor); + + proto_item_append_text(item, ": Slot:0x%x/0x%x, Interval:%u-%u, PLLWin:%u, Send:%u, Clock:%u", + u16SlotNr, u16SubslotNr, u32ReservedIntervalBegin, u32ReservedIntervalEnd, + u32PLLWindow, u32SyncSendFactor, u16SendClockFactor); + break; + case(2): + /* PTCPSubdomainID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_subdomain_id, &uuid); + /* ReservedIntervalBegin */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_reserved_interval_begin, &u32ReservedIntervalBegin); + /* ReservedIntervalEnd */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_reserved_interval_end, &u32ReservedIntervalEnd); + /* PLLWindow enum */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_pllwindow, &u32PLLWindow); + /* SyncSendFactor 32 enum */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_sync_send_factor, &u32SyncSendFactor); + /* SendClockFactor 16 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_send_clock_factor, &u16SendClockFactor); + /* PTCPTimeoutFactor 16 enum */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_timeout_factor, &u16PTCPTimeoutFactor); + /* PTCPTakeoverTimeoutFactor 16 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_takeover_timeout_factor, &u16PTCPTakeoverTimeoutFactor); + /* PTCPMasterStartupTime 16 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_master_startup_time, &u16PTCPMasterStartupTime); + /* SyncProperties 16 bitfield */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sync_properties, &u16SyncProperties); + /* PTCP_MasterPriority1 */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_master_priority_1, &u8MasterPriority1); + /* PTCP_MasterPriority2 */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_master_priority_2, &u8MasterPriority2); + /* PTCPLengthSubdomainName */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, tree, drep, + hf_pn_io_ptcp_length_subdomain_name, &u8LengthSubdomainName); + /* PTCPSubdomainName */ + pSubdomainName = (char *)wmem_alloc(wmem_packet_scope(), u8LengthSubdomainName+1); + tvb_memcpy(tvb, (guint8 *) pSubdomainName, offset, u8LengthSubdomainName); + pSubdomainName[u8LengthSubdomainName] = '\0'; + proto_tree_add_string (tree, hf_pn_io_ptcp_subdomain_name, tvb, offset, u8LengthSubdomainName, pSubdomainName); + offset += u8LengthSubdomainName; + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + proto_item_append_text(item, ": Interval:%u-%u, PLLWin:%u, Send:%u, Clock:%u", + u32ReservedIntervalBegin, u32ReservedIntervalEnd, + u32PLLWindow, u32SyncSendFactor, u16SendClockFactor); + break; + default: + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + } + + return offset; +} + + +/* dissect the PDIRData block */ +static int +dissect_PDIRData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + /* versions decoded are High: 1 and LOW 0..2 */ + if (u8BlockVersionHigh != 1 || (u8BlockVersionLow > 2 ) ) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + + proto_item_append_text(item, ": Slot:0x%x/0x%x", + u16SlotNr, u16SubslotNr); + + /* PDIRGlobalData */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + if (u8BlockVersionLow == 0) { + /* PDIRFrameData */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + } else if (u8BlockVersionLow == 1) { + /* [PDIRFrameData] */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + /* PDIRBeginEndData */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + }else if (u8BlockVersionLow == 2) { + /* [PDIRFrameData] */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + /* PDIRBeginEndData */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + } + return offset; +} + + +/* dissect the PDIRGlobalData block */ +static int +dissect_PDIRGlobalData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + e_guid_t uuid; + guint32 u32MaxBridgeDelay; + guint32 u32NumberOfPorts; + guint32 u32MaxPortTxDelay; + guint32 u32MaxPortRxDelay; + guint32 u32MaxLineRxDelay; + guint32 u32YellowTime; + guint32 u32Tmp; + + /* added blockversion 2 */ + if (u8BlockVersionHigh != 1 || (u8BlockVersionLow > 2)) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* IRDataID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ir_data_id, &uuid); + + if (u8BlockVersionLow <= 2) { + /* MaxBridgeDelay */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_max_bridge_delay, &u32MaxBridgeDelay); + /* NumberOfPorts */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_ports, &u32NumberOfPorts); + u32Tmp = u32NumberOfPorts; + + while (u32Tmp--) { + /* MaxPortTxDelay */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_max_port_tx_delay, &u32MaxPortTxDelay); + /* MaxPortRxDelay */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_max_port_rx_delay, &u32MaxPortRxDelay); + if (u8BlockVersionLow >= 2) { + /* MaxLineRxDelay */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_max_line_rx_delay, &u32MaxLineRxDelay); + /* YellowTime */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_yellowtime, &u32YellowTime); + } + } + proto_item_append_text(item, ": MaxBridgeDelay:%u, NumberOfPorts:%u", + u32MaxBridgeDelay, u32NumberOfPorts); + + } + return offset; +} + + +/* dissect the PDIRFrameData block */ +static int +dissect_PDIRFrameData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint32 u32FrameSendOffset; + guint32 u32FrameDataProperties; + guint16 u16DataLength; + guint16 u16ReductionRatio; + guint16 u16Phase; + guint16 u16FrameID; + guint16 u16Ethertype; + guint8 u8RXPort; + guint8 u8FrameDetails; + guint8 u8NumberOfTxPortGroups; + guint8 u8TxPortGroupArray; + guint16 u16TxPortGroupArraySize; + guint16 u16EndOffset; + guint16 n = 0; + proto_item *sub_item; + proto_tree *sub_tree; + + /* added low version 1 */ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow > 1) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + u16EndOffset = offset + u16BodyLength -2; + if (u8BlockVersionLow > 0) { + /* for low version 1 FrameDataProperties is added */ + sub_item = proto_tree_add_item(tree, hf_pn_io_frame_data_properties, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_FrameDataProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_data_properties_forwarding_Mode, &u32FrameDataProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_data_properties_FastForwardingMulticastMACAdd, &u32FrameDataProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_data_properties_FragmentMode, &u32FrameDataProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_data_properties_reserved_1, &u32FrameDataProperties); + offset = + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_data_properties_reserved_2, &u32FrameDataProperties); + } + /* dissect all IR frame data */ + while (offset < u16EndOffset) + { + proto_item *ir_frame_data_sub_item; + proto_tree *ir_frame_data_tree; + + n++; + + /* new subtree for each IR frame */ + ir_frame_data_sub_item = proto_tree_add_item(tree, hf_pn_io_ir_frame_data, tvb, offset, 17, ENC_NA); + ir_frame_data_tree = proto_item_add_subtree(ir_frame_data_sub_item, ett_pn_io_ir_frame_data); + + /* FrameSendOffset */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_frame_send_offset, &u32FrameSendOffset); + /* DataLength */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_data_length, &u16DataLength); + /* ReductionRatio */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_reduction_ratio, &u16ReductionRatio); + /* Phase */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_phase, &u16Phase); + /* FrameID */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_frame_id, &u16FrameID); + + /* Ethertype */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_ethertype, &u16Ethertype); + /* RxPort */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, ir_frame_data_tree, drep, + hf_pn_io_rx_port, &u8RXPort); + /* FrameDetails */ + sub_item = proto_tree_add_item(ir_frame_data_tree, hf_pn_io_frame_details, tvb, offset, 1, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_frame_defails); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_details_sync_frame, &u8FrameDetails); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_details_meaning_frame_send_offset, &u8FrameDetails); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_frame_details_reserved, &u8FrameDetails); + /* TxPortGroup */ + u8NumberOfTxPortGroups = tvb_get_guint8(tvb, offset); + sub_item = proto_tree_add_uint(ir_frame_data_tree, hf_pn_io_nr_of_tx_port_groups, + tvb, offset, 1, u8NumberOfTxPortGroups); + offset++; + if ((u8NumberOfTxPortGroups > 21) || ((u8NumberOfTxPortGroups & 0x1) !=1)) { + expert_add_info(pinfo, sub_item, &ei_pn_io_nr_of_tx_port_groups); + } + + /* TxPortArray */ + u16TxPortGroupArraySize = (u8NumberOfTxPortGroups + 7 / 8); + sub_item = proto_tree_add_item(ir_frame_data_tree, hf_pn_io_TxPortGroupProperties, + tvb, offset, u16TxPortGroupArraySize, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_GroupProperties); + while (u16TxPortGroupArraySize > 0) + { + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit0, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit1, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit2, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit3, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit4, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit5, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit6, &u8TxPortGroupArray); + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_TxPortGroupProperties_bit7, &u8TxPortGroupArray); + + offset+=1; + u16TxPortGroupArraySize --; + } + + /* align to next dataset */ + offset = dissect_pn_align4(tvb, offset, pinfo, ir_frame_data_tree); + + proto_item_append_text(ir_frame_data_tree, ": Offset:%u, Len:%u, Ratio:%u, Phase:%u, FrameID:0x%04x", + u32FrameSendOffset, u16DataLength, u16ReductionRatio, u16Phase, u16FrameID); + + } + + proto_item_append_text(item, ": Frames:%u", n); + + return offset; +} + + +static int +dissect_PDIRBeginEndData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint16 u16StartOfRedFrameID; + guint16 u16EndOfRedFrameID; + guint32 u32NumberOfPorts; + guint32 u32NumberOfAssignments; + guint32 u32NumberOfPhases; + guint32 u32RedOrangePeriodBegin; + guint32 u32OrangePeriodBegin; + guint32 u32GreenPeriodBegin; + guint16 u16TXPhaseAssignment; + guint16 u16RXPhaseAssignment; + guint32 u32SubStart; + guint32 u32Tmp; + guint32 u32Tmp2; + guint32 u32TxRedOrangePeriodBegin[0x11] = {0}; + guint32 u32TxOrangePeriodBegin [0x11] = {0}; + guint32 u32TxGreenPeriodBegin [0x11] = {0}; + guint32 u32RxRedOrangePeriodBegin[0x11] = {0}; + guint32 u32RxOrangePeriodBegin [0x11] = {0}; + guint32 u32RxGreenPeriodBegin [0x11] = {0}; + guint32 u32PortIndex; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_start_of_red_frame_id, &u16StartOfRedFrameID); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_end_of_red_frame_id, &u16EndOfRedFrameID); + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_ports, &u32NumberOfPorts); + u32Tmp2 = u32NumberOfPorts; + while (u32Tmp2--) { + proto_item *ir_begin_end_port_sub_item; + proto_tree *ir_begin_end_port_tree; + + /* new subtree for each Port */ + ir_begin_end_port_sub_item = proto_tree_add_item(tree, hf_pn_io_ir_begin_end_port, tvb, offset, 0, ENC_NA); + ir_begin_end_port_tree = proto_item_add_subtree(ir_begin_end_port_sub_item, ett_pn_io_ir_begin_end_port); + u32SubStart = offset; + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_number_of_assignments, &u32NumberOfAssignments); + u32Tmp = u32NumberOfAssignments; + u32PortIndex = 0; + if (u32Tmp <= 0x10) + { + while (u32Tmp--) { + /* TXBeginEndAssignment */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_red_orange_period_begin_tx, &u32RedOrangePeriodBegin); + u32TxRedOrangePeriodBegin[u32PortIndex] = u32RedOrangePeriodBegin; + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_orange_period_begin_tx, &u32OrangePeriodBegin); + u32TxOrangePeriodBegin[u32PortIndex]= u32OrangePeriodBegin; + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_green_period_begin_tx, &u32GreenPeriodBegin); + u32TxGreenPeriodBegin[u32PortIndex] = u32GreenPeriodBegin; + + /* RXBeginEndAssignment */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_red_orange_period_begin_rx, &u32RedOrangePeriodBegin); + u32RxRedOrangePeriodBegin[u32PortIndex] = u32RedOrangePeriodBegin; + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_orange_period_begin_rx, &u32OrangePeriodBegin); + u32RxOrangePeriodBegin[u32PortIndex]= u32OrangePeriodBegin; + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_green_period_begin_rx, &u32GreenPeriodBegin); + u32RxGreenPeriodBegin[u32PortIndex] = u32GreenPeriodBegin; + + u32PortIndex++; + } + } + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ir_begin_end_port_tree, drep, + hf_pn_io_number_of_phases, &u32NumberOfPhases); + u32Tmp = u32NumberOfPhases; + if (u32Tmp <= 0x10) + { + while (u32Tmp--) { + proto_item *ir_begin_tx_phase_sub_item; + proto_tree *ir_begin_tx_phase_tree; + + /* new subtree for TXPhaseAssignment */ + ir_begin_tx_phase_sub_item = proto_tree_add_item(ir_begin_end_port_tree, + hf_pn_ir_tx_phase_assignment, tvb, offset, 0, ENC_NA); + ir_begin_tx_phase_tree = proto_item_add_subtree(ir_begin_tx_phase_sub_item, ett_pn_io_ir_tx_phase); + /* bit 0..3 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_begin_value, &u16TXPhaseAssignment); + /* bit 4..7 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_orange_begin, &u16TXPhaseAssignment); + /* bit 8..11 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_end_reserved, &u16TXPhaseAssignment); + /* bit 12..15 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_reserved, &u16TXPhaseAssignment); + + proto_item_append_text(ir_begin_tx_phase_sub_item, + ": 0x%x, RedOrangePeriodBegin: %d, OrangePeriodBegin: %d, GreenPeriodBegin: %d", + u16TXPhaseAssignment, + u32TxRedOrangePeriodBegin[u16TXPhaseAssignment & 0x0F], + u32TxOrangePeriodBegin[(u16TXPhaseAssignment & 0x0F0) >> 4], + u32TxGreenPeriodBegin[(u16TXPhaseAssignment & 0x0F00)>> 8]); + + /* new subtree for RXPhaseAssignment */ + ir_begin_tx_phase_sub_item = proto_tree_add_item(ir_begin_end_port_tree, + hf_pn_ir_rx_phase_assignment, tvb, offset, 0, ENC_NA); + ir_begin_tx_phase_tree = proto_item_add_subtree(ir_begin_tx_phase_sub_item, ett_pn_io_ir_rx_phase); + /* bit 0..3 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_begin_value, &u16RXPhaseAssignment); + /* bit 4..7 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_orange_begin, &u16RXPhaseAssignment); + /* bit 8..11 */ + dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_end_reserved, &u16RXPhaseAssignment); + /* bit 12..15 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ir_begin_tx_phase_tree, drep, + hf_pn_io_tx_phase_assignment_reserved, &u16RXPhaseAssignment); + + proto_item_append_text(ir_begin_tx_phase_sub_item, + ": 0x%x, RedOrangePeriodBegin: %d, OrangePeriodBegin: %d, GreenPeriodBegin: %d", + u16RXPhaseAssignment, + u32RxRedOrangePeriodBegin[u16RXPhaseAssignment & 0x0F], + u32RxOrangePeriodBegin[(u16RXPhaseAssignment & 0x0F0) >> 4], + u32RxGreenPeriodBegin[(u16RXPhaseAssignment & 0x0F00)>> 8]); + } + } + proto_item_append_text(ir_begin_end_port_sub_item, ": Assignments:%u, Phases:%u", + u32NumberOfAssignments, u32NumberOfPhases); + + proto_item_set_len(ir_begin_end_port_sub_item, offset - u32SubStart); + } + + proto_item_append_text(item, ": StartOfRedFrameID: 0x%x, EndOfRedFrameID: 0x%x, Ports: %u", + u16StartOfRedFrameID, u16EndOfRedFrameID, u32NumberOfPorts); + + return offset+u16BodyLength; +} + + +/* dissect the DiagnosisData block */ +static int +dissect_DiagnosisData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 body_length) +{ + guint32 u32Api; + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint16 u16ChannelNumber; + guint16 u16UserStructureIdentifier; + proto_item *sub_item; + + + if (u8BlockVersionHigh != 1 || (u8BlockVersionLow != 0 && u8BlockVersionLow != 1)) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + if (u8BlockVersionLow == 1) { + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_api, &u32Api); + body_length-=4; + } + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* ChannelNumber got new ranges: 0..0x7FFF the source is a channel as specified by the manufacturer */ + /* fetch u16ChannelNumber */ + u16ChannelNumber = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohs(tvb, offset) + : tvb_get_ntohs(tvb, offset)); + if (tree) { + sub_item = proto_tree_add_item(tree,hf_pn_io_channel_number, tvb, offset, 2, DREP_ENC_INTEGER(drep)); + if (u16ChannelNumber < 0x8000){ /* 0..0x7FFF the source is a channel as specified by the manufacturer */ + proto_item_append_text(sub_item, " channel number of the diagnosis source"); + } + else + if (u16ChannelNumber == 0x8000) /* 0x8000 the whole submodule is the source, */ + proto_item_append_text(sub_item, " (whole) Submodule"); + else + proto_item_append_text(sub_item, " reserved"); + } + offset = offset +2; /* Advance behind ChannelNumber */ + /* ChannelProperties */ + offset = dissect_ChannelProperties(tvb, offset, pinfo, tree, item, drep); + body_length-=8; + /* UserStructureIdentifier */ + u16UserStructureIdentifier = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohs(tvb, offset) + : tvb_get_ntohs(tvb, offset)); + if (u16UserStructureIdentifier > 0x7FFF){ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_user_structure_identifier, &u16UserStructureIdentifier); + } + else + { /* range 0x0 to 0x7fff is manufacturer specific */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_user_structure_identifier_manf, &u16UserStructureIdentifier); + } + proto_item_append_text(item, ", USI:0x%x", u16UserStructureIdentifier); + body_length-=2; + + /* the rest of the block contains optional: [MaintenanceItem] and/or [AlarmItem] */ + while (body_length) { + offset = dissect_AlarmUserStructure(tvb, offset, pinfo, tree, item, drep, + &body_length, u16UserStructureIdentifier); + } + return offset; +} + + +static int +dissect_ARProperties(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32ARProperties; + guint8 startupMode; + + sub_item = proto_tree_add_item(tree, hf_pn_io_ar_properties, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_ar_properties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_pull_module_alarm_allowed, &u32ARProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_arproperties_StartupMode, &u32ARProperties); + startupMode = (guint8)((u32ARProperties >> 30) & 0x01); + /* Advanced startup mode */ + if (startupMode) + { + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_combined_object_container_with_advanced_startupmode, &u32ARProperties); + } + /* Legacy startup mode */ + else + { + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_combined_object_container_with_legacy_startupmode, &u32ARProperties); + } + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_reserved, &u32ARProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_achnowledge_companion_ar, &u32ARProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_companion_ar, &u32ARProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_device_access, &u32ARProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_reserved_1, &u32ARProperties); +/* removed within 2.3 + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_data_rate, &u32ARProperties); +*/ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_parametrization_server, &u32ARProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_supervisor_takeover_allowed, &u32ARProperties); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_ar_properties_state, &u32ARProperties); + + return offset; +} + + +/* dissect the IOCRProperties */ +static int +dissect_IOCRProperties(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32IOCRProperties; + + sub_item = proto_tree_add_item(tree, hf_pn_io_iocr_properties, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_iocr_properties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_full_subframe_structure, &u32IOCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_distributed_subframe_watchdog, &u32IOCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_fast_forwarding_mac_adr, &u32IOCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_reserved_3, &u32IOCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_reserved_2, &u32IOCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_media_redundancy, &u32IOCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_reserved_1, &u32IOCRProperties); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocr_properties_rtclass, &u32IOCRProperties); + + return offset; +} + + +/* dissect the ARData block */ +static int +dissect_ARData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BlockLength) +{ + guint16 u16NumberOfARs; + guint16 u16NumberofEntries; + e_guid_t aruuid; + e_guid_t uuid; + guint16 u16ARType; + char *pStationName; + guint16 u16NameLength; + guint16 u16NumberOfIOCRs; + guint16 u16IOCRType; + guint16 u16FrameID; + guint16 u16CycleCounter; + guint8 u8DataStatus; + guint8 u8TransferStatus; + proto_item *ds_item; + proto_tree *ds_tree; + guint16 u16UDPRTPort; + guint16 u16AlarmCRType; + guint16 u16LocalAlarmReference; + guint16 u16RemoteAlarmReference; + guint16 u16NumberOfAPIs; + guint32 u32Api; + proto_item *iocr_item; + proto_tree *iocr_tree; + proto_item *ar_item; + proto_tree *ar_tree; + guint32 u32IOCRStart; + gint32 i32EndOffset; + guint32 u32ARDataStart; + + /* added BlockversionLow == 1 */ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow > 1) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + i32EndOffset = offset + u16BlockLength; + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_ars, &u16NumberOfARs); + /* BlockversionLow: 0 */ + if (u8BlockVersionLow == 0) { + while (u16NumberOfARs--) { + ar_item = proto_tree_add_item(tree, hf_pn_io_ar_data, tvb, offset, 0, ENC_NA); + ar_tree = proto_item_add_subtree(ar_item, ett_pn_io_ar_data); + u32ARDataStart = offset; + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_ar_uuid, &aruuid); + proto_item_append_text(ar_item, "ARUUID:%s", guid_to_str(wmem_packet_scope(), (const e_guid_t*) &aruuid)); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_ar_type, &u16ARType); + offset = dissect_ARProperties(tvb, offset, pinfo, ar_tree, item, drep); + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_cminitiator_objectuuid, &uuid); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_station_name_length, &u16NameLength); + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (ar_tree, hf_pn_io_cminitiator_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_number_of_iocrs, &u16NumberOfIOCRs); + + while (u16NumberOfIOCRs--) { + iocr_item = proto_tree_add_item(ar_tree, hf_pn_io_iocr_tree, tvb, offset, 0, ENC_NA); + iocr_tree = proto_item_add_subtree(iocr_item, ett_pn_io_iocr); + u32IOCRStart = offset; + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, + hf_pn_io_iocr_type, &u16IOCRType); + offset = dissect_IOCRProperties(tvb, offset, pinfo, iocr_tree, drep); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, + hf_pn_io_frame_id, &u16FrameID); + + proto_item_append_text(iocr_item, ": FrameID:0x%x", u16FrameID); + + /* add cycle counter */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, + hf_pn_io_cycle_counter, &u16CycleCounter); + + u8DataStatus = tvb_get_guint8(tvb, offset); + u8TransferStatus = tvb_get_guint8(tvb, offset+1); + + /* add data status subtree */ + ds_item = proto_tree_add_uint_format(iocr_tree, hf_pn_io_data_status, + tvb, offset, 1, u8DataStatus, + "DataStatus: 0x%02x (Frame: %s and %s, Provider: %s and %s)", + u8DataStatus, + (u8DataStatus & 0x04) ? "Valid" : "Invalid", + (u8DataStatus & 0x01) ? "Primary" : "Backup", + (u8DataStatus & 0x20) ? "Ok" : "Problem", + (u8DataStatus & 0x10) ? "Run" : "Stop"); + ds_tree = proto_item_add_subtree(ds_item, ett_pn_io_data_status); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_res67, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_ok, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_operate, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_res3, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_valid, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_res1, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_primary, tvb, offset, 1, u8DataStatus); + + offset++; + + /* add transfer status */ + if (u8TransferStatus) { + proto_tree_add_uint_format(iocr_tree, hf_pn_io_transfer_status, tvb, + offset, 1, u8TransferStatus, + "TransferStatus: 0x%02x (ignore this frame)", u8TransferStatus); + } else { + proto_tree_add_uint_format(iocr_tree, hf_pn_io_transfer_status, tvb, + offset, 1, u8TransferStatus, + "TransferStatus: 0x%02x (OK)", u8TransferStatus); + } + + offset++; + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, + hf_pn_io_cminitiator_udprtport, &u16UDPRTPort); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, + hf_pn_io_cmresponder_udprtport, &u16UDPRTPort); + + proto_item_set_len(iocr_item, offset - u32IOCRStart); + } + + /* AlarmCRType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_alarmcr_type, &u16AlarmCRType); + /* LocalAlarmReference */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_localalarmref, &u16LocalAlarmReference); + /* RemoteAlarmReference */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_remotealarmref, &u16RemoteAlarmReference); + /* ParameterServerObjectUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_parameter_server_objectuuid, &uuid); + /* StationNameLength */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_station_name_length, &u16NameLength); + /* ParameterServerStationName */ + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (ar_tree, hf_pn_io_parameter_server_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + /* NumberOfAPIs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + /* API */ + if (u16NumberOfAPIs > 0) { + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ar_tree, drep, + hf_pn_io_api, &u32Api); + } + proto_item_set_len(ar_item, offset - u32ARDataStart); + } + } + else + { /* BlockversionLow == 1 */ + while (u16NumberOfARs--) { + ar_item = proto_tree_add_item(tree, hf_pn_io_ar_data, tvb, offset, 0, ENC_NA); + ar_tree = proto_item_add_subtree(ar_item, ett_pn_io_ar_data); + u32ARDataStart = offset; + /*ARUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_ar_uuid, &aruuid); + proto_item_append_text(ar_item, "ARUUID:%s", guid_to_str(wmem_packet_scope(), (const e_guid_t*) &aruuid)); + /* CMInitiatorObjectUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_cminitiator_objectuuid, &uuid); + /* ParameterServerObjectUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_parameter_server_objectuuid, &uuid); + /* ARProperties*/ + offset = dissect_ARProperties(tvb, offset, pinfo, ar_tree, item, drep); + /* ARType*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_ar_type, &u16ARType); + /* AlarmCRType */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_alarmcr_type, &u16AlarmCRType); + /* LocalAlarmReference */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_localalarmref, &u16LocalAlarmReference); + /* RemoteAlarmReference */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_remotealarmref, &u16RemoteAlarmReference); + /* InitiatorUDPRTPort*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_cminitiator_udprtport, &u16UDPRTPort); + /* ResponderUDPRTPort*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_cmresponder_udprtport, &u16UDPRTPort); + /* CMInitiatorStationName*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_station_name_length, &u16NameLength); + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (ar_tree, hf_pn_io_cminitiator_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + /** align padding! **/ + offset = dissect_pn_align4(tvb, offset, pinfo, ar_tree); + + /* StationNameLength */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_station_name_length, &u16NameLength); + if (u16NameLength != 0) { + /* ParameterServerStationName */ + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (ar_tree, hf_pn_io_parameter_server_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + } + else + { /* display no name present */ + proto_tree_add_string (ar_tree, hf_pn_io_parameter_server_station_name, tvb, offset, u16NameLength, " <no ParameterServerStationName present>"); + } + /** align padding! **/ + offset = dissect_pn_align4(tvb, offset, pinfo, ar_tree); + + /* NumberOfIOCRs*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_number_of_iocrs, &u16NumberOfIOCRs); + /* align to next 32 bit */ + offset = dissect_pn_padding(tvb, offset, pinfo, ar_tree, 2); + + while (u16NumberOfIOCRs--) { + iocr_item = proto_tree_add_item(ar_tree, hf_pn_io_iocr_tree, tvb, offset, 0, ENC_NA); + iocr_tree = proto_item_add_subtree(iocr_item, ett_pn_io_iocr); + u32IOCRStart = offset; + + /* IOCRProperties*/ + offset = dissect_IOCRProperties(tvb, offset, pinfo, iocr_tree, drep); + /* IOCRType*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, hf_pn_io_iocr_type, &u16IOCRType); + /* FrameID*/ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, hf_pn_io_frame_id, &u16FrameID); + proto_item_append_text(iocr_item, ": FrameID:0x%x", u16FrameID); + + /* add cycle counter */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, iocr_tree, drep, + hf_pn_io_cycle_counter, &u16CycleCounter); + + u8DataStatus = tvb_get_guint8(tvb, offset); + u8TransferStatus = tvb_get_guint8(tvb, offset+1); + + /* add data status subtree */ + ds_item = proto_tree_add_uint_format(iocr_tree, hf_pn_io_data_status, + tvb, offset, 1, u8DataStatus, + "DataStatus: 0x%02x (Frame: %s and %s, Provider: %s and %s)", + u8DataStatus, + (u8DataStatus & 0x04) ? "Valid" : "Invalid", + (u8DataStatus & 0x01) ? "Primary" : "Backup", + (u8DataStatus & 0x20) ? "Ok" : "Problem", + (u8DataStatus & 0x10) ? "Run" : "Stop"); + ds_tree = proto_item_add_subtree(ds_item, ett_pn_io_data_status); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_res67, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_ok, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_operate, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_res3, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_valid, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_res1, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(ds_tree, hf_pn_io_data_status_primary, tvb, offset, 1, u8DataStatus); + + offset++; + + /* add transfer status */ + if (u8TransferStatus) { + proto_tree_add_uint_format(iocr_tree, hf_pn_io_transfer_status, tvb, + offset, 1, u8TransferStatus, + "TransferStatus: 0x%02x (ignore this frame)", u8TransferStatus); + } else { + proto_tree_add_uint_format(iocr_tree, hf_pn_io_transfer_status, tvb, + offset, 1, u8TransferStatus, + "TransferStatus: 0x%02x (OK)", u8TransferStatus); + } + offset++; + proto_item_set_len(iocr_item, offset - u32IOCRStart); + } + /* NumberOfAPIs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_number_of_apis, &u16NumberOfAPIs); + /* align to next 32 bit */ + offset = dissect_pn_padding(tvb, offset, pinfo, ar_tree, 2); + /* API */ + if (u16NumberOfAPIs > 0) { + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_api, &u32Api); + } + /* get the number of subblocks an dissect them */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ar_tree, drep, hf_pn_io_number_of_ARDATAInfo, &u16NumberofEntries); + + offset = dissect_pn_padding(tvb, offset, pinfo, ar_tree, 2); + + while ((offset < i32EndOffset) && (u16NumberofEntries > 0)) { + offset = dissect_a_block(tvb, offset, pinfo, ar_tree, drep); + u16NumberofEntries--; + } + proto_item_set_len(ar_item, offset - u32ARDataStart); + } + } + return offset; +} + + +/* dissect the APIData block */ +static int +dissect_APIData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberOfAPIs; + guint32 u32Api; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* NumberOfAPIs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + + while (u16NumberOfAPIs--) { + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_api, &u32Api); + } + + return offset; +} + +/* dissect the SLRData block */ +static int +dissect_SRLData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 RedundancyInfo; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + /* bit 0 ..1 EndPoint1 and EndPoint2*/ + dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_RedundancyInfo, &RedundancyInfo); + /* bit 2 .. 15 reserved */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_RedundancyInfo_reserved, &RedundancyInfo); + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + return offset; +} + +/* dissect the LogData block */ +static int +dissect_LogData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint64 u64ActualLocaltimeStamp; + guint16 u16NumberOfLogEntries; + guint64 u64LocaltimeStamp; + e_guid_t aruuid; + guint32 u32EntryDetail; + dcerpc_info di; /* fake dcerpc_info struct */ + dcerpc_call_value call_data; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + di.conformant_run = 0; + /* we need di->call_data->flags.NDR64 == 0 */ + call_data.flags = 0; + di.call_data = &call_data; + di.dcerpc_procedure_name = ""; + + /* ActualLocalTimeStamp */ + offset = dissect_dcerpc_uint64(tvb, offset, pinfo, tree, &di, drep, + hf_pn_io_actual_local_time_stamp, &u64ActualLocaltimeStamp); + /* NumberOfLogEntries */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_log_entries, &u16NumberOfLogEntries); + + while (u16NumberOfLogEntries--) { + /* LocalTimeStamp */ + offset = dissect_dcerpc_uint64(tvb, offset, pinfo, tree, &di, drep, + hf_pn_io_local_time_stamp, &u64LocaltimeStamp); + /* ARUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_uuid, &aruuid); + /* PNIOStatus */ + offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep); + /* EntryDetail */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_entry_detail, &u32EntryDetail); + } + + return offset; +} + + +/* dissect the FS Hello block */ +static int +dissect_FSHello_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32FSHelloMode; + guint32 u32FSHelloInterval; + guint32 u32FSHelloRetry; + guint32 u32FSHelloDelay; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* FSHelloMode */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fs_hello_mode, &u32FSHelloMode); + /* FSHelloInterval */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fs_hello_interval, &u32FSHelloInterval); + /* FSHelloRetry */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fs_hello_retry, &u32FSHelloRetry); + /* FSHelloDelay */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fs_hello_delay, &u32FSHelloDelay); + + proto_item_append_text(item, ": Mode:%s, Interval:%ums, Retry:%u, Delay:%ums", + val_to_str(u32FSHelloMode, pn_io_fs_hello_mode_vals, "0x%x"), + u32FSHelloInterval, u32FSHelloRetry, u32FSHelloDelay); + + return offset; +} + + +/* dissect the FS Parameter block */ +static int +dissect_FSParameter_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint32 u32FSParameterMode; + e_guid_t FSParameterUUID; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* FSParameterMode */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_fs_parameter_mode, &u32FSParameterMode); + /* FSParameterUUID */ + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_fs_parameter_uuid, &FSParameterUUID); + + proto_item_append_text(item, ": Mode:%s", + val_to_str(u32FSParameterMode, pn_io_fs_parameter_mode_vals, "0x%x")); + + return offset; +} + + + + +/* dissect the FSUDataAdjust block */ +static int +dissect_PDInterfaceFSUDataAdjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + tvbuff_t *new_tvb; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + u16BodyLength -= 2; + + /* sub blocks */ + new_tvb = tvb_new_subset_length(tvb, offset, u16BodyLength); + dissect_blocks(new_tvb, 0, pinfo, tree, drep); + offset += u16BodyLength; + + return offset; +} + + +/* dissect the ARFSUDataAdjust block */ +static int +dissect_ARFSUDataAdjust_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + tvbuff_t *new_tvb; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + u16BodyLength -= 2; + + /* sub blocks */ + new_tvb = tvb_new_subset_length(tvb, offset, u16BodyLength); + dissect_blocks(new_tvb, 0, pinfo, tree, drep); + offset += u16BodyLength; + + return offset; +} + +static const char * +decode_ARType_spezial(guint16 ARType, guint16 ARAccess) +{ + if (ARType == 0x0001) + return ("IO Controller AR"); + else if (ARType == 0x0003) + return("IO Controller AR"); + else if (ARType == 0x0010) + return("IO Controller AR (RT_CLASS_3)"); + else if (ARType == 0x0020) + return("IO Controller AR (sysred/CiR)"); + else if (ARType == 0x0006) + { + if (ARAccess) /*TRUE */ + return("DeviceAccess AR"); + else + return("IO Supervisor AR"); + } + else + return("reserved"); +} + +/* dissect the ARBlockReq */ +static int +dissect_ARBlockReq_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t ** ar) +{ + guint16 u16ARType; + guint32 u32ARProperties; + gboolean have_aruuid = FALSE; + e_guid_t aruuid; + e_guid_t uuid; + guint16 u16SessionKey; + guint8 mac[6]; + guint16 u16TimeoutFactor; + guint16 u16UDPRTPort; + guint16 u16NameLength; + char *pStationName; + pnio_ar_t *par; + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16ArNumber; + guint16 u16ArResource; + guint16 u16ArReserved; + proto_item *sub_item_selector; + proto_tree *sub_tree_selector; + conversation_t *conversation; + apduStatusSwitch *apdu_status_switch = NULL; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + u32ARProperties = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohl (tvb, offset + 2 + 16 +2 + 6 +12) + : tvb_get_ntohl (tvb, offset + 2 + 16 +2 + 6 +12)); + + u16ARType = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohs (tvb, offset) + : tvb_get_ntohs (tvb, offset)); + + if (tree) { + proto_tree_add_string_format(tree, hf_pn_io_artype_req, tvb, offset, 2, + "ARType", "ARType: (0x%04x) %s ", + u16ARType, decode_ARType_spezial(u16ARType, u32ARProperties)); + } + offset = offset + 2; + + if (u16ARType == 0x0020) + { + sub_item = proto_tree_add_item(tree, hf_pn_io_ar_uuid, tvb, offset, 16, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_ar_info); + + proto_tree_add_item(sub_tree, hf_pn_io_ar_discriminator, tvb, offset, 6, ENC_NA); + offset += 6; + + proto_tree_add_item(sub_tree, hf_pn_io_ar_configid, tvb, offset, 8, ENC_NA); + offset += 8; + + sub_item_selector = proto_tree_add_item(sub_tree, hf_pn_io_ar_selector, tvb, offset, 2, ENC_BIG_ENDIAN); + sub_tree_selector = proto_item_add_subtree(sub_item_selector, ett_pn_io_ar_info); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree_selector, drep, hf_pn_io_ar_arnumber, &u16ArNumber); + dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree_selector, drep, hf_pn_io_ar_arresource, &u16ArResource); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree_selector, drep, hf_pn_io_ar_arreserved, &u16ArReserved); + + /* When ARType==IOCARSR, then find or create conversation for this frame */ + if (!pinfo->fd->flags.visited) { + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_UDP, 0, 0, 0); + if (conversation == NULL) { + /* If conversation is null, then create new conversation */ + /* Connect Request is sent by controller and not by device. */ + /* All conversations are based on Controller MAC as address */ + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_UDP, 0, 0, 0); + } + + /* Try to get apdu status switch information from the conversation */ + apdu_status_switch = (apduStatusSwitch*)conversation_get_proto_data(conversation, proto_pn_io_apdu_status); + + /* If apdu status switch is null, then fill it*/ + /* If apdu status switch is not null, then update it*/ + if (apdu_status_switch == NULL) { + /* apdu status switch information is valid for whole file*/ + apdu_status_switch = wmem_new0(wmem_file_scope(), apduStatusSwitch); + copy_address_shallow(&apdu_status_switch->dl_src, conversation_key_addr1(conversation->key_ptr)); + copy_address_shallow(&apdu_status_switch->dl_dst, conversation_key_addr2(conversation->key_ptr)); + apdu_status_switch->isRedundancyActive = TRUE; + conversation_add_proto_data(conversation, proto_pn_io_apdu_status, apdu_status_switch); + } + else { + copy_address_shallow(&apdu_status_switch->dl_src, conversation_key_addr1(conversation->key_ptr)); + copy_address_shallow(&apdu_status_switch->dl_dst, conversation_key_addr2(conversation->key_ptr)); + apdu_status_switch->isRedundancyActive = TRUE; + } + } + } + else + { + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_uuid, &aruuid); + have_aruuid = TRUE; + } + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sessionkey, &u16SessionKey); + offset = dissect_pn_mac(tvb, offset, pinfo, tree, + hf_pn_io_cminitiator_macadd, mac); + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_cminitiator_objectuuid, &uuid); + + + offset = dissect_ARProperties(tvb, offset, pinfo, tree, item, drep); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_cminitiator_activitytimeoutfactor, &u16TimeoutFactor); /* XXX - special values */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_cminitiator_udprtport, &u16UDPRTPort); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_station_name_length, &u16NameLength); + + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (tree, hf_pn_io_cminitiator_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + + proto_item_append_text(item, ": %s, Session:%u, MAC:%02x:%02x:%02x:%02x:%02x:%02x, Port:0x%x, Station:%s", + decode_ARType_spezial(u16ARType, u32ARProperties), + u16SessionKey, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + u16UDPRTPort, + pStationName); + + if (have_aruuid) { + par = pnio_ar_find_by_aruuid(pinfo, &aruuid); + if (par == NULL) { + par = pnio_ar_new(&aruuid); + memcpy( (void *) (&par->controllermac), mac, sizeof(par->controllermac)); + par->arType = u16ARType; /* store AR-type for filter generation */ + /*strncpy( (char *) (&par->controllername), pStationName, sizeof(par->controllername));*/ + } else { + /*expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, "ARBlockReq: AR already existing!");*/ + } + *ar = par; + } else { + *ar = NULL; + } + + return offset; +} + + +/* dissect the ARBlockRes */ +static int +dissect_ARBlockRes_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t **ar) +{ + guint16 u16ARType; + e_guid_t uuid; + guint16 u16SessionKey; + guint8 mac[6]; + guint16 u16UDPRTPort; + pnio_ar_t *par; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_type, &u16ARType); + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_ar_uuid, &uuid); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sessionkey, &u16SessionKey); + offset = dissect_pn_mac(tvb, offset, pinfo, tree, + hf_pn_io_cmresponder_macadd, mac); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_cmresponder_udprtport, &u16UDPRTPort); + + proto_item_append_text(item, ": %s, Session:%u, MAC:%02x:%02x:%02x:%02x:%02x:%02x, Port:0x%x", + val_to_str(u16ARType, pn_io_ar_type, "0x%x"), + u16SessionKey, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + u16UDPRTPort); + + /* The value NIL indicates the usage of the implicit AR*/ + par = pnio_ar_find_by_aruuid(pinfo, &uuid); + if (par != NULL) { + memcpy( (void *) (&par->devicemac), mac, sizeof(par->controllermac)); + } + *ar = par; + + return offset; +} + + +/* dissect the IOCRBlockReq */ +static int +dissect_IOCRBlockReq_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t *ar) +{ + guint16 u16IOCRType; + guint16 u16IOCRReference; + guint16 u16LT; + guint16 u16DataLength; + guint16 u16FrameID; + guint16 u16SendClockFactor; + guint16 u16ReductionRatio; + guint16 u16Phase; + guint16 u16Sequence; + guint32 u32FrameSendOffset; + guint16 u16WatchdogFactor; + guint16 u16DataHoldFactor; + guint16 u16IOCRTagHeader; + guint8 mac[6]; + guint16 u16NumberOfAPIs; + guint32 u32Api; + guint16 u16NumberOfIODataObjects; + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint16 u16IODataObjectFrameOffset; + guint16 u16NumberOfIOCS; + guint16 u16IOCSFrameOffset; + proto_item *api_item; + proto_tree *api_tree; + guint32 u32ApiStart; + guint16 u16Tmp; + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32SubStart; + + conversation_t *conversation; + stationInfo *station_info = NULL; + iocsObject *iocs_object; + iocsObject *cmp_iocs_object; + ioDataObject *io_data_object; + ioDataObject *cmp_io_data_object; + wmem_list_frame_t *frame; + wmem_list_t *iocs_list; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_type, &u16IOCRType); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_reference, &u16IOCRReference); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_lt, &u16LT); + + offset = dissect_IOCRProperties(tvb, offset, pinfo, tree, drep); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_data_length, &u16DataLength); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_frame_id, &u16FrameID); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_send_clock_factor, &u16SendClockFactor); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_reduction_ratio, &u16ReductionRatio); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_phase, &u16Phase); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_sequence, &u16Sequence); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_frame_send_offset, &u32FrameSendOffset); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_watchdog_factor, &u16WatchdogFactor); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_data_hold_factor, &u16DataHoldFactor); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_tag_header, &u16IOCRTagHeader); + offset = dissect_pn_mac(tvb, offset, pinfo, tree, + hf_pn_io_iocr_multicast_mac_add, mac); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + + proto_item_append_text(item, ": %s, Ref:0x%x, Len:%u, FrameID:0x%x, Clock:%u, Ratio:%u, Phase:%u APIs:%u", + val_to_str(u16IOCRType, pn_io_iocr_type, "0x%x"), + u16IOCRReference, u16DataLength, u16FrameID, + u16SendClockFactor, u16ReductionRatio, u16Phase, u16NumberOfAPIs); + + while (u16NumberOfAPIs--) { + api_item = proto_tree_add_item(tree, hf_pn_io_api_tree, tvb, offset, 0, ENC_NA); + api_tree = proto_item_add_subtree(api_item, ett_pn_io_api); + u32ApiStart = offset; + + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_api, &u32Api); + /* NumberOfIODataObjects */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_number_of_io_data_objects, &u16NumberOfIODataObjects); + + /* Set global Variant for Number of IO Data Objects */ + /* Notice: Handle Input & Output seperate!!! */ + if (!pinfo->fd->flags.visited) { + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + /* Create new conversation, if no "Ident OK" frame as been dissected yet! + * Need to switch dl_src & dl_dst, as Connect Request is sent by controller and not by device. + * All conversations are based on Device MAC as addr1 */ + conversation = conversation_new(pinfo->num, &pinfo->dl_dst, &pinfo->dl_src, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info == NULL) { + station_info = wmem_new0(wmem_file_scope(), stationInfo); + init_pnio_rtc1_station(station_info); + conversation_add_proto_data(conversation, proto_pn_dcp, station_info); + } + else { + station_info->ioDataObjectNr = u16NumberOfIODataObjects; + } + } + + u16Tmp = u16NumberOfIODataObjects; + while (u16Tmp--) { + sub_item = proto_tree_add_item(api_tree, hf_pn_io_io_data_object, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_io_data_object); + u32SubStart = offset; + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* IODataObjectFrameOffset */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_io_data_object_frame_offset, &u16IODataObjectFrameOffset); + + proto_item_append_text(sub_item, ": Slot: 0x%x, Subslot: 0x%x FrameOffset: %u", + u16SlotNr, u16SubslotNr, u16IODataObjectFrameOffset); + + proto_item_set_len(sub_item, offset - u32SubStart); + + if (!pinfo->fd->flags.visited && station_info != NULL) { + io_data_object = wmem_new0(wmem_file_scope(), ioDataObject); + io_data_object->slotNr = u16SlotNr; + io_data_object->subSlotNr = u16SubslotNr; + io_data_object->frameOffset = u16IODataObjectFrameOffset; + /* initial - Will be added later with Write Request */ + io_data_object->f_dest_adr = 0; + io_data_object->f_par_crc1 = 0; + io_data_object->f_src_adr = 0; + io_data_object->f_crc_seed = FALSE; + io_data_object->f_crc_len = 0; + /* Reset as a PNIO Connect Request of a known module appears */ + io_data_object->last_sb_cb = 0; + io_data_object->lastToggleBit = 0; + + if (u16IOCRType == PN_INPUT_CR) { + iocs_list = station_info->ioobject_data_in; + } + else { + iocs_list = station_info->ioobject_data_out; + } + + for (frame = wmem_list_head(iocs_list); frame != NULL; frame = wmem_list_frame_next(frame)) { + cmp_io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (cmp_io_data_object->slotNr == u16SlotNr && cmp_io_data_object->subSlotNr == u16SubslotNr) { + /* Found identical existing object */ + break; + } + } + + if (frame == NULL) { + /* new io_object data incoming */ + wmem_list_append(iocs_list, io_data_object); + } + } + } + + /* NumberOfIOCS */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_number_of_iocs, &u16NumberOfIOCS); + + /* Set global Vairant for NumberOfIOCS */ + if (!pinfo->fd->flags.visited) { + if (station_info != NULL) { + station_info->iocsNr = u16NumberOfIOCS; + } + } + + u16Tmp = u16NumberOfIOCS; + while (u16Tmp--) { + sub_item = proto_tree_add_item(api_tree, hf_pn_io_io_cs, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_io_cs); + u32SubStart = offset; + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* IOCSFrameOffset */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_iocs_frame_offset, &u16IOCSFrameOffset); + + proto_item_append_text(sub_item, ": Slot: 0x%x, Subslot: 0x%x FrameOffset: %u", + u16SlotNr, u16SubslotNr, u16IOCSFrameOffset); + + proto_item_set_len(sub_item, offset - u32SubStart); + + if (!pinfo->fd->flags.visited) { + if (station_info != NULL) { + if (u16IOCRType == PN_INPUT_CR) { + iocs_list = station_info->iocs_data_in; + } + else { + iocs_list = station_info->iocs_data_out; + } + + for (frame = wmem_list_head(iocs_list); frame != NULL; frame = wmem_list_frame_next(frame)) { + cmp_iocs_object = (iocsObject*)wmem_list_frame_data(frame); + if (cmp_iocs_object->slotNr == u16SlotNr && cmp_iocs_object->subSlotNr == u16SubslotNr) { + /* Found identical existing object */ + break; + } + } + + if (frame == NULL) { + /* new iocs_object data incoming */ + iocs_object = wmem_new(wmem_file_scope(), iocsObject); + iocs_object->slotNr = u16SlotNr; + iocs_object->subSlotNr = u16SubslotNr; + iocs_object->frameOffset = u16IOCSFrameOffset; + wmem_list_append(iocs_list, iocs_object); + } + } + } + } + + proto_item_append_text(api_item, ": 0x%x, NumberOfIODataObjects: %u NumberOfIOCS: %u", + u32Api, u16NumberOfIODataObjects, u16NumberOfIOCS); + + proto_item_set_len(api_item, offset - u32ApiStart); + } + + if (ar != NULL) { + switch (u16IOCRType) { + case(1): /* Input CR */ + if (ar->inputframeid != 0 && ar->inputframeid != u16FrameID) { + expert_add_info_format(pinfo, item, &ei_pn_io_frame_id, "IOCRBlockReq: input frameID changed from %u to %u!", ar->inputframeid, u16FrameID); + } + ar->inputframeid = u16FrameID; + break; + case(2): /* Output CR */ +#if 0 + /* will usually contain 0xffff here because the correct framid will be given in the connect.Cnf */ + if (ar->outputframeid != 0 && ar->outputframeid != u16FrameID) { + expert_add_info_format(pinfo, item, &ei_pn_io_frame_id, "IOCRBlockReq: output frameID changed from %u to %u!", ar->outputframeid, u16FrameID); + } + ar->outputframeid = u16FrameID; +#endif + break; + default: + expert_add_info_format(pinfo, item, &ei_pn_io_iocr_type, "IOCRBlockReq: IOCRType %u undecoded!", u16IOCRType); + } + } else { + expert_add_info_format(pinfo, item, &ei_pn_io_ar_info_not_found, "IOCRBlockReq: no corresponding AR found!"); + } + + return offset; +} + + +/* dissect the AlarmCRBlockReq */ +static int +dissect_AlarmCRBlockReq_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t *ar) +{ + guint16 u16AlarmCRType; + guint16 u16LT; + guint32 u32AlarmCRProperties; + guint16 u16RTATimeoutFactor; + guint16 u16RTARetries; + guint16 u16LocalAlarmReference; + guint16 u16MaxAlarmDataLength; + guint16 u16AlarmCRTagHeaderHigh; + guint16 u16AlarmCRTagHeaderLow; + proto_item *sub_item; + proto_tree *sub_tree; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_alarmcr_type, &u16AlarmCRType); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_lt, &u16LT); + + sub_item = proto_tree_add_item(tree, hf_pn_io_alarmcr_properties, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_alarmcr_properties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_alarmcr_properties_reserved, &u32AlarmCRProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_alarmcr_properties_transport, &u32AlarmCRProperties); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_alarmcr_properties_priority, &u32AlarmCRProperties); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rta_timeoutfactor, &u16RTATimeoutFactor); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rta_retries, &u16RTARetries); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_localalarmref, &u16LocalAlarmReference); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_maxalarmdatalength, &u16MaxAlarmDataLength); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_alarmcr_tagheaderhigh, &u16AlarmCRTagHeaderHigh); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_alarmcr_tagheaderlow, &u16AlarmCRTagHeaderLow); + + proto_item_append_text(item, ": %s, LT:0x%x, TFactor:%u, Retries:%u, Ref:0x%x, Len:%u Tag:0x%x/0x%x", + val_to_str(u16AlarmCRType, pn_io_alarmcr_type, "0x%x"), + u16LT, u16RTATimeoutFactor, u16RTARetries, u16LocalAlarmReference, u16MaxAlarmDataLength, + u16AlarmCRTagHeaderHigh, u16AlarmCRTagHeaderLow); + + if (ar != NULL) { + if (ar->controlleralarmref != 0xffff && ar->controlleralarmref != u16LocalAlarmReference) { + expert_add_info_format(pinfo, item, &ei_pn_io_localalarmref, "AlarmCRBlockReq: local alarm ref changed from %u to %u!", ar->controlleralarmref, u16LocalAlarmReference); + } + ar->controlleralarmref = u16LocalAlarmReference; + } else { + expert_add_info_format(pinfo, item, &ei_pn_io_ar_info_not_found, "AlarmCRBlockReq: no corresponding AR found!"); + } + + return offset; +} + + +/* dissect the AlarmCRBlockRes */ +static int +dissect_AlarmCRBlockRes_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t *ar) +{ + guint16 u16AlarmCRType; + guint16 u16LocalAlarmReference; + guint16 u16MaxAlarmDataLength; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_alarmcr_type, &u16AlarmCRType); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_localalarmref, &u16LocalAlarmReference); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_maxalarmdatalength, &u16MaxAlarmDataLength); + + proto_item_append_text(item, ": %s, Ref:0x%04x, MaxDataLen:%u", + val_to_str(u16AlarmCRType, pn_io_alarmcr_type, "0x%x"), + u16LocalAlarmReference, u16MaxAlarmDataLength); + + if (ar != NULL) { + if (ar->devicealarmref != 0xffff && ar->devicealarmref != u16LocalAlarmReference) { + expert_add_info_format(pinfo, item, &ei_pn_io_localalarmref, "AlarmCRBlockRes: local alarm ref changed from %u to %u!", ar->devicealarmref, u16LocalAlarmReference); + } + ar->devicealarmref = u16LocalAlarmReference; + } else { + expert_add_info_format(pinfo, item, &ei_pn_io_ar_info_not_found, "AlarmCRBlockRes: no corresponding AR found!"); + } + + return offset; +} + +/* dissect the ARServerBlock */ +static int +dissect_ARServerBlock(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + char *pStationName; + guint16 u16NameLength, u16padding; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_station_name_length, &u16NameLength); + + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (tree, hf_pn_io_cminitiator_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + /* Padding to next 4 byte allignment in this block */ + u16padding = (u16NameLength-2) & 0x3; + if (u16padding >0) + offset = dissect_pn_padding(tvb, offset, pinfo, tree, u16padding); + return offset; +} + + + +/* dissect the IOCRBlockRes */ +static int +dissect_IOCRBlockRes_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + pnio_ar_t *ar) +{ + guint16 u16IOCRType; + guint16 u16IOCRReference; + guint16 u16FrameID; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_type, &u16IOCRType); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_reference, &u16IOCRReference); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_frame_id, &u16FrameID); + + proto_item_append_text(item, ": %s, Ref:0x%04x, FrameID:0x%04x", + val_to_str(u16IOCRType, pn_io_iocr_type, "0x%x"), + u16IOCRReference, u16FrameID); + + if (ar != NULL) { + switch (u16IOCRType) { + case(1): /* Input CR */ + if (ar->inputframeid != 0 && ar->inputframeid != u16FrameID) { + expert_add_info_format(pinfo, item, &ei_pn_io_frame_id, "IOCRBlockRes: input frameID changed from %u to %u!", ar->inputframeid, u16FrameID); + } + ar->inputframeid = u16FrameID; + break; + case(2): /* Output CR */ + if (ar->outputframeid != 0 && ar->outputframeid != u16FrameID) { + expert_add_info_format(pinfo, item, &ei_pn_io_frame_id, "IOCRBlockRes: output frameID changed from %u to %u!", ar->outputframeid, u16FrameID); + } + ar->outputframeid = u16FrameID; + break; + default: + expert_add_info_format(pinfo, item, &ei_pn_io_iocr_type, "IOCRBlockRes: IOCRType %u undecoded!", u16IOCRType); + } + } else { + expert_add_info_format(pinfo, item, &ei_pn_io_ar_info_not_found, "IOCRBlockRes: no corresponding AR found!"); + } + + return offset; +} + + + +/* dissect the MCRBlockReq */ +static int +dissect_MCRBlockReq_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16IOCRReference; + guint32 u32AddressResolutionProperties; + guint16 u16MCITimeoutFactor; + guint16 u16NameLength; + char *pStationName; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_reference, &u16IOCRReference); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_address_resolution_properties, &u32AddressResolutionProperties); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_mci_timeout_factor, &u16MCITimeoutFactor); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_station_name_length, &u16NameLength); + + pStationName = (char *)wmem_alloc(wmem_packet_scope(), u16NameLength+1); + tvb_memcpy(tvb, (guint8 *) pStationName, offset, u16NameLength); + pStationName[u16NameLength] = '\0'; + proto_tree_add_string (tree, hf_pn_io_provider_station_name, tvb, offset, u16NameLength, pStationName); + offset += u16NameLength; + + proto_item_append_text(item, ", CRRef:%u, Properties:0x%x, TFactor:%u, Station:%s", + u16IOCRReference, u32AddressResolutionProperties, u16MCITimeoutFactor, pStationName); + + return offset; +} + + + +/* dissect the SubFrameBlock */ +static int +dissect_SubFrameBlock_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint16 u16IOCRReference; + guint8 mac[6]; + guint32 u32SubFrameData; + guint16 u16Tmp; + proto_item *sub_item; + proto_tree *sub_tree; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* IOCRReference */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_iocr_reference, &u16IOCRReference); + + /* CMInitiatorMACAdd */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, + hf_pn_io_cminitiator_macadd, mac); + + /* SubFrameData n*32 */ + u16BodyLength -= 10; + u16Tmp = u16BodyLength; + do { + sub_item = proto_tree_add_item(tree, hf_pn_io_subframe_data, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_subframe_data); + /* 31-16 reserved_2 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subframe_data_reserved2, &u32SubFrameData); + /* 15- 8 DataLength */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subframe_data_length, &u32SubFrameData); + /* 7 reserved_1 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subframe_data_reserved1, &u32SubFrameData); + /* 6-0 Position */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subframe_data_position, &u32SubFrameData); + + proto_item_append_text(sub_item, ", Length:%u, Pos:%u", + (u32SubFrameData & 0x0000FF00) >> 8, u32SubFrameData & 0x0000007F); + } while (u16Tmp -= 4); + + proto_item_append_text(item, ", CRRef:%u, %u*Data", + u16IOCRReference, u16BodyLength/4); + + return offset; +} + +/* dissect the (PD)SubFrameBlock 0x022B */ +static int +dissect_PDSubFrameBlock_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint32 u32SFIOCRProperties; + guint32 u32SubFrameData; + guint16 u16FrameID; + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16RemainingLength; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + /* FrameID */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_frame_id, &u16FrameID); + /* SFIOCRProperties */ + sub_item = proto_tree_add_item(tree, hf_pn_io_SFIOCRProperties, tvb, offset, PD_SUB_FRAME_BLOCK_FIOCR_PROPERTIES_LENGTH, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_SFIOCRProperties); + + /* dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties, &u32SFIOCRProperties); */ + /* Bit 31: SFIOCRProperties.SFCRC16 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties_SFCRC16, &u32SFIOCRProperties); + + /* Bit 30: SFIOCRProperties.DFPRedundantPathLayout */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties_DFPRedundantPathLayout, &u32SFIOCRProperties); + /* Bit 29: SFIOCRProperties.DFPRedundantPathLayout */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties_DFPType, &u32SFIOCRProperties); + /* Bit 28 - 29: SFIOCRProperties.reserved_2 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties_reserved_2, &u32SFIOCRProperties); + /* Bit 24 - 27: SFIOCRProperties.reserved_1 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties_reserved_1, &u32SFIOCRProperties); + /* Bit 16 - 23: SFIOCRProperties.DFPmode */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_SFIOCRProperties_DFPmode, &u32SFIOCRProperties); + /* Bit 8 - 15: SFIOCRProperties.RestartFactorForDistributedWD */ + /* 0x00 Mandatory No restart delay necessary + 0x01 - 0x09 Optional Less than 1 s restart delay + 0x0A - 0x50 Mandatory 1 s to 8 s restart delay + 0x51 - 0xFF Optional More than 8 s restart delay */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_RestartFactorForDistributedWD, &u32SFIOCRProperties); + /* bit 0..7 SFIOCRProperties.DistributedWatchDogFactor */ + offset = /* it is the last one, so advance! */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_DistributedWatchDogFactor, &u32SFIOCRProperties); + + /* SubframeData */ + u16RemainingLength = u16BodyLength - PD_SUB_FRAME_BLOCK_FIOCR_PROPERTIES_LENGTH - PD_SUB_FRAME_BLOCK_FRAME_ID_LENGTH; + while (u16RemainingLength >= PD_SUB_FRAME_BLOCK_SUB_FRAME_DATA_LENGTH) + { + guint8 Position, + DataLength; + sub_item = proto_tree_add_item(tree, hf_pn_io_subframe_data, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_subframe_data); + + /* Bit 0 - 6: SubframeData.Position */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_subframe_data_position, &u32SubFrameData); + /* Bit 7: SubframeData.reserved_1 */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_subframe_reserved1, &u32SubFrameData); + /* Bit 8 - 15: SubframeData.dataLength */ + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_subframe_data_length, &u32SubFrameData); + /* Bit 16 - 31: SubframeData.reserved_2 */ + offset = + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_subframe_reserved2, &u32SubFrameData); + Position = (guint8) (u32SubFrameData & 0x7F); /* the lower 6 bits */ + DataLength =(guint8) ((u32SubFrameData >>8) & 0x0ff); /* bit 8 to 15 */ + proto_item_append_text(sub_item, ", Length:%u (0x%x), Pos:%u", + DataLength,DataLength, Position); + u16RemainingLength = u16RemainingLength - 4; + } + return offset; +} + + +/* dissect the IRInfoBlock */ +static int +dissect_IRInfoBlock_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength _U_) +{ + guint16 u16NumberOfIOCR; + guint16 u16SubframeOffset; + guint32 u32SubframeData; + guint16 u16IOCRReference; + e_guid_t IRDataUUID; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hf_pn_io_IRData_uuid, &IRDataUUID); + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + /* Numbers of IOCRs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_iocrs, &u16NumberOfIOCR); + + while (u16NumberOfIOCR--) + { /* IOCRReference */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_iocr_reference, &u16IOCRReference); + + /* SubframeOffset 16 */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_iocr_SubframeOffset, &u16SubframeOffset); + + /* SubframeData 32 */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pn_io_iocr_SubframeData, &u32SubframeData); + } + return offset; +} + +/* dissect the SRInfoBlock */ +static int +dissect_SRInfoBlock_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength _U_) +{ + guint16 u16RedundancyDataHoldFactor; + guint32 u32sr_properties; + guint8 u8SRPropertiesMode; + proto_item *sub_item; + proto_tree *sub_tree; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_RedundancyDataHoldFactor, &u16RedundancyDataHoldFactor); + + u32sr_properties = tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN); + sub_item = proto_tree_add_item(tree, hf_pn_io_sr_properties, tvb, offset, 4, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_sr_properties); + + u8SRPropertiesMode = (guint8)((u32sr_properties >> 2) & 0x01); + + /* SRProperties.InputValidOnBackupAR with SRProperties.Mode == 1 */ + if (u8SRPropertiesMode) + { + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_sr_properties_InputValidOnBackupAR_with_SRProperties_Mode_1, &u32sr_properties); + } + /* SRProperties.InputValidOnBackupAR with SRProperties.Mode == 0 */ + else + { + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_sr_properties_InputValidOnBackupAR_with_SRProperties_Mode_0, &u32sr_properties); + } + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_sr_properties_Reserved_1, &u32sr_properties); + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_sr_properties_Mode, &u32sr_properties); + + dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_sr_properties_Reserved_2, &u32sr_properties); + + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, hf_pn_io_sr_properties_Reserved_3, &u32sr_properties); + return offset; +} + +/* dissect the RSInfoBlock */ +static int +dissect_RSInfoBlock_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, + guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, guint16 u16BodyLength _U_) +{ + guint32 u32RSProperties; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* Padding 2 + 2 + 1 + 1 = 6 */ + /* Therefore we need 2 byte padding to make the block u32 aligned */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pn_io_rs_properties, &u32RSProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pn_io_rs_properties_alarm_transport, &u32RSProperties); + dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pn_io_rs_properties_reserved1, &u32RSProperties); + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, hf_pn_io_rs_properties_reserved2, &u32RSProperties); + + return offset; +} + +/* dissect the PDIRSubframeData block 0x022a */ +static int +dissect_PDIRSubframeData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberOfSubframeBlocks; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, hf_pn_io_NumberOfSubframeBlocks, &u16NumberOfSubframeBlocks); + + while (u16NumberOfSubframeBlocks --) + { /* dissect the Subframe Block */ + offset = dissect_a_block(tvb, offset, pinfo, /*sub_*/tree, drep); + } + + return offset; +} + +static int +dissect_ARVendorBlockReq_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength _U_) +{ + guint16 APStructureIdentifier; + guint32 gu32API; + guint32 guDataBytes; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + APStructureIdentifier = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohs(tvb, offset) + : tvb_get_ntohs(tvb, offset)); + + gu32API = ((drep[0] & DREP_LITTLE_ENDIAN) + ? tvb_get_letohl(tvb, offset + 2) + : tvb_get_ntohl (tvb, offset + 2)); + + if (tree) + { + if (gu32API == 0) + { + if (APStructureIdentifier <0x8000) + { + proto_tree_add_item(tree, hf_pn_io_arvendor_strucidentifier_if0_low, tvb, offset, 2, DREP_ENC_INTEGER(drep)); + } + else + { + if (APStructureIdentifier > 0x8000) + { + proto_tree_add_item(tree, hf_pn_io_arvendor_strucidentifier_if0_high, tvb, offset, 2, DREP_ENC_INTEGER(drep)); + } + else /* APStructureIdentifier == 0x8000 */ + { + proto_tree_add_item(tree, hf_pn_io_arvendor_strucidentifier_if0_is8000, tvb, offset, 2, DREP_ENC_INTEGER(drep)); + } + } + } + else + { + proto_tree_add_item(tree, hf_pn_io_arvendor_strucidentifier_not0, tvb, offset, 2, DREP_ENC_INTEGER(drep)); + } + /* API */ + proto_tree_add_item(tree, hf_pn_io_api, tvb, offset + 2, 4, DREP_ENC_INTEGER(drep)); + } + offset += 6; + if (u16BodyLength < 6 ) + return offset; /* there are no user bytes! */ + guDataBytes = u16BodyLength - 6; + + dissect_pn_user_data(tvb, offset, pinfo, tree, guDataBytes, "Data "); + return offset; +} + +/* dissect the DataDescription */ +static int +dissect_DataDescription(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, ioDataObject *tmp_io_data_object) +{ + guint16 u16DataDescription; + guint16 u16SubmoduleDataLength; + guint8 u8LengthIOCS; + guint8 u8LengthIOPS; + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32SubStart; + + conversation_t *conversation; + stationInfo *station_info = NULL; + ioDataObject *io_data_object; + wmem_list_frame_t *frame; + wmem_list_t *ioobject_list; + + sub_item = proto_tree_add_item(tree, hf_pn_io_data_description_tree, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_data_description); + u32SubStart = offset; + + /* DataDescription */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_data_description, &u16DataDescription); + /* SubmoduleDataLength */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_submodule_data_length, &u16SubmoduleDataLength); + /* LengthIOCS */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_length_iocs, &u8LengthIOCS); + /* LengthIOPS */ + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_length_iops, &u8LengthIOPS); + + proto_item_append_text(sub_item, ": %s, SubmoduleDataLength: %u, LengthIOCS: %u, u8LengthIOPS: %u", + val_to_str(u16DataDescription, pn_io_data_description, "(0x%x)"), + u16SubmoduleDataLength, u8LengthIOCS, u8LengthIOPS); + proto_item_set_len(sub_item, offset - u32SubStart); + + /* Save new data for IO Data Objects */ + if (!pinfo->fd->flags.visited) { + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + + if (station_info != NULL) { + if (u16DataDescription == PN_INPUT_DATADESCRITPION) { + /* INPUT HANDLING */ + ioobject_list = station_info->ioobject_data_in; + } + else { + /* OUTPUT HANDLING */ + ioobject_list = station_info->ioobject_data_out; + } + + for (frame = wmem_list_head(ioobject_list); frame != NULL; frame = wmem_list_frame_next(frame)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (io_data_object->slotNr == tmp_io_data_object->slotNr && io_data_object->subSlotNr == tmp_io_data_object->subSlotNr) { + /* Write additional data from dissect_ExpectedSubmoduleBlockReq_block() to corresponding io_data_object */ + io_data_object->moduleIdentNr = tmp_io_data_object->moduleIdentNr; + io_data_object->subModuleIdentNr = tmp_io_data_object->subModuleIdentNr; + io_data_object->length = u16SubmoduleDataLength; + + io_data_object->moduleNameStr = wmem_strdup(wmem_file_scope(), tmp_io_data_object->moduleNameStr); + io_data_object->profisafeSupported = tmp_io_data_object->profisafeSupported; + io_data_object->discardIOXS = tmp_io_data_object->discardIOXS; + io_data_object->amountInGSDML = tmp_io_data_object->amountInGSDML; + io_data_object->fParameterIndexNr = tmp_io_data_object->fParameterIndexNr; + + break; + } + } + } + } + + return offset; +} + + +/* dissect the ExpectedSubmoduleBlockReq */ +static int +dissect_ExpectedSubmoduleBlockReq_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberOfAPIs; + guint32 u32Api; + guint16 u16SlotNr; + guint32 u32ModuleIdentNumber; + guint16 u16ModuleProperties; + guint16 u16NumberOfSubmodules; + guint16 u16SubslotNr; + guint32 u32SubmoduleIdentNumber; + guint16 u16SubmoduleProperties; + proto_item *api_item; + proto_tree *api_tree; + guint32 u32ApiStart; + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *submodule_item; + proto_tree *submodule_tree; + guint32 u32SubStart; + + /* Variable for the search of gsd file */ + const char vendorIdStr[] = "VendorID=\""; + const char deviceIdStr[] = "DeviceID=\""; + const char moduleStr[] = "ModuleIdentNumber=\""; + const char subModuleStr[] = "SubmoduleIdentNumber=\""; + const char profisafeStr[] = "PROFIsafeSupported=\"true\""; + const char fParameterStr[] = "<F_ParameterRecordDataItem"; + const char fParameterIndexStr[] = "Index="; + const char moduleNameInfo[] = "<Name"; + const char moduleValueInfo[] = "Value=\""; + + guint16 searchVendorID = 0; + guint16 searchDeviceID = 0; + gboolean vendorMatch; + gboolean deviceMatch; + conversation_t *conversation; + stationInfo *station_info = NULL; + ioDataObject *io_data_object = NULL; /* Used to transfer data to fct. "dissect_DataDescription()" */ + + /* Variable for the search of GSD-file */ + guint32 read_vendor_id; + guint32 read_device_id; + guint32 read_module_id; + guint32 read_submodule_id; + gboolean gsdmlFoundFlag; + gchar tmp_moduletext[MAX_NAMELENGTH]; + gchar *convertStr; /* GSD-file search */ + gchar *pch; /* helppointer, to save temp. the found Networkpath of GSD-file */ + gchar *puffer; /* used for fgets() during GSD-file search */ + gchar *temp; /* used for fgets() during GSD-file search */ + gchar *diropen = NULL; /* saves the final networkpath to open for GSD-files */ + GDir *dir; + FILE *fp = NULL; /* filepointer */ + const gchar *filename; /* saves the found GSD-file name */ + + /* Helppointer initial */ + convertStr = (gchar*)wmem_alloc(wmem_packet_scope(), MAX_NAMELENGTH); + convertStr[0] = '\0'; + pch = (gchar*)wmem_alloc(wmem_packet_scope(), MAX_LINE_LENGTH); + pch[0] = '\0'; + puffer = (gchar*)wmem_alloc(wmem_packet_scope(), MAX_LINE_LENGTH); + puffer[0] = '\0'; + temp = (gchar*)wmem_alloc(wmem_packet_scope(), MAX_LINE_LENGTH); + temp[0] = '\0'; + + /* Initial */ + io_data_object = wmem_new0(wmem_file_scope(), ioDataObject); + io_data_object->profisafeSupported = FALSE; + io_data_object->moduleNameStr = (gchar*)wmem_alloc(wmem_file_scope(), MAX_NAMELENGTH); + g_strlcpy(io_data_object->moduleNameStr, "Unknown", MAX_NAMELENGTH); + vendorMatch = FALSE; + deviceMatch = FALSE; + gsdmlFoundFlag = FALSE; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + + proto_item_append_text(item, ": APIs:%u", u16NumberOfAPIs); + + + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info != NULL) { + station_info->gsdFound = FALSE; + station_info->gsdPathLength = FALSE; + + /* Set searchVendorID and searchDeviceID for GSDfile search */ + searchVendorID = station_info->u16Vendor_id; + searchDeviceID = station_info->u16Device_id; + + /* Use the given GSD-file networkpath of the PNIO-Preference */ + if(pnio_ps_networkpath[0] != '\0') { /* check the length of the given networkpath (array overflow protection) */ + station_info->gsdPathLength = TRUE; + + if ((dir = g_dir_open(pnio_ps_networkpath, 0, NULL)) != NULL) { + /* Find all GSD-files within directory */ + while ((filename = g_dir_read_name(dir)) != NULL) { + + /* ---- complete the path to open a GSD-file ---- */ + diropen = wmem_strdup_printf(wmem_packet_scope(), "%s" G_DIR_SEPARATOR_S "%s", pnio_ps_networkpath, filename); + + /* ---- Open the found GSD-file ---- */ + fp = ws_fopen(diropen, "r"); + + if(fp != NULL) { + /* ---- Get VendorID & DeviceID ---- */ + while(pn_fgets(puffer, MAX_LINE_LENGTH, fp) != NULL) { + /* ----- VendorID ------ */ + if((strstr(puffer, vendorIdStr)) != NULL) { + memset (convertStr, 0, sizeof(*convertStr)); + pch = strstr(puffer, vendorIdStr); + if (pch!= NULL && sscanf(pch, "VendorID=\"%199[^\"]", convertStr) == 1) { + read_vendor_id = (guint32) strtoul (convertStr, NULL, 0); + + if(read_vendor_id == searchVendorID) { + vendorMatch = TRUE; /* found correct VendorID */ + } + } + } + + /* ----- DeviceID ------ */ + if((strstr(puffer, deviceIdStr)) != NULL) { + memset(convertStr, 0, sizeof(*convertStr)); + pch = strstr(puffer, deviceIdStr); + if (pch != NULL && sscanf(pch, "DeviceID=\"%199[^\"]", convertStr) == 1) { + read_device_id = (guint32)strtoul(convertStr, NULL, 0); + + if(read_device_id == searchDeviceID) { + deviceMatch = TRUE; /* found correct DeviceID */ + } + } + } + } + + fclose(fp); + fp = NULL; + + if(vendorMatch && deviceMatch) { + break; /* Found correct GSD-file! -> Break the searchloop */ + } + else { + /* Couldn't find the correct GSD-file to the corresponding device */ + vendorMatch = FALSE; + deviceMatch = FALSE; + gsdmlFoundFlag = FALSE; + diropen = ""; /* reset array for next search */ + } + } + } + + g_dir_close(dir); + } + + /* ---- Found the correct GSD-file -> set Flag and save the completed path ---- */ + if(vendorMatch && deviceMatch) { + gsdmlFoundFlag = TRUE; + station_info->gsdFound = TRUE; + station_info->gsdLocation = wmem_strdup(wmem_file_scope(), diropen); + } + else { + /* Copy searchpath to array for a detailed output message in cyclic data dissection */ + station_info->gsdLocation = wmem_strdup_printf(wmem_file_scope(), "%s" G_DIR_SEPARATOR_S "*.xml", pnio_ps_networkpath); + } + } + else { + /* will be used later on in cyclic RTC1 data dissection for detailed output message */ + station_info->gsdPathLength = FALSE; + } + } + + while (u16NumberOfAPIs--) { + api_item = proto_tree_add_item(tree, hf_pn_io_api_tree, tvb, offset, 0, ENC_NA); + api_tree = proto_item_add_subtree(api_item, ett_pn_io_api); + u32ApiStart = offset; + + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_api, &u32Api); + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* ModuleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_module_ident_number, &u32ModuleIdentNumber); + /* ModuleProperties */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_module_properties, &u16ModuleProperties); + /* NumberOfSubmodules */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_number_of_submodules, &u16NumberOfSubmodules); + + proto_item_append_text(api_item, ": %u, Slot:0x%x, IdentNumber:0x%x Properties:0x%x Submodules:%u", + u32Api, u16SlotNr, u32ModuleIdentNumber, u16ModuleProperties, u16NumberOfSubmodules); + + proto_item_append_text(item, ", Submodules:%u", u16NumberOfSubmodules); + + while (u16NumberOfSubmodules--) { + sub_item = proto_tree_add_item(api_tree, hf_pn_io_submodule_tree, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_submodule); + u32SubStart = offset; + + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* SubmoduleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_submodule_ident_number, &u32SubmoduleIdentNumber); + /* SubmoduleProperties */ + submodule_item = proto_tree_add_item(sub_tree, hf_pn_io_submodule_properties, tvb, offset, 2, ENC_BIG_ENDIAN); + submodule_tree = proto_item_add_subtree(submodule_item, ett_pn_io_submodule_properties); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_properties_reserved, &u16SubmoduleProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_properties_discard_ioxs, &u16SubmoduleProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_properties_reduce_output_submodule_data_length, &u16SubmoduleProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_properties_reduce_input_submodule_data_length, &u16SubmoduleProperties); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_properties_shared_input, &u16SubmoduleProperties); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_properties_type, &u16SubmoduleProperties); + + io_data_object->slotNr = u16SlotNr; + io_data_object->subSlotNr = u16SubslotNr; + io_data_object->moduleIdentNr = u32ModuleIdentNumber; + io_data_object->subModuleIdentNr = u32SubmoduleIdentNumber; + io_data_object->discardIOXS = u16SubmoduleProperties & 0x0020; + + /* Search the moduleID and subModuleID, find if PROFIsafe and also search for F-Par. Indexnumber + * --------------------------------------------------------------------------------------------- + * Speical case: Module has several ModuleIdentNr. in one GSD-file + * Also with the given parameters of wireshark, some modules were completely equal. For this + * special case a compromise for this problem has been made, to set the module name will + * be more generally displayed. + * Also this searchloop will find the F-Parameter Indexnumber, so that Wireshark is able to + * dissect those F-Parameters correctly, as this index can change between the vendors. + */ + + io_data_object->amountInGSDML = 0; + io_data_object->fParameterIndexNr = 0; + io_data_object->profisafeSupported = FALSE; + + if (diropen != NULL) { + fp = ws_fopen(diropen, "r"); + } + else { + fp = NULL; + } + if(fp != NULL && gsdmlFoundFlag) { + fseek(fp, 0, SEEK_SET); + + /* Find Indexnumber for fParameter */ + while(pn_fgets(temp, MAX_LINE_LENGTH, fp) != NULL) { + if((strstr(temp, fParameterStr)) != NULL) { + memset (convertStr, 0, sizeof(*convertStr)); + + pch = strstr(temp, fParameterIndexStr); + if (pch != NULL && sscanf(pch, "Index=\"%199[^\"]", convertStr) == 1) { + io_data_object->fParameterIndexNr = (guint32)strtoul(convertStr, NULL, 0); + } + break; /* found Indexnumber -> break search loop */ + } + } + + memset (temp, 0, sizeof(*temp)); + fseek(fp, 0, SEEK_SET); /* Set filepointer to the beginning */ + + while(pn_fgets(temp, MAX_LINE_LENGTH, fp) != NULL) { + if((strstr(temp, moduleStr)) != NULL) { /* find the String "ModuleIdentNumber=" */ + memset (convertStr, 0, sizeof(*convertStr)); + pch = strstr(temp, moduleStr); /* search for "ModuleIdentNumber=\"" within GSD-file */ + if (pch != NULL && sscanf(pch, "ModuleIdentNumber=\"%199[^\"]", convertStr) == 1) { /* Change format of Value string-->numeric string */ + read_module_id = (guint32)strtoul(convertStr, NULL, 0); /* Change numeric string --> unsigned long; read_module_id contains the Value of the ModuleIdentNumber */ + + /* If the found ModuleID matches with the wanted ModuleID, search for the Submodule and break */ + if (read_module_id == io_data_object->moduleIdentNr) { + ++io_data_object->amountInGSDML; /* Save the amount of same (!) Module- & SubmoduleIdentNr in one GSD-file */ + + while(pn_fgets(temp, MAX_LINE_LENGTH, fp) != NULL) { + if((strstr(temp, moduleNameInfo)) != NULL) { /* find the String "<Name" for the TextID */ + long filePosRecord; + + if (sscanf(temp, "%*s TextId=\"%199[^\"]", tmp_moduletext) != 1) /* saves the correct TextId for the next searchloop */ + break; + + filePosRecord = ftell(fp); /* save the current position of the filepointer (Offset) */ + /* ftell() may return -1 for error, don't move fp in this case */ + if (filePosRecord >= 0) { + while (pn_fgets(temp, MAX_LINE_LENGTH, fp) != NULL && io_data_object->amountInGSDML == 1) { + /* Find a String with the saved TextID and with a fitting value for it in the same line. This value is the name of the Module! */ + if(((strstr(temp, tmp_moduletext)) != NULL) && ((strstr(temp, moduleValueInfo)) != NULL)) { + pch = strstr(temp, moduleValueInfo); + if (pch != NULL && sscanf(pch, "Value=\"%199[^\"]", io_data_object->moduleNameStr) == 1) + break; /* Found the name of the module */ + } + } + + fseek(fp, filePosRecord, SEEK_SET); /* set filepointer to the correct TextID */ + } + } + + /* Search for Submoduleidentnumber in GSD-file */ + if((strstr(temp, subModuleStr)) != NULL) { + memset (convertStr, 0, sizeof(*convertStr)); + pch = strstr(temp, subModuleStr); + if (pch != NULL && sscanf(pch, "SubmoduleIdentNumber=\"%199[^\"]", convertStr) == 1) { + read_submodule_id = (guint32) strtoul (convertStr, NULL, 0); /* read_submodule_id contains the Value of the SubModuleIdentNumber */ + + /* Find "PROFIsafeSupported" flag of the module in GSD-file */ + if(read_submodule_id == io_data_object->subModuleIdentNr) { + if((strstr(temp, profisafeStr)) != NULL) { + io_data_object->profisafeSupported = TRUE; /* flag is in the same line as SubmoduleIdentNr */ + break; + } + else { /* flag is not in the same line as Submoduleidentnumber -> search for it */ + while(pn_fgets(temp, MAX_LINE_LENGTH, fp) != NULL) { + if((strstr(temp, profisafeStr)) != NULL) { + io_data_object->profisafeSupported = TRUE; + break; /* Found the PROFIsafeSupported flag of the module */ + } + + else if((strstr(temp, ">")) != NULL) { + break; + } + } + } + } + break; /* Found the PROFIsafe Module */ + } + } + } + } + } + } + } + + fclose(fp); + fp = NULL; + } + + if(fp != NULL) + { + fclose(fp); + fp = NULL; + } + + switch (u16SubmoduleProperties & 0x03) { + case(0x00): /* no input and no output data (one Input DataDescription Block follows) */ + offset = dissect_DataDescription(tvb, offset, pinfo, sub_tree, drep, io_data_object); + break; + case(0x01): /* input data (one Input DataDescription Block follows) */ + offset = dissect_DataDescription(tvb, offset, pinfo, sub_tree, drep, io_data_object); + break; + case(0x02): /* output data (one Output DataDescription Block follows) */ + offset = dissect_DataDescription(tvb, offset, pinfo, sub_tree, drep, io_data_object); + break; + case(0x03): /* input and output data (one Input and one Output DataDescription Block follows) */ + offset = dissect_DataDescription(tvb, offset, pinfo, sub_tree, drep, io_data_object); + offset = dissect_DataDescription(tvb, offset, pinfo, sub_tree, drep, io_data_object); + break; + default: /* will not execute because of the line preceding the switch */ + break; + } + + proto_item_append_text(sub_item, ": Subslot:0x%x, Ident:0x%x Properties:0x%x", + u16SubslotNr, u32SubmoduleIdentNumber, u16SubmoduleProperties); + proto_item_set_len(sub_item, offset - u32SubStart); + } + + proto_item_set_len(api_item, offset - u32ApiStart); + } + + return offset; +} + + +/* dissect the ModuleDiffBlock */ +static int +dissect_ModuleDiffBlock_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16NumberOfAPIs; + guint32 u32Api; + guint16 u16NumberOfModules; + guint16 u16SlotNr; + guint32 u32ModuleIdentNumber; + guint16 u16ModuleState; + guint16 u16NumberOfSubmodules; + guint16 u16SubslotNr; + guint32 u32SubmoduleIdentNumber; + guint16 u16SubmoduleState; + proto_item *api_item; + proto_tree *api_tree; + guint32 u32ApiStart; + proto_item *module_item; + proto_tree *module_tree; + guint32 u32ModuleStart; + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *submodule_item; + proto_tree *submodule_tree; + guint32 u32SubStart; + + conversation_t *conversation; + stationInfo *station_info; + wmem_list_frame_t *frame; + moduleDiffInfo *module_diff_info; + moduleDiffInfo *cmp_module_diff_info; + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* NumberOfAPIs */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_number_of_apis, &u16NumberOfAPIs); + + proto_item_append_text(item, ": APIs:%u", u16NumberOfAPIs); + + while (u16NumberOfAPIs--) { + api_item = proto_tree_add_item(tree, hf_pn_io_api_tree, tvb, offset, 0, ENC_NA); + api_tree = proto_item_add_subtree(api_item, ett_pn_io_api); + u32ApiStart = offset; + + /* API */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_api, &u32Api); + /* NumberOfModules */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, api_tree, drep, + hf_pn_io_number_of_modules, &u16NumberOfModules); + + proto_item_append_text(api_item, ": %u, Modules: %u", + u32Api, u16NumberOfModules); + + proto_item_append_text(item, ", Modules:%u", u16NumberOfModules); + + while (u16NumberOfModules--) { + module_item = proto_tree_add_item(api_tree, hf_pn_io_module_tree, tvb, offset, 0, ENC_NA); + module_tree = proto_item_add_subtree(module_item, ett_pn_io_module); + u32ModuleStart = offset; + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* ModuleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_module_ident_number, &u32ModuleIdentNumber); + /* ModuleState */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_module_state, &u16ModuleState); + /* NumberOfSubmodules */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, module_tree, drep, + hf_pn_io_number_of_submodules, &u16NumberOfSubmodules); + + proto_item_append_text(module_item, ": Slot 0x%x, Ident: 0x%x State: %s Submodules: %u", + u16SlotNr, u32ModuleIdentNumber, + val_to_str(u16ModuleState, pn_io_module_state, "(0x%x)"), + u16NumberOfSubmodules); + + + if (!pinfo->fd->flags.visited) { + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info != NULL) { + for (frame = wmem_list_head(station_info->diff_module); frame != NULL; frame = wmem_list_frame_next(frame)) { + cmp_module_diff_info = (moduleDiffInfo*)wmem_list_frame_data(frame); + if (cmp_module_diff_info->slotNr == u16SlotNr) { + /* Found identical existing object */ + break; + } + } + + if (frame == NULL) { + /* new diffModuleInfo data incoming */ + module_diff_info = wmem_new(wmem_file_scope(), moduleDiffInfo); + module_diff_info->slotNr = u16SlotNr; + module_diff_info->modulID = u32ModuleIdentNumber; + wmem_list_append(station_info->diff_module, module_diff_info); + } + } + } + + proto_item_append_text(item, ", Submodules:%u", u16NumberOfSubmodules); + + while (u16NumberOfSubmodules--) { + sub_item = proto_tree_add_item(module_tree, hf_pn_io_submodule_tree, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_submodule); + u32SubStart = offset; + + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + /* SubmoduleIdentNumber */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_submodule_ident_number, &u32SubmoduleIdentNumber); + /* SubmoduleState */ + submodule_item = proto_tree_add_item(sub_tree, hf_pn_io_submodule_state, tvb, offset, 2, ENC_BIG_ENDIAN); + submodule_tree = proto_item_add_subtree(submodule_item, ett_pn_io_submodule_state); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_format_indicator, &u16SubmoduleState); + if (u16SubmoduleState & 0x8000) { + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_ident_info, &u16SubmoduleState); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_ar_info, &u16SubmoduleState); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_diag_info, &u16SubmoduleState); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_maintenance_demanded, &u16SubmoduleState); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_maintenance_required, &u16SubmoduleState); + dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_qualified_info, &u16SubmoduleState); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_add_info, &u16SubmoduleState); + } else { + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, submodule_tree, drep, + hf_pn_io_submodule_state_detail, &u16SubmoduleState); + } + + proto_item_append_text(sub_item, ": Subslot 0x%x, IdentNumber: 0x%x, State: 0x%x", + u16SubslotNr, u32SubmoduleIdentNumber, u16SubmoduleState); + + proto_item_set_len(sub_item, offset - u32SubStart); + } /* NumberOfSubmodules */ + + proto_item_set_len(module_item, offset - u32ModuleStart); + } + + proto_item_set_len(api_item, offset - u32ApiStart); + } + + return offset; +} + + +/* dissect the IsochronousModeData block */ +static int +dissect_IsochronousModeData_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + guint16 u16SlotNr; + guint16 u16SubslotNr; + guint16 u16ControllerApplicationCycleFactor; + guint16 u16TimeDataCycle; + guint32 u32TimeIOInput; + guint32 u32TimeIOOutput; + guint32 u32TimeIOInputValid; + guint32 u32TimeIOOutputValid; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* SlotNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_slot_nr, &u16SlotNr); + /* Subslotnumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_subslot_nr, &u16SubslotNr); + + /* ControllerApplicationCycleFactor */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_controller_appl_cycle_factor, &u16ControllerApplicationCycleFactor); + /* TimeDataCycle */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_time_data_cycle, &u16TimeDataCycle); + /* TimeIOInput (ns) */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_time_io_input, &u32TimeIOInput); + /* TimeIOOutput (ns) */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_time_io_output, &u32TimeIOOutput); + /* TimeIOInputValid (ns) */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_time_io_input_valid, &u32TimeIOInputValid); + /* TimeIOOutputValid (ns) */ + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tree, drep, + hf_pn_io_time_io_output_valid, &u32TimeIOOutputValid); + + + return offset+1; +} + + +/* dissect the MultipleBlockHeader block */ +static int +dissect_MultipleBlockHeader_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16BodyLength) +{ + guint32 u32Api; + guint16 u16SlotNr; + guint16 u16SubslotNr; + tvbuff_t *new_tvb; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + 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_item_append_text(item, ": Api:0x%x Slot:%u Subslot:0x%x", + u32Api, u16SlotNr, u16SubslotNr); + + new_tvb = tvb_new_subset_length(tvb, offset, u16BodyLength-10); + offset = dissect_blocks(new_tvb, 0, pinfo, tree, drep); + + /*offset += u16BodyLength;*/ + + return offset; +} + +/* dissect Combined Object Container Content block */ +static int +dissect_COContainerContent_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16Index, guint32 *u32RecDataLen, pnio_ar_t **ar) +{ + guint32 u32Api; + guint16 u16SlotNr; + guint16 u16SubslotNr; + + if(u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + 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); + + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 2); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_index, &u16Index); + + proto_item_append_text(item, ": Api:0x%x Slot:%u Subslot:0x%x Index:0x%x", + u32Api, u16SlotNr, u16SubslotNr, u16Index); + + if(u16Index != 0x80B0) { + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, u32RecDataLen, ar); + } + + return offset; +} + + +static const gchar * +indexReservedForProfiles(guint16 u16Index) +{ + /* "reserved for profiles" */ + if (u16Index >= 0xb000 && u16Index <= 0xbfff) { + return "Reserved for Profiles (subslot specific)"; + } + if (u16Index >= 0xd000 && u16Index <= 0xdfff) { + return "Reserved for Profiles (slot specific)"; + } + if (u16Index >= 0xec00 && u16Index <= 0xefff) { + return "Reserved for Profiles (AR specific)"; + } + if (u16Index >= 0xf400 && u16Index <= 0xf7ff) { + return "Reserved for Profiles (API specific)"; + } + if (u16Index >= 0xfc00 /* up to 0xffff */) { + return "Reserved for Profiles (device specific)"; + } + + return NULL; +} + + +/* dissect the RecordDataReadQuery block */ +static int +dissect_RecordDataReadQuery_block(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, guint8 *drep _U_, guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow, + guint16 u16Index, guint16 u16BodyLength) +{ + const gchar *userProfile; + + + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + + /* user specified format? */ + if (u16Index < 0x8000) { + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u16BodyLength, "User Specified Data"); + return offset; + } + + /* "reserved for profiles"? */ + userProfile = indexReservedForProfiles(u16Index); + if (userProfile != NULL) { + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u16BodyLength, userProfile); + return offset; + } + + return dissect_pn_undecoded(tvb, offset, pinfo, tree, u16BodyLength); +} + +/* dissect the RS_GetEvent block */ +static int +dissect_RS_GetEvent_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, + guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_RS_EventInfo(tvb, offset, pinfo, tree, drep); + return offset; +} + +/* dissect the RS_AdjustControl */ +static int +dissect_RS_AdjustControl(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep, + guint16 *u16RSBodyLength, guint16 *u16RSBlockType) +{ + guint16 u16ChannelNumber; + guint16 u16SoEMaxScanDelay; + proto_item *sub_item; + proto_tree *sub_tree; + guint8 u8SoEAdjustSpecifierReserved; + guint8 u8SoEAdjustSpecifierIndicent; + + switch (*u16RSBlockType) { + case(0xc010): /* SoE_DigitalInputObserver */ + + /* ChannelNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_channel_number, &u16ChannelNumber); + + /* SoE_MaxScanDelay */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_soe_max_scan_delay, &u16SoEMaxScanDelay); + + /* SoE_AdjustSpecifier */ + sub_item = proto_tree_add_item(tree, hf_pn_io_soe_adjust_specifier, tvb, offset, 1, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_soe_adjust_specifier); + + dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_soe_adjust_specifier_reserved, &u8SoEAdjustSpecifierReserved); + + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_soe_adjust_specifier_incident, &u8SoEAdjustSpecifierIndicent); + + /* Padding 2 + 2 + 1 = 5 */ + /* Therefore we need 3 byte padding to make the block u32 aligned */ + offset = dissect_pn_padding(tvb, offset, pinfo, tree, 3); + break; + default: + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, *u16RSBodyLength, "UserData"); + break; + } + return offset; +} + +/* dissect the RS_AdjustBlock */ +static int +dissect_RS_AdjustBlock(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + + guint16 u16RSBodyLength; + guint16 u16RSBlockType; + + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_adjust_block, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_adjust_block); + + /* RS_BlockHeader */ + offset = dissect_RS_BlockHeader(tvb, offset, pinfo, sub_tree, sub_item, drep, + &u16RSBodyLength, &u16RSBlockType); + + /* RS_AdjustControl */ + offset = dissect_RS_AdjustControl(tvb, offset, pinfo, sub_tree, drep, + &u16RSBodyLength, &u16RSBlockType); + + return offset; +} + +/* dissect the RS_AdjustInfo */ +static int +dissect_RS_AdjustInfo(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16NumberofEntries; + + sub_item = proto_tree_add_item(tree, hf_pn_io_rs_adjust_info, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_rs_adjust_info); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_number_of_rs_event_info, &u16NumberofEntries); + + while (u16NumberofEntries > 0) { + u16NumberofEntries--; + offset = dissect_RS_AdjustBlock(tvb, offset, pinfo, sub_tree, drep); + } + return offset; +} + +/* dissect the RS_AdjustObserver block */ +static int +dissect_RS_AdjustObserver_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, + guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_RS_AdjustInfo(tvb, offset, pinfo, tree, drep); + return offset; +} + +static int +dissect_RS_AckInfo(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep) +{ + guint16 u16RSSpecifierSequenceNumber; + + /* RS_Specifier.SequenceNumber */ + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tree, drep, + hf_pn_io_rs_specifier_sequence, &u16RSSpecifierSequenceNumber); + + return offset; +} + +/* dissect the RS_AckEvent block */ +static int +dissect_RS_AckEvent_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 *drep, + guint8 u8BlockVersionHigh, guint8 u8BlockVersionLow) +{ + if (u8BlockVersionHigh != 1 || u8BlockVersionLow != 0) { + expert_add_info_format(pinfo, item, &ei_pn_io_block_version, + "Block version %u.%u not implemented yet!", u8BlockVersionHigh, u8BlockVersionLow); + return offset; + } + offset = dissect_RS_AckInfo(tvb, offset, pinfo, tree, drep); + 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, guint16 *u16Index, guint32 *u32RecDataLen, pnio_ar_t **ar) +{ + guint16 u16BlockType; + guint16 u16BlockLength; + guint8 u8BlockVersionHigh; + guint8 u8BlockVersionLow; + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32SubStart; + guint16 u16BodyLength; + proto_item *header_item; + proto_tree *header_tree; + gint remainingBytes; + + /* from here, we only have big endian (network byte ordering)!!! */ + drep[0] &= ~DREP_LITTLE_ENDIAN; + + sub_item = proto_tree_add_item(tree, hf_pn_io_block, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_block); + u32SubStart = offset; + + header_item = proto_tree_add_item(sub_tree, hf_pn_io_block_header, tvb, offset, 6, ENC_NA); + header_tree = proto_item_add_subtree(header_item, ett_pn_io_block_header); + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, header_tree, drep, + hf_pn_io_block_type, &u16BlockType); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, header_tree, drep, + hf_pn_io_block_length, &u16BlockLength); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, header_tree, drep, + hf_pn_io_block_version_high, &u8BlockVersionHigh); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, header_tree, drep, + hf_pn_io_block_version_low, &u8BlockVersionLow); + + proto_item_append_text(header_item, ": Type=%s, Length=%u(+4), Version=%u.%u", + val_to_str(u16BlockType, pn_io_block_type, "Unknown (0x%04x)"), + u16BlockLength, u8BlockVersionHigh, u8BlockVersionLow); + + proto_item_set_text(sub_item, "%s", + val_to_str(u16BlockType, pn_io_block_type, "Unknown (0x%04x)")); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + val_to_str(u16BlockType, pn_io_block_type, "Unknown")); + + /* block length is without type and length fields, but with version field */ + /* as it's already dissected, remove it */ + u16BodyLength = u16BlockLength - 2; + remainingBytes = tvb_reported_length_remaining(tvb, offset); + if (remainingBytes < 0) + remainingBytes = 0; + if (remainingBytes +2 < u16BodyLength) + { + proto_item_append_text(sub_item, " Block_Length: %d greater than remaining Bytes, trying with Blocklen = remaining (%d)", u16BodyLength, remainingBytes); + u16BodyLength = remainingBytes; + } + switch (u16BlockType) { + case(0x0001): + case(0x0002): + dissect_AlarmNotification_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0008): + dissect_IODWriteReqHeader_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16Index, u32RecDataLen, ar); + break; + case(0x0009): + dissect_IODReadReqHeader_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16Index, u32RecDataLen, ar); + break; + case(0x0010): + dissect_DiagnosisData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0012): /* ExpectedIdentificationData */ + case(0x0013): /* RealIdentificationData */ + dissect_IdentificationData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0014): + dissect_SubstituteValue_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0015): + dissect_RecordInputDataObjectElement_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0016): + dissect_RecordOutputDataObjectElement_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + /* 0x0017 reserved */ + case(0x0018): + dissect_ARData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0019): + dissect_LogData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x001A): + dissect_APIData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x001B): + dissect_SRLData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0020): + dissect_IandM0_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0021): + dissect_IandM1_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0022): + dissect_IandM2_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0023): + dissect_IandM3_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0024): + dissect_IandM4_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0025): + dissect_IandM5_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh,u8BlockVersionLow); + break; + case(0x0030): + dissect_IandM0FilterData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0031): + dissect_IandM0FilterData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0032): + dissect_IandM0FilterData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0034): + dissect_IandM5Data_block(tvb, offset, pinfo, sub_tree, sub_item, drep); + break; + case(0x0035): + dissect_AssetManagementData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0036): + dissect_AM_FullInformation_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0037): + dissect_AM_HardwareOnlyInformation_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0038): + dissect_AM_FirmwareOnlyInformation_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0101): + dissect_ARBlockReq_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + ar); + break; + case(0x0102): + dissect_IOCRBlockReq_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + *ar); + break; + case(0x0103): + dissect_AlarmCRBlockReq_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + *ar); + break; + case(0x0104): + dissect_ExpectedSubmoduleBlockReq_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0106): + dissect_MCRBlockReq_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0107): + dissect_SubFrameBlock_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0108): + case(0x8108): + dissect_ARVendorBlockReq_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0109): + dissect_IRInfoBlock_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x010A): + dissect_SRInfoBlock_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x010C): + dissect_RSInfoBlock_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0110): + case(0x0111): + case(0x0112): + case(0x0113): + case(0x0114): + case(0x0116): + case(0x0117): + dissect_ControlConnect_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, ar); + break; + + case(0x0118): + dissect_ControlBlockPrmBegin(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength, ar); + break; + + case(0x0119): + dissect_SubmoduleListBlock(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength, ar); + break; + + case(0x0200): /* PDPortDataCheck */ + dissect_PDPortData_Check_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0201): + dissect_PDevData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0202): /*dissect_PDPortData_Adjust_block */ + dissect_PDPortData_Adjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0203): + dissect_PDSyncData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0204): + dissect_IsochronousModeData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0205): + dissect_PDIRData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0206): + dissect_PDIRGlobalData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0207): + dissect_PDIRFrameData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0208): + dissect_PDIRBeginEndData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16BodyLength); + break; + case(0x0209): + dissect_AdjustDomainBoundary_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x020A): + dissect_CheckPeers_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x020B): + dissect_CheckLineDelay_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x020C): + dissect_CheckMAUType_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x020E): + dissect_AdjustMAUType_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x020F): + dissect_PDPortDataReal_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0210): + dissect_AdjustMulticastBoundary_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0211): + dissect_PDInterfaceMrpDataAdjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0212): + dissect_PDInterfaceMrpDataReal_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0213): + dissect_PDInterfaceMrpDataCheck_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0214): + case(0x0215): + dissect_PDPortMrpData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0216): + dissect_MrpManagerParams_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0217): + dissect_MrpClientParams_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0218): + dissect_MrpRTModeManagerData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0219): + dissect_MrpRingStateData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x021A): + dissect_MrpRTStateData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x021B): + dissect_AdjustPortState_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x021C): + dissect_CheckPortState_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x021D): + dissect_MrpRTModeClientData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x021E): + dissect_CheckSyncDifference_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x021F): + dissect_CheckMAUTypeDifference_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0220): + dissect_PDPortFODataReal_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0221): + dissect_FiberOpticManufacturerSpecific_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0222): + dissect_PDPortFODataAdjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0223): + dissect_PDPortFODataCheck_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0224): + dissect_AdjustPeerToPeerBoundary_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0225): + dissect_AdjustDCPBoundary_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0226): + dissect_AdjustPreambleLength_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0227): + dissect_CheckMAUTypeExtension_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0228): + dissect_FiberOpticDiagnosisInfo_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0229): + dissect_AdjustMAUTypeExtension_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x022A): + dissect_PDIRSubframeData_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x022B): + dissect_PDSubFrameBlock_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + + case(0x0230): + dissect_PDPortFODataCheck_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0231): + dissect_MrpInstanceDataAdjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0232): + dissect_MrpInstanceDataReal_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0233): + dissect_MrpInstanceDataCheck_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + + case(0x0240): + dissect_PDInterfaceDataReal_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0250): + dissect_PDInterfaceAdjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0251): + dissect_PDPortStatistic_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0400): + dissect_MultipleBlockHeader_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0401): + dissect_COContainerContent_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, *u16Index, u32RecDataLen, ar); + break; + case(0x0500): + dissect_RecordDataReadQuery_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, *u16Index, u16BodyLength); + break; + case(0x0600): + dissect_FSHello_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0601): + dissect_FSParameter_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0608): + dissect_PDInterfaceFSUDataAdjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x010B): + case(0x0609): + dissect_ARFSUDataAdjust_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, u16BodyLength); + break; + case(0x0900): + dissect_RS_AdjustObserver_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0901): + dissect_RS_GetEvent_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0902): + dissect_RS_AckEvent_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x0f00) : + dissect_Maintenance_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x8001): + case(0x8002): + dissect_Alarm_ack_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x8008): + dissect_IODWriteResHeader_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16Index, u32RecDataLen, ar); + break; + case(0x8009): + dissect_IODReadResHeader_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, + u16Index, u32RecDataLen, ar); + break; + case(0x8101): + dissect_ARBlockRes_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, ar); + break; + case(0x8102): + dissect_IOCRBlockRes_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, *ar); + break; + case(0x8103): + dissect_AlarmCRBlockRes_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, *ar); + break; + case(0x8104): + dissect_ModuleDiffBlock_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x8106): + dissect_ARServerBlock(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow); + break; + case(0x8110): + case(0x8111): + case(0x8112): + case(0x8113): + case(0x8114): + case(0x8116): + case(0x8117): + case(0x8118): + dissect_ControlConnect_block(tvb, offset, pinfo, sub_tree, sub_item, drep, u8BlockVersionHigh, u8BlockVersionLow, ar); + break; + default: + dissect_pn_undecoded(tvb, offset, pinfo, sub_tree, u16BodyLength); + } + offset += u16BodyLength; + + proto_item_set_len(sub_item, offset - u32SubStart); + + return offset; +} + + +/* dissect any PN-IO block */ +static int +dissect_a_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + + if (ar != NULL) { + pnio_ar_info(tvb, pinfo, tree, ar); + } + + 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) +{ + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + + while (tvb_captured_length(tvb) > (guint) offset) { + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + u16Index++; + } + + if (ar != NULL) { + pnio_ar_info(tvb, pinfo, tree, ar); + } + + 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, dcerpc_info *di, guint8 *drep) +{ + guint32 u32ArgsMax; + guint32 u32ArgsLen; + guint32 u32MaxCount; + guint32 u32Offset; + guint32 u32ArraySize; + + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32SubStart; + + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO-CM"); + + /* args_max */ + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, + hf_pn_io_args_max, &u32ArgsMax); + /* args_len */ + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, + hf_pn_io_args_len, &u32ArgsLen); + + sub_item = proto_tree_add_item(tree, hf_pn_io_array, tvb, offset, 0, ENC_NA); + 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, di, drep, + hf_pn_io_array_max_count, &u32MaxCount); + offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, di, drep, + hf_pn_io_array_offset, &u32Offset); + offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, di, 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, dcerpc_info *di, guint8 *drep) +{ + guint32 u32ArgsLen; + guint32 u32MaxCount; + guint32 u32Offset; + guint32 u32ArraySize; + + proto_item *sub_item; + proto_tree *sub_tree; + guint32 u32SubStart; + + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO-CM"); + + offset = dissect_PNIO_status(tvb, offset, pinfo, tree, drep); + + /* args_len */ + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, + hf_pn_io_args_len, &u32ArgsLen); + + sub_item = proto_tree_add_item(tree, hf_pn_io_array, tvb, offset, 0, ENC_NA); + 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, di, drep, + hf_pn_io_array_max_count, &u32MaxCount); + offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, di, drep, + hf_pn_io_array_offset, &u32Offset); + offset = dissect_ndr_uint32(tvb, offset, pinfo, sub_tree, di, 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 request */ +static int +dissect_IPNIO_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + + offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_blocks(tvb, offset, pinfo, tree, drep); + + return offset; +} + + +/* dissect a PN-IO response */ +static int +dissect_IPNIO_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + + offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_blocks(tvb, offset, pinfo, tree, drep); + + return offset; +} + +/* dissect a PROFIDrive parameter request */ +static int +dissect_ProfiDriveParameterRequest(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + guint8 request_reference; + guint8 request_id; + guint8 do_id; + guint8 no_of_parameters; + guint8 addr_idx; + proto_item *profidrive_item; + proto_tree *profidrive_tree; + + profidrive_item = proto_tree_add_item(tree, hf_pn_io_block, tvb, offset, 0, ENC_NA); + profidrive_tree = proto_item_add_subtree(profidrive_item, ett_pn_io_profidrive_parameter_request); + proto_item_set_text(profidrive_item, "PROFIDrive Parameter Request: "); + + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_request_reference, &request_reference); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_request_id, &request_id); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_do_id, &do_id); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_no_of_parameters, &no_of_parameters); + + proto_item_append_text(profidrive_item, "ReqRef:0x%02x, ReqId:%s, DO:%u, NoOfParameters:%u", + request_reference, val_to_str(request_id, pn_io_profidrive_request_id_vals, "Unknown"), + do_id, no_of_parameters); + + col_add_fstr(pinfo->cinfo, COL_INFO, "PROFIDrive Write Request, ReqRef:0x%02x, %s DO:%u", + request_reference, + request_id==0x01 ? "Read" : + request_id==0x02 ? "Change" : + "", + do_id); + + /* Parameter address list */ + for(addr_idx=0; addr_idx<no_of_parameters; addr_idx++) { + guint8 attribute; + guint8 no_of_elems; + guint16 parameter; + guint16 idx; + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(profidrive_tree, hf_pn_io_block, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_profidrive_parameter_address); + proto_item_set_text(sub_item, "Parameter Address %u: ", addr_idx+1); + + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_profidrive_param_attribute, &attribute); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_profidrive_param_no_of_elems, &no_of_elems); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_profidrive_param_number, ¶meter); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_profidrive_param_subindex, &idx); + + proto_item_append_text(sub_item, "Attr:%s, Elems:%u, Parameter:%u, Index:%u", + val_to_str(attribute, pn_io_profidrive_attribute_vals, "Unknown"), no_of_elems, + parameter, idx); + + if (no_of_elems>1) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", P%d[%d..%d]", parameter, idx, idx+no_of_elems-1); + } + else { + col_append_fstr(pinfo->cinfo, COL_INFO, ", P%d[%d]", parameter, idx); + } + } + + /* in case of change request parameter value list */ + if (request_id == 0x02) { + for(addr_idx=0; addr_idx<no_of_parameters; addr_idx++) { + guint8 format; + guint8 no_of_vals; + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(profidrive_tree, hf_pn_io_block, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_io_profidrive_parameter_value); + proto_item_set_text(sub_item, "Parameter Value %u: ", addr_idx+1); + + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_profidrive_param_format, &format); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, sub_tree, drep, + hf_pn_io_profidrive_param_no_of_values, &no_of_vals); + + proto_item_append_text(sub_item, "Format:%s, NoOfVals:%u", + val_to_str(format, pn_io_profidrive_format_vals, "Unknown"), no_of_vals); + + while (no_of_vals--) + { + offset = dissect_profidrive_value(tvb, offset, pinfo, sub_tree, drep, format); + } + } + } + + return offset; +} + +static int +dissect_ProfiDriveParameterResponse(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + guint8 request_reference; + guint8 response_id; + guint8 do_id; + guint8 no_of_parameters; + proto_item *profidrive_item; + proto_tree *profidrive_tree; + + profidrive_item = proto_tree_add_item(tree, hf_pn_io_block, tvb, offset, 0, ENC_NA); + profidrive_tree = proto_item_add_subtree(profidrive_item, ett_pn_io_profidrive_parameter_response); + proto_item_set_text(profidrive_item, "PROFIDrive Parameter Response: "); + + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_request_reference, &request_reference); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_response_id, &response_id); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_do_id, &do_id); + offset = dissect_dcerpc_uint8(tvb, offset, pinfo, profidrive_tree, drep, + hf_pn_io_profidrive_no_of_parameters, &no_of_parameters); + + proto_item_append_text(profidrive_item, "ReqRef:0x%02x, RspId:%s, DO:%u, NoOfParameters:%u", + request_reference, val_to_str(response_id, pn_io_profidrive_response_id_vals, "Unknown"), + do_id, no_of_parameters); + + col_add_fstr(pinfo->cinfo, COL_INFO, "PROFIDrive Read Response, ReqRef:0x%02x, RspId:%s", + request_reference, + val_to_str(response_id, pn_io_profidrive_response_id_vals, "Unknown response")); + return offset; +} + +static int +dissect_RecordDataRead(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, guint16 u16Index, guint32 u32RecDataLen) +{ + const gchar *userProfile; + pnio_ar_t *ar = NULL; + + + /* user specified format? */ + if (u16Index < 0x8000) { + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u32RecDataLen, "User Specified Data"); + return offset; + } + + /* profidrive parameter access response */ + if (u16Index == 0xb02e || u16Index == 0xb02f) { + return dissect_ProfiDriveParameterResponse(tvb, offset, pinfo, tree, drep); + } + + /* "reserved for profiles"? */ + userProfile = indexReservedForProfiles(u16Index); + if (userProfile != NULL) { + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u32RecDataLen, userProfile); + return offset; + } + + /* see: pn_io_index */ + /* single block only */ + switch (u16Index) { + case(0x8010): /* Maintenance required in channel coding for one subslot */ + case(0x8011): /* Maintenance demanded in channel coding for one subslot */ + case(0x8012): /* Maintenance required in all codings for one subslot */ + case(0x8013): /* Maintenance demanded in all codings for one subslot */ + case(0x801e): /* SubstituteValues for one subslot */ + case(0x8028): /* RecordInputDataObjectElement for one subslot */ + case(0x8029): /* RecordOutputDataObjectElement for one subslot */ + case(0x8050): /* PDInterfaceMrpDataReal for one subslot */ + case(0x8051): /* PDInterfaceMrpDataCheck for one subslot */ + case(0x8052): /* PDInterfaceMrpDataAdjust for one subslot */ + case(0x8053): /* PDPortMrpDataAdjust for one subslot */ + case(0x8054): /* PDPortMrpDataReal for one subslot */ + case(0x8060): /* PDPortFODataReal for one subslot */ + case(0x8061): /* PDPortFODataCheck for one subslot */ + case(0x8062): /* PDPortFODataAdjust for one subslot */ + case(0x8070): /* PDNCDataCheck for one subslot */ + case(0x8071): /* PDPortStatistic for one subslot */ + case(0x8080): /* PDInterfaceDataReal */ + case(0x8090): /* PDInterfaceFSUDataAdjust */ + case(0x80CF): /* RS_AdjustObserver */ + + case(0xaff0): /* I&M0 */ + case(0xaff1): /* I&M1 */ + case(0xaff2): /* I&M2 */ + case(0xaff3): /* I&M3 */ + case(0xaff4): /* I&M4 */ + case(0xaff5): /* I&M5 */ + case(0xaff6): /* I&M6 */ + case(0xaff7): /* I&M7 */ + case(0xaff8): /* I&M8 */ + case(0xaff9): /* I&M9 */ + case(0xaffa): /* I&M10 */ + case(0xaffb): /* I&M11 */ + case(0xaffc): /* I&M12 */ + case(0xaffd): /* I&M13 */ + case(0xaffe): /* I&M14 */ + case(0xafff): /* I&M15 */ + + case(0xc010): /* Maintenance required in channel coding for one slot */ + case(0xc011): /* Maintenance demanded in channel coding for one slot */ + case(0xc012): /* Maintenance required in all codings for one slot */ + case(0xc013): /* Maintenance demanded in all codings for one slot */ + + case(0xe002): /* ModuleDiffBlock for one AR */ + case(0xe010): /* Maintenance required in channel coding for one AR */ + case(0xe011): /* Maintenance demanded in channel coding for one AR */ + case(0xe012): /* Maintenance required in all codings for one AR */ + case(0xe013): /* Maintenance demanded in all codings for one AR */ + + case(0xf010): /* Maintenance required in channel coding for one API */ + case(0xf011): /* Maintenance demanded in channel coding for one API */ + case(0xf012): /* Maintenance required in all codings for one API */ + case(0xf013): /* Maintenance demanded in all codings for one API */ + case(0xf020): /* ARData for one API */ + + case(0xf820): /* ARData */ + case(0xf821): /* APIData */ + case(0xf830): /* LogData */ + case(0xf831): /* PDevData */ + case(0xf880) : /* AssetManagementData */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + break; + + case(0xf840): /* I&M0FilterData */ + { + int end_offset = offset + u32RecDataLen; + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + if (end_offset > offset) + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + if (end_offset > offset) + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + } + break; + + case(0xB050): + case(0xB051): + case(0xB060): + case(0xB061): + + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + break; + + + /*** multiple blocks possible ***/ + case(0x8000): /* ExpectedIdentificationData for one subslot */ + case(0x8001): /* RealIdentificationData for one subslot */ + case(0x800a): /* Diagnosis in channel decoding for one subslot */ + case(0x800b): /* Diagnosis in all codings for one subslot */ + case(0x800c): /* Diagnosis, Maintenance, Qualified and Status for one subslot */ + + case(0x802a): /* PDPortDataReal */ + case(0x802b): /* PDPortDataCheck */ + case(0x802d): /* Expected PDSyncData for one subslot with SyncID value 0 for PTCPoverRTA */ + case(0x802e): /* Expected PDSyncData for one subslot with SyncID value 0 for PTCPoverRTC */ + case(0x802f): /* PDPortDataAdjust */ + case(0x8030): /* IsochronousModeData for one subslot */ + case(0x8031): /* Expected PDSyncData for one subslot with SyncID value 1 */ + case(0x8032): + case(0x8033): + case(0x8034): + case(0x8035): + case(0x8036): + case(0x8037): + case(0x8038): + case(0x8039): + case(0x803a): + case(0x803b): + case(0x803c): + case(0x803d): + case(0x803e): + case(0x803f): + case(0x8040): /* Expected PDSyncData for one subslot with SyncID value 2 ... 30 */ + case(0x8041): + case(0x8042): + case(0x8043): + case(0x8044): + case(0x8045): + case(0x8046): + case(0x8047): + case(0x8048): + case(0x8049): + case(0x804a): + case(0x804b): + case(0x804c): + case(0x804d): + case(0x804e): + case(0x804f): /* Expected PDSyncData for one subslot with SyncID value 31 */ + case(0x8072): /* PDPortStatistic for one subslot */ + case(0xc000): /* ExpectedIdentificationData for one slot */ + case(0xc001): /* RealIdentificationData for one slot */ + case(0xc00a): /* Diagnosis in channel coding for one slot */ + case(0xc00b): /* Diagnosis in all codings for one slot */ + case(0xc00c): /* Diagnosis, Maintenance, Qualified and Status for one slot */ + + case(0xe000): /* ExpectedIdentificationData for one AR */ + case(0xe001): /* RealIdentificationData for one AR */ + case(0xe00a): /* Diagnosis in channel decoding for one AR */ + case(0xe00b): /* Diagnosis in all codings for one AR */ + case(0xe00c): /* Diagnosis, Maintenance, Qualified and Status for one AR */ + case(0xe030): /* IsochronousModeData for one AR */ + case(0xE060): /* RS_GetEvent (using RecordDataRead service) */ + case(0xf000): /* RealIdentificationData for one API */ + case(0xf00a): /* Diagnosis in channel decoding for one API */ + case(0xf00b): /* Diagnosis in all codings for one API */ + case(0xf00c): /* Diagnosis, Maintenance, Qualified and Status for one API */ + case(0xf80c): /* Diagnosis, Maintenance, Qualified and Status for one device */ + case(0xf841): /* PDRealData */ + case(0xf842): /* PDExpectedData */ + offset = dissect_blocks(tvb, offset, pinfo, tree, drep); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, u32RecDataLen); + } + + 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, dcerpc_info *di, guint8 *drep) +{ + guint16 u16Index = 0; + guint32 u32RecDataLen = 0; + pnio_ar_t *ar = NULL; + + offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, di, drep); + + /* IODReadHeader */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + + /* RecordDataRead */ + if (u32RecDataLen != 0) { + offset = dissect_RecordDataRead(tvb, offset, pinfo, tree, drep, u16Index, u32RecDataLen); + } + + if (ar != NULL) { + pnio_ar_info(tvb, pinfo, tree, ar); + } + + return offset; +} + +/* F-Parameter record data object */ +static int +dissect_ProfiSafeParameterRequest(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, guint16 u16Index, wmem_list_frame_t *frame) +{ + proto_item *f_item; + proto_tree *f_tree; + proto_item *flags1_item; + proto_tree *flags1_tree; + proto_item *flags2_item; + proto_tree *flags2_tree; + guint16 src_addr; + guint16 dst_addr; + guint16 wd_time; + guint16 par_crc; + guint32 ipar_crc = 0; + guint8 prm_flag1; + guint8 prm_flag1_chck_seq; + guint8 prm_flag1_chck_ipar; + guint8 prm_flag1_sil; + guint8 prm_flag1_crc_len; + guint8 prm_flag1_crc_seed; + guint8 prm_flag1_reserved; + guint8 prm_flag2; + guint8 prm_flag2_reserved; + guint8 prm_flag2_f_block_id; + guint8 prm_flag2_f_par_version; + + conversation_t *conversation; + stationInfo *station_info; + ioDataObject *io_data_object; + wmem_list_frame_t *frame_out; + + f_item = proto_tree_add_item(tree, hf_pn_io_block, tvb, offset, 0, ENC_NA); + f_tree = proto_item_add_subtree(f_item, ett_pn_io_profisafe_f_parameter); + proto_item_set_text(f_item, "F-Parameter: "); + + flags1_item = proto_tree_add_item(f_tree, hf_pn_io_ps_f_prm_flag1, tvb, offset, 1, ENC_BIG_ENDIAN); + flags1_tree = proto_item_add_subtree(flags1_item, ett_pn_io_profisafe_f_parameter_prm_flag1); + + /* dissection of F_Prm_Flag1 */ + dissect_dcerpc_uint8(tvb, offset, pinfo, flags1_tree, drep, + hf_pn_io_ps_f_prm_flag1_chck_seq, &prm_flag1_chck_seq); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags1_tree, drep, + hf_pn_io_ps_f_prm_flag1_chck_ipar, &prm_flag1_chck_ipar); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags1_tree, drep, + hf_pn_io_ps_f_prm_flag1_sil, &prm_flag1_sil); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags1_tree, drep, + hf_pn_io_ps_f_prm_flag1_crc_len, &prm_flag1_crc_len); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags1_tree, drep, + hf_pn_io_ps_f_prm_flag1_crc_seed, &prm_flag1_crc_seed); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags1_tree, drep, + hf_pn_io_ps_f_prm_flag1_reserved, &prm_flag1_reserved); + prm_flag1 = prm_flag1_chck_seq|prm_flag1_chck_ipar|prm_flag1_sil|prm_flag1_crc_len|prm_flag1_crc_seed|prm_flag1_reserved; + offset++; + + flags2_item = proto_tree_add_item(f_tree, hf_pn_io_ps_f_prm_flag2, tvb, offset, 1, ENC_BIG_ENDIAN); + flags2_tree = proto_item_add_subtree(flags2_item, ett_pn_io_profisafe_f_parameter_prm_flag2); + + /* dissection of F_Prm_Flag2 */ + dissect_dcerpc_uint8(tvb, offset, pinfo, flags2_tree, drep, + hf_pn_io_ps_f_prm_flag2_reserved, &prm_flag2_reserved); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags2_tree, drep, + hf_pn_io_ps_f_prm_flag2_f_block_id, &prm_flag2_f_block_id); + dissect_dcerpc_uint8(tvb, offset, pinfo, flags2_tree, drep, + hf_pn_io_ps_f_prm_flag2_f_par_version, &prm_flag2_f_par_version); + prm_flag2 = prm_flag2_reserved|prm_flag2_f_block_id|prm_flag2_f_par_version; + offset++; + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, f_item, drep, + hf_pn_io_ps_f_src_adr, &src_addr); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, f_item, drep, + hf_pn_io_ps_f_dest_adr, &dst_addr); + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, f_item, drep, + hf_pn_io_ps_f_wd_time, &wd_time); + + /* Dissection for F_iPar_CRC: see F_Prm_Flag2 -> F_Block_ID */ + if( (prm_flag2_f_block_id & 0x08) && !(prm_flag2_f_block_id & 0x20) ) { + offset = dissect_dcerpc_uint32(tvb, offset, pinfo, f_item, drep, + hf_pn_io_ps_f_ipar_crc, &ipar_crc); + } + + offset = dissect_dcerpc_uint16(tvb, offset, pinfo, f_item, drep, + hf_pn_io_ps_f_par_crc, &par_crc); + + + /* Differniate between ipar_crc and no_ipar_crc */ + if( (prm_flag2_f_block_id & 0x08) && !(prm_flag2_f_block_id & 0x20) ) { /* include ipar_crc display */ + col_append_fstr(pinfo->cinfo, COL_INFO, + ", F-Parameter record, prm_flag1:0x%02x, prm_flag2:0x%02x, src:0x%04x," + " dst:0x%04x, wd_time:%d, ipar_crc:0x%04x, crc:0x%04x", + prm_flag1, prm_flag2, src_addr, dst_addr, wd_time, ipar_crc, par_crc); + + proto_item_append_text(f_item, "prm_flag1:0x%02x, prm_flag2:0x%02x, src:0x%04x, dst:0x%04x, wd_time:%d, ipar_crc:0x%04x, par_crc:0x%04x", + prm_flag1, prm_flag2, src_addr, dst_addr, wd_time, ipar_crc, par_crc); + } + else { /* exclude ipar_crc display */ + col_append_fstr(pinfo->cinfo, COL_INFO, + ", F-Parameter record, prm_flag1:0x%02x, prm_flag2:0x%02x, src:0x%04x," + " dst:0x%04x, wd_time:%d, crc:0x%04x", + prm_flag1, prm_flag2, src_addr, dst_addr, wd_time, par_crc); + + proto_item_append_text(f_item, "prm_flag1:0x%02x, prm_flag2:0x%02x, src:0x%04x, dst:0x%04x, wd_time:%d, par_crc:0x%04x", + prm_flag1, prm_flag2, src_addr, dst_addr, wd_time, par_crc); + } + + if (!pinfo->fd->flags.visited) { + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info != NULL) { + if (frame != NULL) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + + io_data_object->f_par_crc1 = par_crc; + io_data_object->f_src_adr = src_addr; + io_data_object->f_dest_adr = dst_addr; + io_data_object->f_crc_seed = prm_flag1 & 0x40; + if (!(prm_flag1 & 0x10)) { + if (prm_flag1 & 0x20) { + io_data_object->f_crc_len = 4; + } else { + io_data_object->f_crc_len = 3; + } + } + } + + /* Find same module within output data to saved data */ + for (frame_out = wmem_list_head(station_info->ioobject_data_out); frame_out != NULL; frame_out = wmem_list_frame_next(frame_out)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame_out); + if (u16Index == io_data_object->fParameterIndexNr && /* Check F-Parameter Indexnumber */ + io_data_object->profisafeSupported && /* Arrayelement has to be PS-Module */ + io_data_object->f_par_crc1 == 0) { /* Find following object with no f_par_crc1 */ + + io_data_object->f_par_crc1 = par_crc; + io_data_object->f_src_adr = src_addr; + io_data_object->f_dest_adr = dst_addr; + io_data_object->f_crc_seed = prm_flag1 & 0x40; + if (!(prm_flag1 & 0x10)) { + if (prm_flag1 & 0x20) { + io_data_object->f_crc_len = 4; + } else { + io_data_object->f_crc_len = 3; + } + } + + break; + } + } + } + } + + return offset; +} + +static int +dissect_RecordDataWrite(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, guint16 u16Index, guint32 u32RecDataLen) +{ + conversation_t *conversation; + stationInfo *station_info; + wmem_list_frame_t *frame; + ioDataObject *io_data_object; + + const gchar *userProfile; + pnio_ar_t *ar = NULL; + + /* PROFISafe */ + /* Get current conversation endpoints using MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info != NULL) { + if (!pinfo->fd->flags.visited) { + /* Search within the entire existing list for current input object data */ + for (frame = wmem_list_head(station_info->ioobject_data_in); frame != NULL; frame = wmem_list_frame_next(frame)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (u16Index == io_data_object->fParameterIndexNr && /* Check F-Parameter Indexnumber */ + io_data_object->profisafeSupported && /* Arrayelement has to be PS-Module */ + io_data_object->f_par_crc1 == 0) { /* Find following object with no f_par_crc1 */ + + return dissect_ProfiSafeParameterRequest(tvb, offset, pinfo, tree, drep, u16Index, frame); + } + } + } + else { + /* User clicked another time the frame to see the data -> PROFIsafe data has already been saved + * Check whether the device contains an PROFIsafe supported submodule. + */ + + for (frame = wmem_list_head(station_info->ioobject_data_in); frame != NULL; frame = wmem_list_frame_next(frame)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (u16Index == io_data_object->fParameterIndexNr && /* Check F-Parameter Indexnumber */ + io_data_object->profisafeSupported) { /* Arrayelement has to be PS-Module */ + + return dissect_ProfiSafeParameterRequest(tvb, offset, pinfo, tree, drep, u16Index, frame); + } + } + + for (frame = wmem_list_head(station_info->ioobject_data_out); frame != NULL; frame = wmem_list_frame_next(frame)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (u16Index == io_data_object->fParameterIndexNr && /* Check F-Parameter Indexnumber */ + io_data_object->profisafeSupported) { /* Arrayelement has to be PS-Module */ + + return dissect_ProfiSafeParameterRequest(tvb, offset, pinfo, tree, drep, u16Index, frame); + } + } + } + } + + /* user specified format? */ + if (u16Index < 0x8000) { + return dissect_pn_user_data(tvb, offset, pinfo, tree, u32RecDataLen, "User Specified Data"); + } + + /* profidrive parameter request */ + if (u16Index == 0xb02e || u16Index == 0xb02f) { + return dissect_ProfiDriveParameterRequest(tvb, offset, pinfo, tree, drep); + } + + /* "reserved for profiles"? */ + userProfile = indexReservedForProfiles(u16Index); + if (userProfile != NULL) { + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, u32RecDataLen, userProfile); + return offset; + } + + /* see: pn_io_index */ + switch (u16Index) { + case(0x8020): /* PDIRSubframeData */ + case(0x801e): /* SubstituteValues for one subslot */ + case(0x802b): /* PDPortDataCheck for one subslot */ + case(0x802c): /* PDirData for one subslot */ + case(0x802d): /* Expected PDSyncData for one subslot with SyncID value 0 for PTCPoverRTA */ + case(0x802e): /* Expected PDSyncData for one subslot with SyncID value 0 for PTCPoverRTC */ + case(0x802f): /* PDPortDataAdjust for one subslot */ + case(0x8030): /* IsochronousModeData for one subslot */ + case(0x8051): /* PDInterfaceMrpDataCheck for one subslot */ + case(0x8052): /* PDInterfaceMrpDataAdjust for one subslot */ + case(0x8053): /* PDPortMrpDataAdjust for one subslot */ + case(0x8061): /* PDPortFODataCheck for one subslot */ + case(0x8062): /* PDPortFODataAdjust for one subslot */ + case(0x8070): /* PDNCDataCheck for one subslot */ + case(0x8071): /* PDInterfaceAdjust */ + case(0x8090): /* PDInterfaceFSUDataAdjust */ + case(0x80B0): /* CombinedObjectContainer*/ + case(0x80CF): /* RS_AdjustObserver */ + case(0xe030): /* IsochronousModeData for one AR */ + case(0xe050): /* FastStartUp data for one AR */ + case(0xe061): /* RS_AckEvent (using RecordDataWrite service) */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, u32RecDataLen); + } + + return offset; +} + +#define PN_IO_MAX_RECURSION_DEPTH 100 + +static int +dissect_IODWriteReq(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep, pnio_ar_t **ar, guint recursion_count) +{ + guint16 u16Index = 0; + guint32 u32RecDataLen = 0; + + if (++recursion_count >= PN_IO_MAX_RECURSION_DEPTH) { + proto_tree_add_expert(tree, pinfo, &ei_pn_io_max_recursion_depth_reached, + tvb, 0, 0); + return tvb_captured_length(tvb); + } + + /* IODWriteHeader */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, ar); + + /* IODWriteMultipleReq? */ + if (u16Index == 0xe040) { + while (tvb_captured_length_remaining(tvb, offset) > 0) { + offset = dissect_IODWriteReq(tvb, offset, pinfo, tree, drep, ar, recursion_count++); + } + } else { + tvbuff_t *new_tvb = tvb_new_subset_length(tvb, offset, u32RecDataLen); + /* RecordDataWrite */ + offset += dissect_RecordDataWrite(new_tvb, 0, pinfo, tree, drep, u16Index, u32RecDataLen); + + /* Padding */ + switch (offset % 4) { + case(3): + offset += 1; + break; + case(2): + offset += 2; + break; + case(1): + offset += 3; + break; + default: /* will not execute because of the line preceding the switch */ + break; + } + } + + 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, dcerpc_info *di, guint8 *drep) +{ + pnio_ar_t *ar = NULL; + guint recursion_count = 0; + + offset = dissect_IPNIO_rqst_header(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_IODWriteReq(tvb, offset, pinfo, tree, drep, &ar, recursion_count); + + if (ar != NULL) { + pnio_ar_info(tvb, pinfo, tree, ar); + } + + return offset; +} + + + +static int +dissect_IODWriteRes(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep) +{ + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + + /* IODWriteResHeader */ + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + + /* IODWriteMultipleRes? */ + if (u16Index == 0xe040) { + while (tvb_captured_length_remaining(tvb, offset) > 0) { + offset = dissect_block(tvb, offset, pinfo, tree, drep, &u16Index, &u32RecDataLen, &ar); + } + } + + if (ar != NULL) { + pnio_ar_info(tvb, pinfo, tree, ar); + } + + 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, dcerpc_info *di, guint8 *drep) +{ + + offset = dissect_IPNIO_resp_header(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_IODWriteRes(tvb, offset, pinfo, tree, drep); + + return offset; +} + + +/* dissect the IOxS (IOCS, IOPS) field */ +static int +dissect_PNIO_IOxS(tvbuff_t *tvb, int offset, + packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex) +{ + + if (tree) { + guint8 u8IOxS; + proto_item *ioxs_item; + proto_tree *ioxs_tree; + + u8IOxS = tvb_get_guint8(tvb, offset); + + /* add ioxs subtree */ + ioxs_item = proto_tree_add_uint(tree, hfindex, tvb, offset, 1, u8IOxS); + proto_item_append_text(ioxs_item, + " (%s%s)", + (u8IOxS & 0x01) ? "another IOxS follows " : "", + (u8IOxS & 0x80) ? "good" : "bad"); + ioxs_tree = proto_item_add_subtree(ioxs_item, ett_pn_io_ioxs); + + proto_tree_add_uint(ioxs_tree, hf_pn_io_ioxs_datastate, tvb, offset, 1, u8IOxS); + proto_tree_add_uint(ioxs_tree, hf_pn_io_ioxs_instance, tvb, offset, 1, u8IOxS); + proto_tree_add_uint(ioxs_tree, hf_pn_io_ioxs_res14, tvb, offset, 1, u8IOxS); + proto_tree_add_uint(ioxs_tree, hf_pn_io_ioxs_extension, tvb, offset, 1, u8IOxS); + } + + return offset + 1; +} + + +/* dissect a PN-IO Cyclic Service Data Unit (on top of PN-RT protocol) */ +static int +dissect_PNIO_C_SDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep _U_) +{ + proto_tree *data_tree = NULL; + /* gint iTotalLen = 0; */ + /* gint iSubFrameLen = 0; */ + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO"); + + if (tree) { + proto_item *data_item; + data_item = proto_tree_add_protocol_format(tree, proto_pn_io, tvb, offset, tvb_captured_length(tvb), + "PROFINET IO Cyclic Service Data Unit: %u bytes", tvb_captured_length(tvb)); + data_tree = proto_item_add_subtree(data_item, ett_pn_io_rtc); + } + + /*dissect_dcerpc_uint16(tvb, offset, pinfo, data_tree, drep, hf_pn_io_packedframe_SFCRC, &u16SFCRC);*/ + if (dissect_CSF_SDU_heur(tvb, pinfo, data_tree, NULL)) + return(tvb_captured_length(tvb)); + + /* XXX - dissect the remaining data */ + /* this will be one or more DataItems followed by an optional GAP and RTCPadding */ + /* as we don't have the required context information to dissect the specific DataItems, */ + /* this will be tricky :-( */ + /* actual: there may be an IOxS but most case there isn't so better display a data-stream */ + /* offset = dissect_PNIO_IOxS(tvb, offset, pinfo, data_tree, drep, hf_pn_io_ioxs); */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset), + "User Data (including GAP and RTCPadding)"); + + 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; + int start_offset = offset; + guint16 u16Index = 0; + guint32 u32RecDataLen; + pnio_ar_t *ar = NULL; + + + proto_item *rta_item; + proto_tree *rta_tree; + + proto_item *sub_item; + proto_tree *sub_tree; + + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO-AL"); + + rta_item = proto_tree_add_protocol_format(tree, proto_pn_io, tvb, offset, tvb_captured_length(tvb), + "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); + + 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, ENC_NA); + 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, ENC_NA); + 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 */ + col_append_str(pinfo->cinfo, COL_INFO, ", Data-RTA"); + offset = dissect_block(tvb, offset, pinfo, rta_tree, drep, &u16Index, &u32RecDataLen, &ar); + break; + case(2): /* NACK-RTA */ + col_append_str(pinfo->cinfo, COL_INFO, ", NACK-RTA"); + /* no additional data */ + break; + case(3): /* ACK-RTA */ + col_append_str(pinfo->cinfo, COL_INFO, ", ACK-RTA"); + /* no additional data */ + break; + case(4): /* ERR-RTA */ + col_append_str(pinfo->cinfo, COL_INFO, ", ERR-RTA"); + offset = dissect_PNIO_status(tvb, offset, pinfo, rta_tree, drep); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length(tvb)); + } + + proto_item_set_len(rta_item, offset - start_offset); + + return offset; +} + + +/* possibly dissect a PN-IO related PN-RT packet */ +static gboolean +dissect_PNIO_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + void *data) +{ + guint8 drep_data = 0; + guint8 *drep = &drep_data; + guint8 u8CBAVersion; + /* the sub tvb will NOT contain the frame_id here! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + heur_dtbl_entry_t *hdtbl_entry; + + /* + * In case the packet is a protocol encoded in the basic PNIO transport stream, + * give that protocol a chance to make a heuristic dissection, before we continue + * to dissect it as a normal PNIO packet. + */ + if (dissector_try_heuristic(heur_pn_subdissector_list, tvb, pinfo, tree, &hdtbl_entry, NULL)) + return TRUE; + + u8CBAVersion = tvb_get_guint8 (tvb, 0); + + /* is this a (none DFP) PNIO class 3 data packet? */ + /* frame id must be in valid range (cyclic Real-Time, class=3) */ + if ((u16FrameID >= 0x0100 && u16FrameID <= 0x06FF) || /* RTC3 non redundant */ + (u16FrameID >= 0x700 && u16FrameID <= 0x0fff)) { /* RTC3 redundant */ + dissect_PNIO_C_SDU(tvb, 0, pinfo, tree, drep); + return TRUE; + } + + /* The following range is reserved for following developments */ + /* frame id must be in valid range (Reserved) and + * first byte (CBA version field) has to be != 0x11 */ + if (u16FrameID >= 0x1000 && u16FrameID <= 0x7fff && u8CBAVersion != 0x11) { + dissect_PNIO_C_SDU(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 >= 0x8000 && u16FrameID < 0xbfff && u8CBAVersion != 0x11) { + dissect_PNIO_C_SDU_RTC1(tvb, 0, pinfo, tree, drep); + return TRUE; + } + + /* is this a PNIO class 1 (legacy) data packet? */ + /* frame id must be in valid range (cyclic Real-Time, class=1, legacy) and + * first byte (CBA version field) has to be != 0x11 */ + if (u16FrameID >= 0xc000 && u16FrameID < 0xfbff && u8CBAVersion != 0x11) { + dissect_PNIO_C_SDU_RTC1(tvb, 0, pinfo, tree, drep); + return TRUE; + } + + /* is this a PNIO high priority alarm packet? */ + if (u16FrameID == 0xfc01) { + col_set_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) { + col_set_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; +} + + + +static gboolean +pn_io_ar_conv_valid(packet_info *pinfo) +{ + void* profinet_type = p_get_proto_data(pinfo->pool, pinfo, proto_pn_io, 0); + + return ((profinet_type != NULL) && (GPOINTER_TO_UINT(profinet_type) == 10)); +} + +static gchar * +pn_io_ar_conv_filter(packet_info *pinfo) +{ + pnio_ar_t *ar = (pnio_ar_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pn_io, 0); + void* profinet_type = p_get_proto_data(pinfo->pool, pinfo, proto_pn_io, 0); + char *buf; + address controllermac_addr, devicemac_addr; + + if ((profinet_type == NULL) || (GPOINTER_TO_UINT(profinet_type) != 10) || (ar == NULL)) { + return NULL; + } + + set_address(&controllermac_addr, AT_ETHER, 6, ar->controllermac); + set_address(&devicemac_addr, AT_ETHER, 6, ar->devicemac); + + buf = g_strdup_printf( + "pn_io.ar_uuid == %s || " /* ARUUID */ + "(pn_io.alarm_src_endpoint == 0x%x && eth.src == %s) || " /* Alarm CR (contr -> dev) */ + "(pn_io.alarm_src_endpoint == 0x%x && eth.src == %s)", /* Alarm CR (dev -> contr) */ + guid_to_str(pinfo->pool, (const e_guid_t*) &ar->aruuid), + ar->controlleralarmref, address_to_str(pinfo->pool, &controllermac_addr), + ar->devicealarmref, address_to_str(pinfo->pool, &devicemac_addr)); + return buf; +} + +static gchar * +pn_io_ar_conv_data_filter(packet_info *pinfo) +{ + pnio_ar_t *ar = (pnio_ar_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pn_io, 0); + void* profinet_type = p_get_proto_data(pinfo->pool, pinfo, proto_pn_io, 0); + char *buf, *controllermac_str, *devicemac_str, *guid_str; + address controllermac_addr, devicemac_addr; + + if ((profinet_type == NULL) || (GPOINTER_TO_UINT(profinet_type) != 10) || (ar == NULL)) { + return NULL; + } + + set_address(&controllermac_addr, AT_ETHER, 6, ar->controllermac); + set_address(&devicemac_addr, AT_ETHER, 6, ar->devicemac); + + controllermac_str = address_to_str(pinfo->pool, &controllermac_addr); + devicemac_str = address_to_str(pinfo->pool, &devicemac_addr); + guid_str = guid_to_str(pinfo->pool, (const e_guid_t*) &ar->aruuid); + if (ar->arType == 0x0010) /* IOCARSingle using RT_CLASS_3 */ + { + buf = g_strdup_printf( + "pn_io.ar_uuid == %s || " /* ARUUID */ + "(pn_rt.frame_id == 0x%x) || (pn_rt.frame_id == 0x%x) || " + "(pn_io.alarm_src_endpoint == 0x%x && eth.src == %s) || " /* Alarm CR (contr -> dev) */ + "(pn_io.alarm_src_endpoint == 0x%x && eth.src == %s)", /* Alarm CR (dev -> contr) */ + guid_str, + ar->inputframeid, ar->outputframeid, + ar->controlleralarmref, controllermac_str, + ar->devicealarmref, devicemac_str); + } + else + { + buf = g_strdup_printf( + "pn_io.ar_uuid == %s || " /* ARUUID */ + "(pn_rt.frame_id == 0x%x && eth.src == %s && eth.dst == %s) || " /* Input CR && dev MAC -> contr MAC */ + "(pn_rt.frame_id == 0x%x && eth.src == %s && eth.dst == %s) || " /* Output CR && contr MAC -> dev MAC */ + "(pn_io.alarm_src_endpoint == 0x%x && eth.src == %s) || " /* Alarm CR (contr -> dev) */ + "(pn_io.alarm_src_endpoint == 0x%x && eth.src == %s)", /* Alarm CR (dev -> contr) */ + guid_str, + ar->inputframeid, devicemac_str, controllermac_str, + ar->outputframeid, controllermac_str, devicemac_str, + ar->controlleralarmref, controllermac_str, + ar->devicealarmref, devicemac_str); + } + return buf; +} + + + +/* the PNIO dcerpc interface table */ +static dcerpc_sub_dissector pn_io_dissectors[] = { + { 0, "Connect", dissect_IPNIO_rqst, dissect_IPNIO_resp }, + { 1, "Release", dissect_IPNIO_rqst, dissect_IPNIO_resp }, + { 2, "Read", dissect_IPNIO_rqst, dissect_IPNIO_Read_resp }, + { 3, "Write", dissect_IPNIO_Write_rqst, dissect_IPNIO_Write_resp }, + { 4, "Control", dissect_IPNIO_rqst, dissect_IPNIO_resp }, + { 5, "Read Implicit", dissect_IPNIO_rqst, dissect_IPNIO_Read_resp }, + { 0, NULL, NULL, NULL } +}; + + +static void +pnio_cleanup(void) { + g_list_free(pnio_ars); + pnio_ars = 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, + NULL, HFILL } + }, + { &hf_pn_io_reserved16, + { "Reserved", "pn_io.reserved16", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_array, + { "Array", "pn_io.array", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_status, + { "Status", "pn_io.status", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_args_max, + { "ArgsMaximum", "pn_io.args_max", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_args_len, + { "ArgsLength", "pn_io.args_len", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_array_max_count, + { "MaximumCount", "pn_io.array_max_count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_array_offset, + { "Offset", "pn_io.array_offset", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_array_act_count, + { "ActualCount", "pn_io.array_act_count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_ar_data, + { "ARDATA for AR:", "pn_io.ar_data", + FT_NONE, BASE_NONE, 0x0, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_type, + { "ARType", "pn_io.ar_type", + FT_UINT16, BASE_HEX, VALS(pn_io_ar_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_cminitiator_macadd, + { "CMInitiatorMacAdd", "pn_io.cminitiator_mac_add", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_cminitiator_objectuuid, + { "CMInitiatorObjectUUID", "pn_io.cminitiator_uuid", + FT_GUID, BASE_NONE, 0x0, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_parameter_server_objectuuid, + { "ParameterServerObjectUUID", "pn_io.parameter_server_objectuuid", + FT_GUID, BASE_NONE, 0x0, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties, + { "ARProperties", "pn_io.ar_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_state, + { "State", "pn_io.ar_properties.state", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_state), 0x00000007, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_supervisor_takeover_allowed, + { "SupervisorTakeoverAllowed", "pn_io.ar_properties.supervisor_takeover_allowed", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_supervisor_takeover_allowed), 0x00000008, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_parametrization_server, + { "ParametrizationServer", "pn_io.ar_properties.parametrization_server", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_parametrization_server), 0x00000010, + NULL, HFILL } + }, + { &hf_pn_io_artype_req, + { "ARType", "pn_io.artype_req", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_pn_io_ar_properties_companion_ar, + { "CompanionAR", "pn_io.ar_properties.companion_ar", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_companion_ar), 0x00000600, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_achnowledge_companion_ar, + { "AcknowledgeCompanionAR", "pn_io.ar_properties.acknowledge_companion_ar", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_acknowldege_companion_ar), 0x00000800, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_reserved, + { "Reserved", "pn_io.ar_properties.reserved", + FT_UINT32, BASE_HEX, NULL, 0x1FFFF000, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_combined_object_container_with_legacy_startupmode, + { "CombinedObjectContainer", "pn_io.ar_properties.combined_object_container", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_combined_object_container_with_legacy_startupmode), 0x20000000, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_combined_object_container_with_advanced_startupmode, + { "CombinedObjectContainer", "pn_io.ar_properties.combined_object_container", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_combined_object_container_with_advanced_startupmode), 0x20000000, + NULL, HFILL } + }, + { &hf_pn_io_arproperties_StartupMode, + { "StartupMode", "pn_io.ar_properties.StartupMode", + FT_UINT32, BASE_HEX, VALS(pn_io_arpropertiesStartupMode), 0x40000000, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_pull_module_alarm_allowed, + { "PullModuleAlarmAllowed", "pn_io.ar_properties.pull_module_alarm_allowed", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_pull_module_alarm_allowed), 0x80000000, + NULL, HFILL } + }, + { &hf_pn_RedundancyInfo, + { "RedundancyInfo.EndPoint", "pn_io.srl_data.redundancyInfo", + FT_UINT16, BASE_HEX, VALS(pn_io_RedundancyInfo), 0x0000003, + NULL, HFILL } + }, + { &hf_pn_RedundancyInfo_reserved, + { "RedundancyInfo.reserved", "pn_io.srl_data.redundancyInfoReserved", + FT_UINT16, BASE_HEX, NULL, 0xFFFFFFFC, + NULL, HFILL } + }, + { &hf_pn_io_number_of_ARDATAInfo, + { "ARDataInfo.NumberOfEntries", "pn_io.number_of_ARDATAInfo", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_cminitiator_activitytimeoutfactor, + { "CMInitiatorActivityTimeoutFactor", "pn_io.cminitiator_activitytimeoutfactor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_cminitiator_udprtport, + { "CMInitiatorUDPRTPort", "pn_io.cminitiator_udprtport", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_station_name_length, + { "StationNameLength", "pn_io.station_name_length", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_cminitiator_station_name, + { "CMInitiatorStationName", "pn_io.cminitiator_station_name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_parameter_server_station_name, + { "ParameterServerStationName", "pn_io.parameter_server_station_name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_cmresponder_macadd, + { "CMResponderMacAdd", "pn_io.cmresponder_macadd", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_cmresponder_udprtport, + { "CMResponderUDPRTPort", "pn_io.cmresponder_udprtport", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_number_of_iocrs, + { "NumberOfIOCRs", "pn_io.number_of_iocrs", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_tree, + { "IOCR", "pn_io.iocr_tree", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_type, + { "IOCRType", "pn_io.iocr_type", + FT_UINT16, BASE_HEX, VALS(pn_io_iocr_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_reference, + { "IOCRReference", "pn_io.iocr_reference", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_SubframeOffset, + { "-> SubframeOffset", "pn_io.subframe_offset", + FT_UINT8, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_SubframeData, + { "SubframeData", "pn_io.subframe_data", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_RedundancyDataHoldFactor, + { "RedundancyDataHoldFactor", "pn_io.RedundancyDataHoldFactor", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_RedundancyDataHoldFactor), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties, + { "SRProperties", "pn_io.sr_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties_InputValidOnBackupAR_with_SRProperties_Mode_0, + { "InputValidOnBackupAR", "pn_io.sr_properties.InputValidOnBackupAR", + FT_BOOLEAN, 32, TFS(&tfs_pn_io_sr_properties_BackupAR_with_SRProperties_Mode_0), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties_InputValidOnBackupAR_with_SRProperties_Mode_1, + { "InputValidOnBackupAR", "pn_io.sr_properties.InputValidOnBackupAR", + FT_BOOLEAN, 32, TFS(&tfs_pn_io_sr_properties_BackupAR_with_SRProperties_Mode_1), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties_Reserved_1, + { "Reserved_1", "pn_io.sr_properties.Reserved_1", + FT_BOOLEAN, 32, TFS(&tfs_pn_io_sr_properties_Reserved1), 0x00000002, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties_Mode, + { "Mode", "pn_io.sr_properties.Mode", + FT_BOOLEAN, 32, TFS(&tfs_pn_io_sr_properties_Mode), 0x00000004, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties_Reserved_2, + { "Reserved_2", "pn_io.sr_properties.Reserved_2", + FT_UINT32, BASE_HEX, NULL, 0x0000FFF8, + NULL, HFILL } + }, + { &hf_pn_io_sr_properties_Reserved_3, + { "Reserved_3", "pn_io.sr_properties.Reserved_3", + FT_UINT32, BASE_HEX, NULL, 0xFFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_arvendor_strucidentifier_if0_low, + { "APStructureIdentifier: Vendor specific", "pn_io.structidentifier_api_0_low", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_arvendor_strucidentifier_if0_high, + { "APStructureIdentifier: Administrative number for common profiles", "pn_io.structidentifier_api_0_high", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_arvendor_strucidentifier_if0_is8000, + { "APStructureIdentifier: Extended identification rules", "pn_io.tructidentifier_api_0_is8000", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_arvendor_strucidentifier_not0, + { "APStructureIdentifier: Administrative number for application profiles", "pn_io.tructidentifier_api_not_0", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_lt, + { "LT", "pn_io.lt", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties, + { "IOCRProperties", "pn_io.iocr_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_rtclass, + { "RTClass", "pn_io.iocr_properties.rtclass", + FT_UINT32, BASE_HEX, VALS(pn_io_iocr_properties_rtclass), 0x0000000F, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_reserved_1, + { "Reserved1", "pn_io.iocr_properties.reserved1", + FT_UINT32, BASE_HEX, NULL, 0x00000FF0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_media_redundancy, + { "MediaRedundancy", "pn_io.iocr_properties.media_redundancy", + FT_UINT32, BASE_HEX, VALS(pn_io_iocr_properties_media_redundancy), 0x00000800, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_reserved_2, + { "Reserved2", "pn_io.iocr_properties.reserved2", + FT_UINT32, BASE_HEX, NULL, 0x00FFF000, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_reserved_3, + { "Reserved3", "pn_io.iocr_properties.reserved3", + FT_UINT32, BASE_HEX, NULL, 0xF000000, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_fast_forwarding_mac_adr, + { "FastForwardingMACAdr", "pn_io.iocr_properties.fast_forwarding_mac_adr", + FT_UINT32, BASE_HEX, NULL, 0x20000000, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_distributed_subframe_watchdog, + { "DistributedSubFrameWatchDog", "pn_io.iocr_properties.distributed_subframe_watchdog", + FT_UINT32, BASE_HEX, NULL, 0x40000000, + NULL, HFILL } + }, + { &hf_pn_io_iocr_properties_full_subframe_structure, + { "FullSubFrameStructure", "pn_io.iocr_properties.full_subframe_structure", + FT_UINT32, BASE_HEX, NULL, 0x80000000, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties, + { "SFIOCRProperties", "pn_io.SFIOCRProperties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_DistributedWatchDogFactor, + { "SFIOCRProperties.DistributedWatchDogFactor", "pn_io.SFIOCRProperties.DistributedWatchDogFactor", + FT_UINT32, BASE_HEX, NULL, 0x0FF, + NULL, HFILL } + }, + { &hf_pn_io_RestartFactorForDistributedWD, + { "SFIOCRProperties.RestartFactorForDistributedWD", "pn_io.SFIOCRProperties.RestartFactorForDistributedWD", + FT_UINT32, BASE_HEX, NULL, 0xff00, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties_DFPmode, + { "SFIOCRProperties.DFPmode", "pn_io.SFIOCRProperties.DFPmode", + FT_UINT32, BASE_HEX, NULL, 0xFF0000, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties_reserved_1, + { "SFIOCRProperties.reserved_1", "pn_io.SFIOCRProperties.reserved_1", + FT_UINT32, BASE_HEX, NULL, 0x0F000000, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties_reserved_2, + { "SFIOCRProperties.reserved_2", "pn_io.SFIOCRProperties.reserved_2", + FT_UINT32, BASE_HEX, NULL, 0x010000000, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties_DFPType, + { "SFIOCRProperties.DFPType", "pn_io.SFIOCRProperties.DFPType", + FT_UINT32, BASE_HEX, VALS(pn_io_SFIOCRProperties_DFPType_vals), 0x020000000, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties_DFPRedundantPathLayout, + { "SFIOCRProperties.DFPRedundantPathLayout", "pn_io.SFIOCRProperties.DFPRedundantPathLayout", + FT_UINT32, BASE_HEX, VALS(pn_io_DFPRedundantPathLayout_decode), 0x040000000, + NULL, HFILL } + }, + { &hf_pn_io_SFIOCRProperties_SFCRC16, + { "SFIOCRProperties.SFCRC16", "pn_io.SFIOCRProperties.SFCRC16", + FT_UINT32, BASE_HEX, VALS(pn_io_SFCRC16_Decode), 0x080000000, + NULL, HFILL } + }, + { &hf_pn_io_data_length, + { "DataLength", "pn_io.data_length", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ir_frame_data, + { "Frame data", "pn_io.ir_frame_data", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_id, + { "FrameID", "pn_io.frame_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_send_clock_factor, + { "SendClockFactor", "pn_io.send_clock_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_reduction_ratio, + { "ReductionRatio", "pn_io.reduction_ratio", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_phase, + { "Phase", "pn_io.phase", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sequence, + { "Sequence", "pn_io.sequence", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_send_offset, + { "FrameSendOffset", "pn_io.frame_send_offset", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_data_properties, + { "FrameDataProperties", "pn_io.frame_data_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_data_properties_forwarding_Mode, + { "ForwardingMode", "pn_io.frame_data_properties_forwardingMode", + FT_UINT32, BASE_HEX, VALS(hf_pn_io_frame_data_properties_forwardingMode), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_frame_data_properties_FastForwardingMulticastMACAdd, + { "FastForwardingMulticastMACAdd", "pn_io.frame_data_properties_MulticastMACAdd", + FT_UINT32, BASE_HEX, VALS(hf_pn_io_frame_data_properties_FFMulticastMACAdd), 0x06, + NULL, HFILL } + }, + { &hf_pn_io_frame_data_properties_FragmentMode, + { "FragmentationMode", "pn_io.frame_data_properties_FragMode", + FT_UINT32, BASE_HEX, VALS(hf_pn_io_frame_data_properties_FragMode), 0x18, + NULL, HFILL } + }, + { &hf_pn_io_frame_data_properties_reserved_1, + { "Reserved_1", "pn_io.frame_data.reserved_1", + FT_UINT32, BASE_HEX, NULL, 0x0000FFE0, + NULL, HFILL } + }, + { &hf_pn_io_frame_data_properties_reserved_2, + { "Reserved_2", "pn_io.frame_data.reserved_2", + FT_UINT32, BASE_HEX, NULL, 0xFFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_watchdog_factor, + { "WatchdogFactor", "pn_io.watchdog_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_data_hold_factor, + { "DataHoldFactor", "pn_io.data_hold_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_tag_header, + { "IOCRTagHeader", "pn_io.iocr_tag_header", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocr_multicast_mac_add, + { "IOCRMulticastMACAdd", "pn_io.iocr_multicast_mac_add", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_apis, + { "NumberOfAPIs", "pn_io.number_of_apis", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_io_data_objects, + { "NumberOfIODataObjects", "pn_io.number_of_io_data_objects", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_iocs, + { "NumberOfIOCS", "pn_io.number_of_iocs", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocs_frame_offset, + { "IOCSFrameOffset", "pn_io.iocs_frame_offset", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarmcr_type, + { "AlarmCRType", "pn_io.alarmcr_type", + FT_UINT16, BASE_HEX, VALS(pn_io_alarmcr_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarmcr_properties, + { "AlarmCRProperties", "pn_io.alarmcr_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarmcr_properties_priority, + { "priority", "pn_io.alarmcr_properties.priority", + FT_UINT32, BASE_HEX, VALS(pn_io_alarmcr_properties_priority), 0x00000001, + NULL, HFILL } + }, + { &hf_pn_io_alarmcr_properties_transport, + { "Transport", "pn_io.alarmcr_properties.transport", + FT_UINT32, BASE_HEX, VALS(pn_io_alarmcr_properties_transport), 0x00000002, + NULL, HFILL } + }, + { &hf_pn_io_alarmcr_properties_reserved, + { "Reserved", "pn_io.alarmcr_properties.reserved", + FT_UINT32, BASE_HEX, NULL, 0xFFFFFFFC, + NULL, HFILL } + }, + { &hf_pn_io_rta_timeoutfactor, + { "RTATimeoutFactor", "pn_io.rta_timeoutfactor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_rta_retries, + { "RTARetries", "pn_io.rta_retries", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, /* XXX - only values 3 - 15 allowed */ + { &hf_pn_io_localalarmref, + { "LocalAlarmReference", "pn_io.localalarmref", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_remotealarmref, + { "RemoteAlarmReference", "pn_io.remotealarmref", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - special values */ + { &hf_pn_io_maxalarmdatalength, + { "MaxAlarmDataLength", "pn_io.maxalarmdatalength", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - only values 200 - 1432 allowed */ + { &hf_pn_io_alarmcr_tagheaderhigh, + { "AlarmCRTagHeaderHigh", "pn_io.alarmcr_tagheaderhigh", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - 16 bitfield! */ + { &hf_pn_io_alarmcr_tagheaderlow, + { "AlarmCRTagHeaderLow", "pn_io.alarmcr_tagheaderlow", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, /* XXX - 16 bitfield!*/ + { &hf_pn_io_api_tree, + { "API", "pn_io.api_tree", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_module_tree, + { "Module", "pn_io.module_tree", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_submodule_tree, + { "Submodule", "pn_io.submodule_tree", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_io_data_object, + { "IODataObject", "pn_io.io_data_object", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_io_data_object_frame_offset, + { "IODataObjectFrameOffset", "pn_io.io_data_object.frame_offset", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_io_cs, + { "IOCS", "pn_io.io_cs", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_substitutionmode, + { "Substitutionmode", "pn_io.substitutionmode", + FT_UINT16, BASE_HEX, VALS(pn_io_substitutionmode), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_IRData_uuid, + { "IRDataUUID", "pn_io.IRData_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_uuid, + { "ARUUID", "pn_io.ar_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_target_ar_uuid, + { "TargetARUUID", "pn_io.target_ar_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_discriminator, + { "Discriminator", "pn_io.ar_discriminator", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_configid, + { "ConfigID", "pn_io.ar_configid", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_arnumber, + { "ARnumber", "pn_io.ar_arnumber", + FT_UINT16, BASE_HEX, VALS(pn_io_ar_arnumber), 0x0007, + NULL, HFILL } + }, + { &hf_pn_io_ar_arresource, + { "ARresource", "pn_io.ar_arnumber", + FT_UINT16, BASE_HEX, VALS(pn_io_ar_arresource), 0x0018, + NULL, HFILL } + }, + { &hf_pn_io_ar_arreserved, + { "ARreserved", "pn_io.ar_arreserved", + FT_UINT16, BASE_HEX, NULL, 0xFFE0, + NULL, HFILL } + }, + { &hf_pn_io_ar_selector, + { "Selector", "pn_io.ar_selector", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_api, + { "API", "pn_io.api", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_slot_nr, + { "SlotNumber", "pn_io.slot_nr", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_subslot_nr, + { "SubslotNumber", "pn_io.subslot_nr", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_index, + { "Index", "pn_io.index", + FT_UINT16, BASE_HEX, VALS(pn_io_index), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_seq_number, + { "SeqNumber", "pn_io.seq_number", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_record_data_length, + { "RecordDataLength", "pn_io.record_data_length", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_add_val1, + { "AdditionalValue1", "pn_io.add_val1", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_add_val2, + { "AdditionalValue2", "pn_io.add_val2", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_block_header, + { "BlockHeader", "pn_io.block_header", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_block_type, + { "BlockType", "pn_io.block_type", + FT_UINT16, BASE_HEX, VALS(pn_io_block_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_block_length, + { "BlockLength", "pn_io.block_length", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_block_version_high, + { "BlockVersionHigh", "pn_io.block_version_high", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_block_version_low, + { "BlockVersionLow", "pn_io.block_version_low", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sessionkey, + { "SessionKey", "pn_io.session_key", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_control_command, + { "ControlCommand", "pn_io.control_command", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_control_command_reserved, + { "ControlBlockProperties.reserved", "pn_io.control_properties_reserved", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_control_command_prmend, + { "PrmEnd", "pn_io.control_command.prmend", + FT_UINT16, BASE_DEC, NULL, 0x0001, + NULL, HFILL } + }, + { &hf_pn_io_control_command_applready, + { "ApplicationReady", "pn_io.control_command.applready", + FT_UINT16, BASE_DEC, NULL, 0x0002, + NULL, HFILL } + }, + { &hf_pn_io_control_command_release, + { "Release", "pn_io.control_command.release", + FT_UINT16, BASE_DEC, NULL, 0x0004, + NULL, HFILL } + }, + { &hf_pn_io_control_command_done, + { "Done", "pn_io.control_command.done", + FT_UINT16, BASE_DEC, NULL, 0x0008, + NULL, HFILL } + }, + { &hf_pn_io_control_command_ready_for_companion, + { "ReadyForCompanion", "pn_io.control_command.ready_for_companion", + FT_UINT16, BASE_DEC, NULL, 0x0010, + NULL, HFILL } + }, + { &hf_pn_io_control_command_ready_for_rt_class3, + { "ReadyForRT Class 3", "pn_io.control_command.ready_for_rt_class3", + FT_UINT16, BASE_DEC, NULL, 0x0020, + NULL, HFILL } + }, + { &hf_pn_io_control_command_prmbegin, + { "PrmBegin", "pn_io.control_command.prmbegin", + FT_UINT16, BASE_DEC, VALS(pn_io_control_properties_prmbegin_vals), 0x0040, + NULL, HFILL } + }, + { &hf_pn_io_control_command_reserved_7_15, + { "ControlBlockProperties.reserved", "pn_io.control_properties_reserved_7_15", + FT_UINT16, BASE_HEX, NULL, 0x0FF80, + NULL, HFILL } + }, + { &hf_pn_io_control_block_properties, + { "ControlBlockProperties", "pn_io.control_block_properties", + FT_UINT16, BASE_HEX, VALS(pn_io_control_properties_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_control_block_properties_applready, + { "ControlBlockProperties", "pn_io.control_block_properties.appl_ready", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_control_block_properties_applready0, + { "ApplicationReady", "pn_io.control_block_properties.appl_ready0", + FT_UINT16, BASE_HEX, VALS(pn_io_control_properties_application_ready_vals), 0x0001, + NULL, HFILL } + }, + { &hf_pn_io_SubmoduleListEntries, + { "NumberOfEntries", "pn_io.SubmoduleListEntries", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code, + { "ErrorCode", "pn_io.error_code", + FT_UINT8, BASE_HEX, VALS(pn_io_error_code), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_decode, + { "ErrorDecode", "pn_io.error_decode", + FT_UINT8, BASE_HEX, VALS(pn_io_error_decode), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code1, + { "ErrorCode1", "pn_io.error_code1", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code1), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code1_pniorw, + { "ErrorCode1", "pn_io.error_code1", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code1_pniorw), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pniorw, + { "ErrorCode2 for PNIORW is user specified!", "pn_io.error_code2", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code1_pnio, + { "ErrorCode1", "pn_io.error_code1", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code1_pnio), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_1, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_1), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_2, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_2), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_3, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_3), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_4, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_4), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_5, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_5), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_6, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_6), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_7, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_7), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_8, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_8), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_13, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_13), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_20, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_20), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_21, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_21), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_22, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_22), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_23, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_23), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_40, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_40), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_60, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_60), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_61, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_61), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_62, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_62), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_63, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_63), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_64, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_64), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_65, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_65), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_66, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_66), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_70, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_70), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_71, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_71), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_72, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_72), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_73, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_73), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_74, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_74), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_75, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_75), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_76, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_76), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_77, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_77), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_253, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_253), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_code2_pnio_255, + { "ErrorCode2", "pn_io.error_code2", + FT_UINT8, BASE_DEC, VALS(pn_io_error_code2_pnio_255), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_block, + { "Block", "pn_io.block", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarm_type, + { "AlarmType", "pn_io.alarm_type", + FT_UINT16, BASE_HEX, VALS(pn_io_alarm_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarm_specifier, + { "AlarmSpecifier", "pn_io.alarm_specifier", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarm_specifier_sequence, + { "SequenceNumber", "pn_io.alarm_specifier.sequence", + FT_UINT16, BASE_HEX, NULL, 0x07FF, + NULL, HFILL } + }, + { &hf_pn_io_alarm_specifier_channel, + { "ChannelDiagnosis", "pn_io.alarm_specifier.channel", + FT_UINT16, BASE_HEX, NULL, 0x0800, + NULL, HFILL } + }, + { &hf_pn_io_alarm_specifier_manufacturer, + { "ManufacturerSpecificDiagnosis", "pn_io.alarm_specifier.manufacturer", + FT_UINT16, BASE_HEX, NULL, 0x1000, + NULL, HFILL } + }, + { &hf_pn_io_alarm_specifier_submodule, + { "SubmoduleDiagnosisState", "pn_io.alarm_specifier.submodule", + FT_UINT16, BASE_HEX, NULL, 0x2000, + NULL, HFILL } + }, + { &hf_pn_io_alarm_specifier_ardiagnosis, + { "ARDiagnosisState", "pn_io.alarm_specifier.ardiagnosis", + FT_UINT16, BASE_HEX, NULL, 0x8000, + NULL, HFILL } + }, + { &hf_pn_io_alarm_dst_endpoint, + { "AlarmDstEndpoint", "pn_io.alarm_dst_endpoint", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_alarm_src_endpoint, + { "AlarmSrcEndpoint", "pn_io.alarm_src_endpoint", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdu_type, + { "PDUType", "pn_io.pdu_type", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdu_type_type, + { "Type", "pn_io.pdu_type.type", + FT_UINT8, BASE_HEX, VALS(pn_io_pdu_type), 0x0F, + NULL, HFILL } + }, + { &hf_pn_io_pdu_type_version, + { "Version", "pn_io.pdu_type.version", + FT_UINT8, BASE_HEX, NULL, 0xF0, + NULL, HFILL } + }, + { &hf_pn_io_add_flags, + { "AddFlags", "pn_io.add_flags", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_window_size, + { "WindowSize", "pn_io.window_size", + FT_UINT8, BASE_DEC, NULL, 0x0F, + NULL, HFILL } + }, + { &hf_pn_io_tack, + { "TACK", "pn_io.tack", + FT_UINT8, BASE_HEX, NULL, 0xF0, + NULL, HFILL } + }, + { &hf_pn_io_send_seq_num, + { "SendSeqNum", "pn_io.send_seq_num", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ack_seq_num, + { "AckSeqNum", "pn_io.ack_seq_num", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_var_part_len, + { "VarPartLen", "pn_io.var_part_len", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_module_ident_number, + { "ModuleIdentNumber", "pn_io.module_ident_number", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_submodule_ident_number, + { "SubmoduleIdentNumber", "pn_io.submodule_ident_number", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_number_of_modules, + { "NumberOfModules", "pn_io.number_of_modules", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_module_properties, + { "ModuleProperties", "pn_io.module_properties", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_module_state, + { "ModuleState", "pn_io.module_state", + FT_UINT16, BASE_HEX, VALS(pn_io_module_state), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_submodules, + { "NumberOfSubmodules", "pn_io.number_of_submodules", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_submodule_properties, + { "SubmoduleProperties", "pn_io.submodule_properties", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_submodule_properties_type, + { "Type", "pn_io.submodule_properties.type", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_properties_type), 0x0003, + NULL, HFILL } + }, + { &hf_pn_io_submodule_properties_shared_input, + { "SharedInput", "pn_io.submodule_properties.shared_input", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_properties_shared_input), 0x0004, + NULL, HFILL } + }, + { &hf_pn_io_submodule_properties_reduce_input_submodule_data_length, + { "ReduceInputSubmoduleDataLength", "pn_io.submodule_properties.reduce_input_submodule_data_length", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_properties_reduce_input_submodule_data_length), 0x0008, + NULL, HFILL } + }, + { &hf_pn_io_submodule_properties_reduce_output_submodule_data_length, + { "ReduceOutputSubmoduleDataLength", "pn_io.submodule_properties.reduce_output_submodule_data_length", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_properties_reduce_output_submodule_data_length), 0x0010, + NULL, HFILL } + }, + { &hf_pn_io_submodule_properties_discard_ioxs, + { "DiscardIOXS", "pn_io.submodule_properties.discard_ioxs", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_properties_discard_ioxs), 0x0020, + NULL, HFILL } + }, + { &hf_pn_io_submodule_properties_reserved, + { "Reserved", "pn_io.submodule_properties.reserved", + FT_UINT16, BASE_HEX, NULL, 0xFFC0, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state, + { "SubmoduleState", "pn_io.submodule_state", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_format_indicator, + { "FormatIndicator", "pn_io.submodule_state.format_indicator", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_format_indicator), 0x8000, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_add_info, + { "AddInfo", "pn_io.submodule_state.add_info", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_add_info), 0x0007, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_qualified_info, + { "QualifiedInfo", "pn_io.submodule_state.qualified_info", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_qualified_info), 0x0008, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_maintenance_required, + { "MaintenanceRequired", "pn_io.submodule_state.maintenance_required", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_maintenance_required), 0x0010, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_maintenance_demanded, + { "MaintenanceDemanded", "pn_io.submodule_state.maintenance_demanded", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_maintenance_demanded), 0x0020, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_diag_info, + { "DiagInfo", "pn_io.submodule_state.diag_info", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_diag_info), 0x0040, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_ar_info, + { "ARInfo", "pn_io.submodule_state.ar_info", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_ar_info), 0x0780, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_ident_info, + { "IdentInfo", "pn_io.submodule_state.ident_info", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_ident_info), 0x7800, + NULL, HFILL } + }, + { &hf_pn_io_submodule_state_detail, + { "Detail", "pn_io.submodule_state.detail", + FT_UINT16, BASE_HEX, VALS(pn_io_submodule_state_detail), 0x7FFF, + NULL, HFILL } + }, + { &hf_pn_io_data_description_tree, + { "DataDescription", "pn_io.data_description_tree", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_data_description, + { "DataDescription", "pn_io.data_description", + FT_UINT16, BASE_HEX, VALS(pn_io_data_description), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_submodule_data_length, + { "SubmoduleDataLength", "pn_io.submodule_data_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_iocs, + { "LengthIOCS", "pn_io.length_iocs", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_iops, + { "LengthIOPS", "pn_io.length_iops", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_iocs, + { "IOCS", "pn_io.ioxs", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iops, + { "IOPS", "pn_io.iops", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_extension, + { "Extension (1:another IOxS follows/0:no IOxS follows)", "pn_io.ioxs.extension", + FT_UINT8, BASE_HEX, NULL, 0x01, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_res14, + { "Reserved (should be zero)", "pn_io.ioxs.res14", + FT_UINT8, BASE_HEX, NULL, 0x1E, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_instance, + { "Instance (only valid, if DataState is bad)", + "pn_io.ioxs.instance", FT_UINT8, BASE_HEX, VALS(pn_io_ioxs), + 0x60, NULL, HFILL } + }, + { &hf_pn_io_ioxs_datastate, + { "DataState (1:good/0:bad)", "pn_io.ioxs.datastate", + FT_UINT8, BASE_HEX, NULL, 0x80, + NULL, HFILL } + }, + { &hf_pn_io_address_resolution_properties, + { "AddressResolutionProperties", "pn_io.address_resolution_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mci_timeout_factor, + { "MCITimeoutFactor", "pn_io.mci_timeout_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_provider_station_name, + { "ProviderStationName", "pn_io.provider_station_name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_user_structure_identifier, + { "UserStructureIdentifier", "pn_io.user_structure_identifier", + FT_UINT16, BASE_HEX, VALS(pn_io_user_structure_identifier), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_user_structure_identifier_manf, + { "UserStructureIdentifier manufacturer specific", "pn_io.user_structure_identifier_manf", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ar_properties_reserved_1, + { "Reserved_1", "pn_io.ar_properties.reserved_1", + FT_UINT32, BASE_HEX, NULL, 0x000000E0, + NULL, HFILL }}, + { &hf_pn_io_ar_properties_device_access, + { "DeviceAccess", "pn_io.ar_properties.device_access", + FT_UINT32, BASE_HEX, VALS(pn_io_arproperties_DeviceAccess), 0x00000100, + NULL, HFILL }}, + { &hf_pn_io_subframe_data, + { "SubFrameData", "pn_io.subframe_data", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_subframe_reserved2, + { "Reserved1", "pn_io.subframe_data.reserved2", + FT_UINT32, BASE_HEX, NULL, 0xFFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_subframe_data_length, + { "DataLength", "pn_io.subframe_data.data_length", + FT_UINT32, BASE_HEX, NULL, 0x0000FF00, + NULL, HFILL } + }, + { &hf_pn_io_subframe_reserved1, + { "Reserved1", "pn_io.subframe_data.reserved1", + FT_UINT32, BASE_HEX, NULL, 0x00000080, + NULL, HFILL } + }, + { &hf_pn_io_subframe_data_position, + { "DataPosition", "pn_io.subframe_data.position", + FT_UINT32, BASE_HEX, NULL, 0x0000007F, + NULL, HFILL } + }, + { &hf_pn_io_subframe_data_reserved1, + { "Reserved1", "pn_io.subframe_data.reserved_1", + FT_UINT32, BASE_HEX, NULL, 0x00000080, + NULL, HFILL } + }, + { &hf_pn_io_subframe_data_reserved2, + { "Reserved1", "pn_io.subframe_data.reserved_2", + FT_UINT32, BASE_HEX, NULL, 0xFFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_channel_number, + { "ChannelNumber", "pn_io.channel_number", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_channel_properties, + { "ChannelProperties", "pn_io.channel_properties", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_channel_properties_type, + { "Type", "pn_io.channel_properties.type", + FT_UINT16, BASE_HEX, VALS(pn_io_channel_properties_type), 0x00FF, + NULL, HFILL } + }, + { &hf_pn_io_channel_properties_accumulative, + { "Accumulative", "pn_io.channel_properties.accumulative", + FT_UINT16, BASE_HEX, VALS(pn_io_channel_properties_accumulative_vals), 0x0100, + NULL, HFILL } + }, + { &hf_pn_io_NumberOfSubframeBlocks, + { "NumberOfSubframeBlocks", "pn_io.NumberOfSubframeBlocks", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_channel_properties_maintenance, + { "Maintenance (Severity)", "pn_io.channel_properties.maintenance", + FT_UINT16, BASE_HEX, VALS(pn_io_channel_properties_maintenance), 0x0600, + NULL, HFILL } + }, + { &hf_pn_io_channel_properties_specifier, + { "Specifier", "pn_io.channel_properties.specifier", + FT_UINT16, BASE_HEX, VALS(pn_io_channel_properties_specifier), 0x1800, + NULL, HFILL } + }, + { &hf_pn_io_channel_properties_direction, + { "Direction", "pn_io.channel_properties.direction", + FT_UINT16, BASE_HEX, VALS(pn_io_channel_properties_direction), 0xE000, + NULL, HFILL } + }, + + { &hf_pn_io_channel_error_type, + { "ChannelErrorType", "pn_io.channel_error_type", + FT_UINT16, BASE_HEX, VALS(pn_io_channel_error_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type0", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8000, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type0800", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8000), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8001, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8001", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8001), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8002, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8002", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8002), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8003, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8003", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8003), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8004, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8004", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8004), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8005, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8005", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8005), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8007, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8007", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8007), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x8008, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type8008", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x8008), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x800A, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type800A", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x800A), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x800B, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type800B", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x800B), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type0x800C, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type800C", + FT_UINT16, BASE_HEX, VALS(pn_io_ext_channel_error_type0x800C), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_error_type, + { "ExtChannelErrorType", "pn_io.ext_channel_error_type", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ext_channel_add_value, + { "ExtChannelAddValue", "pn_io.ext_channel_add_value", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_subdomain_id, + { "PTCPSubdomainID", "pn_io.ptcp_subdomain_id", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ir_data_id, + { "IRDataID", "pn_io.ir_data_id", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_max_bridge_delay, + { "MaxBridgeDelay", "pn_io.max_bridge_delay", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_ports, + { "NumberOfPorts", "pn_io.number_of_ports", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_max_port_tx_delay, + { "MaxPortTxDelay", "pn_io.max_port_tx_delay", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_max_port_rx_delay, + { "MaxPortRxDelay", "pn_io.max_port_rx_delay", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_max_line_rx_delay, + { "MaxLineRxDelay", "pn_io.max_line_rx_delay", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_yellowtime, + { "YellowTime", "pn_io.yellowtime", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_reserved_interval_begin, + { "ReservedIntervalBegin", "pn_io.reserved_interval_begin", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_reserved_interval_end, + { "ReservedIntervalEnd", "pn_io.reserved_interval_end", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pllwindow, + { "PLLWindow", "pn_io.pllwindow", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sync_send_factor, + { "SyncSendFactor", "pn_io.sync_send_factor", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sync_properties, + { "SyncProperties", "pn_io.sync_properties", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_sync_frame_address, + { "SyncFrameAddress", "pn_io.sync_frame_address", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_timeout_factor, + { "PTCPTimeoutFactor", "pn_io.ptcp_timeout_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_takeover_timeout_factor, + { "PTCPTakeoverTimeoutFactor", "pn_io.ptcp_takeover_timeout_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_master_startup_time, + { "PTCPMasterStartupTime", "pn_io.ptcp_master_startup_time", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_master_priority_1, + { "PTCP_MasterPriority1", "pn_io.ptcp_master_priority_1", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_master_priority_2, + { "PTCP_MasterPriority2", "pn_io.ptcp_master_priority_2", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_length_subdomain_name, + { "PTCPLengthSubdomainName", "pn_io.ptcp_length_subdomain_name", + FT_UINT8, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ptcp_subdomain_name, + { "PTCPSubdomainName", "pn_io.ptcp_subdomain_name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_MultipleInterfaceMode_NameOfDevice, + { "MultipleInterfaceMode.NameOfDevice", "pn_io.MultipleInterfaceMode_NameOfDevice", + FT_UINT32, BASE_HEX, VALS(pn_io_MultipleInterfaceMode_NameOfDevice), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_MultipleInterfaceMode_reserved_1, + { "MultipleInterfaceMode.Reserved_1", "pn_io.MultipleInterfaceMode_reserved_1", + FT_UINT32, BASE_HEX, NULL, 0xFFFE, + NULL, HFILL } + }, + { &hf_pn_io_MultipleInterfaceMode_reserved_2, + { "MultipleInterfaceMode.Reserved_2", "pn_io.MultipleInterfaceMode_reserved_2", + FT_UINT32, BASE_HEX, NULL, 0xFFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status, + { "CounterStatus", "pn_io.CounterStatus", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_ifInOctets, + { "CounterStatus.ifInOctets", "pn_io.CounterStatus.ifInOctets", + FT_BOOLEAN, 16, TFS(&pn_io_pdportstatistic_counter_status_contents), 0x0001, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_ifOutOctets, + { "CounterStatus.ifOutOctets", "pn_io.CounterStatus.ifOutOctets", + FT_BOOLEAN, 16, TFS(&pn_io_pdportstatistic_counter_status_contents), 0x0002, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_ifInDiscards, + { "CounterStatus.ifInDiscards", "pn_io.CounterStatus.ifInDiscards", + FT_BOOLEAN, 16, TFS(&pn_io_pdportstatistic_counter_status_contents), 0x0004, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_ifOutDiscards, + { "CounterStatus.ifOutDiscards", "pn_io.CounterStatus.ifOutDiscards", + FT_BOOLEAN, 16, TFS(&pn_io_pdportstatistic_counter_status_contents), 0x0008, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_ifInErrors, + { "CounterStatus.ifInErrors", "pn_io.CounterStatus.ifInErrors", + FT_BOOLEAN, 16, TFS(&pn_io_pdportstatistic_counter_status_contents), 0x0010, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_ifOutErrors, + { "CounterStatus.ifOutErrors", "pn_io.CounterStatus.ifOutErrors", + FT_BOOLEAN, 16, TFS(&pn_io_pdportstatistic_counter_status_contents), 0x0020, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_counter_status_reserved, + { "CounterStatus.Reserved", "pn_io.CounterStatus.Reserved", + FT_UINT16, BASE_HEX, VALS(pn_io_pdportstatistic_counter_status_reserved), 0xFFC0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_ifInOctets, + { "ifInOctets", "pn_io.ifInOctets", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_ifOutOctets, + { "ifOutOctets", "pn_io.ifOutOctets", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_ifInDiscards, + { "ifInDiscards", "pn_io.ifInDiscards", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_ifOutDiscards, + { "ifOutDiscards", "pn_io.ifOutDiscards", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_ifInErrors, + { "ifInErrors", "pn_io.ifInErrors", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_pdportstatistic_ifOutErrors, + { "ifOutErrors", "pn_io.ifOutErrors", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_domain_boundary, + { "DomainBoundary", "pn_io.domain_boundary", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_domain_boundary_ingress, + { "DomainBoundaryIngress", "pn_io.domain_boundary.ingress", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_domain_boundary_egress, + { "DomainBoundaryEgress", "pn_io.domain_boundary.egress", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_multicast_boundary, + { "MulticastBoundary", "pn_io.multicast_boundary", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_adjust_properties, + { "AdjustProperties", "pn_io.adjust_properties", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_PreambleLength, + { "Preamble Length", "pn_io.preamble_length", + FT_UINT16, BASE_DEC_HEX, VALS(pn_io_preamble_length), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mau_type, + { "MAUType", "pn_io.mau_type", + FT_UINT16, BASE_HEX, VALS(pn_io_mau_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mau_type_mode, + { "MAUTypeMode", "pn_io.mau_type_mode", + FT_UINT16, BASE_HEX, VALS(pn_io_mau_type_mode), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_dcp_boundary_value, + { "DCPBoundary", "pn_io.dcp_boundary_value", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_dcp_boundary_value_bit0, + { "DCPBoundary", "pn_io.dcp_boundary_value_bit0", + FT_UINT32, BASE_HEX, VALS(pn_io_dcp_boundary_value_bit0), 0x1, + NULL, HFILL } + }, + { &hf_pn_io_dcp_boundary_value_bit1, + { "DCPBoundary", "pn_io.dcp_boundary_value_bit1", + FT_UINT32, BASE_HEX, VALS(pn_io_dcp_boundary_value_bit1), 0x2, + NULL, HFILL } + }, + { &hf_pn_io_dcp_boundary_value_otherbits, + { "DCPBoundary", "pn_io.dcp_boundary_value_otherbits", + FT_UINT32, BASE_HEX, NULL, 0xFFFFFFFC, + NULL, HFILL } + }, + { &hf_pn_io_peer_to_peer_boundary_value, + { "AdjustPeerToPeer-Boundary", "pn_io.peer_to_peer_boundary_value", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_peer_to_peer_boundary_value_bit0, + { "AdjustPeerToPeer-Boundary", "pn_io.peer_to_peer_boundary_value_bit0", + FT_UINT32, BASE_HEX, VALS(pn_io_peer_to_peer_boundary_value_bit0), 0x1, + NULL, HFILL } + }, + { &hf_pn_io_peer_to_peer_boundary_value_bit1, + { "AdjustPeerToPeer-Boundary", "pn_io.peer_to_peer_boundary_value_bit1", + FT_UINT32, BASE_HEX, VALS(pn_io_peer_to_peer_boundary_value_bit1), 0x2, + NULL, HFILL } + }, + { &hf_pn_io_peer_to_peer_boundary_value_bit2, + { "AdjustPeerToPeer-Boundary", "pn_io.peer_to_peer_boundary_value_bit2", + FT_UINT32, BASE_HEX, VALS(pn_io_peer_to_peer_boundary_value_bit2), 0x4, + NULL, HFILL } + }, + { &hf_pn_io_peer_to_peer_boundary_value_otherbits, + { "AdjustPeerToPeer-Boundary", "pn_io.peer_to_peer_boundary_value_otherbits", + FT_UINT32, BASE_HEX, NULL, 0xFFFFFFF8, + NULL, HFILL } + }, + { &hf_pn_io_port_state, + { "PortState", "pn_io.port_state", + FT_UINT16, BASE_HEX, VALS(pn_io_port_state), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_line_delay, + { "LineDelay", "pn_io.line_delay", + FT_UINT32, BASE_HEX, NULL, 0x0, + "LineDelay in nanoseconds", HFILL } + }, + { &hf_pn_io_line_delay_value, + { "LineDelayValue", "pn_io.line_delay_value", + FT_UINT32, BASE_DEC | BASE_RANGE_STRING, RVALS(pn_io_line_delay_value), 0x7FFFFFFF, + NULL, HFILL } + }, + { &hf_pn_io_cable_delay_value, + { "CableDelayValue", "pn_io.cable_delay_value", + FT_UINT32, BASE_DEC | BASE_RANGE_STRING, RVALS(pn_io_cable_delay_value), 0x7FFFFFFF, + NULL, HFILL } + }, + { &hf_pn_io_line_delay_format_indicator, + { "LineDelayFormatIndicator", "pn_io.line_delay_format_indicator", + FT_UINT32, BASE_HEX, NULL, 0x80000000, + "LineDelay FormatIndicator", HFILL } + }, + { &hf_pn_io_number_of_peers, + { "NumberOfPeers", "pn_io.number_of_peers", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_peer_port_id, + { "LengthPeerPortID", "pn_io.length_peer_port_id", + FT_UINT8, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_peer_port_id, + { "PeerPortID", "pn_io.peer_port_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_peer_chassis_id, + { "LengthPeerChassisID", "pn_io.length_peer_chassis_id", + FT_UINT8, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_peer_chassis_id, + { "PeerChassisID", "pn_io.peer_chassis_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_own_chassis_id, + { "LengthOwnChassisID", "pn_io.length_own_chassis_id", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_own_chassis_id, + { "OwnChassisID", "pn_io.own_chassis_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_own_port_id, + { "LengthOwnPortID", "pn_io.length_own_port_id", + FT_UINT8, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_own_port_id, + { "OwnPortID", "pn_io.own_port_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_peer_macadd, + { "PeerMACAddress", "pn_io.peer_macadd", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_macadd, + { "MACAddress", "pn_io.macadd", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_media_type, + { "MediaType", "pn_io.media_type", + FT_UINT32, BASE_HEX, VALS(pn_io_media_type), 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_ethertype, + { "Ethertype", "pn_io.ethertype", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rx_port, + { "RXPort", "pn_io.rx_port", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_details, + { "FrameDetails", "pn_io.frame_details", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_details_sync_frame, + { "SyncFrame", "pn_io.frame_details.sync_frame", + FT_UINT8, BASE_HEX, VALS(pn_io_frame_details_sync_master_vals), 0x03, + NULL, HFILL } + }, + { &hf_pn_io_frame_details_meaning_frame_send_offset, + { "Meaning", "pn_io.frame_details.meaning_frame_send_offset", + FT_UINT8, BASE_HEX, VALS(pn_io_frame_details_meaning_frame_send_offset_vals), 0x0C, + NULL, HFILL } + }, + { &hf_pn_io_frame_details_reserved, + { "Reserved", "pn_io.frame_details.reserved", + FT_UINT8, BASE_HEX, NULL, 0xF0, + NULL, HFILL } + }, + { &hf_pn_io_nr_of_tx_port_groups, + { "NumberOfTxPortGroups", "pn_io.nr_of_tx_port_groups", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties, + { "TxPortGroupProperties", "pn_io.tx_port_properties", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit0, + { "TxPortLocal", "pn_io.tx_port_properties_bit_0", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit1, + { "TxPort_1", "pn_io.tx_port_properties_bit_1", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x02, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit2, + { "TxPort_2", "pn_io.tx_port_properties_bit_2", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x04, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit3, + { "TxPort_3", "pn_io.tx_port_properties_bit_3", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x08, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit4, + { "TxPort_4", "pn_io.tx_port_properties_bit_4", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x10, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit5, + { "TxPort_5", "pn_io.tx_port_properties_bit_5", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x20, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit6, + { "TxPort_6", "pn_io.tx_port_properties_bit_6", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x40, + NULL, HFILL } + }, + { &hf_pn_io_TxPortGroupProperties_bit7, + { "TxPort_7", "pn_io.tx_port_properties_bit_7", + FT_UINT8, BASE_HEX, VALS(pn_io_txgroup_state), 0x80, + NULL, HFILL } + }, + + { &hf_pn_io_start_of_red_frame_id, + { "StartOfRedFrameID", "pn_io.start_of_red_frame_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_end_of_red_frame_id, + { "EndOfRedFrameID", "pn_io.end_of_red_frame_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ir_begin_end_port, + { "Port", "pn_io.ir_begin_end_port", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_assignments, + { "NumberOfAssignments", "pn_io.number_of_assignments", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_phases, + { "NumberOfPhases", "pn_io.number_of_phases", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_red_orange_period_begin_tx, + { "RedOrangePeriodBegin [TX]", "pn_io.red_orange_period_begin_tx", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_orange_period_begin_tx, + { "OrangePeriodBegin [TX]", "pn_io.orange_period_begin_tx", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_green_period_begin_tx, + { "GreenPeriodBegin [TX]", "pn_io.green_period_begin_tx", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_red_orange_period_begin_rx, + { "RedOrangePeriodBegin [RX]", "pn_io.red_orange_period_begin_rx", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_orange_period_begin_rx, + { "OrangePeriodBegin [RX]", "pn_io.orange_period_begin_rx", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_green_period_begin_rx, + { "GreenPeriodBegin [RX]", "pn_io.green_period_begin_rx", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_ir_tx_phase_assignment, + { "TXPhaseAssignment", "pn_io.tx_phase_assignment_sub", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_tx_phase_assignment_begin_value, + { "AssignedValueForReservedBegin", "pn_io.tx_phase_assignment_begin_value", + FT_UINT16, BASE_DEC, NULL, 0x0F, + NULL, HFILL } + }, + { &hf_pn_io_tx_phase_assignment_orange_begin, + { "AssignedValueForOrangeBegin", "pn_io.tx_phase_assignment_orange_begin", + FT_UINT16, BASE_DEC, NULL, 0x0F0, + NULL, HFILL } + }, + { &hf_pn_io_tx_phase_assignment_end_reserved, + { "AssignedValueForReservedEnd", "pn_io.tx_phase_assignment_end_reserved", + FT_UINT16, BASE_DEC, NULL, 0x0F00, + NULL, HFILL } + }, + { &hf_pn_io_tx_phase_assignment_reserved, + { "Reserved should be 0", "pn_io.tx_phase_assignment_reserved", + FT_UINT16, BASE_DEC, NULL, 0x0F000, + NULL, HFILL } + }, + { &hf_pn_ir_rx_phase_assignment, + { "RXPhaseAssignment", "pn_io.rx_phase_assignment_sub", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_slot, + { "Slot", "pn_io.slot", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_subslot, + { "Subslot", "pn_io.subslot", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_slots, + { "NumberOfSlots", "pn_io.number_of_slots", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_subslots, + { "NumberOfSubslots", "pn_io.number_of_subslots", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_maintenance_required_power_budget, + { "MaintenanceRequiredPowerBudget", "pn_io.maintenance_required_power_budget", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_maintenance_demanded_power_budget, + { "MaintenanceDemandedPowerBudget", "pn_io.maintenance_demanded_power_budget", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_error_power_budget, + { "ErrorPowerBudget", "pn_io.error_power_budget", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fiber_optic_type, + { "FiberOpticType", "pn_io.fiber_optic_type", + FT_UINT32, BASE_HEX, VALS(pn_io_fiber_optic_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fiber_optic_cable_type, + { "FiberOpticCableType", "pn_io.fiber_optic_cable_type", + FT_UINT32, BASE_HEX, VALS(pn_io_fiber_optic_cable_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_controller_appl_cycle_factor, + { "ControllerApplicationCycleFactor", "pn_io.controller_appl_cycle_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_time_data_cycle, + { "TimeDataCycle", "pn_io.time_data_cycle", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_time_io_input, + { "TimeIOInput", "pn_io.time_io_input", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_time_io_output, + { "TimeIOOutput", "pn_io.time_io_output", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_time_io_input_valid, + { "TimeIOInputValid", "pn_io.time_io_input_valid", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_time_io_output_valid, + { "TimeIOOutputValid", "pn_io.time_io_output_valid", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_maintenance_status, + { "MaintenanceStatus", "pn_io.maintenance_status", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_maintenance_status_required, + { "Required", "pn_io.maintenance_status_required", + FT_UINT32, BASE_HEX, NULL, 0x0001, + NULL, HFILL } + }, + { &hf_pn_io_maintenance_status_demanded, + { "Demanded", "pn_io.maintenance_status_demanded", + FT_UINT32, BASE_HEX, NULL, 0x0002, + NULL, HFILL } + }, + { &hf_pn_io_vendor_id_high, + { "VendorIDHigh", "pn_io.vendor_id_high", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_vendor_id_low, + { "VendorIDLow", "pn_io.vendor_id_low", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_vendor_block_type, + { "VendorBlockType", "pn_io.vendor_block_type", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_order_id, + { "OrderID", "pn_io.order_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_serial_number, + { "IMSerialNumber", "pn_io.im_serial_number", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_hardware_revision, + { "IMHardwareRevision", "pn_io.im_hardware_revision", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + /* XXX - better use a simple char here -> vals */ + { &hf_pn_io_im_revision_prefix, + { "IMRevisionPrefix", "pn_io.im_revision_prefix", + FT_CHAR, BASE_HEX, VALS(pn_io_im_revision_prefix_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_sw_revision_functional_enhancement, + { "IMSWRevisionFunctionalEnhancement", "pn_io.im_sw_revision_functional_enhancement", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_revision_bugfix, + { "IM_SWRevisionBugFix", "pn_io.im_revision_bugfix", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_sw_revision_internal_change, + { "IMSWRevisionInternalChange", "pn_io.im_sw_revision_internal_change", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_revision_counter, + { "IMRevisionCounter", "pn_io.im_revision_counter", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_profile_id, + { "IMProfileID", "pn_io.im_profile_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_profile_specific_type, + { "IMProfileSpecificType", "pn_io.im_profile_specific_type", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_version_major, + { "IMVersionMajor", "pn_io.im_version_major", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_version_minor, + { "IMVersionMinor", "pn_io.im_version_minor", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_supported, + { "IM_Supported", "pn_io.im_supported", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_numberofentries, + { "NumberOfEntries", "pn_io.im_numberofentries", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_annotation, + { "IM Annotation", "pn_io.im_annotation", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_order_id, + { "IM Order ID", "pn_io.im_order_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_ars, + { "NumberOfARs", "pn_io.number_of_ars", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_cycle_counter, + { "CycleCounter", "pn_io.cycle_counter", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_data_status, + { "DataStatus", "pn_io.ds", + FT_UINT8, BASE_HEX, 0, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_data_status_res67, + { "Reserved (should be zero)", "pn_io.ds_res67", + FT_UINT8, BASE_HEX, 0, 0xc0, + NULL, HFILL } + }, + { &hf_pn_io_data_status_ok, + { "StationProblemIndicator (1:Ok/0:Problem)", "pn_io.ds_ok", + FT_UINT8, BASE_HEX, 0, 0x20, + NULL, HFILL } + }, + { &hf_pn_io_data_status_operate, + { "ProviderState (1:Run/0:Stop)", "pn_io.ds_operate", + FT_UINT8, BASE_HEX, 0, 0x10, + NULL, HFILL } + }, + { &hf_pn_io_data_status_res3, + { "Reserved (should be zero)", "pn_io.ds_res3", + FT_UINT8, BASE_HEX, 0, 0x08, + NULL, HFILL } + }, + { &hf_pn_io_data_status_valid, + { "DataValid (1:Valid/0:Invalid)", "pn_io.ds_valid", + FT_UINT8, BASE_HEX, 0, 0x04, + NULL, HFILL } + }, + { &hf_pn_io_data_status_res1, + { "primary AR of a given AR-set is present (0:One/ 1:None)", "pn_io.ds_res1", + FT_UINT8, BASE_HEX, 0, 0x02, + NULL, HFILL } + }, + { &hf_pn_io_data_status_primary, + { "State (1:Primary/0:Backup)", "pn_io.ds_primary", + FT_UINT8, BASE_HEX, 0, 0x01, + NULL, HFILL } + }, + { &hf_pn_io_transfer_status, + { "TransferStatus", "pn_io.transfer_status", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_actual_local_time_stamp, + { "ActualLocalTimeStamp", "pn_io.actual_local_time_stamp", + FT_UINT64, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_local_time_stamp, + { "LocalTimeStamp", "pn_io.local_time_stamp", + FT_UINT64, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_log_entries, + { "NumberOfLogEntries", "pn_io.number_of_log_entries", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_entry_detail, + { "EntryDetail", "pn_io.entry_detail", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ip_address, + { "IPAddress", "pn_io.ip_address", + FT_IPv4, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_subnetmask, + { "Subnetmask", "pn_io.subnetmask", + FT_IPv4, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_standard_gateway, + { "StandardGateway", "pn_io.standard_gateway", + FT_IPv4, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_mrp_domain_uuid, + { "MRP_DomainUUID", "pn_io.mrp_domain_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_role, + { "MRP_Role", "pn_io.mrp_role", + FT_UINT16, BASE_HEX, VALS(pn_io_mrp_role_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_length_domain_name, + { "MRP_LengthDomainName", "pn_io.mrp_length_domain_name", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_domain_name, + { "MRP_DomainName", "pn_io.mrp_domain_name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_instances, + { "NumberOfMrpInstances", "pn_io.mrp_Number_MrpInstances", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_instance, + { "Mrp_Instance", "pn_io.mrp_MrpInstance", + FT_UINT8, BASE_DEC, VALS(pn_io_mrp_instance_no), 0x0, + NULL, HFILL } + }, + + { &hf_pn_io_mrp_prio, + { "MRP_Prio", "pn_io.mrp_prio", + FT_UINT16, BASE_HEX, VALS(pn_io_mrp_prio_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_topchgt, + { "MRP_TOPchgT", "pn_io.mrp_topchgt", + FT_UINT16, BASE_DEC, NULL, 0x0, + "time base 10ms", HFILL } + }, + { &hf_pn_io_mrp_topnrmax, + { "MRP_TOPNRmax", "pn_io.mrp_topnrmax", + FT_UINT16, BASE_DEC, NULL, 0x0, + "number of iterations", HFILL } + }, + { &hf_pn_io_mrp_tstshortt, + { "MRP_TSTshortT", "pn_io.mrp_tstshortt", + FT_UINT16, BASE_DEC, NULL, 0x0, + "time base 1 ms", HFILL } + }, + { &hf_pn_io_mrp_tstdefaultt, + { "MRP_TSTdefaultT", "pn_io.mrp_tstdefaultt", + FT_UINT16, BASE_DEC, NULL, 0x0, + "time base 1ms", HFILL } + }, + { &hf_pn_io_mrp_tstnrmax, + { "MRP_TSTNRmax", "pn_io.mrp_tstnrmax", + FT_UINT16, BASE_DEC, NULL, 0x0, + "number of outstanding test indications causes ring failure", HFILL } + }, + { &hf_pn_io_mrp_check, + { "MRP_Check", "pn_io.mrp_check", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_check_mrm, + { "MRP_Check.MediaRedundancyManager", "pn_io.mrp_check.mrm", + FT_UINT32, BASE_HEX, VALS(pn_io_mrp_mrm_on), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_mrp_check_mrpdomain, + { "MRP_Check.MRP_DomainUUID", "pn_io.mrp_check.domainUUID", + FT_UINT32, BASE_HEX, VALS(pn_io_mrp_checkUUID), 0x02, + NULL, HFILL } + }, + { &hf_pn_io_mrp_check_reserved_1, + { "MRP_Check.reserved_1", "pn_io.mrp_check_reserved_1", + FT_UINT32, BASE_HEX, NULL, 0x0FFFFFC, + NULL, HFILL } + }, + { &hf_pn_io_mrp_check_reserved_2, + { "MRP_Check.reserved_2", "pn_io.mrp_check_reserved_2", + FT_UINT32, BASE_HEX, NULL, 0x0FF000000, + NULL, HFILL } + }, + { &hf_pn_io_mrp_rtmode, + { "MRP_RTMode", "pn_io.mrp_rtmode", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_rtmode_rtclass12, + { "RTClass1_2", "pn_io.mrp_rtmode.class1_2", + FT_UINT32, BASE_HEX, VALS(pn_io_mrp_rtmode_rtclass12_vals), 0x00000001, + NULL, HFILL } + }, + { &hf_pn_io_mrp_rtmode_rtclass3, + { "RTClass1_3", "pn_io.mrp_rtmode.class3", + FT_UINT32, BASE_HEX, VALS(pn_io_mrp_rtmode_rtclass3_vals), 0x00000002, + NULL, HFILL } + }, + { &hf_pn_io_mrp_rtmode_reserved1, + { "Reserved_1", "pn_io.mrp_rtmode.reserved_1", + FT_UINT32, BASE_HEX, NULL, 0x00fffffc, + NULL, HFILL } + }, + { &hf_pn_io_mrp_rtmode_reserved2, + { "Reserved_2", "pn_io.mrp_rtmode.reserved_2", + FT_UINT32, BASE_HEX, NULL, 0xff000000, + NULL, HFILL } + }, + { &hf_pn_io_mrp_lnkdownt, + { "MRP_LNKdownT", "pn_io.mrp_lnkdownt", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Link down Interval in ms", HFILL } + }, + { &hf_pn_io_mrp_lnkupt, + { "MRP_LNKupT", "pn_io.mrp_lnkupt", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Link up Interval in ms", HFILL } + }, + { &hf_pn_io_mrp_lnknrmax, + { "MRP_LNKNRmax", "pn_io.mrp_lnknrmax", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_version, + { "MRP_Version", "pn_io.mrp_version", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_substitute_active_flag, + { "SubstituteActiveFlag", "pn_io.substitute_active_flag", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_length_data, + { "LengthData", "pn_io.length_data", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_ring_state, + { "MRP_RingState", "pn_io.mrp_ring_state", + FT_UINT16, BASE_HEX, VALS(pn_io_mrp_ring_state_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mrp_rt_state, + { "MRP_RTState", "pn_io.mrp_rt_state", + FT_UINT16, BASE_HEX, VALS(pn_io_mrp_rt_state_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_tag_function, + { "IM_Tag_Function", "pn_io.im_tag_function", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_tag_location, + { "IM_Tag_Location", "pn_io.im_tag_location", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_date, + { "IM_Date", "pn_io.im_date", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_descriptor, + { "IM_Descriptor", "pn_io.im_descriptor", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fs_hello_mode, + { "FSHelloMode", "pn_io.fs_hello_mode", + FT_UINT32, BASE_HEX, VALS(pn_io_fs_hello_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fs_hello_interval, + { "FSHelloInterval", "pn_io.fs_hello_interval", + FT_UINT32, BASE_DEC, NULL, 0x0, + "ms before conveying a second DCP_Hello.req", HFILL } + }, + { &hf_pn_io_fs_hello_retry, + { "FSHelloRetry", "pn_io.fs_hello_retry", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fs_hello_delay, + { "FSHelloDelay", "pn_io.fs_hello_delay", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fs_parameter_mode, + { "FSParameterMode", "pn_io.fs_parameter_mode", + FT_UINT32, BASE_HEX, VALS(pn_io_fs_parameter_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_fs_parameter_uuid, + { "FSParameterUUID", "pn_io.fs_parameter_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_check_sync_mode, + { "CheckSyncMode", "pn_io.check_sync_mode", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_check_sync_mode_reserved, + { "Reserved", "pn_io.check_sync_mode.reserved", + FT_UINT16, BASE_HEX, NULL, 0xFFFC, + NULL, HFILL } + }, + { &hf_pn_io_check_sync_mode_sync_master, + { "SyncMaster", "pn_io.check_sync_mode.sync_master", + FT_UINT16, BASE_HEX, NULL, 0x0002, + NULL, HFILL } + }, + { &hf_pn_io_check_sync_mode_cable_delay, + { "CableDelay", "pn_io.check_sync_mode.cable_delay", + FT_UINT16, BASE_HEX, NULL, 0x0001, + NULL, HFILL } + }, + /* PROFIsafe F-Parameter */ + { &hf_pn_io_ps_f_prm_flag1, + { "F_Prm_Flag1", "pn_io.ps.f_prm_flag1", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag1_chck_seq, + { "F_Check_SeqNr", "pn_io.ps.f_prm_flag1.f_check_seqnr", + FT_UINT8, BASE_HEX, VALS(pn_io_f_check_seqnr), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag1_chck_ipar, + { "F_Check_iPar", "pn_io.ps.f_prm_flag1.f_check_ipar", + FT_UINT8, BASE_HEX, VALS(pn_io_f_check_ipar), 0x02, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag1_sil, + { "F_SIL", "pn_io.ps.f_prm_flag1.f_sil", + FT_UINT8, BASE_HEX, VALS(pn_io_f_sil), 0xc, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag1_crc_len, + { "F_CRC_Length", "pn_io.ps.f_prm_flag1.f_crc_len", + FT_UINT8, BASE_HEX, VALS(pn_io_f_crc_len), 0x30, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag1_crc_seed, + { "F_CRC_Seed", "pn_io.ps.f_prm_flag1.f_crc_seed", + FT_UINT8, BASE_HEX, VALS(pn_io_f_crc_seed), 0x40, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag1_reserved, + { "Reserved", "pn_io.ps.f_prm_flag1.reserved", + FT_UINT8, BASE_HEX, NULL, 0x80, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag2, + { "F_Prm_Flag2", "pn_io.ps.f_prm_flag2", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag2_reserved, + { "Reserved", "pn_io.ps.f_prm_flag2.reserved", + FT_UINT8, BASE_HEX, NULL, 0x07, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag2_f_block_id, + { "F_Block_ID", "pn_io.ps.f_prm_flag2.f_block_id", + FT_UINT8, BASE_HEX, VALS(pn_io_f_block_id), 0x38, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_prm_flag2_f_par_version, + { "F_Par_Version", "pn_io.ps.f_prm_flag2.f_par_version", + FT_UINT8, BASE_HEX, VALS(pn_io_f_par_version), 0xC0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_wd_time, + { "F_WD_Time", "pn_io.ps.f_wd_time", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_ipar_crc, + { "F_iPar_CRC", "pn_io.ps.f_ipar_crc", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_par_crc, + { "F_Par_CRC", "pn_io.ps.f_par_crc", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_dest_adr, + { "F_Dest_Add", "pn_io.ps.f_dest_add", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_src_adr, + { "F_Source_Add", "pn_io.ps.f_source_add", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + /* profidrive parameter access */ + { &hf_pn_io_profidrive_request_reference, + { "RequestReference", "pn_io.profidrive.parameter.request_reference", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_request_id, + { "RequestID", "pn_io.profidrive.parameter.request_id", + FT_UINT8, BASE_HEX, VALS(pn_io_profidrive_request_id_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_do_id, + { "DO", "pn_io.profidrive.parameter.do", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_no_of_parameters, + { "NoOfParameters", "pn_io.profidrive.parameter.no_of_parameters", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_attribute, + { "Attribute", "pn_io.profidrive.parameter.attribute", + FT_UINT8, BASE_HEX, VALS(pn_io_profidrive_attribute_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_no_of_elems, + { "NoOfElements", "pn_io.profidrive.parameter.no_of_elems", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_number, + { "Parameter", "pn_io.profidrive.parameter.number", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_subindex, + { "Index", "pn_io.profidrive.parameter.index", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_response_id, + { "ResponseID", "pn_io.profidrive.parameter.response_id", + FT_UINT8, BASE_HEX, VALS(pn_io_profidrive_response_id_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_format, + { "Format", "pn_io.profidrive.parameter.format", + FT_UINT8, BASE_HEX, VALS(pn_io_profidrive_format_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_no_of_values, + { "NoOfValues", "pn_io.profidrive.parameter.no_of_values", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_value_byte, + { "Value", "pn_io.profidrive.parameter.value_b", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_value_word, + { "Value", "pn_io.profidrive.parameter.value_w", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_value_dword, + { "Value", "pn_io.profidrive.parameter.value_dw", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_value_float, + { "Value", "pn_io.profidrive.parameter.value_float", + FT_FLOAT, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_profidrive_param_value_string, + { "Value", "pn_io.profidrive.parameter.value_str", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_alarm_info_reserved_8_15, + { "RSAlarmInfo.Reserved2", "pn_io.rs_alarm_info_reserved_8_15", + FT_UINT16, BASE_HEX, NULL, 0x0FF00, + NULL, HFILL } + }, + { &hf_pn_io_rs_alarm_info_reserved_0_7, + { "RSAlarmInfo.Reserved1", "pn_io.rs_alarm_info_reserved_0_7", + FT_UINT16, BASE_HEX, NULL, 0x000FF, + NULL, HFILL } + }, + { &hf_pn_io_rs_alarm_info, + { "RS Alarm Info", "pn_io.rs_alarm_info", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_event_info, + { "RS Event Info", "pn_io.rs_event_info", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_event_block, + { "RS Event Block", "pn_io.rs_event_block", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_adjust_block, + { "RS Adjust Block", "pn_io.rs_adjust_block", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_event_data_extension, + { "RS Event Data Extension", "pn_io.rs_event_data_extension", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_rs_event_info, + { "RSEventInfo.NumberOfEntries", "pn_io.number_of_rs_event_info", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_block_type, + { "RS Block Type", "pn_io.rs_block_type", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_rs_block_type), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_block_length, + { "RS Block Length", "pn_io.rs_block_length", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_specifier, + { "RS_Specifier", "pn_io.rs_specifier", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_specifier_sequence, + { "RS_Specifier.SequenceNumber", "pn_io.rs_specifier.sequence", + FT_UINT16, BASE_HEX, NULL, 0x07FF, + NULL, HFILL } + }, + { &hf_pn_io_rs_specifier_reserved, + { "RS_Specifier.Reserved", "pn_io.rs_specifier_reserved", + FT_UINT16, BASE_HEX, NULL, 0x3800, + NULL, HFILL } + }, + { &hf_pn_io_rs_specifier_specifier, + { "RS_Specifier.Specifier", "pn_io.rs_specifier.specifier", + FT_UINT16, BASE_HEX, VALS(pn_io_rs_specifier_specifier), 0xC000, + NULL, HFILL } + }, + { &hf_pn_io_rs_time_stamp, + { "RS_TimeStamp", "pn_io.rs_time_stamp", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_time_stamp_status, + { "RS_TimeStamp.Status", "pn_io.rs_time_stamp.status", + FT_UINT16, BASE_HEX, VALS(pn_io_rs_time_stamp_status), 0x0003, + NULL, HFILL } + }, + { &hf_pn_io_rs_time_stamp_value, + { "RS_TimeStamp.Value", "pn_io.rs_time_stamp.value", + FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_minus_error, + { "RS_MinusError", "pn_io.rs_minus_error", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_plus_error, + { "RS_PlusError", "pn_io.rs_plus_error", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_extension_block_type, + { "RS_ExtensionBlockType", "pn_io.rs_extension_block_type", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_extension_block_length, + { "RS_ExtensionBlockLength", "pn_io.rs_extension_block_length", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_reason_code, + { "RS_ReasonCode", "pn_io.rs_reason_code", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_reason_code_reason, + { "RS_ReasonCode.Reason", "pn_io.rs_reason_code.reason", + FT_UINT32, BASE_HEX, VALS(pn_io_rs_reason_code_reason), 0x0000FFFF, + NULL, HFILL } + }, + { &hf_pn_io_rs_reason_code_detail, + { "RS_ReasonCode.Detail", "pn_io.rs_reason_code.detail", + FT_UINT32, BASE_HEX, VALS(pn_io_rs_reason_code_detail), 0xFFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_rs_domain_identification, + { "RS_DomainIdentification", "pn_io.rs_domain_identification", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_master_identification, + { "RS_MasterIdentification", "pn_io.rs_master_identification", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_soe_digital_input_current_value, + { "SoE_DigitalInputCurrentValue", "pn_io.soe_digital_input_current_value", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_soe_digital_input_current_value_value, + { "SoE_DigitalInputCurrentValue.Value", "pn_io.soe_digital_input_current_value.value", + FT_UINT16, BASE_HEX, VALS(pn_io_soe_digital_input_current_value_value), 0x0001, + NULL, HFILL } + }, + { &hf_pn_io_soe_digital_input_current_value_reserved, + { "SoE_DigitalInputCurrentValue.Reserved", "pn_io.soe_digital_input_current_value.reserved", + FT_UINT16, BASE_HEX, NULL, 0xFFFE, + NULL, HFILL } + }, + { &hf_pn_io_am_device_identification, + { "AM_DeviceIdentification", "pn_io.am_device_identification", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_device_identification_device_sub_id, + { "AM_DeviceIdentification.DeviceSubID", "pn_io.am_device_identification.device_sub_id", + FT_UINT64, BASE_HEX, NULL, 0x000000000000FFFF, + NULL, HFILL } + }, + { &hf_pn_io_am_device_identification_device_id, + { "AM_DeviceIdentification.DeviceID", "pn_io.am_device_identification.device_id", + FT_UINT64, BASE_HEX, NULL, 0x00000000FFFF0000, + NULL, HFILL } + }, + { &hf_pn_io_am_device_identification_vendor_id, + { "AM_DeviceIdentification.VendorID", "pn_io.am_device_identification.vendor_id", + FT_UINT64, BASE_HEX, NULL, 0x0000FFFF00000000, + NULL, HFILL } + }, + { &hf_pn_io_am_device_identification_organization, + { "AM_DeviceIdentification.Organization", "pn_io.am_device_identification.organization", + FT_UINT64, BASE_HEX, NULL, 0xFFFF000000000000, + NULL, HFILL } + }, + { &hf_pn_io_rs_adjust_info, + { "RS Adjust Info", "pn_io.rs_adjust_info", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_soe_max_scan_delay, + { "SoE_MaxScanDelay", "pn_io.soe_max_scan_delay", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_soe_adjust_specifier, + { "SoE_AdjustSpecifier", "pn_io.soe_adjust_specifier", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_soe_adjust_specifier_reserved, + { "SoE_AdjustSpecifier.Reserved", "pn_io.soe_adjust_specifier.reserved", + FT_UINT8, BASE_HEX, NULL, 0x3F, + NULL, HFILL } + }, + { &hf_pn_io_soe_adjust_specifier_incident, + { "SoE_AdjustSpecifier.Incident", "pn_io.soe_adjust_specifier.incident", + FT_UINT8, BASE_HEX, VALS(pn_io_soe_adjust_specifier_incident), 0xC0, + NULL, HFILL } + }, + { &hf_pn_io_rs_properties, + { "RSProperties", "pn_io.rs_properties", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_rs_properties_alarm_transport, + { "RSProperties", "pn_io.rs_properties", + FT_UINT32, BASE_HEX, VALS(pn_io_rs_properties_alarm_transport), 0x00000001, + NULL, HFILL } + }, + { &hf_pn_io_rs_properties_reserved1, + { "RSProperties.Reserved1", "pn_io.rs_properties.reserved1", + FT_UINT32, BASE_HEX, NULL, 0x00FFFFFE, + NULL, HFILL } + }, + { &hf_pn_io_rs_properties_reserved2, + { "RSProperties.Reserved2", "pn_io.rs_properties.reserved2", + FT_UINT32, BASE_HEX, NULL, 0xFF000000, + NULL, HFILL } + }, + { &hf_pn_io_asset_management_info, + { "Asset Management Info", "pn_io.asset_management_info", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_number_of_asset_management_info, + { "AssetManagementInfo.NumberOfEntries", "pn_io.number_of_asset_management_info", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_im_uniqueidentifier, + { "IM_UniqueIdentifier", "pn_io.IM_UniqueIdentifier", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_structure, + { "AM_Location.Structure", "pn_io.am_location.structure", + FT_UINT8, BASE_HEX, VALS(pn_io_am_location_structure_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location, + { "AM_Location", "pn_io.am_location", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_0, + { "AM_Location Level 0", "pn_io.am_location.level_0", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_1, + { "AM_Location Level 1", "pn_io.am_location.level_1", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_2, + { "AM_Location Level 2", "pn_io.am_location.level_2", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_3, + { "AM_Location Level 3", "pn_io.am_location.level_3", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_4, + { "AM_Location Level 4", "pn_io.am_location.level_4", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_5, + { "AM_Location Level 5", "pn_io.am_location.level_5", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_6, + { "AM_Location Level 6", "pn_io.am_location.level_6", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_7, + { "AM_Location Level 7", "pn_io.am_location.level_7", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_8, + { "AM_Location Level 8", "pn_io.am_location.level_8", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_9, + { "AM_Location Level 9", "pn_io.am_location.level_9", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_10, + { "AM_Location Level 10", "pn_io.am_location.level_10", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_level_11, + { "AM_Location Level 11", "pn_io.am_location.level_11", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_am_location_level_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_reserved1, + { "Reserved 1", "pn_io.am_location.reserved1", + FT_UINT8, BASE_HEX, VALS(pn_io_am_location_reserved_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_reserved2, + { "Reserved 2", "pn_io.am_location.reserved2", + FT_UINT16, BASE_HEX, VALS(pn_io_am_location_reserved_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_reserved3, + { "Reserved 3", "pn_io.am_location.reserved3", + FT_UINT16, BASE_HEX, VALS(pn_io_am_location_reserved_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_location_reserved4, + { "Reserved 3", "pn_io.am_location.reserved4", + FT_UINT16, BASE_HEX, VALS(pn_io_am_location_reserved_vals), 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_software_revision, + { "AM Software Revision", "pn_io.am_software_revision", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_hardware_revision, + { "AM Hardware Revision", "pn_io.am_hardware_revision", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_am_type_identification, + { "AM Type Identification", "pn_io.am_type_identification", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_mau_type_extension, + { "MAU Type Extension", "pn_io.mau_type_extension", + FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(pn_io_mau_type_extension), 0x0, + NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_pn_io, + &ett_pn_io_block, + &ett_pn_io_block_header, + &ett_pn_io_status, + &ett_pn_io_rtc, + &ett_pn_io_rta, + &ett_pn_io_pdu_type, + &ett_pn_io_add_flags, + &ett_pn_io_control_command, + &ett_pn_io_ioxs, + &ett_pn_io_api, + &ett_pn_io_data_description, + &ett_pn_io_module, + &ett_pn_io_submodule, + &ett_pn_io_io_data_object, + &ett_pn_io_io_cs, + &ett_pn_io_ar_properties, + &ett_pn_io_iocr_properties, + &ett_pn_io_submodule_properties, + &ett_pn_io_alarmcr_properties, + &ett_pn_io_submodule_state, + &ett_pn_io_channel_properties, + &ett_pn_io_slot, + &ett_pn_io_subslot, + &ett_pn_io_maintenance_status, + &ett_pn_io_data_status, + &ett_pn_io_iocr, + &ett_pn_io_mrp_rtmode, + &ett_pn_io_control_block_properties, + &ett_pn_io_check_sync_mode, + &ett_pn_io_ir_frame_data, + &ett_pn_FrameDataProperties, + &ett_pn_io_ar_info, + &ett_pn_io_ar_data, + &ett_pn_io_ir_begin_end_port, + &ett_pn_io_ir_tx_phase, + &ett_pn_io_ir_rx_phase, + &ett_pn_io_subframe_data, + &ett_pn_io_SFIOCRProperties, + &ett_pn_io_frame_defails, + &ett_pn_io_profisafe_f_parameter, + &ett_pn_io_profisafe_f_parameter_prm_flag1, + &ett_pn_io_profisafe_f_parameter_prm_flag2, + &ett_pn_io_profidrive_parameter_request, + &ett_pn_io_profidrive_parameter_response, + &ett_pn_io_profidrive_parameter_address, + &ett_pn_io_profidrive_parameter_value, + &ett_pn_io_GroupProperties, + &ett_pn_io_rs_alarm_info, + &ett_pn_io_rs_event_info, + &ett_pn_io_rs_event_block, + &ett_pn_io_rs_adjust_block, + &ett_pn_io_rs_event_data_extension, + &ett_pn_io_rs_specifier, + &ett_pn_io_rs_time_stamp, + &ett_pn_io_am_device_identification, + &ett_pn_io_rs_reason_code, + &ett_pn_io_soe_digital_input_current_value, + &ett_pn_io_rs_adjust_info, + &ett_pn_io_soe_adjust_specifier, + &ett_pn_io_asset_management_info, + &ett_pn_io_asset_management_block, + &ett_pn_io_am_location, + &ett_pn_io_sr_properties, + &ett_pn_io_line_delay, + &ett_pn_io_counter_status, + &ett_pn_io_dcp_boundary, + &ett_pn_io_peer_to_peer_boundary, + &ett_pn_io_mau_type_extension + }; + + static ei_register_info ei[] = { + { &ei_pn_io_block_version, { "pn_io.block_version.not_implemented", PI_UNDECODED, PI_WARN, "Block version not implemented yet!", EXPFILL }}, + { &ei_pn_io_error_code1, { "pn_io.error_code1.expert", PI_UNDECODED, PI_WARN, "Unknown ErrorCode1", EXPFILL }}, + { &ei_pn_io_error_code2, { "pn_io.error_code2.expert", PI_UNDECODED, PI_WARN, "Unknown ErrorDecode", EXPFILL }}, + { &ei_pn_io_ar_info_not_found, { "pn_io.ar_info_not_found", PI_UNDECODED, PI_NOTE, "IODWriteReq: AR information not found!", EXPFILL }}, + { &ei_pn_io_block_length, { "pn_io.block_length.invalid", PI_UNDECODED, PI_WARN, "Block length invalid!", EXPFILL }}, + { &ei_pn_io_unsupported, { "pn_io.profidrive.parameter.format.invalid", PI_UNDECODED, PI_WARN, "Unknown Fomatvalue", EXPFILL }}, + { &ei_pn_io_mrp_instances, { "pn_io.mrp_Number_MrpInstances.invalid", PI_UNDECODED, PI_WARN, "Number of MrpInstances invalid", EXPFILL }}, + { &ei_pn_io_frame_id, { "pn_io.frame_id.changed", PI_UNDECODED, PI_WARN, "FrameID changed", EXPFILL }}, + { &ei_pn_io_iocr_type, { "pn_io.iocr_type.unknown", PI_UNDECODED, PI_WARN, "IOCRType undecoded!", EXPFILL }}, + { &ei_pn_io_localalarmref, { "pn_io.localalarmref.changed", PI_UNDECODED, PI_WARN, "AlarmCRBlockReq: local alarm ref changed", EXPFILL }}, + { &ei_pn_io_nr_of_tx_port_groups, { "pn_io.nr_of_tx_port_groups.not_allowed", PI_PROTOCOL, PI_WARN, "Not allowed value of NumberOfTxPortGroups", EXPFILL }}, + { &ei_pn_io_max_recursion_depth_reached, { "pn_io.max_recursion_depth_reached", PI_PROTOCOL, PI_WARN, "Maximum allowed recursion depth reached - stopping dissection", EXPFILL }} + }; + + module_t *pnio_module; + expert_module_t* expert_pn_io; + + proto_pn_io = proto_register_protocol ("PROFINET IO", "PNIO", "pn_io"); + + /* Register by name */ + register_dissector("pnio", dissect_PNIO_heur, proto_pn_io); + + /* Created to remove Decode As confusion */ + proto_pn_io_device = proto_register_protocol_in_name_only("PROFINET IO (Device)", "PNIO (Device Interface)", "pn_io_device", proto_pn_io, FT_PROTOCOL); + proto_pn_io_controller = proto_register_protocol_in_name_only("PROFINET IO (Controller)", "PNIO (Controller Interface)", "pn_io_controller", proto_pn_io, FT_PROTOCOL); + proto_pn_io_supervisor = proto_register_protocol_in_name_only("PROFINET IO (Supervisor)", "PNIO (Supervisor Interface)", "pn_io_supervisor", proto_pn_io, FT_PROTOCOL); + proto_pn_io_parameterserver = proto_register_protocol_in_name_only("PROFINET IO (Parameter Server)", "PNIO (Parameter Server Interface)", "pn_io_parameterserver", proto_pn_io, FT_PROTOCOL); + proto_pn_io_implicitar = proto_register_protocol_in_name_only("PROFINET IO (Implicit Ar)", "PNIO (Implicit Ar)", "pn_io_implicitar", proto_pn_io, FT_PROTOCOL); + proto_pn_io_apdu_status = proto_register_protocol_in_name_only("PROFINET IO (Apdu Status)", "PNIO (Apdu Status)", "pn_io_apdu_status", proto_pn_io, FT_PROTOCOL); + + proto_register_field_array (proto_pn_io, hf, array_length (hf)); + proto_register_subtree_array (ett, array_length (ett)); + expert_pn_io = expert_register_protocol(proto_pn_io); + expert_register_field_array(expert_pn_io, ei, array_length(ei)); + + /* Register preferences */ + pnio_module = prefs_register_protocol(proto_pn_io, NULL); + prefs_register_bool_preference(pnio_module, "pnio_ps_selection", + "Enable detailed PROFIsafe dissection", + "Whether the PNIO dissector is allowed to use detailed PROFIsafe dissection of cyclic data frames", + &pnio_ps_selection); + prefs_register_directory_preference(pnio_module, "pnio_ps_networkpath", + "Configuration GSD-File Networkpath", /* Title */ + "Select your Networkpath to your GSD-Files.", /* Descreption */ + &pnio_ps_networkpath); /* Variable to save the GSD-File networkpath */ + + /* subdissector code */ + register_dissector("pn_io", dissect_PNIO_heur, proto_pn_io); + heur_pn_subdissector_list = register_heur_dissector_list("pn_io", proto_pn_io); + + /* Initialise RTC1 dissection */ + init_pn_io_rtc1(proto_pn_io); + + /* Cleanup functions of PNIO protocol */ + register_cleanup_routine(pnio_cleanup); + + register_conversation_filter("pn_io", "PN-IO AR", pn_io_ar_conv_valid, pn_io_ar_conv_filter); + register_conversation_filter("pn_io", "PN-IO AR (with data)", pn_io_ar_conv_valid, pn_io_ar_conv_data_filter); +} + + +void +proto_reg_handoff_pn_io (void) +{ + /* Register the protocols as dcerpc */ + dcerpc_init_uuid (proto_pn_io_device, ett_pn_io, &uuid_pn_io_device, ver_pn_io_device, pn_io_dissectors, hf_pn_io_opnum); + dcerpc_init_uuid (proto_pn_io_controller, ett_pn_io, &uuid_pn_io_controller, ver_pn_io_controller, pn_io_dissectors, hf_pn_io_opnum); + dcerpc_init_uuid (proto_pn_io_supervisor, ett_pn_io, &uuid_pn_io_supervisor, ver_pn_io_supervisor, pn_io_dissectors, hf_pn_io_opnum); + dcerpc_init_uuid (proto_pn_io_parameterserver, ett_pn_io, &uuid_pn_io_parameterserver, ver_pn_io_parameterserver, pn_io_dissectors, hf_pn_io_opnum); + dcerpc_init_uuid (proto_pn_io_implicitar, ett_pn_io, &uuid_pn_io_implicitar, ver_pn_io_implicitar, pn_io_dissectors, hf_pn_io_opnum); + + heur_dissector_add("pn_rt", dissect_PNIO_heur, "PROFINET IO", "pn_io_pn_rt", proto_pn_io, HEURISTIC_ENABLE); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-dcom-cba-acco.c b/plugins/epan/profinet/packet-dcom-cba-acco.c new file mode 100644 index 0000000000..9537ef36df --- /dev/null +++ b/plugins/epan/profinet/packet-dcom-cba-acco.c @@ -0,0 +1,5170 @@ +/* packet-dcom-cba-acco.c + * Routines for DCOM CBA + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <string.h> + +#include <epan/packet.h> +#include <epan/expert.h> +#include <epan/addr_resolv.h> +#include <epan/dissector_filters.h> +#include <epan/proto_data.h> +#include <epan/dissectors/packet-dcerpc.h> +#include <epan/dissectors/packet-dcom.h> +#include "packet-dcom-cba-acco.h" +#include <wsutil/ws_printf.h> /* ws_debug_printf */ + +void proto_register_dcom_cba_acco(void); +void proto_reg_handoff_dcom_cba_acco(void); + +static int hf_cba_acco_opnum = -1; + +static int hf_cba_acco_ping_factor = -1; + +static int hf_cba_acco_count = -1; + +static int hf_cba_acco_item = -1; +static int hf_cba_acco_data = -1; +static int hf_cba_acco_qc = -1; +static int hf_cba_acco_time_stamp = -1; + +static int hf_cba_acco_conn_qos_type = -1; +static int hf_cba_acco_conn_qos_value = -1; +static int hf_cba_acco_conn_state = -1; +static int hf_cba_acco_conn_cons_id = -1; +static int hf_cba_acco_conn_version = -1; +static int hf_cba_acco_conn_prov_id = -1; +static int hf_cba_acco_conn_provider = -1; +static int hf_cba_acco_conn_consumer = -1; +static int hf_cba_acco_conn_provider_item = -1; +static int hf_cba_acco_conn_consumer_item = -1; +static int hf_cba_acco_conn_substitute = -1; +static int hf_cba_acco_conn_epsilon = -1; +static int hf_cba_acco_conn_persist = -1; + +static int hf_cba_acco_cb_length = -1; +static int hf_cba_acco_cb_conn_data = -1; +static int hf_cba_acco_cb_version = -1; +static int hf_cba_acco_cb_flags = -1; +static int hf_cba_acco_cb_count = -1; +static int hf_cba_acco_cb_item = -1; +static int hf_cba_acco_cb_item_hole = -1; +static int hf_cba_acco_cb_item_length = -1; +static int hf_cba_acco_cb_item_data = -1; + +static int hf_cba_connect_in = -1; +static int hf_cba_disconnect_in = -1; +static int hf_cba_connectcr_in = -1; +static int hf_cba_disconnectcr_in = -1; +static int hf_cba_disconnectme_in = -1; +static int hf_cba_data_first_in = -1; +static int hf_cba_data_last_in = -1; + +/* static int hf_cba_acco_server_pICBAAccoCallback = -1; */ + +static int hf_cba_acco_server_first_connect = -1; + +static int hf_cba_acco_serversrt_prov_mac = -1; +static int hf_cba_acco_serversrt_cons_mac = -1; + +static int hf_cba_acco_serversrt_cr_id = -1; +static int hf_cba_acco_serversrt_cr_length = -1; +static int hf_cba_acco_serversrt_cr_flags = -1; +static int hf_cba_acco_serversrt_cr_flags_timestamped = -1; +static int hf_cba_acco_serversrt_cr_flags_reconfigure = -1; +static int hf_cba_acco_serversrt_record_length = -1; +/* static int hf_cba_acco_serversrt_action = -1; */ +static int hf_cba_acco_serversrt_last_connect = -1; + +static int hf_cba_getprovconnout = -1; + +static int hf_cba_type_desc_len = -1; + +static int hf_cba_connectincr = -1; +static int hf_cba_connectoutcr = -1; +static int hf_cba_connectin = -1; +static int hf_cba_connectout = -1; +static int hf_cba_getconnectionout = -1; +static int hf_cba_readitemout = -1; +static int hf_cba_writeitemin = -1; +static int hf_cba_addconnectionin = -1; +static int hf_cba_addconnectionout = -1; +static int hf_cba_getidout = -1; + +static int hf_cba_getconsconnout = -1; +static int hf_cba_diagconsconnout = -1; +static int hf_cba_acco_conn_error_state = -1; + +static int hf_cba_acco_info_max = -1; +static int hf_cba_acco_info_curr = -1; + +static int hf_cba_acco_cdb_cookie = -1; + +static int hf_cba_acco_rtauto = -1; + +static int hf_cba_acco_prov_crid = -1; + +static int hf_cba_acco_diag_req = -1; +static int hf_cba_acco_diag_in_length = -1; +static int hf_cba_acco_diag_out_length = -1; +static int hf_cba_acco_diag_data = -1; +static int hf_cba_acco_dcom_call = -1; +static int hf_cba_acco_srt_call = -1; + +gint ett_cba_connectincr = -1; +gint ett_cba_connectoutcr = -1; +gint ett_cba_connectin = -1; +gint ett_cba_connectout = -1; +gint ett_cba_getprovconnout = -1; +gint ett_cba_addconnectionin = -1; +gint ett_cba_addconnectionout = -1; +gint ett_cba_getidout = -1; +gint ett_cba_getconnectionout = -1; +gint ett_cba_readitemout = -1; +gint ett_cba_writeitemin = -1; +gint ett_cba_acco_serversrt_cr_flags = -1; +gint ett_cba_frame_info = -1; +gint ett_cba_conn_info = -1; + +static expert_field ei_cba_acco_pdev_find = EI_INIT; +static expert_field ei_cba_acco_prov_crid = EI_INIT; +static expert_field ei_cba_acco_conn_consumer = EI_INIT; +static expert_field ei_cba_acco_ldev_unknown = EI_INIT; +static expert_field ei_cba_acco_no_request_info = EI_INIT; +static expert_field ei_cba_acco_ipid_unknown = EI_INIT; +static expert_field ei_cba_acco_qc = EI_INIT; +static expert_field ei_cba_acco_pdev_find_unknown_interface = EI_INIT; +static expert_field ei_cba_acco_disconnect = EI_INIT; +static expert_field ei_cba_acco_connect = EI_INIT; + +static int proto_ICBAAccoMgt = -1; +static gint ett_ICBAAccoMgt = -1; +static e_guid_t uuid_ICBAAccoMgt = { 0xcba00041, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoMgt = 0; + +static int proto_ICBAAccoMgt2 = -1; +static e_guid_t uuid_ICBAAccoMgt2 = { 0xcba00046, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoMgt2 = 0; + +static int proto_ICBAAccoCallback = -1; +static gint ett_ICBAAccoCallback = -1; +static gint ett_ICBAAccoCallback_Buffer = -1; +static gint ett_ICBAAccoCallback_Item = -1; +static e_guid_t uuid_ICBAAccoCallback = { 0xcba00042, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoCallback = 0; + +static int proto_ICBAAccoCallback2 = -1; +static e_guid_t uuid_ICBAAccoCallback2 = { 0xcba00047, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoCallback2 = 0; + +static int proto_ICBAAccoServer = -1; +static gint ett_ICBAAccoServer = -1; +static e_guid_t uuid_ICBAAccoServer = { 0xcba00043, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoServer = 0; + +static int proto_ICBAAccoServer2 = -1; +static e_guid_t uuid_ICBAAccoServer2 = { 0xcba00048, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoServer2 = 0; + +static int proto_ICBAAccoServerSRT = -1; +static gint ett_ICBAAccoServerSRT = -1; +static e_guid_t uuid_ICBAAccoServerSRT = { 0xcba00045, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoServerSRT = 0; + +static int proto_ICBAAccoSync = -1; +static gint ett_ICBAAccoSync = -1; +static e_guid_t uuid_ICBAAccoSync = { 0xcba00044, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAAccoSync = 0; + + + +static const value_string cba_acco_qc_vals[] = { + { 0x1c, "BadOutOfService" }, + { 0x44, "UncertainLastUsableValue" }, + { 0x48, "UncertainSubstituteSet" }, + { 0x50, "UncertainSensorNotAccurate" }, + { 0x80, "GoodNonCascOk" }, + { 0, NULL } +}; + + +static const value_string cba_qos_type_vals[] = { + { 0x00, "Acyclic" }, + { 0x01, "Acyclic seconds" }, /* obsolete */ + { 0x02, "Acyclic status" }, + { 0x03, "Acyclic HMI" }, + { 0x20, "Constant" }, + { 0x30, "Cyclic Real-Time" }, + { 0, NULL } +}; + + +static const value_string cba_persist_vals[] = { + { 0x00, "Volatile" }, + { 0x01, "PendingPersistent" }, + { 0x02, "Persistent" }, + { 0, NULL } +}; + + +static const value_string cba_acco_conn_state_vals[] = { + { 0x00, "Passive" }, + { 0x01, "Active" }, + { 0, NULL } +}; + +#if 0 +static const value_string cba_acco_serversrt_action_vals[] = { + { 0x00, "Activate" }, + { 0x01, "Deactivate" }, + { 0x02, "Remove" }, + { 0, NULL } +}; +#endif + +static const value_string cba_acco_serversrt_last_connect_vals[] = { + { 0x00, "CR not complete" }, + { 0x01, "CR complete" }, + { 0, NULL } +}; + +static const value_string cba_acco_diag_req_vals[] = { + { 0x0000, "Function directory" }, + { 0x1000, "DevCat statistic" }, + { 0x2000, "Reset statistic" }, + { 0x3000, "Consumer Comm. Events" }, + { 0x4000, "Provider Comm. Events" }, + { 0, NULL } +}; + +static const true_false_string cba_acco_call_flags = { + "Consumer calls Provider (TRUE)", + "Provider calls Consumer (FALSE)" +}; + +static const value_string cba_qos_type_short_vals[] = { + { 0x00, "DCOM" }, + { 0x01, "DCOM(sec)" }, /* obsolete */ + { 0x02, "Status" }, + { 0x03, "HMI" }, + { 0x20, "Const" }, + { 0x30, "SRT" }, + { 0, NULL } +}; + + +typedef struct cba_frame_s { + cba_ldev_t *consparent; + cba_ldev_t *provparent; + GList *conns; + guint packet_connect; + guint packet_disconnect; + guint packet_disconnectme; + guint packet_first; + guint packet_last; + + guint16 length; + const guint8 consmac[6]; + guint16 conscrid; + guint32 provcrid; + guint32 conncrret; + guint16 qostype; + guint16 qosvalue; + guint16 offset; +} cba_frame_t; + +typedef struct cba_connection_s { + cba_ldev_t *consparentacco; + cba_ldev_t *provparentacco; + cba_frame_t *parentframe; + guint packet_connect; + guint packet_disconnect; + guint packet_disconnectme; + guint packet_first; + guint packet_last; + + guint16 length; + guint32 consid; + guint32 provid; + const gchar *provitem; + guint32 connret; + guint16 typedesclen; + guint16 *typedesc; + guint16 qostype; + guint16 qosvalue; + guint16 frame_offset; +} cba_connection_t; + + +typedef struct server_frame_call_s { + guint frame_count; + cba_frame_t **frames; +} server_frame_call_t; + + +typedef struct server_connect_call_s { + guint conn_count; + cba_frame_t *frame; + cba_connection_t **conns; +} server_connect_call_t; + +typedef struct server_disconnectme_call_s { + cba_ldev_t *cons; + cba_ldev_t *prov; +} server_disconnectme_call_t; + + +GList *cba_pdevs; + +/* as we are a plugin, we cannot get this from libwireshark! */ +const true_false_string acco_flags_set_truth = { "Set", "Not set" }; + +static gboolean +cba_filter_valid(packet_info *pinfo) +{ + void* profinet_type = p_get_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0); + + return ((profinet_type != NULL) && (GPOINTER_TO_UINT(profinet_type) < 10)); +} + +static gchar* +cba_build_filter(packet_info *pinfo) +{ + gboolean is_tcp = proto_is_frame_protocol(pinfo->layers, "tcp"); + void* profinet_type = p_get_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0); + + if ((pinfo->net_src.type == AT_IPv4) && (pinfo->net_dst.type == AT_IPv4) && is_tcp) { + /* IPv4 */ + switch(GPOINTER_TO_UINT(profinet_type)) { + case 1: + return g_strdup_printf("(ip.src eq %s and ip.dst eq %s and cba.acco.dcom == 1) || (ip.src eq %s and ip.dst eq %s and cba.acco.dcom == 0)", + address_to_str(pinfo->pool, &pinfo->net_dst), + address_to_str(pinfo->pool, &pinfo->net_src), + address_to_str(pinfo->pool, &pinfo->net_src), + address_to_str(pinfo->pool, &pinfo->net_dst)); + case 2: + return g_strdup_printf("(ip.src eq %s and ip.dst eq %s and cba.acco.dcom == 1) || (ip.src eq %s and ip.dst eq %s and cba.acco.dcom == 0)", + address_to_str(pinfo->pool, &pinfo->net_src), + address_to_str(pinfo->pool, &pinfo->net_dst), + address_to_str(pinfo->pool, &pinfo->net_dst), + address_to_str(pinfo->pool, &pinfo->net_src)); + case 3: + return g_strdup_printf("(ip.src eq %s and ip.dst eq %s and cba.acco.srt == 1) || (ip.src eq %s and ip.dst eq %s and cba.acco.srt == 0)", + address_to_str(pinfo->pool, &pinfo->net_dst), + address_to_str(pinfo->pool, &pinfo->net_src), + address_to_str(pinfo->pool, &pinfo->net_src), + address_to_str(pinfo->pool, &pinfo->net_dst)); + case 4: + return g_strdup_printf("(ip.src eq %s and ip.dst eq %s and cba.acco.srt == 1) || (ip.src eq %s and ip.dst eq %s and cba.acco.srt == 0)", + address_to_str(pinfo->pool, &pinfo->net_src), + address_to_str(pinfo->pool, &pinfo->net_dst), + address_to_str(pinfo->pool, &pinfo->net_dst), + address_to_str(pinfo->pool, &pinfo->net_src)); + default: + return NULL; + } + } + + return NULL; +} + +#if 0 +static void +cba_connection_dump(cba_connection_t *conn, const char *role) +{ + if (conn->qostype != 0x30) { + ws_debug_printf(" %s#%5u: CID:0x%8x PID:0x%8x PItem:\"%s\" Type:%s QoS:%s/%u Ret:%s Data#%5u-#%5u", + role, + conn->packet_connect, + conn->consid, conn->provid, conn->provitem, + conn->typedesclen != 0 ? val_to_str(conn->typedesc[0], dcom_variant_type_vals, "Unknown (0x%08x)") : "-", + val_to_str(conn->qostype, cba_qos_type_short_vals, "0x%x"), conn->qosvalue, + conn->connret==0xffffffff ? "[pending]" : val_to_str(conn->connret, dcom_hresult_vals, "Unknown (0x%08x)"), + conn->packet_first, conn->packet_last); + } else { + ws_debug_printf(" %s#%5u: CID:0x%8x PID:0x%8x PItem:\"%s\" Type:%s QoS:%s/%u Ret:%s Off:%u", + role, + conn->packet_connect, + conn->consid, conn->provid, conn->provitem, + conn->typedesclen != 0 ? val_to_str(conn->typedesc[0], dcom_variant_type_vals, "Unknown (0x%08x)") : "-", + val_to_str(conn->qostype, cba_qos_type_short_vals, "0x%x"), conn->qosvalue, + conn->connret==0xffffffff ? "[pending]" : val_to_str(conn->connret, dcom_hresult_vals, "Unknown (0x%08x)"), + conn->frame_offset); + } +} + + +static void +cba_object_dump(void) +{ + GList *pdevs; + GList *ldevs; + GList *frames; + GList *conns; + cba_pdev_t *pdev; + cba_ldev_t *ldev; + cba_frame_t *frame; + address addr; + + + for(pdevs = cba_pdevs; pdevs != NULL; pdevs = g_list_next(pdevs)) { + pdev = pdevs->data; + set_address(&addr, AT_IPv4, 4, pdev->ip); + ws_debug_printf("PDev #%5u: %s IFs:%u", pdev->first_packet, address_to_str(wmem_packet_scope(), &addr), + pdev->object ? g_list_length(pdev->object->interfaces) : 0); + + for(ldevs = pdev->ldevs; ldevs != NULL; ldevs = g_list_next(ldevs)) { + ldev = ldevs->data; + ws_debug_printf(" LDev#%5u: \"%s\" LDevIFs:%u AccoIFs:%u", ldev->first_packet, ldev->name, + ldev->ldev_object ? g_list_length(ldev->ldev_object->interfaces) : 0, + ldev->acco_object ? g_list_length(ldev->acco_object->interfaces) : 0); + for(frames = ldev->consframes; frames != NULL; frames = g_list_next(frames)) { + frame = frames->data; + ws_debug_printf(" ConsFrame#%5u: CCRID:0x%x PCRID:0x%x Len:%u Ret:%s Data#%5u-#%5u", + frame->packet_connect, frame->conscrid, frame->provcrid, frame->length, + frame->conncrret==0xffffffff ? "[pending]" : val_to_str(frame->conncrret, dcom_hresult_vals, "Unknown (0x%08x)"), + frame->packet_first, frame->packet_last); + for(conns = frame->conns; conns != NULL; conns = g_list_next(conns)) { + cba_connection_dump(conns->data, "ConsConn"); + } + } + for(frames = ldev->provframes; frames != NULL; frames = g_list_next(frames)) { + frame = frames->data; + ws_debug_printf(" ProvFrame#%5u: CCRID:0x%x PCRID:0x%x Len:%u Ret:%s Data#%5u-#%5u", + frame->packet_connect, frame->conscrid, frame->provcrid, frame->length, + frame->conncrret==0xffffffff ? "[pending]" : val_to_str(frame->conncrret, dcom_hresult_vals, "Unknown (0x%08x)"), + frame->packet_first, frame->packet_last); + for(conns = frame->conns; conns != NULL; conns = g_list_next(conns)) { + cba_connection_dump(conns->data, "ProvConn"); + } + } + for(conns = ldev->consconns; conns != NULL; conns = g_list_next(conns)) { + cba_connection_dump(conns->data, "ConsConn"); + } + for(conns = ldev->provconns; conns != NULL; conns = g_list_next(conns)) { + cba_connection_dump(conns->data, "ProvConn"); + } + } + } +} +#endif + + +cba_pdev_t * +cba_pdev_find(packet_info *pinfo, const address *addr, e_guid_t *ipid) +{ + cba_pdev_t *pdev; + dcom_interface_t *interf; + + + interf = dcom_interface_find(pinfo, addr, ipid); + if (interf != NULL) { + pdev = (cba_pdev_t *)interf->parent->private_data; + if (pdev == NULL) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_pdev_find, "pdev_find: no pdev for IP:%s IPID:%s", + address_to_str(wmem_packet_scope(), addr), guids_resolve_guid_to_str(ipid)); + } + } else { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_pdev_find_unknown_interface, "pdev_find: unknown interface of IP:%s IPID:%s", + address_to_str(wmem_packet_scope(), addr), guids_resolve_guid_to_str(ipid)); + pdev = NULL; + } + + return pdev; +} + + +cba_pdev_t * +cba_pdev_add(packet_info *pinfo, const address *addr) +{ + GList *cba_iter; + cba_pdev_t *pdev; + + + /* find pdev */ + for(cba_iter = cba_pdevs; cba_iter != NULL; cba_iter = g_list_next(cba_iter)) { + pdev = (cba_pdev_t *)cba_iter->data; + if (memcmp(pdev->ip, addr->data, 4) == 0) { + return pdev; + } + } + + /* not found, create a new */ + pdev = (cba_pdev_t *)wmem_alloc(wmem_file_scope(), sizeof(cba_pdev_t)); + memcpy( (void *) (pdev->ip), addr->data, 4); + pdev->first_packet = pinfo->num; + pdev->ldevs = NULL; + pdev->object = NULL; + cba_pdevs = g_list_append(cba_pdevs, pdev); + + return pdev; +} + + +void +cba_pdev_link(packet_info *pinfo _U_, cba_pdev_t *pdev, dcom_interface_t *pdev_interf) +{ + + /* "crosslink" pdev interface and its object */ + pdev->object = pdev_interf->parent; + pdev_interf->private_data = pdev; + if (pdev_interf->parent) { + pdev_interf->parent->private_data = pdev; + } +} + + +void +cba_ldev_link(packet_info *pinfo _U_, cba_ldev_t *ldev, dcom_interface_t *ldev_interf) +{ + + /* "crosslink" interface and its object */ + ldev->ldev_object = ldev_interf->parent; + ldev_interf->private_data = ldev; + if (ldev_interf->parent) { + ldev_interf->parent->private_data = ldev; + } +} + + +void +cba_ldev_link_acco(packet_info *pinfo _U_, cba_ldev_t *ldev, dcom_interface_t *acco_interf) +{ + + /* "crosslink" interface and its object */ + ldev->acco_object = acco_interf->parent; + acco_interf->private_data = ldev; + if (acco_interf->parent) { + acco_interf->parent->private_data = ldev; + } +} + + +cba_ldev_t * +cba_ldev_add(packet_info *pinfo, cba_pdev_t *pdev, const char *name) +{ + GList *cba_iter; + cba_ldev_t *ldev; + + + /* find ldev */ + for(cba_iter = pdev->ldevs; cba_iter != NULL; cba_iter = g_list_next(cba_iter)) { + ldev = (cba_ldev_t *)cba_iter->data; + if (strcmp(ldev->name, name) == 0) { + return ldev; + } + } + + /* not found, create a new */ + ldev = (cba_ldev_t *)wmem_alloc(wmem_file_scope(), sizeof(cba_ldev_t)); + ldev->name = wmem_strdup(wmem_file_scope(), name); + ldev->first_packet = pinfo->num; + ldev->ldev_object = NULL; + ldev->acco_object = NULL; + ldev->parent = pdev; + + ldev->provframes = NULL; + ldev->consframes = NULL; + ldev->provconns = NULL; + ldev->consconns = NULL; + + pdev->ldevs = g_list_append(pdev->ldevs, ldev); + + return ldev; +} + + +cba_ldev_t * +cba_ldev_find(packet_info *pinfo, const address *addr, e_guid_t *ipid) { + dcom_interface_t *interf; + cba_ldev_t *ldev; + + + interf = dcom_interface_find(pinfo, addr, ipid); + if (interf != NULL) { + ldev = (cba_ldev_t *)interf->private_data; + + if (ldev == NULL) { + ldev = (cba_ldev_t *)interf->parent->private_data; + } + if (ldev == NULL) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_ldev_unknown, "Unknown LDev of %s", + address_to_str(wmem_packet_scope(), addr)); + } + } else { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_ipid_unknown, "Unknown IPID of %s", + address_to_str(wmem_packet_scope(), addr)); + ldev = NULL; + } + + return ldev; +} + + +static cba_ldev_t * +cba_acco_add(packet_info *pinfo, const char *acco) +{ + char *ip_str; + char *delim; + guint32 ip; + cba_pdev_t *pdev; + cba_ldev_t *ldev; + address addr; + + + ip_str = g_strdup(acco); + delim = strchr(ip_str, '!'); + if (delim == NULL) { + g_free(ip_str); + return NULL; + } + *delim = 0; + + if (!get_host_ipaddr(ip_str, &ip)) { + g_free(ip_str); + return NULL; + } + + set_address(&addr, AT_IPv4, 4, &ip); + pdev = cba_pdev_add(pinfo, &addr); + delim++; + + ldev = cba_ldev_add(pinfo, pdev, delim); + + g_free(ip_str); + + return ldev; +} + + +static gboolean +cba_packet_in_range(packet_info *pinfo, guint packet_connect, guint packet_disconnect, guint packet_disconnectme) +{ + + if (packet_connect == 0) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_connect, "cba_packet_in_range#%u: packet_connect not set?", pinfo->num); + } + + if (packet_connect == 0 || pinfo->num < packet_connect) { + return FALSE; + } + if (packet_disconnect != 0 && pinfo->num > packet_disconnect) { + return FALSE; + } + if (packet_disconnectme != 0 && pinfo->num > packet_disconnectme) { + return FALSE; + } + + return TRUE; +} + + +static void +cba_frame_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, cba_frame_t *frame) +{ + if (tree) { + proto_item *item; + proto_item *sub_item; + proto_tree *sub_tree; + + sub_tree = proto_tree_add_subtree_format(tree, tvb, 0, 0, ett_cba_frame_info, &sub_item, + "Cons:\"%s\" CCRID:0x%x Prov:\"%s\" PCRID:0x%x QoS:%s/%ums Len:%u", + frame->consparent ? frame->consparent->name : "", frame->conscrid, + frame->provparent ? frame->provparent->name : "", frame->provcrid, + val_to_str(frame->qostype, cba_qos_type_short_vals, "%u"), + frame->qosvalue, frame->length); + PROTO_ITEM_SET_GENERATED(sub_item); + + item = proto_tree_add_uint(sub_tree, hf_cba_acco_conn_qos_type, tvb, 0, 0, frame->qostype); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_conn_qos_value, tvb, 0, 0, frame->qosvalue); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_serversrt_cr_id, tvb, 0, 0, frame->conscrid); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_prov_crid, tvb, 0, 0, frame->provcrid); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_serversrt_cr_length, tvb, 0, 0, frame->length); + PROTO_ITEM_SET_GENERATED(item); + + if (frame->consparent != NULL) { + item = proto_tree_add_string(sub_tree, hf_cba_acco_conn_consumer, tvb, 0, 0, frame->consparent->name); + PROTO_ITEM_SET_GENERATED(item); + } + if (frame->provparent != NULL) { + item = proto_tree_add_string(sub_tree, hf_cba_acco_conn_provider, tvb, 0, 0, frame->provparent->name); + PROTO_ITEM_SET_GENERATED(item); + } + + item = proto_tree_add_uint(sub_tree, hf_cba_connectcr_in, + tvb, 0, 0, frame->packet_connect); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_data_first_in, + tvb, 0, 0, frame->packet_first); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_data_last_in, + tvb, 0, 0, frame->packet_last); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_disconnectcr_in, + tvb, 0, 0, frame->packet_disconnect); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_disconnectme_in, + tvb, 0, 0, frame->packet_disconnectme); + PROTO_ITEM_SET_GENERATED(item); + } +} + + +static cba_frame_t * +cba_frame_connect(packet_info *pinfo, cba_ldev_t *cons_ldev, cba_ldev_t *prov_ldev, + guint16 qostype, guint16 qosvalue, const guint8 *consmac, guint16 conscrid, guint16 length) +{ + GList *cba_iter; + cba_frame_t *frame; + + /* find frame */ + for(cba_iter = cons_ldev->consframes; cba_iter != NULL; cba_iter = g_list_next(cba_iter)) { + frame = (cba_frame_t *)cba_iter->data; + if ( frame->conscrid == conscrid && + memcmp(frame->consmac, consmac, 6) == 0 && + cba_packet_in_range(pinfo, frame->packet_connect, frame->packet_disconnect, frame->packet_disconnectme)) { + return frame; + } + } + + frame = (cba_frame_t *)wmem_alloc(wmem_file_scope(), sizeof(cba_frame_t)); + + frame->consparent = cons_ldev; + frame->provparent = prov_ldev; + + frame->packet_connect = pinfo->num; + frame->packet_disconnect = 0; + frame->packet_disconnectme = 0; + frame->packet_first = 0; + frame->packet_last = 0; + + frame->length = length; + memcpy( (guint8 *) (frame->consmac), consmac, sizeof(frame->consmac)); + frame->conscrid = conscrid; + frame->qostype = qostype; + frame->qosvalue = qosvalue; + + frame->offset = 4; + frame->conns = NULL; + + frame->provcrid = 0; + frame->conncrret = -1; + + cons_ldev->consframes = g_list_append(cons_ldev->consframes, frame); + prov_ldev->provframes = g_list_append(prov_ldev->provframes, frame); + + return frame; +} + + +static void +cba_frame_disconnect(packet_info *pinfo, cba_frame_t *frame) +{ + + if (frame->packet_disconnect == 0) { + frame->packet_disconnect = pinfo->num; + } + + if (frame->packet_disconnect != pinfo->num) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_disconnect, "cba_frame_disconnect#%u: frame already disconnected in #%u", + pinfo->num, frame->packet_disconnect); + } +} + + +static void +cba_frame_disconnectme(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, cba_ldev_t *cons_ldev, cba_ldev_t *prov_ldev) +{ + GList *frames; + cba_frame_t *frame; + + + for(frames = cons_ldev->consframes; frames != NULL; frames = g_list_next(frames)) { + frame = (cba_frame_t *)frames->data; + + if ( frame->provparent == prov_ldev && + cba_packet_in_range(pinfo, frame->packet_connect, frame->packet_disconnect, frame->packet_disconnectme)) { + + cba_frame_info(tvb, pinfo, tree, frame); + + if (frame->packet_disconnectme == 0) { + frame->packet_disconnectme = pinfo->num; + } + + if (frame->packet_disconnectme != pinfo->num) { + expert_add_info_format(pinfo, tree, &ei_cba_acco_disconnect, "cba_frame_disconnectme#%u: frame already disconnectme'd in #%u", + pinfo->num, frame->packet_disconnectme); + } + } + } +} + + +static cba_frame_t * +cba_frame_find_by_cons(packet_info *pinfo, const guint8 *consmac, guint16 conscrid) +{ + GList *pdevs; + GList *ldevs; + GList *frames; + cba_pdev_t *pdev; + cba_ldev_t *ldev; + cba_frame_t *frame; + + + /* find pdev */ + for(pdevs = cba_pdevs; pdevs != NULL; pdevs = g_list_next(pdevs)) { + pdev = (cba_pdev_t *)pdevs->data; + + /* find ldev */ + for(ldevs = pdev->ldevs; ldevs != NULL; ldevs = g_list_next(ldevs)) { + ldev = (cba_ldev_t *)ldevs->data; + + /* find frame */ + for(frames = ldev->consframes; frames != NULL; frames = g_list_next(frames)) { + frame = (cba_frame_t *)frames->data; + + if ( frame->conscrid == conscrid && + memcmp(frame->consmac, consmac, 6) == 0 && + cba_packet_in_range(pinfo, frame->packet_connect, frame->packet_disconnect, frame->packet_disconnectme)) { + return frame; + } + } + } + } + + return NULL; +} + + +static cba_frame_t * +cba_frame_find_by_provcrid(packet_info *pinfo, cba_ldev_t *prov_ldev, guint32 provcrid) +{ + GList *frames; + cba_frame_t *frame; + + + if (prov_ldev == NULL) { + return NULL; + } + + for(frames = prov_ldev->provframes; frames != NULL; frames = g_list_next(frames)) { + frame = (cba_frame_t *)frames->data; + + if ( frame->provcrid == provcrid && + cba_packet_in_range(pinfo, frame->packet_connect, frame->packet_disconnect, frame->packet_disconnectme)) { + return frame; + } + } + + expert_add_info(pinfo, NULL, &ei_cba_acco_prov_crid); + + return NULL; +} + + +static void +cba_frame_incoming_data(tvbuff_t *tvb _U_, packet_info *pinfo, proto_tree *tree _U_, cba_frame_t *frame) +{ + if (frame->packet_first == 0) { + frame->packet_first = pinfo->num; + } + + if ( pinfo->num > frame->packet_last && + cba_packet_in_range(pinfo, frame->packet_connect, frame->packet_disconnect, frame->packet_disconnectme)) { + frame->packet_last = pinfo->num; + } +} + + +static void +cba_connection_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, cba_connection_t *conn) +{ + if (tree) { + proto_item *item; + proto_item *sub_item; + proto_tree *sub_tree; + + if (conn->qostype != 0x30) { + sub_tree = proto_tree_add_subtree_format(tree, tvb, 0, 0, ett_cba_conn_info, &sub_item, + "ProvItem:\"%s\" PID:0x%x CID:0x%x QoS:%s/%ums", + conn->provitem, conn->provid, conn->consid, + val_to_str(conn->qostype, cba_qos_type_short_vals, "%u"), conn->qosvalue); + } else { + sub_tree = proto_tree_add_subtree_format(tree, tvb, 0, 0, ett_cba_conn_info, &sub_item, + "ProvItem:\"%s\" PID:0x%x CID:0x%x Len:%u", + conn->provitem, conn->provid, conn->consid, conn->length); + } + PROTO_ITEM_SET_GENERATED(sub_item); + + item = proto_tree_add_string(sub_tree, hf_cba_acco_conn_provider_item, tvb, 0, 0 /* len */, conn->provitem); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_conn_prov_id, tvb, 0, 0 /* len */, conn->provid); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_conn_cons_id, tvb, 0, 0 /* len */, conn->consid); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_serversrt_record_length, tvb, 0, 0 /* len */, conn->length); + PROTO_ITEM_SET_GENERATED(item); + + if (conn->qostype != 0x30) { + item = proto_tree_add_uint(sub_tree, hf_cba_acco_conn_qos_type, + tvb, 0, 0, conn->qostype); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_acco_conn_qos_value, + tvb, 0, 0, conn->qosvalue); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_connect_in, + tvb, 0, 0, conn->packet_connect); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_data_first_in, + tvb, 0, 0, conn->packet_first); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_data_last_in, + tvb, 0, 0, conn->packet_last); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_disconnect_in, + tvb, 0, 0, conn->packet_disconnect); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(sub_tree, hf_cba_disconnectme_in, + tvb, 0, 0, conn->packet_disconnectme); + PROTO_ITEM_SET_GENERATED(item); + } + } +} + + +static cba_connection_t * +cba_connection_connect(packet_info *pinfo, cba_ldev_t *cons_ldev, cba_ldev_t *prov_ldev, cba_frame_t *cons_frame, + guint16 qostype, guint16 qosvalue, const char *provitem, guint32 consid, guint16 length, + guint16 *typedesc, guint16 typedesclen) +{ + GList *cba_iter; + cba_connection_t *conn; + + + /* find connection */ + if (cons_frame != NULL) { + /* SRT: search in frame */ + for(cba_iter = cons_frame->conns; cba_iter != NULL; cba_iter = g_list_next(cba_iter)) { + conn = (cba_connection_t *)cba_iter->data; + if (conn->consid == consid) { + return conn; + } + } + } else { + /* DCOM: search in ldev */ + for(cba_iter = cons_ldev->consconns; cba_iter != NULL; cba_iter = g_list_next(cba_iter)) { + conn = (cba_connection_t *)cba_iter->data; + if ( conn->consid == consid && + cba_packet_in_range(pinfo, conn->packet_connect, conn->packet_disconnect, conn->packet_disconnectme)) { + return conn; + } + } + } + + conn = (cba_connection_t *)wmem_alloc(wmem_file_scope(), sizeof(cba_connection_t)); + + conn->consparentacco = cons_ldev; + conn->provparentacco = prov_ldev; + conn->parentframe = cons_frame; + + conn->packet_connect = pinfo->num; + conn->packet_disconnect = 0; + conn->packet_disconnectme = 0; + conn->packet_first = 0; + conn->packet_last = 0; + + conn->consid = consid; + conn->provitem = wmem_strdup(wmem_file_scope(), provitem); + conn->typedesclen = typedesclen; + conn->typedesc = typedesc; + conn->qostype = qostype; + conn->qosvalue = qosvalue; + conn->length = length; + + conn->provid = 0; + conn->connret = -1; + + if (cons_frame != NULL) { + conn->frame_offset = cons_frame->offset; + conn->length = length; + cons_frame->offset += length; + cons_frame->conns = g_list_append(cons_frame->conns, conn); + } else { + conn->frame_offset = 0; + cons_ldev->consconns = g_list_append(cons_ldev->consconns, conn); + prov_ldev->provconns = g_list_append(prov_ldev->provconns, conn); + } + + return conn; +} + + +static void +cba_connection_disconnect(packet_info *pinfo, cba_connection_t *conn) +{ + /* XXX - detect multiple disconnects? */ + if (conn->packet_disconnect == 0) { + conn->packet_disconnect = pinfo->num; + } + + if (conn->packet_disconnect != pinfo->num) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_disconnect, "connection_disconnect#%u: already disconnected", + conn->packet_disconnect); + } +} + + +static void +cba_connection_disconnectme(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, cba_ldev_t *cons_ldev, cba_ldev_t *prov_ldev) +{ + GList *conns; + cba_connection_t *conn; + + + for(conns = cons_ldev->consconns; conns != NULL; conns = g_list_next(conns)) { + conn = (cba_connection_t *)conns->data; + + if ( conn->provparentacco == prov_ldev && + cba_packet_in_range(pinfo, conn->packet_connect, conn->packet_disconnect, conn->packet_disconnectme)) { + + cba_connection_info(tvb, pinfo, tree, conn); + + if (conn->packet_disconnectme == 0) { + conn->packet_disconnectme = pinfo->num; + } + + if (conn->packet_disconnectme != pinfo->num) { + expert_add_info_format(pinfo, tree, &ei_cba_acco_disconnect, "connection_disconnectme#%u: already disconnectme'd", + conn->packet_disconnectme); + } + } + } +} + + +static cba_connection_t * +cba_connection_find_by_provid(tvbuff_t *tvb _U_, packet_info *pinfo, proto_tree *tree _U_, cba_ldev_t *prov_ldev, guint32 provid) +{ + GList *cba_iter; + cba_connection_t *conn; + + + for(cba_iter = prov_ldev->provconns; cba_iter != NULL; cba_iter = g_list_next(cba_iter)) { + conn = (cba_connection_t *)cba_iter->data; + if ( conn->provid == provid && + cba_packet_in_range(pinfo, conn->packet_connect, conn->packet_disconnect, conn->packet_disconnectme)) { + return conn; + } + } + return NULL; +} + + +static void +cba_connection_incoming_data(tvbuff_t *tvb _U_, packet_info *pinfo, proto_tree *tree _U_, cba_connection_t *conn) +{ + if (conn->packet_first == 0) { + conn->packet_first = pinfo->num; + } + + if ( pinfo->num > conn->packet_last && + cba_packet_in_range(pinfo, conn->packet_connect, conn->packet_disconnect, conn->packet_disconnectme)) { + conn->packet_last = pinfo->num; + } +} + + +/* dissect a response containing an array of hresults (e.g: ICBAAccoMgt::RemoveConnections) */ +static int +dissect_HResultArray_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32Idx; + guint32 u32Tmp; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + u32Tmp = u32ArraySize; + while (u32Tmp--) { + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult, u32Idx); + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32ArraySize, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServer_SetActivation_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32Idx; + guint32 u32Tmp; + proto_item *item; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + u32Tmp = u32ArraySize; + while (u32Tmp--) { + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult, u32Idx); + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32ArraySize, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_Disconnect_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32Idx; + guint32 u32Tmp; + proto_item *item; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + u32Tmp = u32ArraySize; + while (u32Tmp--) { + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult, u32Idx); + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32ArraySize, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_SetActivation_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32Idx; + guint32 u32Tmp; + proto_item *item; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + u32Tmp = u32ArraySize; + while (u32Tmp--) { + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult, u32Idx); + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32ArraySize, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServer_Connect_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8State; + guint32 u32Count; + guint32 u32ArraySize; + + guint32 u32VariableOffset; + guint32 u32SubStart; + guint32 u32Pointer; + guint16 u16VarType; + guint32 u32ConsID; + gchar szItem[1000] = { 0 }; + guint32 u32MaxItemLen = sizeof(szItem); + gchar szCons[1000] = { 0 }; + guint32 u32MaxConsLen = sizeof(szCons); + guint32 u32Idx; + + proto_item *item; + dcom_interface_t *cons_interf; + cba_ldev_t *cons_ldev; + cba_ldev_t *prov_ldev; + cba_connection_t *conn; + server_connect_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szCons, u32MaxConsLen); + + /* find the consumer ldev by its name */ + cons_ldev = cba_acco_add(pinfo, szCons); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + offset = dissect_dcom_BYTE(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, &cons_interf); + if (cons_interf == NULL) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_conn_consumer, + "Server_Connect: consumer interface invalid"); + } + + /* "crosslink" consumer interface and its object */ + if (cons_interf != NULL && cons_ldev != NULL) { + cba_ldev_link_acco(pinfo, cons_ldev, cons_interf); + } + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* link connections infos to the call */ + if (prov_ldev != NULL && cons_ldev != NULL) { + call = (server_connect_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_connect_call_t) + u32ArraySize * sizeof(cba_connection_t *)); + call->conn_count = 0; + call->frame = NULL; + call->conns = (cba_connection_t **) (call+1); + di->call_data->private_data = call; + } else{ + call = NULL; + } + + u32VariableOffset = offset + u32ArraySize*16; + + /* array of CONNECTINs */ + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_connectin, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectin); + u32SubStart = offset; + + /* ProviderItem */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szItem, u32MaxItemLen); + } + + /* DataType */ + offset = dissect_dcom_VARTYPE(tvb, offset, pinfo, sub_tree, di, drep, + &u16VarType); + + /* Epsilon */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_epsilon); + } + /* ConsumerID */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID); + + /* add to object database */ + if (prov_ldev != NULL && cons_ldev != NULL) { + conn = cba_connection_connect(pinfo, cons_ldev, prov_ldev, /*cons_frame*/ NULL, + u16QoSType, u16QoSValue, szItem, u32ConsID, 0, + /* XXX - VarType must be translated to new type description if it includes an array (0x2000) */ + (guint16 *)wmem_memdup(wmem_file_scope(), &u16VarType, 2), 1); + + cba_connection_info(tvb, pinfo, sub_tree, conn); + } else { + conn = NULL; + } + + /* add to current call */ + if (call != NULL) { + call->conn_count++; + call->conns[u32Idx-1] = conn; + } + + /* update subtree header */ + proto_item_append_text(sub_item, "[%u]: ConsID=0x%x, ProvItem=\"%s\", VarType=%s", + u32Idx, u32ConsID, szItem, + val_to_str(u16VarType, dcom_variant_type_vals, "Unknown (0x%04x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Consumer=\"%s\" Cnt=%u", szCons, u32Count); + + return u32VariableOffset; +} + +static int +dissect_ICBAAccoServer2_Connect2_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8State; + guint32 u32Count; + guint32 u32ArraySize; + + guint32 u32VariableOffset; + guint32 u32SubStart; + guint32 u32Pointer; + guint16 u16VarType; + guint32 u32ConsID; + gchar szItem[1000] = { 0 }; + guint32 u32MaxItemLen = sizeof(szItem); + gchar szCons[1000] = { 0 }; + guint32 u32MaxConsLen = sizeof(szCons); + guint32 u32Idx; + guint16 u16TypeDescLen; + guint32 u32ArraySize2; + guint32 u32Idx2; + guint16 u16VarType2 = -1; + + proto_item *item; + dcom_interface_t *cons_interf; + cba_ldev_t *prov_ldev; + cba_ldev_t *cons_ldev; + cba_connection_t *conn; + guint16 typedesclen = 0; + guint16 *typedesc = NULL; + server_connect_call_t *call = NULL; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szCons, u32MaxConsLen); + + /* find the consumer ldev by its name */ + cons_ldev = cba_acco_add(pinfo, szCons); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + offset = dissect_dcom_BYTE(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_MInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, &cons_interf); + if (cons_interf == NULL) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_conn_consumer, + "Server2_Connect2: consumer interface invalid"); + } + } else { + /* GetConnectionData do it this way */ + cons_interf = NULL; + } + + /* "crosslink" consumer interface and its object */ + if (cons_interf != NULL && cons_ldev != NULL) { + cba_ldev_link_acco(pinfo, cons_ldev, cons_interf); + } + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* link connection infos to the call */ + if (prov_ldev != NULL && cons_ldev != NULL) { + call = (server_connect_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_connect_call_t) + u32ArraySize * sizeof(cba_connection_t *)); + call->conn_count = 0; + call->frame = NULL; + call->conns = (cba_connection_t **) (call+1); + di->call_data->private_data = call; + } else{ + call = NULL; + } + + u32VariableOffset = offset + u32ArraySize*20; + + /* array of CONNECTINs */ + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_connectin, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectin); + u32SubStart = offset; + + /* ProviderItem */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szItem, u32MaxItemLen); + } + + /* TypeDescLen */ + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_type_desc_len, &u16TypeDescLen); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + /* pTypeDesc */ + if (u32Pointer) { + u32VariableOffset = dissect_dcom_dcerpc_array_size(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + &u32ArraySize2); + + /* limit the allocation to a reasonable size */ + if (u32ArraySize2 < 1000) { + typedesc = (guint16 *)wmem_alloc0(wmem_file_scope(), u32ArraySize2 * 2); + typedesclen = u32ArraySize2; + } else { + typedesc = NULL; + typedesclen = 0; + } + + /* extended type description will build an array here */ + u32Idx2 = 1; + while (u32ArraySize2--) { + /* ToBeDone: some of the type description values are counts */ + u32VariableOffset = dissect_dcom_VARTYPE(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + &u16VarType); + + if (typedesc != NULL && u32Idx2 <= typedesclen) { + typedesc[u32Idx2-1] = u16VarType; + } + + /* remember first VarType only */ + if (u32Idx2 == 1) { + u16VarType2 = u16VarType; + } + u32Idx2++; + } + } + + /* Epsilon */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_epsilon); + } + /* ConsumerID */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID); + + /* add to object database */ + if (prov_ldev != NULL && cons_ldev != NULL) { + conn = cba_connection_connect(pinfo, cons_ldev, prov_ldev, /*cons_frame*/ NULL, + u16QoSType, u16QoSValue, szItem, u32ConsID, 0, + typedesc, typedesclen); + + cba_connection_info(tvb, pinfo, sub_tree, conn); + } else { + conn = NULL; + } + + /* add to current call */ + if (call != NULL) { + call->conn_count++; + call->conns[u32Idx-1] = conn; + } + + /* update subtree header */ + proto_item_append_text(sub_item, "[%u]: ConsID=0x%x, ProvItem=\"%s\", TypeDesc=%s", + u32Idx, u32ConsID, szItem, + val_to_str(u16VarType2, dcom_variant_type_vals, "Unknown (0x%04x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Consumer=\"%s\" Cnt=%u", szCons, u32Count); + + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoServer_Connect_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint8 u8FirstConnect; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32HResult; + guint32 u32Idx = 1; + guint32 u32ProvID; + guint32 u32SubStart; + + proto_item *item; + cba_connection_t *conn; + server_connect_call_t *call = (server_connect_call_t *)di->call_data->private_data; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + if (call == NULL) { + expert_add_info(pinfo, NULL, &ei_cba_acco_no_request_info); + } + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_server_first_connect, &u8FirstConnect); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* array of CONNECTOUTs */ + while(u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_connectout, tvb, offset, 8, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectout); + u32SubStart = offset; + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID); + + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + /* put response data into the connection */ + if (call && u32Idx <= call->conn_count) { + conn = call->conns[u32Idx-1]; + conn->provid = u32ProvID; + conn->connret = u32HResult; + + cba_connection_info(tvb, pinfo, sub_tree, conn); + } + + proto_item_append_text(sub_item, "[%u]: ProvID=0x%x %s", + u32Idx, u32ProvID, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + /* this might be a global HRESULT */ + while(call && u32Idx <= call->conn_count) { + conn = call->conns[u32Idx-1]; + conn->provid = 0; + conn->connret = u32HResult; + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %s Cnt=%u -> %s", + (u8FirstConnect) ? "First" : "NotFirst", + u32Idx-1, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServer_Disconnect_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvID; + + proto_item *item; + cba_ldev_t *prov_ldev; + cba_connection_t *conn; + server_connect_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + /* link connection infos to the call */ + if (prov_ldev != NULL) { + call = (server_connect_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_connect_call_t) + u32ArraySize * sizeof(cba_connection_t *)); + call->conn_count = 0; + call->frame = NULL; + call->conns = (cba_connection_t **) (call+1); + di->call_data->private_data = call; + } else{ + call = NULL; + } + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID, u32Idx); + + /* add to current call */ + if (call != NULL) { + conn = cba_connection_find_by_provid(tvb, pinfo, tree, prov_ldev, u32ProvID); + call->conn_count++; + call->conns[u32Idx-1] = conn; + } + + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + + return offset; +} + + +static int +dissect_ICBAAccoServer_Disconnect_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32Idx; + guint32 u32Tmp; + + proto_item *item; + cba_connection_t *conn; + server_connect_call_t *call = (server_connect_call_t *)di->call_data->private_data; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + if (call == NULL) { + expert_add_info(pinfo, NULL, &ei_cba_acco_no_request_info); + } + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + u32Tmp = u32ArraySize; + while (u32Tmp--) { + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult, u32Idx); + + /* mark this connection as disconnected */ + if (call && u32Idx <= call->conn_count) { + conn = call->conns[u32Idx-1]; + if (conn != NULL) { + cba_connection_disconnect(pinfo, conn); + } + } + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32ArraySize, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_Disconnect_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvID; + proto_item *item; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID, u32Idx); + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return offset; +} + + +static int +dissect_ICBAAccoServer_DisconnectMe_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + proto_item *item; + cba_ldev_t *prov_ldev; + cba_ldev_t *cons_ldev; + server_disconnectme_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szStr, u32MaxStr); + + /* find the consumer ldev by its name */ + cons_ldev = cba_acco_add(pinfo, szStr); + + if (prov_ldev != NULL && cons_ldev != NULL) { + call = (server_disconnectme_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_disconnectme_call_t)); + call->cons = cons_ldev; + call->prov = prov_ldev; + di->call_data->private_data = call; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, " Consumer=\"%s\"", szStr); + + return offset; +} + + +static int +dissect_ICBAAccoServer_DisconnectMe_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + proto_item *item; + server_disconnectme_call_t *call; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + call = (server_disconnectme_call_t *)di->call_data->private_data; + if (call) { + cba_connection_disconnectme(tvb, pinfo, tree, call->cons, call->prov); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_DisconnectMe_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + proto_item *item; + cba_ldev_t *prov_ldev; + cba_ldev_t *cons_ldev; + server_disconnectme_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szStr, u32MaxStr); + + /* find the consumer ldev by its name */ + cons_ldev = cba_acco_add(pinfo, szStr); + + if (prov_ldev != NULL && cons_ldev != NULL) { + call = (server_disconnectme_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_disconnectme_call_t)); + call->cons = cons_ldev; + call->prov = prov_ldev; + di->call_data->private_data = call; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, " Consumer=\"%s\"", szStr); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_DisconnectMe_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + proto_item *item; + server_disconnectme_call_t *call; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + call = (server_disconnectme_call_t *)di->call_data->private_data; + if (call) { + cba_frame_disconnectme(tvb, pinfo, tree, call->cons, call->prov); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServer_Ping_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + proto_item *item; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServer_SetActivation_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint8 u8State; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvID; + proto_item *item; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID, u32Idx); + u32Idx++; + } + + /* update column info now */ + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_SetActivation_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint8 u8State; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvID; + proto_item *item; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID, u32Idx); + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return offset; +} + + +static int +dissect_ICBAAccoServer_Ping_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + proto_item *item; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szStr, u32MaxStr); + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, " Consumer=\"%s\"", szStr); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_ConnectCR_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szCons[1000] = { 0 }; + guint32 u32MaxConsLen = sizeof(szCons); + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8ConsMac[6]; + guint16 u16CRID = 0; + guint16 u16CRLength = 0; + guint32 u32Flags; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + proto_item *item; + proto_tree *flags_tree; + guint32 u32SubStart; + dcom_interface_t *cons_interf; + cba_ldev_t *prov_ldev; + cba_ldev_t *cons_ldev; + cba_frame_t *frame; + server_frame_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + /* szCons */ + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szCons, u32MaxConsLen); + + /* find the consumer ldev by its name */ + cons_ldev = cba_acco_add(pinfo, szCons); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, &cons_interf); + if (cons_interf == NULL) { + expert_add_info_format(pinfo, NULL, &ei_cba_acco_conn_consumer, + "ServerSRT_ConnectCR: consumer interface invalid"); + } + + /* "crosslink" consumer interface and its object */ + if (cons_interf != NULL && cons_ldev != NULL) { + cba_ldev_link_acco(pinfo, cons_ldev, cons_interf); + } + + /* ConsumerMAC (big-endian, 1byte-aligned) */ + tvb_memcpy(tvb, u8ConsMac, offset, 6); + + proto_tree_add_ether(tree, hf_cba_acco_serversrt_cons_mac, tvb, + offset, 6, u8ConsMac); + offset += 6; + + /* add flags subtree */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, NULL /*tree*/, di, drep, + 0 /* hfindex */, &u32Flags); + offset -= 4; + item = proto_tree_add_uint_format_value(tree, hf_cba_acco_serversrt_cr_flags, + tvb, offset, 4, u32Flags, + "0x%02x (%s, %s)", u32Flags, + (u32Flags & 0x2) ? "Reconfigure" : "not Reconfigure", + (u32Flags & 0x1) ? "Timestamped" : "not Timestamped"); + flags_tree = proto_item_add_subtree(item, ett_cba_acco_serversrt_cr_flags); + proto_tree_add_boolean(flags_tree, hf_cba_acco_serversrt_cr_flags_reconfigure, tvb, offset, 4, u32Flags); + proto_tree_add_boolean(flags_tree, hf_cba_acco_serversrt_cr_flags_timestamped, tvb, offset, 4, u32Flags); + offset += 4; + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* link frame infos to the call */ + if (prov_ldev != NULL && cons_ldev != NULL && u32ArraySize < 100) { + call = (server_frame_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_frame_call_t) + u32ArraySize * sizeof(cba_frame_t *)); + call->frame_count = 0; + call->frames = (cba_frame_t **) (call+1); + di->call_data->private_data = call; + } else { + call = NULL; + } + + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + /* array of CONNECTINCRs */ + sub_item = proto_tree_add_item(tree, hf_cba_connectincr, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectincr); + u32SubStart = offset; + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_serversrt_cr_id, &u16CRID); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_serversrt_cr_length, &u16CRLength); + + /* add to object database */ + if (prov_ldev != NULL && cons_ldev != NULL) { + frame = cba_frame_connect(pinfo, cons_ldev, prov_ldev, u16QoSType, u16QoSValue, u8ConsMac, u16CRID, u16CRLength); + + cba_frame_info(tvb, pinfo, sub_tree, frame); + } else { + frame = NULL; + } + + /* add to current call */ + if (call != NULL) { + call->frame_count++; + call->frames[u32Idx-1] = frame; + } + + /* update subtree header */ + proto_item_append_text(sub_item, "[%u]: CRID=0x%x, CRLength=%u", + u32Idx, u16CRID, u16CRLength); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": %sConsCRID=0x%x Len=%u QoS=%u", + (u32Flags & 0x2) ? "Reco " : "", u16CRID, u16CRLength, u16QoSValue); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_ConnectCR_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint8 u8FirstConnect; + guint8 u8ProvMac[6]; + guint32 u32ProvCRID = 0; + guint32 u32HResult; + guint32 u32ArraySize; + guint32 u32Idx = 1; + guint32 u32Pointer; + guint32 u32SubStart; + proto_item *item; + cba_frame_t *frame; + server_frame_call_t *call = (server_frame_call_t *)di->call_data->private_data; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + if (call == NULL) { + expert_add_info(pinfo, NULL, &ei_cba_acco_no_request_info); + } + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_server_first_connect, &u8FirstConnect); + + /* ProviderMAC (big-endian, 1byte-aligned) */ + tvb_memcpy(tvb, u8ProvMac, offset, 6); + + proto_tree_add_ether(tree, hf_cba_acco_serversrt_prov_mac, tvb, + offset, 6, u8ProvMac); + offset += 6; + + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + /* array of CONNECTOUTCRs */ + sub_item = proto_tree_add_item(tree, hf_cba_connectoutcr, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectoutcr); + u32SubStart = offset; + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_prov_crid, &u32ProvCRID); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult); + + /* put response data into the frame */ + if (call && u32Idx <= call->frame_count) { + frame = call->frames[u32Idx-1]; + frame->provcrid = u32ProvCRID; + frame->conncrret = u32HResult; + + cba_frame_info(tvb, pinfo, sub_tree, frame); + } + + /* update subtree header */ + proto_item_append_text(sub_item, "[%u]: ProvCRID=0x%x, %s", + u32Idx, u32ProvCRID, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + /* this might be a global HRESULT */ + while(call && u32Idx <= call->frame_count) { + frame = call->frames[u32Idx-1]; + frame->provcrid = 0; + frame->conncrret = u32HResult; + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %s PCRID=0x%x -> %s", + (u8FirstConnect) ? "FirstCR" : "NotFirstCR", + u32ProvCRID, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_DisconnectCR_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvCRID = 0; + proto_item *item; + cba_ldev_t *prov_ldev; + cba_frame_t *frame; + server_frame_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* link frame infos to the call */ + if (prov_ldev != NULL) { + call = (server_frame_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_frame_call_t) + u32ArraySize * sizeof(cba_frame_t *)); + call->frame_count = 0; + call->frames = (cba_frame_t **) (call+1); + di->call_data->private_data = call; + } else{ + call = NULL; + } + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_prov_crid, &u32ProvCRID, u32Idx); + + /* find frame and add it to current call */ + if (call != NULL) { + frame = cba_frame_find_by_provcrid(pinfo, prov_ldev, u32ProvCRID); + call->frame_count++; + call->frames[u32Idx-1] = frame; + } + + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": PCRID=0x%x", + u32ProvCRID); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_DisconnectCR_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32Idx; + guint32 u32Tmp; + cba_frame_t *frame; + proto_item *item; + server_frame_call_t *call = (server_frame_call_t *)di->call_data->private_data; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + u32Tmp = u32ArraySize; + while (u32Tmp--) { + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult, u32Idx); + /* put response data into the frame */ + if (call && u32Idx <= call->frame_count) { + frame = call->frames[u32Idx-1]; + if (frame != NULL) { + cba_frame_disconnect(pinfo, frame); + } + } + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServerSRT_Connect_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32ProvCRID; + guint8 u8State; + guint8 u8LastConnect; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32VariableOffset; + guint32 u32Idx; + guint32 u32SubStart; + guint32 u32Pointer; + gchar szProvItem[1000] = { 0 }; + guint32 u32MaxProvItemLen = sizeof(szProvItem); + guint16 u16TypeDescLen; + guint32 u32ArraySize2; + guint32 u32Idx2; + guint16 u16VarType2 = -1; + guint16 u16VarType; + guint32 u32ConsID; + guint16 u16RecordLength; + + proto_item *item; + cba_ldev_t *prov_ldev; + cba_frame_t *frame = NULL; + guint16 typedesclen = 0; + guint16 *typedesc = NULL; + + cba_connection_t *conn; + server_connect_call_t *call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + prov_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_prov_crid, &u32ProvCRID); + + frame = cba_frame_find_by_provcrid(pinfo, prov_ldev, u32ProvCRID); + + if (frame != NULL) { + cba_frame_info(tvb, pinfo, tree, frame); + } + + offset = dissect_dcom_BYTE(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_BYTE(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_serversrt_last_connect, &u8LastConnect); + + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* link connections infos to the call */ + if (frame != NULL) { + call = (server_connect_call_t *)wmem_alloc(wmem_file_scope(), sizeof(server_connect_call_t) + u32ArraySize * sizeof(cba_connection_t *)); + call->conn_count = 0; + call->frame = frame; + call->conns = (cba_connection_t **) (call+1); + di->call_data->private_data = call; + } else{ + call = NULL; + } + + u32VariableOffset = offset + u32ArraySize*20; + + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + /* array of CONNECTINs */ + sub_item = proto_tree_add_item(tree, hf_cba_connectin, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectin); + u32SubStart = offset; + + /* ProviderItem */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szProvItem, u32MaxProvItemLen); + } + + /* TypeDescLen */ + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_type_desc_len, &u16TypeDescLen); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + /* pTypeDesc */ + if (u32Pointer) { + u32VariableOffset = dissect_dcom_dcerpc_array_size(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + &u32ArraySize2); + + typedesc = (guint16 *)wmem_alloc0(wmem_file_scope(), u32ArraySize2 * 2); + typedesclen = u32ArraySize2; + + /* extended type description will build an array here */ + u32Idx2 = 1; + while (u32ArraySize2--) { + /* ToBeDone: some of the type description values are counts */ + u32VariableOffset = dissect_dcom_VARTYPE(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + &u16VarType); + + if (u32Idx2 <= typedesclen) { + typedesc[u32Idx2-1] = u16VarType; + } + + /* remember first VarType only */ + if (u32Idx2 == 1) { + u16VarType2 = u16VarType; + } + u32Idx2++; + } + } + + /* ConsumerID */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID); + + /* RecordLength */ + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_serversrt_record_length, &u16RecordLength); + + /* add to object database */ + if (frame != NULL) { + conn = cba_connection_connect(pinfo, frame->consparent, frame->provparent, frame, + frame->qostype, frame->qosvalue, szProvItem, u32ConsID, u16RecordLength, + typedesc, typedesclen); + + cba_connection_info(tvb, pinfo, sub_tree, conn); + } else { + conn = NULL; + } + + /* add to current call */ + if (call != NULL) { + call->conn_count++; + call->conns[u32Idx-1] = conn; + } + + /* update subtree header */ + proto_item_append_text(sub_item, "[%u]: ConsID=0x%x, ProvItem=\"%s\", TypeDesc=%s", + u32Idx, u32ConsID, szProvItem, + val_to_str(u16VarType2, dcom_variant_type_vals, "Unknown (0x%04x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": %s Cnt=%u PCRID=0x%x", + (u8LastConnect) ? "LastOfCR" : "", + u32Idx-1, + u32ProvCRID); + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoServerSRT_Connect_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + guint32 u32ArraySize; + guint32 u32Idx = 1; + guint32 u32SubStart; + guint32 u32ProvID; + guint32 u32HResult; + + proto_item *item; + + server_connect_call_t *call = (server_connect_call_t *)di->call_data->private_data; + cba_connection_t *conn; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + if (call == NULL) { + expert_add_info(pinfo, NULL, &ei_cba_acco_no_request_info); + } + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (call && call->frame != NULL) { + cba_frame_info(tvb, pinfo, tree, call->frame); + } + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /* array of CONNECTOUTs */ + while(u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_connectout, tvb, offset, 8, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_connectout); + u32SubStart = offset; + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID); + + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + /* put response data into the frame */ + if (call && u32Idx <= call->conn_count) { + conn = call->conns[u32Idx-1]; + conn->provid = u32ProvID; + conn->connret = u32HResult; + + cba_connection_info(tvb, pinfo, sub_tree, conn); + } + + proto_item_append_text(sub_item, "[%u]: ProvID=0x%x %s", + u32Idx, u32ProvID, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + /* this might be a global HRESULT */ + while(call && u32Idx <= call->conn_count) { + conn = call->conns[u32Idx-1]; + conn->provid = 0; + conn->connret = u32HResult; + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32Idx-1, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_Server_GetProvIDs_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32Pointer; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvID; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + if (u32Count) { + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u ProvID=", u32Count); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, + tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID, u32Idx); + + if (u32Idx == 1) { + col_append_fstr(pinfo->cinfo, COL_INFO, "0x%x", u32ProvID); + } else if (u32Idx < 10) { + col_append_fstr(pinfo->cinfo, COL_INFO, ",0x%x", u32ProvID); + } else if (u32Idx == 10) { + col_append_str(pinfo->cinfo, COL_INFO, ",..."); + } + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_Server_GetProvConnections_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ProvID; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_prov_id, &u32ProvID, u32Idx); + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return offset; +} + + +static int +dissect_Server_GetProvConnections_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32TmpCount; + guint32 u32Pointer; + guint32 u32VariableOffset; + guint32 u32Idx; + guint32 u32SubStart; + gchar szCons[1000] = { 0 }; + guint32 u32MaxConsLen = sizeof(szCons); + gchar szProvItem[1000] = { 0 }; + guint32 u32MaxProvItemLen = sizeof(szProvItem); + guint32 u32ConsID; + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8State; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + u32VariableOffset = offset; + + if (u32Pointer) { + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + u32VariableOffset = offset + u32Count*28; + + /* array fixed part (including pointers to variable part) */ + u32TmpCount = u32Count; + u32Idx = 1; + while (u32TmpCount--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_getprovconnout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_getprovconnout); + u32SubStart = offset; + + /* wszConsumer */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_consumer, szCons, u32MaxConsLen); + } + /* wszProviderItem */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szProvItem, u32MaxProvItemLen); + } + /* dwConsID */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID); + + /* Epsilon */ + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_epsilon); + } + + /* QoS Type */ + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + /* QoS Value */ + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + /* State */ + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_state, &u8State); + /* PartialResult */ + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: %s", + u32Idx, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + u32VariableOffset = dissect_dcom_HRESULT(tvb, u32VariableOffset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return u32VariableOffset; +} + + +#define CBA_MRSH_VERSION_DCOM 0x01 +#define CBA_MRSH_VERSION_SRT_WITH_CONSID 0x10 +#define CBA_MRSH_VERSION_SRT_WITHOUT_CONSID 0x11 + + +static int +dissect_CBA_Connection_Data(tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree, cba_ldev_t *cons_ldev, cba_frame_t *frame) +{ + guint8 u8Version; + guint8 u8Flags; + guint16 u16CountFix; + guint16 u16Count; + guint32 u32ItemIdx; + guint32 u32HoleIdx; + proto_item *conn_data_item = NULL; + proto_tree *conn_data_tree = NULL; + guint16 u16Len; + guint32 u32ID; + guint8 u8QC; + guint16 u16DataLen; + guint16 u16HdrLen; + int offset = 0; + int offset_hole; + gboolean qc_reported = FALSE; + int qc_good = 0; + int qc_uncertain = 0; + int qc_bad = 0; + GList *conns; + int item_offset; + cba_connection_t *conn; + + + /*** ALL data in this buffer is NOT aligned and always little endian ordered ***/ + + if (tree) { + conn_data_item = proto_tree_add_item(tree, hf_cba_acco_cb_conn_data, tvb, offset, 0, ENC_NA); + conn_data_tree = proto_item_add_subtree(conn_data_item, ett_ICBAAccoCallback_Buffer); + } + + /* add buffer header */ + u8Version = tvb_get_guint8 (tvb, offset); + if (conn_data_tree) { + proto_tree_add_item(conn_data_tree, hf_cba_acco_cb_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + offset += 1; + + u8Flags = tvb_get_guint8 (tvb, offset); + if (conn_data_tree) { + proto_tree_add_item(conn_data_tree, hf_cba_acco_cb_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + offset += 1; + + u16Count = tvb_get_letohs (tvb, offset); + if (conn_data_tree) { + proto_tree_add_item(conn_data_tree, hf_cba_acco_cb_count, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + offset += 2; + u16CountFix = u16Count; + + /* show meta information */ + if (frame) { + cba_frame_info(tvb, pinfo, conn_data_tree, frame); + } else { + if (cons_ldev && cons_ldev->name) { + proto_item *item; + item = proto_tree_add_string(conn_data_tree, hf_cba_acco_conn_consumer, tvb, offset, 0, cons_ldev->name); + PROTO_ITEM_SET_GENERATED(item); + } + } + + /* update column info now */ +#if 0 + col_append_fstr(pinfo->cinfo, COL_INFO, " Cnt=%u", u16Count); +#endif + + /* is this an OnDataChanged buffer format (version), we know? */ + if ((u8Version != CBA_MRSH_VERSION_DCOM) && + (u8Version != CBA_MRSH_VERSION_SRT_WITH_CONSID) && + (u8Version != CBA_MRSH_VERSION_SRT_WITHOUT_CONSID)) + { + return offset; + } + + /* Timestamps are currently unused -> flags must be zero */ + if (u8Flags != 0) { + return offset; + } + + u32ItemIdx = 1; + u32HoleIdx = 1; + while (u16Count--) { + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *item; + + /* find next record header */ + u16Len = tvb_get_letohs (tvb, offset); + + /* trapped inside an empty hole? -> try to find next record header */ + if (u16Len == 0 && + (u8Version == CBA_MRSH_VERSION_SRT_WITH_CONSID || + u8Version == CBA_MRSH_VERSION_SRT_WITHOUT_CONSID)) + { + u32HoleIdx++; + offset_hole = offset; + /* length smaller or larger than possible -> must be a hole */ + while (u16Len == 0) { + offset++; + u16Len = tvb_get_letohs(tvb, offset); + /* this is a bit tricky here! we know: */ + /* u16Len must be greater than 3 (min. size of header itself) */ + /* u16Len must be a lot smaller than 0x300 (max. size of frame) */ + /* -> if we found a length larger than 0x300, */ + /* this must be actually the high byte, so do one more step */ + if (u16Len > 0x300) { + u16Len = 0; + } + } + proto_tree_add_none_format(conn_data_tree, hf_cba_acco_cb_item_hole, tvb, + offset_hole, offset - offset_hole, + "Hole(--): -------------, offset=%2u, length=%2u", + offset_hole, offset - offset_hole); + } + + /* add callback-item subtree */ + sub_item = proto_tree_add_item(conn_data_tree, hf_cba_acco_cb_item, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_ICBAAccoCallback_Item); + + item_offset = offset; + + /* add item header fields */ + if (sub_tree) { + proto_tree_add_item(sub_tree, hf_cba_acco_cb_item_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + offset += 2; + u16HdrLen = 2; + + if (u8Version == CBA_MRSH_VERSION_DCOM || + u8Version == CBA_MRSH_VERSION_SRT_WITH_CONSID) + { + u32ID = tvb_get_letohl (tvb, offset); + if (sub_tree) { + proto_tree_add_item(sub_tree, hf_cba_acco_conn_cons_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); + } + offset += 4; + u16HdrLen += 4; + } else { + u32ID = 0; + } + + u8QC = tvb_get_guint8 (tvb, offset); + item = NULL; + if (sub_tree) { + item = proto_tree_add_item(sub_tree, hf_cba_acco_qc, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + offset += 1; + u16HdrLen += 1; + + if ( u8QC != 0x80 && /* GoodNonCascOk */ + u8QC != 0x1C && /* BadOutOfService (usually permanent, so don't report for every frame) */ + qc_reported == 0) { + expert_add_info_format(pinfo, item, &ei_cba_acco_qc, "%s QC: %s", + u8Version == CBA_MRSH_VERSION_DCOM ? "DCOM" : "SRT", + val_to_str(u8QC, cba_acco_qc_vals, "Unknown (0x%02x)")); + qc_reported = 0; + } + + switch(u8QC >> 6) { + case(00): + qc_bad++; + break; + case(01): + qc_uncertain++; + break; + default: + qc_good++; + } + + /* user data length is item length without headers */ + u16DataLen = u16Len - u16HdrLen; + + /* append text to subtree header */ + if (u8Version == CBA_MRSH_VERSION_DCOM || + u8Version == CBA_MRSH_VERSION_SRT_WITH_CONSID) + { + proto_item_append_text(sub_item, + "[%2u]: ConsID=0x%08x, offset=%2u, length=%2u (user-length=%2u), QC=%s (0x%02x)", + u32ItemIdx, u32ID, offset - u16HdrLen, u16Len, u16DataLen, + val_to_str(u8QC, cba_acco_qc_vals, "Unknown (0x%02x)"), u8QC ); + } else { + proto_item_append_text(sub_item, + "[%2u]: ConsID=-, offset=%2u, length=%2u (user-length=%2u), QC=%s (0x%02x)", + u32ItemIdx, offset - u16HdrLen, u16Len, u16DataLen, + val_to_str(u8QC, cba_acco_qc_vals, "Unknown (0x%02x)"), u8QC ); + } + proto_item_set_len(sub_item, u16Len); + + /* hexdump of user data */ + proto_tree_add_item(sub_tree, hf_cba_acco_cb_item_data, tvb, offset, u16DataLen, ENC_NA); + offset += u16DataLen; + + if (frame != NULL ) { + /* find offset in SRT */ + /* XXX - expensive! */ + cba_frame_incoming_data(tvb, pinfo, sub_tree, frame); + for(conns = frame->conns; conns != NULL; conns = g_list_next(conns)) { + conn = (cba_connection_t *)conns->data; + if (conn->frame_offset == item_offset) { + cba_connection_info(tvb, pinfo, sub_tree, conn); + break; + } + } + } else { + /* find consID in ldev */ + /* XXX - expensive! */ + if (cons_ldev != NULL) { + for(conns = cons_ldev->consconns; conns != NULL; conns = g_list_next(conns)) { + conn = (cba_connection_t *)conns->data; + if (conn->consid == u32ID) { + cba_connection_info(tvb, pinfo, sub_tree, conn); + cba_connection_incoming_data(tvb, pinfo, sub_tree, conn); + break; + } + } + } + } + + u32ItemIdx++; + } + + if (u8Version == 1) { + proto_item_append_text(conn_data_item, + ": Version=0x%x (DCOM), Flags=0x%x, Count=%u", + u8Version, u8Flags, u16CountFix); + } else { + proto_item_append_text(conn_data_item, + ": Version=0x%x (SRT), Flags=0x%x, Count=%u, Items=%u, Holes=%u", + u8Version, u8Flags, u16CountFix, u32ItemIdx-1, u32HoleIdx-1); + } + proto_item_set_len(conn_data_item, offset); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", QC (G:%u,U:%u,B:%u)", + qc_good, qc_uncertain, qc_bad); + + return offset; +} + + +static gboolean +dissect_CBA_Connection_Data_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + void *data) +{ + guint8 u8Version; + guint8 u8Flags; + /* the tvb will NOT contain the frame_id here! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + cba_frame_t *frame; + + /* frame id must be in valid range (cyclic Real-Time, class=1 or class=2) */ + if (u16FrameID < 0x8000 || u16FrameID >= 0xfb00) { + return FALSE; + } + + u8Version = tvb_get_guint8 (tvb, 0); + u8Flags = tvb_get_guint8 (tvb, 1); + + /* version and flags must be ok */ + if (u8Version != 0x11 || u8Flags != 0x00) { + return FALSE; + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-CBA"); + + frame = cba_frame_find_by_cons(pinfo, (const guint8 *)pinfo->dl_dst.data, u16FrameID); + + dissect_CBA_Connection_Data(tvb, pinfo, tree, frame ? frame->consparent : NULL, frame); + + return TRUE; +} + + +static int +dissect_ICBAAccoCallback_OnDataChanged_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Length; + guint32 u32ArraySize; + tvbuff_t *next_tvb; + proto_item *item; + cba_ldev_t *cons_ldev; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + /* get corresponding provider ldev */ + cons_ldev = cba_ldev_find(pinfo, &pinfo->net_dst, &di->call_data->object_uuid); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + /* length */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_cb_length, &u32Length); + + /* array size */ + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /*** the data below is NOT ndr encoded (especially NOT aligned)!!! ***/ + /* dissect PROFINET component data (without header) */ + next_tvb = tvb_new_subset_remaining(tvb, offset); + + offset += dissect_CBA_Connection_Data(next_tvb, pinfo, tree, cons_ldev, NULL /* frame */); + + return offset; +} + + +static int +dissect_ICBAAccoCallback_OnDataChanged_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + proto_item *item; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoCallback_Gnip_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + proto_item *item; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(3)); + + return offset; +} + + +static int +dissect_ICBAAccoCallback_Gnip_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + proto_item *item; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_srt_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(4)); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoServer2_GetConnectionData_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + proto_item *item; + cba_ldev_t *cons_ldev; + cba_ldev_t **call; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, TRUE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(2)); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_consumer, szStr, u32MaxStr); + + cons_ldev = cba_acco_add(pinfo, szStr); + + /* link ldev to the call */ + if (cons_ldev != NULL) { + call = (cba_ldev_t **)wmem_alloc(wmem_file_scope(), sizeof(cba_ldev_t *)); + *call = cons_ldev; + di->call_data->private_data = call; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, " Consumer=\"%s\"", szStr); + + return offset; +} + + +static int +dissect_ICBAAccoServer2_GetConnectionData_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Length; + guint32 u32ArraySize; + tvbuff_t *next_tvb; + guint32 u32Pointer; + guint32 u32HResult; + proto_item *item; + cba_ldev_t **call = (cba_ldev_t **)di->call_data->private_data; + cba_ldev_t *cons_ldev = (call!=NULL) ? *call : NULL; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + if (cons_ldev == NULL) { + expert_add_info(pinfo, NULL, &ei_cba_acco_no_request_info); + } + + item = proto_tree_add_boolean (tree, hf_cba_acco_dcom_call, tvb, offset, 0, FALSE); + PROTO_ITEM_SET_GENERATED(item); + p_add_proto_data(pinfo->pool, pinfo, proto_ICBAAccoMgt, 0, GUINT_TO_POINTER(1)); + + /* length */ + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_cb_length, &u32Length); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + /* array size */ + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + /*** the data below is NOT ndr encoded (especially NOT aligned)!!! ***/ + /* dissect PROFINET component data (without header) */ + next_tvb = tvb_new_subset_remaining(tvb, offset); + + offset += dissect_CBA_Connection_Data(next_tvb, pinfo, tree, (call != NULL) ? *call : NULL, NULL /* frame */); + + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_AddConnections_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szConsumer[1000] = { 0 }; + guint32 u32MaxConsLen = sizeof(szConsumer); + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8State; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Pointer; + guint16 u16Persistence; + gchar szConsItem[1000] = { 0 }; + guint32 u32MaxConsItemLen = sizeof(szConsItem); + gchar szProvItem[1000] = { 0 }; + guint32 u32MaxProvItemLen = sizeof(szProvItem); + guint32 u32VariableOffset; + guint32 u32SubStart; + guint32 u32Idx; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_provider, szConsumer, u32MaxConsLen); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32VariableOffset = offset + u32ArraySize * 20; + + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_addconnectionin, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_addconnectionin); + u32SubStart = offset; + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szProvItem, u32MaxProvItemLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_consumer_item, szConsItem, u32MaxConsItemLen); + } + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_persist, &u16Persistence); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_substitute); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_epsilon); + } + proto_item_append_text(sub_item, "[%u]: ConsItem=\"%s\" ProvItem=\"%s\" %s Pers=%u", + u32Idx, szConsItem, szProvItem, + val_to_str(u16Persistence, cba_persist_vals, "Unknown (0x%02x)"), u16Persistence); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Prov=\"%s\" State=%s Cnt=%u", + szConsumer, + val_to_str(u8State, cba_acco_conn_state_vals, "Unknown (0x%02x)"), + u32Count); + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoMgt_AddConnections_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + guint32 u32ArraySize = 0; + guint32 u32ConsID; + guint16 u16ConnVersion; + guint32 u32HResult = 0; + guint32 u32Count = 0; + guint32 u32Idx; + guint32 u32SubStart; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Count = u32ArraySize; + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_addconnectionout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_addconnectionout); + u32SubStart = offset; + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_version, &u16ConnVersion); + + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: ConsID=0x%x Version=%u %s", + u32Idx, u32ConsID, u16ConnVersion, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_RemoveConnections_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ConsID; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID, u32Idx); + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_SetActivationState_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint8 u8State; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ConsID; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_state, &u8State); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID, u32Idx); + u32Idx++; + } + + /* update column info now */ + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_GetInfo_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Max; + guint32 u32CurCnt; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_info_max, &u32Max); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_info_curr, &u32CurCnt); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %u/%u -> %s", + u32CurCnt, u32Max, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_GetIDs_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32Pointer; + guint32 u32ArraySize; + guint32 u32ConsID; + guint8 u8State; + guint16 u16Version; + guint32 u32HResult; + guint32 u32Idx; + guint32 u32SubStart; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + if (u32Count) { + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u ConsID=", u32Count); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_getidout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_getidout); + u32SubStart = offset; + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID); + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_state, &u8State); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_version, &u16Version); + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: ConsID=0x%x State=%s Version=%u %s", + u32Idx, u32ConsID, + val_to_str(u8State, cba_acco_conn_state_vals, "Unknown (0x%02x)"), + u16Version, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + if (u32Idx == 1) { + col_append_fstr(pinfo->cinfo, COL_INFO, "0x%x", u32ConsID); + } else if (u32Idx < 10) { + col_append_fstr(pinfo->cinfo, COL_INFO, ",0x%x", u32ConsID); + } else if (u32Idx == 10) { + col_append_str(pinfo->cinfo, COL_INFO, ",..."); + } + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt2_GetConsIDs_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32Pointer; + guint32 u32ArraySize; + guint32 u32Idx; + guint32 u32ConsID; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + if (u32Count) { + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u ConsID=", u32Count); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, + tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID, u32Idx); + + if (u32Idx == 1) { + col_append_fstr(pinfo->cinfo, COL_INFO, "0x%x", u32ConsID); + } else if (u32Idx < 10) { + col_append_fstr(pinfo->cinfo, COL_INFO, ",0x%x", u32ConsID); + } else if (u32Idx == 10) { + col_append_str(pinfo->cinfo, COL_INFO, ",..."); + } + + u32Idx++; + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt2_GetConsConnections_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32TmpCount; + guint32 u32Pointer; + guint32 u32HResult; + + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8State; + guint16 u16Persistence; + guint32 u32SubStart; + guint32 u32Idx; + guint32 u32VariableOffset; + gchar szProv[1000] = { 0 }; + guint32 u32MaxProvLen = sizeof(szProv); + gchar szProvItem[1000] = { 0 }; + guint32 u32MaxProvItemLen = sizeof(szProvItem); + gchar szConsItem[1000] = { 0 }; + guint32 u32MaxConsItemLen = sizeof(szConsItem); + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + u32VariableOffset = offset; + + if (u32Pointer) { + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + u32VariableOffset = offset + u32Count*32; + + /* array fixed part (including pointers to variable part) */ + u32TmpCount = u32Count; + u32Idx = 1; + while (u32TmpCount--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_getconsconnout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_getconnectionout); + u32SubStart = offset; + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider, szProv, u32MaxProvLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szProvItem, u32MaxProvItemLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_consumer_item, szConsItem, u32MaxConsItemLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_substitute); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_epsilon); + } + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_state, &u8State); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_persist, &u16Persistence); + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: %s", + u32Idx, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + u32VariableOffset = dissect_dcom_HRESULT(tvb, u32VariableOffset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoMgt2_DiagConsConnections_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32TmpCount; + guint32 u32Pointer; + guint32 u32HResult; + guint8 u8State; + guint16 u16Persistence; + guint16 u16ConnVersion; + guint32 u32SubStart; + guint32 u32Idx; + guint32 u32VariableOffset; + guint32 u32ConnErrorState; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + u32VariableOffset = offset; + + if (u32Pointer) { + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + u32VariableOffset = offset + u32Count*16; + + /* array fixed part (including pointers to variable part) */ + u32TmpCount = u32Count; + u32Idx = 1; + while (u32TmpCount--) { + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *state_item; + + sub_item = proto_tree_add_item(tree, hf_cba_diagconsconnout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_getconnectionout); + u32SubStart = offset; + + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_state, &u8State); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_persist, &u16Persistence); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_version, &u16ConnVersion); + /* connection state */ +#if 0 + offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_error_state, &u32ConnErrorState); +#endif + offset = dissect_dcom_HRESULT_item(tvb, offset, pinfo, sub_tree, di, drep, + &u32ConnErrorState, hf_cba_acco_conn_error_state, &state_item); + proto_item_set_text(state_item, "ConnErrorState: %s (0x%x)", + val_to_str(u32ConnErrorState, dcom_hresult_vals, "Unknown (0x%08x)"), + u32ConnErrorState); + + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: %s", + u32Idx, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + u32VariableOffset = dissect_dcom_HRESULT(tvb, u32VariableOffset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoMgt_GetConnections_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32ConsID; + guint32 u32Count; + guint32 u32ArraySize; + guint32 u32Idx; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32Idx = 1; + while (u32ArraySize--){ + offset = dissect_dcom_indexed_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_cons_id, &u32ConsID, u32Idx); + u32Idx++; + } + + return offset; +} + + +static int +dissect_ICBAAccoMgt_GetConnections_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32TmpCount; + guint32 u32Pointer; + guint32 u32HResult; + + guint16 u16QoSType; + guint16 u16QoSValue; + guint8 u8State; + guint16 u16Persistence; + guint16 u16ConnVersion; + guint32 u32SubStart; + guint32 u32Idx; + guint32 u32VariableOffset; + gchar szProv[1000] = { 0 }; + guint32 u32MaxProvLen = sizeof(szProv); + gchar szProvItem[1000] = { 0 }; + guint32 u32MaxProvItemLen = sizeof(szProvItem); + gchar szConsItem[1000] = { 0 }; + guint32 u32MaxConsItemLen = sizeof(szConsItem); + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + u32VariableOffset = offset; + + if (u32Pointer) { + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + u32VariableOffset = offset + u32Count*36; + + /* array fixed part (including pointers to variable part) */ + u32TmpCount = u32Count; + u32Idx = 1; + while (u32TmpCount--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_getconnectionout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_getconnectionout); + u32SubStart = offset; + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider, szProv, u32MaxProvLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_provider_item, szProvItem, u32MaxProvItemLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_consumer_item, szConsItem, u32MaxConsItemLen); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_substitute); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_epsilon); + } + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + offset = dissect_dcom_BOOLEAN(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_state, &u8State); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_persist, &u16Persistence); + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_conn_version, &u16ConnVersion); + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: %s", + u32Idx, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + u32VariableOffset = dissect_dcom_HRESULT(tvb, u32VariableOffset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoMgt_ReviseQoS_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16QoSType; + guint16 u16QoSValue; + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_LPWSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_rtauto, szStr, u32MaxStr); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_type, &u16QoSType); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": RTAuto=\"%s\" QoSType=%s QoSValue=%u", + szStr, + val_to_str(u16QoSType, cba_qos_type_vals, "Unknown (0x%04x)"), + u16QoSValue); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_ReviseQoS_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16QoSValue; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_conn_qos_value, &u16QoSValue); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %u -> %s", + u16QoSValue, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_get_PingFactor_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16PF; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_ping_factor, &u16PF); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %u -> %s", + u16PF, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_put_PingFactor_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16PF; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_ping_factor, &u16PF); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %u", u16PF); + + return offset; +} + + + +static int +dissect_ICBAAccoMgt_get_CDBCookie_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Cookie; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_cdb_cookie, &u32Cookie); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": CDBCookie=0x%x -> %s", + u32Cookie, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_GetDiagnosis_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Request; + guint32 u32InLength; + guint32 u32ArraySize; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_diag_req, &u32Request); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_diag_in_length, &u32InLength); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + if (u32ArraySize != 0) { + proto_tree_add_item(tree, hf_cba_acco_diag_data, tvb, offset, u32InLength, ENC_NA); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %s: %u bytes", + val_to_str(u32Request, cba_acco_diag_req_vals, "Unknown request (0x%08x)"), + u32InLength); + + return offset; +} + + +static int +dissect_ICBAAccoMgt_GetDiagnosis_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32OutLength; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_diag_out_length, &u32OutLength); + + if (u32OutLength != 0) { + proto_tree_add_item(tree, hf_cba_acco_diag_data, tvb, offset, u32OutLength, ENC_NA); + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %u bytes", + u32OutLength); + + return offset; +} + + +static int +dissect_ICBAAccoSync_ReadItems_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + guint32 u32Pointer; + guint32 u32ArraySize; + guint32 u32VariableOffset; + guint32 u32Idx; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32VariableOffset = offset + u32ArraySize*4; + + u32Idx = 1; + while (u32ArraySize--) { + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_indexed_LPWSTR(tvb, u32VariableOffset, pinfo, tree, di, drep, + hf_cba_acco_item, szStr, u32MaxStr, u32Idx); + } + + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return u32VariableOffset; +} + + + + +static int +dissect_ICBAAccoSync_ReadItems_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + guint16 u16QC; + guint32 u32ArraySize = 0; + guint32 u32HResult; + guint32 u32Idx; + guint32 u32SubStart; + guint32 u32VariableOffset; + guint32 u32Tmp; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + u32VariableOffset = offset; + + if (u32Pointer) { + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32VariableOffset = offset + u32ArraySize * 20; + u32Idx = 1; + u32Tmp = u32ArraySize; + while(u32Tmp--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_readitemout, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_readitemout); + u32SubStart = offset; + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, hf_cba_acco_data); + } + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_qc, &u16QC); + offset = dissect_dcom_FILETIME(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_time_stamp, NULL); + + offset = dissect_dcom_indexed_HRESULT(tvb, offset, pinfo, sub_tree, di, drep, + &u32HResult, u32Idx); + + proto_item_append_text(sub_item, "[%u]: QC=%s (0x%02x) %s", + u32Idx, + val_to_str(u16QC, cba_acco_qc_vals, "Unknown"), + u16QC, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + } + + u32VariableOffset = dissect_dcom_HRESULT(tvb, u32VariableOffset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u -> %s", + u32ArraySize, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return u32VariableOffset; +} + + +static int +dissect_ICBAAccoSync_WriteItems_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + guint32 u32Pointer; + guint32 u32VariableOffset; + guint32 u32SubStart; + guint32 u32Idx; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32VariableOffset = offset + u32ArraySize * 8; + u32Idx = 1; + while(u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_writeitemin, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_writeitemin); + u32SubStart = offset; + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_item, szStr, u32MaxStr); + } + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_data); + } + + proto_item_append_text(sub_item, "[%u]: Item=\"%s\"", u32Idx, szStr); + proto_item_set_len(sub_item, offset - u32SubStart); + + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return u32VariableOffset; +} + + + +static int +dissect_ICBAAccoSync_WriteItemsQCD_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32ArraySize; + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + guint32 u32Pointer; + guint32 u32VariableOffset; + guint32 u32SubStart; + guint32 u32Idx; + guint16 u16QC; + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_acco_count, &u32Count); + + offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, di, drep, + &u32ArraySize); + + u32VariableOffset = offset + u32ArraySize * 20; + u32Idx = 1; + while(u32ArraySize--) { + proto_item *sub_item; + proto_tree *sub_tree; + + sub_item = proto_tree_add_item(tree, hf_cba_writeitemin, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_cba_writeitemin); + u32SubStart = offset; + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_LPWSTR(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_item, szStr, u32MaxStr); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, di, drep, + &u32Pointer); + if (u32Pointer) { + u32VariableOffset = dissect_dcom_VARIANT(tvb, u32VariableOffset, pinfo, sub_tree, di, drep, + hf_cba_acco_data); + } + + offset = dissect_dcom_WORD(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_qc, &u16QC); + + offset = dissect_dcom_FILETIME(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_acco_time_stamp, NULL); + + proto_item_append_text(sub_item, "[%u]: Item=\"%s\" QC=%s (0x%02x)", + u32Idx, szStr, + val_to_str(u16QC, cba_acco_qc_vals, "Unknown"), u16QC); + + proto_item_set_len(sub_item, offset - u32SubStart); + u32Idx++; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cnt=%u", u32Count); + + return u32VariableOffset; +} + + +/* sub dissector table of ICBAAccoMgt / ICBAAccoMgt2 interface */ +static dcerpc_sub_dissector ICBAAccoMgt_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "AddConnections", dissect_ICBAAccoMgt_AddConnections_rqst, dissect_ICBAAccoMgt_AddConnections_resp }, + { 4, "RemoveConnections", dissect_ICBAAccoMgt_RemoveConnections_rqst, dissect_HResultArray_resp }, + { 5, "ClearConnections", dissect_dcom_simple_rqst, dissect_dcom_simple_resp }, + { 6, "SetActivationState", dissect_ICBAAccoMgt_SetActivationState_rqst, dissect_HResultArray_resp }, + { 7, "GetInfo", dissect_dcom_simple_rqst, dissect_ICBAAccoMgt_GetInfo_resp }, + { 8, "GetIDs", dissect_dcom_simple_rqst, dissect_ICBAAccoMgt_GetIDs_resp }, + { 9, "GetConnections", dissect_ICBAAccoMgt_GetConnections_rqst, dissect_ICBAAccoMgt_GetConnections_resp }, + {10, "ReviseQoS", dissect_ICBAAccoMgt_ReviseQoS_rqst, dissect_ICBAAccoMgt_ReviseQoS_resp }, + {11, "get_PingFactor", dissect_dcom_simple_rqst, dissect_ICBAAccoMgt_get_PingFactor_resp }, + {12, "put_PingFactor", dissect_ICBAAccoMgt_put_PingFactor_rqst, dissect_dcom_simple_resp }, + {13, "get_CDBCookie", dissect_dcom_simple_rqst, dissect_ICBAAccoMgt_get_CDBCookie_resp }, + /* stage 2 */ + {14, "GetConsIDs", dissect_dcom_simple_rqst, dissect_ICBAAccoMgt2_GetConsIDs_resp }, + {15, "GetConsConnections", dissect_ICBAAccoMgt_GetConnections_rqst, dissect_ICBAAccoMgt2_GetConsConnections_resp }, + {16, "DiagConsConnections", dissect_ICBAAccoMgt_GetConnections_rqst, dissect_ICBAAccoMgt2_DiagConsConnections_resp }, + {17, "GetProvIDs", dissect_dcom_simple_rqst, dissect_Server_GetProvIDs_resp }, + {18, "GetProvConnections", dissect_Server_GetProvConnections_rqst, dissect_Server_GetProvConnections_resp }, + {19, "GetDiagnosis", dissect_ICBAAccoMgt_GetDiagnosis_rqst, dissect_ICBAAccoMgt_GetDiagnosis_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAAccoCallback interface */ +static dcerpc_sub_dissector ICBAAccoCallback_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "OnDataChanged", dissect_ICBAAccoCallback_OnDataChanged_rqst, dissect_ICBAAccoCallback_OnDataChanged_resp }, + /* stage 2 */ + { 4, "Gnip", dissect_ICBAAccoCallback_Gnip_rqst, dissect_ICBAAccoCallback_Gnip_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAAccoServer interface */ +static dcerpc_sub_dissector ICBAAccoServer_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "Connect", dissect_ICBAAccoServer_Connect_rqst, dissect_ICBAAccoServer_Connect_resp }, + { 4, "Disconnect", dissect_ICBAAccoServer_Disconnect_rqst, dissect_ICBAAccoServer_Disconnect_resp }, + { 5, "DisconnectMe", dissect_ICBAAccoServer_DisconnectMe_rqst, dissect_ICBAAccoServer_DisconnectMe_resp }, + { 6, "SetActivation", dissect_ICBAAccoServer_SetActivation_rqst, dissect_ICBAAccoServer_SetActivation_resp }, + { 7, "Ping", dissect_ICBAAccoServer_Ping_rqst, dissect_ICBAAccoServer_Ping_resp }, + /* stage 2 */ + { 8, "Connect2", dissect_ICBAAccoServer2_Connect2_rqst, dissect_ICBAAccoServer_Connect_resp }, + { 9, "GetConnectionData", dissect_ICBAAccoServer2_GetConnectionData_rqst, dissect_ICBAAccoServer2_GetConnectionData_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAAccoServerSRT interface (stage 2 only) */ +static dcerpc_sub_dissector ICBAAccoServerSRT_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "ConnectCR", dissect_ICBAAccoServerSRT_ConnectCR_rqst, dissect_ICBAAccoServerSRT_ConnectCR_resp }, + { 4, "DisconnectCR", dissect_ICBAAccoServerSRT_DisconnectCR_rqst, dissect_ICBAAccoServerSRT_DisconnectCR_resp }, + { 5, "Connect", dissect_ICBAAccoServerSRT_Connect_rqst, dissect_ICBAAccoServerSRT_Connect_resp }, + { 6, "Disconnect", dissect_ICBAAccoServerSRT_Disconnect_rqst, dissect_ICBAAccoServerSRT_Disconnect_resp }, + { 7, "DisconnectMe", dissect_ICBAAccoServerSRT_DisconnectMe_rqst, dissect_ICBAAccoServerSRT_DisconnectMe_resp }, + { 8, "SetActivation", dissect_ICBAAccoServerSRT_SetActivation_rqst, dissect_ICBAAccoServerSRT_SetActivation_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAAccoSync interface */ +static dcerpc_sub_dissector ICBAAccoSync_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "ReadItems", dissect_ICBAAccoSync_ReadItems_rqst, dissect_ICBAAccoSync_ReadItems_resp }, + { 4, "WriteItems", dissect_ICBAAccoSync_WriteItems_rqst, dissect_HResultArray_resp }, + { 5, "WriteItemsQCD", dissect_ICBAAccoSync_WriteItemsQCD_rqst, dissect_HResultArray_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* register protocol */ +void +proto_register_dcom_cba_acco (void) +{ + static gint *ett3[3]; + static gint *ett4[4]; + static gint *ett5[5]; + + + static hf_register_info hf_cba_acco_array[] = { + { &hf_cba_acco_opnum, + { "Operation", "cba.acco.opnum", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_ping_factor, + { "PingFactor", "cba.acco.ping_factor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_count, + { "Count", "cba.acco.count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_info_max, + { "Max", "cba.acco.info_max", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_info_curr, + { "Current", "cba.acco.info_curr", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_rtauto, + { "RTAuto", "cba.acco.rtauto", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_item, + { "Item", "cba.acco.item", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_data, + { "Data", "cba.acco.data", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_qc, + { "QualityCode", "cba.acco.qc", + FT_UINT8, BASE_HEX, VALS(cba_acco_qc_vals), 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_time_stamp, + { "TimeStamp", "cba.acco.time_stamp", + FT_UINT64, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_readitemout, + { "ReadItemOut", "cba.acco.readitemout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_writeitemin, + { "WriteItemIn", "cba.acco.writeitemin", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cdb_cookie, + { "CDBCookie", "cba.acco.cdb_cookie", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + /* dcom_hresult_vals from packet-dcom.h doesn't work here, as length is unknown! */ + { &hf_cba_acco_conn_error_state, + { "ConnErrorState", "cba.acco.conn_error_state", + FT_UINT32, BASE_HEX, NULL /*VALS(dcom_hresult_vals)*/, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_diag_req, + { "Request", "cba.acco.diag_req", + FT_UINT32, BASE_HEX, VALS(cba_acco_diag_req_vals), 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_diag_in_length, + { "InLength", "cba.acco.diag_in_length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_diag_out_length, + { "OutLength", "cba.acco.diag_out_length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_diag_data, + { "Data", "cba.acco.diag_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_dcom_call, + { "DcomRuntime", "cba.acco.dcom", + FT_BOOLEAN, BASE_NONE, TFS(&cba_acco_call_flags), 0x0, + "This is a DCOM runtime context", HFILL } + }, + { &hf_cba_acco_srt_call, + { "SrtRuntime", "cba.acco.srt", + FT_BOOLEAN, BASE_NONE, TFS(&cba_acco_call_flags), 0x0, + "This is an SRT runtime context", HFILL } + } + + }; + + static hf_register_info hf_cba_acco_server[] = { +#if 0 + { &hf_cba_acco_server_pICBAAccoCallback, + { "pICBAAccoCallback", "cba.acco.server_pICBAAccoCallback", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, +#endif + { &hf_cba_acco_server_first_connect, + { "FirstConnect", "cba.acco.server_first_connect", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_getprovconnout, + { "GETPROVCONNOUT", "cba.acco.getprovconnout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_prov_mac, + { "ProviderMAC", "cba.acco.serversrt_prov_mac", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_cons_mac, + { "ConsumerMAC", "cba.acco.serversrt_cons_mac", + FT_ETHER, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_cr_id, + { "ConsumerCRID", "cba.acco.serversrt_cr_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_cr_length, + { "CRLength", "cba.acco.serversrt_cr_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_cr_flags, + { "Flags", "cba.acco.serversrt_cr_flags", + FT_UINT32, BASE_HEX, 0, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_cr_flags_timestamped, + { "Timestamped", "cba.acco.serversrt_cr_flags_timestamped", + FT_BOOLEAN, 32, TFS (&acco_flags_set_truth), 0x1, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_cr_flags_reconfigure, + { "Reconfigure", "cba.acco.serversrt_cr_flags_reconfigure", + FT_BOOLEAN, 32, TFS (&acco_flags_set_truth), 0x2, + NULL, HFILL } + }, + { &hf_cba_type_desc_len, + { "TypeDescLen", "cba.acco.type_desc_len", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_serversrt_record_length, + { "RecordLength", "cba.acco.serversrt_record_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, +#if 0 + { &hf_cba_acco_serversrt_action, + { "Action", "cba.acco.serversrt_action", + FT_UINT32, BASE_DEC, VALS(cba_acco_serversrt_action_vals), 0x0, + NULL, HFILL } + }, +#endif + { &hf_cba_acco_serversrt_last_connect, + { "LastConnect", "cba.acco.serversrt_last_connect", + FT_UINT8, BASE_DEC, VALS(cba_acco_serversrt_last_connect_vals), 0x0, + NULL, HFILL } + }, + }; + + static hf_register_info hf_cba_connectcr_array[] = { + { &hf_cba_acco_prov_crid, + { "ProviderCRID", "cba.acco.prov_crid", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + }; + + static hf_register_info hf_cba_connect_array[] = { + { &hf_cba_addconnectionin, + { "ADDCONNECTIONIN", "cba.acco.addconnectionin", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_addconnectionout, + { "ADDCONNECTIONOUT", "cba.acco.addconnectionout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_getidout, + { "GETIDOUT", "cba.acco.getidout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_getconnectionout, + { "GETCONNECTIONOUT", "cba.acco.getconnectionout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_getconsconnout, + { "GETCONSCONNOUT", "cba.acco.getconsconnout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_diagconsconnout, + { "DIAGCONSCONNOUT", "cba.acco.diagconsconnout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_connectincr, + { "CONNECTINCR", "cba.acco.connectincr", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_connectoutcr, + { "CONNECTOUTCR", "cba.acco.connectoutcr", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_connectin, + { "CONNECTIN", "cba.acco.connectin", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_connectout, + { "CONNECTOUT", "cba.acco.connectout", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_prov_id, + { "ProviderID", "cba.acco.conn_prov_id", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_cons_id, + { "ConsumerID", "cba.acco.conn_cons_id", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_version, + { "ConnVersion", "cba.acco.conn_version", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_consumer, + { "Consumer", "cba.acco.conn_consumer", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_qos_type, + { "QoSType", "cba.acco.conn_qos_type", + FT_UINT16, BASE_HEX, VALS(cba_qos_type_vals), 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_qos_value, + { "QoSValue", "cba.acco.conn_qos_value", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_state, + { "State", "cba.acco.conn_state", + FT_UINT8, BASE_HEX, VALS(cba_acco_conn_state_vals), 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_provider, + { "Provider", "cba.acco.conn_provider", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_provider_item, + { "ProviderItem", "cba.acco.conn_provider_item", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_consumer_item, + { "ConsumerItem", "cba.acco.conn_consumer_item", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_persist, + { "Persistence", "cba.acco.conn_persist", + FT_UINT16, BASE_HEX, VALS(cba_persist_vals), 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_epsilon, + { "Epsilon", "cba.acco.conn_epsilon", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_conn_substitute, + { "Substitute", "cba.acco.conn_substitute", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + }; + + static hf_register_info hf_cba_acco_cb[] = { + { &hf_cba_acco_cb_length, + { "Length", "cba.acco.cb_length", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_version, + { "Version", "cba.acco.cb_version", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_flags, + { "Flags", "cba.acco.cb_flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_count, + { "Count", "cba.acco.cb_count", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_conn_data, + { "CBA Connection data", "cba.acco.cb_conn_data", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_item, + { "Item", "cba.acco.cb_item", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_item_hole, + { "Hole", "cba.acco.cb_item_hole", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_item_length, + { "Length", "cba.acco.cb_item_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_acco_cb_item_data, + { "Data(Hex)", "cba.acco.cb_item_data", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_cba_connect_in, + { "Connect in frame", "cba.connect_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "This connection Connect was in the packet with this number", HFILL } + }, + { &hf_cba_disconnect_in, + { "Disconnect in frame", "cba.disconnect_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "This connection Disconnect was in the packet with this number", HFILL } + }, + { &hf_cba_connectcr_in, + { "ConnectCR in frame", "cba.connect_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "This frame ConnectCR was in the packet with this number", HFILL } + }, + { &hf_cba_disconnectcr_in, + { "DisconnectCR in frame", "cba.disconnect_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "This frame DisconnectCR was in the packet with this number", HFILL } + }, + { &hf_cba_disconnectme_in, + { "DisconnectMe in frame", "cba.disconnectme_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "This connection/frame DisconnectMe was in the packet with this number", HFILL } + }, + { &hf_cba_data_first_in, + { "First data in frame", "cba.data_first_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "The first data of this connection/frame in the packet with this number", HFILL } + }, + { &hf_cba_data_last_in, + { "Last data in frame", "cba.data_last_in", + FT_FRAMENUM, BASE_NONE, NULL, 0, + "The last data of this connection/frame in the packet with this number", HFILL } + }, + }; + + static ei_register_info ei[] = { + { &ei_cba_acco_pdev_find, { "cba.acco.pdev_find.fail", PI_UNDECODED, PI_NOTE, "pdev_find: no pdev for IP", EXPFILL }}, + { &ei_cba_acco_pdev_find_unknown_interface, { "cba.acco.pdev_find.unknown_interface", PI_UNDECODED, PI_NOTE, "pdev_find: unknown interface", EXPFILL }}, + { &ei_cba_acco_ldev_unknown, { "cba.acco.ldev.unknown", PI_UNDECODED, PI_NOTE, "Unknown LDev", EXPFILL }}, + { &ei_cba_acco_ipid_unknown, { "cba.acco.ipid.unknown", PI_UNDECODED, PI_NOTE, "Unknown IPID", EXPFILL }}, + { &ei_cba_acco_prov_crid, { "cba.acco.prov_crid.unknown", PI_UNDECODED, PI_NOTE, "Unknown provider frame ProvCRID", EXPFILL }}, + { &ei_cba_acco_conn_consumer, { "cba.acco.conn_consumer.invalid", PI_UNDECODED, PI_NOTE, "Consumer interface invalid", EXPFILL }}, + { &ei_cba_acco_no_request_info, { "cba.acco.no_request_info", PI_UNDECODED, PI_NOTE, "No request info, response data ignored", EXPFILL }}, + { &ei_cba_acco_qc, { "cba.acco.qc.expert", PI_RESPONSE_CODE, PI_CHAT, "expert QC", EXPFILL }}, + { &ei_cba_acco_disconnect, { "cba.acco.disconnect", PI_SEQUENCE, PI_NOTE, "Disconnection sequence issue", EXPFILL }}, + { &ei_cba_acco_connect, { "cba.acco.connect_not_set", PI_SEQUENCE, PI_NOTE, "packet_connect not set", EXPFILL }}, + }; + + expert_module_t* expert_cba_acco; + + ett5[0] = &ett_ICBAAccoMgt; + ett5[1] = &ett_cba_addconnectionin; + ett5[2] = &ett_cba_addconnectionout; + ett5[3] = &ett_cba_getidout; + ett5[4] = &ett_cba_getconnectionout; + proto_ICBAAccoMgt = proto_register_protocol ("ICBAAccoMgt", "ICBAAccoMgt", "cba_acco_mgt"); + proto_register_field_array(proto_ICBAAccoMgt, hf_cba_acco_array, array_length(hf_cba_acco_array)); + proto_register_field_array(proto_ICBAAccoMgt, hf_cba_connect_array, array_length(hf_cba_connect_array)); + proto_register_field_array(proto_ICBAAccoMgt, hf_cba_connectcr_array, array_length(hf_cba_connectcr_array)); + proto_register_subtree_array (ett5, array_length (ett5)); + + /* XXX - just pick a protocol to register the expert info in */ + /* XXX - also, just pick a protocol to use proto_data for */ + expert_cba_acco = expert_register_protocol(proto_ICBAAccoMgt); + expert_register_field_array(expert_cba_acco, ei, array_length(ei)); + + proto_ICBAAccoMgt2 = proto_register_protocol ("ICBAAccoMgt2", "ICBAAccoMgt2", "cba_acco_mgt2"); + + ett3[0] = &ett_ICBAAccoCallback; + ett3[1] = &ett_ICBAAccoCallback_Item; + ett3[2] = &ett_ICBAAccoCallback_Buffer; + proto_ICBAAccoCallback = proto_register_protocol ("ICBAAccoCallback", "ICBAAccoCB", "cba_acco_cb"); + proto_register_field_array(proto_ICBAAccoCallback, hf_cba_acco_cb, array_length(hf_cba_acco_cb)); + proto_register_subtree_array (ett3, array_length (ett3)); + + proto_ICBAAccoCallback2 = proto_register_protocol ("ICBAAccoCallback2", "ICBAAccoCB2", "cba_acco_cb2"); + + ett4[0] = &ett_ICBAAccoServer; + ett4[1] = &ett_cba_connectin; + ett4[2] = &ett_cba_connectout; + ett4[3] = &ett_cba_getprovconnout; + proto_ICBAAccoServer = proto_register_protocol ("ICBAAccoServer", "ICBAAccoServ", "cba_acco_server"); + proto_register_field_array(proto_ICBAAccoServer, hf_cba_acco_server, array_length(hf_cba_acco_server)); + proto_register_subtree_array (ett4, array_length (ett4)); + + proto_ICBAAccoServer2 = proto_register_protocol ("ICBAAccoServer2", "ICBAAccoServ2", "cba_acco_server2"); + + ett4[0] = &ett_ICBAAccoServerSRT; + ett4[1] = &ett_cba_acco_serversrt_cr_flags; + ett4[2] = &ett_cba_connectincr; + ett4[3] = &ett_cba_connectoutcr; + proto_ICBAAccoServerSRT = proto_register_protocol ("ICBAAccoServerSRT", "ICBAAccoServSRT", "cba_acco_server_srt"); + proto_register_subtree_array (ett4, array_length (ett4)); + + ett5[0] = &ett_ICBAAccoSync; + ett5[1] = &ett_cba_readitemout; + ett5[2] = &ett_cba_writeitemin; + ett5[3] = &ett_cba_frame_info; + ett5[4] = &ett_cba_conn_info; + proto_ICBAAccoSync = proto_register_protocol ("ICBAAccoSync", "ICBAAccoSync", "cba_acco_sync"); + proto_register_subtree_array (ett5, array_length (ett5)); + + register_conversation_filter("cba", "PN-CBA", cba_filter_valid, cba_build_filter); +} + + +/* handoff protocol */ +void +proto_reg_handoff_dcom_cba_acco (void) +{ + /* Register the interfaces */ + dcerpc_init_uuid(proto_ICBAAccoMgt, ett_ICBAAccoMgt, + &uuid_ICBAAccoMgt, ver_ICBAAccoMgt, ICBAAccoMgt_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoMgt2, ett_ICBAAccoMgt, + &uuid_ICBAAccoMgt2, ver_ICBAAccoMgt2, ICBAAccoMgt_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoCallback, ett_ICBAAccoCallback, + &uuid_ICBAAccoCallback, ver_ICBAAccoCallback, ICBAAccoCallback_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoCallback2, ett_ICBAAccoCallback, + &uuid_ICBAAccoCallback2, ver_ICBAAccoCallback2, ICBAAccoCallback_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoServer, ett_ICBAAccoServer, + &uuid_ICBAAccoServer, ver_ICBAAccoServer, ICBAAccoServer_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoServer2, ett_ICBAAccoServer, + &uuid_ICBAAccoServer2, ver_ICBAAccoServer2, ICBAAccoServer_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoServerSRT, ett_ICBAAccoServerSRT, + &uuid_ICBAAccoServerSRT, ver_ICBAAccoServerSRT, ICBAAccoServerSRT_dissectors, hf_cba_acco_opnum); + + dcerpc_init_uuid(proto_ICBAAccoSync, ett_ICBAAccoSync, + &uuid_ICBAAccoSync, ver_ICBAAccoSync, ICBAAccoSync_dissectors, hf_cba_acco_opnum); + + + heur_dissector_add("pn_rt", dissect_CBA_Connection_Data_heur, "PROFINET CBA IO", "pn_cba_pn_rt", proto_ICBAAccoServer, HEURISTIC_ENABLE); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-dcom-cba-acco.h b/plugins/epan/profinet/packet-dcom-cba-acco.h new file mode 100644 index 0000000000..356d540377 --- /dev/null +++ b/plugins/epan/profinet/packet-dcom-cba-acco.h @@ -0,0 +1,71 @@ +/* packet-dcom-cba-acco.h + * Routines for DCOM CBA + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __PACKET_DCERPC_DCOM_CBA_ACCO_H +#define __PACKET_DCERPC_DCOM_CBA_ACCO_H + +typedef struct cba_pdev_s { + GList *ldevs; + dcom_object_t *object; + gint first_packet; + + const guint8 ip[4]; +} cba_pdev_t; + +typedef struct cba_ldev_s { + GList *provframes; + GList *consframes; + GList *provconns; + GList *consconns; + dcom_object_t *ldev_object; + dcom_object_t *acco_object; + cba_pdev_t *parent; + gint first_packet; + + const char *name; +} cba_ldev_t; + + +extern GList *cba_pdevs; + +extern cba_pdev_t * +cba_pdev_find(packet_info *pinfo, const address *addr, e_guid_t *ipid); + +extern void +cba_pdev_link(packet_info *pinfo, cba_pdev_t *pdev, dcom_interface_t *pdev_interf); + +extern cba_pdev_t * +cba_pdev_add(packet_info *pinfo, const address *addr); + +extern void +cba_ldev_link(packet_info *pinfo, cba_ldev_t *ldev, dcom_interface_t *ldev_interf); + +extern void +cba_ldev_link_acco(packet_info *pinfo, cba_ldev_t *ldev, dcom_interface_t *acco_interf); + +extern cba_ldev_t * +cba_ldev_find(packet_info *pinfo, const address *addr, e_guid_t *ipid); + +extern cba_ldev_t * +cba_ldev_add(packet_info *pinfo, cba_pdev_t *pdev, const char *name); + +#endif /* packet-dcerpc-dcom-cba-acco.h */ diff --git a/plugins/epan/profinet/packet-dcom-cba.c b/plugins/epan/profinet/packet-dcom-cba.c new file mode 100644 index 0000000000..244b102cb0 --- /dev/null +++ b/plugins/epan/profinet/packet-dcom-cba.c @@ -0,0 +1,1742 @@ +/* packet-dcom-cba.c + * Routines for DCOM CBA + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/expert.h> +#include <epan/dissectors/packet-dcerpc.h> +#include <epan/dissectors/packet-dcom.h> +#include <epan/dissectors/packet-dcom-dispatch.h> +#include "packet-dcom-cba-acco.h" + +void proto_register_dcom_cba(void); +void proto_reg_handoff_dcom_cba(void); + +static int hf_cba_opnum = -1; + +static int hf_cba_revision_major = -1; +static int hf_cba_revision_minor = -1; +static int hf_cba_revision_service_pack = -1; +static int hf_cba_revision_build = -1; + +static int hf_cba_time = -1; + +static int hf_cba_name = -1; +static int hf_cba_producer = -1; +static int hf_cba_product = -1; +static int hf_cba_production_date = -1; +static int hf_cba_serial_no = -1; +static int hf_cba_multi_app = -1; +static int hf_cba_profinet_dcom_stack = -1; +static int hf_cba_pdev_stamp = -1; + +static int hf_cba_browse_count = -1; +static int hf_cba_browse_offset = -1; +static int hf_cba_browse_max_return = -1; +static int hf_cba_browse_item = -1; +static int hf_cba_browse_data_type = -1; +static int hf_cba_browse_access_right = -1; +static int hf_cba_browse_selector = -1; +static int hf_cba_browse_info1 = -1; +static int hf_cba_browse_info2 = -1; + +static int hf_cba_cookie = -1; +static int hf_cba_state = -1; +static int hf_cba_new_state = -1; +static int hf_cba_old_state = -1; +static int hf_cba_grouperror = -1; +static int hf_cba_new_grouperror = -1; +static int hf_cba_old_grouperror = -1; + +static int hf_cba_component_id = -1; +static int hf_cba_component_version = -1; +static int hf_cba_pbaddress = -1; +static int hf_cba_pbaddress_system_id = -1; +static int hf_cba_pbaddress_address = -1; + +static int hf_cba_save_ldev_name = -1; +static int hf_cba_save_result = -1; + +static expert_field ei_cba_acco_interface_pointer_unresolved = EI_INIT; + +static e_guid_t uuid_coclass_CBAPhysicalDevice = { 0xcba00000, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; + + +/* CBA interfaces */ +static int proto_ICBAPhysicalDevice = -1; +static gint ett_ICBAPhysicalDevice = -1; +static e_guid_t uuid_ICBAPhysicalDevice = { 0xcba00001, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAPhysicalDevice = 0; + +static int proto_ICBAPhysicalDevice2 = -1; +static e_guid_t uuid_ICBAPhysicalDevice2 = { 0xcba00006, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAPhysicalDevice2 = 0; + +static int proto_ICBABrowse = -1; +static gint ett_ICBABrowse = -1; +static e_guid_t uuid_ICBABrowse = { 0xcba00002, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBABrowse = 0; + +static int proto_ICBABrowse2 = -1; +static e_guid_t uuid_ICBABrowse2 = { 0xcba00007, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBABrowse2 = 0; + +static int proto_ICBAPhysicalDevicePC = -1; +static gint ett_ICBAPhysicalDevicePC = -1; +static e_guid_t uuid_ICBAPhysicalDevicePC = { 0xcba00003, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAPhysicalDevicePC = 0; + +static int proto_ICBAPhysicalDevicePCEvent = -1; +static gint ett_ICBAPhysicalDevicePCEvent = -1; +static e_guid_t uuid_ICBAPhysicalDevicePCEvent = { 0xcba00004, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAPhysicalDevicePCEvent = 0; + +static int proto_ICBAPersist = -1; +static gint ett_ICBAPersist = -1; +static e_guid_t uuid_ICBAPersist = { 0xcba00005, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAPersist = 0; + +static int proto_ICBAPersist2 = -1; +static e_guid_t uuid_ICBAPersist2 = { 0xcba00008, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAPersist2 = 0; + +static int proto_ICBALogicalDevice = -1; +static gint ett_ICBALogicalDevice = -1; +static e_guid_t uuid_ICBALogicalDevice = { 0xcba00011, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBALogicalDevice = 0; + +static int proto_ICBALogicalDevice2 = -1; +static e_guid_t uuid_ICBALogicalDevice2 = { 0xcba00017, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBALogicalDevice2 = 0; + +static int proto_ICBAState = -1; +static gint ett_ICBAState = -1; +static e_guid_t uuid_ICBAState = { 0xcba00012, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAState = 0; + +static int proto_ICBAStateEvent = -1; +static gint ett_ICBAStateEvent = -1; +static e_guid_t uuid_ICBAStateEvent = { 0xcba00013, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAStateEvent = 0; + +static int proto_ICBATime = -1; +static gint ett_ICBATime = -1; +static e_guid_t uuid_ICBATime = { 0xcba00014, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBATime = 0; + +static int proto_ICBAGroupError = -1; +static gint ett_ICBAGroupError = -1; +static e_guid_t uuid_ICBAGroupError = { 0xcba00015, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAGroupError = 0; + +static int proto_ICBAGroupErrorEvent = -1; +static gint ett_ICBAGroupErrorEvent = -1; +static e_guid_t uuid_ICBAGroupErrorEvent = { 0xcba00016, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBAGroupErrorEvent = 0; + +static int proto_ICBARTAuto = -1; +static gint ett_ICBARTAuto = -1; +static e_guid_t uuid_ICBARTAuto = { 0xcba00051, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBARTAuto = 0; + +static int proto_ICBARTAuto2 = -1; +static e_guid_t uuid_ICBARTAuto2 = { 0xcba00052, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBARTAuto2 = 0; + +static int proto_ICBASystemProperties = -1; +static gint ett_ICBASystemProperties = -1; +static e_guid_t uuid_ICBASystemProperties = { 0xcba00062, 0x6c97, 0x11d1, { 0x82, 0x71, 0x00, 0xa0, 0x24, 0x42, 0xdf, 0x7d } }; +static guint16 ver_ICBASystemProperties = 0; + + +static gint ett_PBAddress = -1; + + +static const value_string cba_state_vals[] = { + { 0x00, "NonExistent" }, + { 0x01, "Initializing" }, + { 0x02, "Ready" }, + { 0x03, "Operating" }, + { 0x04, "Defect" }, + { 0, NULL } +}; + + +static const value_string cba_grouperror_vals[] = { + { 0x00, "NonAccessible" }, + { 0x01, "Okay" }, + { 0x02, "Problem" }, + { 0x03, "Unknown" }, + { 0x04, "MaintenanceRequired" }, + { 0x05, "MaintenanceDemanded" }, + { 0x06, "MaintenanceRequiredAndDemanded" }, + { 0x07, "ProblemAndMaintenanceRequired" }, + { 0x08, "ProblemAndMaintenanceDemanded" }, + { 0x09, "ProblemAndMaintenanceRequiredAndDemanded" }, + { 0, NULL } +}; + +static const value_string dcom_boolean_vals[] = { + { 0x00, "FALSE" }, + { 0x01, "TRUE" }, + { 0xffff, "TRUE" }, + { 0, NULL } +}; + + + + +static int +dissect_ICBABrowse_get_Count_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Count; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_count, &u32Count); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + if (u32HResult) { /* !S_OK */ + col_append_fstr(pinfo->cinfo, COL_INFO, "-> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, " Cnt=%u -> S_OK", u32Count); + } + + + return offset; +} + + +static int +dissect_ICBABrowse_BrowseItems_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Offset; + guint32 u32MaxReturn; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_offset, &u32Offset); + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_max_return, &u32MaxReturn); + + col_append_fstr(pinfo->cinfo, COL_INFO, " Offset=%u MaxReturn=%u", + u32Offset, u32MaxReturn); + + return offset; +} + + +static int +dissect_ICBABrowse_BrowseItems_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_browse_item); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_browse_data_type); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_browse_access_right); + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBABrowse2_get_Count2_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Selector; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_selector, &u32Selector); + + col_append_fstr(pinfo->cinfo, COL_INFO, " Selector=%u", + u32Selector); + + return offset; +} + + + +static int +dissect_ICBABrowse2_BrowseItems2_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Selector; + guint32 u32Offset; + guint32 u32MaxReturn; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_selector, &u32Selector); + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_offset, &u32Offset); + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_browse_max_return, &u32MaxReturn); + + col_append_fstr(pinfo->cinfo, COL_INFO, " Sel=%u Offset=%u MaxReturn=%u", + u32Selector, u32Offset, u32MaxReturn); + + return offset; +} + + +static int +dissect_ICBABrowse2_BrowseItems2_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_browse_item); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_browse_info1); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_browse_info2); + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAPersist2_Save2_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_save_ldev_name); + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, hf_cba_save_result); + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + + +static int +dissect_get_BSTR_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep, int hfindex) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + guint32 u32Pointer; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_BSTR(tvb, offset, pinfo, tree, di, drep, + hfindex, szStr, u32MaxStr); + } else { + szStr[0] = '\0'; + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": \"%s\" -> %s", szStr, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_get_ProductionDate_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + gdouble r8Date; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DATE(tvb, offset, pinfo, tree, di, drep, + hf_cba_production_date, &r8Date); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Date: %g -> %s", + r8Date, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_get_SerialNo_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + guint32 u32Pointer; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_VARIANT(tvb, offset, pinfo, tree, di, drep, + hf_cba_serial_no); + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBATime_get_Time_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + gdouble r8Date; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DATE(tvb, offset, pinfo, tree, di, drep, + hf_cba_time, &r8Date); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Time: %g -> %s", + r8Date, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBATime_put_Time_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gdouble r8Date; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DATE(tvb, offset, pinfo, tree, di, drep, + hf_cba_time, &r8Date); + + return offset; +} + + +static int +dissect_get_Producer_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + + return dissect_get_BSTR_resp(tvb, offset, pinfo, tree, di, drep, hf_cba_producer); +} + + +static int +dissect_get_Product_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + + return dissect_get_BSTR_resp(tvb, offset, pinfo, tree, di, drep, hf_cba_product); +} + + +static int +dissect_ICBAPhysicalDevice_get_LogicalDevice_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Pointer; + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + gchar *call; + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + + if (u32Pointer) { + offset = dissect_dcom_BSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_name, szStr, u32MaxStr); + } else { + szStr[0] = '\0'; + } + + if (strlen(szStr) > 0) { + call = wmem_strdup(wmem_file_scope(), szStr); + di->call_data->private_data = call; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": \"%s\"", szStr); + + return offset; +} + + +static int +dissect_ICBAPhysicalDevice_get_LogicalDevice_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + gchar *ldev_name = (gchar *)di->call_data->private_data; + dcom_interface_t *pdev_interf; + dcom_interface_t *ldev_interf; + cba_pdev_t *pdev; + cba_ldev_t *ldev; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, &ldev_interf); + + /* try to read the ldev name from the request */ + if (ldev_name != NULL && ldev_interf != NULL) { + /* XXX - this is a hack to create a pdev interface */ + /* as I currently don't understand the objref process for a root interface! */ + pdev_interf = dcom_interface_new(pinfo, &pinfo->net_dst, &uuid_ICBAPhysicalDevice, 0, 0, &di->call_data->object_uuid); + if (pdev_interf != NULL) { + pdev = cba_pdev_add(pinfo, &pinfo->net_dst); + cba_pdev_link(pinfo, pdev, pdev_interf); + + ldev = cba_ldev_add(pinfo, pdev, ldev_name); + cba_ldev_link(pinfo, ldev, ldev_interf); + } + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAPhysicalDevice2_Type_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16MultiApp; + guint16 u16PROFInetDCOMStack; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_VARIANT_BOOL(tvb, offset, pinfo, tree, di, drep, + hf_cba_multi_app, &u16MultiApp); + + offset = dissect_dcom_VARIANT_BOOL(tvb, offset, pinfo, tree, di, drep, + hf_cba_profinet_dcom_stack, &u16PROFInetDCOMStack); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " App=%s Stack=%s -> %s", + (u16MultiApp) ? "Multi" : "Single", + (u16PROFInetDCOMStack) ? "PN-DCOM" : "MS-DCOM", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_PROFInetRevision_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16Major; + guint16 u16Minor; + guint16 u16ServicePack; + guint16 u16Build; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_revision_major, &u16Major); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_revision_minor, &u16Minor); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_revision_service_pack, &u16ServicePack); + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_revision_build, &u16Build); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " Revision=%u.%u.%u.%u -> %s", + u16Major, u16Minor, u16ServicePack, u16Build, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAPhysicalDevice2_get_PDevStamp_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32PDevStamp; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_pdev_stamp, &u32PDevStamp); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " PDevStamp=0x%x -> %s", + u32PDevStamp, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_Revision_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16Major; + guint16 u16Minor; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_revision_major, &u16Major); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_revision_minor, &u16Minor); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": %u.%u -> %s", + u16Major, u16Minor, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBALogicalDevice_get_Name_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + guint32 u32Pointer; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_BSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_name, szStr, u32MaxStr); + } else { + szStr[0] = '\0'; + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": \"%s\" -> %s", szStr, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_RTAuto_get_Name_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + + return dissect_get_BSTR_resp(tvb, offset, pinfo, tree, di, drep, hf_cba_name); +} + + +static int +dissect_ICBALogicalDevice_get_ACCO_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + dcom_interface_t *acco_interf; + cba_ldev_t *ldev; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, &acco_interf); + if (acco_interf == NULL) { + expert_add_info(pinfo, NULL, &ei_cba_acco_interface_pointer_unresolved); + } + + ldev = cba_ldev_find(pinfo, &pinfo->net_src, &di->call_data->object_uuid); + + /* "crosslink" interface and its object */ + if (ldev != NULL && acco_interf != NULL) { + cba_ldev_link_acco(pinfo, ldev, acco_interf); + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBALogicalDevice_get_RTAuto_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, NULL); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBALogicalDevice_Get_RTAuto_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + guint32 u32Pointer; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_BSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_name, szStr, u32MaxStr); + } else { + szStr[0] = '\0'; + } + + col_append_fstr(pinfo->cinfo, COL_INFO, ": \"%s\"", szStr); + + return offset; +} + + + +static int +dissect_ComponentInfo_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + gchar szStr[1000]; + guint32 u32MaxStr = sizeof(szStr); + gchar szStr2[1000]; + guint32 u32MaxStr2 = sizeof(szStr2); + guint32 u32HResult; + guint32 u32Pointer; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_BSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_component_id, szStr, u32MaxStr); + } else { + szStr[0] = '\0'; + } + + offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, di, drep, + &u32Pointer); + if (u32Pointer) { + offset = dissect_dcom_BSTR(tvb, offset, pinfo, tree, di, drep, + hf_cba_component_version, szStr2, u32MaxStr2); + } else { + szStr2[0] = '\0'; + } + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": ID=\"%s\" Version=\"%s\" -> %s", + szStr, szStr2, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static void +dissect_PBAddressInfo(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, dcerpc_info *di, guint8 *drep, + guint32 u32VarType _U_, guint32 u32ArraySize) +{ + guint8 u8ID; + guint8 u8Addr; + proto_item *sub_item; + proto_tree *sub_tree; + + + while (u32ArraySize != 0) { + sub_item = proto_tree_add_item(tree, hf_cba_pbaddress, tvb, offset, 2, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_PBAddress); + + offset = dissect_dcom_BYTE(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_pbaddress_system_id, &u8ID); + offset = dissect_dcom_BYTE(tvb, offset, pinfo, sub_tree, di, drep, + hf_cba_pbaddress_address, &u8Addr); + u32ArraySize-=2; + + proto_item_append_text(sub_item, ": ID=0x%x Addr=%u", u8ID, u8Addr); + col_append_fstr(pinfo->cinfo, COL_INFO, ", ID=0x%x Addr=%u", + u8ID, u8Addr); + } +} + + +static int +dissect_PBAddressInfo_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32HResult; + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_SAFEARRAY(tvb, offset, pinfo, tree, di, drep, 0 /*hfindex _U_ */, dissect_PBAddressInfo); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_Advise_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, NULL); + + return offset; +} + + +static int +dissect_Advise_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Cookie; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_cookie, &u32Cookie); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cookie=0x%x -> %s", + u32Cookie, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_Unadvise_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Cookie; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_cookie, &u32Cookie); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cookie=0x%x", + u32Cookie); + + return offset; +} + + +static int +dissect_ICBAState_get_State_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16State; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_state, &u16State); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": State=%s -> %s", + val_to_str(u16State, cba_state_vals, "Unknown (0x%08x)"), + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAStateEvent_OnStateChanged_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16NewState; + guint16 u16OldState; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_new_state, &u16NewState); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_old_state, &u16OldState); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": NewState=%s OldState=%s", + val_to_str(u16NewState, cba_state_vals, "Unknown (0x%04x)"), + val_to_str(u16OldState, cba_state_vals, "Unknown (0x%04x)") ); + + return offset; +} + + +static int +dissect_ICBAGroupError_OnGroupErrorChanged_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16NewGroupError; + guint16 u16OldGroupError; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_new_grouperror, &u16NewGroupError); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_old_grouperror, &u16OldGroupError); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": NewGE=%s OldGE=%s", + val_to_str(u16NewGroupError, cba_grouperror_vals, "Unknown (0x%04x)"), + val_to_str(u16OldGroupError, cba_grouperror_vals, "Unknown (0x%04x)") ); + + return offset; +} + + +static int +dissect_ICBAPhysicalDevicePCEvent_OnLogicalDeviceAdded_rqst(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint32 u32Cookie; + guint32 u32HResult; + + + offset = dissect_dcom_this(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_cookie, &u32Cookie); + + offset = dissect_dcom_PMInterfacePointer(tvb, offset, pinfo, tree, di, drep, 0, NULL); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": Cookie=0x%x %s", + u32Cookie, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +static int +dissect_ICBAGroupError_GroupError_resp(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) +{ + guint16 u16GroupError; + guint32 u32Cookie; + guint32 u32HResult; + + + offset = dissect_dcom_that(tvb, offset, pinfo, tree, di, drep); + + offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_grouperror, &u16GroupError); + + offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, di, drep, + hf_cba_cookie, &u32Cookie); + + offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, di, drep, + &u32HResult); + + col_append_fstr(pinfo->cinfo, COL_INFO, ": GroupError=%s Cookie=0x%x -> %s", + val_to_str(u16GroupError, cba_grouperror_vals, "Unknown (0x%08x)"), + u32Cookie, + val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") ); + + return offset; +} + + +/* sub dissector table of ICBAPhysicalDevice / ICBAPhysicalDevice2 interface */ +static dcerpc_sub_dissector ICBAPhysicalDevice_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "get_Producer", dissect_dcom_simple_rqst, dissect_get_Producer_resp }, + { 8, "get_Product", dissect_dcom_simple_rqst, dissect_get_Product_resp }, + { 9, "get_SerialNo", dissect_dcom_simple_rqst, dissect_get_SerialNo_resp }, + {10, "get_ProductionDate", dissect_dcom_simple_rqst, dissect_get_ProductionDate_resp }, + {11, "Revision", dissect_dcom_simple_rqst, dissect_Revision_resp }, + {12, "get_LogicalDevice", dissect_ICBAPhysicalDevice_get_LogicalDevice_rqst, dissect_ICBAPhysicalDevice_get_LogicalDevice_resp }, + /* stage 2 */ + {13, "Type", dissect_dcom_simple_rqst, dissect_ICBAPhysicalDevice2_Type_resp }, + {14, "PROFInetRevision", dissect_dcom_simple_rqst, dissect_PROFInetRevision_resp }, + {15, "PDevStamp", dissect_dcom_simple_rqst, dissect_ICBAPhysicalDevice2_get_PDevStamp_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBABrowse / ICBABrowse2 interface */ +static dcerpc_sub_dissector ICBABrowse_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "get_Count", dissect_dcom_simple_rqst, dissect_ICBABrowse_get_Count_resp }, + { 8, "BrowseItems", dissect_ICBABrowse_BrowseItems_rqst, dissect_ICBABrowse_BrowseItems_resp }, + /* stage 2 */ + { 9, "get_Count2", dissect_ICBABrowse2_get_Count2_rqst, dissect_ICBABrowse_get_Count_resp }, + {10, "BrowseItems2", dissect_ICBABrowse2_BrowseItems2_rqst, dissect_ICBABrowse2_BrowseItems2_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAPersist / ICBAPersist2 interface */ +static dcerpc_sub_dissector ICBAPersist_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "Save", dissect_dcom_simple_rqst, dissect_dcom_simple_resp }, + /* stage 2 */ + { 8, "Save2", dissect_dcom_simple_rqst, dissect_ICBAPersist2_Save2_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAPhysicalDevicePC interface */ +/* (local COM interface, not to be called over network) */ +static dcerpc_sub_dissector ICBAPhysicalDevicePC_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "AddLogicalDevice", dissect_Advise_rqst, dissect_Advise_resp }, + { 4, "RemoveLogicalDevice", dissect_Unadvise_rqst, dissect_dcom_simple_resp }, + { 5, "AdvisePDevPC", dissect_Advise_rqst, dissect_Advise_resp }, + { 6, "UnadvisePDevPC", dissect_Unadvise_rqst, dissect_dcom_simple_resp }, + /* stage 2 */ + { 7, "RegisterApplication", NULL, NULL }, + { 8, "UnRegisterApplication", NULL, NULL }, + { 9, "AddLogicalDevice2", NULL, NULL }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAPhysicalDevicePCEvent interface */ +static dcerpc_sub_dissector ICBAPhysicalDevicePCEvent_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "OnLogicalDeviceAdded", dissect_ICBAPhysicalDevicePCEvent_OnLogicalDeviceAdded_rqst, dissect_dcom_simple_resp }, + { 4, "OnLogicalDeviceRemoved", dissect_Unadvise_rqst, dissect_dcom_simple_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBALogicalDevice / ICBALogicalDevice2 interface */ +static dcerpc_sub_dissector ICBALogicalDevice_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "get_Name", dissect_dcom_simple_rqst, dissect_ICBALogicalDevice_get_Name_resp }, + { 8, "get_Producer", dissect_dcom_simple_rqst, dissect_get_Producer_resp }, + { 9, "get_Product", dissect_dcom_simple_rqst, dissect_get_Product_resp }, + {10, "get_SerialNo", dissect_dcom_simple_rqst, dissect_get_SerialNo_resp }, + {11, "get_ProductionDate", dissect_dcom_simple_rqst, dissect_get_ProductionDate_resp }, + {12, "Revision", dissect_dcom_simple_rqst, dissect_Revision_resp }, + {13, "get_ACCO", dissect_dcom_simple_rqst, dissect_ICBALogicalDevice_get_ACCO_resp }, + {14, "get_RTAuto", dissect_ICBALogicalDevice_Get_RTAuto_rqst, dissect_ICBALogicalDevice_get_RTAuto_resp }, + /* stage 2 */ + {15, "PROFInetRevision", dissect_dcom_simple_rqst, dissect_PROFInetRevision_resp }, + {16, "ComponentInfo", dissect_dcom_simple_rqst, dissect_ComponentInfo_resp }, + {17, "PBAddressInfo", dissect_dcom_simple_rqst, dissect_PBAddressInfo_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAState interface */ +static dcerpc_sub_dissector ICBAState_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "get_State", dissect_dcom_simple_rqst, dissect_ICBAState_get_State_resp }, + { 8, "Activate", dissect_dcom_simple_rqst, dissect_dcom_simple_resp }, + { 9, "Deactivate", dissect_dcom_simple_rqst, dissect_dcom_simple_resp }, + {10, "Reset", dissect_dcom_simple_rqst, dissect_dcom_simple_resp }, + {11, "AdviseState", dissect_Advise_rqst, dissect_Advise_resp }, + {12, "UnadviseState", dissect_Unadvise_rqst, dissect_dcom_simple_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAStateEvent interface */ +static dcerpc_sub_dissector ICBAStateEvent_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "OnStateChanged", dissect_ICBAStateEvent_OnStateChanged_rqst, dissect_dcom_simple_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBATime interface */ +static dcerpc_sub_dissector ICBATime_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "get_Time", dissect_dcom_simple_rqst, dissect_ICBATime_get_Time_resp }, + { 8, "put_Time", dissect_ICBATime_put_Time_rqst, dissect_dcom_simple_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAGroupError interface */ +static dcerpc_sub_dissector ICBAGroupError_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "GroupError", dissect_dcom_simple_rqst, dissect_ICBAGroupError_GroupError_resp }, + { 8, "AdviseGroupError", dissect_Advise_rqst, dissect_Advise_resp }, + { 9, "UnadviseGroupError", dissect_Unadvise_rqst, dissect_dcom_simple_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBAGroupErrorEvent interface */ +static dcerpc_sub_dissector ICBAGroupErrorEvent_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "OnGroupErrorChanged", dissect_ICBAGroupError_OnGroupErrorChanged_rqst, dissect_dcom_simple_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* sub dissector table of ICBARTAuto interface */ +static dcerpc_sub_dissector ICBARTAuto_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "get_Name", dissect_dcom_simple_rqst, dissect_RTAuto_get_Name_resp }, + { 8, "Revision", dissect_dcom_simple_rqst, dissect_Revision_resp }, + + /* stage 2 */ + { 9, "ComponentInfo", dissect_dcom_simple_rqst, dissect_ComponentInfo_resp }, + { 0, NULL, NULL, NULL }, +}; + + +/* the interface ICBASystemProperties will NOT be seen on the ethernet */ +/* sub dissector table of ICBASystemProperties interface (stage 2 only) */ +/* (usually not called over network, no dissecting needed) */ +static dcerpc_sub_dissector ICBASystemProperties_dissectors[] = { + { 0, "QueryInterface", NULL, NULL }, + { 1, "AddRef", NULL, NULL }, + { 2, "Release", NULL, NULL }, + + { 3, "GetTypeInfoCount", dissect_dcom_simple_rqst, dissect_IDispatch_GetTypeInfoCount_resp }, + { 4, "GetTypeInfo", dissect_IDispatch_GetTypeInfo_rqst, dissect_IDispatch_GetTypeInfo_resp }, + { 5, "GetIDsOfNames", dissect_IDispatch_GetIDsOfNames_rqst, dissect_IDispatch_GetIDsOfNames_resp }, + { 6, "Invoke", dissect_IDispatch_Invoke_rqst, dissect_IDispatch_Invoke_resp }, + + { 7, "StateCollection", dissect_dcom_simple_rqst, NULL }, + { 8, "StampCollection", dissect_dcom_simple_rqst, NULL }, + { 0, NULL, NULL, NULL }, +}; + + +static void cba_cleanup(void) { + g_list_free(cba_pdevs); + cba_pdevs = NULL; +} + + +/* register protocol */ +void +proto_register_dcom_cba (void) +{ + static hf_register_info hf_cba_browse_array[] = { + { &hf_cba_browse_count, + { "Count", "cba.browse.count", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_offset, + { "Offset", "cba.browse.offset", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_max_return, + { "MaxReturn", "cba.browse.max_return", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_item, + { "ItemNames", "cba.browse.item", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_data_type, + { "DataTypes", "cba.browse.data_type", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_access_right, + { "AccessRights", "cba.browse.access_right", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_selector, + { "Selector", "cba.browse.selector", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_info1, + { "Info1", "cba.browse.info1", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_browse_info2, + { "Info2", "cba.browse.info2", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + }; + + + static hf_register_info hf_cba_pdev_array[] = { + { &hf_cba_revision_major, + { "Major", "cba.revision_major", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_revision_minor, + { "Minor", "cba.revision_minor", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_revision_service_pack, + { "ServicePack", "cba.revision_service_pack", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_revision_build, + { "Build", "cba_revision_build", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_producer, + { "Producer", "cba.producer", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_product, + { "Product", "cba.product", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_multi_app, + { "MultiApp", "cba.multi_app", + FT_UINT16, BASE_HEX, VALS(dcom_boolean_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_profinet_dcom_stack, + { "PROFInetDCOMStack", "cba.profinet_dcom_stack", + FT_UINT16, BASE_HEX, VALS(dcom_boolean_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_pdev_stamp, + { "PDevStamp", "cba.pdev_stamp", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_save_ldev_name, + { "LDevName", "cba.save_ldev_name", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_save_result, + { "PartialResult", "cba.save_result", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + }; + + static hf_register_info hf_cba_ldev_array[] = { + { &hf_cba_name, + { "Name", "cba.name", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_component_id, + { "ComponentID", "cba.component_id", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_component_version, + { "Version", "cba.component_version", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_pbaddress, + { "PROFIBUS Address", "cba.pbaddress", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_pbaddress_system_id, + { "SystemID", "cba.pbaddress.system_id", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_pbaddress_address, + { "Address", "cba.pbaddress.address", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + }; + + static hf_register_info hf_cba_array[] = { + { &hf_cba_opnum, + { "Operation", "cba.opnum", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_production_date, + { "ProductionDate", "cba.production_date", + FT_DOUBLE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_time, + { "Time", "cba.time", + FT_DOUBLE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_serial_no, + { "SerialNo", "cba.serial_no", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_state, + { "State", "cba.state", + FT_UINT16, BASE_HEX, VALS(cba_state_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_new_state, + { "NewState", "cba.state_new", + FT_UINT16, BASE_HEX, VALS(cba_state_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_old_state, + { "OldState", "cba.state_old", + FT_UINT16, BASE_HEX, VALS(cba_state_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_cookie, + { "Cookie", "cba.cookie", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_cba_grouperror, + { "GroupError", "cba.grouperror", + FT_UINT16, BASE_HEX, VALS(cba_grouperror_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_new_grouperror, + { "NewGroupError", "cba.grouperror_new", + FT_UINT16, BASE_HEX, VALS(cba_grouperror_vals), 0x0, + NULL, HFILL }}, + + { &hf_cba_old_grouperror, + { "OldGroupError", "cba.grouperror_old", + FT_UINT16, BASE_HEX, VALS(cba_grouperror_vals), 0x0, + NULL, HFILL }}, + + }; + + static gint *ett_cba[] = { + &ett_ICBAPhysicalDevice, + &ett_ICBABrowse, + &ett_ICBAPhysicalDevicePC, + &ett_ICBAPhysicalDevicePCEvent, + &ett_ICBAPersist, + &ett_ICBALogicalDevice, + &ett_ICBAState, + &ett_ICBAStateEvent, + &ett_ICBATime, + &ett_ICBAGroupError, + &ett_ICBAGroupErrorEvent, + &ett_ICBARTAuto, + &ett_ICBASystemProperties, + &ett_PBAddress + }; + + static ei_register_info ei[] = { + { &ei_cba_acco_interface_pointer_unresolved, { "cba.acco.interface_pointer_unresolved", PI_UNDECODED, PI_WARN, "LDev_get_ACCO: can't resolve ACCO interface pointer", EXPFILL }}, + }; + + expert_module_t* expert_cba_acco; + + proto_register_subtree_array (ett_cba, array_length (ett_cba)); + + proto_ICBAPhysicalDevice = proto_register_protocol ("ICBAPhysicalDevice", "ICBAPDev", "cba_pdev"); + proto_register_field_array(proto_ICBAPhysicalDevice, hf_cba_pdev_array, array_length(hf_cba_pdev_array)); + + /* XXX - just pick a protocol to register the expert info in */ + expert_cba_acco = expert_register_protocol(proto_ICBAPhysicalDevice); + expert_register_field_array(expert_cba_acco, ei, array_length(ei)); + + proto_ICBAPhysicalDevice2 = proto_register_protocol ("ICBAPhysicalDevice2", "ICBAPDev2", "cba_pdev2"); + + proto_ICBABrowse = proto_register_protocol ("ICBABrowse", "ICBABrowse", "cba_browse"); + proto_register_field_array(proto_ICBABrowse, hf_cba_array, array_length(hf_cba_array)); + proto_register_field_array(proto_ICBABrowse, hf_cba_browse_array, array_length(hf_cba_browse_array)); + + proto_ICBABrowse2 = proto_register_protocol ("ICBABrowse2", "ICBABrowse2", "cba_browse2"); + + proto_ICBAPhysicalDevicePC = proto_register_protocol ("ICBAPhysicalDevicePC", "ICBAPDevPC", "cba_pdev_pc"); + + proto_ICBAPhysicalDevicePCEvent = proto_register_protocol ("ICBAPhysicalDevicePCEvent", "ICBAPDevPCEvent", "cba_pdev_pc_event"); + + proto_ICBAPersist = proto_register_protocol ("ICBAPersist", "ICBAPersist", "cba_persist"); + + proto_ICBAPersist2 = proto_register_protocol ("ICBAPersist2", "ICBAPersist2", "cba_persist2"); + + proto_ICBALogicalDevice = proto_register_protocol ("ICBALogicalDevice", "ICBALDev", "cba_ldev"); + proto_register_field_array(proto_ICBAPhysicalDevice, hf_cba_ldev_array, array_length(hf_cba_ldev_array)); + + proto_ICBALogicalDevice2 = proto_register_protocol ("ICBALogicalDevice2", "ICBALDev2", "cba_ldev2"); + + proto_ICBAState = proto_register_protocol ("ICBAState", "ICBAState", "cba_state"); + + proto_ICBAStateEvent = proto_register_protocol ("ICBAStateEvent", "ICBAStateEvent", "cba_state_event"); + + proto_ICBATime = proto_register_protocol ("ICBATime", "ICBATime", "cba_time"); + + proto_ICBAGroupError = proto_register_protocol ("ICBAGroupError", "ICBAGErr", "cba_grouperror"); + + proto_ICBAGroupErrorEvent = proto_register_protocol ("ICBAGroupErrorEvent", "ICBAGErrEvent", "cba_grouperror_event"); + + proto_ICBARTAuto = proto_register_protocol ("ICBARTAuto", "ICBARTAuto", "cba_rtauto"); + + proto_ICBARTAuto2 = proto_register_protocol ("ICBARTAuto2", "ICBARTAuto2", "cba_rtauto2"); + + proto_ICBASystemProperties = proto_register_protocol ("ICBASystemProperties", "ICBASysProp", "cba_sysprop"); + + register_cleanup_routine(cba_cleanup); +} + + +/* handoff protocol */ +void +proto_reg_handoff_dcom_cba (void) +{ + /* Register the CBA class ID */ + guids_add_uuid(&uuid_coclass_CBAPhysicalDevice, "CBA"); + + /* Register the interfaces */ + dcerpc_init_uuid(proto_ICBAPhysicalDevice, ett_ICBAPhysicalDevice, + &uuid_ICBAPhysicalDevice, ver_ICBAPhysicalDevice, + ICBAPhysicalDevice_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAPhysicalDevice2, ett_ICBAPhysicalDevice, + &uuid_ICBAPhysicalDevice2, ver_ICBAPhysicalDevice2, + ICBAPhysicalDevice_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBABrowse, ett_ICBABrowse, + &uuid_ICBABrowse, ver_ICBABrowse, + ICBABrowse_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBABrowse2, ett_ICBABrowse, + &uuid_ICBABrowse2, ver_ICBABrowse2, + ICBABrowse_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAPhysicalDevicePC, ett_ICBAPhysicalDevicePC, + &uuid_ICBAPhysicalDevicePC, ver_ICBAPhysicalDevicePC, + ICBAPhysicalDevicePC_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAPhysicalDevicePCEvent, ett_ICBAPhysicalDevicePCEvent, + &uuid_ICBAPhysicalDevicePCEvent, ver_ICBAPhysicalDevicePCEvent, + ICBAPhysicalDevicePCEvent_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAPersist, ett_ICBAPersist, + &uuid_ICBAPersist, ver_ICBAPersist, + ICBAPersist_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAPersist2, ett_ICBAPersist, + &uuid_ICBAPersist2, ver_ICBAPersist2, + ICBAPersist_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBALogicalDevice, ett_ICBALogicalDevice, + &uuid_ICBALogicalDevice, ver_ICBALogicalDevice, + ICBALogicalDevice_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBALogicalDevice2, ett_ICBALogicalDevice, + &uuid_ICBALogicalDevice2, ver_ICBALogicalDevice2, + ICBALogicalDevice_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAState, ett_ICBAState, + &uuid_ICBAState, ver_ICBAState, + ICBAState_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAStateEvent, ett_ICBAStateEvent, + &uuid_ICBAStateEvent, ver_ICBAStateEvent, + ICBAStateEvent_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBATime, ett_ICBATime, + &uuid_ICBATime, ver_ICBATime, + ICBATime_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAGroupError, ett_ICBAGroupError, + &uuid_ICBAGroupError, ver_ICBAGroupError, + ICBAGroupError_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBAGroupErrorEvent, ett_ICBAGroupErrorEvent, + &uuid_ICBAGroupErrorEvent, ver_ICBAGroupErrorEvent, + ICBAGroupErrorEvent_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBARTAuto, ett_ICBARTAuto, + &uuid_ICBARTAuto, ver_ICBARTAuto, + ICBARTAuto_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBARTAuto2, ett_ICBARTAuto, + &uuid_ICBARTAuto2, ver_ICBARTAuto2, + ICBARTAuto_dissectors, hf_cba_opnum); + + dcerpc_init_uuid(proto_ICBASystemProperties, ett_ICBASystemProperties, + &uuid_ICBASystemProperties, ver_ICBASystemProperties, + ICBASystemProperties_dissectors, hf_cba_opnum); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn-dcp.c b/plugins/epan/profinet/packet-pn-dcp.c new file mode 100644 index 0000000000..2838663b5c --- /dev/null +++ b/plugins/epan/profinet/packet-pn-dcp.c @@ -0,0 +1,1400 @@ +/* packet-pn-dcp.c + * Routines for PN-DCP (PROFINET Discovery and basic Configuration Protocol) + * packet dissection. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Cyclic PNIO RTC1 Data Dissection: + * + * Added new functions to packet-pn-dcp.c. The profinet plug-in will now save + * the information (Stationname, -type, -id) of "Ident OK" frames. Those + * informations will later be used for detailled dissection of cyclic PNIO RTC1 + * dataframes. + * + * The declaration of the new added structures are within packet-pn.h to + * use the information within packet-pn-rtc-one.c + * + * Overview for cyclic PNIO RTC1 data dissection functions: + * -> dissect_PNDCP_Suboption_Device (Save Stationname, -type, -id) + */ + + +#include "config.h" + +#include <string.h> + +#include <glib.h> + +#include <epan/packet.h> +#include <epan/exceptions.h> +#include <epan/to_str.h> +#include <epan/wmem/wmem.h> +#include <epan/expert.h> +#include <epan/conversation.h> + +#include "packet-pn.h" + + +void proto_register_pn_dcp(void); +void proto_reg_handoff_pn_dcp(void); + +int proto_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_block_error = -1; + +static int hf_pn_dcp_option = -1; +static int hf_pn_dcp_block_info = -1; +static int hf_pn_dcp_block_qualifier = -1; +static int hf_pn_dcp_blockqualifier = -1; +static int hf_pn_dcp_blockqualifier_r2f = -1; + +static int hf_pn_dcp_suboption_ip = -1; +static int hf_pn_dcp_suboption_ip_block_info = -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_standard_gateway = -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_device_aliasname = -1; +static int hf_pn_dcp_suboption_device_instance_high = -1; +static int hf_pn_dcp_suboption_device_instance_low = -1; +static int hf_pn_dcp_suboption_device_oem_ven_id = -1; +static int hf_pn_dcp_suboption_device_oem_dev_id = -1; + +static int hf_pn_dcp_suboption_dhcp = -1; +static int hf_pn_dcp_suboption_dhcp_device_id = -1; + +static int hf_pn_dcp_suboption_control = -1; +static int hf_pn_dcp_suboption_control_response = -1; +static int hf_pn_dcp_suboption_control_signal_value = -1; + +static int hf_pn_dcp_suboption_deviceinitiative = -1; +static int hf_pn_dcp_deviceinitiative_value = -1; + +static int hf_pn_dcp_suboption_all = -1; + +static int hf_pn_dcp_suboption_manuf = -1; + + +static gint ett_pn_dcp = -1; +static gint ett_pn_dcp_block = -1; + +static expert_field ei_pn_dcp_block_parse_error = EI_INIT; +static expert_field ei_pn_dcp_block_error_unknown = EI_INIT; +static expert_field ei_pn_dcp_ip_conflict = EI_INIT; + +#define PNDCP_SERVICE_ID_GET 0x03 +#define PNDCP_SERVICE_ID_SET 0x04 +#define PNDCP_SERVICE_ID_IDENTIFY 0x05 +#define PNDCP_SERVICE_ID_HELLO 0x06 + +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" }, + { PNDCP_SERVICE_ID_HELLO, "Hello" }, + /* 0x07 - 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_block_error[] = { + { 0x00, "Ok" }, + { 0x01, "Option unsupp." }, + { 0x02, "Suboption unsupp. or no DataSet avail." }, + { 0x03, "Suboption not set" }, + { 0x04, "Resource Error" }, + { 0x05, "SET not possible by local reasons" }, + { 0x06, "In operation, SET not possible" }, + /* all others reserved */ + { 0, NULL } +}; + +static const value_string pn_dcp_block_info[] = { + { 0x0000, "Reserved" }, + /*0x0001 - 0xffff reserved */ + { 0, NULL } +}; + +static const value_string pn_dcp_block_qualifier[] = { + { 0x0000, "Use the value temporary" }, + { 0x0001, "Save the value permanent" }, + /*0x0002 - 0xffff reserved */ + { 0, NULL } +}; + +static const value_string pn_dcp_BlockQualifier[] = { + { 0x0002, "Reset application data" }, + { 0x0003, "Reset application data" }, + { 0x0004, "Reset communication parameter" }, + { 0x0005, "Reset communication parameter" }, + { 0x0006, "Reset engineering parameter" }, + { 0x0007, "Reset engineering parameter" }, + { 0x0008, "Resets all stored data" }, + { 0x0009, "Resets all stored data" }, + { 0x000A, "Reset engineering parameter" }, + { 0x000B, "Reset engineering parameter" }, + { 0x000C, "Reserved" }, + { 0x000D, "Reserved" }, + { 0x000E, "Reserved" }, + { 0x0010, "Resets all stored data in the IOD or IOC to its factory values" }, + { 0x0011, "Resets all stored data in the IOD or IOC to its factory values" }, + { 0x0012, "Reset and restore data" }, + { 0x0013, "Reset and restore data" }, + { 0x0014, "Reserved" }, + { 0x0015, "Reserved" }, + { 0x0016, "Reserved" }, + { 0, NULL } +}; + +#define PNDCP_OPTION_IP 0x01 +#define PNDCP_OPTION_DEVICE 0x02 +#define PNDCP_OPTION_DHCP 0x03 +#define PNDCP_OPTION_RESERVED 0x04 +#define PNDCP_OPTION_CONTROL 0x05 +#define PNDCP_OPTION_DEVICEINITIATIVE 0x06 +#define PNDCP_OPTION_MANUF_X80 0x80 +#define PNDCP_OPTION_MANUF_X81 0x81 +#define PNDCP_OPTION_MANUF_X82 0x82 +#define PNDCP_OPTION_MANUF_X83 0x83 +#define PNDCP_OPTION_MANUF_X84 0x84 +#define PNDCP_OPTION_MANUF_X85 0x85 +#define PNDCP_OPTION_MANUF_X86 0x86 +#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_RESERVED, "Reserved" }, + { PNDCP_OPTION_CONTROL, "Control" }, + { PNDCP_OPTION_DEVICEINITIATIVE, "Device Initiative" }, + /*0x07 - 0x7f reserved */ + /*0x80 - 0xfe manufacturer specific */ + { PNDCP_OPTION_MANUF_X80, "Manufacturer specific" }, + { PNDCP_OPTION_MANUF_X81, "Manufacturer specific" }, + { PNDCP_OPTION_MANUF_X82, "Manufacturer specific" }, + { PNDCP_OPTION_MANUF_X83, "Manufacturer specific" }, + { PNDCP_OPTION_MANUF_X84, "Manufacturer specific" }, + { PNDCP_OPTION_MANUF_X85, "Manufacturer specific" }, + { PNDCP_OPTION_MANUF_X86, "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_block_info[] = { + { 0x0000, "IP not set" }, + { 0x0001, "IP set" }, + { 0x0002, "IP set by DHCP" }, + { 0x0080, "IP not set (address conflict detected)" }, + { 0x0081, "IP set (address conflict detected)" }, + { 0x0082, "IP set by DHCP (address conflict detected)" }, + /*0x0003 - 0xffff reserved */ + { 0, NULL } +}; + +static const value_string pn_dcp_suboption_control_signal_value[] = { + {0x0100, "Flash Once"}, + {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 +#define PNDCP_SUBOPTION_DEVICE_ALIAS_NAME 0x06 +#define PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE 0x07 +#define PNDCP_SUBOPTION_DEVICE_OEM_DEV_ID 0x08 + +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" }, + { PNDCP_SUBOPTION_DEVICE_ALIAS_NAME, "Alias Name" }, + { PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE, "Device Instance" }, + { PNDCP_SUBOPTION_DEVICE_OEM_DEV_ID, "OEM Device ID"}, + /*0x09 - 0xff reserved */ + { 0, NULL } +}; + +#define PNDCP_SUBOPTION_DHCP_CLIENT_ID 61 + +static const value_string pn_dcp_suboption_dhcp[] = { + { 12, "Host name" }, + { 43, "Vendor specific" }, + { 54, "Server identifier" }, + { 55, "Parameter request list" }, + { 60, "Class identifier" }, + { PNDCP_SUBOPTION_DHCP_CLIENT_ID, "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 } +}; + +#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 +#define PNDCP_SUBOPTION_CONTROL_FACT_RESET 0x05 +#define PNDCP_SUBOPTION_CONTROL_RESET_TO_FACT 0x06 + +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" }, + { PNDCP_SUBOPTION_CONTROL_FACT_RESET, "Reset Factory Settings" }, + { PNDCP_SUBOPTION_CONTROL_RESET_TO_FACT,"Reset to Factory" }, + /*0x07 - 0xff reserved */ + { 0, NULL } +}; + +#define PNDCP_SUBOPTION_DEVICEINITIATIVE 0x01 + +static const value_string pn_dcp_suboption_deviceinitiative[] = { + { 0x00, "Reserved" }, + { PNDCP_SUBOPTION_DEVICEINITIATIVE, "Device Initiative" }, + /*0x00 - 0xff reserved */ + { 0, NULL } +}; + +static const value_string pn_dcp_deviceinitiative_value[] = { + { 0x00, "Device does not issue a DCP-Hello-ReqPDU after power on" }, + { 0x01, "Device does issue a DCP-Hello-ReqPDU after power on" }, + /*0x02 - 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_other[] = { + { 0x00, "Default" }, + /* all other reserved */ + { 0, NULL } +}; + +static const value_string pn_dcp_suboption_manuf[] = { + /* none known */ + { 0, NULL } +}; + + + + + +/* 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_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_DEVICEINITIATIVE: + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_deviceinitiative, &suboption); + val_str = pn_dcp_suboption_deviceinitiative; + 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) { + 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, + guint8 service_id, gboolean is_response) +{ + guint8 suboption; + guint16 block_length; + guint16 block_info; + guint16 block_qualifier; + guint32 ip; + proto_item *item = NULL; + address addr; + + + /* SuboptionIPParameter */ + offset = dissect_pn_uint8 (tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip, &suboption); + /* DCPBlockLength */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); + + switch (suboption) { + case PNDCP_SUBOPTION_IP_MAC: + /* MACAddressValue? */ + pn_append_info(pinfo, dcp_item, ", MAC"); + proto_item_append_text(block_item, "IP/MAC"); + + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); + break; + case PNDCP_SUBOPTION_IP_IP: + pn_append_info(pinfo, dcp_item, ", IP"); + proto_item_append_text(block_item, "IP/IP"); + + /* BlockInfo? */ + if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) || + ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) || + ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) { + block_info = tvb_get_ntohs (tvb, offset); + if (tree) { + item = proto_tree_add_uint(tree, hf_pn_dcp_suboption_ip_block_info, tvb, offset, 2, block_info); + } + offset += 2; + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_suboption_ip_block_info, "Undecoded")); + block_length -= 2; + if (block_info & 0x80) { + expert_add_info(pinfo, item, &ei_pn_dcp_ip_conflict); + } + } + + /* BlockQualifier? */ + if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier); + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + block_length -= 2; + } + + /* IPParameterValue ... */ + + /* IPAddress */ + offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_ip, &ip); + set_address(&addr, AT_IPv4, 4, &ip); + proto_item_append_text(block_item, ", IP: %s", address_to_str(wmem_packet_scope(), &addr)); + + /* Subnetmask */ + offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_subnetmask, &ip); + set_address(&addr, AT_IPv4, 4, &ip); + proto_item_append_text(block_item, ", Subnet: %s", address_to_str(wmem_packet_scope(), &addr)); + + /* StandardGateway */ + offset = dissect_pn_ipv4(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_ip_standard_gateway, &ip); + set_address(&addr, AT_IPv4, 4, &ip); + proto_item_append_text(block_item, ", Gateway: %s", address_to_str(wmem_packet_scope(), &addr)); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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, + guint8 service_id, gboolean is_response) +{ + guint8 suboption; + guint16 block_length; + gchar *info_str; + guint8 device_role; + guint16 vendor_id; + guint16 device_id; + char *typeofstation; + char *nameofstation; + char *aliasname; + guint16 block_info = 0; + guint16 block_qualifier = 0; + gboolean have_block_info = FALSE; + gboolean have_block_qualifier = FALSE; + guint8 device_instance_high; + guint8 device_instance_low; + guint16 oem_vendor_id; + guint16 oem_device_id; + conversation_t *conversation; + stationInfo *station_info; + + /* SuboptionDevice... */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption); + /* DCPBlockLength */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); + + /* BlockInfo? */ + if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) || + ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) || + ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info); + have_block_info = TRUE; + block_length -= 2; + } + + /* BlockQualifier? */ + if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier); + have_block_qualifier = TRUE; + block_length -= 2; + } + + switch (suboption) { + case PNDCP_SUBOPTION_DEVICE_MANUF: + typeofstation = (char *)wmem_alloc(wmem_packet_scope(), block_length+1); + tvb_memcpy(tvb, (guint8 *) 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, ", DeviceVendorValue"); + proto_item_append_text(block_item, "Device/Manufacturer specific"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info){ + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_item_append_text(block_item, ", DeviceVendorValue: \"%s\"", typeofstation); + + + if (pinfo->fd->flags.visited == FALSE) { + /* Create a conversation between the MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info == NULL) { + station_info = wmem_new0(wmem_file_scope(), stationInfo); + init_pnio_rtc1_station(station_info); + conversation_add_proto_data(conversation, proto_pn_dcp, station_info); + } + + station_info->typeofstation = wmem_strdup(wmem_file_scope(), typeofstation); + } + + offset += block_length; + break; + + case PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION: + nameofstation = (char *)wmem_alloc(wmem_packet_scope(), block_length+1); + tvb_memcpy(tvb, (guint8 *) 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, wmem_strdup_printf(wmem_packet_scope(), ", NameOfStation:\"%s\"", nameofstation)); + proto_item_append_text(block_item, "Device/NameOfStation"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_item_append_text(block_item, ", \"%s\"", nameofstation); + + + if (pinfo->fd->flags.visited == FALSE) { + /* Create a conversation between the MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info == NULL) { + station_info = wmem_new0(wmem_file_scope(), stationInfo); + init_pnio_rtc1_station(station_info); + conversation_add_proto_data(conversation, proto_pn_dcp, station_info); + } + + station_info->nameofstation = wmem_strdup(wmem_file_scope(), 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); + + if (pinfo->fd->flags.visited == FALSE) { + /* Create a conversation between the MAC addresses */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + if (conversation == NULL) { + conversation = conversation_new(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + } + + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info == NULL) { + station_info = wmem_new0(wmem_file_scope(), stationInfo); + init_pnio_rtc1_station(station_info); + conversation_add_proto_data(conversation, proto_pn_dcp, station_info); + } + + station_info->u16Vendor_id = vendor_id; + station_info->u16Device_id = device_id; + } + + + pn_append_info(pinfo, dcp_item, ", Dev-ID"); + proto_item_append_text(block_item, "Device/Device ID"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_item_append_text(block_item, ", VendorID: 0x%04x / DeviceID: 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 (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) + proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); + 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 = wmem_strdup_printf(wmem_packet_scope(), ", Dev-Options(%u)", block_length/2); + pn_append_info(pinfo, dcp_item, info_str); + proto_item_append_text(block_item, "Device/Device Options"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + 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; + case PNDCP_SUBOPTION_DEVICE_ALIAS_NAME: + aliasname = (char *)wmem_alloc(wmem_packet_scope(), block_length+1); + tvb_memcpy(tvb, (guint8 *) aliasname, offset, block_length); + aliasname[block_length] = '\0'; + proto_tree_add_string (tree, hf_pn_dcp_suboption_device_aliasname, tvb, offset, block_length, aliasname); + pn_append_info(pinfo, dcp_item, wmem_strdup_printf(wmem_packet_scope(), ", AliasName:\"%s\"", aliasname)); + proto_item_append_text(block_item, "Device/AliasName"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_item_append_text(block_item, ", \"%s\"", aliasname); + offset += block_length; + break; + case PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE: + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_instance_high, &device_instance_high); + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_instance_low, &device_instance_low); + pn_append_info(pinfo, dcp_item, ", Dev-Instance"); + proto_item_append_text(block_item, "Device/Device Instance"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_item_append_text(block_item, ", InstanceHigh: %d, Instance Low: %d", + device_instance_high, device_instance_low); + break; + case PNDCP_SUBOPTION_DEVICE_OEM_DEV_ID: + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_oem_ven_id, &oem_vendor_id); + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_oem_dev_id, &oem_device_id); + pn_append_info(pinfo, dcp_item, ", OEM-Dev-ID"); + proto_item_append_text(block_item, "Device/OEM Device ID"); + if(have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if(have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_item_append_text(block_item, ", OEMVendorID: 0x%04x / OEMDeviceID: 0x%04x", oem_vendor_id, oem_device_id); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); + } + + return offset; +} + + +/* dissect the "DHCP" suboption */ +static int +dissect_PNDCP_Suboption_DHCP(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, proto_item *block_item, proto_item *dcp_item, + guint8 service_id _U_, gboolean is_response _U_) +{ + guint8 suboption; + guint16 block_length; + guint16 block_info = 0; + guint16 block_qualifier = 0; + gboolean have_block_info = FALSE; + gboolean have_block_qualifier = FALSE; + + + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_dhcp, &suboption); + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); + + /* BlockInfo? */ + if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) || + ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) || + ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info); + have_block_info=TRUE; + block_length -= 2; + } + + /* BlockQualifier? */ + if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier); + have_block_qualifier=TRUE; + block_length -= 2; + } + + switch (suboption) { + case PNDCP_SUBOPTION_DHCP_CLIENT_ID: + pn_append_info(pinfo, dcp_item, ", DHCP client identifier"); + proto_item_append_text(block_item, "DHCP/Client-ID"); + if (have_block_qualifier) { + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + } + if (have_block_info) { + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + } + proto_tree_add_item(tree, hf_pn_dcp_suboption_dhcp_device_id, tvb, offset, block_length, ENC_NA); + offset += block_length; + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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, + guint8 service_id _U_, gboolean is_response _U_) +{ + guint8 suboption; + guint16 block_length; + guint16 block_qualifier; + guint16 BlockQualifier; + guint16 u16SignalValue; + gchar *info_str; + guint8 block_error; + proto_item *item = NULL; + + + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control, &suboption); + 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_block_qualifier, &block_qualifier); + 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_block_qualifier, &block_qualifier); + 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_block_qualifier, &block_qualifier); + block_length -= 2; + + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_control_signal_value, &u16SignalValue); + 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_response, + FALSE /* append_col */); + block_error = tvb_get_guint8 (tvb, offset); + if (tree) { + item = proto_tree_add_uint(tree, hf_pn_dcp_block_error, tvb, offset, 1, block_error); + } + offset += 1; + if (block_error != 0) { + expert_add_info_format(pinfo, item, &ei_pn_dcp_block_error_unknown, "%s", + val_to_str(block_error, pn_dcp_block_error, "Unknown")); + } + info_str = wmem_strdup_printf(wmem_packet_scope(), ", Response(%s)", + val_to_str(block_error, pn_dcp_block_error, "Unknown")); + pn_append_info(pinfo, dcp_item, info_str); + proto_item_append_text(block_item, ", BlockError: %s", + val_to_str(block_error, pn_dcp_block_error, "Unknown")); + + break; + case PNDCP_SUBOPTION_CONTROL_FACT_RESET: + pn_append_info(pinfo, dcp_item, ", Reset FactorySettings"); + proto_item_append_text(block_item, "Control/Reset FactorySettings"); + block_length -= 2; + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_blockqualifier_r2f, &BlockQualifier); + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(BlockQualifier, pn_dcp_suboption_other, "reserved")); + block_length -= 2; + break; + + case PNDCP_SUBOPTION_CONTROL_RESET_TO_FACT: + pn_append_info(pinfo, dcp_item, ", Reset to Factory"); + proto_item_append_text(block_item, "Reset to FactorySettings"); + + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_blockqualifier, &BlockQualifier); + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(BlockQualifier, pn_dcp_BlockQualifier, "reserved")); + block_length -= 2; + + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); + } + + return offset; +} + + +/* dissect the "deviceinitaitve" suboption */ +static int +dissect_PNDCP_Suboption_DeviceInitiative(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, proto_item *block_item, proto_item *dcp_item, + guint8 service_id, gboolean is_response) +{ + guint8 suboption; + guint16 block_length; + guint16 block_info; + guint16 block_qualifier; + guint16 value; + + + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_deviceinitiative, &suboption); + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); + + pn_append_info(pinfo, dcp_item, ", DeviceInitiative"); + proto_item_append_text(block_item, "DeviceInitiative/DeviceInitiative"); + + /* BlockInfo? */ + if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) || + ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) || + ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info); + proto_item_append_text(block_item, ", BlockInfo: %s", + val_to_str(block_info, pn_dcp_block_info, "Unknown")); + block_length -= 2; + } + + /* BlockQualifier? */ + if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) { + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier); + proto_item_append_text(block_item, ", BlockQualifier: %s", + val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); + block_length -= 2; + } + + /* DeviceInitiativeValue */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_deviceinitiative_value, &value); + + 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, + guint8 service_id _U_, gboolean is_response _U_) +{ + guint8 suboption; + guint16 block_length; + + + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_all, &suboption); + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); + + switch (suboption) { + case 255: /* All */ + pn_append_info(pinfo, dcp_item, ", All"); + proto_item_append_text(block_item, "All/All"); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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, + guint8 service_id _U_, gboolean is_response _U_) +{ + guint16 block_length; + + offset = dissect_pn_uint8( tvb, offset, pinfo, tree, hf_pn_dcp_suboption_manuf, NULL); + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); + + pn_append_info(pinfo, dcp_item, ", Manufacturer Specific"); + proto_item_append_text(block_item, "Manufacturer Specific"); + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, 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, + guint8 service_id, gboolean is_response) +{ + guint8 option; + proto_item *block_item; + proto_tree *block_tree; + int ori_offset = offset; + + /* subtree for block */ + block_item = proto_tree_add_none_format(tree, hf_pn_dcp_block, + tvb, offset, 0, "Block: "); + 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); + + switch (option) { + case PNDCP_OPTION_IP: + offset = dissect_PNDCP_Suboption_IP(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response); + break; + case PNDCP_OPTION_DEVICE: + offset = dissect_PNDCP_Suboption_Device(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response); + break; + case PNDCP_OPTION_DHCP: + offset = dissect_PNDCP_Suboption_DHCP(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response); + break; + case PNDCP_OPTION_CONTROL: + offset = dissect_PNDCP_Suboption_Control(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response); + break; + case PNDCP_OPTION_DEVICEINITIATIVE: + offset = dissect_PNDCP_Suboption_DeviceInitiative(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response); + break; + case PNDCP_OPTION_ALLSELECTOR: + offset = dissect_PNDCP_Suboption_All(tvb, offset, pinfo, block_tree, block_item, dcp_item, service_id, is_response); + 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, service_id, is_response); + } + + proto_item_set_len(block_item, offset-ori_offset); + + if ((offset-ori_offset) & 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); + proto_tree_add_item_ret_uint(tree, hf_pn_dcp_xid, tvb, offset, 4, ENC_BIG_ENDIAN, &xid); + offset += 4; + 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; + case PNDCP_SERVICE_ID_HELLO: + pn_append_info(pinfo, dcp_item, "Hello"); + break; + default: + dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_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: + dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset)); + return; + } + + xid_str = wmem_strdup_printf(wmem_packet_scope(), ", Xid:0x%x", xid); + pn_append_info(pinfo, dcp_item, 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, service_id, is_response); + } + /* prevent an infinite loop */ + if (offset <= ori_offset || data_length < (offset - ori_offset)) { + proto_tree_add_expert(tree, pinfo, &ei_pn_dcp_block_parse_error, + tvb, ori_offset, tvb_captured_length_remaining(tvb, ori_offset)); + break; + } + data_length -= (offset - 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, + void *data) +{ + /* the tvb will NOT contain the frame_id here, so get it from dissection data! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + proto_item *item; + proto_tree *dcp_tree; + + + /* frame id must be in valid range (acyclic Real-Time, DCP) */ + if (u16FrameID < FRAME_ID_DCP_HELLO || u16FrameID > FRAME_ID_DCP_IDENT_RES) { + /* we are not interested in this packet */ + return FALSE; + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-DCP"); + col_clear(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_service_id, + { "ServiceID", "pn_dcp.service_id", + FT_UINT8, BASE_DEC, VALS(pn_dcp_service_id), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_service_type, + { "ServiceType", "pn_dcp.service_type", + FT_UINT8, BASE_DEC, VALS(pn_dcp_service_type), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_xid, + { "Xid", "pn_dcp.xid", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_reserved8, + { "Reserved", "pn_dcp.reserved8", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_reserved16, + { "Reserved", "pn_dcp.reserved16", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_response_delay, + { "ResponseDelay", "pn_dcp.response_delay", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_data_length, + { "DCPDataLength", "pn_dcp.data_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_block_length, + { "DCPBlockLength", "pn_dcp.block_length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_option, + { "Option", "pn_dcp.option", + FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, + NULL, HFILL }}, + +#if 0 + { &hf_pn_dcp_suboption, + { "Suboption", "pn_dcp.suboption", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, +#endif + + { &hf_pn_dcp_block_error, + { "BlockError", "pn_dcp.block_error", + FT_UINT8, BASE_DEC, VALS(pn_dcp_block_error), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_block, + { "Block", "pn_dcp.block", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_block_info, + { "BlockInfo", "pn_dcp.block_info", + FT_UINT16, BASE_DEC, VALS(pn_dcp_block_info), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_block_qualifier, + { "BlockQualifier", "pn_dcp.block_qualifier", + FT_UINT16, BASE_DEC, VALS(pn_dcp_block_qualifier), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_blockqualifier_r2f, + { "BlockQualifier: ResettoFactory", "pn_dcp.block_qualifier_reset", + FT_UINT16, BASE_DEC, VALS(pn_dcp_BlockQualifier), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_blockqualifier, + { "BlockQualifier: ResetFactorySettings", "pn_dcp.block_qualifier_reset", + FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_other), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_ip, + { "Suboption", "pn_dcp.suboption_ip", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_ip), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_ip_block_info, + { "BlockInfo", "pn_dcp.suboption_ip_block_info", + FT_UINT16, BASE_DEC, VALS(pn_dcp_suboption_ip_block_info), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_ip_ip, + { "IPaddress", "pn_dcp.subobtion_ip_ip", + FT_IPv4, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_ip_subnetmask, + { "Subnetmask", "pn_dcp.subobtion_ip_subnetmask", + FT_IPv4, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_ip_standard_gateway, + { "StandardGateway", "pn_dcp.suboption_ip_standard_gateway", + FT_IPv4, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device, + { "Suboption", "pn_dcp.suboption_device", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_device), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_typeofstation, + { "DeviceVendorValue", "pn_dcp.suboption_device_devicevendorvalue", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_nameofstation, + { "NameOfStation", "pn_dcp.suboption_device_nameofstation", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_vendor_id, + { "VendorID", "pn_dcp.suboption_vendor_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_id, + { "DeviceID", "pn_dcp.suboption_device_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_role, + { "DeviceRoleDetails", "pn_dcp.suboption_device_role", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_aliasname, + { "AliasName", "pn_dcp.suboption_device_aliasname", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_instance_high, + { "DeviceInstanceHigh", "pn_dcp.suboption_device_instance", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_instance_low, + { "DeviceInstanceLow", "pn_dcp.suboption_device_instance", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_oem_ven_id, + { "OEMVendorID", "pn_dcp.suboption_device_oem_ven_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_device_oem_dev_id, + { "OEMDeviceID", "pn_dcp.suboption_device_oem_dev_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_dhcp, + { "Suboption", "pn_dcp.suboption_dhcp", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_dhcp), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_dhcp_device_id, + { "Device ID", "pn_dcp.suboption_dhcp_device_id", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_control, + { "Suboption", "pn_dcp.suboption_control", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_control), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_control_response, + { "Response", "pn_dcp.suboption_control_response", + FT_UINT8, BASE_DEC, VALS(pn_dcp_option), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_control_signal_value, + { "SignalValue", "pn_dcp.suboption_control_signal_value", + FT_UINT16, BASE_HEX, VALS(pn_dcp_suboption_control_signal_value), 0x0, + NULL, HFILL } }, + + { &hf_pn_dcp_suboption_deviceinitiative, + { "Suboption", "pn_dcp.suboption_deviceinitiative", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_deviceinitiative), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_deviceinitiative_value, + { "DeviceInitiativeValue", "pn_dcp.deviceinitiative_value", + FT_UINT16, BASE_DEC, VALS(pn_dcp_deviceinitiative_value), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_all, + { "Suboption", "pn_dcp.suboption_all", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_all), 0x0, + NULL, HFILL }}, + + { &hf_pn_dcp_suboption_manuf, + { "Suboption", "pn_dcp.suboption_manuf", + FT_UINT8, BASE_DEC, VALS(pn_dcp_suboption_manuf), 0x0, + NULL, HFILL }}, + + }; + + static gint *ett[] = { + &ett_pn_dcp, + &ett_pn_dcp_block + }; + + static ei_register_info ei[] = { + { &ei_pn_dcp_block_parse_error, { "pn_dcp.block_error.parse", PI_PROTOCOL, PI_ERROR, "parse error", EXPFILL }}, + { &ei_pn_dcp_block_error_unknown, { "pn_dcp.block_error.unknown", PI_RESPONSE_CODE, PI_CHAT, "Unknown", EXPFILL }}, + { &ei_pn_dcp_ip_conflict, { "pn_dcp.ip_conflict", PI_RESPONSE_CODE, PI_NOTE, "IP address conflict detected!", EXPFILL }}, + }; + + expert_module_t* expert_pn_dcp; + + 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)); + expert_pn_dcp = expert_register_protocol(proto_pn_dcp); + expert_register_field_array(expert_pn_dcp, ei, array_length(ei)); +} + +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, "PROFINET DCP IO", "pn_dcp_pn_rt", proto_pn_dcp, HEURISTIC_ENABLE); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn-mrp.c b/plugins/epan/profinet/packet-pn-mrp.c new file mode 100644 index 0000000000..7aa57c0ab5 --- /dev/null +++ b/plugins/epan/profinet/packet-pn-mrp.c @@ -0,0 +1,680 @@ +/* packet-pn-mrp.c + * Routines for PN-MRP (PROFINET Media Redundancy Protocol) + * packet dissection. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/oui.h> +#include <epan/etypes.h> +#include <epan/dissectors/packet-dcerpc.h> + +#include "packet-pn.h" + +void proto_register_pn_mrp(void); +void proto_reg_handoff_pn_mrp(void); + +static int proto_pn_mrp = -1; + +static int hf_pn_mrp_type = -1; +static int hf_pn_mrp_length = -1; +static int hf_pn_mrp_version = -1; +static int hf_pn_mrp_sequence_id = -1; +static int hf_pn_mrp_sa = -1; +static int hf_pn_mrp_prio = -1; +static int hf_pn_mrp_port_role = -1; +static int hf_pn_mrp_ring_state = -1; +static int hf_pn_mrp_interval = -1; +static int hf_pn_mrp_transition = -1; +static int hf_pn_mrp_time_stamp = -1; +static int hf_pn_mrp_blocked = -1; +static int hf_pn_mrp_domain_uuid = -1; +static int hf_pn_mrp_oui = -1; +static int hf_pn_mrp_ed1type = -1; +static int hf_pn_mrp_ed1_manufacturer_data = -1; +static int hf_pn_mrp_sub_tlv_header_type = -1; +static int hf_pn_mrp_sub_tlv_header_length = -1; +static int hf_pn_mrp_sub_option2 = -1; +static int hf_pn_mrp_other_mrm_prio = -1; +static int hf_pn_mrp_other_mrm_sa = -1; + +static gint ett_pn_mrp = -1; +static gint ett_pn_mrp_type = -1; +static gint ett_pn_sub_tlv = -1; + +static const value_string pn_mrp_block_type_vals[] = { + { 0x00, "MRP_End" }, + { 0x01, "MRP_Common" }, + { 0x02, "MRP_Test" }, + { 0x03, "MRP_TopologyChange" }, + { 0x04, "MRP_LinkDown" }, + { 0x05, "MRP_LinkUp" }, + { 0x06, "MRP_InTest" }, + { 0x07, "MRP_InTopologyChange" }, + { 0x08, "MRP_InLinkDown" }, + { 0x09, "MRP_InLinkUp" }, + { 0x0A, "MRP_InLinkStatusPoll" }, + /*0x0B - 0x7E Reserved */ + { 0x7F, "MRP_Option (Organizationally Specific)"}, + { 0, NULL }, +}; + +static const value_string pn_mrp_oui_vals[] = { + { OUI_PROFINET, "PROFINET" }, + { OUI_SIEMENS, "SIEMENS" }, + + { 0, NULL } +}; + + + +static const value_string pn_mrp_port_role_vals[] = { + { 0x0000, "Primary ring port" }, + { 0x0001, "Secondary ring port"}, + /*0x0002 - 0xFFFF Reserved */ + + { 0, NULL } +}; + +#if 0 +static const value_string pn_mrp_role_vals[] = { + { 0x0000, "Media redundancy disabled" }, + { 0x0001, "Media redundancy client" }, + { 0x0002, "Media redundancy manager" }, + { 0x0003, "Media redundancy manager (auto)" }, + /*0x0004 - 0xFFFF Reserved */ + + { 0, NULL } +}; +#endif + +static const value_string pn_mrp_ring_state_vals[] = { + { 0x0000, "Ring open" }, + { 0x0001, "Ring closed"}, + /*0x0002 - 0xFFFF Reserved */ + + { 0, NULL } +}; + + +#if 0 +static const value_string pn_mrp_prio_vals[] = { + { 0x8000, "Default priority for redundancy manager" }, + + { 0, NULL } +}; +#endif + +static const value_string pn_mrp_sub_tlv_header_type_vals[] = { + { 0x00, "End" }, + { 0x01, "MRP_TestMgrNAck" }, + { 0x02, "MRP_TestPropagate" }, + { 0x03, "MRP_AutoMgr" }, + { 0, NULL }, +}; + +static int +dissect_PNMRP_Common(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_) +{ + guint16 sequence_id; + e_guid_t uuid; + + + /* MRP_SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_sequence_id, &sequence_id); + + /* MRP_DomainUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_mrp_domain_uuid, &uuid); + + return offset; +} + + +static int +dissect_PNMRP_Link(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_) +{ + guint8 mac[6]; + guint16 port_role; + guint16 interval; + guint16 blocked; + proto_item *sub_item; + + /* MRP_SA */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac); + + /* MRP_PortRole */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_port_role, &port_role); + + /* MRP_Interval */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval, &sub_item); + if (tree) + { + proto_item_append_text(sub_item," Interval for next topology change event (in ms)"); + if (interval <0x07D1) + proto_item_append_text(sub_item," Mandatory"); + else + proto_item_append_text(sub_item," Optional"); + } + + /* MRP_Blocked */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_blocked, &blocked, &sub_item); + if (tree) + { + if (blocked == 0) + proto_item_append_text(sub_item," The MRC is not able to receive and forward frames to port in state blocked"); + else + if (blocked == 1) + proto_item_append_text(sub_item," The MRC is able to receive and forward frames to port in state blocked"); + else + proto_item_append_text(sub_item," Reserved"); + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + return offset; +} + +static const char * mrp_Prio2msg(guint16 prio) +{ + + if (prio == 0x0000) + return(" Highest priority redundancy manager"); + if ((prio >= 0x1000) && (prio <= 0x7000)) + return(" High priorities"); + if (prio == 0x8000) + return(" Default priority for redundancy manager"); + if ((prio >= 0x8001) && (prio <= 0x8FFF)) + return(" Low priorities for redundancy manager"); + if ((prio >= 0x9000) && (prio <= 0x9FFF)) + return(" High priorities for redundancy manager (auto)"); + if (prio == 0xA000) + return(" Default priority for redundancy manager (auto)"); + if ((prio >= 0xA001) && (prio <= 0xF000)) + return(" Low priorities for redundancy manager (auto)"); + if (prio ==0xFFFF) + return(" Lowest priority for redundancy manager (auto)"); + + return(" Reserved"); +} + +static int +dissect_PNMRP_Test(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_) +{ + guint16 prio; + guint8 mac[6]; + guint16 port_role; + guint16 ring_state; + guint16 transition; + guint32 time_stamp; + proto_item *sub_item; + + + /* MRP_Prio */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio, &sub_item); + if (tree) + proto_item_append_text(sub_item, "%s", mrp_Prio2msg(prio)); + + /* MRP_SA */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac); + + /* MRP_PortRole */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_port_role, &port_role); + + /* MRP_RingState */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_ring_state, &ring_state); + + /* MRP_Transition */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_transition, &transition); + + /* MRP_TimeStamp */ + proto_tree_add_item_ret_uint(tree, hf_pn_mrp_time_stamp, tvb, offset, 4, ENC_BIG_ENDIAN, &time_stamp); + offset += 4; + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + return offset; +} + + +static int +dissect_PNMRP_TopologyChange(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_) +{ + guint16 prio; + guint8 mac[6]; + guint16 interval; + proto_item *sub_item; + + + /* MRP_Prio */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_prio, &prio, &sub_item); + if (tree) + proto_item_append_text(sub_item, "%s", mrp_Prio2msg(prio)); + + /* MRP_SA */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrp_sa, mac); + + /* MRP_Interval */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, tree, hf_pn_mrp_interval, &interval, &sub_item); + if (tree) + { + proto_item_append_text(sub_item," Interval for next topology change event (in ms) "); + if (interval <0x07D1) + proto_item_append_text(sub_item,"Mandatory"); + else + proto_item_append_text(sub_item,"Optional"); + } + /* Padding */ + /*offset = dissect_pn_align4(tvb, offset, pinfo, tree);*/ + + return offset; +} + +static int +dissect_PNMRP_Ed1ManufacturerData(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree, guint8 *pLength) +{ + guint16 u16MrpEd1ManufacturerData; + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_ed1_manufacturer_data, + &u16MrpEd1ManufacturerData); + *pLength -= 2; + return offset; +} + +static int +dissect_PNMRP_SubOption2(tvbuff_t *tvb, int offset, +packet_info *pinfo, proto_tree *tree) +{ + guint8 u8SubType; + guint8 u8Sublength; + proto_item *sub_item; + proto_tree *sub_tree; + guint16 u16Prio; + guint16 u16OtherPrio; + guint8 mac[6]; + guint8 otherMac[6]; + + sub_item = proto_tree_add_item(tree, hf_pn_mrp_sub_option2, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_sub_tlv); + + /* + MRP_SubTLVHeader (Type=0x01 or Type=0x02, Length = 0x12), + MRP_Prio, + MRP_SA, + MRP_OtherMRMPrio, + MRP_OtherMRMSA, + Padding (=0x00,0x00) + */ + /* MRP_SubTLVHeader.Type */ + offset = dissect_pn_uint8(tvb, offset, pinfo, sub_tree, hf_pn_mrp_sub_tlv_header_type, &u8SubType); + + /* MRP_SubTLVHeader.Length */ + offset = dissect_pn_uint8(tvb, offset, pinfo, sub_tree, hf_pn_mrp_sub_tlv_header_length, &u8Sublength); + + if (u8SubType == 0x00) + { + // IEC area: 0x00: MRP_End; + return offset; + } + else if (u8SubType == 0x01) + { + // IEC area: 0x01: MRP_TestMgrNAck; + + /* MRP_Prio */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, sub_tree, hf_pn_mrp_prio, &u16Prio, &sub_item); + proto_item_append_text(sub_item, "%s", mrp_Prio2msg(u16Prio)); + + /* MRP_SA */ + offset = dissect_pn_mac(tvb, offset, pinfo, sub_tree, hf_pn_mrp_sa, mac); + + /* MRP_OtherMRMPrio */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, sub_tree, hf_pn_mrp_other_mrm_prio, + &u16OtherPrio, &sub_item); + proto_item_append_text(sub_item, "%s", mrp_Prio2msg(u16OtherPrio)); + + /* MRP_OtherMRMSA */ + offset = dissect_pn_mac(tvb, offset, pinfo, sub_tree, hf_pn_mrp_other_mrm_sa, otherMac); + + offset = dissect_pn_align4(tvb, offset, pinfo, sub_tree); + } + else if (u8SubType == 0x02) + { + /* MRP_Prio */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, sub_tree, hf_pn_mrp_prio, &u16Prio, &sub_item); + proto_item_append_text(sub_item, "%s", mrp_Prio2msg(u16Prio)); + + /* MRP_SA */ + offset = dissect_pn_mac(tvb, offset, pinfo, sub_tree, hf_pn_mrp_sa, mac); + + /* MRP_OtherMRMPrio */ + offset = dissect_pn_uint16_ret_item(tvb, offset, pinfo, sub_tree, hf_pn_mrp_other_mrm_prio, + &u16OtherPrio, &sub_item); + proto_item_append_text(sub_item, "%s", mrp_Prio2msg(u16OtherPrio)); + + /* MRP_OtherMRMSA */ + offset = dissect_pn_mac(tvb, offset, pinfo, sub_tree, hf_pn_mrp_other_mrm_sa, otherMac); + + offset = dissect_pn_align4(tvb, offset, pinfo, sub_tree); + } + return offset; +} + +static int +dissect_PNMRP_Option(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 length) +{ + guint32 oui; + guint8 u8MrpEd1Type; + + /* OUI (organizational unique id) */ + offset = dissect_pn_oid(tvb, offset, pinfo,tree, hf_pn_mrp_oui, &oui); + + switch (oui) + { + case OUI_SIEMENS: + proto_item_append_text(item, "(SIEMENS)"); + length -= 3; + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_mrp_ed1type, &u8MrpEd1Type); + length -= 1; + switch (u8MrpEd1Type) + { + case 0x00: + offset = dissect_PNMRP_Ed1ManufacturerData(tvb, offset, pinfo, tree, &length); + break; + case 0x01: + case 0x02: + case 0x03: + break; + case 0x04: + offset = dissect_PNMRP_Ed1ManufacturerData(tvb, offset, pinfo, tree, &length); + break; + /* 0x05 to 0xFF*/ + default: + break; + } + //offset = dissect_PNMRP_Ed1ManufacturerData(tvb, offset, pinfo, tree, &length); + + if (length != 0) + { + offset = dissect_PNMRP_SubOption2(tvb, offset, pinfo, tree); + } + col_append_str(pinfo->cinfo, COL_INFO, "(Siemens)"); + break; + default: + proto_item_append_text(item, " (Unknown-OUI)"); + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length); + + } + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + return offset; +} + + +static int +dissect_PNMRP_PDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 version; + guint8 type; + guint8 length; + gint i; + tvbuff_t *new_tvb; + proto_item *sub_item; + proto_tree *sub_tree; + + /* MRP_Version */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrp_version, &version); + + /* the rest of the packet has 4byte alignment regarding to the beginning of the next TLV block! */ + /* XXX - do we have to free this new tvb below? */ + new_tvb = tvb_new_subset_remaining(tvb, offset); + offset = 0; + + for(i=0; tvb_reported_length_remaining(tvb, offset) > 0; i++) { + + sub_item = proto_tree_add_item(tree, hf_pn_mrp_type, new_tvb, offset, 1, ENC_BIG_ENDIAN); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_mrp_type); + + /* MRP_TLVHeader.Type */ + offset = dissect_pn_uint8(new_tvb, offset, pinfo, sub_tree, hf_pn_mrp_type, &type); + + /* MRP_TLVHeader.Length */ + offset = dissect_pn_uint8(new_tvb, offset, pinfo, sub_tree, hf_pn_mrp_length, &length); + + if (i != 0) { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + + proto_item_append_text(item, ", "); + } else { + proto_item_append_text(item, " "); + } + col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(type, pn_mrp_block_type_vals, "Unknown TLVType 0x%x")); + proto_item_append_text(item, "%s", val_to_str_const(type, pn_mrp_block_type_vals, "Unknown TLVType 0x%x")); + + switch(type) { + case 0x00: + /* no content */ + return offset; + break; + case 0x01: + offset = dissect_PNMRP_Common(new_tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x02: + offset = dissect_PNMRP_Test(new_tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x03: + offset = dissect_PNMRP_TopologyChange(new_tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x04: + case 0x05: /* dissection of up and down is identical! */ + offset = dissect_PNMRP_Link(new_tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x7f: + offset = dissect_PNMRP_Option(new_tvb, offset, pinfo, sub_tree, sub_item, length); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, sub_tree, length); + + } + } + + return offset; +} + + +/* Dissect MRP packets */ +static int +dissect_PNMRP(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + proto_item *ti = NULL; + proto_tree *mrp_tree = NULL; + + guint32 offset = 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-MRP"); + + /* Clear the information column on summary display */ + col_clear(pinfo->cinfo, COL_INFO); + + if (tree) + { + ti = proto_tree_add_item(tree, proto_pn_mrp, tvb, offset, -1, ENC_NA); + mrp_tree = proto_item_add_subtree(ti, ett_pn_mrp); + } + + dissect_PNMRP_PDU(tvb, offset, pinfo, mrp_tree, ti); + return tvb_captured_length(tvb); +} + + +void +proto_register_pn_mrp (void) +{ + static hf_register_info hf[] = { + { &hf_pn_mrp_type, + { "MRP_TLVHeader.Type", "pn_mrp.type", + FT_UINT8, BASE_HEX, VALS(pn_mrp_block_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_length, + { "MRP_TLVHeader.Length", "pn_mrp.length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_version, + { "MRP_Version", "pn_mrp.version", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_sequence_id, + { "MRP_SequenceID", "pn_mrp.sequence_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Unique sequence number to each outstanding service request", HFILL }}, + + { &hf_pn_mrp_sa, + { "MRP_SA", "pn_mrp.sa", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_prio, + { "MRP_Prio", "pn_mrp.prio", + FT_UINT16, BASE_HEX, 0, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_port_role, + { "MRP_PortRole", "pn_mrp.port_role", + FT_UINT16, BASE_HEX, VALS(pn_mrp_port_role_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_ring_state, + { "MRP_RingState", "pn_mrp.ring_state", + FT_UINT16, BASE_HEX, VALS(pn_mrp_ring_state_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_interval, + { "MRP_Interval", "pn_mrp.interval", + FT_UINT16, BASE_DEC, NULL, 0x0, + "Interval for next topology change event (in ms)", HFILL }}, + + { &hf_pn_mrp_transition, + { "MRP_Transition", "pn_mrp.transition", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Number of transitions between media redundancy lost and ok states", HFILL }}, + + { &hf_pn_mrp_time_stamp, + { "MRP_TimeStamp [ms]", "pn_mrp.time_stamp", + FT_UINT32, BASE_HEX, NULL, 0x0, + "Actual counter value of 1ms counter", HFILL }}, + + { &hf_pn_mrp_blocked, + { "MRP_Blocked", "pn_mrp.blocked", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_domain_uuid, + { "MRP_DomainUUID", "pn_mrp.domain_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_oui, + { "MRP_ManufacturerOUI", "pn_mrp.oui", + FT_UINT24, BASE_HEX, VALS(pn_mrp_oui_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_ed1type, + { "MRP_Ed1Type", "pn_mrp.ed1type", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_ed1_manufacturer_data, + { "MRP_Ed1ManufacturerData", "pn_mrp.ed1manufacturerdata", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_sub_option2, + { "MRP_SubOption2", "pn_mrp.sub_option2", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } }, + + { &hf_pn_mrp_sub_tlv_header_type, + { "MRP_SubTLVHeader.Type", "pn_mrp.sub_type", + FT_UINT8, BASE_HEX, VALS(pn_mrp_sub_tlv_header_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_sub_tlv_header_length, + { "MRP_SubTLVHeader.Length", "pn_mrp.sub_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_other_mrm_prio, + { "MRP_OtherMRMPrio", "pn_mrp.other_mrm_prio", + FT_UINT16, BASE_HEX, 0, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrp_other_mrm_sa, + { "MRP_OtherMRMSA", "pn_mrp.other_mrm_sa", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL }} + }; + + static gint *ett[] = { + &ett_pn_mrp, + &ett_pn_mrp_type, + &ett_pn_sub_tlv + }; + + proto_pn_mrp = proto_register_protocol ("PROFINET MRP", "PN-MRP", "pn_mrp"); + proto_register_field_array (proto_pn_mrp, hf, array_length (hf)); + proto_register_subtree_array (ett, array_length (ett)); +} + + +void +proto_reg_handoff_pn_mrp (void) +{ + dissector_handle_t mrp_handle; + + + mrp_handle = create_dissector_handle(dissect_PNMRP,proto_pn_mrp); + dissector_add_uint("ethertype", ETHERTYPE_MRP, mrp_handle); + +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn-mrrt.c b/plugins/epan/profinet/packet-pn-mrrt.c new file mode 100644 index 0000000000..269fe015dd --- /dev/null +++ b/plugins/epan/profinet/packet-pn-mrrt.c @@ -0,0 +1,259 @@ +/* packet-pn-mrrt.c + * Routines for PN-MRRT (PROFINET Media Redundancy for cyclic realtime data) + * packet dissection. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/dissectors/packet-dcerpc.h> + +#include "packet-pn.h" + +void proto_register_pn_mrrt(void); +void proto_reg_handoff_pn_mrrt(void); + +static int proto_pn_mrrt = -1; + +static int hf_pn_mrrt_sequence_id = -1; +static int hf_pn_mrrt_domain_uuid = -1; +static int hf_pn_mrrt_type = -1; +static int hf_pn_mrrt_length = -1; +static int hf_pn_mrrt_version = -1; +static int hf_pn_mrrt_sa = -1; + + +static gint ett_pn_mrrt = -1; + + + +static const value_string pn_mrrt_block_type_vals[] = { + { 0x00, "End" }, + { 0x01, "Common" }, + { 0x02, "Test" }, + /*0x03 - 0x7E Reserved */ + { 0x7F, "Organizationally Specific"}, + { 0, NULL }, +}; + + + + +static int +dissect_PNMRRT_Common(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 length _U_) +{ + guint16 sequence_id; + e_guid_t uuid; + + + /* MRRT_SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrrt_sequence_id, &sequence_id); + + /* MRRT_DomainUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_mrrt_domain_uuid, &uuid); + + col_append_str(pinfo->cinfo, COL_INFO, "Common"); + + proto_item_append_text(item, "Common"); + + return offset; +} + + +static int +dissect_PNMRRT_Test(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint8 length _U_) +{ + guint8 mac[6]; + + + /* MRRT_SA */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_mrrt_sa, mac); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + col_append_str(pinfo->cinfo, COL_INFO, "Test"); + + proto_item_append_text(item, "Test"); + + return offset; +} + +static int +dissect_PNMRRT_PDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 version; + guint8 type; + guint8 length; + gint i = 0; + + + /* MRRT_Version */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_mrrt_version, &version); + + while (tvb_reported_length_remaining(tvb, offset) > 0) { + /* MRRT_TLVHeader.Type */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_mrrt_type, &type); + + /* MRRT_TLVHeader.Length */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_mrrt_length, &length); + + + if (i != 0) { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + + proto_item_append_text(item, ", "); + } + + i++; + + switch(type) { + case 0x00: + /* no content */ + col_append_str(pinfo->cinfo, COL_INFO, "End"); + proto_item_append_text(item, "End"); + return offset; + break; + case 0x01: + offset = dissect_PNMRRT_Common(tvb, offset, pinfo, tree, item, length); + break; + case 0x02: + offset = dissect_PNMRRT_Test(tvb, offset, pinfo, tree, item, length); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length); + + col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TLVType 0x%x", type); + proto_item_append_text(item, "Unknown TLVType 0x%x", type); + break; + } + } + + return offset; +} + + +/* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */ +static gboolean +dissect_PNMRRT_Data_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + void *data) +{ + /* the tvb will NOT contain the frame_id here, so get it from dissector data! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + proto_item *item; + proto_tree *mrrt_tree; + int offset = 0; + guint32 u32SubStart; + + + /* frame id must be in valid range (MRRT) */ + if (u16FrameID != 0xFF60) { + /* we are not interested in this packet */ + return FALSE; + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-MRRT"); + col_clear(pinfo->cinfo, COL_INFO); + + /* subtree for MRRT */ + item = proto_tree_add_protocol_format(tree, proto_pn_mrrt, tvb, 0, 0, "PROFINET MRRT, "); + mrrt_tree = proto_item_add_subtree(item, ett_pn_mrrt); + u32SubStart = offset; + + offset = dissect_PNMRRT_PDU(tvb, offset, pinfo, mrrt_tree, item); + + proto_item_set_len(item, offset - u32SubStart); + + return TRUE; +} + + +void +proto_register_pn_mrrt (void) +{ + static hf_register_info hf[] = { + + { &hf_pn_mrrt_type, + { "Type", "pn_mrrt.type", + FT_UINT8, BASE_HEX, VALS(pn_mrrt_block_type_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_mrrt_length, + { "Length", "pn_mrrt.length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrrt_version, + { "Version", "pn_mrrt.version", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrrt_sequence_id, + { "SequenceID", "pn_mrrt.sequence_id", + FT_UINT16, BASE_HEX, NULL, 0x0, + "Unique sequence number to each outstanding service request", HFILL }}, + + { &hf_pn_mrrt_sa, + { "SA", "pn_mrrt.sa", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_mrrt_domain_uuid, + { "DomainUUID", "pn_mrrt.domain_uuid", + FT_GUID, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + }; + + + static gint *ett[] = { + &ett_pn_mrrt + }; + + proto_pn_mrrt = proto_register_protocol ("PROFINET MRRT", "PN-MRRT", "pn_mrrt"); + proto_register_field_array (proto_pn_mrrt, hf, array_length (hf)); + proto_register_subtree_array (ett, array_length (ett)); +} + + +void +proto_reg_handoff_pn_mrrt (void) +{ + + /* register ourself as an heuristic pn-rt payload dissector */ + heur_dissector_add("pn_rt", dissect_PNMRRT_Data_heur, "PROFINET MRRT IO", "pn_mrrt_pn_rt", proto_pn_mrrt, HEURISTIC_ENABLE); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn-ptcp.c b/plugins/epan/profinet/packet-pn-ptcp.c new file mode 100644 index 0000000000..d7771f3d06 --- /dev/null +++ b/plugins/epan/profinet/packet-pn-ptcp.c @@ -0,0 +1,1105 @@ +/* packet-pn-ptcp.c + * Routines for PN-PTCP (PROFINET Precision Time Clock Protocol) + * packet dissection. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/oui.h> +#include <epan/dissectors/packet-dcerpc.h> + +#include "packet-pn.h" + +void proto_register_pn_ptcp(void); +void proto_reg_handoff_pn_ptcp(void); + +static int proto_pn_ptcp = -1; + +static int hf_pn_ptcp_header = -1; +static int hf_pn_ptcp_block = -1; +static int hf_pn_ptcp_block_tlvheader = -1; + +static int hf_pn_ptcp_res1 = -1; +static int hf_pn_ptcp_res2 = -1; +static int hf_pn_ptcp_delay10ns = -1; +static int hf_pn_ptcp_seq_id = -1; +static int hf_pn_ptcp_delay1ns_byte = -1; +static int hf_pn_ptcp_delay1ns_fup = -1; +static int hf_pn_ptcp_delay1ns = -1; + +static int hf_pn_ptcp_tl_length = -1; +static int hf_pn_ptcp_tl_type = -1; + +static int hf_pn_ptcp_master_source_address = -1; +static int hf_pn_ptcp_subdomain_uuid = -1; + +static int hf_pn_ptcp_port_mac_address = -1; + +static int hf_pn_ptcp_t2portrxdelay = -1; +static int hf_pn_ptcp_t3porttxdelay = -1; + +static int hf_pn_ptcp_t2timestamp = -1; + +static int hf_pn_ptcp_epoch_number = -1; +static int hf_pn_ptcp_seconds = -1; +static int hf_pn_ptcp_nanoseconds = -1; + +static int hf_pn_ptcp_flags = -1; +static int hf_pn_ptcp_currentutcoffset = -1; + +static int hf_pn_ptcp_master_priority1 = -1; +static int hf_pn_ptcp_master_priority_level = -1; +static int hf_pn_ptcp_master_priority1_res = -1; +static int hf_pn_ptcp_master_priority1_act =-1; + +static int hf_pn_ptcp_master_priority2 = -1; +static int hf_pn_ptcp_clock_class = -1; +static int hf_pn_ptcp_clock_accuracy = -1; +static int hf_pn_ptcp_clockvariance = -1; + +static int hf_pn_ptcp_oui = -1; +static int hf_pn_ptcp_profinet_subtype = -1; +static int hf_pn_ptcp_irdata_uuid = -1; + +static gint ett_pn_ptcp = -1; +static gint ett_pn_ptcp_header = -1; +static gint ett_pn_ptcp_block = -1; +static gint ett_pn_ptcp_block_header = -1; + +#define OUI_PROFINET_MULTICAST 0x010ECF /* PROFIBUS Nutzerorganisation e.V. */ + + +#define PN_PTCP_BT_END 0x00 +#define PN_PTCP_BT_SUBDOMAIN 0x01 +#define PN_PTCP_BT_TIME 0x02 +#define PN_PTCP_BT_TIME_EXTENSION 0x03 +#define PN_PTCP_BT_MASTER 0x04 +#define PN_PTCP_BT_PORT_PARAMETER 0x05 +#define PN_PTCP_BT_DELAY_PARAMETER 0x06 +#define PN_PTCP_BT_PORT_TIME 0x07 +#define PN_PTCP_BT_OPTION 0x7F +#define PN_PTCP_BT_RTDATA 0x7F + + +static const value_string pn_ptcp_block_type[] = { + { PN_PTCP_BT_END, "End" }, + { PN_PTCP_BT_SUBDOMAIN, "Subdomain"}, + { PN_PTCP_BT_TIME, "Time"}, + { PN_PTCP_BT_TIME_EXTENSION, "TimeExtension"}, + { PN_PTCP_BT_MASTER, "Master"}, + { PN_PTCP_BT_PORT_PARAMETER, "PortParameter"}, + { PN_PTCP_BT_DELAY_PARAMETER, "DelayParameter"}, + { PN_PTCP_BT_PORT_TIME, "PortTime"}, + /*0x08 - 0x7E Reserved */ + { PN_PTCP_BT_OPTION, "Organizationally Specific"}, + { 0, NULL } +}; + +static const value_string pn_ptcp_oui_vals[] = { + { OUI_PROFINET, "PROFINET" }, + { OUI_PROFINET_MULTICAST, "PROFINET" }, + { 0, NULL } +}; + +static const value_string pn_ptcp_master_prio1_vals[] = { + { 0x00, "Sync slave" }, + { 0x01, "Primary master" }, + { 0x02, "Secondary master" }, + { 0x03, "Reserved" }, + { 0x04, "Reserved" }, + { 0x05, "Reserved" }, + { 0x06, "Reserved" }, + { 0x07, "Reserved" }, + { 0, NULL } +}; + +static const value_string pn_ptcp_master_prio1_levels[] = { + { 0x00, "Level 0 (highest)" }, + { 0x01, "Level 1" }, + { 0x02, "Level 2" }, + { 0x03, "Level 3" }, + { 0x04, "Level 4" }, + { 0x05, "Level 5" }, + { 0x06, "Level 6" }, + { 0x07, "Level 7 (lowest)" }, + { 0, NULL } +}; + +static const value_string pn_ptcp_master_prio1_vals_active[] = { + { 0x00, "inactive" }, + { 0x01, "active" }, + { 0, NULL } +}; + +#if 0 +static const value_string pn_ptcp_master_prio1_short_vals[] = { + { 0x01, "Primary" }, + { 0x02, "Secondary" }, + { 0, NULL } +}; +#endif + +static const value_string pn_ptcp_master_prio2_vals[] = { + { 0xFF, "Default" }, + { 0, NULL } +}; + +static const value_string pn_ptcp_clock_class_vals[] = { + { 0xFF, "Slave-only clock" }, + { 0, NULL } +}; + +static const value_string pn_ptcp_clock_accuracy_vals[] = { + { 0x20, "25ns" }, + { 0x21, "100ns (Default)" }, + { 0x22, "250ns" }, + { 0x23, "1us" }, + { 0x24, "2.5us" }, + { 0x25, "10us" }, + { 0x26, "25us" }, + { 0x27, "100us" }, + { 0x28, "250us" }, + { 0x29, "1ms" }, + { 0xFE, "Unknown" }, + { 0, NULL } +}; + +static const value_string pn_ptcp_profinet_subtype_vals[] = { + { 0x01, "RTData" }, + { 0, NULL } +}; + + + + +static int +dissect_PNPTCP_TLVHeader(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, guint16 *type, guint16 *length) +{ + guint16 tl_type; + guint16 tl_length; + + + /* Type */ + dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_type, &tl_type); + *type = tl_type >> 9; + + /* Length */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_tl_length, &tl_length); + *length = tl_length & 0x1FF; + + return offset; +} + + +static int +dissect_PNPTCP_Subdomain(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID) +{ + guint8 mac[6]; + e_guid_t uuid; + + + /* MasterSourceAddress */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_master_source_address, mac); + + /* SubdomainUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_subdomain_uuid, &uuid); + + if ((u16FrameID == 0xff00) || (u16FrameID == 0xff01)) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", Master=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + proto_item_append_text(item, ": MasterSource=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + proto_item_append_text(item, ", Subdomain=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.data1, uuid.data2, uuid.data3, + uuid.data4[0], uuid.data4[1], + uuid.data4[2], uuid.data4[3], + uuid.data4[4], uuid.data4[5], + uuid.data4[6], uuid.data4[7]); + + return offset; +} + + +static int +dissect_PNPTCP_Time(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 EpochNumber; + guint32 Seconds; + guint32 NanoSeconds; + + + /* EpochNumber */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_epoch_number, &EpochNumber); + + /* Seconds */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_seconds, tvb, offset, 4, ENC_BIG_ENDIAN, &Seconds); + offset += 4; + + /* NanoSeconds */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_nanoseconds, tvb, offset, 4, ENC_BIG_ENDIAN, &NanoSeconds); + offset += 4; + + proto_item_append_text(item, ": Seconds=%u NanoSeconds=%u EpochNumber=%u", + Seconds, NanoSeconds, EpochNumber); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Time: %4us %09uns, Epoch: %u", + Seconds, NanoSeconds, EpochNumber); + + return offset; +} + + +static int +dissect_PNPTCP_TimeExtension(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint16 Flags; + guint16 CurrentUTCOffset; + + + /* Flags */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_flags, &Flags); + + /* CurrentUTCOffset */ + offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_ptcp_currentutcoffset, &CurrentUTCOffset); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + proto_item_append_text(item, ": Flags=0x%x, CurrentUTCOffset=%u", Flags, CurrentUTCOffset); + + return offset; +} + + +static int +dissect_PNPTCP_Master(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint8 MasterPriority1; + guint8 MasterPriority2; + guint8 ClockClass; + guint8 ClockAccuracy; + gint16 ClockVariance; + + + /* MasterPriority1 is a bit field */ + /* Bit 0 - 2: PTCP_MasterPriority1.Priority */ + dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1, &MasterPriority1); + /* Bit 3 - 5: PTCP_MasterPriority1.Level */ + dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority_level, &MasterPriority1); + /* Bit 6: PTCP_MasterPriority1.Reserved */ + dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_res, &MasterPriority1); + /* Bit 7: PTCP_MasterPriority1.Active */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority1_act, &MasterPriority1); + + /* MasterPriority2 */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_master_priority2, &MasterPriority2); + + /* ClockClass */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_class, &ClockClass); + + /* ClockAccuracy */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_clock_accuracy, &ClockAccuracy); + + /* ClockVariance */ + offset = dissect_pn_int16(tvb, offset, pinfo, tree, hf_pn_ptcp_clockvariance, &ClockVariance); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Prio1=\"%s\"", + val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)")); + + if ((MasterPriority1 & 0x80) == 0) { + proto_item_append_text(item, ": Prio1=\"%s\", Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d", + val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"), + val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"), + val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"), + val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"), + ClockVariance); + } + else { + col_append_str(pinfo->cinfo, COL_INFO, " active"); + proto_item_append_text(item, ": Prio1=\"%s\" is active, Prio2=%s, Clock: Class=\"%s\", Accuracy=%s, Variance=%d", + val_to_str(MasterPriority1 & 0x7, pn_ptcp_master_prio1_vals, "(Reserved: 0x%x)"), + val_to_str(MasterPriority2, pn_ptcp_master_prio2_vals, "(Reserved: 0x%x)"), + val_to_str(ClockClass, pn_ptcp_clock_class_vals, "(Reserved: 0x%x)"), + val_to_str(ClockAccuracy, pn_ptcp_clock_accuracy_vals, "(Reserved: 0x%x)"), + ClockVariance); + } + + + return offset; +} + + +static int +dissect_PNPTCP_PortParameter(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint32 t2portrxdelay; + guint32 t3porttxdelay; + + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* T2PortRxDelay */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_t2portrxdelay, tvb, offset, 4, ENC_BIG_ENDIAN, &t2portrxdelay); + offset += 4; + + /* T3PortTxDelay */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_t3porttxdelay, tvb, offset, 4, ENC_BIG_ENDIAN, &t3porttxdelay); + offset += 4; + + proto_item_append_text(item, ": T2PortRxDelay=%uns, T3PortTxDelay=%uns", + t2portrxdelay, t3porttxdelay); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", T2Rx=%uns, T3Tx=%uns", + t2portrxdelay, t3porttxdelay); + + return offset; +} + + +static int +dissect_PNPTCP_DelayParameter(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint8 mac[6]; + + + /* PortMACAddress */ + offset = dissect_pn_mac(tvb, offset, pinfo, tree, hf_pn_ptcp_port_mac_address, mac); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + + proto_item_append_text(item, ": PortMAC=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", PortMAC=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + return offset; +} + + +static int +dissect_PNPTCP_PortTime(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item) +{ + guint32 t2timestamp; + + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* T2TimeStamp */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_t2timestamp, tvb, offset, 4, ENC_BIG_ENDIAN, &t2timestamp); + offset += 4; + + proto_item_append_text(item, ": T2TimeStamp=%uns", t2timestamp); + + col_append_fstr(pinfo->cinfo, COL_INFO, ", T2TS=%uns", t2timestamp); + + return offset; +} + + +static int +dissect_PNPTCP_Option_PROFINET(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length) +{ + guint8 subType; + e_guid_t uuid; + + /* OUI already dissected! */ + + /* SubType */ + offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_ptcp_profinet_subtype, &subType); + length -= 1; + + switch (subType) { + case 1: /* RTData */ + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + /* IRDataUUID */ + offset = dissect_pn_uuid(tvb, offset, pinfo, tree, hf_pn_ptcp_irdata_uuid, &uuid); + proto_item_append_text(item, ": IRDataUUID=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.data1, uuid.data2, uuid.data3, + uuid.data4[0], uuid.data4[1], + uuid.data4[2], uuid.data4[3], + uuid.data4[4], uuid.data4[5], + uuid.data4[6], uuid.data4[7]); + + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length); + break; + } + + return offset; +} + + +static int +dissect_PNPTCP_Option(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 length) +{ + guint32 oui; + + + /* verify remaining TLV length */ + if (length < 4) + { + /* too short */ + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length); + return (offset); + } + + /* OUI (organizational unique id) */ + offset = dissect_pn_oid(tvb, offset, pinfo,tree, hf_pn_ptcp_oui, &oui); + length -= 3; + + switch (oui) + { + case OUI_PROFINET: + case OUI_PROFINET_MULTICAST: + proto_item_append_text(item, ": PROFINET"); + offset = dissect_PNPTCP_Option_PROFINET(tvb, offset, pinfo, tree, item, length); + break; + default: + /* SubType */ + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length); + } + + return (offset); +} + + +static int +dissect_PNPTCP_block(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item _U_, gboolean *end, guint16 u16FrameID) +{ + guint16 type; + guint16 length; + + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *tlvheader_item; + proto_tree *tlvheader_tree; + guint32 u32SubStart; + + + *end = FALSE; + + /* block subtree */ + sub_item = proto_tree_add_item(tree, hf_pn_ptcp_block, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_ptcp_block); + u32SubStart = offset; + + /* tlvheader subtree */ + tlvheader_item = proto_tree_add_item(sub_tree, hf_pn_ptcp_block_tlvheader, tvb, offset, 2 /* len */, ENC_NA); + tlvheader_tree = proto_item_add_subtree(tlvheader_item, ett_pn_ptcp_block_header); + + offset = dissect_PNPTCP_TLVHeader(tvb, offset, pinfo, tlvheader_tree, sub_item, &type, &length); + + proto_item_set_text(sub_item, "%s", + val_to_str(type, pn_ptcp_block_type, "Unknown")); + + proto_item_append_text(tlvheader_item, ": Type=%s (%x), Length=%u", + val_to_str(type, pn_ptcp_block_type, "Unknown"), type, length); + + switch (type) { + case 0x00: /* End, no content */ + *end = TRUE; + break; + case 0x01: /* Subdomain */ + dissect_PNPTCP_Subdomain(tvb, offset, pinfo, sub_tree, sub_item, u16FrameID); + break; + case 0x02: /* Time */ + dissect_PNPTCP_Time(tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x03: /* TimeExtension */ + dissect_PNPTCP_TimeExtension(tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x04: /* Master */ + dissect_PNPTCP_Master(tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x05: /* PortParameter */ + dissect_PNPTCP_PortParameter(tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x06: /* DelayParameter */ + dissect_PNPTCP_DelayParameter(tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x07: /* PortTime */ + dissect_PNPTCP_PortTime(tvb, offset, pinfo, sub_tree, sub_item); + break; + case 0x7F: /* Organizational Specific */ + dissect_PNPTCP_Option(tvb, offset, pinfo, sub_tree, sub_item, length); + break; + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, length); + } + offset += length; + + proto_item_set_len(sub_item, offset - u32SubStart); + + return offset; +} + + +static int +dissect_PNPTCP_blocks(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID) +{ + gboolean end = FALSE; + + /* as long as we have some bytes, try a new block */ + while (!end) { + offset = dissect_PNPTCP_block(tvb, offset, pinfo, tree, item, &end, u16FrameID); + } + + return offset; +} + + +static int +dissect_PNPTCP_FollowUpPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, + const char *name, const char *name_short) +{ + proto_item *header_item; + proto_tree *header_tree; + guint16 seq_id; + gint32 delay1ns_fup; + + + /* dissect the header */ + header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA); + header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header); + + /* Padding 12 bytes */ + offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12); + + /* SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, header_tree); + + /* Delay1ns_FUP */ + proto_tree_add_item_ret_int(header_tree, hf_pn_ptcp_delay1ns_fup, tvb, offset, 4, ENC_BIG_ENDIAN, &delay1ns_fup); + offset += 4; + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11dns", name, seq_id, delay1ns_fup); + proto_item_append_text(item, "%s: Sequence=%u, Delay=%dns", name_short, seq_id, delay1ns_fup); + proto_item_append_text(header_item, ": Sequence=%u, Delay=%dns", seq_id, delay1ns_fup); + + + /* dissect the TLV blocks */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID); + + return offset; +} + + +static int +dissect_PNPTCP_RTSyncPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, + const char *name, const char *name_short) +{ + proto_item *header_item; + proto_tree *header_tree; + guint32 delay10ns; + guint16 seq_id; + guint8 delay1ns_8; + guint64 delay1ns_64; + guint32 delay1ns_32; + guint32 delayms; + + + header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA); + header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header); + + /* Reserved_1 */ + proto_tree_add_item(tree, hf_pn_ptcp_res1, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Reserved_2 */ + proto_tree_add_item(tree, hf_pn_ptcp_res2, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Delay10ns */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_delay10ns, tvb, offset, 4, ENC_BIG_ENDIAN, &delay10ns); + offset += 4; + + /* SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id); + + /* Delay1ns */ + offset = dissect_pn_uint8(tvb, offset, pinfo, header_tree, hf_pn_ptcp_delay1ns_byte, &delay1ns_8); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, header_tree); + + /* Delay1ns */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_delay1ns, tvb, offset, 4, ENC_BIG_ENDIAN, &delay1ns_32); + offset += 4; + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, tree); + + + delay1ns_64 = ((guint64) delay10ns) * 10 + delay1ns_8 + delay1ns_32; + delayms = (guint32) (delay1ns_64 / (1000 * 1000)); + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11" G_GINT64_MODIFIER "uns", + name, seq_id, delay1ns_64); + proto_item_append_text(item, "%s: Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns", + name_short, seq_id, delay1ns_64); + proto_item_append_text(header_item, ": Sequence=%u, Delay=%" G_GINT64_MODIFIER "uns", + seq_id, delay1ns_64); + + if (delay1ns_64 != 0) + proto_item_append_text(header_item, " (%u.%03u,%03u,%03u sec)", + delayms / 1000, + delayms % 1000, + (delay10ns % (1000*100)) / 100, + delay10ns % 100 * 10 + delay1ns_8); + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID); + + return offset; +} + + +static int +dissect_PNPTCP_AnnouncePDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, + const char *name, const char *name_short) +{ + proto_item *header_item; + proto_tree *header_tree; + guint16 seq_id; + + + /* dissect the header */ + header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA); + header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header); + + /* Padding 12 bytes */ + offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12); + + /* SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id); + + /* Padding 6 bytes */ + offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 6); + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u", name, seq_id); + proto_item_append_text(item, "%s: Sequence=%u", name_short, seq_id); + proto_item_append_text(header_item, ": Sequence=%u", seq_id); + + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID); + + return offset; +} + + +static int +dissect_PNPTCP_DelayPDU(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, proto_item *item, guint16 u16FrameID, + const char *name, const char *name_short) +{ + proto_item *header_item; + proto_tree *header_tree; + guint16 seq_id; + guint32 delay1ns; + + + /* dissect the header */ + header_item = proto_tree_add_item(tree, hf_pn_ptcp_header, tvb, offset, 20 /* len */, ENC_NA); + header_tree = proto_item_add_subtree(header_item, ett_pn_ptcp_header); + + /* Padding 12 bytes */ + offset = dissect_pn_padding(tvb, offset, pinfo, header_tree, 12); + + /* SequenceID */ + offset = dissect_pn_uint16(tvb, offset, pinfo, header_tree, hf_pn_ptcp_seq_id, &seq_id); + + /* Padding */ + offset = dissect_pn_align4(tvb, offset, pinfo, header_tree); + + /* Delay1ns_FUP */ + proto_tree_add_item_ret_uint(tree, hf_pn_ptcp_delay1ns, tvb, offset, 4, ENC_BIG_ENDIAN, &delay1ns); + offset += 4; + + col_append_fstr(pinfo->cinfo, COL_INFO, "%s, Seq=%3u, Delay=%11uns", name, seq_id, delay1ns); + proto_item_append_text(item, "%s: Sequence=%u, Delay=%uns", name_short, seq_id, delay1ns); + proto_item_append_text(header_item, ": Sequence=%u, Delay=%uns", seq_id, delay1ns); + + + /* dissect the PDU */ + offset = dissect_PNPTCP_blocks(tvb, offset, pinfo, tree, item, u16FrameID); + + return offset; +} + + +/* possibly dissect a PN-RT packet (frame ID must be in the appropriate range) */ +static gboolean +dissect_PNPTCP_Data_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + /* the tvb will NOT contain the frame_id here, so get it from dissector data! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + proto_item *item; + proto_tree *ptcp_tree; + int offset = 0; + guint32 u32SubStart; + + + /* frame id must be in valid range (acyclic Real-Time, PTCP) */ + /* 0x0000 - 0x007F: RTSyncPDU (with follow up) */ + /* 0x0080 - 0x00FF: RTSyncPDU (without follow up) */ + /* 0xFF00 - 0xFF1F: AnnouncePDU */ + /* 0xFF20 - 0xFF3F: FollowUpPDU */ + /* 0xFF40 - 0xFF5F: Delay...PDU */ + if ( ((u16FrameID >= 0x0100) && (u16FrameID < 0xFF00)) || (u16FrameID > 0xFF5F) ) { + /* we are not interested in this packet */ + return FALSE; + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-PTCP"); + col_clear(pinfo->cinfo, COL_INFO); + + /* subtree for PTCP */ + item = proto_tree_add_protocol_format(tree, proto_pn_ptcp, tvb, 0, 0, "PROFINET PTCP, "); + ptcp_tree = proto_item_add_subtree(item, ett_pn_ptcp); + u32SubStart = offset; + + switch (u16FrameID) { + /* range 1 (0x0000 - 0x007F) */ + /* 0x0000 - 0x001F reserved */ + case 0x0020: + offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "RTSync FU (Clock)", "RTSync FU (Clock)"); + break; + case 0x0021: + offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "RTSync FU (Time)", "RTSync FU (Time)"); + break; + /* 0x0022 - 0x007F reserved */ + + /* range 2 (0x0080 - 0x00FF) */ + case 0x0080: + offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "RTSync (Clock)", "RTSync (Clock)"); + break; + case 0x0081: + offset = dissect_PNPTCP_RTSyncPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "RTSync (Time)", "RTSync (Time)"); + break; + /* 0x0081 - 0x00FF reserved */ + + /* range 7 (0xFF00 - 0xFF5F) */ + case 0xff00: + offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "Announce (Clock)", "Announce (Clock)"); + break; + case 0xff01: + offset = dissect_PNPTCP_AnnouncePDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "Announce (Time)", "Announce (Time)"); + break; + /* 0xFF02 - 0xFF1F reserved */ + case 0xff20: + offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "FollowUp (Clock)", "FollowUp (Clock)"); + break; + case 0xff21: + offset = dissect_PNPTCP_FollowUpPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "FollowUp (Time)", "FollowUp (Time)"); + break; + /* 0xFF22 - 0xFF3F reserved */ + case 0xff40: + offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "DelayReq ", "DelayReq"); + break; + case 0xff41: + offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "DelayRes ", "DelayRes"); + break; + case 0xff42: + offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "DelayFuRes ", "DelayFuRes"); + break; + case 0xff43: + offset = dissect_PNPTCP_DelayPDU(tvb, offset, pinfo, ptcp_tree, item, u16FrameID, + "DelayRes ", "DelayRes"); + break; + /* 0xFF44 - 0xFF5F reserved */ + default: + offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset)); + + col_append_fstr(pinfo->cinfo, COL_INFO, "Reserved FrameID 0x%04x", u16FrameID); + + proto_item_append_text(item, "Reserved FrameID 0x%04x", u16FrameID); + + offset += tvb_captured_length_remaining(tvb, offset); + break; + } + + proto_item_set_len(item, offset - u32SubStart); + + return TRUE; +} + + +void +proto_register_pn_ptcp (void) +{ + static hf_register_info hf[] = { + { &hf_pn_ptcp_header, + { "Header", "pn_ptcp.header", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_block, + { "Block", "pn_ptcp.block", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_block_tlvheader, + { "TLVHeader", "pn_ptcp.tlvheader", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_res1, + { "Reserved 1", "pn_ptcp.res1", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_res2, + { "Reserved 2", "pn_ptcp.res2", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_delay10ns, + { "Delay10ns", "pn_ptcp.delay10ns", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_seq_id, + { "SequenceID", "pn_ptcp.sequence_id", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_delay1ns_byte, + { "Delay1ns_Byte", "pn_ptcp.delay1ns_byte", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_delay1ns, + { "Delay1ns", "pn_ptcp.delay1ns", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_delay1ns_fup, + { "Delay1ns_FUP", "pn_ptcp.delay1ns_fup", + FT_INT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_tl_length, + { "TypeLength.Length", "pn_ptcp.tl_length", + FT_UINT16, BASE_DEC, 0x0, 0x1FF, + NULL, HFILL }}, + + { &hf_pn_ptcp_tl_type, + { "TypeLength.Type", "pn_ptcp.tl_type", + FT_UINT16, BASE_DEC, 0x0, 0xFE00, + NULL, HFILL }}, + + + { &hf_pn_ptcp_master_source_address, + { "MasterSourceAddress", "pn_ptcp.master_source_address", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_subdomain_uuid, + { "SubdomainUUID", "pn_ptcp.subdomain_uuid", + FT_GUID, BASE_NONE, 0x0, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_port_mac_address, + { "PortMACAddress", "pn_ptcp.port_mac_address", + FT_ETHER, BASE_NONE, 0x0, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_t2portrxdelay, + { "T2PortRxDelay (ns)", "pn_ptcp.t2portrxdelay", + FT_UINT32, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_t3porttxdelay, + { "T3PortTxDelay (ns)", "pn_ptcp.t3porttxdelay", + FT_UINT32, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_t2timestamp, + { "T2TimeStamp (ns)", "pn_ptcp.t2timestamp", + FT_UINT32, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_epoch_number, + { "EpochNumber", "pn_ptcp.epoch_number", + FT_UINT16, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_seconds, + { "Seconds", "pn_ptcp.seconds", + FT_UINT32, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_nanoseconds, + { "NanoSeconds", "pn_ptcp.nanoseconds", + FT_UINT32, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_flags, + { "Flags", "pn_ptcp.flags", + FT_UINT16, BASE_HEX, 0x0, 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_currentutcoffset, + { "CurrentUTCOffset", "pn_ptcp.currentutcoffset", + FT_UINT16, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_master_priority1, + { "MasterPriority1.Priority", "pn_ptcp.master_priority1_prio", + FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals), 0x07, + NULL, HFILL }}, + + { &hf_pn_ptcp_master_priority_level, + { "MasterPriority1.Level", "pn_ptcp.master_priority1_level", + FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_levels), 0x38, + NULL, HFILL }}, + + { &hf_pn_ptcp_master_priority1_res, + { "MasterPriority1.Reserved", "pn_ptcp.master_priority1_res", + FT_UINT8, BASE_HEX, 0x0, 0x40, + NULL, HFILL }}, + + { &hf_pn_ptcp_master_priority1_act, + { "MasterPriority1.Active", "pn_ptcp.master_priority1_act", + FT_UINT8, BASE_HEX, VALS(pn_ptcp_master_prio1_vals_active), 0x80, + NULL, HFILL }}, + + { &hf_pn_ptcp_master_priority2, + { "MasterPriority2", "pn_ptcp.master_priority2", + FT_UINT8, BASE_DEC, VALS(pn_ptcp_master_prio2_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_clock_class, + { "ClockClass", "pn_ptcp.clock_class", + FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_class_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_clock_accuracy, + { "ClockAccuracy", "pn_ptcp.clock_accuracy", + FT_UINT8, BASE_DEC, VALS(pn_ptcp_clock_accuracy_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_clockvariance, + { "ClockVariance", "pn_ptcp.clockvariance", + FT_INT16, BASE_DEC, 0x0, 0x0, + NULL, HFILL }}, + + + { &hf_pn_ptcp_oui, + { "Organizationally Unique Identifier", "pn_ptcp.oui", + FT_UINT24, BASE_HEX, VALS(pn_ptcp_oui_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_ptcp_profinet_subtype, + { "Subtype", "pn_ptcp.subtype", + FT_UINT8, BASE_HEX, VALS(pn_ptcp_profinet_subtype_vals), 0x0, + "PROFINET Subtype", HFILL }}, + + + { &hf_pn_ptcp_irdata_uuid, + { "IRDataUUID", "pn_ptcp.irdata_uuid", + FT_GUID, BASE_NONE, 0x0, 0x0, + NULL, HFILL }}, + + }; + + static gint *ett[] = { + &ett_pn_ptcp, + &ett_pn_ptcp_header, + &ett_pn_ptcp_block, + &ett_pn_ptcp_block_header + }; + proto_pn_ptcp = proto_register_protocol ("PROFINET PTCP", "PN-PTCP", "pn_ptcp"); + proto_register_field_array (proto_pn_ptcp, hf, array_length (hf)); + proto_register_subtree_array (ett, array_length (ett)); +} + +void +proto_reg_handoff_pn_ptcp (void) +{ + /* register ourself as an heuristic pn-rt payload dissector */ + heur_dissector_add("pn_rt", dissect_PNPTCP_Data_heur, "PROFINET PTCP IO", "pn_ptcp_pn_rt", proto_pn_ptcp, HEURISTIC_ENABLE); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn-rt.c b/plugins/epan/profinet/packet-pn-rt.c new file mode 100644 index 0000000000..3e4e1f5f80 --- /dev/null +++ b/plugins/epan/profinet/packet-pn-rt.c @@ -0,0 +1,1171 @@ +/* packet-pn-rt.c + * Routines for pn-rt (PROFINET Real-Time) packet dissection. + * This is the base for other PROFINET protocols like IO, CBA, DCP, ... + * (the "content subdissectors" will register themselves using a heuristic) + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/reassemble.h> +#include <epan/prefs.h> +#include <epan/etypes.h> +#include <epan/expert.h> +#include <epan/crc16-tvb.h> +#include <epan/dissectors/packet-dcerpc.h> + +#include <wsutil/crc16-plain.h> +#include "packet-pn.h" + + +void proto_register_pn_rt(void); +void proto_reg_handoff_pn_rt(void); + +#define PROFINET_UDP_PORT 0x8892 + +/* Define the pn-rt proto */ +static int proto_pn_rt = -1; +static gboolean pnio_desegment = TRUE; + +/* Define many header fields for pn-rt */ +static int hf_pn_rt_frame_id = -1; +static int hf_pn_rt_cycle_counter = -1; +static int hf_pn_rt_transfer_status = -1; +static int hf_pn_rt_data_status = -1; +static int hf_pn_rt_data_status_ignore = -1; +static int hf_pn_rt_frame_info_type = -1; +static int hf_pn_rt_frame_info_function_meaning_input_conv = -1; +static int hf_pn_rt_frame_info_function_meaning_output_conv = -1; +static int hf_pn_rt_data_status_Reserved_2 = -1; +static int hf_pn_rt_data_status_ok = -1; +static int hf_pn_rt_data_status_operate = -1; +static int hf_pn_rt_data_status_res3 = -1; +static int hf_pn_rt_data_status_valid = -1; +static int hf_pn_rt_data_status_redundancy = -1; +static int hf_pn_rt_data_status_redundancy_output_cr = -1; +static int hf_pn_rt_data_status_redundancy_input_cr_state_is_backup = -1; +static int hf_pn_rt_data_status_redundancy_input_cr_state_is_primary = -1; +static int hf_pn_rt_data_status_primary = -1; + +static int hf_pn_rt_sf_crc16 = -1; +static int hf_pn_rt_sf_crc16_status = -1; +static int hf_pn_rt_sf = -1; +static int hf_pn_rt_sf_position = -1; +/* static int hf_pn_rt_sf_position_control = -1; */ +static int hf_pn_rt_sf_data_length = -1; +static int hf_pn_rt_sf_cycle_counter = -1; + +static int hf_pn_rt_frag = -1; +static int hf_pn_rt_frag_data_length = -1; +static int hf_pn_rt_frag_status = -1; +static int hf_pn_rt_frag_status_more_follows = -1; +static int hf_pn_rt_frag_status_error = -1; +static int hf_pn_rt_frag_status_fragment_number = -1; +static int hf_pn_rt_frag_data = -1; + + +/* + * Define the trees for pn-rt + * We need one tree for pn-rt itself and one for the pn-rt data status subtree + */ +static int ett_pn_rt = -1; +static int ett_pn_rt_data_status = -1; +static int ett_pn_rt_sf = -1; +static int ett_pn_rt_frag = -1; +static int ett_pn_rt_frag_status = -1; + +static expert_field ei_pn_rt_sf_crc16 = EI_INIT; + +/* + * Here are the global variables associated with + * the various user definable characteristics of the dissection + */ +/* Place summary in proto tree */ +static gboolean pn_rt_summary_in_tree = TRUE; + +/* heuristic to find the right pn-rt payload dissector */ +static heur_dissector_list_t heur_subdissector_list; + + +#if 0 +static const value_string pn_rt_position_control[] = { + { 0x00, "CRC16 and CycleCounter shall not be checked" }, + { 0x80, "CRC16 and CycleCounter valid" }, + { 0, NULL } +}; +#endif + +static const true_false_string tfs_pn_rt_ds_redundancy_output_cr = + { "Unknown", "Redundancy has no meaning for OutputCRs, it is set to the fixed value of zero" }; + +static const true_false_string tfs_pn_rt_ds_redundancy_input_cr_state_is_backup = + { "None primary AR of a given AR-set is present", "Default - One primary AR of a given AR-set is present" }; + +static const true_false_string tfs_pn_rt_ds_redundancy_input_cr_state_is_primary = + { "The ARState from the IO device point of view is Backup", "Default - The ARState from the IO device point of view is Primary" }; + +static const value_string pn_rt_frame_info_function_meaning_input_conv[] = { + {0x00, "Backup Acknowledge without actual data" }, + {0x02, "Primary Missing without actual data" }, + {0x04, "Backup Acknowledge with actual data independent from the Arstate" }, + {0x05, "Primary Acknowledge"}, + {0x06, "Primary Missing with actual data independent from the Arstate" }, + {0x07, "Primary Fault" }, + {0, NULL} +}; + +static const value_string pn_rt_frame_info_function_meaning_output_conv[] = { + { 0x04, "Backup Request" }, + { 0x05, "Primary Request" }, + { 0, NULL } +}; + +static const true_false_string tfs_pn_rt_ds_redundancy = + {"Redundancy has no meaning for OutputCRs / One primary AR of a given AR-set is present" , "None primary AR of a given AR-set is present" }; + +static const value_string pn_rt_frag_status_error[] = { + { 0x00, "reserved" }, + { 0x01, "reserved: invalid should be zero" }, + { 0, NULL } +}; + +static const value_string pn_rt_frag_status_more_follows[] = { + { 0x00, "Last fragment" }, + { 0x01, "More fragments follow" }, + { 0, NULL } +}; + +/* Copied and renamed from proto.c because global value_strings don't work for plugins */ +static const value_string plugin_proto_checksum_vals[] = { + { PROTO_CHECKSUM_E_BAD, "Bad" }, + { PROTO_CHECKSUM_E_GOOD, "Good" }, + { PROTO_CHECKSUM_E_UNVERIFIED, "Unverified" }, + { PROTO_CHECKSUM_E_NOT_PRESENT, "Not present" }, + + { 0, NULL } +}; + +static void +dissect_DataStatus(tvbuff_t *tvb, int offset, proto_tree *tree, packet_info *pinfo, guint8 u8DataStatus) +{ + proto_item *sub_item; + proto_tree *sub_tree; + guint8 u8DataValid; + guint8 u8Redundancy; + guint8 u8State; + conversation_t *conversation; + gboolean inputFlag = FALSE; + gboolean outputFlag = FALSE; + apduStatusSwitch *apdu_status_switch; + + u8State = (u8DataStatus & 0x01); + u8Redundancy = (u8DataStatus >> 1) & 0x01; + u8DataValid = (u8DataStatus >> 2) & 0x01; + + /* if PN Connect Request has been read, IOC mac is dl_src and IOD mac is dl_dst */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_UDP, 0, 0, 0); + + if (conversation != NULL) { + apdu_status_switch = (apduStatusSwitch*)conversation_get_proto_data(conversation, proto_pn_io_apdu_status); + if (apdu_status_switch != NULL && apdu_status_switch->isRedundancyActive) { + /* IOC -> IOD: OutputCR */ + if (addresses_equal(&(pinfo->src), conversation_key_addr1(conversation->key_ptr)) && addresses_equal(&(pinfo->dst), conversation_key_addr2(conversation->key_ptr))) { + outputFlag = TRUE; + inputFlag = FALSE; + } + /* IOD -> IOC: InputCR */ + if (addresses_equal(&(pinfo->dst), conversation_key_addr1(conversation->key_ptr)) && addresses_equal(&(pinfo->src), conversation_key_addr2(conversation->key_ptr))) { + inputFlag = TRUE; + outputFlag = FALSE; + } + } + } + + /* input conversation is found */ + if (inputFlag) + { + proto_tree_add_string_format_value(tree, hf_pn_rt_frame_info_type, tvb, + offset, 0, "Input", "Input Frame (IO_Device -> IO_Controller)"); + } + /* output conversation is found. */ + else if (outputFlag) + { + proto_tree_add_string_format_value(tree, hf_pn_rt_frame_info_type, tvb, + offset, 0, "Output", "Output Frame (IO_Controller -> IO_Device)"); + } + + sub_item = proto_tree_add_uint_format(tree, hf_pn_rt_data_status, + tvb, offset, 1, u8DataStatus, + "DataStatus: 0x%02x (Frame: %s and %s, Provider: %s and %s)", + u8DataStatus, + (u8DataStatus & 0x04) ? "Valid" : "Invalid", + (u8DataStatus & 0x01) ? "Primary" : "Backup", + (u8DataStatus & 0x20) ? "Ok" : "Problem", + (u8DataStatus & 0x10) ? "Run" : "Stop"); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_rt_data_status); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_ignore, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_Reserved_2, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_ok, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_operate, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_res3, tvb, offset, 1, u8DataStatus); + /* input conversation is found */ + if (inputFlag) + { + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_valid, tvb, offset, 1, u8DataStatus); + proto_tree_add_item(tree, hf_pn_rt_frame_info_function_meaning_input_conv, tvb, offset, 1, u8DataStatus); + if (u8State == 0 && u8Redundancy == 0 && u8DataValid == 1) + { + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_input_cr_state_is_backup, tvb, offset, 1, u8DataStatus); + } + else if (u8State == 0 && u8Redundancy == 0 && u8DataValid == 0) + { + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_input_cr_state_is_backup, tvb, offset, 1, u8DataStatus); + } + else if (u8State == 0 && u8Redundancy == 1 && u8DataValid == 1) + { + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_input_cr_state_is_backup, tvb, offset, 1, u8DataStatus); + } + else if (u8State == 0 && u8Redundancy == 1 && u8DataValid == 0) + { + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_input_cr_state_is_backup, tvb, offset, 1, u8DataStatus); + } + else if (u8State == 1 && u8Redundancy == 0 && u8DataValid == 1) + { + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_input_cr_state_is_primary, tvb, offset, 1, u8DataStatus); + } + else if (u8State == 1 && u8Redundancy == 1 && u8DataValid == 1) + { + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_input_cr_state_is_primary, tvb, offset, 1, u8DataStatus); + } + + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_primary, tvb, offset, 1, u8DataStatus); + return; + } + // output conversation is found. + else if (outputFlag) + { + proto_tree_add_item(tree, hf_pn_rt_frame_info_function_meaning_output_conv, tvb, offset, 1, u8DataStatus); + + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_valid, tvb, offset, 1, u8DataStatus); + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy_output_cr, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_primary, tvb, offset, 1, u8DataStatus); + + return; + } + + // If no conversation is found + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_valid, tvb, offset, 1, u8DataStatus); + proto_tree_add_boolean(sub_tree, hf_pn_rt_data_status_redundancy, tvb, offset, 1, u8DataStatus); + proto_tree_add_uint(sub_tree, hf_pn_rt_data_status_primary, tvb, offset, 1, u8DataStatus); +} + + +static gboolean +IsDFP_Frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 u16FrameID) +{ + guint16 u16SFCRC16; + guint8 u8SFPosition; + guint8 u8SFDataLength = 255; + int offset = 0; + guint32 u32SubStart; + guint16 crc; + gint tvb_len = 0; + unsigned char virtualFramebuffer[16]; + + /* try to build a temporaray buffer for generating this CRC */ + if (!pinfo->src.data || !pinfo->dst.data || + pinfo->dst.type != AT_ETHER || pinfo->src.type != AT_ETHER) { + /* if we don't have src/dst mac addresses then we assume it's not + * to avoid various crashes */ + return FALSE; + } + memcpy(&virtualFramebuffer[0], pinfo->dst.data, 6); + memcpy(&virtualFramebuffer[6], pinfo->src.data, 6); + virtualFramebuffer[12] = 0x88; + virtualFramebuffer[13] = 0x92; + virtualFramebuffer[15] = (unsigned char) (u16FrameID &0xff); + virtualFramebuffer[14] = (unsigned char) (u16FrameID>>8); + crc = crc16_plain_init(); + crc = crc16_plain_update(crc, &virtualFramebuffer[0], 16); + crc = crc16_plain_finalize(crc); + /* can check this CRC only by having built a temporary data buffer out of the pinfo data */ + u16SFCRC16 = tvb_get_letohs(tvb, offset); + if (u16SFCRC16 != 0) /* no crc! */ + { + if (u16SFCRC16 != crc) + { + proto_item_append_text(tree, ", no packed frame: SFCRC16 is 0x%x should be 0x%x", u16SFCRC16, crc); + return(FALSE); + } + } + /* end of first CRC check */ + + offset += 2; /*Skip first crc */ + tvb_len = tvb_captured_length(tvb); + if (offset + 4 > tvb_len) + return FALSE; + if (tvb_get_letohs(tvb, offset) == 0) + return FALSE; /* no valid DFP frame */ + while (1) { + u32SubStart = offset; + + u8SFPosition = tvb_get_guint8(tvb, offset); + offset += 1; + + u8SFDataLength = tvb_get_guint8(tvb, offset); + offset += 1; + + if (u8SFDataLength == 0) { + break; + } + + offset += 2; + + offset += u8SFDataLength; + if (offset > tvb_len) + return /*TRUE; */FALSE; + + u16SFCRC16 = tvb_get_letohs(tvb, offset); + if (u16SFCRC16 != 0) { + if (u8SFPosition & 0x80) { + crc = crc16_plain_tvb_offset_seed(tvb, u32SubStart, offset-u32SubStart, 0); + if (crc != u16SFCRC16) { + return FALSE; + } else { + } + } else { + } + } + offset += 2; + } + return TRUE; +} + +/* possibly dissect a CSF_SDU related PN-RT packet */ +gboolean +dissect_CSF_SDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + /* the sub tvb will NOT contain the frame_id here! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + guint16 u16SFCRC16; + guint8 u8SFPosition; + guint8 u8SFDataLength = 255; + guint8 u8SFCycleCounter; + guint8 u8SFDataStatus; + gint offset = 0; + guint32 u32SubStart; + proto_item *sub_item; + proto_tree *sub_tree; + guint16 crc; + + + /* possible FrameID ranges for DFP */ + if ((u16FrameID < 0x100) || (u16FrameID > 0x0FFF)) + return (FALSE); + if (IsDFP_Frame(tvb, pinfo, tree, u16FrameID)) { + /* can't check this CRC, as the checked data bytes are not available */ + u16SFCRC16 = tvb_get_letohs(tvb, offset); + if (u16SFCRC16 != 0) { + /* Checksum verify will always succeed */ + /* XXX - should we combine the two calls to always show "unverified"? */ + proto_tree_add_checksum(tree, tvb, offset, hf_pn_rt_sf_crc16, hf_pn_rt_sf_crc16_status, &ei_pn_rt_sf_crc16, pinfo, u16SFCRC16, + ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY); + } + else { + proto_tree_add_checksum(tree, tvb, offset, hf_pn_rt_sf_crc16, hf_pn_rt_sf_crc16_status, &ei_pn_rt_sf_crc16, pinfo, 0, + ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); + } + offset += 2; + + while (1) { + sub_item = proto_tree_add_item(tree, hf_pn_rt_sf, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_rt_sf); + u32SubStart = offset; + + u8SFPosition = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(sub_tree, hf_pn_rt_sf_position, tvb, offset, 1, u8SFPosition); + offset += 1; + + u8SFDataLength = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(sub_tree, hf_pn_rt_sf_data_length, tvb, offset, 1, u8SFDataLength); + offset += 1; + + if (u8SFDataLength == 0) { + proto_item_append_text(sub_item, ": Pos:%u, Length:%u", u8SFPosition, u8SFDataLength); + proto_item_set_len(sub_item, offset - u32SubStart); + break; + } + + u8SFCycleCounter = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(sub_tree, hf_pn_rt_sf_cycle_counter, tvb, offset, 1, u8SFCycleCounter); + offset += 1; + + u8SFDataStatus = tvb_get_guint8(tvb, offset); + dissect_DataStatus(tvb, offset, sub_tree, pinfo, u8SFDataStatus); + offset += 1; + + offset = dissect_pn_user_data(tvb, offset, pinfo, sub_tree, u8SFDataLength, "DataItem"); + + u16SFCRC16 = tvb_get_letohs(tvb, offset); + + if (u16SFCRC16 != 0 /* "old check": u8SFPosition & 0x80 */) { + crc = crc16_plain_tvb_offset_seed(tvb, u32SubStart, offset-u32SubStart, 0); + proto_tree_add_checksum(tree, tvb, offset, hf_pn_rt_sf_crc16, hf_pn_rt_sf_crc16_status, &ei_pn_rt_sf_crc16, pinfo, crc, + ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY); + } else { + proto_tree_add_checksum(tree, tvb, offset, hf_pn_rt_sf_crc16, hf_pn_rt_sf_crc16_status, &ei_pn_rt_sf_crc16, pinfo, 0, + ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); + } + offset += 2; + + proto_item_append_text(sub_item, ": Pos:%u, Length:%u, Cycle:%u, Status: 0x%02x (%s,%s,%s,%s)", + u8SFPosition, u8SFDataLength, u8SFCycleCounter, u8SFDataStatus, + (u8SFDataStatus & 0x04) ? "Valid" : "Invalid", + (u8SFDataStatus & 0x01) ? "Primary" : "Backup", + (u8SFDataStatus & 0x20) ? "Ok" : "Problem", + (u8SFDataStatus & 0x10) ? "Run" : "Stop"); + + proto_item_set_len(sub_item, offset - u32SubStart); + } + + return TRUE; + } + + return FALSE; + +} + +/* for reasemble processing we need some inits.. */ +/* Register PNIO defrag table init routine. */ + +static reassembly_table pdu_reassembly_table; +static GHashTable *reasembled_frag_table = NULL; + +static dissector_table_t ethertype_subdissector_table; + +static guint32 start_frag_OR_ID[16]; + + +static void +pnio_defragment_init(void) +{ + guint32 i; + for (i=0; i < 16; i++) /* init the reasemble help array */ + start_frag_OR_ID[i] = 0; + reasembled_frag_table = g_hash_table_new(NULL, NULL); +} + +static void +pnio_defragment_cleanup(void) +{ + g_hash_table_destroy(reasembled_frag_table); +} + +/* possibly dissect a FRAG_PDU related PN-RT packet */ +static gboolean +dissect_FRAG_PDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + /* the sub tvb will NOT contain the frame_id here! */ + guint16 u16FrameID = GPOINTER_TO_UINT(data); + int offset = 0; + + + /* possible FrameID ranges for FRAG_PDU */ + if (u16FrameID >= 0xFF80 && u16FrameID <= 0xFF8F) { + proto_item *sub_item; + proto_tree *sub_tree; + proto_item *status_item; + proto_tree *status_tree; + guint8 u8FragDataLength; + guint8 u8FragStatus; + gboolean bMoreFollows; + guint8 uFragNumber; + + sub_item = proto_tree_add_item(tree, hf_pn_rt_frag, tvb, offset, 0, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_pn_rt_frag); + + u8FragDataLength = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(sub_tree, hf_pn_rt_frag_data_length, tvb, offset, 1, u8FragDataLength); + offset += 1; + + status_item = proto_tree_add_item(sub_tree, hf_pn_rt_frag_status, tvb, offset, 1, ENC_NA); + status_tree = proto_item_add_subtree(status_item, ett_pn_rt_frag_status); + + u8FragStatus = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(status_tree, hf_pn_rt_frag_status_more_follows, tvb, offset, 1, u8FragStatus); + proto_tree_add_uint(status_tree, hf_pn_rt_frag_status_error, tvb, offset, 1, u8FragStatus); + proto_tree_add_uint(status_tree, hf_pn_rt_frag_status_fragment_number, tvb, offset, 1, u8FragStatus); + offset += 1; + uFragNumber = u8FragStatus & 0x3F; /* bits 0 to 5 */ + bMoreFollows = (u8FragStatus & 0x80) != 0; + proto_item_append_text(status_item, ": Number: %u, %s", + uFragNumber, + val_to_str( (u8FragStatus & 0x80) >> 7, pn_rt_frag_status_more_follows, "Unknown")); + + /* Is this a string or a bunch of bytes? Should it be FT_BYTES? */ + proto_tree_add_string_format(sub_tree, hf_pn_rt_frag_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), "data", + "Fragment Length: %d bytes", tvb_captured_length_remaining(tvb, offset)); + col_append_fstr(pinfo->cinfo, COL_INFO, " Fragment Length: %d bytes", tvb_captured_length_remaining(tvb, offset)); + + dissect_pn_user_data_bytes(tvb, offset, pinfo, sub_tree, tvb_captured_length_remaining(tvb, offset), FRAG_DATA); + if ((guint)tvb_captured_length_remaining(tvb, offset) < (guint)(u8FragDataLength *8)) { + proto_item_append_text(status_item, ": FragDataLength out of Framerange -> discarding!"); + return (TRUE); + } + /* defragmentation starts here */ + if (pnio_desegment) + { + guint32 u32FragID; + guint32 u32ReasembleID /*= 0xfedc ??*/; + fragment_head *pdu_frag; + + u32FragID = (u16FrameID & 0xf); + if (uFragNumber == 0) + { /* this is the first "new" fragment, so set up a new key Id */ + guint32 u32FrameKey; + u32FrameKey = (pinfo->num << 2) | u32FragID; + /* store it in the array */ + start_frag_OR_ID[u32FragID] = u32FrameKey; + } + u32ReasembleID = start_frag_OR_ID[u32FragID]; + /* use frame data instead of "pnio fraglen" which sets 8 octet steps */ + pdu_frag = fragment_add_seq(&pdu_reassembly_table, tvb, offset, + pinfo, u32ReasembleID, NULL, uFragNumber, + (tvb_captured_length_remaining(tvb, offset))/*u8FragDataLength*8*/, bMoreFollows, 0); + + if (pdu_frag && !bMoreFollows) /* PDU is complete! and last fragment */ + { /* store this fragment as the completed fragment in hash table */ + g_hash_table_insert(reasembled_frag_table, GUINT_TO_POINTER(pinfo->num), pdu_frag); + start_frag_OR_ID[u32FragID] = 0; /* reset the starting frame counter */ + } + if (!bMoreFollows) /* last fragment */ + { + pdu_frag = (fragment_head *)g_hash_table_lookup(reasembled_frag_table, GUINT_TO_POINTER(pinfo->num)); + if (pdu_frag) /* found a matching fragment; dissect it */ + { + guint16 type; + tvbuff_t *pdu_tvb; + + /* create the new tvb for defragmented frame */ + pdu_tvb = tvb_new_chain(tvb, pdu_frag->tvb_data); + /* add the defragmented data to the data source list */ + add_new_data_source(pinfo, pdu_tvb, "Reassembled Profinet Frame"); + /* PDU is complete: look for the Ethertype and give it to the appropriate dissection routine */ + type = tvb_get_ntohs(pdu_tvb, 0); + pdu_tvb = tvb_new_subset_remaining(pdu_tvb, 2); + if (!dissector_try_uint(ethertype_subdissector_table, type, pdu_tvb, pinfo, tree)) + call_data_dissector(pdu_tvb, pinfo, tree); + } + } + return TRUE; + } + else + return TRUE; + } + return FALSE; +} + + +/* + * dissect_pn_rt - The dissector for the Soft-Real-Time protocol + */ +static int +dissect_pn_rt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + gint pdu_len; + gint data_len; + guint16 u16FrameID; + guint8 u8DataStatus; + guint8 u8TransferStatus; + guint16 u16CycleCounter; + const gchar *pszProtAddInfo; + const gchar *pszProtShort; + const gchar *pszProtSummary; + const gchar *pszProtComment; + proto_tree *pn_rt_tree, *ti; + gchar szFieldSummary[100]; + tvbuff_t *next_tvb; + gboolean bCyclic; + heur_dtbl_entry_t *hdtbl_entry; + + + /* If the link-layer dissector for the protocol above us knows whether + * the packet, as handed to it, includes a link-layer FCS, what it + * hands to us should not include the FCS; if that's not the case, + * that's a bug in that dissector, and should be fixed there. + * + * If the link-layer dissector for the protocol above us doesn't know + * whether the packet, as handed to us, includes a link-layer FCS, + * there are limits as to what can be done there; the dissector + * ultimately needs a "yes, it has an FCS" preference setting, which + * both the Ethernet and 802.11 dissectors do. If that's not the case + * for a dissector, that's a deficiency in that dissector, and should + * be fixed there. + * + * Therefore, we assume we are not handed a packet that includes an + * FCS. If we are ever handed such a packet, either the link-layer + * dissector needs to be fixed or the link-layer dissector's preference + * needs to be set for your capture (even if that means adding such + * a preference). This dissector (and other dissectors for protcols + * running atop the link layer) should not attempt to process the + * FCS themselves, as that will just break things. */ + + /* Initialize variables */ + pn_rt_tree = NULL; + ti = NULL; + + /* + * Set the columns now, so that they'll be set correctly if we throw + * an exception. We can set them (or append things) later again .... + */ + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN-RT"); + col_set_str(pinfo->cinfo, COL_INFO, "PROFINET Real-Time"); + + pdu_len = tvb_reported_length(tvb); + if (pdu_len < 6) { + dissect_pn_malformed(tvb, 0, pinfo, tree, pdu_len); + return 0; + } + + /* build some "raw" data */ + u16FrameID = tvb_get_ntohs(tvb, 0); + if (u16FrameID <= 0x001F) { + pszProtShort = "PN-RT"; + pszProtAddInfo = "reserved, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0x0000-0x001F: Reserved ID"; + bCyclic = FALSE; + } else if (u16FrameID <= 0x0021) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "Synchronization, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0x0020-0x0021: Real-Time: Sync (with follow up)"; + bCyclic = FALSE; + } else if (u16FrameID <= 0x007F) { + pszProtShort = "PN-RT"; + pszProtAddInfo = "reserved, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0x0022-0x007F: Reserved ID"; + bCyclic = FALSE; + } else if (u16FrameID <= 0x0081) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "Synchronization, "; + pszProtSummary = "Isochronous-Real-Time"; + pszProtComment = "0x0080-0x0081: Real-Time: Sync (without follow up)"; + bCyclic = FALSE; + } else if (u16FrameID <= 0x00FF) { + pszProtShort = "PN-RT"; + pszProtAddInfo = "reserved, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0x0082-0x00FF: Reserved ID"; + bCyclic = FALSE; + } else if (u16FrameID <= 0x6FF) { + pszProtShort = "PN-RTC3"; + pszProtAddInfo = "RTC3, "; + pszProtSummary = "Isochronous-Real-Time"; + pszProtComment = "0x0100-0x06FF: RED: Real-Time(class=3): non redundant, normal or DFP"; + bCyclic = TRUE; + } else if (u16FrameID <= 0x0FFF) { + pszProtShort = "PN-RTC3"; + pszProtAddInfo = "RTC3, "; + pszProtSummary = "Isochronous-Real-Time"; + pszProtComment = "0x0700-0x0FFF: RED: Real-Time(class=3): redundant, normal or DFP"; + bCyclic = TRUE; + } else if (u16FrameID <= 0x7FFF) { + pszProtShort = "PN-RT"; + pszProtAddInfo = "reserved, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0x1000-0x7FFF: Reserved ID"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xBBFF) { + pszProtShort = "PN-RTC1"; + pszProtAddInfo = "RTC1, "; + pszProtSummary = "cyclic Real-Time"; + pszProtComment = "0x8000-0xBBFF: Real-Time(class=1 unicast): non redundant, normal"; + bCyclic = TRUE; + } else if (u16FrameID <= 0xBFFF) { + pszProtShort = "PN-RTC1"; + pszProtAddInfo = "RTC1, "; + pszProtSummary = "cyclic Real-Time"; + pszProtComment = "0xBC00-0xBFFF: Real-Time(class=1 multicast): non redundant, normal"; + bCyclic = TRUE; + } else if (u16FrameID <= 0xF7FF) { + /* check if udp frame on PNIO port */ + if (pinfo->destport == 0x8892) + { /* UDP frame */ + pszProtShort = "PN-RTCUDP,"; + pszProtAddInfo = "RT_CLASS_UDP, "; + pszProtComment = "0xC000-0xF7FF: Real-Time(UDP unicast): Cyclic"; + } + else + { /* layer 2 frame */ + pszProtShort = "PN-RT"; + pszProtAddInfo = "RTC1(legacy), "; + pszProtComment = "0xC000-0xF7FF: Real-Time(class=1 unicast): Cyclic"; + } + pszProtSummary = "cyclic Real-Time"; + bCyclic = TRUE; + } else if (u16FrameID <= 0xFBFF) { + if (pinfo->destport == 0x8892) + { /* UDP frame */ + pszProtShort = "PN-RTCUDP,"; + pszProtAddInfo = "RT_CLASS_UDP, "; + pszProtComment = "0xF800-0xFBFF:: Real-Time(UDP multicast): Cyclic"; + } + else + { /* layer 2 frame */ + pszProtShort = "PN-RT"; + pszProtAddInfo = "RTC1(legacy), "; + pszProtComment = "0xF800-0xFBFF: Real-Time(class=1 multicast): Cyclic"; + } + pszProtSummary = "cyclic Real-Time"; + bCyclic = TRUE; + } else if (u16FrameID <= 0xFDFF) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = "Reserved, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFC00-0xFDFF: Reserved"; + bCyclic = FALSE; + if (u16FrameID == 0xfc01) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = "Alarm High, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "Real-Time: Acyclic PN-IO Alarm high priority"; + } + + } else if (u16FrameID <= 0xFEFF) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = "Reserved, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFE00-0xFEFF: Real-Time: Reserved"; + bCyclic = FALSE; + if (u16FrameID == 0xFE01) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = "Alarm Low, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "Real-Time: Acyclic PN-IO Alarm low priority"; + } + if (u16FrameID == FRAME_ID_DCP_HELLO) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = ""; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol) hello"; + } + if (u16FrameID == FRAME_ID_DCP_GETORSET) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = ""; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol) get/set"; + } + if (u16FrameID == FRAME_ID_DCP_IDENT_REQ) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = ""; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol) identify multicast request"; + } + if (u16FrameID == FRAME_ID_DCP_IDENT_RES) { + pszProtShort = "PN-RTA"; + pszProtAddInfo = ""; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "Real-Time: DCP (Dynamic Configuration Protocol) identify response"; + } + } else if (u16FrameID <= 0xFF01) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "RTA Sync, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFF00-0xFF01: PTCP Announce"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xFF1F) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "RTA Sync, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFF02-0xFF1F: Reserved"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xFF21) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "Follow Up, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFF20-0xFF21: PTCP Follow Up"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xFF22) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "Follow Up, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFF22-0xFF3F: Reserved"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xFF43) { + pszProtShort = "PN-PTCP"; + pszProtAddInfo = "Delay, "; + pszProtSummary = "acyclic Real-Time"; + pszProtComment = "0xFF40-0xFF43: Acyclic Real-Time: Delay"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xFF7F) { + pszProtShort = "PN-RT"; + pszProtAddInfo = "Reserved, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0xFF44-0xFF7F: reserved ID"; + bCyclic = FALSE; + } else if (u16FrameID <= 0xFF8F) { + pszProtShort = "PN-RT"; + pszProtAddInfo = ""; + pszProtSummary = "Fragmentation"; + pszProtComment = "0xFF80-0xFF8F: Fragmentation"; + bCyclic = FALSE; + } else { + pszProtShort = "PN-RT"; + pszProtAddInfo = "Reserved, "; + pszProtSummary = "Real-Time"; + pszProtComment = "0xFF90-0xFFFF: reserved ID"; + bCyclic = FALSE; + } + + /* decode optional cyclic fields at the packet end and build the summary line */ + if (bCyclic) { + /* cyclic transfer has cycle counter, data status and transfer status fields at the end */ + u16CycleCounter = tvb_get_ntohs(tvb, pdu_len - 4); + u8DataStatus = tvb_get_guint8(tvb, pdu_len - 2); + u8TransferStatus = tvb_get_guint8(tvb, pdu_len - 1); + + g_snprintf (szFieldSummary, sizeof(szFieldSummary), + "%sID:0x%04x, Len:%4u, Cycle:%5u (%s,%s,%s,%s)", + pszProtAddInfo, u16FrameID, pdu_len - 2 - 4, u16CycleCounter, + (u8DataStatus & 0x04) ? "Valid" : "Invalid", + (u8DataStatus & 0x01) ? "Primary" : "Backup", + (u8DataStatus & 0x20) ? "Ok" : "Problem", + (u8DataStatus & 0x10) ? "Run" : "Stop"); + + /* user data length is packet len - frame id - optional cyclic status fields */ + data_len = pdu_len - 2 - 4; + } else { + /* satisfy the gcc compiler, so it won't throw an "uninitialized" warning */ + u16CycleCounter = 0; + u8DataStatus = 0; + u8TransferStatus = 0; + + /* acyclic transfer has no fields at the end */ + g_snprintf (szFieldSummary, sizeof(szFieldSummary), + "%sID:0x%04x, Len:%4u", + pszProtAddInfo, u16FrameID, pdu_len - 2); + + /* user data length is packet len - frame id field */ + data_len = pdu_len - 2; + } + + /* build protocol tree only, if tree is really used */ + if (tree) { + /* build pn_rt protocol tree with summary line */ + if (pn_rt_summary_in_tree) { + ti = proto_tree_add_protocol_format(tree, proto_pn_rt, tvb, 0, pdu_len, + "PROFINET %s, %s", pszProtSummary, szFieldSummary); + } else { + ti = proto_tree_add_item(tree, proto_pn_rt, tvb, 0, pdu_len, ENC_NA); + } + pn_rt_tree = proto_item_add_subtree(ti, ett_pn_rt); + + /* add frame ID */ + proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_frame_id, tvb, + 0, 2, u16FrameID, "FrameID: 0x%04x (%s)", u16FrameID, pszProtComment); + + if (bCyclic) { + /* add cycle counter */ + proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_cycle_counter, tvb, + pdu_len - 4, 2, u16CycleCounter, "CycleCounter: %u", u16CycleCounter); + + /* add data status subtree */ + dissect_DataStatus(tvb, pdu_len - 2, pn_rt_tree, pinfo, u8DataStatus); + + /* add transfer status */ + if (u8TransferStatus) { + proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_transfer_status, tvb, + pdu_len - 1, 1, u8TransferStatus, + "TransferStatus: 0x%02x (ignore this frame)", u8TransferStatus); + } else { + proto_tree_add_uint_format(pn_rt_tree, hf_pn_rt_transfer_status, tvb, + pdu_len - 1, 1, u8TransferStatus, + "TransferStatus: 0x%02x (OK)", u8TransferStatus); + } + } + } + + /* update column info now */ + col_add_str(pinfo->cinfo, COL_INFO, szFieldSummary); + col_set_str(pinfo->cinfo, COL_PROTOCOL, pszProtShort); + + /* get frame user data tvb (without header and footer) */ + next_tvb = tvb_new_subset_length(tvb, 2, 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, &hdtbl_entry, GUINT_TO_POINTER( (guint32) u16FrameID))) { + /*col_set_str(pinfo->cinfo, COL_INFO, "Unknown");*/ + + /* Oh, well, we don't know this; dissect it as data. */ + dissect_pn_undecoded(next_tvb, 0, pinfo, tree, tvb_captured_length(next_tvb)); + } + return tvb_captured_length(tvb); +} + + +/* Register all the bits needed by the filtering engine */ +void +proto_register_pn_rt(void) +{ + static hf_register_info hf[] = { + { &hf_pn_rt_frame_id, + { "FrameID", "pn_rt.frame_id", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_cycle_counter, + { "CycleCounter", "pn_rt.cycle_counter", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_data_status, + { "DataStatus", "pn_rt.ds", + FT_UINT8, BASE_HEX, 0, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_ignore, + { "Ignore (1:Ignore/0:Evaluate)", "pn_rt.ds_ignore", FT_UINT8, BASE_HEX, 0, 0x80, + NULL, HFILL }}, + + { &hf_pn_rt_frame_info_type, + { "PN Frame Type", "pn_rt.ds_frame_info_type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_frame_info_function_meaning_input_conv, + { "Function/Meaning", "pn_rt.ds_frame_info_meaning", + FT_UINT8, BASE_HEX, VALS(pn_rt_frame_info_function_meaning_input_conv), 0x7, + NULL, HFILL } }, + + { &hf_pn_rt_frame_info_function_meaning_output_conv, + { "Function/Meaning", "pn_rt.ds_frame_info_meaning", + FT_UINT8, BASE_HEX, VALS(pn_rt_frame_info_function_meaning_output_conv), 0x7, + NULL, HFILL } }, + + { &hf_pn_rt_data_status_Reserved_2, + { "Reserved_2 (should be zero)", "pn_rt.ds_Reserved_2", + FT_UINT8, BASE_HEX, 0, 0x40, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_ok, + { "StationProblemIndicator (1:Ok/0:Problem)", "pn_rt.ds_ok", + FT_UINT8, BASE_HEX, 0, 0x20, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_operate, + { "ProviderState (1:Run/0:Stop)", "pn_rt.ds_operate", + FT_UINT8, BASE_HEX, 0, 0x10, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_res3, + { "Reserved_1 (should be zero)", "pn_rt.ds_res3", + FT_UINT8, BASE_HEX, 0, 0x08, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_valid, + { "DataValid (1:Valid/0:Invalid)", "pn_rt.ds_valid", + FT_UINT8, BASE_HEX, 0, 0x04, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_redundancy, + { "Redundancy", "pn_rt.ds_redundancy", + FT_BOOLEAN, 8, TFS(&tfs_pn_rt_ds_redundancy), 0x02, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_redundancy_output_cr, + { "Redundancy", "pn_rt.ds_redundancy", + FT_BOOLEAN, 8, TFS(&tfs_pn_rt_ds_redundancy_output_cr), 0x02, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_redundancy_input_cr_state_is_backup, + { "Redundancy", "pn_rt.ds_redundancy", + FT_BOOLEAN, 8, TFS(&tfs_pn_rt_ds_redundancy_input_cr_state_is_backup), 0x02, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_redundancy_input_cr_state_is_primary, + { "Redundancy", "pn_rt.ds_redundancy", + FT_BOOLEAN, 8, TFS(&tfs_pn_rt_ds_redundancy_input_cr_state_is_primary), 0x02, + NULL, HFILL }}, + + { &hf_pn_rt_data_status_primary, + { "State (1:Primary/0:Backup)", "pn_rt.ds_primary", + FT_UINT8, BASE_HEX, 0, 0x01, + NULL, HFILL }}, + + { &hf_pn_rt_transfer_status, + { "TransferStatus", "pn_rt.transfer_status", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_sf, + { "SubFrame", "pn_rt.sf", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_sf_crc16, + { "SFCRC16", "pn_rt.sf.crc16", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_sf_crc16_status, + { "SFCRC16 status", "pn_rt.sf.crc16.status", + FT_UINT8, BASE_NONE, VALS(plugin_proto_checksum_vals), 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_sf_position, + { "Position", "pn_rt.sf.position", + FT_UINT8, BASE_DEC, NULL, 0x7F, + NULL, HFILL }}, + +#if 0 + { &hf_pn_rt_sf_position_control, + { "Control", "pn_rt.sf.position_control", + FT_UINT8, BASE_DEC, VALS(pn_rt_position_control), 0x80, + NULL, HFILL }}, +#endif + + { &hf_pn_rt_sf_data_length, + { "DataLength", "pn_rt.sf.data_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_sf_cycle_counter, + { "CycleCounter", "pn_rt.sf.cycle_counter", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_frag, + { "PROFINET Fragment", "pn_rt.frag", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_frag_data_length, + { "FragDataLength", "pn_rt.frag_data_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_frag_status, + { "FragStatus", "pn_rt.frag_status", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_rt_frag_status_more_follows, + { "MoreFollows", "pn_rt.frag_status.more_follows", + FT_UINT8, BASE_HEX, VALS(pn_rt_frag_status_more_follows), 0x80, + NULL, HFILL }}, + + { &hf_pn_rt_frag_status_error, + { "Reserved", "pn_rt.frag_status.error", + FT_UINT8, BASE_HEX, VALS(pn_rt_frag_status_error), 0x40, + NULL, HFILL }}, + + { &hf_pn_rt_frag_status_fragment_number, + { "FragmentNumber (zero based)", "pn_rt.frag_status.fragment_number", + FT_UINT8, BASE_DEC, NULL, 0x3F, + NULL, HFILL }}, + + /* Is this a string or a bunch of bytes? Should it be FT_BYTES? */ + { &hf_pn_rt_frag_data, + { "FragData", "pn_rt.frag_data", + FT_STRING, BASE_NONE, NULL, 0x00, + NULL, HFILL }}, + + }; + static gint *ett[] = { + &ett_pn_rt, + &ett_pn_rt_data_status, + &ett_pn_rt_sf, + &ett_pn_rt_frag, + &ett_pn_rt_frag_status + }; + + static ei_register_info ei[] = { + { &ei_pn_rt_sf_crc16, { "pn_rt.sf.crc16_bad", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }}, + }; + + module_t *pn_rt_module; + expert_module_t* expert_pn_rt; + + proto_pn_rt = proto_register_protocol("PROFINET Real-Time Protocol", + "PN-RT", "pn_rt"); + + proto_register_field_array(proto_pn_rt, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_pn_rt = expert_register_protocol(proto_pn_rt); + expert_register_field_array(expert_pn_rt, ei, array_length(ei)); + + /* Register our configuration options */ + + pn_rt_module = prefs_register_protocol(proto_pn_rt, NULL); + + 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); + + prefs_register_bool_preference(pn_rt_module, "desegment", + "reassemble PNIO Fragments", + "Reassemble PNIO Fragments and get them decoded", + &pnio_desegment); + + /* register heuristics anchor for payload dissectors */ + heur_subdissector_list = register_heur_dissector_list("pn_rt", proto_pn_rt); + + init_pn (proto_pn_rt); + register_init_routine(pnio_defragment_init); + register_cleanup_routine(pnio_defragment_cleanup); + reassembly_table_register(&pdu_reassembly_table, + &addresses_reassembly_table_functions); +} + + +/* The registration hand-off routine is called at startup */ +void +proto_reg_handoff_pn_rt(void) +{ + dissector_handle_t pn_rt_handle; + + pn_rt_handle = create_dissector_handle(dissect_pn_rt, proto_pn_rt); + + dissector_add_uint("ethertype", ETHERTYPE_PROFINET, pn_rt_handle); + dissector_add_uint_with_preference("udp.port", PROFINET_UDP_PORT, pn_rt_handle); + + heur_dissector_add("pn_rt", dissect_CSF_SDU_heur, "PROFINET CSF_SDU IO", "pn_csf_sdu_pn_rt", proto_pn_rt, HEURISTIC_ENABLE); + heur_dissector_add("pn_rt", dissect_FRAG_PDU_heur, "PROFINET Frag PDU IO", "pn_frag_pn_rt", proto_pn_rt, HEURISTIC_ENABLE); + + ethertype_subdissector_table = find_dissector_table("ethertype"); +} + + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn-rtc-one.c b/plugins/epan/profinet/packet-pn-rtc-one.c new file mode 100644 index 0000000000..f908fbb851 --- /dev/null +++ b/plugins/epan/profinet/packet-pn-rtc-one.c @@ -0,0 +1,1103 @@ +/* packet-pn-rtc-one.c + * Routines for PROFINET IO - RTC1 dissection. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * The PN-IO protocol is a field bus protocol related to decentralized + * periphery and is developed by the PROFIBUS Nutzerorganisation e.V. (PNO), + * see: www.profibus.com + * + * + * PN-IO is based on the common DCE-RPC and the "lightweight" PN-RT + * (ethernet type 0x8892) protocols. + * + * The context manager (CM) part is handling context information + * (like establishing, ...) and is using DCE-RPC as its underlying + * protocol. + * + * The actual cyclic data transfer and acyclic notification uses the + * "lightweight" PN-RT protocol. + * + * There are some other related PROFINET protocols (e.g. PN-DCP, which is + * handling addressing topics). + * + * Please note: the PROFINET CBA protocol is independent of the PN-IO protocol! + */ + +/* + * Cyclic PNIO RTC1 Data Dissection: + * + * To dissect cyclic PNIO RTC1 frames, this plug-in has to collect important module + * information out of "Ident OK", "Connect Request" and "Write Response" + * frames first. + * + * The data of Stationname-, -type and -id will be gained out of + * packet-pn-dcp.c. The header packet-pn.h will transfer those data between + * those two files. + * + * This file is used as a "addon" for packet-dcerpc-pn-io.c. Within "packet-dcerpc-pn-io.c" + * the defined structures in "packet-pn.h" will be filled with all necessary information. + * Those informations will be used in thise file to dissect cyclic PNIO RTC1 and PROFIsafe + * frames. Furthermore since RTC1 is a special frame type of PNIO, this dissection uses the + * already defined protocol PNIO. + * + * Overview for cyclic PNIO RTC1 data dissection functions: + * -> dissect_PNIO_C_SDU_RTC1 (general dissection of RTC1) + */ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <glib.h> +#include <epan/packet.h> +#include <epan/dissectors/packet-dcerpc.h> +#include <epan/proto.h> +#include <epan/expert.h> + +#include "packet-pn.h" + + +#define F_MESSAGE_TRAILER_4BYTE 4 /* PROFIsafe: Defines the Amount of Bytes for CRC and Status-/Controlbyte */ +#define PN_INPUT_CR 1 /* PROFINET Input Connect Request value */ +#define PN_INPUT_DATADESCRITPION 1 /* PROFINET Input Data Description value */ + + +static int proto_pn_io_rtc1 = -1; + +/* General module information */ +static int hf_pn_io_frame_info_type = -1; +static int hf_pn_io_frame_info_vendor = -1; +static int hf_pn_io_frame_info_nameofstation = -1; +static int hf_pn_io_frame_info_gsd_found = -1; +static int hf_pn_io_frame_info_gsd_error = -1; +static int hf_pn_io_frame_info_gsd_path = -1; +static int hf_pn_io_io_data_object = -1; +static int hf_pn_io_io_data_object_info_module_diff = -1; +static int hf_pn_io_io_data_object_info_moduleidentnumber = -1; +static int hf_pn_io_io_data_object_info_submoduleidentnumber = -1; + +static int hf_pn_io_iocs = -1; +static int hf_pn_io_iops = -1; +static int hf_pn_io_ioxs_extension = -1; +static int hf_pn_io_ioxs_res14 = -1; +static int hf_pn_io_ioxs_instance = -1; +static int hf_pn_io_ioxs_datastate = -1; + +/* PROFIsafe statusbyte and controlbyte */ +static int hf_pn_io_ps_sb = -1; +static int hf_pn_io_ps_sb_iparOK = -1; +static int hf_pn_io_ps_sb_DeviceFault = -1; +static int hf_pn_io_ps_sb_CECRC = -1; +static int hf_pn_io_ps_sb_WDtimeout = -1; +static int hf_pn_io_ps_sb_FVactivated = -1; +static int hf_pn_io_ps_sb_Toggle_d = -1; +static int hf_pn_io_ps_sb_ConsNr_reset = -1; +static int hf_pn_io_ps_sb_res = -1; +static int hf_pn_io_ps_sb_toggelBitChanged = -1; +static int hf_pn_io_ps_sb_toggelBitChange_slot_nr = -1; +static int hf_pn_io_ps_sb_toggelBitChange_subslot_nr = -1; + +static int hf_pn_io_ps_cb = -1; +static int hf_pn_io_ps_cb_iparEN = -1; +static int hf_pn_io_ps_cb_OAReq = -1; +static int hf_pn_io_ps_cb_resetConsNr = -1; +static int hf_pn_io_ps_cb_useTO2 = -1; +static int hf_pn_io_ps_cb_activateFV = -1; +static int hf_pn_io_ps_cb_Toggle_h = -1; +static int hf_pn_io_ps_cb_Chf_ACK = -1; +static int hf_pn_io_ps_cb_loopcheck = -1; +static int hf_pn_io_ps_cb_toggelBitChanged = -1; +static int hf_pn_io_ps_cb_toggelBitChange_slot_nr = -1; +static int hf_pn_io_ps_cb_toggelBitChange_subslot_nr = -1; + +/* PROFIsafe */ +static int hf_pn_io_ps_f_dest_adr = -1; +static int hf_pn_io_ps_f_data = -1; + +static gint ett_pn_io_rtc = -1; +static gint ett_pn_io_ioxs = -1; +static gint ett_pn_io_io_data_object = -1; + +static expert_field ei_pn_io_too_many_data_objects = EI_INIT; + +static const value_string pn_io_ioxs_extension[] = { + { 0x00 /* 0*/, "No IOxS octet follows" }, + { 0x01 /* 1*/, "One more IOxS octet follows" }, + { 0, NULL } +}; + +static const value_string pn_io_ioxs_instance[] = { + { 0x00 /* 0*/, "Detected by subslot" }, + { 0x01 /* 1*/, "Detected by slot" }, + { 0x02 /* 2*/, "Detected by IO device" }, + { 0x03 /* 3*/, "Detected by IO controller" }, + { 0, NULL } +}; + +static const value_string pn_io_ioxs_datastate[] = { + { 0x00 /* 0*/, "Bad" }, + { 0x01 /* 1*/, "Good" }, + { 0, NULL } +}; + + +static const int *ps_sb_fields[] = { + &hf_pn_io_ps_sb_res, + &hf_pn_io_ps_sb_ConsNr_reset, + &hf_pn_io_ps_sb_Toggle_d, + &hf_pn_io_ps_sb_FVactivated, + &hf_pn_io_ps_sb_WDtimeout, + &hf_pn_io_ps_sb_CECRC, + &hf_pn_io_ps_sb_DeviceFault, + &hf_pn_io_ps_sb_iparOK, + NULL +}; + +static const int *ps_cb_fields[] = { + &hf_pn_io_ps_cb_loopcheck, + &hf_pn_io_ps_cb_Chf_ACK, + &hf_pn_io_ps_cb_Toggle_h, + &hf_pn_io_ps_cb_activateFV, + &hf_pn_io_ps_cb_useTO2, + &hf_pn_io_ps_cb_resetConsNr, + &hf_pn_io_ps_cb_OAReq, + &hf_pn_io_ps_cb_iparEN, + NULL +}; + +static const int *ioxs_fields[] = { + &hf_pn_io_ioxs_datastate, + &hf_pn_io_ioxs_instance, + &hf_pn_io_ioxs_res14, + &hf_pn_io_ioxs_extension, + NULL +}; + + +/* Dissector for PROFIsafe Status Byte */ +static int +dissect_pn_io_ps_SB(tvbuff_t *tvb, int offset, +packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex, const int **fields) +{ + + if (tree) { + guint8 u8StatusByte; + proto_item *sb_item; + + u8StatusByte = tvb_get_guint8(tvb, offset); + + /* Add Status Byte subtree */ + sb_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex, ett_pn_io_ioxs, fields, + ENC_LITTLE_ENDIAN, BMT_NO_APPEND); + proto_item_append_text(sb_item, " (%s)", ((u8StatusByte == 0x20) || (u8StatusByte == 0x00)) ? "normal" : "unnormal"); + } + + return offset + 1; +} + + +/* Dissector for PROFIsafe Control Byte */ +static int +dissect_pn_io_ps_CB(tvbuff_t *tvb, int offset, +packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex, const int **fields) +{ + + if (tree) { + guint8 u8ControlByte; + proto_item *cb_item; + + u8ControlByte = tvb_get_guint8(tvb, offset); + + /* Add Status Byte subtree */ + cb_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex, ett_pn_io_ioxs, fields, + ENC_LITTLE_ENDIAN, BMT_NO_APPEND); + proto_item_append_text(cb_item, " (%s)", ((u8ControlByte == 0x20) || (u8ControlByte == 0x00) || + (u8ControlByte == 0xa0) || (u8ControlByte == 0x80)) ? "normal" : "unnormal"); + } + + return offset + 1; +} + + +/* Dissector for IOCS (As each IOCS stands for a specific Slot & Subslot) */ +static int +dissect_PNIO_IOCS(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, + guint8 *drep _U_, int hfindex, guint16 slotNr, guint16 subSlotNr, const int **fields) +{ + + if (tree) { + guint8 u8IOxS; + proto_item *ioxs_item; + + u8IOxS = tvb_get_guint8(tvb, offset); + + /* Add ioxs subtree */ + ioxs_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex, + ett_pn_io_ioxs, fields, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); + proto_item_append_text(ioxs_item, + " (%s%s), Slot: 0x%x, Subslot: 0x%x", + (u8IOxS & 0x01) ? "another IOxS follows " : "", + (u8IOxS & 0x80) ? "good" : "bad", + slotNr, + subSlotNr); + } + + return offset + 1; +} + + +/* dissect the IOxS (IOCS, IOPS) field */ +static int +dissect_PNIO_IOxS(tvbuff_t *tvb, int offset, +packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex, const int **fields) +{ + + if (tree) { + guint8 u8IOxS; + proto_item *ioxs_item; + + u8IOxS = tvb_get_guint8(tvb, offset); + + /* Add ioxs subtree */ + ioxs_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex, + ett_pn_io_ioxs, fields, ENC_LITTLE_ENDIAN, BMT_NO_APPEND); + proto_item_append_text(ioxs_item, + " (%s%s)", + (u8IOxS & 0x01) ? "another IOxS follows " : "", + (u8IOxS & 0x80) ? "good" : "bad"); + } + + return offset + 1; +} + + +/* Universel dissector for flexibel PROFIsafe Data 8 to 64 Bits */ +static int +dissect_pn_io_ps_uint(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, guint8 *drep, +int hfindex, guint8 bytelength, guint64 *pdata) +{ + guint64 data; + gboolean generalDissection; + + generalDissection = FALSE; + + switch (bytelength) { + case 1: /* 8 Bit Safety IO Data */ + data = tvb_get_guint8(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 2: /* 16 Bit Safety IO Data */ + data = tvb_get_letohs(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 3: /* 24 Bit Safety IO Data */ + data = tvb_get_letoh24(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 4: /* 32 Bit Safety IO Data */ + data = tvb_get_letohl(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 5: /* 40 Bit Safety IO Data */ + data = tvb_get_letoh40(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 6: /* 48 Bit Safety IO Data */ + data = tvb_get_letoh48(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 7: /* 56 Bit Safety IO Data */ + data = tvb_get_letoh56(tvb, offset); + if (pdata) + *pdata = data; + break; + + case 8: /* 64 Bit Safety IO Data */ + data = tvb_get_letoh64(tvb, offset); + if (pdata) + *pdata = data; + break; + + default: /* Safety IO Data is too big to save it into one variable */ + dissect_pn_user_data(tvb, offset, pinfo, tree, bytelength, "Safety IO Data"); + generalDissection = TRUE; + break; + } + + if (tree && generalDissection == FALSE) { + proto_tree_add_item(tree, hfindex, tvb, offset, bytelength, DREP_ENC_INTEGER(drep)); + } + + return offset + bytelength; +} + + +/* dissect a PN-IO RTC1 Cyclic Service Data Unit */ +int +dissect_PNIO_C_SDU_RTC1(tvbuff_t *tvb, int offset, + packet_info *pinfo, proto_tree *tree, guint8 *drep _U_) +{ + proto_tree *data_tree = NULL; + + /* Count & offset for comparation of the arrays */ + guint16 frameOffset; + guint32 objectCounter; + gboolean inputFlag; + gboolean outputFlag; + gboolean psInfoText; /* Used to display only once per frame the info text "PROFIsafe Device" */ + + proto_item *data_item; + proto_item *IODataObject_item; + proto_item *IODataObject_item_info; + proto_tree *IODataObject_tree; + proto_item *ModuleID_item; + proto_item *ModuleDiff_item; + + wmem_strbuf_t *moduleName; + + guint8 toggleBitSb; + guint8 toggleBitCb; + guint64 f_data; + + guint8 statusbyte; + guint8 controlbyte; + + guint16 number_io_data_objects_input_cr; + guint16 number_iocs_input_cr; + guint16 number_io_data_objects_output_cr; + guint16 number_iocs_output_cr; + + conversation_t *conversation; + stationInfo *station_info = NULL; + iocsObject *iocs_object; + ioDataObject *io_data_object; + moduleDiffInfo *module_diff_info; + wmem_list_frame_t *frame; + wmem_list_frame_t *frame_diff; + + /* Initial */ + frameOffset = 0; + f_data = 0; + inputFlag = FALSE; + outputFlag = FALSE; + psInfoText = FALSE; + number_io_data_objects_input_cr = 0; + number_iocs_input_cr = 0; + number_io_data_objects_output_cr = 0; + number_iocs_output_cr = 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO"); /* set protocol name */ + + data_item = proto_tree_add_protocol_format(tree, proto_pn_io_rtc1, tvb, offset, tvb_captured_length(tvb), + "PROFINET IO Cyclic Service Data Unit: %u bytes", tvb_captured_length(tvb)); + data_tree = proto_item_add_subtree(data_item, ett_pn_io_rtc); + + /* dissect_dcerpc_uint16(tvb, offset, pinfo, data_tree, drep, hf_pn_io_packedframe_SFCRC, &u16SFCRC); */ + if (!(dissect_CSF_SDU_heur(tvb, pinfo, data_tree, NULL) == FALSE)) + return(tvb_captured_length(tvb)); + + /* Only dissect cyclic RTC1 frames, if PN Connect Request has been read */ + conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0); + + /* Detect input data package and output data package */ + if (conversation != NULL) { + station_info = (stationInfo*)conversation_get_proto_data(conversation, proto_pn_dcp); + if (station_info != NULL) { + if (pnio_ps_selection == TRUE) { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO_PS"); /* set PROFISsafe protocol name */ + } + + if (addresses_equal(&(pinfo->src), conversation_key_addr1(conversation->key_ptr)) && addresses_equal(&(pinfo->dst), conversation_key_addr2(conversation->key_ptr))) { + inputFlag = TRUE; + outputFlag = FALSE; + number_io_data_objects_input_cr = station_info->ioDataObjectNr; + number_iocs_input_cr = station_info->iocsNr; + } + + if (addresses_equal(&(pinfo->dst), conversation_key_addr1(conversation->key_ptr)) && addresses_equal(&(pinfo->src), conversation_key_addr2(conversation->key_ptr))) { + outputFlag = TRUE; + inputFlag = FALSE; + number_io_data_objects_output_cr = station_info->ioDataObjectNr; + number_iocs_output_cr = station_info->iocsNr; + } + } + } + + /* ------- Input (PNIO) / Response (PNIO_PS) Frame Handling ------- */ + if (inputFlag) { + if (pnio_ps_selection == TRUE) { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb, + offset, 0, "Response", "Response Frame (IO_Device -> IO_Controller)"); + } + else { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb, + offset, 0, "Input", "Input Frame (IO_Device -> IO_Controller)"); + } + + if (station_info != NULL) { + if (station_info->typeofstation != NULL) { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_vendor, tvb, 0, + 0, station_info->typeofstation, "\"%s\"", station_info->typeofstation); + } + if (station_info->nameofstation != NULL) { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_nameofstation, tvb, 0, + 0, station_info->nameofstation, "\"%s\"", station_info->nameofstation); + } + + if (station_info->gsdPathLength == TRUE) { /* given path isn't too long for the array */ + if (station_info->gsdFound == TRUE) { /* found a GSD-file */ + if (station_info->gsdLocation != NULL) { + IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_found, tvb, offset, 0, ENC_NA); + proto_item_append_text(IODataObject_item_info, ": \"%s\"", station_info->gsdLocation); + } + } + else { + if (station_info->gsdLocation != NULL) { + IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_error, tvb, offset, 0, ENC_NA); + proto_item_append_text(IODataObject_item_info, " Please place relevant GSD-file under \"%s\"", station_info->gsdLocation); + } + } + } + else { + IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_path, tvb, offset, 0, ENC_NA); + proto_item_append_text(IODataObject_item_info, " Please check your GSD-file networkpath. (No Path configured)"); + } + } + + /* ---- Input IOData-/IOCS-Object Handling ---- */ + objectCounter = number_io_data_objects_input_cr + number_iocs_input_cr; + if (objectCounter > (guint)tvb_reported_length_remaining(tvb, offset)) { + expert_add_info_format(pinfo, data_item, &ei_pn_io_too_many_data_objects, "Too many data objects: %d", objectCounter); + return(tvb_captured_length(tvb)); + } + + while (objectCounter--) { + /* ---- Input IO Data Object Handling ---- */ + if (station_info != NULL) { + for (frame = wmem_list_head(station_info->ioobject_data_in); frame != NULL; frame = wmem_list_frame_next(frame)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (io_data_object->frameOffset == frameOffset) { + /* Found following object */ + + IODataObject_item = proto_tree_add_item(data_tree, hf_pn_io_io_data_object, tvb, offset, 0, ENC_NA); + IODataObject_tree = proto_item_add_subtree(IODataObject_item, ett_pn_io_io_data_object); + + /* Control: the Device still uses the correct ModuleIdentNumber? */ + for (frame_diff = wmem_list_head(station_info->diff_module); frame_diff != NULL; frame_diff = wmem_list_frame_next(frame_diff)) { + module_diff_info = (moduleDiffInfo*)wmem_list_frame_data(frame_diff); + if (io_data_object->moduleIdentNr != module_diff_info->modulID) { + ModuleDiff_item = proto_tree_add_item(IODataObject_tree, hf_pn_io_io_data_object_info_module_diff, tvb, 0, 0, ENC_NA); + proto_item_append_text(ModuleDiff_item, ": Device using ModuleIdentNumber 0x%08x instead of 0x%08x", module_diff_info->modulID, io_data_object->moduleIdentNr); + break; + } + } + + proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_moduleidentnumber, tvb, 0, 0, io_data_object->moduleIdentNr); + proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_submoduleidentnumber, tvb, 0, 0, io_data_object->subModuleIdentNr); + + /* PROFIsafe Supported Inputmodule handling */ + if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) { + if (io_data_object->profisafeSupported == TRUE && psInfoText == FALSE) { + /* Only add one information string per device to the infotext */ + col_append_str(pinfo->cinfo, COL_INFO, ", PROFIsafe Device"); /* Add string to wireshark infotext */ + psInfoText = TRUE; + } + + proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_f_dest_adr, tvb, 0, 0, io_data_object->f_dest_adr); + + /* Get Safety IO Data */ + if ((io_data_object->length - F_MESSAGE_TRAILER_4BYTE) > 0) { + offset = dissect_pn_io_ps_uint(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_f_data, + (io_data_object->length - F_MESSAGE_TRAILER_4BYTE), &f_data); + } + + /* ---- Check for new PNIO data using togglebit ---- */ + statusbyte = tvb_get_guint8(tvb, offset); + toggleBitSb = statusbyte & 0x20; /* get ToggleBit of StatusByte */ + + if (io_data_object->lastToggleBit != toggleBitSb) { /* ToggleBit has changed --> new Data incoming */ + /* Special Filter for ToggleBit within Statusbyte */ + ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_sb_toggelBitChanged, tvb, offset, 0, toggleBitSb); + PROTO_ITEM_SET_HIDDEN(ModuleID_item); + + ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_sb_toggelBitChange_slot_nr, tvb, offset, 0, io_data_object->slotNr); + PROTO_ITEM_SET_HIDDEN(ModuleID_item); + + ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_sb_toggelBitChange_subslot_nr, tvb, offset, 0, io_data_object->subSlotNr); + PROTO_ITEM_SET_HIDDEN(ModuleID_item); + } + + offset = dissect_pn_io_ps_SB(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_sb, ps_sb_fields); + offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->f_crc_len, "CRC"); + + io_data_object->last_sb_cb = statusbyte; /* save the value of current statusbyte */ + io_data_object->lastToggleBit = toggleBitSb; /* save the value of current togglebit within statusbyte */ + } /* END of PROFIsafe Module Handling */ + + else { + /* Module is not PROFIsafe supported */ + offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->length, "IO Data"); + } + + if (io_data_object->discardIOXS == FALSE) { + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_iops, ioxs_fields); + proto_item_set_len(IODataObject_item, io_data_object->length + 1); /* Length = Databytes + IOXS Byte */ + } + else { + proto_item_set_len(IODataObject_item, io_data_object->length); /* Length = Databytes */ + } + + proto_item_append_text(IODataObject_item, ": Slot: 0x%x Subslot: 0x%x", + io_data_object->slotNr, io_data_object->subSlotNr); + + + /* ModuleIdentNr appears not only once in GSD-file -> set module name more generally */ + if (io_data_object->amountInGSDML > 1) { /* if ModuleIdentNr only appears once in GSD-file, use the found GSD-file-ModuleName, else ... */ + if (io_data_object->slotNr == 0) { + moduleName = wmem_strbuf_new(wmem_packet_scope(), "Headstation"); + } + else { + moduleName = wmem_strbuf_new(wmem_packet_scope(), "Module"); + } + + if (io_data_object->profisafeSupported == TRUE) { + /* PROFIsafe */ + if (io_data_object->length >= 5) { /* 5 due to 3 CRC bytes & 1 status byte & (at least) 1 data byte */ + wmem_strbuf_append(moduleName, ", DI"); + } + else { + wmem_strbuf_append(moduleName, ", DO"); + } + } + else { + /* PROFINET */ + if (io_data_object->length > 0) { + wmem_strbuf_append(moduleName, ", DI"); + } + else { + wmem_strbuf_append(moduleName, ", DO"); + } + } + + io_data_object->moduleNameStr = wmem_strdup(wmem_file_scope(), wmem_strbuf_get_str(moduleName)); + } + + proto_item_append_text(IODataObject_item, " ModuleName: \"%s\"", io_data_object->moduleNameStr); + + /* emphasize the PROFIsafe supported Modul */ + if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) { + (proto_item_append_text(IODataObject_item, " (PROFIsafe Module)")); + } + + + /* Set frameOffset to its new value, to find the next object */ + frameOffset = frameOffset + io_data_object->length; /* frameOffset = current value + data bytes */ + if (io_data_object->discardIOXS == FALSE) { + frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */ + } + } + } + } + + /* ---- Input IOCS Object Handling ---- */ + if (station_info != NULL) { + for (frame = wmem_list_head(station_info->iocs_data_in); frame != NULL; frame = wmem_list_frame_next(frame)) { + iocs_object = (iocsObject*)wmem_list_frame_data(frame); + if (iocs_object->frameOffset == frameOffset) { + offset = dissect_PNIO_IOCS(tvb, offset, pinfo, data_tree, drep, hf_pn_io_iocs, iocs_object->slotNr, + iocs_object->subSlotNr, ioxs_fields); + + /* Set frameOffset to its new value, to find the next object */ + frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */ + + break; + } + } + } + } + + /* Dissect padding */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset), "GAP and RTCPadding"); + } /* END of Input Frame Handling */ + + /* ----- Output (PNIO) / Request (PNIO_PS) Frame Handling ------ */ + else if (outputFlag) { + if (pnio_ps_selection == TRUE) { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb, + offset, 0, "Request", "Request Frame (IO_Controller -> IO_Device)"); + } + else { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb, + offset, 0, "Output", "Output Frame (IO_Controller -> IO_Device)"); + } + + if (station_info != NULL) { + if (station_info->typeofstation != NULL) { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_vendor, tvb, 0, + 0, station_info->typeofstation, "\"%s\"", station_info->typeofstation); + } + if (station_info->nameofstation != NULL) { + proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_nameofstation, tvb, 0, + 0, station_info->nameofstation, "\"%s\"", station_info->nameofstation); + } + + if (station_info->gsdPathLength == TRUE) { /* given path isn't too long for the array */ + if (station_info->gsdFound == TRUE) { /* found a GSD-file */ + if (station_info->gsdLocation != NULL) { + IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_found, tvb, offset, 0, ENC_NA); + proto_item_append_text(IODataObject_item_info, ": \"%s\"", station_info->gsdLocation); + } + } + else { + if (station_info->gsdLocation != NULL) { + IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_error, tvb, offset, 0, ENC_NA); + proto_item_append_text(IODataObject_item_info, " Please place relevant GSD-file under \"%s\"", station_info->gsdLocation); + } + } + } + else { + IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_path, tvb, offset, 0, ENC_NA); + proto_item_append_text(IODataObject_item_info, " Please check your GSD-file networkpath. (No Path configured)"); + } + } + + /* ---- Output IOData-/IOCS-Object Handling ---- */ + objectCounter = number_io_data_objects_output_cr + number_iocs_output_cr; + if (objectCounter > (guint)tvb_reported_length_remaining(tvb, offset)) { + expert_add_info_format(pinfo, data_item, &ei_pn_io_too_many_data_objects, "Too many data objects: %d", objectCounter); + return(tvb_captured_length(tvb)); + } + while (objectCounter--) { + /* ---- Output IO Data Object Handling ---- */ + if (station_info != NULL) { + for (frame = wmem_list_head(station_info->ioobject_data_out); frame != NULL; frame = wmem_list_frame_next(frame)) { + io_data_object = (ioDataObject*)wmem_list_frame_data(frame); + if (io_data_object != NULL && io_data_object->frameOffset == frameOffset) { + /* Found following object */ + + IODataObject_item = proto_tree_add_item(data_tree, hf_pn_io_io_data_object, tvb, offset, 0, ENC_NA); + IODataObject_tree = proto_item_add_subtree(IODataObject_item, ett_pn_io_io_data_object); + + /* Control: the Device still uses the correct ModuleIdentNumber? */ + for (frame_diff = wmem_list_head(station_info->diff_module); frame_diff != NULL; frame_diff = wmem_list_frame_next(frame_diff)) { + module_diff_info = (moduleDiffInfo*)wmem_list_frame_data(frame_diff); + if (io_data_object->moduleIdentNr != module_diff_info->modulID) { + ModuleDiff_item = proto_tree_add_item(IODataObject_tree, hf_pn_io_io_data_object_info_module_diff, tvb, 0, 0, ENC_NA); + proto_item_append_text(ModuleDiff_item, ": Device using ModuleIdentNumber 0x%08x instead of 0x%08x", module_diff_info->modulID, io_data_object->moduleIdentNr); + break; + } + } + + proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_moduleidentnumber, tvb, 0, 0, io_data_object->moduleIdentNr); + proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_submoduleidentnumber, tvb, 0, 0, io_data_object->subModuleIdentNr); + + if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) { + if (io_data_object->profisafeSupported == TRUE && psInfoText == FALSE) { + /* Only add one information string per device to the infotext */ + col_append_str(pinfo->cinfo, COL_INFO, ", PROFIsafe Device"); /* Add string to wireshark infotext */ + psInfoText = TRUE; + } + + proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_f_dest_adr, tvb, 0, 0, io_data_object->f_dest_adr); + + /* Get Safety IO Data */ + if ((io_data_object->length - F_MESSAGE_TRAILER_4BYTE) > 0) { + offset = dissect_pn_io_ps_uint(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_f_data, + (io_data_object->length - F_MESSAGE_TRAILER_4BYTE), &f_data); + } + + /* ---- Check for new PNIO data using togglebit ---- */ + controlbyte = tvb_get_guint8(tvb, offset); + toggleBitCb = controlbyte & 0x20; /* get ToggleBit of Controlbyte */ + + if (io_data_object->lastToggleBit != toggleBitCb) { /* ToggleBit has changed --> new Data incoming */ + /* Special Filter for ToggleBit within Controlbyte */ + ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_cb_toggelBitChanged, tvb, offset, 0, toggleBitCb); + PROTO_ITEM_SET_HIDDEN(ModuleID_item); + + ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_cb_toggelBitChange_slot_nr, tvb, offset, 0, io_data_object->slotNr); + PROTO_ITEM_SET_HIDDEN(ModuleID_item); + + ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_cb_toggelBitChange_subslot_nr, tvb, offset, 0, io_data_object->subSlotNr); + PROTO_ITEM_SET_HIDDEN(ModuleID_item); + } + + offset = dissect_pn_io_ps_CB(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_cb, ps_cb_fields); + offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->f_crc_len, "CRC"); + + io_data_object->last_sb_cb = controlbyte; /* save the value of current controlbyte */ + io_data_object->lastToggleBit = toggleBitCb; /* save the value of current togglebit within controlbyte */ + } /* End of PROFIsafe Module Handling */ + else { + /* Module is not PROFIsafe supported */ + offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->length, "IO Data"); + } + + if (io_data_object->discardIOXS == FALSE) { + offset = dissect_PNIO_IOxS(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_iops, ioxs_fields); + proto_item_set_len(IODataObject_item, io_data_object->length + 1); /* Length = Databytes + IOXS Byte */ + } + else { + proto_item_set_len(IODataObject_item, io_data_object->length); /* Length = Databytes */ + } + + proto_item_append_text(IODataObject_item, ": Slot: 0x%x Subslot: 0x%x", + io_data_object->slotNr, io_data_object->subSlotNr); + + + /* ModuleIdentNr appears not only once in GSD-file -> set module name more generally */ + if (io_data_object->amountInGSDML > 1) { /* if ModuleIdentNr only appears once in GSD-file, use the found GSD-file-ModuleName, else ... */ + if (io_data_object->slotNr == 0) { + moduleName = wmem_strbuf_new(wmem_packet_scope(), "Headstation"); + } + else { + moduleName = wmem_strbuf_new(wmem_packet_scope(), "Module"); + } + + if (io_data_object->profisafeSupported == TRUE) { + /* PROFIsafe */ + if (io_data_object->length >= 5) { /* 5 due to 3 CRC bytes & 1 status byte & (at least) 1 data byte */ + wmem_strbuf_append(moduleName, ", DO"); + } + else { + wmem_strbuf_append(moduleName, ", DI"); + } + } + else { + /* PROFINET */ + if (io_data_object->length > 0) { + wmem_strbuf_append(moduleName, ", DO"); + } + else { + wmem_strbuf_append(moduleName, ", DI"); + } + } + + io_data_object->moduleNameStr = wmem_strdup(wmem_file_scope(), wmem_strbuf_get_str(moduleName)); + } + + proto_item_append_text(IODataObject_item, " ModuleName: \"%s\"", io_data_object->moduleNameStr); + + /* emphasize the PROFIsafe supported Modul */ + if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) { + proto_item_append_text(IODataObject_item, " (PROFIsafe Module)"); + } + + /* Set frameOffset to its new value, to find the next object */ + frameOffset = frameOffset + io_data_object->length; /* frameOffset = current value + data bytes */ + if (io_data_object->discardIOXS == FALSE) { + frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */ + } + } + } + } + + /* ---- Output IOCS Object Handling ---- */ + if (station_info != NULL) { + for (frame = wmem_list_head(station_info->iocs_data_out); frame != NULL; frame = wmem_list_frame_next(frame)) { + iocs_object = (iocsObject*)wmem_list_frame_data(frame); + if (iocs_object->frameOffset == frameOffset) { + offset = dissect_PNIO_IOCS(tvb, offset, pinfo, data_tree, drep, hf_pn_io_iocs, iocs_object->slotNr, + iocs_object->subSlotNr, ioxs_fields); + + /* Set frameOffset to its new value, to find the next object */ + frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */ + + break; + } + } + } + } + + /* Dissect padding */ + offset = dissect_pn_user_data(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset), "GAP and RTCPadding"); + } /* END of Output Frame Handling */ + + return offset; +} + + +void +init_pn_io_rtc1(int proto) +{ + static hf_register_info hf[] = { + { &hf_pn_io_io_data_object, + { "IODataObject", "pn_io.io_data_object", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_io_data_object_info_module_diff, + { "Difference", "pn_io.io_data_object.diff_module", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_io_data_object_info_moduleidentnumber, + { "ModuleIdentNumber", "pn_io.io_data_object.module_nr", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_io_data_object_info_submoduleidentnumber, + { "SubmoduleIdentNumber", "pn_io.io_data_object.submodule_nr", + FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_info_type, + { "PN Frame Type", "pn_io.frame_info.type", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_info_vendor, + { "DeviceVendorValue", "pn_io.frame_info.vendor", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_info_nameofstation, + { "NameOfStation", "pn_io.frame_info.nameofstation", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_info_gsd_found, + { "GSD-file found", "pn_io.frame_info.gsd_found", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_info_gsd_error, + { "GSD-file not found.", "pn_io.frame_info.gsd_error", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_frame_info_gsd_path, + { "GSD-file networkpath failure!", "pn_io.frame_info.gsd_path", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iocs, + { "IOCS", "pn_io.ioxs", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_iops, + { "IOPS", "pn_io.ioxs", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_extension, + { "Extension", "pn_io.ioxs.extension", + FT_UINT8, BASE_HEX, VALS(pn_io_ioxs_extension), 0x01, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_res14, + { "Reserved", "pn_io.ioxs.res14", + FT_UINT8, BASE_HEX, NULL, 0x1E, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_instance, + { "Instance", "pn_io.ioxs.instance", + FT_UINT8, BASE_HEX, VALS(pn_io_ioxs_instance), 0x60, + NULL, HFILL } + }, + { &hf_pn_io_ioxs_datastate, + { "DataState", "pn_io.ioxs.datastate", + FT_UINT8, BASE_HEX, VALS(pn_io_ioxs_datastate), 0x80, + NULL, HFILL } + }, + /* PROFIsafe parameter */ + /* Status Byte & Control Byte for PROFIsafe --- dissector handle */ + { &hf_pn_io_ps_sb, + { "Status Byte", "pn_io.ps.sb", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_toggelBitChanged, + { "Status Byte", "pn_io.ps.sb.toggle_d_changed", + FT_UINT8, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_toggelBitChange_slot_nr, + { "Slot_Number", "pn_io.ps.sb.toggle_d_changed.slot", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_toggelBitChange_subslot_nr, + { "Sub_Slot_Number", "pn_io.ps.sb.toggle_d_changed.subslot", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb, + { "Control Byte", "pn_io.ps.cb", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_toggelBitChanged, + { "Control Byte", "pn_io.ps.cb.toggle_h_changed", + FT_UINT8, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_toggelBitChange_slot_nr, + { "Slot_Number", "pn_io.ps.cb.toggle_h_changed.slot", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_toggelBitChange_subslot_nr, + { "Sub_Slot_Number", "pn_io.ps.cb.toggle_h_changed.subslot", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + /* Structures for dissecting Status Byte & Control Byte PROFIsafe ---dissector details */ + { &hf_pn_io_ps_sb_iparOK, + { "iPar_OK - F-Device has new iParameter values assigned", "pn_io.ps.sb.iPar_OK", + FT_UINT8, BASE_HEX, NULL, 0x01, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_DeviceFault, + { "Device_Fault - Failure exists in F-Device or F-Module", "pn_io.ps.sb.DeviceFault", + FT_UINT8, BASE_HEX, NULL, 0x02, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_CECRC, + { "CE_CRC - CRC Communication fault", "pn_io.ps.sb.CE_CRC", + FT_UINT8, BASE_HEX, NULL, 0x04, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_WDtimeout, + { "WD_timeout - WatchDog timeout Communication fault", "pn_io.ps.sb.WD_timeout", + FT_UINT8, BASE_HEX, NULL, 0x08, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_FVactivated, + { "FV_activated - Fail-safe values (FV) activated", "pn_io.ps.sb.FV_activated", + FT_UINT8, BASE_HEX, NULL, 0x10, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_Toggle_d, + { "Toggle_d - Device-based Toggle Bit", "pn_io.ps.sb.Toggle_d", + FT_UINT8, BASE_HEX, NULL, 0x20, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_ConsNr_reset, + { "cons_nr_R - F-Device has reset its consecutive number counter", "pn_io.ps.sb.cons_nr_R", + FT_UINT8, BASE_HEX, NULL, 0x40, + NULL, HFILL } + }, + { &hf_pn_io_ps_sb_res, + { "Bit7 - reserved for future releases", "pn_io.ps.sb.bit7", + FT_UINT8, BASE_HEX, NULL, 0x80, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_iparEN, + { "iPar_EN - iParameter assignment deblocked", "pn_io.ps.cb.iparEN", + FT_UINT8, BASE_HEX, NULL, 0x01, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_OAReq, + { "OA_Req - Operator acknowledge requested", "pn_io.ps.cb.OA_Req", + FT_UINT8, BASE_HEX, NULL, 0x02, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_resetConsNr, + { "R_cons_nr - Set the Virtual Consecutive Number within the F-Device to be \"0\"", "pn_io.ps.cb.R_cons_nr", + FT_UINT8, BASE_HEX, NULL, 0x04, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_useTO2, + { "Bit3 - Reserved or Use the secondary watchdog (Use_TO2)", "pn_io.ps.cb.bit3", + FT_UINT8, BASE_HEX, NULL, 0x08, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_activateFV, + { "activate_FV - Fail-safe values (FV) to be activated", "pn_io.ps.cb.activate_FV", + FT_UINT8, BASE_HEX, NULL, 0x10, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_Toggle_h, + { "Toggle_h - Host-based Toggle Bit", "pn_io.ps.cb.Toggle_h", + FT_UINT8, BASE_HEX, NULL, 0x20, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_Chf_ACK, + { "Bit6 - Reserved or Operator acknowledge after cleared channel fault (ChF_Ack)", "pn_io.ps.cb.bit6", + FT_UINT8, BASE_HEX, NULL, 0x40, + NULL, HFILL } + }, + { &hf_pn_io_ps_cb_loopcheck, + { "Bit7 - Reserved or Loop-back check (Loopcheck, shall be set to 1)", "pn_io.ps.cb.bit7", + FT_UINT8, BASE_HEX, NULL, 0x80, + NULL, HFILL } + }, + /* PROFIsafe */ + { &hf_pn_io_ps_f_dest_adr, + { "F_Dest_Add", "pn_io.ps.f_dest_add", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pn_io_ps_f_data, + { "SafetyIO Data", "pn_io.ps.f_data", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_pn_io_rtc, + &ett_pn_io_ioxs, + &ett_pn_io_io_data_object + }; + + static ei_register_info ei[] = { + { &ei_pn_io_too_many_data_objects, { "pn_io.too_many_data_objects", PI_MALFORMED, PI_ERROR, "Too many data objects", EXPFILL }}, + }; + + expert_module_t* expert_pn_io; + + proto_pn_io_rtc1 = proto; + proto_register_field_array(proto, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_pn_io = expert_register_protocol(proto_pn_io_rtc1); + expert_register_field_array(expert_pn_io, ei, array_length(ei)); +} + + +/* +* Editor modelines - http://www.wireshark.org/tools/modelines.html +* +* Local variables: +* c-basic-offset: 4 +* tab-width: 8 +* indent-tabs-mode: nil +* End: +* +* vi: set shiftwidth=4 tabstop=8 expandtab: +* :indentSize=4:tabSize=8:noTabs=true: +*/ diff --git a/plugins/epan/profinet/packet-pn.c b/plugins/epan/profinet/packet-pn.c new file mode 100644 index 0000000000..de7c4aada5 --- /dev/null +++ b/plugins/epan/profinet/packet-pn.c @@ -0,0 +1,394 @@ +/* packet-pn.c + * Common functions for other PROFINET protocols like IO, CBA, DCP, ... + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "config.h" + +#include <string.h> + +#include <epan/packet.h> +#include <epan/expert.h> +#include <epan/wmem/wmem.h> +#include <epan/dissectors/packet-dcerpc.h> + +#include "packet-pn.h" + + + +static int hf_pn_padding = -1; +static int hf_pn_undecoded_data = -1; +static int hf_pn_user_data = -1; +static int hf_pn_user_bytes = -1; +static int hf_pn_frag_bytes = -1; +static int hf_pn_malformed = -1; + +static expert_field ei_pn_undecoded_data = EI_INIT; + +/* Initialize PNIO RTC1 stationInfo memory */ +void +init_pnio_rtc1_station(stationInfo *station_info) { + station_info->iocs_data_in = wmem_list_new(wmem_file_scope()); + station_info->iocs_data_out = wmem_list_new(wmem_file_scope()); + station_info->ioobject_data_in = wmem_list_new(wmem_file_scope()); + station_info->ioobject_data_out = wmem_list_new(wmem_file_scope()); + station_info->diff_module = wmem_list_new(wmem_file_scope()); +} + +/* 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); + proto_tree_add_uint(tree, hfindex, tvb, offset, 1, data); + if (pdata) + *pdata = data; + return offset + 1; +} + +/* dissect a 16 bit unsigned integer; return the item through a pointer as well */ +int +dissect_pn_uint16_ret_item(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint16 *pdata, proto_item ** new_item) +{ + guint16 data; + proto_item *item = NULL; + + data = tvb_get_ntohs (tvb, offset); + + item = proto_tree_add_uint(tree, hfindex, tvb, offset, 2, data); + if (pdata) + *pdata = data; + if (new_item) + *new_item = item; + return offset + 2; +} + +/* 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); + + proto_tree_add_uint(tree, hfindex, tvb, offset, 2, data); + if (pdata) + *pdata = data; + return offset + 2; +} + +/* dissect a 16 bit signed integer */ +int +dissect_pn_int16(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, gint16 *pdata) +{ + gint16 data; + + data = tvb_get_ntohs (tvb, offset); + + proto_tree_add_int(tree, hfindex, tvb, offset, 2, data); + if (pdata) + *pdata = data; + return offset + 2; +} + +/* dissect a 24bit OUI (IEC organizational unique id) */ +int +dissect_pn_oid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint32 *pdata) +{ + guint32 data; + + data = tvb_get_ntoh24(tvb, offset); + + proto_tree_add_uint(tree, hfindex, tvb, offset, 3, data); + if (pdata) + *pdata = data; + return offset + 3; +} + +/* dissect a 6 byte MAC address */ +int +dissect_pn_mac(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint8 *pdata) +{ + guint8 data[6]; + + tvb_memcpy(tvb, data, offset, 6); + proto_tree_add_ether(tree, hfindex, tvb, offset, 6, data); + + if (pdata) + memcpy(pdata, data, 6); + + return offset + 6; +} + +/* 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; + + data = tvb_get_ipv4(tvb, offset); + proto_tree_add_ipv4(tree, hfindex, tvb, offset, 4, data); + + if (pdata) + *pdata = data; + + return offset + 4; +} + +/* dissect a 16 byte UUID address */ +int +dissect_pn_uuid(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, e_guid_t *uuid) +{ + guint8 drep[2] = { 0,0 }; + + offset = dissect_dcerpc_uuid_t(tvb, offset, pinfo, tree, drep, + hfindex, uuid); + + return offset; +} + +/* "dissect" some bytes still undecoded (with Expert warning) */ +int +dissect_pn_undecoded(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint32 length) +{ + proto_item *item; + + + item = proto_tree_add_string_format(tree, hf_pn_undecoded_data, tvb, offset, length, "data", + "Undecoded Data: %d bytes", length); + + expert_add_info_format(pinfo, item, &ei_pn_undecoded_data, + "Undecoded Data, %u bytes", length); + + return offset + length; +} + +/* "dissect" some user bytes */ +int +dissect_pn_user_data_bytes(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint32 length, int iSelect) +{ + if(iSelect == FRAG_DATA) + proto_tree_add_item(tree, hf_pn_frag_bytes, tvb, offset, length, ENC_NA); + else + proto_tree_add_item(tree, hf_pn_user_bytes, tvb, offset, length, ENC_NA); + + return offset + length; +} + +int +dissect_pn_user_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint32 length, const char *text) +{ + if (length != 0) { + proto_tree_add_string_format(tree, hf_pn_user_data, tvb, offset, length, "data", + "%s: %d bytes", text, length); + } + return offset + length; +} + +/* packet is malformed, mark it as such */ +int +dissect_pn_malformed(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint32 length) +{ + proto_tree_add_item(tree, hf_pn_malformed, tvb, 0, 10000, ENC_NA); + + return offset + length; +} + + +/* 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_padding, tvb, offset, length, "data", + "Padding: %u byte", length); + + return offset + length; +} + +/* align offset to 4 */ +int +dissect_pn_align4(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree) +{ + guint padding = 0; + + + if (offset % 4) { + padding = 4 - (offset % 4); + + proto_tree_add_string_format(tree, hf_pn_padding, tvb, offset, padding, "data", + "Padding: %u byte", padding); + } + + return offset + padding; +} + +/* append the given info text to item and column */ +void +pn_append_info(packet_info *pinfo, proto_item *dcp_item, const char *text) +{ + col_append_str(pinfo->cinfo, COL_INFO, text); + + proto_item_append_text(dcp_item, "%s", text); +} + + + +void +init_pn (int proto) +{ + static hf_register_info hf[] = { + { &hf_pn_padding, + { "Padding", "pn.padding", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_undecoded_data, + { "Undecoded Data", "pn.undecoded", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_user_data, + { "User Data", "pn.user_data", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_user_bytes, + { "Substitute Data", "pn.user_bytes", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_frag_bytes, + { "Fragment Data", "pn.frag_bytes", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_pn_malformed, + { "Malformed", "pn_rt.malformed", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }} + + }; + + /*static gint *ett[] = { + };*/ + + static ei_register_info ei[] = { + { &ei_pn_undecoded_data, { "pn.undecoded_data", PI_UNDECODED, PI_WARN, "Undecoded Data", EXPFILL }}, + }; + + expert_module_t* expert_pn; + + + proto_register_field_array (proto, hf, array_length (hf)); + /*proto_register_subtree_array (ett, array_length (ett));*/ + expert_pn = expert_register_protocol(proto); + expert_register_field_array(expert_pn, ei, array_length(ei)); +} + +/* Read a string from an "xml" file, dropping xml comment blocks */ +char *pn_fgets(char *str, int n, FILE *stream) +{ + const char XML_COMMENT_START[] = "<!--"; + const char XML_COMMENT_END[] = "-->"; + + char *retVal = fgets(str, n, stream); + if (retVal == NULL) { + /* No input, we're done */ + return retVal; + } + + /* Search for the XML begin comment marker */ + char *comment_start = strstr(str, XML_COMMENT_START); + char *common_start_end = comment_start + sizeof(XML_COMMENT_START) - 1; + if(comment_start == NULL) { + /* No comment start, we're done */ + return retVal; + } + + /* Terminate the input buffer at the comment start */ + *comment_start = '\0'; + size_t used_space = comment_start - str; + size_t remaining_space = n - used_space; + + /* Read more data looking for the comment end */ + char *comment_end = strstr(common_start_end, XML_COMMENT_END); + if (comment_end == NULL) { + // Not found in this line, read more lines until we do find it */ + char *temp = (char*)wmem_alloc(wmem_packet_scope(), MAX_LINE_LENGTH); + char *next_line = temp; + while((comment_end == NULL) && (next_line != NULL)) { + next_line = fgets(temp, MAX_LINE_LENGTH, stream); + if (next_line == NULL) { + /* No more data, exit now */ + break; + } + comment_end = strstr(next_line, XML_COMMENT_END); + } + } + + if (comment_end == NULL) { + /* We didn't find the comment end, return what we have */ + return retVal; + } + + /* We did find a comment end, skip past the comment */ + char *comment_end_end = comment_end + sizeof(XML_COMMENT_END) - 1; + + /* Check we have space left in the buffer to move the trailing bytes after the comment end */ + size_t remaining_bytes = strlen(comment_end_end) + 1; + if (remaining_bytes < remaining_space) { + g_strlcat(str, comment_end_end, n); + } + else { + /* Seek the file back to the comment end so the next read picks it up */ + fseek(stream, -(long)(remaining_bytes), SEEK_CUR); + } + + return retVal; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/plugins/epan/profinet/packet-pn.h b/plugins/epan/profinet/packet-pn.h new file mode 100644 index 0000000000..77cd635348 --- /dev/null +++ b/plugins/epan/profinet/packet-pn.h @@ -0,0 +1,174 @@ +/* packet-pn.h + * Common functions for other PROFINET protocols like DCP, MRP, ... + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Cyclic PNIO RTC1 Data Dissection: + * + * Added new structures to packet-pn.h to transfer the gained data of + * packet-pn-dcp.c and packet-dcerpc-pn-io.c to packet-pn-rtc-one.c for + * detailled dissection of cyclic PNIO RTC1 dataframes. + * + */ + +#define FRAME_ID_DCP_HELLO 0xfefc +#define FRAME_ID_DCP_GETORSET 0xfefd +#define FRAME_ID_DCP_IDENT_REQ 0xfefe +#define FRAME_ID_DCP_IDENT_RES 0xfeff + + +/* ---- Structures for pnio_rtc1 ---- */ +extern int proto_pn_dcp; +extern int proto_pn_io_apdu_status; +extern gboolean pnio_ps_selection; /* given by pnio preferences */ + +/* Structure for general station information */ +typedef struct tagStationInfo { + /* general information */ + gchar *typeofstation; + gchar *nameofstation; + guint16 u16Vendor_id; + guint16 u16Device_id; + /* frame structure */ + guint16 ioDataObjectNr; + guint16 iocsNr; + /* GSDfile station information */ + gboolean gsdFound; + gboolean gsdPathLength; + gchar *gsdLocation; + /* IOCS object data */ + wmem_list_t *iocs_data_in; + wmem_list_t *iocs_data_out; + /* IOData object data */ + wmem_list_t *ioobject_data_in; + wmem_list_t *ioobject_data_out; + /* Different ModuleIdentnumber */ + wmem_list_t *diff_module; +} stationInfo; + +typedef struct tagApduStatusSwitch +{ + gboolean isRedundancyActive; + address dl_dst; + address dl_src; +}apduStatusSwitch; + +/* Structure for IOCS Frames */ +typedef struct tagIocsObject { + guint16 slotNr; + guint16 subSlotNr; + guint16 frameOffset; +} iocsObject; + +/* Structure for IO Data Objects */ +typedef struct tagIoDataObject { + guint16 slotNr; + guint16 subSlotNr; + guint32 moduleIdentNr; + guint32 subModuleIdentNr; + guint16 frameOffset; + guint16 length; + guint16 amountInGSDML; + guint32 fParameterIndexNr; + guint16 f_par_crc1; + guint16 f_src_adr; + guint16 f_dest_adr; + gboolean f_crc_seed; + guint8 f_crc_len; + address srcAddr; + address dstAddr; + gboolean profisafeSupported; + gboolean discardIOXS; + gchar *moduleNameStr; + tvbuff_t *tvb_slot; + tvbuff_t *tvb_subslot; + /* Status- or Controlbyte data*/ + guint8 last_sb_cb; + guint8 lastToggleBit; +} ioDataObject; + +/* Structure for Modules with different ModuleIdentnumber */ +typedef struct tagModuleDiffInfo { + guint16 slotNr; + guint32 modulID; +} moduleDiffInfo; + + +extern void init_pn(int proto); +extern void init_pn_io_rtc1(int proto); + +extern void init_pnio_rtc1_station(stationInfo *station_info); + +extern int dissect_pn_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint8 *pdata); + +extern int dissect_pn_uint16_ret_item(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, int hfindex, guint16 *pdata, proto_item ** new_item); +extern int dissect_pn_uint16(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint16 *pdata); + +extern int dissect_pn_int16(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, int hfindex, gint16 *pdata); + +extern int dissect_pn_oid(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint32 *pdata); + +extern int dissect_pn_mac(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint8 *pdata); + +extern int dissect_pn_ipv4(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, int hfindex, guint32 *pdata); + +extern int dissect_pn_uuid(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, int hfindex, e_guid_t *uuid); + +extern int dissect_pn_undecoded(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 length); + +extern int dissect_pn_user_data(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint32 length, const char *text); + +#define SUBST_DATA 1 +#define FRAG_DATA 2 + +extern int dissect_pn_user_data_bytes(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, + proto_tree *tree, guint32 length, int iSelect); + +extern int dissect_pn_malformed(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint32 length); + +extern int dissect_pn_padding(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, int length); + +extern int dissect_pn_align4(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); + +extern int dissect_PNIO_C_SDU_RTC1(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, guint8 *drep _U_); + +extern void pn_append_info(packet_info *pinfo, proto_item *dcp_item, const char *text); + +extern gboolean dissect_CSF_SDU_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data); + +#define MAX_LINE_LENGTH 1024 /* used for fgets() */ + +/* Read a string from an "xml" file, dropping xml comment blocks */ +#include <stdio.h> +extern char *pn_fgets(char *str, int n, FILE *stream); |