diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-s7comm.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-s7comm.c')
-rw-r--r-- | epan/dissectors/packet-s7comm.c | 8609 |
1 files changed, 8609 insertions, 0 deletions
diff --git a/epan/dissectors/packet-s7comm.c b/epan/dissectors/packet-s7comm.c new file mode 100644 index 00000000..de55b83b --- /dev/null +++ b/epan/dissectors/packet-s7comm.c @@ -0,0 +1,8609 @@ +/* packet-s7comm.c + * + * Author: Thomas Wiens, 2014 (th.wiens@gmx.de) + * Description: Wireshark dissector for S7-Communication + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/reassemble.h> +#include <stdlib.h> +#include <wsutil/strtoi.h> +#include <epan/expert.h> + +#include "packet-s7comm.h" +#include "packet-s7comm_szl_ids.h" + +#define PROTO_TAG_S7COMM "S7COMM" + +/* Min. telegram length for heuristic check */ +#define S7COMM_MIN_TELEGRAM_LENGTH 10 + +/* Protocol identifier */ +#define S7COMM_PROT_ID 0x32 + +/* Wireshark ID of the S7COMM protocol */ +static int proto_s7comm = -1; + +/* Forward declarations */ +void proto_reg_handoff_s7comm(void); +void proto_register_s7comm (void); +static guint32 s7comm_decode_ud_tis_data(tvbuff_t *tvb, proto_tree *tree, guint8 type, guint8 subfunc, guint16 td_size, guint32 offset); + +/************************************************************************** + * PDU types + */ +#define S7COMM_ROSCTR_JOB 0x01 +#define S7COMM_ROSCTR_ACK 0x02 +#define S7COMM_ROSCTR_ACK_DATA 0x03 +#define S7COMM_ROSCTR_USERDATA 0x07 + +static const value_string rosctr_names[] = { + { S7COMM_ROSCTR_JOB, "Job" }, /* Request: job with acknowledgement */ + { S7COMM_ROSCTR_ACK, "Ack" }, /* acknowledgement without additional field */ + { S7COMM_ROSCTR_ACK_DATA, "Ack_Data" }, /* Response: acknowledgement with additional field */ + { S7COMM_ROSCTR_USERDATA, "Userdata" }, + { 0, NULL } +}; +/************************************************************************** + * Error classes in header + */ +#define S7COMM_ERRCLS_NONE 0x00 +#define S7COMM_ERRCLS_APPREL 0x81 +#define S7COMM_ERRCLS_OBJDEF 0x82 +#define S7COMM_ERRCLS_RESOURCE 0x83 +#define S7COMM_ERRCLS_SERVICE 0x84 +#define S7COMM_ERRCLS_SUPPLIES 0x85 +#define S7COMM_ERRCLS_ACCESS 0x87 + +static const value_string errcls_names[] = { + { S7COMM_ERRCLS_NONE, "No error" }, + { S7COMM_ERRCLS_APPREL, "Application relationship" }, + { S7COMM_ERRCLS_OBJDEF, "Object definition" }, + { S7COMM_ERRCLS_RESOURCE, "No resources available" }, + { S7COMM_ERRCLS_SERVICE, "Error on service processing" }, + { S7COMM_ERRCLS_SUPPLIES, "Error on supplies" }, + { S7COMM_ERRCLS_ACCESS, "Access error" }, + { 0, NULL } +}; + +/************************************************************************** + * Error code in parameter part + */ + +static const value_string param_errcode_names[] = { + { 0x0000, "No error" }, + { 0x0110, "Invalid block number" }, + { 0x0111, "Invalid request length" }, + { 0x0112, "Invalid parameter" }, + { 0x0113, "Invalid block type" }, + { 0x0114, "Block not found" }, + { 0x0115, "Block already exists" }, + { 0x0116, "Block is write-protected" }, + { 0x0117, "The block/operating system update is too large" }, + { 0x0118, "Invalid block number" }, + { 0x0119, "Incorrect password entered" }, + { 0x011A, "PG resource error" }, + { 0x011B, "PLC resource error" }, + { 0x011C, "Protocol error" }, + { 0x011D, "Too many blocks (module-related restriction)" }, + { 0x011E, "There is no longer a connection to the database, or S7DOS handle is invalid" }, + { 0x011F, "Result buffer too small" }, + { 0x0120, "End of block list" }, + { 0x0140, "Insufficient memory available" }, + { 0x0141, "Job cannot be processed because of a lack of resources" }, + { 0x8001, "The requested service cannot be performed while the block is in the current status" }, + { 0x8003, "S7 protocol error: Error occurred while transferring the block" }, + { 0x8100, "Application, general error: Service unknown to remote module" }, + { 0x8104, "This service is not implemented on the module or a frame error was reported" }, + { 0x8204, "The type specification for the object is inconsistent" }, + { 0x8205, "A copied block already exists and is not linked" }, + { 0x8301, "Insufficient memory space or work memory on the module, or specified storage medium not accessible" }, + { 0x8302, "Too few resources available or the processor resources are not available" }, + { 0x8304, "No further parallel upload possible. There is a resource bottleneck" }, + { 0x8305, "Function not available" }, + { 0x8306, "Insufficient work memory (for copying, linking, loading AWP)" }, + { 0x8307, "Not enough retentive work memory (for copying, linking, loading AWP)" }, + { 0x8401, "S7 protocol error: Invalid service sequence (for example, loading or uploading a block)" }, + { 0x8402, "Service cannot execute owing to status of the addressed object" }, + { 0x8404, "S7 protocol: The function cannot be performed" }, + { 0x8405, "Remote block is in DISABLE state (CFB). The function cannot be performed" }, + { 0x8500, "S7 protocol error: Wrong frames" }, + { 0x8503, "Alarm from the module: Service canceled prematurely" }, + { 0x8701, "Error addressing the object on the communications partner (for example, area length error)" }, + { 0x8702, "The requested service is not supported by the module" }, + { 0x8703, "Access to object refused" }, + { 0x8704, "Access error: Object damaged" }, + { 0xD001, "Protocol error: Illegal job number" }, + { 0xD002, "Parameter error: Illegal job variant" }, + { 0xD003, "Parameter error: Debugging function not supported by module" }, + { 0xD004, "Parameter error: Illegal job status" }, + { 0xD005, "Parameter error: Illegal job termination" }, + { 0xD006, "Parameter error: Illegal link disconnection ID" }, + { 0xD007, "Parameter error: Illegal number of buffer elements" }, + { 0xD008, "Parameter error: Illegal scan rate" }, + { 0xD009, "Parameter error: Illegal number of executions" }, + { 0xD00A, "Parameter error: Illegal trigger event" }, + { 0xD00B, "Parameter error: Illegal trigger condition" }, + { 0xD011, "Parameter error in path of the call environment: Block does not exist" }, + { 0xD012, "Parameter error: Wrong address in block" }, + { 0xD014, "Parameter error: Block being deleted/overwritten" }, + { 0xD015, "Parameter error: Illegal tag address" }, + { 0xD016, "Parameter error: Test jobs not possible, because of errors in user program" }, + { 0xD017, "Parameter error: Illegal trigger number" }, + { 0xD025, "Parameter error: Invalid path" }, + { 0xD026, "Parameter error: Illegal access type" }, + { 0xD027, "Parameter error: This number of data blocks is not permitted" }, + { 0xD031, "Internal protocol error" }, + { 0xD032, "Parameter error: Wrong result buffer length" }, + { 0xD033, "Protocol error: Wrong job length" }, + { 0xD03F, "Coding error: Error in parameter section (for example, reserve bytes not equal to 0)" }, + { 0xD041, "Data error: Illegal status list ID" }, + { 0xD042, "Data error: Illegal tag address" }, + { 0xD043, "Data error: Referenced job not found, check job data" }, + { 0xD044, "Data error: Illegal tag value, check job data" }, + { 0xD045, "Data error: Exiting the ODIS control is not allowed in HOLD" }, + { 0xD046, "Data error: Illegal measuring stage during run-time measurement" }, + { 0xD047, "Data error: Illegal hierarchy in 'Read job list'" }, + { 0xD048, "Data error: Illegal deletion ID in 'Delete job'" }, + { 0xD049, "Invalid substitute ID in 'Replace job'" }, + { 0xD04A, "Error executing 'program status'" }, + { 0xD05F, "Coding error: Error in data section (for example, reserve bytes not equal to 0, ...)" }, + { 0xD061, "Resource error: No memory space for job" }, + { 0xD062, "Resource error: Job list full" }, + { 0xD063, "Resource error: Trigger event occupied" }, + { 0xD064, "Resource error: Not enough memory space for one result buffer element" }, + { 0xD065, "Resource error: Not enough memory space for several result buffer elements" }, + { 0xD066, "Resource error: The timer available for run-time measurement is occupied by another job" }, + { 0xD067, "Resource error: Too many 'modify tag' jobs active (in particular multi-processor operation)" }, + { 0xD081, "Function not permitted in current mode" }, + { 0xD082, "Mode error: Cannot exit HOLD mode" }, + { 0xD0A1, "Function not permitted in current protection level" }, + { 0xD0A2, "Function not possible at present, because a function is running that modifies memory" }, + { 0xD0A3, "Too many 'modify tag' jobs active on the I/O (in particular multi-processor operation)" }, + { 0xD0A4, "'Forcing' has already been established" }, + { 0xD0A5, "Referenced job not found" }, + { 0xD0A6, "Job cannot be disabled/enabled" }, + { 0xD0A7, "Job cannot be deleted, for example because it is currently being read" }, + { 0xD0A8, "Job cannot be replaced, for example because it is currently being read or deleted" }, + { 0xD0A9, "Job cannot be read, for example because it is currently being deleted" }, + { 0xD0AA, "Time limit exceeded in processing operation" }, + { 0xD0AB, "Invalid job parameters in process operation" }, + { 0xD0AC, "Invalid job data in process operation" }, + { 0xD0AD, "Operating mode already set" }, + { 0xD0AE, "The job was set up over a different connection and can only be handled over this connection" }, + { 0xD0C1, "At least one error has been detected while accessing the tag(s)" }, + { 0xD0C2, "Change to STOP/HOLD mode" }, + { 0xD0C3, "At least one error was detected while accessing the tag(s). Mode change to STOP/HOLD" }, + { 0xD0C4, "Timeout during run-time measurement" }, + { 0xD0C5, "Display of block stack inconsistent, because blocks were deleted/reloaded" }, + { 0xD0C6, "Job was automatically deleted as the jobs it referenced have been deleted" }, + { 0xD0C7, "The job was automatically deleted because STOP mode was exited" }, + { 0xD0C8, "'Block status' aborted because of inconsistencies between test job and running program" }, + { 0xD0C9, "Exit the status area by resetting OB90" }, + { 0xD0CA, "Exiting the status range by resetting OB90 and access error reading tags before exiting" }, + { 0xD0CB, "The output disable for the peripheral outputs has been activated again" }, + { 0xD0CC, "The amount of data for the debugging functions is restricted by the time limit" }, + { 0xD201, "Syntax error in block name" }, + { 0xD202, "Syntax error in function parameters" }, + { 0xD205, "Linked block already exists in RAM: Conditional copying is not possible" }, + { 0xD206, "Linked block already exists in EPROM: Conditional copying is not possible" }, + { 0xD208, "Maximum number of copied (not linked) blocks on module exceeded" }, + { 0xD209, "(At least) one of the given blocks not found on the module" }, + { 0xD20A, "The maximum number of blocks that can be linked with one job was exceeded" }, + { 0xD20B, "The maximum number of blocks that can be deleted with one job was exceeded" }, + { 0xD20C, "OB cannot be copied because the associated priority class does not exist" }, + { 0xD20D, "SDB cannot be interpreted (for example, unknown number)" }, + { 0xD20E, "No (further) block available" }, + { 0xD20F, "Module-specific maximum block size exceeded" }, + { 0xD210, "Invalid block number" }, + { 0xD212, "Incorrect header attribute (run-time relevant)" }, + { 0xD213, "Too many SDBs. Note the restrictions on the module being used" }, + { 0xD216, "Invalid user program - reset module" }, + { 0xD217, "Protection level specified in module properties not permitted" }, + { 0xD218, "Incorrect attribute (active/passive)" }, + { 0xD219, "Incorrect block lengths (for example, incorrect length of first section or of the whole block)" }, + { 0xD21A, "Incorrect local data length or write-protection code faulty" }, + { 0xD21B, "Module cannot compress or compression was interrupted early" }, + { 0xD21D, "The volume of dynamic project data transferred is illegal" }, + { 0xD21E, "Unable to assign parameters to a module (such as FM, CP). The system data could not be linked" }, + { 0xD220, "Invalid programming language. Note the restrictions on the module being used" }, + { 0xD221, "The system data for connections or routing are not valid" }, + { 0xD222, "The system data of the global data definition contain invalid parameters" }, + { 0xD223, "Error in instance data block for communication function block or maximum number of instance DBs exceeded" }, + { 0xD224, "The SCAN system data block contains invalid parameters" }, + { 0xD225, "The DP system data block contains invalid parameters" }, + { 0xD226, "A structural error occurred in a block" }, + { 0xD230, "A structural error occurred in a block" }, + { 0xD231, "At least one loaded OB cannot be copied because the associated priority class does not exist" }, + { 0xD232, "At least one block number of a loaded block is illegal" }, + { 0xD234, "Block exists twice in the specified memory medium or in the job" }, + { 0xD235, "The block contains an incorrect checksum" }, + { 0xD236, "The block does not contain a checksum" }, + { 0xD237, "You are about to load the block twice, i.e. a block with the same time stamp already exists on the CPU" }, + { 0xD238, "At least one of the blocks specified is not a DB" }, + { 0xD239, "At least one of the DBs specified is not available as a linked variant in the load memory" }, + { 0xD23A, "At least one of the specified DBs is considerably different from the copied and linked variant" }, + { 0xD240, "Coordination rules violated" }, + { 0xD241, "The function is not permitted in the current protection level" }, + { 0xD242, "Protection violation while processing F blocks" }, + { 0xD250, "Update and module ID or version do not match" }, + { 0xD251, "Incorrect sequence of operating system components" }, + { 0xD252, "Checksum error" }, + { 0xD253, "No executable loader available; update only possible using a memory card" }, + { 0xD254, "Storage error in operating system" }, + { 0xD280, "Error compiling block in S7-300 CPU" }, + { 0xD2A1, "Another block function or a trigger on a block is active" }, + { 0xD2A2, "A trigger is active on a block. Complete the debugging function first" }, + { 0xD2A3, "The block is not active (linked), the block is occupied or the block is currently marked for deletion" }, + { 0xD2A4, "The block is already being processed by another block function" }, + { 0xD2A6, "It is not possible to save and change the user program simultaneously" }, + { 0xD2A7, "The block has the attribute 'unlinked' or is not processed" }, + { 0xD2A8, "An active debugging function is preventing parameters from being assigned to the CPU" }, + { 0xD2A9, "New parameters are being assigned to the CPU" }, + { 0xD2AA, "New parameters are currently being assigned to the modules" }, + { 0xD2AB, "The dynamic configuration limits are currently being changed" }, + { 0xD2AC, "A running active or deactivate assignment (SFC 12) is temporarily preventing R-KiR process" }, + { 0xD2B0, "An error occurred while configuring in RUN (CiR)" }, + { 0xD2C0, "The maximum number of technological objects has been exceeded" }, + { 0xD2C1, "The same technology data block already exists on the module" }, + { 0xD2C2, "Downloading the user program or downloading the hardware configuration is not possible" }, + { 0xD401, "Information function unavailable" }, + { 0xD402, "Information function unavailable" }, + { 0xD403, "Service has already been logged on/off (Diagnostics/PMC)" }, + { 0xD404, "Maximum number of nodes reached. No more logons possible for diagnostics/PMC" }, + { 0xD405, "Service not supported or syntax error in function parameters" }, + { 0xD406, "Required information currently unavailable" }, + { 0xD407, "Diagnostics error occurred" }, + { 0xD408, "Update aborted" }, + { 0xD409, "Error on DP bus" }, + { 0xD601, "Syntax error in function parameter" }, + { 0xD602, "Incorrect password entered" }, + { 0xD603, "The connection has already been legitimized" }, + { 0xD604, "The connection has already been enabled" }, + { 0xD605, "Legitimization not possible because password does not exist" }, + { 0xD801, "At least one tag address is invalid" }, + { 0xD802, "Specified job does not exist" }, + { 0xD803, "Illegal job status" }, + { 0xD804, "Illegal cycle time (illegal time base or multiple)" }, + { 0xD805, "No more cyclic read jobs can be set up" }, + { 0xD806, "The referenced job is in a state in which the requested function cannot be performed" }, + { 0xD807, "Function aborted due to overload, meaning executing the read cycle takes longer than the set scan cycle time" }, + { 0xDC01, "Date and/or time invalid" }, + { 0xE201, "CPU is already the master" }, + { 0xE202, "Connect and update not possible due to different user program in flash module" }, + { 0xE203, "Connect and update not possible due to different firmware" }, + { 0xE204, "Connect and update not possible due to different memory configuration" }, + { 0xE205, "Connect/update aborted due to synchronization error" }, + { 0xE206, "Connect/update denied due to coordination violation" }, + { 0xEF01, "S7 protocol error: Error at ID2; only 00H permitted in job" }, + { 0xEF02, "S7 protocol error: Error at ID2; set of resources does not exist" }, + { 0, NULL } +}; +static value_string_ext param_errcode_names_ext = VALUE_STRING_EXT_INIT(param_errcode_names); + +/************************************************************************** + * Function codes in parameter part + */ +#define S7COMM_SERV_CPU 0x00 +#define S7COMM_SERV_MODETRANS 0x01 +#define S7COMM_SERV_SETUPCOMM 0xF0 +#define S7COMM_SERV_READVAR 0x04 +#define S7COMM_SERV_WRITEVAR 0x05 + +#define S7COMM_FUNCREQUESTDOWNLOAD 0x1A +#define S7COMM_FUNCDOWNLOADBLOCK 0x1B +#define S7COMM_FUNCDOWNLOADENDED 0x1C +#define S7COMM_FUNCSTARTUPLOAD 0x1D +#define S7COMM_FUNCUPLOAD 0x1E +#define S7COMM_FUNCENDUPLOAD 0x1F +#define S7COMM_FUNCPISERVICE 0x28 +#define S7COMM_FUNC_PLC_STOP 0x29 + +static const value_string param_functionnames[] = { + { S7COMM_SERV_CPU, "CPU services" }, + { S7COMM_SERV_MODETRANS, "Mode transition" }, + { S7COMM_SERV_SETUPCOMM, "Setup communication" }, + { S7COMM_SERV_READVAR, "Read Var" }, + { S7COMM_SERV_WRITEVAR, "Write Var" }, + /* Block management services */ + { S7COMM_FUNCREQUESTDOWNLOAD, "Request download" }, + { S7COMM_FUNCDOWNLOADBLOCK, "Download block" }, + { S7COMM_FUNCDOWNLOADENDED, "Download ended" }, + { S7COMM_FUNCSTARTUPLOAD, "Start upload" }, + { S7COMM_FUNCUPLOAD, "Upload" }, + { S7COMM_FUNCENDUPLOAD, "End upload" }, + { S7COMM_FUNCPISERVICE, "PI-Service" }, + { S7COMM_FUNC_PLC_STOP, "PLC Stop" }, + { 0, NULL } +}; +/************************************************************************** + * Area names + */ +#define S7COMM_AREA_DATARECORD 0x01 /* Data record, used with RDREC or firmware updates on CP */ +#define S7COMM_AREA_SYSINFO 0x03 /* System info of 200 family */ +#define S7COMM_AREA_SYSFLAGS 0x05 /* System flags of 200 family */ +#define S7COMM_AREA_ANAIN 0x06 /* analog inputs of 200 family */ +#define S7COMM_AREA_ANAOUT 0x07 /* analog outputs of 200 family */ +#define S7COMM_AREA_P 0x80 /* direct peripheral access */ +#define S7COMM_AREA_INPUTS 0x81 +#define S7COMM_AREA_OUTPUTS 0x82 +#define S7COMM_AREA_FLAGS 0x83 +#define S7COMM_AREA_DB 0x84 /* data blocks */ +#define S7COMM_AREA_DI 0x85 /* instance data blocks */ +#define S7COMM_AREA_LOCAL 0x86 /* local data (should not be accessible over network) */ +#define S7COMM_AREA_V 0x87 /* previous (Vorgaenger) local data (should not be accessible over network) */ +#define S7COMM_AREA_COUNTER 28 /* S7 counters */ +#define S7COMM_AREA_TIMER 29 /* S7 timers */ +#define S7COMM_AREA_COUNTER200 30 /* IEC counters (200 family) */ +#define S7COMM_AREA_TIMER200 31 /* IEC timers (200 family) */ + +static const value_string item_areanames[] = { + { S7COMM_AREA_DATARECORD, "Data record" }, + { S7COMM_AREA_SYSINFO, "System info of 200 family" }, + { S7COMM_AREA_SYSFLAGS, "System flags of 200 family" }, + { S7COMM_AREA_ANAIN, "Analog inputs of 200 family" }, + { S7COMM_AREA_ANAOUT, "Analog outputs of 200 family" }, + { S7COMM_AREA_P, "Direct peripheral access (P)" }, + { S7COMM_AREA_INPUTS, "Inputs (I)" }, + { S7COMM_AREA_OUTPUTS, "Outputs (Q)" }, + { S7COMM_AREA_FLAGS, "Flags (M)" }, + { S7COMM_AREA_DB, "Data blocks (DB)" }, + { S7COMM_AREA_DI, "Instance data blocks (DI)" }, + { S7COMM_AREA_LOCAL, "Local data (L)" }, + { S7COMM_AREA_V, "Unknown yet (V)" }, + { S7COMM_AREA_COUNTER, "S7 counters (C)" }, + { S7COMM_AREA_TIMER, "S7 timers (T)" }, + { S7COMM_AREA_COUNTER200, "IEC counters (200 family)" }, + { S7COMM_AREA_TIMER200, "IEC timers (200 family)" }, + { 0, NULL } +}; + +static const value_string item_areanames_short[] = { + { S7COMM_AREA_DATARECORD, "RECORD" }, + { S7COMM_AREA_SYSINFO, "SI200" }, + { S7COMM_AREA_SYSFLAGS, "SF200" }, + { S7COMM_AREA_ANAIN, "AI200" }, + { S7COMM_AREA_ANAOUT, "AO" }, + { S7COMM_AREA_P, "P" }, + { S7COMM_AREA_INPUTS, "I" }, + { S7COMM_AREA_OUTPUTS, "Q" }, + { S7COMM_AREA_FLAGS, "M" }, + { S7COMM_AREA_DB, "DB" }, + { S7COMM_AREA_DI, "DI" }, + { S7COMM_AREA_LOCAL, "L" }, + { S7COMM_AREA_V, "V" }, + { S7COMM_AREA_COUNTER, "C" }, + { S7COMM_AREA_TIMER, "T" }, + { S7COMM_AREA_COUNTER200, "C200" }, + { S7COMM_AREA_TIMER200, "T200" }, + { 0, NULL } +}; +/************************************************************************** + * Transport sizes in item data + */ + /* types of 1 byte length */ +#define S7COMM_TRANSPORT_SIZE_BIT 1 +#define S7COMM_TRANSPORT_SIZE_BYTE 2 +#define S7COMM_TRANSPORT_SIZE_CHAR 3 + /* types of 2 bytes length */ +#define S7COMM_TRANSPORT_SIZE_WORD 4 +#define S7COMM_TRANSPORT_SIZE_INT 5 + /* types of 4 bytes length */ +#define S7COMM_TRANSPORT_SIZE_DWORD 6 +#define S7COMM_TRANSPORT_SIZE_DINT 7 +#define S7COMM_TRANSPORT_SIZE_REAL 8 + /* Special types */ +#define S7COMM_TRANSPORT_SIZE_DATE 9 +#define S7COMM_TRANSPORT_SIZE_TOD 10 +#define S7COMM_TRANSPORT_SIZE_TIME 11 +#define S7COMM_TRANSPORT_SIZE_S5TIME 12 +#define S7COMM_TRANSPORT_SIZE_DT 15 + /* Timer or counter */ +#define S7COMM_TRANSPORT_SIZE_COUNTER 28 +#define S7COMM_TRANSPORT_SIZE_TIMER 29 +#define S7COMM_TRANSPORT_SIZE_IEC_COUNTER 30 +#define S7COMM_TRANSPORT_SIZE_IEC_TIMER 31 +#define S7COMM_TRANSPORT_SIZE_HS_COUNTER 32 +static const value_string item_transportsizenames[] = { + { S7COMM_TRANSPORT_SIZE_BIT, "BIT" }, + { S7COMM_TRANSPORT_SIZE_BYTE, "BYTE" }, + { S7COMM_TRANSPORT_SIZE_CHAR, "CHAR" }, + { S7COMM_TRANSPORT_SIZE_WORD, "WORD" }, + { S7COMM_TRANSPORT_SIZE_INT, "INT" }, + { S7COMM_TRANSPORT_SIZE_DWORD, "DWORD" }, + { S7COMM_TRANSPORT_SIZE_DINT, "DINT" }, + { S7COMM_TRANSPORT_SIZE_REAL, "REAL" }, + { S7COMM_TRANSPORT_SIZE_TOD, "TOD" }, + { S7COMM_TRANSPORT_SIZE_TIME, "TIME" }, + { S7COMM_TRANSPORT_SIZE_S5TIME, "S5TIME" }, + { S7COMM_TRANSPORT_SIZE_DT, "DATE_AND_TIME" }, + { S7COMM_TRANSPORT_SIZE_COUNTER, "COUNTER" }, + { S7COMM_TRANSPORT_SIZE_TIMER, "TIMER" }, + { S7COMM_TRANSPORT_SIZE_IEC_COUNTER, "IEC TIMER" }, + { S7COMM_TRANSPORT_SIZE_IEC_TIMER, "IEC COUNTER" }, + { S7COMM_TRANSPORT_SIZE_HS_COUNTER, "HS COUNTER" }, + { 0, NULL } +}; + +/************************************************************************** + * Syntax Ids of variable specification + */ +#define S7COMM_SYNTAXID_S7ANY 0x10 /* Address data S7-Any pointer-like DB1.DBX10.2 */ +#define S7COMM_SYNTAXID_SHORT 0x11 +#define S7COMM_SYNTAXID_EXT 0x12 +#define S7COMM_SYNTAXID_PBC_ID 0x13 /* R_ID for PBC */ +#define S7COMM_SYNTAXID_ALARM_LOCKFREESET 0x15 /* Alarm lock/free dataset */ +#define S7COMM_SYNTAXID_ALARM_INDSET 0x16 /* Alarm indication dataset */ +#define S7COMM_SYNTAXID_ALARM_ACKSET 0x19 /* Alarm acknowledge message dataset */ +#define S7COMM_SYNTAXID_ALARM_QUERYREQSET 0x1a /* Alarm query request dataset */ +#define S7COMM_SYNTAXID_NOTIFY_INDSET 0x1c /* Notify indication dataset */ +#define S7COMM_SYNTAXID_NCK 0x82 /* Sinumerik NCK HMI access (current units) */ +#define S7COMM_SYNTAXID_NCK_METRIC 0x83 /* Sinumerik NCK HMI access metric units */ +#define S7COMM_SYNTAXID_NCK_INCH 0x84 /* Sinumerik NCK HMI access inch */ +#define S7COMM_SYNTAXID_DRIVEESANY 0xa2 /* seen on Drive ES Starter with routing over S7 */ +#define S7COMM_SYNTAXID_1200SYM 0xb2 /* Symbolic address mode of S7-1200 */ +#define S7COMM_SYNTAXID_DBREAD 0xb0 /* Kind of DB block read, seen only at an S7-400 */ + +static const value_string item_syntaxid_names[] = { + { S7COMM_SYNTAXID_S7ANY, "S7ANY" }, + { S7COMM_SYNTAXID_SHORT, "ParameterShort" }, + { S7COMM_SYNTAXID_EXT, "ParameterExtended" }, + { S7COMM_SYNTAXID_PBC_ID, "PBC-R_ID" }, + { S7COMM_SYNTAXID_ALARM_LOCKFREESET, "ALARM_LOCKFREE" }, + { S7COMM_SYNTAXID_ALARM_INDSET, "ALARM_IND" }, + { S7COMM_SYNTAXID_ALARM_ACKSET, "ALARM_ACK" }, + { S7COMM_SYNTAXID_ALARM_QUERYREQSET, "ALARM_QUERYREQ" }, + { S7COMM_SYNTAXID_NOTIFY_INDSET, "NOTIFY_IND" }, + { S7COMM_SYNTAXID_NCK, "NCK" }, + { S7COMM_SYNTAXID_NCK_METRIC, "NCK_M" }, + { S7COMM_SYNTAXID_NCK_INCH, "NCK_I" }, + { S7COMM_SYNTAXID_DRIVEESANY, "DRIVEESANY" }, + { S7COMM_SYNTAXID_1200SYM, "1200SYM" }, + { S7COMM_SYNTAXID_DBREAD, "DBREAD" }, + { 0, NULL } +}; + +/************************************************************************** + * Transport sizes in data + */ +#define S7COMM_DATA_TRANSPORT_SIZE_NULL 0 +#define S7COMM_DATA_TRANSPORT_SIZE_BBIT 3 /* bit access, len is in bits */ +#define S7COMM_DATA_TRANSPORT_SIZE_BBYTE 4 /* byte/word/dword access, len is in bits */ +#define S7COMM_DATA_TRANSPORT_SIZE_BINT 5 /* integer access, len is in bits */ +#define S7COMM_DATA_TRANSPORT_SIZE_BDINT 6 /* integer access, len is in bytes */ +#define S7COMM_DATA_TRANSPORT_SIZE_BREAL 7 /* real access, len is in bytes */ +#define S7COMM_DATA_TRANSPORT_SIZE_BSTR 9 /* octet string, len is in bytes */ +#define S7COMM_DATA_TRANSPORT_SIZE_NCKADDR1 17 /* NCK address description, fixed length */ +#define S7COMM_DATA_TRANSPORT_SIZE_NCKADDR2 18 /* NCK address description, fixed length */ + +static const value_string data_transportsizenames[] = { + { S7COMM_DATA_TRANSPORT_SIZE_NULL, "NULL" }, + { S7COMM_DATA_TRANSPORT_SIZE_BBIT, "BIT" }, + { S7COMM_DATA_TRANSPORT_SIZE_BBYTE, "BYTE/WORD/DWORD" }, + { S7COMM_DATA_TRANSPORT_SIZE_BINT, "INTEGER" }, + { S7COMM_DATA_TRANSPORT_SIZE_BDINT, "DINTEGER" }, + { S7COMM_DATA_TRANSPORT_SIZE_BREAL, "REAL" }, + { S7COMM_DATA_TRANSPORT_SIZE_BSTR, "OCTET STRING" }, + { S7COMM_DATA_TRANSPORT_SIZE_NCKADDR1, "NCK ADDRESS1" }, + { S7COMM_DATA_TRANSPORT_SIZE_NCKADDR2, "NCK ADDRESS2" }, + { 0, NULL } +}; +/************************************************************************** + * Returnvalues of an item response + */ + +const value_string s7comm_item_return_valuenames[] = { + { S7COMM_ITEM_RETVAL_RESERVED, "Reserved" }, + { S7COMM_ITEM_RETVAL_DATA_HW_FAULT, "Hardware error" }, + { S7COMM_ITEM_RETVAL_DATA_ACCESS_FAULT, "Accessing the object not allowed" }, + { S7COMM_ITEM_RETVAL_DATA_OUTOFRANGE, "Invalid address" }, + { S7COMM_ITEM_RETVAL_DATA_NOT_SUP, "Data type not supported" }, + { S7COMM_ITEM_RETVAL_DATA_SIZEMISMATCH, "Data type inconsistent" }, + { S7COMM_ITEM_RETVAL_DATA_ERR, "Object does not exist" }, + { S7COMM_ITEM_RETVAL_DATA_OK, "Success" }, + { 0, NULL } +}; +/************************************************************************** + * Block Types, used when blocktype is transfered as string + */ +#define S7COMM_BLOCKTYPE_OB 0x3038 /* '08' */ +#define S7COMM_BLOCKTYPE_CMOD 0x3039 /* '09' */ +#define S7COMM_BLOCKTYPE_DB 0x3041 /* '0A' */ +#define S7COMM_BLOCKTYPE_SDB 0x3042 /* '0B' */ +#define S7COMM_BLOCKTYPE_FC 0x3043 /* '0C' */ +#define S7COMM_BLOCKTYPE_SFC 0x3044 /* '0D' */ +#define S7COMM_BLOCKTYPE_FB 0x3045 /* '0E' */ +#define S7COMM_BLOCKTYPE_SFB 0x3046 /* '0F' */ + +static const value_string blocktype_names[] = { + { S7COMM_BLOCKTYPE_OB, "OB" }, + { S7COMM_BLOCKTYPE_CMOD, "CMod" }, + { S7COMM_BLOCKTYPE_DB, "DB" }, + { S7COMM_BLOCKTYPE_SDB, "SDB" }, + { S7COMM_BLOCKTYPE_FC, "FC" }, + { S7COMM_BLOCKTYPE_SFC, "SFC" }, + { S7COMM_BLOCKTYPE_FB, "FB" }, + { S7COMM_BLOCKTYPE_SFB, "SFB" }, + { 0, NULL } +}; + + +static const value_string blocktype_attribute1_names[] = { + { '_', "Complete Module" }, + { '$', "Module header for up-loading" }, + { 0, NULL } +}; + +static const value_string blocktype_attribute2_names[] = { + { 'P', "Passive (copied, but not chained) module" }, + { 'A', "Active embedded module" }, + { 'B', "Active as well as passive module" }, + { 0, NULL } +}; + +/************************************************************************** + * Subblk types + */ +#define S7COMM_SUBBLKTYPE_NONE 0x00 +#define S7COMM_SUBBLKTYPE_OB 0x08 +#define S7COMM_SUBBLKTYPE_DB 0x0a +#define S7COMM_SUBBLKTYPE_SDB 0x0b +#define S7COMM_SUBBLKTYPE_FC 0x0c +#define S7COMM_SUBBLKTYPE_SFC 0x0d +#define S7COMM_SUBBLKTYPE_FB 0x0e +#define S7COMM_SUBBLKTYPE_SFB 0x0f + +static const value_string subblktype_names[] = { + { S7COMM_SUBBLKTYPE_NONE, "Not set" }, + { S7COMM_SUBBLKTYPE_OB, "OB" }, + { S7COMM_SUBBLKTYPE_DB, "DB" }, + { S7COMM_SUBBLKTYPE_SDB, "SDB" }, + { S7COMM_SUBBLKTYPE_FC, "FC" }, + { S7COMM_SUBBLKTYPE_SFC, "SFC" }, + { S7COMM_SUBBLKTYPE_FB, "FB" }, + { S7COMM_SUBBLKTYPE_SFB, "SFB" }, + { 0, NULL } +}; + +/************************************************************************** + * Block security + */ +#define S7COMM_BLOCKSECURITY_OFF 0 +#define S7COMM_BLOCKSECURITY_KNOWHOWPROTECT 3 + +static const value_string blocksecurity_names[] = { + { S7COMM_BLOCKSECURITY_OFF, "None" }, + { S7COMM_BLOCKSECURITY_KNOWHOWPROTECT, "Know How Protect" }, + { 0, NULL } +}; +/************************************************************************** + * Block Languages + */ +static const value_string blocklanguage_names[] = { + { 0x00, "Not defined" }, + { 0x01, "AWL" }, + { 0x02, "KOP" }, + { 0x03, "FUP" }, + { 0x04, "SCL" }, + { 0x05, "DB" }, + { 0x06, "GRAPH" }, + { 0x07, "SDB" }, + { 0x08, "CPU-DB" }, /* DB was created from Plc programm (CREAT_DB) */ + { 0x11, "SDB (after overall reset)" }, /* another SDB, don't know what it means, in SDB 1 and SDB 2, uncertain*/ + { 0x12, "SDB (Routing)" }, /* another SDB, in SDB 999 and SDB 1000 (routing information), uncertain */ + { 0x29, "ENCRYPT" }, /* block is encrypted with S7-Block-Privacy */ + { 0, NULL } +}; + +/************************************************************************** + * Names of types in userdata parameter part + */ + +static const value_string userdata_type_names[] = { + { S7COMM_UD_TYPE_IND, "Indication" }, + { S7COMM_UD_TYPE_REQ, "Request" }, + { S7COMM_UD_TYPE_RES, "Response" }, + { 0, NULL } +}; + +/************************************************************************** + * Subfunctions only used in Sinumerik NC file download + */ +#define S7COMM_NCPRG_FUNCREQUESTDOWNLOAD 1 +#define S7COMM_NCPRG_FUNCDOWNLOADBLOCK 2 +#define S7COMM_NCPRG_FUNCCONTDOWNLOAD 3 +#define S7COMM_NCPRG_FUNCDOWNLOADENDED 4 +#define S7COMM_NCPRG_FUNCSTARTUPLOAD 6 +#define S7COMM_NCPRG_FUNCUPLOAD 7 +#define S7COMM_NCPRG_FUNCCONTUPLOAD 8 + +static const value_string userdata_ncprg_subfunc_names[] = { + { S7COMM_NCPRG_FUNCREQUESTDOWNLOAD, "Request download" }, + { S7COMM_NCPRG_FUNCDOWNLOADBLOCK, "Download block" }, + { S7COMM_NCPRG_FUNCCONTDOWNLOAD, "Continue download" }, + { S7COMM_NCPRG_FUNCDOWNLOADENDED, "Download ended" }, + { S7COMM_NCPRG_FUNCSTARTUPLOAD, "Start upload" }, + { S7COMM_NCPRG_FUNCUPLOAD, "Upload" }, + { S7COMM_NCPRG_FUNCCONTUPLOAD, "Continue upload" }, + { 0, NULL } +}; + +/************************************************************************** + * Subfunctions for Data Record Routing to Profibus + */ +#define S7COMM_DRR_FUNCINIT 1 +#define S7COMM_DRR_FUNCFINISH 2 +#define S7COMM_DRR_FUNCDATA 3 + +static const value_string userdata_drr_subfunc_names[] = { + { S7COMM_DRR_FUNCINIT, "DRR Init" }, + { S7COMM_DRR_FUNCFINISH, "DRR Finish" }, + { S7COMM_DRR_FUNCDATA, "DRR Data" }, + { 0, NULL } +}; + +/************************************************************************** + * Userdata Parameter, last data unit + */ +#define S7COMM_UD_LASTDATAUNIT_YES 0x00 +#define S7COMM_UD_LASTDATAUNIT_NO 0x01 + +static const value_string userdata_lastdataunit_names[] = { + { S7COMM_UD_LASTDATAUNIT_YES, "Yes" }, + { S7COMM_UD_LASTDATAUNIT_NO, "No" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of Function groups in userdata parameter part + */ +#define S7COMM_UD_FUNCGROUP_TIS 0x01 +#define S7COMM_UD_FUNCGROUP_CYCLIC 0x02 +#define S7COMM_UD_FUNCGROUP_BLOCK 0x03 +#define S7COMM_UD_FUNCGROUP_CPU 0x04 +#define S7COMM_UD_FUNCGROUP_SEC 0x05 /* Security functions e.g. plc password */ +#define S7COMM_UD_FUNCGROUP_PBC_BSEND 0x06 /* PBC = Programmable Block Communication (PBK in german) */ +#define S7COMM_UD_FUNCGROUP_TIME 0x07 +#define S7COMM_UD_FUNCGROUP_NCPRG 0x3f +#define S7COMM_UD_FUNCGROUP_DRR 0x20 + +static const value_string userdata_functiongroup_names[] = { + { S7COMM_UD_FUNCGROUP_TIS, "Programmer commands" }, + { S7COMM_UD_FUNCGROUP_CYCLIC, "Cyclic services" }, /* to read data from plc without a request */ + { S7COMM_UD_FUNCGROUP_BLOCK, "Block functions" }, + { S7COMM_UD_FUNCGROUP_CPU, "CPU functions" }, + { S7COMM_UD_FUNCGROUP_SEC, "Security" }, + { S7COMM_UD_FUNCGROUP_PBC_BSEND, "PBC BSEND" }, + { S7COMM_UD_FUNCGROUP_TIME, "Time functions" }, + { S7COMM_UD_FUNCGROUP_NCPRG, "NC programming" }, + { S7COMM_UD_FUNCGROUP_DRR, "DR Routing" }, + { 0, NULL } +}; + +/************************************************************************** + * Variable status: Area of data request + * + * Low Hi + * 0=M 0=BOOL + * 1=E 1=BYTE + * 2=A 2=WORD + * 3=PEx 3=DWORD + * 7=DB + * 54=TIMER + * 64=COUNTER + */ +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MX 0x00 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MB 0x01 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MW 0x02 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MD 0x03 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EX 0x10 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EB 0x11 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EW 0x12 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_ED 0x13 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AX 0x20 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AB 0x21 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AW 0x22 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AD 0x23 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PEB 0x31 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PEW 0x32 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PED 0x33 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBX 0x70 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBB 0x71 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBW 0x72 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBD 0x73 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_T 0x54 +#define S7COMM_UD_SUBF_TIS_VARSTAT_AREA_C 0x64 + +static const value_string userdata_tis_varstat_area_names[] = { + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MX, "MX" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MB, "MB" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MW, "MW" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MD, "MD" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EB, "IB" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EX, "IX" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EW, "IW" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_ED, "ID" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AX, "QX" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AB, "QB" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AW, "QW" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AD, "QD" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PEB, "PIB" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PEW, "PIW" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PED, "PID" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBX, "DBX" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBB, "DBB" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBW, "DBW" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBD, "DBD" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_T, "TIMER" }, + { S7COMM_UD_SUBF_TIS_VARSTAT_AREA_C, "COUNTER" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of userdata subfunctions in group 1 (Programmer commands) + * In szl dataset 0x0132/2 these are defined as "Test and installation functions TIS". + * The methods supported by the CPU are listed in the funkt_n bits. + */ +#define S7COMM_UD_SUBF_TIS_BLOCKSTAT 0x01 +#define S7COMM_UD_SUBF_TIS_VARSTAT 0x02 +#define S7COMM_UD_SUBF_TIS_OUTISTACK 0x03 +#define S7COMM_UD_SUBF_TIS_OUTBSTACK 0x04 +#define S7COMM_UD_SUBF_TIS_OUTLSTACK 0x05 +#define S7COMM_UD_SUBF_TIS_TIMEMEAS 0x06 +#define S7COMM_UD_SUBF_TIS_FORCESEL 0x07 +#define S7COMM_UD_SUBF_TIS_MODVAR 0x08 +#define S7COMM_UD_SUBF_TIS_FORCE 0x09 +#define S7COMM_UD_SUBF_TIS_BREAKPOINT 0x0a +#define S7COMM_UD_SUBF_TIS_EXITHOLD 0x0b +#define S7COMM_UD_SUBF_TIS_MEMORYRES 0x0c +#define S7COMM_UD_SUBF_TIS_DISABLEJOB 0x0d +#define S7COMM_UD_SUBF_TIS_ENABLEJOB 0x0e +#define S7COMM_UD_SUBF_TIS_DELETEJOB 0x0f +#define S7COMM_UD_SUBF_TIS_READJOBLIST 0x10 +#define S7COMM_UD_SUBF_TIS_READJOB 0x11 +#define S7COMM_UD_SUBF_TIS_REPLACEJOB 0x12 +#define S7COMM_UD_SUBF_TIS_BLOCKSTAT2 0x13 +#define S7COMM_UD_SUBF_TIS_FLASHLED 0x16 + +static const value_string userdata_tis_subfunc_names[] = { + { S7COMM_UD_SUBF_TIS_BLOCKSTAT, "Block status" }, + { S7COMM_UD_SUBF_TIS_VARSTAT, "Variable status" }, + { S7COMM_UD_SUBF_TIS_OUTISTACK, "Output ISTACK" }, + { S7COMM_UD_SUBF_TIS_OUTBSTACK, "Output BSTACK" }, + { S7COMM_UD_SUBF_TIS_OUTLSTACK, "Output LSTACK" }, + { S7COMM_UD_SUBF_TIS_TIMEMEAS, "Time measurement from to" }, /* never seen yet */ + { S7COMM_UD_SUBF_TIS_FORCESEL, "Force selection" }, + { S7COMM_UD_SUBF_TIS_MODVAR, "Modify variable" }, + { S7COMM_UD_SUBF_TIS_FORCE, "Force" }, + { S7COMM_UD_SUBF_TIS_BREAKPOINT, "Breakpoint" }, + { S7COMM_UD_SUBF_TIS_EXITHOLD, "Exit HOLD" }, + { S7COMM_UD_SUBF_TIS_MEMORYRES, "Memory reset" }, + { S7COMM_UD_SUBF_TIS_DISABLEJOB, "Disable job" }, + { S7COMM_UD_SUBF_TIS_ENABLEJOB, "Enable job" }, + { S7COMM_UD_SUBF_TIS_DELETEJOB, "Delete job" }, + { S7COMM_UD_SUBF_TIS_READJOBLIST, "Read job list" }, + { S7COMM_UD_SUBF_TIS_READJOB, "Read job" }, + { S7COMM_UD_SUBF_TIS_REPLACEJOB, "Replace job" }, + { S7COMM_UD_SUBF_TIS_BLOCKSTAT2, "Block status v2" }, + { S7COMM_UD_SUBF_TIS_FLASHLED, "Flash LED" }, + { 0, NULL } +}; + +/************************************************************************** + * Variable status: Trigger point + */ +static const value_string userdata_varstat_trgevent_names[] = { + { 0x0000, "Immediately" }, + { 0x0100, "System Trigger" }, + { 0x0200, "System checkpoint main cycle start" }, + { 0x0300, "System checkpoint main cycle end" }, + { 0x0400, "Mode transition RUN-STOP" }, + { 0x0500, "After code address" }, + { 0x0600, "Code address area" }, + { 0x0601, "Code address area with call environment" }, /* Call conditions like opened DB/DI or called block */ + { 0x0700, "Data address" }, + { 0x0800, "Data address area" }, + { 0x0900, "Local data address" }, + { 0x0a00, "Local data address area" }, + { 0x0b00, "Range trigger" }, + { 0x0c00, "Before code address" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of userdata subfunctions in group 2 (cyclic data) + */ +#define S7COMM_UD_SUBF_CYCLIC_TRANSF 0x01 +#define S7COMM_UD_SUBF_CYCLIC_UNSUBSCRIBE 0x04 +#define S7COMM_UD_SUBF_CYCLIC_CHANGE 0x05 +#define S7COMM_UD_SUBF_CYCLIC_CHANGE_MOD 0x07 +#define S7COMM_UD_SUBF_CYCLIC_RDREC 0x08 + +static const value_string userdata_cyclic_subfunc_names[] = { + { S7COMM_UD_SUBF_CYCLIC_TRANSF, "Cyclic transfer" }, + { S7COMM_UD_SUBF_CYCLIC_UNSUBSCRIBE, "Unsubscribe" }, + { S7COMM_UD_SUBF_CYCLIC_CHANGE, "Change driven transfer" }, + { S7COMM_UD_SUBF_CYCLIC_CHANGE_MOD, "Change driven transfer modify" }, + { S7COMM_UD_SUBF_CYCLIC_RDREC, "RDREC" }, + { 0, NULL } +}; + +/************************************************************************** + * Timebase for cyclic services + */ +static const value_string cycl_interval_timebase_names[] = { + { 0, "100 milliseconds" }, + { 1, "1 second" }, + { 2, "10 seconds" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of userdata subfunctions in group 3 (Block functions) + */ +#define S7COMM_UD_SUBF_BLOCK_LIST 0x01 +#define S7COMM_UD_SUBF_BLOCK_LISTTYPE 0x02 +#define S7COMM_UD_SUBF_BLOCK_BLOCKINFO 0x03 + +static const value_string userdata_block_subfunc_names[] = { + { S7COMM_UD_SUBF_BLOCK_LIST, "List blocks" }, + { S7COMM_UD_SUBF_BLOCK_LISTTYPE, "List blocks of type" }, + { S7COMM_UD_SUBF_BLOCK_BLOCKINFO, "Get block info" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of userdata subfunctions in group 4 (CPU functions) + */ +#define S7COMM_UD_SUBF_CPU_SCAN_IND 0x09 +#define S7COMM_UD_SUBF_CPU_AR_SEND_IND 0x10 + +static const value_string userdata_cpu_subfunc_names[] = { + { S7COMM_UD_SUBF_CPU_READSZL, "Read SZL" }, + { S7COMM_UD_SUBF_CPU_MSGS, "Message service" }, /* Header constant is also different here */ + { S7COMM_UD_SUBF_CPU_DIAGMSG, "Diagnostic message" }, /* Diagnostic message from PLC */ + { S7COMM_UD_SUBF_CPU_ALARM8_IND, "ALARM_8 indication" }, /* PLC is indicating an ALARM message, using ALARM_8 SFBs */ + { S7COMM_UD_SUBF_CPU_NOTIFY_IND, "NOTIFY indication" }, /* PLC is indicating a NOTIFY message, using NOTIFY SFBs */ + { S7COMM_UD_SUBF_CPU_ALARM8LOCK, "ALARM_8 lock" }, /* Lock an ALARM message from HMI/SCADA */ + { S7COMM_UD_SUBF_CPU_ALARM8UNLOCK, "ALARM_8 unlock" }, /* Unlock an ALARM message from HMI/SCADA */ + { S7COMM_UD_SUBF_CPU_SCAN_IND, "SCAN indication" }, /* PLC is indicating a SCAN message */ + { S7COMM_UD_SUBF_CPU_AR_SEND_IND, "AR_SEND indication" }, /* PLC is indicating a AR_SEND message */ + { S7COMM_UD_SUBF_CPU_ALARMS_IND, "ALARM_S indication" }, /* PLC is indicating an ALARM message, using ALARM_S/ALARM_D SFCs */ + { S7COMM_UD_SUBF_CPU_ALARMSQ_IND, "ALARM_SQ indication" }, /* PLC is indicating an ALARM message, using ALARM_SQ/ALARM_DQ SFCs */ + { S7COMM_UD_SUBF_CPU_ALARMQUERY, "ALARM query" }, /* HMI/SCADA query of ALARMs */ + { S7COMM_UD_SUBF_CPU_ALARMACK, "ALARM ack" }, /* Alarm was acknowledged in HMI/SCADA */ + { S7COMM_UD_SUBF_CPU_ALARMACK_IND, "ALARM ack indication" }, /* Alarm acknowledge indication from CPU to HMI */ + { S7COMM_UD_SUBF_CPU_ALARM8LOCK_IND, "ALARM lock indication" }, /* Alarm lock indication from CPU to HMI */ + { S7COMM_UD_SUBF_CPU_ALARM8UNLOCK_IND, "ALARM unlock indication" }, /* Alarm unlock indication from CPU to HMI */ + { S7COMM_UD_SUBF_CPU_NOTIFY8_IND, "NOTIFY_8 indication" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of userdata subfunctions in group 5 (Security?) + */ +#define S7COMM_UD_SUBF_SEC_PASSWD 0x01 + +static const value_string userdata_sec_subfunc_names[] = { + { S7COMM_UD_SUBF_SEC_PASSWD, "PLC password" }, + { 0, NULL } +}; + +/************************************************************************** + * Names of userdata subfunctions in group 7 (Time functions) + */ +#define S7COMM_UD_SUBF_TIME_READ 0x01 +#define S7COMM_UD_SUBF_TIME_SET 0x02 +#define S7COMM_UD_SUBF_TIME_READF 0x03 +#define S7COMM_UD_SUBF_TIME_SET2 0x04 + +static const value_string userdata_time_subfunc_names[] = { + { S7COMM_UD_SUBF_TIME_READ, "Read clock" }, + { S7COMM_UD_SUBF_TIME_SET, "Set clock" }, + { S7COMM_UD_SUBF_TIME_READF, "Read clock (following)" }, + { S7COMM_UD_SUBF_TIME_SET2, "Set clock" }, + { 0, NULL } +}; + +/******************************************************************************************************* + * Weekday names in DATE_AND_TIME + */ +static const value_string weekdaynames[] = { + { 0, "Undefined" }, + { 1, "Sunday" }, + { 2, "Monday" }, + { 3, "Tuesday" }, + { 4, "Wednesday" }, + { 5, "Thursday" }, + { 6, "Friday" }, + { 7, "Saturday" }, + { 0, NULL } +}; + +/************************************************************************** + **************************************************************************/ + +/************************************************************************** + * Flags for LID access + */ +#define S7COMM_TIA1200_VAR_ENCAPS_LID 0x2 +#define S7COMM_TIA1200_VAR_ENCAPS_IDX 0x3 +#define S7COMM_TIA1200_VAR_OBTAIN_LID 0x4 +#define S7COMM_TIA1200_VAR_OBTAIN_IDX 0x5 +#define S7COMM_TIA1200_VAR_PART_START 0x6 +#define S7COMM_TIA1200_VAR_PART_LEN 0x7 + +static const value_string tia1200_var_lid_flag_names[] = { + { S7COMM_TIA1200_VAR_ENCAPS_LID, "Encapsulated LID" }, + { S7COMM_TIA1200_VAR_ENCAPS_IDX, "Encapsulated Index" }, + { S7COMM_TIA1200_VAR_OBTAIN_LID, "Obtain by LID" }, + { S7COMM_TIA1200_VAR_OBTAIN_IDX, "Obtain by Index" }, + { S7COMM_TIA1200_VAR_PART_START, "Part Start Address" }, + { S7COMM_TIA1200_VAR_PART_LEN, "Part Length" }, + { 0, NULL } +}; + +/************************************************************************** + * TIA 1200 Area Names for variable access + */ +#define S7COMM_TIA1200_VAR_ITEM_AREA1_DB 0x8a0e /* Reading DB, 2 byte DB-Number following */ +#define S7COMM_TIA1200_VAR_ITEM_AREA1_IQMCT 0x0000 /* Reading I/Q/M/C/T, 2 Byte detail area following */ + +static const value_string tia1200_var_item_area1_names[] = { + { S7COMM_TIA1200_VAR_ITEM_AREA1_DB, "DB" }, + { S7COMM_TIA1200_VAR_ITEM_AREA1_IQMCT, "IQMCT" }, + { 0, NULL } +}; + +#define S7COMM_TIA1200_VAR_ITEM_AREA2_I 0x50 +#define S7COMM_TIA1200_VAR_ITEM_AREA2_Q 0x51 +#define S7COMM_TIA1200_VAR_ITEM_AREA2_M 0x52 +#define S7COMM_TIA1200_VAR_ITEM_AREA2_C 0x53 +#define S7COMM_TIA1200_VAR_ITEM_AREA2_T 0x54 + +static const value_string tia1200_var_item_area2_names[] = { + { S7COMM_TIA1200_VAR_ITEM_AREA2_I, "Inputs (I)" }, + { S7COMM_TIA1200_VAR_ITEM_AREA2_Q, "Outputs (Q)" }, + { S7COMM_TIA1200_VAR_ITEM_AREA2_M, "Flags (M)" }, + { S7COMM_TIA1200_VAR_ITEM_AREA2_C, "Counter (C)" }, + { S7COMM_TIA1200_VAR_ITEM_AREA2_T, "Timer (T)" }, + { 0, NULL } +}; + +/************************************************************************** + * NCK areas + */ +#define S7COMM_NCK_AREA_N_NCK 0 +#define S7COMM_NCK_AREA_B_MODEGROUP 1 +#define S7COMM_NCK_AREA_C_CHANNEL 2 +#define S7COMM_NCK_AREA_A_AXIS 3 +#define S7COMM_NCK_AREA_T_TOOL 4 +#define S7COMM_NCK_AREA_V_FEEDDRIVE 5 +#define S7COMM_NCK_AREA_H_MAINDRIVE 6 +#define S7COMM_NCK_AREA_M_MMC 7 + +static const value_string nck_area_names[] = { + { S7COMM_NCK_AREA_N_NCK, "N - NCK" }, + { S7COMM_NCK_AREA_B_MODEGROUP, "B - Mode group" }, + { S7COMM_NCK_AREA_C_CHANNEL, "C - Channel" }, + { S7COMM_NCK_AREA_A_AXIS, "A - Axis" }, + { S7COMM_NCK_AREA_T_TOOL, "T - Tool" }, + { S7COMM_NCK_AREA_V_FEEDDRIVE, "V - Feed drive" }, + { S7COMM_NCK_AREA_H_MAINDRIVE, "M - Main drive" }, + { S7COMM_NCK_AREA_M_MMC, "M - MMC" }, + { 0, NULL } +}; + +static const value_string nck_module_names[] = { + { 0x10, "Y - Global system data" }, + { 0x11, "YNCFL - NCK instruction groups" }, + { 0x12, "FU - NCU global settable frames" }, + { 0x13, "FA - Active NCU global frames" }, + { 0x14, "TO - Tool data" }, + { 0x15, "RP - Arithmetic parameters" }, + { 0x16, "SE - Setting data" }, + { 0x17, "SGUD - SGUD-Block" }, + { 0x18, "LUD - Local userdata" }, + { 0x19, "TC - Toolholder parameters" }, + { 0x1a, "M - Machine data" }, + { 0x1c, "WAL - Working area limitation" }, + { 0x1e, "DIAG - Internal diagnostic data" }, + { 0x1f, "CC - Unknown" }, + { 0x20, "FE - Channel-specific external frame" }, + { 0x21, "TD - Tool data: General data" }, + { 0x22, "TS - Tool edge data: Monitoring data" }, + { 0x23, "TG - Tool data: Grinding-specific data" }, + { 0x24, "TU - Tool data" }, + { 0x25, "TUE - Tool edge data, userdefined data" }, + { 0x26, "TV - Tool data, directory" }, + { 0x27, "TM - Magazine data: General data" }, + { 0x28, "TP - Magazine data: Location data" }, + { 0x29, "TPM - Magazine data: Multiple assignment of location data" }, + { 0x2a, "TT - Magazine data: Location typ" }, + { 0x2b, "TMV - Magazine data: Directory" }, + { 0x2c, "TMC - Magazine data: Configuration data" }, + { 0x2d, "MGUD - MGUD-Block" }, + { 0x2e, "UGUD - UGUD-Block" }, + { 0x2f, "GUD4 - GUD4-Block" }, + { 0x30, "GUD5 - GUD5-Block" }, + { 0x31, "GUD6 - GUD6-Block" }, + { 0x32, "GUD7 - GUD7-Block" }, + { 0x33, "GUD8 - GUD8-Block" }, + { 0x34, "GUD9 - GUD9-Block" }, + { 0x35, "PA - Channel-specific protection zones" }, + { 0x36, "GD1 - SGUD-Block GD1" }, + { 0x37, "NIB - State data: Nibbling" }, + { 0x38, "ETP - Types of events" }, + { 0x39, "ETPD - Data lists for protocolling" }, + { 0x3a, "SYNACT - Channel-specific synchronous actions" }, + { 0x3b, "DIAGN - Diagnostic data" }, + { 0x3c, "VSYN - Channel-specific user variables for synchronous actions" }, + { 0x3d, "TUS - Tool data: user monitoring data" }, + { 0x3e, "TUM - Tool data: user magazine data" }, + { 0x3f, "TUP - Tool data: user magazine place data" }, + { 0x40, "TF - Parameterizing, return parameters of _N_TMGETT, _N_TSEARC" }, + { 0x41, "FB - Channel-specific base frames" }, + { 0x42, "SSP2 - State data: Spindle" }, + { 0x43, "PUD - programmglobale Benutzerdaten" }, + { 0x44, "TOS - Edge-related location-dependent fine total offsets" }, + { 0x45, "TOST - Edge-related location-dependent fine total offsets, transformed" }, + { 0x46, "TOE - Edge-related coarse total offsets, setup offsets" }, + { 0x47, "TOET - Edge-related coarse total offsets, transformed setup offsets" }, + { 0x48, "AD - Adapter data" }, + { 0x49, "TOT - Edge data: Transformed offset data" }, + { 0x4a, "AEV - Working offsets: Directory" }, + { 0x4b, "YFAFL - NCK instruction groups (Fanuc)" }, + { 0x4c, "FS - System-Frame" }, + { 0x4d, "SD - Servo data" }, + { 0x4e, "TAD - Application-specific data" }, + { 0x4f, "TAO - Application-specific cutting edge data" }, + { 0x50, "TAS - Application-specific monitoring data" }, + { 0x51, "TAM - Application-specific magazine data" }, + { 0x52, "TAP - Application-specific magazine location data" }, + { 0x53, "MEM - Unknown" }, + { 0x54, "SALUC - Alarm actions: List in reverse chronological order" }, + { 0x55, "AUXFU - Auxiliary functions" }, + { 0x56, "TDC - Tool/Tools" }, + { 0x57, "CP - Generic coupling" }, + { 0x6e, "SDME - Unknown" }, + { 0x6f, "SPARPI - Program pointer on interruption" }, + { 0x70, "SEGA - State data: Geometry axes in tool offset memory (extended)" }, + { 0x71, "SEMA - State data: Machine axes (extended)" }, + { 0x72, "SSP - State data: Spindle" }, + { 0x73, "SGA - State data: Geometry axes in tool offset memory" }, + { 0x74, "SMA - State data: Machine axes" }, + { 0x75, "SALAL - Alarms: List organized according to time" }, + { 0x76, "SALAP - Alarms: List organized according to priority" }, + { 0x77, "SALA - Alarms: List organized according to time" }, + { 0x78, "SSYNAC - Synchronous actions" }, + { 0x79, "SPARPF - Program pointers for block search and stop run" }, + { 0x7a, "SPARPP - Program pointer in automatic operation" }, + { 0x7b, "SNCF - Active G functions" }, + { 0x7d, "SPARP - Part program information" }, + { 0x7e, "SINF - Part-program-specific status data" }, + { 0x7f, "S - State data" }, + { 0x80, "0x80 - Unknown" }, + { 0x81, "0x81 - Unknown" }, + { 0x82, "0x82 - Unknown" }, + { 0x83, "0x83 - Unknown" }, + { 0x84, "0x84 - Unknown" }, + { 0x85, "0x85 - Unknown" }, + { 0xfd, "0 - Internal" }, + { 0, NULL } +}; +static value_string_ext nck_module_names_ext = VALUE_STRING_EXT_INIT(nck_module_names); + +static gint hf_s7comm_tia1200_item_reserved1 = -1; /* 1 Byte Reserved (always 0xff?) */ +static gint hf_s7comm_tia1200_item_area1 = -1; /* 2 Byte2 Root area (DB or IQMCT) */ +static gint hf_s7comm_tia1200_item_area2 = -1; /* 2 Bytes detail area (I/Q/M/C/T) */ +static gint hf_s7comm_tia1200_item_area2unknown = -1; /* 2 Bytes detail area for possible unknown or not seen areas */ +static gint hf_s7comm_tia1200_item_dbnumber = -1; /* 2 Bytes DB number */ +static gint hf_s7comm_tia1200_item_crc = -1; /* 4 Bytes CRC */ + +static gint hf_s7comm_tia1200_substructure_item = -1; /* Substructure */ +static gint hf_s7comm_tia1200_var_lid_flags = -1; /* LID Flags */ +static gint hf_s7comm_tia1200_item_value = -1; + +/************************************************************************** + **************************************************************************/ + +/* Header Block */ +static gint hf_s7comm_header = -1; +static gint hf_s7comm_header_protid = -1; /* Header Byte 0 */ +static gint hf_s7comm_header_rosctr = -1; /* Header Bytes 1 */ +static gint hf_s7comm_header_redid = -1; /* Header Bytes 2, 3 */ +static gint hf_s7comm_header_pduref = -1; /* Header Bytes 4, 5 */ +static gint hf_s7comm_header_parlg = -1; /* Header Bytes 6, 7 */ +static gint hf_s7comm_header_datlg = -1; /* Header Bytes 8, 9 */ +static gint hf_s7comm_header_errcls = -1; /* Header Byte 10, only available at type 2 or 3 */ +static gint hf_s7comm_header_errcod = -1; /* Header Byte 11, only available at type 2 or 3 */ +/* Parameter Block */ +static gint hf_s7comm_param = -1; +static gint hf_s7comm_param_errcod = -1; /* Parameter part: Error code */ +static gint hf_s7comm_param_service = -1; /* Parameter part: service */ +static gint hf_s7comm_param_itemcount = -1; /* Parameter part: item count */ +static gint hf_s7comm_param_data = -1; /* Parameter part: data */ +static gint hf_s7comm_param_neg_pdu_length = -1; /* Parameter part: Negotiate PDU length */ +static gint hf_s7comm_param_setup_reserved1 = -1; /* Parameter part: Reserved byte in communication setup pdu*/ + +static gint hf_s7comm_param_maxamq_calling = -1; /* Parameter part: Max AmQ calling */ +static gint hf_s7comm_param_maxamq_called = -1; /* Parameter part: Max AmQ called */ + +/* Item data */ +static gint hf_s7comm_param_item = -1; +static gint hf_s7comm_param_subitem = -1; /* Substructure */ +static gint hf_s7comm_item_varspec = -1; /* Variable specification */ +static gint hf_s7comm_item_varspec_length = -1; /* Length of following address specification */ +static gint hf_s7comm_item_syntax_id = -1; /* Syntax Id */ +static gint hf_s7comm_item_transport_size = -1; /* Transport size, 1 Byte*/ +static gint hf_s7comm_item_length = -1; /* length, 2 Bytes*/ +static gint hf_s7comm_item_db = -1; /* DB/M/E/A, 2 Bytes */ +static gint hf_s7comm_item_area = -1; /* Area code, 1 byte */ +static gint hf_s7comm_item_address = -1; /* Bit address, 3 Bytes */ +static gint hf_s7comm_item_address_byte = -1; /* address: Byte address */ +static gint hf_s7comm_item_address_bit = -1; /* address: Bit address */ +static gint hf_s7comm_item_address_nr = -1; /* address: Timer/Counter/block number */ +/* Special variable read with Syntax-Id 0xb0 (DBREAD) */ +static gint hf_s7comm_item_dbread_numareas = -1; /* Number of areas following, 1 Byte*/ +static gint hf_s7comm_item_dbread_length = -1; /* length, 1 Byte*/ +static gint hf_s7comm_item_dbread_db = -1; /* DB number, 2 Bytes*/ +static gint hf_s7comm_item_dbread_startadr = -1; /* Start address, 2 Bytes*/ +/* Reading frequency inverter parameters via routing */ +static gint hf_s7comm_item_driveesany_unknown1 = -1; /* Unknown value 1, 1 Byte */ +static gint hf_s7comm_item_driveesany_unknown2 = -1; /* Unknown value 2, 2 Bytes */ +static gint hf_s7comm_item_driveesany_unknown3 = -1; /* Unknown value 3, 2 Bytes */ +static gint hf_s7comm_item_driveesany_parameter_nr = -1; /* Parameter number, 2 Bytes */ +static gint hf_s7comm_item_driveesany_parameter_idx = -1; /* Parameter index, 2 Bytes */ +/* NCK access with Syntax-Id 0x82 */ +static gint hf_s7comm_item_nck_areaunit = -1; /* Bitmask: aaauuuuu: a=area, u=unit */ +static gint hf_s7comm_item_nck_area = -1; +static gint hf_s7comm_item_nck_unit = -1; +static gint hf_s7comm_item_nck_column = -1; +static gint hf_s7comm_item_nck_line = -1; +static gint hf_s7comm_item_nck_module = -1; +static gint hf_s7comm_item_nck_linecount = -1; + +static gint hf_s7comm_data = -1; +static gint hf_s7comm_data_returncode = -1; /* return code, 1 byte */ +static gint hf_s7comm_data_transport_size = -1; /* transport size 1 byte */ +static gint hf_s7comm_data_length = -1; /* Length of data, 2 Bytes */ + +static gint hf_s7comm_data_item = -1; + +static gint hf_s7comm_readresponse_data = -1; +static gint hf_s7comm_data_fillbyte = -1; + +/* timefunction: s7 timestamp */ +static gint hf_s7comm_data_ts = -1; +static gint hf_s7comm_data_ts_reserved = -1; +static gint hf_s7comm_data_ts_year1 = -1; /* first byte of BCD coded year, should be ignored */ +static gint hf_s7comm_data_ts_year2 = -1; /* second byte of BCD coded year, if 00...89 then it's 2000...2089, else 1990...1999*/ +static gint hf_s7comm_data_ts_month = -1; +static gint hf_s7comm_data_ts_day = -1; +static gint hf_s7comm_data_ts_hour = -1; +static gint hf_s7comm_data_ts_minute = -1; +static gint hf_s7comm_data_ts_second = -1; +static gint hf_s7comm_data_ts_millisecond = -1; +static gint hf_s7comm_data_ts_weekday = -1; + +/* userdata, block services */ +static gint hf_s7comm_userdata_data = -1; + +static gint hf_s7comm_userdata_param_type = -1; +static gint hf_s7comm_userdata_param_funcgroup = -1; +static gint hf_s7comm_userdata_param_subfunc_prog = -1; +static gint hf_s7comm_userdata_param_subfunc_cyclic = -1; +static gint hf_s7comm_userdata_param_subfunc_block = -1; +static gint hf_s7comm_userdata_param_subfunc_cpu = -1; +static gint hf_s7comm_userdata_param_subfunc_sec = -1; +static gint hf_s7comm_userdata_param_subfunc_time = -1; +static gint hf_s7comm_userdata_param_subfunc_ncprg = -1; +static gint hf_s7comm_userdata_param_subfunc_drr = -1; +static gint hf_s7comm_userdata_param_subfunc = -1; /* for all other subfunctions */ +static gint hf_s7comm_userdata_param_seq_num = -1; +static gint hf_s7comm_userdata_param_dataunitref = -1; +static gint hf_s7comm_userdata_param_dataunit = -1; + +/* block functions, list blocks of type */ +static gint hf_s7comm_ud_blockinfo_block_type = -1; /* Block type, 2 bytes */ +static gint hf_s7comm_ud_blockinfo_block_num = -1; /* Block number, 2 bytes as int */ +static gint hf_s7comm_ud_blockinfo_block_cnt = -1; /* Count, 2 bytes as int */ +static gint hf_s7comm_ud_blockinfo_block_flags = -1; /* Block flags (unknown), 1 byte */ +static gint hf_s7comm_ud_blockinfo_block_lang = -1; /* Block language, 1 byte, stringlist blocklanguage_names */ +/* block functions, get block infos */ +static gint hf_s7comm_ud_blockinfo_block_num_ascii = -1; /* Block number, 5 bytes, ASCII*/ +static gint hf_s7comm_ud_blockinfo_filesys = -1; /* Filesystem, 1 byte, ASCII*/ +static gint hf_s7comm_ud_blockinfo_res_infolength = -1; /* Length of Info, 2 bytes as int */ +static gint hf_s7comm_ud_blockinfo_res_unknown2 = -1; /* Unknown blockinfo 2, 2 bytes, HEX*/ +static gint hf_s7comm_ud_blockinfo_res_const3 = -1; /* Constant 3, 2 bytes, ASCII */ +static gint hf_s7comm_ud_blockinfo_res_unknown = -1; /* Unknown byte(s) */ +static gint hf_s7comm_ud_blockinfo_subblk_type = -1; /* Subblk type, 1 byte, stringlist subblktype_names */ +static gint hf_s7comm_ud_blockinfo_load_mem_len = -1; /* Length load memory, 4 bytes, int */ +static gint hf_s7comm_ud_blockinfo_blocksecurity = -1; /* Block Security, 4 bytes, stringlist blocksecurity_names*/ +static gint hf_s7comm_ud_blockinfo_interface_timestamp = -1;/* Interface Timestamp, string */ +static gint hf_s7comm_ud_blockinfo_code_timestamp = -1; /* Code Timestamp, string */ +static gint hf_s7comm_ud_blockinfo_ssb_len = -1; /* SSB length, 2 bytes, int */ +static gint hf_s7comm_ud_blockinfo_add_len = -1; /* ADD length, 2 bytes, int */ +static gint hf_s7comm_ud_blockinfo_localdata_len = -1; /* Length localdata, 2 bytes, int */ +static gint hf_s7comm_ud_blockinfo_mc7_len = -1; /* Length MC7 code, 2 bytes, int */ +static gint hf_s7comm_ud_blockinfo_author = -1; /* Author, 8 bytes, ASCII */ +static gint hf_s7comm_ud_blockinfo_family = -1; /* Family, 8 bytes, ASCII */ +static gint hf_s7comm_ud_blockinfo_headername = -1; /* Name (Header), 8 bytes, ASCII */ +static gint hf_s7comm_ud_blockinfo_headerversion = -1; /* Version (Header), 8 bytes, ASCII */ +static gint hf_s7comm_ud_blockinfo_checksum = -1; /* Block checksum, 2 bytes, HEX */ +static gint hf_s7comm_ud_blockinfo_reserved1 = -1; /* Reserved 1, 4 bytes, HEX */ +static gint hf_s7comm_ud_blockinfo_reserved2 = -1; /* Reserved 2, 4 bytes, HEX */ + +static gint hf_s7comm_userdata_blockinfo_flags = -1; /* Some flags in Block info response */ +static gint hf_s7comm_userdata_blockinfo_linked = -1; /* Some flags in Block info response */ +static gint hf_s7comm_userdata_blockinfo_standard_block = -1; +static gint hf_s7comm_userdata_blockinfo_nonretain = -1; /* Some flags in Block info response */ +static gint ett_s7comm_userdata_blockinfo_flags = -1; +static int * const s7comm_userdata_blockinfo_flags_fields[] = { + &hf_s7comm_userdata_blockinfo_linked, + &hf_s7comm_userdata_blockinfo_standard_block, + &hf_s7comm_userdata_blockinfo_nonretain, + NULL +}; + +/* Programmer commands / Test and installation (TIS) functions */ +static gint hf_s7comm_tis_parameter = -1; +static gint hf_s7comm_tis_data = -1; +static gint hf_s7comm_tis_parametersize = -1; +static gint hf_s7comm_tis_datasize = -1; +static gint hf_s7comm_tis_param1 = -1; +static gint hf_s7comm_tis_param2 = -1; +static const value_string tis_param2_names[] = { /* Values and their meaning are not always clearly defined in every function */ + { 0, "Update Monitor Variables / Activate Modify Values"}, + { 1, "Monitor Variable / Modify Variable" }, + { 2, "Modify Variable permanent" }, + { 256, "Force immediately" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_param3 = -1; +static const value_string tis_param3_names[] = { + { 0, "Every cycle (permanent)" }, + { 1, "Once" }, + { 2, "Always (force)" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_answersize = -1; +static gint hf_s7comm_tis_param5 = -1; +static gint hf_s7comm_tis_param6 = -1; +static gint hf_s7comm_tis_param7 = -1; +static gint hf_s7comm_tis_param8 = -1; +static gint hf_s7comm_tis_param9 = -1; +static gint hf_s7comm_tis_trgevent = -1; +static gint hf_s7comm_tis_res_param1 = -1; +static gint hf_s7comm_tis_res_param2 = -1; +static gint hf_s7comm_tis_job_function = -1; +static gint hf_s7comm_tis_job_seqnr = -1; +static gint hf_s7comm_tis_job_reserved = -1; + + + +/* B/I/L Stack */ +static gint hf_s7comm_tis_interrupted_blocktype = -1; +static gint hf_s7comm_tis_interrupted_blocknr = -1; +static gint hf_s7comm_tis_interrupted_address = -1; +static gint hf_s7comm_tis_interrupted_prioclass = -1; +static gint hf_s7comm_tis_continued_blocktype = -1; +static gint hf_s7comm_tis_continued_blocknr = -1; +static gint hf_s7comm_tis_continued_address = -1; +static gint hf_s7comm_tis_breakpoint_blocktype = -1; +static gint hf_s7comm_tis_breakpoint_blocknr = -1; +static gint hf_s7comm_tis_breakpoint_address = -1; +static gint hf_s7comm_tis_breakpoint_reserved = -1; + +static gint hf_s7comm_tis_p_callenv = -1; +static const value_string tis_p_callenv_names[] = { + { 0, "Specified call environment"}, + { 2, "Specified global and/or instance data block"}, + { 0, NULL } +}; +static gint hf_s7comm_tis_p_callcond = -1; +static const value_string tis_p_callcond_names[] = { + { 0x0000, "Not set" }, + { 0x0001, "On block number" }, + { 0x0101, "On block number with code address" }, + { 0x0a00, "On DB1 (DB) content" }, + { 0x000a, "On DB2 (DI) content" }, + { 0x0a0a, "On DB1 (DB) and DB2 (DI) content" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_p_callcond_blocktype = -1; +static gint hf_s7comm_tis_p_callcond_blocknr = -1; +static gint hf_s7comm_tis_p_callcond_address = -1; + + +static gint hf_s7comm_tis_register_db1_type = -1; +static gint hf_s7comm_tis_register_db2_type = -1; +static gint hf_s7comm_tis_register_db1_nr = -1; +static gint hf_s7comm_tis_register_db2_nr = -1; +static gint hf_s7comm_tis_register_accu1 = -1; +static gint hf_s7comm_tis_register_accu2 = -1; +static gint hf_s7comm_tis_register_accu3 = -1; +static gint hf_s7comm_tis_register_accu4 = -1; +static gint hf_s7comm_tis_register_ar1 = -1; +static gint hf_s7comm_tis_register_ar2 = -1; +static gint hf_s7comm_tis_register_stw = -1; +static gint hf_s7comm_tis_exithold_until = -1; +static const value_string tis_exithold_until_names[] = { + { 0, "Next breakpoint" }, + { 1, "Next statement" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_exithold_res1 = -1; +static gint hf_s7comm_tis_bstack_nest_depth = -1; +static gint hf_s7comm_tis_bstack_reserved = -1; +static gint hf_s7comm_tis_istack_reserved = -1; +static gint hf_s7comm_tis_lstack_reserved = -1; +static gint hf_s7comm_tis_lstack_size = -1; +static gint hf_s7comm_tis_lstack_data = -1; +static gint hf_s7comm_tis_blockstat_flagsunknown = -1; +static gint hf_s7comm_tis_blockstat_number_of_lines = -1; +static gint hf_s7comm_tis_blockstat_line_address = -1; +static gint hf_s7comm_tis_blockstat_data = -1; +static gint hf_s7comm_tis_blockstat_reserved = -1; + +/* Organization block local data */ +static gint hf_s7comm_ob_ev_class = -1; +static gint hf_s7comm_ob_scan_1 = -1; +static gint hf_s7comm_ob_strt_inf = -1; +static gint hf_s7comm_ob_flt_id = -1; +static gint hf_s7comm_ob_priority = -1; +static gint hf_s7comm_ob_number = -1; +static gint hf_s7comm_ob_reserved_1 = -1; +static gint hf_s7comm_ob_reserved_2 = -1; +static gint hf_s7comm_ob_reserved_3 = -1; +static gint hf_s7comm_ob_reserved_4 = -1; +static gint hf_s7comm_ob_reserved_4_dw = -1; +static gint hf_s7comm_ob_prev_cycle = -1; +static gint hf_s7comm_ob_min_cycle = -1; +static gint hf_s7comm_ob_max_cycle = -1; +static gint hf_s7comm_ob_period_exe = -1; +static gint hf_s7comm_ob_sign = -1; +static gint hf_s7comm_ob_dtime = -1; +static gint hf_s7comm_ob_phase_offset = -1; +static gint hf_s7comm_ob_exec_freq = -1; +static gint hf_s7comm_ob_io_flag = -1; +static gint hf_s7comm_ob_mdl_addr = -1; +static gint hf_s7comm_ob_point_addr = -1; +static gint hf_s7comm_ob_inf_len = -1; +static gint hf_s7comm_ob_alarm_type = -1; +static gint hf_s7comm_ob_alarm_slot = -1; +static gint hf_s7comm_ob_alarm_spec = -1; +static gint hf_s7comm_ob_error_info = -1; +static gint hf_s7comm_ob_err_ev_class = -1; +static gint hf_s7comm_ob_err_ev_num = -1; +static gint hf_s7comm_ob_err_ob_priority = -1; +static gint hf_s7comm_ob_err_ob_num = -1; +static gint hf_s7comm_ob_rack_cpu = -1; +static gint hf_s7comm_ob_8x_fault_flags = -1; +static gint hf_s7comm_ob_mdl_type_b = -1; +static gint hf_s7comm_ob_mdl_type_w = -1; +static gint hf_s7comm_ob_rack_num = -1; +static gint hf_s7comm_ob_racks_flt = -1; +static gint hf_s7comm_ob_strtup = -1; +static gint hf_s7comm_ob_stop = -1; +static gint hf_s7comm_ob_strt_info = -1; +static gint hf_s7comm_ob_sw_flt = -1; +static gint hf_s7comm_ob_blk_type = -1; +static gint hf_s7comm_ob_flt_reg = -1; +static gint hf_s7comm_ob_flt_blk_num = -1; +static gint hf_s7comm_ob_prg_addr = -1; +static gint hf_s7comm_ob_mem_area = -1; +static gint hf_s7comm_ob_mem_addr = -1; + +static gint hf_s7comm_diagdata_req_block_type = -1; +static gint hf_s7comm_diagdata_req_block_num = -1; +static gint hf_s7comm_diagdata_req_startaddr_awl = -1; +static gint hf_s7comm_diagdata_req_saz = -1; + +/* Flags for requested registers in diagnostic data telegrams */ +static gint hf_s7comm_diagdata_registerflag = -1; /* Registerflags */ +static gint hf_s7comm_diagdata_registerflag_stw = -1; /* STW = Status word */ +static gint hf_s7comm_diagdata_registerflag_accu1 = -1; /* Accumulator 1 */ +static gint hf_s7comm_diagdata_registerflag_accu2 = -1; /* Accumulator 2 */ +static gint hf_s7comm_diagdata_registerflag_ar1 = -1; /* Addressregister 1 */ +static gint hf_s7comm_diagdata_registerflag_ar2 = -1; /* Addressregister 2 */ +static gint hf_s7comm_diagdata_registerflag_db1 = -1; /* Datablock register 1 */ +static gint hf_s7comm_diagdata_registerflag_db2 = -1; /* Datablock register 2 */ +static gint ett_s7comm_diagdata_registerflag = -1; +static int * const s7comm_diagdata_registerflag_fields[] = { + &hf_s7comm_diagdata_registerflag_stw, + &hf_s7comm_diagdata_registerflag_accu1, + &hf_s7comm_diagdata_registerflag_accu2, + &hf_s7comm_diagdata_registerflag_ar1, + &hf_s7comm_diagdata_registerflag_ar2, + &hf_s7comm_diagdata_registerflag_db1, + &hf_s7comm_diagdata_registerflag_db2, + NULL +}; + +static heur_dissector_list_t s7comm_heur_subdissector_list; + +static expert_field ei_s7comm_data_blockcontrol_block_num_invalid = EI_INIT; +static expert_field ei_s7comm_ud_blockinfo_block_num_ascii_invalid = EI_INIT; + +/* PI service name IDs. Index represents the index in pi_service_names */ +typedef enum +{ + S7COMM_PI_UNKNOWN = 0, + S7COMM_PI_INSE, + S7COMM_PI_INS2, + S7COMM_PI_DELE, + S7COMM_PIP_PROGRAM, + S7COMM_PI_MODU, + S7COMM_PI_GARB, + S7COMM_PI_N_LOGIN_, + S7COMM_PI_N_LOGOUT, + S7COMM_PI_N_CANCEL, + S7COMM_PI_N_DASAVE, + S7COMM_PI_N_DIGIOF, + S7COMM_PI_N_DIGION, + S7COMM_PI_N_DZERO_, + S7COMM_PI_N_ENDEXT, + S7COMM_PI_N_F_OPER, + S7COMM_PI_N_OST_OF, + S7COMM_PI_N_OST_ON, + S7COMM_PI_N_SCALE_, + S7COMM_PI_N_SETUFR, + S7COMM_PI_N_STRTLK, + S7COMM_PI_N_STRTUL, + S7COMM_PI_N_TMRASS, + S7COMM_PI_N_F_DELE, + S7COMM_PI_N_EXTERN, + S7COMM_PI_N_EXTMOD, + S7COMM_PI_N_F_DELR, + S7COMM_PI_N_F_XFER, + S7COMM_PI_N_LOCKE_, + S7COMM_PI_N_SELECT, + S7COMM_PI_N_SRTEXT, + S7COMM_PI_N_F_CLOS, + S7COMM_PI_N_F_OPEN, + S7COMM_PI_N_F_SEEK, + S7COMM_PI_N_ASUP__, + S7COMM_PI_N_CHEKDM, + S7COMM_PI_N_CHKDNO, + S7COMM_PI_N_CONFIG, + S7COMM_PI_N_CRCEDN, + S7COMM_PI_N_DELECE, + S7COMM_PI_N_CREACE, + S7COMM_PI_N_CREATO, + S7COMM_PI_N_DELETO, + S7COMM_PI_N_CRTOCE, + S7COMM_PI_N_DELVAR, + S7COMM_PI_N_F_COPY, + S7COMM_PI_N_F_DMDA, + S7COMM_PI_N_F_PROR, + S7COMM_PI_N_F_PROT, + S7COMM_PI_N_F_RENA, + S7COMM_PI_N_FINDBL, + S7COMM_PI_N_IBN_SS, + S7COMM_PI_N_MMCSEM, + S7COMM_PI_N_NCKMOD, + S7COMM_PI_N_NEWPWD, + S7COMM_PI_N_SEL_BL, + S7COMM_PI_N_SETTST, + S7COMM_PI_N_TMAWCO, + S7COMM_PI_N_TMCRTC, + S7COMM_PI_N_TMCRTO, + S7COMM_PI_N_TMFDPL, + S7COMM_PI_N_TMFPBP, + S7COMM_PI_N_TMGETT, + S7COMM_PI_N_TMMVTL, + S7COMM_PI_N_TMPCIT, + S7COMM_PI_N_TMPOSM, + S7COMM_PI_N_TRESMO, + S7COMM_PI_N_TSEARC +} pi_service_e; + +/* Description for PI service names */ +static const string_string pi_service_names[] = { + { "UNKNOWN", "PI-Service is currently unknown" }, + { "_INSE", "PI-Service _INSE (Activates a PLC module)" }, + { "_INS2", "PI-Service _INS2 (Activates a PLC module)" }, + { "_DELE", "PI-Service _DELE (Removes module from the PLC's passive file system)" }, + { "P_PROGRAM", "PI-Service P_PROGRAM (PLC Start / Stop)" }, + { "_MODU", "PI-Service _MODU (PLC Copy Ram to Rom)" }, + { "_GARB", "PI-Service _GARB (Compress PLC memory)" }, + { "_N_LOGIN_", "PI-Service _N_LOGIN_ (Login)" }, + { "_N_LOGOUT", "PI-Service _N_LOGOUT (Logout)" }, + { "_N_CANCEL", "PI-Service _N_CANCEL (Cancels NC alarm)" }, + { "_N_DASAVE", "PI-Service _N_DASAVE (PI-Service for copying data from SRAM to FLASH)" }, + { "_N_DIGIOF", "PI-Service _N_DIGIOF (Turns off digitizing)" }, + { "_N_DIGION", "PI-Service _N_DIGION (Turns on digitizing)" }, + { "_N_DZERO_", "PI-Service _N_DZERO_ (Set all D nos. invalid for function \"unique D no.\")" }, + { "_N_ENDEXT", "PI-Service _N_ENDEXT ()" }, + { "_N_F_OPER", "PI-Service _N_F_OPER (Opens a file read-only)" }, + { "_N_OST_OF", "PI-Service _N_OST_OF (Overstore OFF)" }, + { "_N_OST_ON", "PI-Service _N_OST_ON (Overstore ON)" }, + { "_N_SCALE_", "PI-Service _N_SCALE_ (Unit of measurement setting (metric<->INCH))" }, + { "_N_SETUFR", "PI-Service _N_SETUFR (Activates user frame)" }, + { "_N_STRTLK", "PI-Service _N_STRTLK (The global start disable is set)" }, + { "_N_STRTUL", "PI-Service _N_STRTUL (The global start disable is reset)" }, + { "_N_TMRASS", "PI-Service _N_TMRASS (Resets the Active status)" }, + { "_N_F_DELE", "PI-Service _N_F_DELE (Deletes file)" }, + { "_N_EXTERN", "PI-Service _N_EXTERN (Selects external program for execution)" }, + { "_N_EXTMOD", "PI-Service _N_EXTMOD (Selects external program for execution)" }, + { "_N_F_DELR", "PI-Service _N_F_DELR (Delete file even without access rights)" }, + { "_N_F_XFER", "PI-Service _N_F_XFER (Selects file for uploading)" }, + { "_N_LOCKE_", "PI-Service _N_LOCKE_ (Locks the active file for editing)" }, + { "_N_SELECT", "PI-Service _N_SELECT (Selects program for execution)" }, + { "_N_SRTEXT", "PI-Service _N_SRTEXT (A file is being marked in /_N_EXT_DIR)" }, + { "_N_F_CLOS", "PI-Service _N_F_CLOS (Closes file)" }, + { "_N_F_OPEN", "PI-Service _N_F_OPEN (Opens file)" }, + { "_N_F_SEEK", "PI-Service _N_F_SEEK (Position the file search pointer)" }, + { "_N_ASUP__", "PI-Service _N_ASUP__ (Assigns interrupt)" }, + { "_N_CHEKDM", "PI-Service _N_CHEKDM (Start uniqueness check on D numbers)" }, + { "_N_CHKDNO", "PI-Service _N_CHKDNO (Check whether the tools have unique D numbers)" }, + { "_N_CONFIG", "PI-Service _N_CONFIG (Reconfigures machine data)" }, + { "_N_CRCEDN", "PI-Service _N_CRCEDN (Creates a cutting edge by specifying an edge no.)" }, + { "_N_DELECE", "PI-Service _N_DELECE (Deletes a cutting edge)" }, + { "_N_CREACE", "PI-Service _N_CREACE (Creates a cutting edge)" }, + { "_N_CREATO", "PI-Service _N_CREATO (Creates a tool)" }, + { "_N_DELETO", "PI-Service _N_DELETO (Deletes tool)" }, + { "_N_CRTOCE", "PI-Service _N_CRTOCE (Generate tool with specified edge number)" }, + { "_N_DELVAR", "PI-Service _N_DELVAR (Delete data block)" }, + { "_N_F_COPY", "PI-Service _N_F_COPY (Copies file within the NCK)" }, + { "_N_F_DMDA", "PI-Service _N_F_DMDA (Deletes MDA memory)" }, + { "_N_F_PROR", "PI-Service _N_F_PROR" }, + { "_N_F_PROT", "PI-Service _N_F_PROT (Assigns a protection level to a file)" }, + { "_N_F_RENA", "PI-Service _N_F_RENA (Renames file)" }, + { "_N_FINDBL", "PI-Service _N_FINDBL (Activates search)" }, + { "_N_IBN_SS", "PI-Service _N_IBN_SS (Sets the set-up switch)" }, + { "_N_MMCSEM", "PI-Service _N_MMCSEM (MMC-Semaphore)" }, + { "_N_NCKMOD", "PI-Service _N_NCKMOD (The mode in which the NCK will work is being set)" }, + { "_N_NEWPWD", "PI-Service _N_NEWPWD (New password)" }, + { "_N_SEL_BL", "PI-Service _N_SEL_BL (Selects a new block)" }, + { "_N_SETTST", "PI-Service _N_SETTST (Activate tools for replacement tool group)" }, + { "_N_TMAWCO", "PI-Service _N_TMAWCO (Set the active wear group in one magazine)" }, + { "_N_TMCRTC", "PI-Service _N_TMCRTC (Create tool with specified edge number)" }, + { "_N_TMCRTO", "PI-Service _N_TMCRTO (Creates tool in the tool management)" }, + { "_N_TMFDPL", "PI-Service _N_TMFDPL (Searches an empty place for loading)" }, + { "_N_TMFPBP", "PI-Service _N_TMFPBP (Searches for empty location)" }, + { "_N_TMGETT", "PI-Service _N_TMGETT (Determines T-number for specific toolID with Duplono)" }, + { "_N_TMMVTL", "PI-Service _N_TMMVTL (Loads or unloads a tool)" }, + { "_N_TMPCIT", "PI-Service _N_TMPCIT (Sets increment value of the piece counter)" }, + { "_N_TMPOSM", "PI-Service _N_TMPOSM (Positions a magazine or tool)" }, + { "_N_TRESMO", "PI-Service _N_TRESMO (Reset monitoring values)" }, + { "_N_TSEARC", "PI-Service _N_TSEARC (Complex search via search screenforms)" }, + { NULL, NULL } +}; + +/* Function 0x28 (PI Start) */ +static gint hf_s7comm_piservice_unknown1 = -1; /* Unknown bytes */ +static gint hf_s7comm_piservice_parameterblock = -1; +static gint hf_s7comm_piservice_parameterblock_len = -1; +static gint hf_s7comm_piservice_servicename = -1; + +static gint ett_s7comm_piservice_parameterblock = -1; + +static gint hf_s7comm_piservice_string_len = -1; +static gint hf_s7comm_pi_n_x_addressident = -1; +static gint hf_s7comm_pi_n_x_password = -1; +static gint hf_s7comm_pi_n_x_filename = -1; +static gint hf_s7comm_pi_n_x_editwindowname = -1; +static gint hf_s7comm_pi_n_x_seekpointer = -1; +static gint hf_s7comm_pi_n_x_windowsize = -1; +static gint hf_s7comm_pi_n_x_comparestring = -1; +static gint hf_s7comm_pi_n_x_skipcount = -1; +static gint hf_s7comm_pi_n_x_interruptnr = -1; +static gint hf_s7comm_pi_n_x_priority = -1; +static gint hf_s7comm_pi_n_x_liftfast = -1; +static gint hf_s7comm_pi_n_x_blsync = -1; +static gint hf_s7comm_pi_n_x_magnr = -1; +static gint hf_s7comm_pi_n_x_dnr = -1; +static gint hf_s7comm_pi_n_x_spindlenumber = -1; +static gint hf_s7comm_pi_n_x_wznr = -1; +static gint hf_s7comm_pi_n_x_class = -1; +static gint hf_s7comm_pi_n_x_tnr = -1; +static gint hf_s7comm_pi_n_x_toolnumber = -1; +static gint hf_s7comm_pi_n_x_cenumber = -1; +static gint hf_s7comm_pi_n_x_datablocknumber = -1; +static gint hf_s7comm_pi_n_x_firstcolumnnumber = -1; +static gint hf_s7comm_pi_n_x_lastcolumnnumber = -1; +static gint hf_s7comm_pi_n_x_firstrownumber = -1; +static gint hf_s7comm_pi_n_x_lastrownumber = -1; +static gint hf_s7comm_pi_n_x_direction = -1; +static gint hf_s7comm_pi_n_x_sourcefilename = -1; +static gint hf_s7comm_pi_n_x_destinationfilename = -1; +static gint hf_s7comm_pi_n_x_channelnumber = -1; +static gint hf_s7comm_pi_n_x_protection = -1; +static gint hf_s7comm_pi_n_x_oldfilename = -1; +static gint hf_s7comm_pi_n_x_newfilename = -1; +static gint hf_s7comm_pi_n_x_findmode = -1; +static gint hf_s7comm_pi_n_x_switch = -1; +static gint hf_s7comm_pi_n_x_functionnumber = -1; +static gint hf_s7comm_pi_n_x_semaphorevalue = -1; +static gint hf_s7comm_pi_n_x_onoff = -1; +static gint hf_s7comm_pi_n_x_mode = -1; +static gint hf_s7comm_pi_n_x_factor = -1; +static gint hf_s7comm_pi_n_x_passwordlevel = -1; +static gint hf_s7comm_pi_n_x_linenumber = -1; +static gint hf_s7comm_pi_n_x_weargroup = -1; +static gint hf_s7comm_pi_n_x_toolstatus = -1; +static gint hf_s7comm_pi_n_x_wearsearchstrat = -1; +static gint hf_s7comm_pi_n_x_toolid = -1; +static gint hf_s7comm_pi_n_x_duplonumber = -1; +static gint hf_s7comm_pi_n_x_edgenumber = -1; +static gint hf_s7comm_pi_n_x_placenr = -1; +static gint hf_s7comm_pi_n_x_placerefnr = -1; +static gint hf_s7comm_pi_n_x_magrefnr = -1; +static gint hf_s7comm_pi_n_x_magnrfrom = -1; +static gint hf_s7comm_pi_n_x_placenrfrom = -1; +static gint hf_s7comm_pi_n_x_magnrto = -1; +static gint hf_s7comm_pi_n_x_placenrto = -1; +static gint hf_s7comm_pi_n_x_halfplacesleft = -1; +static gint hf_s7comm_pi_n_x_halfplacesright = -1; +static gint hf_s7comm_pi_n_x_halfplacesup = -1; +static gint hf_s7comm_pi_n_x_halfplacesdown = -1; +static gint hf_s7comm_pi_n_x_placetype = -1; +static gint hf_s7comm_pi_n_x_searchdirection = -1; +static gint hf_s7comm_pi_n_x_toolname = -1; +static gint hf_s7comm_pi_n_x_placenrsource = -1; +static gint hf_s7comm_pi_n_x_magnrsource = -1; +static gint hf_s7comm_pi_n_x_placenrdestination = -1; +static gint hf_s7comm_pi_n_x_magnrdestination = -1; +static gint hf_s7comm_pi_n_x_incrementnumber = -1; +static gint hf_s7comm_pi_n_x_monitoringmode = -1; +static gint hf_s7comm_pi_n_x_kindofsearch = -1; + +static gint hf_s7comm_data_plccontrol_argument = -1; /* Argument, 2 Bytes as char */ +static gint hf_s7comm_data_plccontrol_block_cnt = -1; /* Number of blocks, 1 Byte as int */ +static gint hf_s7comm_data_pi_inse_unknown = -1; +static gint hf_s7comm_data_plccontrol_part2_len = -1; /* Length part 2 in bytes, 1 Byte as Int */ + +/* block control functions */ +static gint hf_s7comm_data_blockcontrol_unknown1 = -1; /* for all unknown bytes in blockcontrol */ +static gint hf_s7comm_data_blockcontrol_errorcode = -1; /* Error code 2 bytes as int, 0 is no error */ +static gint hf_s7comm_data_blockcontrol_uploadid = -1; +static gint hf_s7comm_data_blockcontrol_file_ident = -1; /* File identifier, as ASCII */ +static gint hf_s7comm_data_blockcontrol_block_type = -1; /* Block type, 2 Byte */ +static gint hf_s7comm_data_blockcontrol_block_num = -1; /* Block number, 5 Bytes, ASCII */ +static gint hf_s7comm_data_blockcontrol_dest_filesys = -1; /* Destination filesystem, 1 Byte, ASCII */ +static gint hf_s7comm_data_blockcontrol_part2_len = -1; /* Length part 2 in bytes, 1 Byte Int */ +static gint hf_s7comm_data_blockcontrol_part2_unknown = -1; /* Unknown char, ASCII */ +static gint hf_s7comm_data_blockcontrol_loadmem_len = -1; /* Length load memory in bytes, ASCII */ +static gint hf_s7comm_data_blockcontrol_mc7code_len = -1; /* Length of MC7 code in bytes, ASCII */ +static gint hf_s7comm_data_blockcontrol_filename_len = -1; +static gint hf_s7comm_data_blockcontrol_filename = -1; +static gint hf_s7comm_data_blockcontrol_upl_lenstring_len = -1; +static gint hf_s7comm_data_blockcontrol_upl_lenstring = -1; + +static gint hf_s7comm_data_blockcontrol_functionstatus = -1; +static gint hf_s7comm_data_blockcontrol_functionstatus_more = -1; +static gint hf_s7comm_data_blockcontrol_functionstatus_error = -1; +static gint ett_s7comm_data_blockcontrol_status = -1; +static int * const s7comm_data_blockcontrol_status_fields[] = { + &hf_s7comm_data_blockcontrol_functionstatus_more, + &hf_s7comm_data_blockcontrol_functionstatus_error, + NULL +}; + +static gint ett_s7comm_plcfilename = -1; +static gint hf_s7comm_data_ncprg_unackcount = -1; +static gint hf_s7comm_data_ncprg_filelength = -1; +static gint hf_s7comm_data_ncprg_filetime = -1; +static gint hf_s7comm_data_ncprg_filepath = -1; +static gint hf_s7comm_data_ncprg_filedata = -1; + +/* Data record routing to Profibus */ +static gint hf_s7comm_data_drr_data = -1; + +/* Variable status */ +static gint hf_s7comm_varstat_unknown = -1; /* Unknown byte(s), hex */ +static gint hf_s7comm_varstat_item_count = -1; /* Item count, 2 bytes, int */ +static gint hf_s7comm_varstat_req_memory_area = -1; /* Memory area, 1 byte, stringlist userdata_tis_varstat_area_names */ +static gint hf_s7comm_varstat_req_repetition_factor = -1; /* Repetition factor, 1 byte as int */ +static gint hf_s7comm_varstat_req_db_number = -1; /* DB number, 2 bytes as int */ +static gint hf_s7comm_varstat_req_startaddress = -1; /* Startaddress, 2 bytes as int */ +static gint hf_s7comm_varstat_req_bitpos = -1; + +/* cyclic services */ +static gint hf_s7comm_cycl_interval_timebase = -1; /* Interval timebase, 1 byte, int */ +static gint hf_s7comm_cycl_interval_time = -1; /* Interval time, 1 byte, int */ +static gint hf_s7comm_cycl_function = -1; +static gint hf_s7comm_cycl_jobid = -1; + +/* Read record */ +static gint hf_s7comm_rdrec_mlen = -1; /* Max. length in bytes of the data record data to be read */ +static gint hf_s7comm_rdrec_index = -1; /* Data record number */ +static gint hf_s7comm_rdrec_id = -1; /* Diagnostic address */ +static gint hf_s7comm_rdrec_statuslen = -1; /* Length of optional status data */ +static gint hf_s7comm_rdrec_statusdata = -1; /* Optional status data */ +static gint hf_s7comm_rdrec_recordlen = -1; /* Length of data record data read */ +static gint hf_s7comm_rdrec_data = -1; /* The read data record */ +static gint hf_s7comm_rdrec_reserved1 = -1; + +/* PBC, Programmable Block Functions */ +static gint hf_s7comm_pbc_unknown = -1; /* unknown, 1 byte */ +static gint hf_s7comm_pbc_bsend_r_id = -1; /* Request ID R_ID, 4 bytes as hex */ +static gint hf_s7comm_pbc_bsend_len = -1; +static gint hf_s7comm_pbc_usend_unknown1 = -1; +static gint hf_s7comm_pbc_usend_r_id = -1; +static gint hf_s7comm_pbc_usend_unknown2 = -1; +static gint hf_s7comm_pbc_arsend_ar_id = -1; +static gint hf_s7comm_pbc_arsend_ret = -1; +static gint hf_s7comm_pbc_arsend_unknown = -1; +static gint hf_s7comm_pbc_arsend_len = -1; + +/* Alarm messages */ +static gint hf_s7comm_cpu_alarm_message_item = -1; +static gint hf_s7comm_cpu_alarm_message_obj_item = -1; +static gint hf_s7comm_cpu_alarm_message_function = -1; +static gint hf_s7comm_cpu_alarm_message_nr_objects = -1; +static gint hf_s7comm_cpu_alarm_message_nr_add_values = -1; +static gint hf_s7comm_cpu_alarm_message_eventid = -1; +static gint hf_s7comm_cpu_alarm_message_timestamp_coming = -1; +static gint hf_s7comm_cpu_alarm_message_timestamp_going = -1; +static gint hf_s7comm_cpu_alarm_message_associated_value = -1; +static gint hf_s7comm_cpu_alarm_message_eventstate = -1; +static gint hf_s7comm_cpu_alarm_message_state = -1; +static gint hf_s7comm_cpu_alarm_message_ackstate_coming = -1; +static gint hf_s7comm_cpu_alarm_message_ackstate_going = -1; +static gint hf_s7comm_cpu_alarm_message_event_coming = -1; +static gint hf_s7comm_cpu_alarm_message_event_going = -1; +static gint hf_s7comm_cpu_alarm_message_event_lastchanged = -1; +static gint hf_s7comm_cpu_alarm_message_event_reserved = -1; +static gint hf_s7comm_cpu_alarm_message_scan_unknown1 = -1; +static gint hf_s7comm_cpu_alarm_message_scan_unknown2 = -1; + +static gint hf_s7comm_cpu_alarm_message_signal_sig1 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig2 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig3 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig4 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig5 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig6 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig7 = -1; +static gint hf_s7comm_cpu_alarm_message_signal_sig8 = -1; +static gint ett_s7comm_cpu_alarm_message_signal = -1; +static int * const s7comm_cpu_alarm_message_signal_fields[] = { + &hf_s7comm_cpu_alarm_message_signal_sig1, + &hf_s7comm_cpu_alarm_message_signal_sig2, + &hf_s7comm_cpu_alarm_message_signal_sig3, + &hf_s7comm_cpu_alarm_message_signal_sig4, + &hf_s7comm_cpu_alarm_message_signal_sig5, + &hf_s7comm_cpu_alarm_message_signal_sig6, + &hf_s7comm_cpu_alarm_message_signal_sig7, + &hf_s7comm_cpu_alarm_message_signal_sig8, + NULL +}; + +static gint hf_s7comm_cpu_alarm_query_unknown1 = -1; +static gint hf_s7comm_cpu_alarm_query_querytype = -1; +static gint hf_s7comm_cpu_alarm_query_unknown2 = -1; +static gint hf_s7comm_cpu_alarm_query_alarmtype = -1; +static gint hf_s7comm_cpu_alarm_query_completelen = -1; +static gint hf_s7comm_cpu_alarm_query_datasetlen = -1; +static gint hf_s7comm_cpu_alarm_query_resunknown1 = -1; + +/* CPU diagnostic messages */ +static gint hf_s7comm_cpu_diag_msg_item = -1; +static gint hf_s7comm_cpu_diag_msg_eventid = -1; +static gint hf_s7comm_cpu_diag_msg_eventid_class = -1; +static gint hf_s7comm_cpu_diag_msg_eventid_ident_entleave = -1; +static gint hf_s7comm_cpu_diag_msg_eventid_ident_diagbuf = -1; +static gint hf_s7comm_cpu_diag_msg_eventid_ident_interr = -1; +static gint hf_s7comm_cpu_diag_msg_eventid_ident_exterr = -1; +static gint hf_s7comm_cpu_diag_msg_eventid_nr = -1; +static gint hf_s7comm_cpu_diag_msg_prioclass = -1; +static gint hf_s7comm_cpu_diag_msg_obnumber = -1; +static gint hf_s7comm_cpu_diag_msg_datid = -1; +static gint hf_s7comm_cpu_diag_msg_info1 = -1; +static gint hf_s7comm_cpu_diag_msg_info2 = -1; + +static gint ett_s7comm_cpu_diag_msg_eventid = -1; +static int * const s7comm_cpu_diag_msg_eventid_fields[] = { + &hf_s7comm_cpu_diag_msg_eventid_class, + &hf_s7comm_cpu_diag_msg_eventid_ident_entleave, + &hf_s7comm_cpu_diag_msg_eventid_ident_diagbuf, + &hf_s7comm_cpu_diag_msg_eventid_ident_interr, + &hf_s7comm_cpu_diag_msg_eventid_ident_exterr, + &hf_s7comm_cpu_diag_msg_eventid_nr, + NULL +}; + +static const true_false_string tfs_s7comm_cpu_diag_msg_eventid_ident_entleave = { + "Event entering", + "Event leaving" +}; + +static const value_string cpu_diag_msg_eventid_class_names[] = { + { 0x01, "Standard OB events" }, + { 0x02, "Synchronous errors" }, + { 0x03, "Asynchronous errors" }, + { 0x04, "Mode transitions" }, + { 0x05, "Run-time events" }, + { 0x06, "Communication events" }, + { 0x07, "Events for fail-safe and fault-tolerant systems" }, + { 0x08, "Standardized diagnostic data on modules" }, + { 0x09, "Predefined user events" }, + { 0x0a, "Freely definable events" }, + { 0x0b, "Freely definable events" }, + { 0x0c, "Reserved" }, + { 0x0d, "Reserved" }, + { 0x0e, "Reserved" }, + { 0x0f, "Events for modules other than CPUs" }, + { 0, NULL } +}; + +static const value_string cpu_diag_eventid_fix_names[] = { + { 0x113A, "Start request for cyclic interrupt OB with special handling (S7-300 only)" }, + { 0x1155, "Status alarm for PROFIBUS DP" }, + { 0x1156, "Update interrupt for PROFIBUS DP" }, + { 0x1157, "Manufacturer interrupt for PROFIBUS DP" }, + { 0x1158, "Status interrupt for PROFINET IO" }, + { 0x1159, "Update interrupt for PROFINET IO" }, + { 0x115A, "Manufacturer interrupt for PROFINET IO" }, + { 0x115B, "IO: Profile-specific interrupt" }, + { 0x116A, "Technology synchronization interrupt" }, + { 0x1381, "Request for manual warm restart" }, + { 0x1382, "Request for automatic warm restart" }, + { 0x1383, "Request for manual hot restart" }, + { 0x1384, "Request for automatic hot restart" }, + { 0x1385, "Request for manual cold restart" }, + { 0x1386, "Request for automatic cold restart" }, + { 0x1387, "Master CPU: request for manual cold restart" }, + { 0x1388, "Master CPU: request for automatic cold restart" }, + { 0x138A, "Master CPU: request for manual warm restart" }, + { 0x138B, "Master CPU: request for automatic warm restart" }, + { 0x138C, "Standby CPU: request for manual hot restart" }, + { 0x138D, "Standby CPU: request for automatic hot restart" }, + { 0x2521, "BCD conversion error" }, + { 0x2522, "Area length error when reading" }, + { 0x2523, "Area length error when writing" }, + { 0x2524, "Area error when reading" }, + { 0x2525, "Area error when writing" }, + { 0x2526, "Timer number error" }, + { 0x2527, "Counter number error" }, + { 0x2528, "Alignment error when reading" }, + { 0x2529, "Alignment error when writing" }, + { 0x2530, "Write error when accessing the DB" }, + { 0x2531, "Write error when accessing the DI" }, + { 0x2532, "Block number error when opening a DB" }, + { 0x2533, "Block number error when opening a DI" }, + { 0x2534, "Block number error when calling an FC" }, + { 0x2535, "Block number error when calling an FB" }, + { 0x253A, "DB not loaded" }, + { 0x253C, "FC not loaded" }, + { 0x253D, "SFC not loaded" }, + { 0x253E, "FB not loaded" }, + { 0x253F, "SFB not loaded" }, + { 0x2942, "I/O access error, reading" }, + { 0x2943, "I/O access error, writing" }, + { 0x3267, "End of module reconfiguration" }, + { 0x3367, "Start of module reconfiguration" }, + { 0x34A4, "PROFInet Interface DB can be addressed again" }, + { 0x3501, "Cycle time exceeded" }, + { 0x3502, "User interface (OB or FRB) request error" }, + { 0x3503, "Delay too long processing a priority class" }, + { 0x3505, "Time-of-day interrupt(s) skipped due to new clock setting" }, + { 0x3506, "Time-of-day interrupt(s) skipped when changing to RUN after HOLD" }, + { 0x3507, "Multiple OB request errors caused internal buffer overflow" }, + { 0x3508, "Synchronous cycle interrupt-timing error" }, + { 0x3509, "Interrupt loss due to excess interrupt load" }, + { 0x350A, "Resume RUN mode after CiR" }, + { 0x350B, "Technology synchronization interrupt - timing error" }, + { 0x3571, "Nesting depth too high in nesting levels" }, + { 0x3572, "Nesting depth for Master Control Relays too high" }, + { 0x3573, "Nesting depth too high after synchronous errors" }, + { 0x3574, "Nesting depth for block calls (U stack) too high" }, + { 0x3575, "Nesting depth for block calls (B stack) too high" }, + { 0x3576, "Local data allocation error" }, + { 0x3578, "Unknown instruction" }, + { 0x357A, "Jump instruction to target outside of the block" }, + { 0x3582, "Memory error detected and corrected by operating system" }, + { 0x3583, "Accumulation of detected and corrected memo errors" }, + { 0x3585, "Error in the PC operating system (only for LC RTX)" }, + { 0x3587, "Multi-bit memory error detected and corrected" }, + { 0x35A1, "User interface (OB or FRB) not found" }, + { 0x35A2, "OB not loaded (started by SFC or operating system due to configuration)" }, + { 0x35A3, "Error when operating system accesses a block" }, + { 0x35A4, "PROFInet Interface DB cannot be addressed" }, + { 0x35D2, "Diagnostic entries cannot be sent at present" }, + { 0x35D3, "Synchronization frames cannot be sent" }, + { 0x35D4, "Illegal time jump resulting from synchronization" }, + { 0x35D5, "Error adopting the synchronization time" }, + { 0x35E1, "Incorrect frame ID in GD" }, + { 0x35E2, "GD packet status cannot be entered in DB" }, + { 0x35E3, "Frame length error in GD" }, + { 0x35E4, "Illegal GD packet number received" }, + { 0x35E5, "Error accessing DB in communication SFBs for configured S7 connections" }, + { 0x35E6, "GD total status cannot be entered in DB" }, + { 0x3821, "BATTF: failure on at least one backup battery of the central rack, problem eliminated" }, + { 0x3822, "BAF: failure of backup voltage on central rack, problem eliminated" }, + { 0x3823, "24 volt supply failure on central rack, problem eliminated" }, + { 0x3825, "BATTF: failure on at least one backup battery of the redundant central rack, problem eliminated" }, + { 0x3826, "BAF: failure of backup voltage on redundant central rack, problem eliminated" }, + { 0x3827, "24 volt supply failure on redundant central rack, problem eliminated" }, + { 0x3831, "BATTF: failure of at least one backup battery of the expansion rack, problem eliminated" }, + { 0x3832, "BAF: failure of backup voltage on expansion rack, problem eliminated" }, + { 0x3833, "24 volt supply failure on at least one expansion rack, problem eliminated" }, + { 0x3842, "Module OK" }, + { 0x3854, "PROFINET IO interface submodule/submodule and matches the configured interface submodule/submodule" }, + { 0x3855, "PROFINET IO interface submodule/submodule inserted, but does not match the configured interface submodule/submodule" }, + { 0x3856, "PROFINET IO interface submodule/submodule inserted, but error in module parameter assignment" }, + { 0x3858, "PROFINET IO interface submodule access error corrected" }, + { 0x3861, "Module/interface module inserted, module type OK" }, + { 0x3863, "Module/interface module plugged in, but wrong module type" }, + { 0x3864, "Module/interface module plugged in, but causing problem (type ID unreadable)" }, + { 0x3865, "Module plugged in, but error in module parameter assignment" }, + { 0x3866, "Module can be addressed again, load voltage error removed" }, + { 0x3881, "Interface error leaving state" }, + { 0x3884, "Interface module plugged in" }, + { 0x38B3, "I/O access error when updating the process image input table" }, + { 0x38B4, "I/O access error when transferring the process image to the output modules" }, + { 0x38C1, "Expansion rack operational again (1 to 21), leaving state" }, + { 0x38C2, "Expansion rack operational again but mismatch between setpoint and actual configuration" }, + { 0x38C4, "Distributed I/Os: station failure, leaving state" }, + { 0x38C5, "Distributed I/Os: station fault, leaving state" }, + { 0x38C6, "Expansion rack operational again, but error(s) in module parameter assignment" }, + { 0x38C7, "DP: station operational again, but error(s) in module parameter assignment" }, + { 0x38C8, "DP: station operational again, but mismatch between setpoint and actual configuration" }, + { 0x38CB, "PROFINET IO station operational again" }, + { 0x38CC, "PROFINET IO station error corrected" }, + { 0x3921, "BATTF: failure on at least one backup battery of the central rack" }, + { 0x3922, "BAF: failure of backup voltage on central rack" }, + { 0x3923, "24 volt supply failure on central rack" }, + { 0x3925, "BATTF: failure on at least one backup battery of the redundant central rack" }, + { 0x3926, "BAF: failure of backup voltage on redundant central rack" }, + { 0x3927, "24 volt supply failure on redundant central rack" }, + { 0x3931, "BATTF: failure of at least one backup battery of the expansion rack" }, + { 0x3932, "BAF: failure of backup voltage on expansion rack" }, + { 0x3933, "24 volt supply failure on at least one expansion rack" }, + { 0x3942, "Module error" }, + { 0x3951, "PROFINET IO submodule removed" }, + { 0x3954, "PROFINET IO interface submodule/submodule removed" }, + { 0x3961, "Module/interface module removed, cannot be addressed" }, + { 0x3966, "Module cannot be addressed, load voltage error" }, + { 0x3968, "Module reconfiguration has ended with error" }, + { 0x3981, "Interface error entering state" }, + { 0x3984, "Interface module removed" }, + { 0x3986, "Performance of an H-Sync link negatively affected" }, + { 0x39B1, "I/O access error when updating the process image input table" }, + { 0x39B2, "I/O access error when transferring the process image to the output modules" }, + { 0x39B3, "I/O access error when updating the process image input table" }, + { 0x39B4, "I/O access error when transferring the process image to the output modules" }, + { 0x39C1, "Expansion rack failure (1 to 21), entering state" }, + { 0x39C3, "Distributed I/Os: master system failure entering state" }, + { 0x39C4, "Distributed I/Os: station failure, entering state" }, + { 0x39C5, "Distributed I/Os: station fault, entering state" }, + { 0x39CA, "PROFINET IO system failure" }, + { 0x39CB, "PROFINET IO station failure" }, + { 0x39CC, "PROFINET IO station error" }, + { 0x39CD, "PROFINET IO station operational again, but expected configuration does not match actual configuration" }, + { 0x39CE, "PROFINET IO station operational again, but error(s) in module parameter assignment" }, + { 0x42F3, "Checksum error detected and corrected by the operating system" }, + { 0x42F4, "Standby CPU: connection/update via SFC90 is locked in the master CPU" }, + { 0x4300, "Backed-up power on" }, + { 0x4301, "Mode transition from STOP to STARTUP" }, + { 0x4302, "Mode transition from STARTUP to RUN" }, + { 0x4303, "STOP caused by stop switch being activated" }, + { 0x4304, "STOP caused by PG STOP operation or by SFB 20 STOP" }, + { 0x4305, "HOLD: breakpoint reached" }, + { 0x4306, "HOLD: breakpoint exited" }, + { 0x4307, "Memory reset started by PG operation" }, + { 0x4308, "Memory reset started by switch setting" }, + { 0x4309, "Memory reset started automatically (power on not backed up)" }, + { 0x430A, "HOLD exited, transition to STOP" }, + { 0x430D, "STOP caused by other CPU in multicomputing" }, + { 0x430E, "Memory reset executed" }, + { 0x430F, "STOP on the module due to STOP on a CPU" }, + { 0x4318, "Start of CiR" }, + { 0x4319, "CiR completed" }, + { 0x4357, "Module watchdog started" }, + { 0x4358, "All modules are ready for operation" }, + { 0x43B0, "Firmware update was successful" }, + { 0x43B4, "Error in firmware fuse" }, + { 0x43B6, "Firmware updates canceled by redundant modules" }, + { 0x43D3, "STOP on standby CPU" }, + { 0x43DC, "Abort during link-up with switchover" }, + { 0x43DE, "Updating aborted due to monitoring time being exceeded during the n-th attempt, new update attempt initiated" }, + { 0x43DF, "Updating aborted for final time due to monitoring time being exceeded after completing the maximum amount of attempts. User intervention required" }, + { 0x43E0, "Change from solo mode after link-up" }, + { 0x43E1, "Change from link-up after updating" }, + { 0x43E2, "Change from updating to redundant mode" }, + { 0x43E3, "Master CPU: change from redundant mode to solo mode" }, + { 0x43E4, "Standby CPU: change from redundant mode after error-search mode" }, + { 0x43E5, "Standby CPU: change from error-search mode after link-up or STOP" }, + { 0x43E6, "Link-up aborted on the standby CPU" }, + { 0x43E7, "Updating aborted on the standby CPU" }, + { 0x43E8, "Standby CPU: change from link-up after startup" }, + { 0x43E9, "Standby CPU: change from startup after updating" }, + { 0x43F1, "Reserve-master switchover" }, + { 0x43F2, "Coupling of incompatible H-CPUs blocked by system program" }, + { 0x4510, "STOP violation of the CPU's data range" }, + { 0x4520, "DEFECTIVE: STOP not possible" }, + { 0x4521, "DEFECTIVE: failure of instruction processing processor" }, + { 0x4522, "DEFECTIVE: failure of clock chip" }, + { 0x4523, "DEFECTIVE: failure of clock pulse generator" }, + { 0x4524, "DEFECTIVE: failure of timer update function" }, + { 0x4525, "DEFECTIVE: failure of multicomputing synchronization" }, + { 0x4527, "DEFECTIVE: failure of I/O access monitoring" }, + { 0x4528, "DEFECTIVE: failure of scan time monitoring" }, + { 0x4530, "DEFECTIVE: memory test error in internal memory" }, + { 0x4532, "DEFECTIVE: failure of core resources" }, + { 0x4536, "DEFECTIVE: switch defective" }, + { 0x4540, "STOP: Memory expansion of the internal work memory has gaps. First memory expansion too small or missing" }, + { 0x4541, "STOP caused by priority class system" }, + { 0x4542, "STOP caused by object management system" }, + { 0x4543, "STOP caused by test functions" }, + { 0x4544, "STOP caused by diagnostic system" }, + { 0x4545, "STOP caused by communication system" }, + { 0x4546, "STOP caused by CPU memory management" }, + { 0x4547, "STOP caused by process image management" }, + { 0x4548, "STOP caused by I/O management" }, + { 0x454A, "STOP caused by configuration: an OB deselected with STEP 7 was being loaded into the CPU during STARTUP" }, + { 0x4550, "DEFECTIVE: internal system error" }, + { 0x4555, "No restart possible, monitoring time elapsed" }, + { 0x4556, "STOP: memory reset request from communication system / due to data inconsistency" }, + { 0x4562, "STOP caused by programming error (OB not loaded or not possible)" }, + { 0x4563, "STOP caused by I/O access error (OB not loaded or not possible)" }, + { 0x4567, "STOP caused by H event" }, + { 0x4568, "STOP caused by time error (OB not loaded or not possible)" }, + { 0x456A, "STOP caused by diagnostic interrupt (OB not loaded or not possible)" }, + { 0x456B, "STOP caused by removing/inserting module (OB not loaded or not possible)" }, + { 0x456C, "STOP caused by CPU hardware error (OB not loaded or not possible, or no FRB)" }, + { 0x456D, "STOP caused by program sequence error (OB not loaded or not possible)" }, + { 0x456E, "STOP caused by communication error (OB not loaded or not possible)" }, + { 0x456F, "STOP caused by rack failure OB (OB not loaded or not possible)" }, + { 0x4570, "STOP caused by process interrupt (OB not loaded or not possible)" }, + { 0x4571, "STOP caused by nesting stack error" }, + { 0x4572, "STOP caused by master control relay stack error" }, + { 0x4573, "STOP caused by exceeding the nesting depth for synchronous errors" }, + { 0x4574, "STOP caused by exceeding interrupt stack nesting depth in the priority class stack" }, + { 0x4575, "STOP caused by exceeding block stack nesting depth in the priority class stack" }, + { 0x4576, "STOP caused by error when allocating the local data" }, + { 0x4578, "STOP caused by unknown opcode" }, + { 0x457A, "STOP caused by code length error" }, + { 0x457B, "STOP caused by DB not being loaded on on-board I/Os" }, + { 0x457D, "Reset/clear request because the version of the internal interface to the integrated technology was changed" }, + { 0x457F, "STOP caused by STOP command" }, + { 0x4580, "STOP: back-up buffer contents inconsistent (no transition to RUN)" }, + { 0x4590, "STOP caused by overloading the internal functions" }, + { 0x45D5, "LINK-UP rejected due to mismatched CPU memory configuration of the sub-PLC" }, + { 0x45D6, "LINK-UP rejected due to mismatched system program of the sub-PLC" }, + { 0x45D8, "DEFECTIVE: hardware fault detected due to other error" }, + { 0x45D9, "STOP due to SYNC module error" }, + { 0x45DA, "STOP due to synchronization error between H CPUs" }, + { 0x45DD, "LINK-UP rejected due to running test or other online functions" }, + { 0x4926, "DEFECTIVE: failure of the watchdog for I/O access" }, + { 0x4931, "STOP or DEFECTIVE: memory test error in memory submodule" }, + { 0x4933, "Checksum error" }, + { 0x4934, "DEFECTIVE: memory not available" }, + { 0x4935, "DEFECTIVE: cancelled by watchdog/processor exceptions" }, + { 0x4949, "STOP caused by continuous hardware interrupt" }, + { 0x494D, "STOP caused by I/O error" }, + { 0x494E, "STOP caused by power failure" }, + { 0x494F, "STOP caused by configuration error" }, + { 0x4959, "One or more modules not ready for operation" }, + { 0x497C, "STOP caused by integrated technology" }, + { 0x49A0, "STOP caused by parameter assignment error or non-permissible variation of setpoint and actual extension: Start-up blocked" }, + { 0x49A1, "STOP caused by parameter assignment error: memory reset request" }, + { 0x49A2, "STOP caused by error in parameter modification: startup disabled" }, + { 0x49A3, "STOP caused by error in parameter modification: memory reset request" }, + { 0x49A4, "STOP: inconsistency in configuration data" }, + { 0x49A5, "STOP: distributed I/Os: inconsistency in the loaded configuration information" }, + { 0x49A6, "STOP: distributed I/Os: invalid configuration information" }, + { 0x49A7, "STOP: distributed I/Os: no configuration information" }, + { 0x49A8, "STOP: error indicated by the interface module for the distributed I/Os" }, + { 0x49B1, "Firmware update data incorrect" }, + { 0x49B2, "Firmware update: hardware version does not match firmware" }, + { 0x49B3, "Firmware update: module type does not match firmware" }, + { 0x49D0, "LINK-UP aborted due to violation of coordination rules" }, + { 0x49D1, "LINK-UP/UPDATE sequence aborted" }, + { 0x49D2, "Standby CPU changed to STOP due to STOP on the master CPU during link-up" }, + { 0x49D4, "STOP on a master, since partner CPU is also a master (link-up error)" }, + { 0x49D7, "LINK-UP rejected due to change in user program or in configuration" }, + { 0x510F, "A problem as occurred with WinLC. This problem has caused the CPU to go into STOP mode or has caused a fault in the CPU" }, + { 0x530D, "New startup information in the STOP mode" }, + { 0x5311, "Startup despite Not Ready message from module(s)" }, + { 0x5371, "Distributed I/Os: end of the synchronization with a DP master" }, + { 0x5380, "Diagnostic buffer entries of interrupt and asynchronous errors disabled" }, + { 0x5395, "Distributed I/Os: reset of a DP master" }, + { 0x53A2, "Download of technology firmware successful" }, + { 0x53A4, "Download of technology DB not successful" }, + { 0x53FF, "Reset to factory setting" }, + { 0x5445, "Start of System reconfiguration in RUN mode" }, + { 0x5481, "All licenses for runtime software are complete again" }, + { 0x5498, "No more inconsistency with DP master systems due to CiR" }, + { 0x5545, "Start of System reconfiguration in RUN mode" }, + { 0x5581, "One or several licenses for runtime software are missing" }, + { 0x558A, "Difference between the MLFB of the configured and inserted CPU" }, + { 0x558B, "Difference in the firmware version of the configured and inserted CPU" }, + { 0x5598, "Start of possible inconsistency with DP master systems due to CiR" }, + { 0x55A5, "Version conflict: internal interface with integrated technology" }, + { 0x55A6, "The maximum number of technology objects has been exceeded" }, + { 0x55A7, "A technology DB of this type is already present" }, + { 0x5879, "Diagnostic message from DP interface: EXTF LED off" }, + { 0x5960, "Parameter assignment error when switching" }, + { 0x5961, "Parameter assignment error" }, + { 0x5962, "Parameter assignment error preventing startup" }, + { 0x5963, "Parameter assignment error with memory reset request" }, + { 0x5966, "Parameter assignment error when switching" }, + { 0x5969, "Parameter assignment error with startup blocked" }, + { 0x596A, "PROFINET IO: IP address of an IO device already present" }, + { 0x596B, "IP address of an Ethernet interface already exists" }, + { 0x596C, "Name of an Ethernet interface already exists" }, + { 0x596D, "The existing network configuration does not mach the system requirements or configuration" }, + { 0x5979, "Diagnostic message from DP interface: EXTF LED on" }, + { 0x597C, "DP Global Control command failed or moved" }, + { 0x59A0, "The interrupt can not be associated in the CPU" }, + { 0x59A1, "Configuration error in the integrated technology" }, + { 0x59A3, "Error when downloading the integrated technology" }, + { 0x6253, "Firmware update: End of firmware download over the network" }, + { 0x6316, "Interface error when starting programmable controller" }, + { 0x6353, "Firmware update: Start of firmware download over the network" }, + { 0x6390, "Formatting of Micro Memory Card complete" }, + { 0x6500, "Connection ID exists twice on module" }, + { 0x6501, "Connection resources inadequate" }, + { 0x6502, "Error in the connection description" }, + { 0x6510, "CFB structure error detected in instance DB when evaluating EPROM" }, + { 0x6514, "GD packet number exists twice on the module" }, + { 0x6515, "Inconsistent length specifications in GD configuration information" }, + { 0x6521, "No memory submodule and no internal memory available" }, + { 0x6522, "Illegal memory submodule: replace submodule and reset memory" }, + { 0x6523, "Memory reset request due to error accessing submodule" }, + { 0x6524, "Memory reset request due to error in block header" }, + { 0x6526, "Memory reset request due to memory replacement" }, + { 0x6527, "Memory replaced, therefore restart not possible" }, + { 0x6528, "Object handling function in the STOP/HOLD mode, no restart possible" }, + { 0x6529, "No startup possible during the \"load user program\" function" }, + { 0x652A, "No startup because block exists twice in user memory" }, + { 0x652B, "No startup because block is too long for submodule - replace submodule" }, + { 0x652C, "No startup due to illegal OB on submodule" }, + { 0x6532, "No startup because illegal configuration information on submodule" }, + { 0x6533, "Memory reset request because of invalid submodule content" }, + { 0x6534, "No startup: block exists more than once on submodule" }, + { 0x6535, "No startup: not enough memory to transfer block from submodule" }, + { 0x6536, "No startup: submodule contains an illegal block number" }, + { 0x6537, "No startup: submodule contains a block with an illegal length" }, + { 0x6538, "Local data or write-protection ID (for DB) of a block illegal for CPU" }, + { 0x6539, "Illegal command in block (detected by compiler)" }, + { 0x653A, "Memory reset request because local OB data on submodule too short" }, + { 0x6543, "No startup: illegal block type" }, + { 0x6544, "No startup: attribute \"relevant for processing\" illegal" }, + { 0x6545, "Source language illegal" }, + { 0x6546, "Maximum amount of configuration information reached" }, + { 0x6547, "Parameter assignment error assigning parameters to modules (not on P bus, cancel download)" }, + { 0x6548, "Plausibility error during block check" }, + { 0x6549, "Structure error in block" }, + { 0x6550, "A block has an error in the CRC" }, + { 0x6551, "A block has no CRC" }, + { 0x6560, "SCAN overflow" }, + { 0x6805, "Resource problem on configured connections, eliminated" }, + { 0x6881, "Interface error leaving state" }, + { 0x6905, "Resource problem on configured connections" }, + { 0x6981, "Interface error entering state" }, + { 0x72A2, "Failure of a DP master or a DP master system" }, + { 0x72A3, "Redundancy restored on the DP slave" }, + { 0x72DB, "Safety program: safety mode disabled" }, + { 0x72E0, "Loss of redundancy in communication, problem eliminated" }, + { 0x7301, "Loss of redundancy (1 of 2) due to failure of a CPU" }, + { 0x7302, "Loss of redundancy (1 of 2) due to STOP on the standby triggered by user" }, + { 0x7303, "H system (1 of 2) changed to redundant mode" }, + { 0x7323, "Discrepancy found in operating system data" }, + { 0x7331, "Standby-master switchover due to master failure" }, + { 0x7333, "Standby-master switchover due to system modification during runtime" }, + { 0x7334, "Standby-master switchover due to communication error at the synchronization module" }, + { 0x7340, "Synchronization error in user program due to elapsed wait time" }, + { 0x7341, "Synchronization error in user program due to waiting at different synchronization points" }, + { 0x7342, "Synchronization error in operating system due to waiting at different synchronization points" }, + { 0x7343, "Synchronization error in operating system due to elapsed wait time" }, + { 0x7344, "Synchronization error in operating system due to incorrect data" }, + { 0x734A, "The \"Re-enable\" job triggered by SFC 90 \"H_CTRL\" was executed" }, + { 0x73A3, "Loss of redundancy on the DP slave" }, + { 0x73C1, "Update process canceled" }, + { 0x73C2, "Updating aborted due to monitoring time being exceeded during the n-th attempt (1 = n = max. possible number of update attempts after abort due to excessive monitoring time)" }, + { 0x73D8, "Safety mode disabled" }, + { 0x73DB, "Safety program: safety mode enabled" }, + { 0x73E0, "Loss of redundancy in communication" }, + { 0x74DD, "Safety program: Shutdown of a fail-save runtime group disabled" }, + { 0x74DE, "Safety program: Shutdown of the F program disabled" }, + { 0x74DF, "Start of F program initialization" }, + { 0x7520, "Error in RAM comparison" }, + { 0x7521, "Error in comparison of process image output value" }, + { 0x7522, "Error in comparison of memory bits, timers, or counters" }, + { 0x75D1, "Safety program: Internal CPU error" }, + { 0x75D2, "Safety program error: Cycle time time-out" }, + { 0x75D6, "Data corrupted in safety program prior to the output to F I/O" }, + { 0x75D7, "Data corrupted in safety program prior to the output to partner F-CPU" }, + { 0x75D9, "Invalid REAL number in a DB" }, + { 0x75DA, "Safety program: Error in safety data format" }, + { 0x75DC, "Runtime group, internal protocol error" }, + { 0x75DD, "Safety program: Shutdown of a fail-save runtime group enabled" }, + { 0x75DE, "Safety program: Shutdown of the F program enabled" }, + { 0x75DF, "End of F program initialization" }, + { 0x75E1, "Safety program: Error in FB \"F_PLK\" or \"F_PLK_O\" or \"F_CYC_CO\" or \"F_TEST\" or \"F_TESTC\"" }, + { 0x75E2, "Safety program: Area length error" }, + { 0x7852, "SYNC module inserted" }, + { 0x7855, "SYNC module eliminated" }, + { 0x78D3, "Communication error between PROFIsafe and F I/O" }, + { 0x78D4, "Error in safety relevant communication between F CPUs" }, + { 0x78D5, "Error in safety relevant communication between F CPUs" }, + { 0x78E3, "F-I/O device input channel depassivated" }, + { 0x78E4, "F-I/O device output channel depassivated" }, + { 0x78E5, "F-I/O device depassivated" }, + { 0x7934, "Standby-master switchover due to connection problem at the SYNC module" }, + { 0x7950, "Synchronization module missing" }, + { 0x7951, "Change at the SYNC module without Power On" }, + { 0x7952, "SYNC module removed" }, + { 0x7953, "Change at the SYNC-module without reset" }, + { 0x7954, "SYNC module: rack number assigned twice" }, + { 0x7955, "SYNC module error" }, + { 0x7956, "Illegal rack number set on SYNC module" }, + { 0x7960, "Redundant I/O: Time-out of discrepancy time at digital input, error is not yet localized" }, + { 0x7961, "Redundant I/O, digital input error: Signal change after expiration of the discrepancy time" }, + { 0x7962, "Redundant I/O: Digital input error" }, + { 0x796F, "Redundant I/O: The I/O was globally disabled" }, + { 0x7970, "Redundant I/O: Digital output error" }, + { 0x7980, "Redundant I/O: Time-out of discrepancy time at analog input" }, + { 0x7981, "Redundant I/O: Analog input error" }, + { 0x7990, "Redundant I/O: Analog output error" }, + { 0x79D3, "Communication error between PROFIsafe and F I/O" }, + { 0x79D4, "Error in safety relevant communication between F CPUs" }, + { 0x79D5, "Error in safety relevant communication between F CPUs" }, + { 0x79E3, "F-I/O device input channel passivated" }, + { 0x79E4, "F-I/O device output channel passivated" }, + { 0x79E5, "F-I/O device passivated" }, + { 0x79E6, "Inconsistent safety program" }, + { 0x79E7, "Simulation block (F system block) loaded" }, + { 0, NULL } +}; +static value_string_ext cpu_diag_eventid_fix_names_ext = VALUE_STRING_EXT_INIT(cpu_diag_eventid_fix_names); + +static const value_string cpu_diag_eventid_0x8_0x9_names[] = { + { 0x8000, "Module fault/OK" }, + { 0x8001, "Internal error" }, + { 0x8002, "External error" }, + { 0x8003, "Channel error" }, + { 0x8004, "No external auxiliary voltage" }, + { 0x8005, "No front connector" }, + { 0x8006, "No parameter assignment" }, + { 0x8007, "Incorrect parameters in module" }, + { 0x8030, "User submodule incorrect/not found" }, + { 0x8031, "Communication problem" }, + { 0x8032, "Operating mode: RUN/STOP (STOP: entering state, RUN: leaving state)" }, + { 0x8033, "Time monitoring responded (watchdog)" }, + { 0x8034, "Internal module power failure" }, + { 0x8035, "BATTF: battery exhausted" }, + { 0x8036, "Total backup failed" }, + { 0x8040, "Expansion rack failed" }, + { 0x8041, "Processor failure" }, + { 0x8042, "EPROM error" }, + { 0x8043, "RAM error" }, + { 0x8044, "ADC/DAC error" }, + { 0x8045, "Fuse blown" }, + { 0x8046, "Hardware interrupt lost Any" }, + { 0x8050, "Configuration/parameter assignment error" }, + { 0x8051, "Common mode error" }, + { 0x8052, "Short circuit to phase" }, + { 0x8053, "Short circuit to ground" }, + { 0x8054, "Wire break" }, + { 0x8055, "Reference channel error" }, + { 0x8056, "Below measuring range" }, + { 0x8057, "Above measuring range Analog input" }, + { 0x8060, "Configuration/parameter assignment error" }, + { 0x8061, "Common mode error" }, + { 0x8062, "Short circuit to phase" }, + { 0x8063, "Short circuit to ground" }, + { 0x8064, "Wire break" }, + { 0x8066, "No load voltage" }, + { 0x8070, "Configuration/parameter assignment error" }, + { 0x8071, "Chassis ground fault" }, + { 0x8072, "Short circuit to phase (sensor)" }, + { 0x8073, "Short circuit to ground (sensor)" }, + { 0x8074, "Wire break" }, + { 0x8075, "No sensor power supply Digital input" }, + { 0x8080, "Configuration/parameter assignment error" }, + { 0x8081, "Chassis ground fault" }, + { 0x8082, "Short circuit to phase" }, + { 0x8083, "Short circuit to ground" }, + { 0x8084, "Wire break" }, + { 0x8085, "Fuse tripped" }, + { 0x8086, "No load voltage" }, + { 0x8087, "Excess temperature Digital output" }, + { 0x80B0, "Counter module, signal A faulty" }, + { 0x80B1, "Counter module, signal B faulty" }, + { 0x80B2, "Counter module, signal N faulty" }, + { 0x80B3, "Counter module, incorrect value passed between the channels" }, + { 0x80B4, "Counter module, 5.2 V sensor supply faulty" }, + { 0x80B5, "Counter module, 24 V sensor supply faulty" }, + { 0x9001, "Automatic/Manual mode (coming=man,going=auto)" }, + { 0x9002, "OPEN/CLOSED, ON/OFF" }, + { 0x9003, "Manual command enable" }, + { 0x9004, "Unit protective command (OPEN/CLOSED)" }, + { 0x9005, "Process enable" }, + { 0x9006, "System protection command" }, + { 0x9007, "Process value monitoring responded" }, + { 0x9008, "Manipulated variable monitoring responded" }, + { 0x9009, "System deviation greater than permitted" }, + { 0x900A, "Limit position error" }, + { 0x900B, "Runtime error" }, + { 0x900C, "Command execution error (sequencer)" }, + { 0x900D, "Operating status running > OPEN" }, + { 0x900E, "Operating status running > CLOSED" }, + { 0x900F, "Command blocking" }, + { 0x9011, "Process status OPEN/ON" }, + { 0x9012, "Process status CLOSED/OFF" }, + { 0x9013, "Process status intermediate position" }, + { 0x9014, "Process status ON via AUTO" }, + { 0x9015, "Process status ON via manual" }, + { 0x9016, "Process status ON via protective command" }, + { 0x9017, "Process status OFF via AUTO" }, + { 0x9018, "Process status OFF via manual" }, + { 0x9019, "Process status OFF via protective command" }, + { 0x9021, "Function error on approach" }, + { 0x9022, "Function error on leaving" }, + { 0x9031, "Actuator (DE/WE) limit position OPEN" }, + { 0x9032, "Actuator (DE/WE) limit position not OPEN" }, + { 0x9033, "Actuator (DE/WE) limit position CLOSED" }, + { 0x9034, "Actuator (DE/WE) limit position not CLOSED" }, + { 0x9041, "Illegal status, tolerance time elapsed" }, + { 0x9042, "Illegal status, tolerance time not elapsed" }, + { 0x9043, "Interlock error, tolerance time = 0" }, + { 0x9044, "Interlock error, tolerance time > 0" }, + { 0x9045, "No reaction" }, + { 0x9046, "Final status exited illegally, tolerance time = 0" }, + { 0x9047, "Final status exited illegally, tolerance time > 0" }, + { 0x9050, "Upper limit of signal range USR" }, + { 0x9051, "Upper limit of measuring range UMR" }, + { 0x9052, "Lower limit of signal range LSR" }, + { 0x9053, "Lower limit of measuring range LMR" }, + { 0x9054, "Upper alarm limit UAL" }, + { 0x9055, "Upper warning limit UWL" }, + { 0x9056, "Upper tolerance limit UTL" }, + { 0x9057, "Lower tolerance limit LTL" }, + { 0x9058, "Lower warning limit LWL" }, + { 0x9059, "Lower alarm limit LAL" }, + { 0x9060, "GRAPH7 step entering/leaving" }, + { 0x9061, "GRAPH7 interlock error" }, + { 0x9062, "GRAPH7 execution error" }, + { 0x9063, "GRAPH7 error noted" }, + { 0x9064, "GRAPH7 error acknowledged" }, + { 0x9070, "Trend exceeded in positive direction" }, + { 0x9071, "Trend exceeded in negative direction" }, + { 0x9072, "No reaction" }, + { 0x9073, "Final state exited illegally" }, + { 0x9080, "Limit value exceeded, tolerance time = 0" }, + { 0x9081, "Limit value exceeded, tolerance time > 0" }, + { 0x9082, "Below limit value, tolerance time = 0" }, + { 0x9083, "Below limit value, tolerance time > 0" }, + { 0x9084, "Gradient exceeded, tolerance time = 0" }, + { 0x9085, "Gradient exceeded, tolerance time > 0" }, + { 0x9086, "Below gradient, tolerance time = 0" }, + { 0x9087, "Below gradient, tolerance time > 0" }, + { 0x9090, "User parameter assignment error entering/leaving" }, + { 0x90F0, "Overflow" }, + { 0x90F1, "Underflow" }, + { 0x90F2, "Division by 0" }, + { 0x90F3, "Illegal calculation operation" }, + { 0, NULL } +}; +static value_string_ext cpu_diag_eventid_0x8_0x9_names_ext = VALUE_STRING_EXT_INIT(cpu_diag_eventid_0x8_0x9_names); + +/************************************************************************** + * Type of alarmquery in alarm query request + */ +#define S7COMM_ALARM_MESSAGE_QUERYTYPE_BYALARMTYPE 1 +#define S7COMM_ALARM_MESSAGE_QUERYTYPE_BYEVENTID 3 + +static const value_string alarm_message_querytype_names[] = { + { S7COMM_ALARM_MESSAGE_QUERYTYPE_BYALARMTYPE, "ByAlarmtype" }, + { S7COMM_ALARM_MESSAGE_QUERYTYPE_BYEVENTID, "ByEventID" }, + { 0, NULL } +}; + +/************************************************************************** + * Alarmtype in alarm query + */ +#define S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_SCAN 1 +#define S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_ALARM_8 2 +#define S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_ALARM_S 4 + +static const value_string alarm_message_query_alarmtype_names[] = { + { S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_SCAN, "SCAN" }, + { S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_ALARM_8, "ALARM_8" }, + { S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_ALARM_S, "ALARM_S" }, + { 0, NULL } +}; + +/* CPU message service */ +static gint hf_s7comm_cpu_msgservice_subscribe_events = -1; +static gint hf_s7comm_cpu_msgservice_subscribe_events_modetrans = -1; +static gint hf_s7comm_cpu_msgservice_subscribe_events_system = -1; +static gint hf_s7comm_cpu_msgservice_subscribe_events_userdefined = -1; +static gint hf_s7comm_cpu_msgservice_subscribe_events_alarms = -1; +static gint ett_s7comm_cpu_msgservice_subscribe_events = -1; +static int * const s7comm_cpu_msgservice_subscribe_events_fields[] = { + &hf_s7comm_cpu_msgservice_subscribe_events_modetrans, + &hf_s7comm_cpu_msgservice_subscribe_events_system, + &hf_s7comm_cpu_msgservice_subscribe_events_userdefined, + &hf_s7comm_cpu_msgservice_subscribe_events_alarms, + NULL +}; +static gint hf_s7comm_cpu_msgservice_req_reserved1 = -1; +static gint hf_s7comm_cpu_msgservice_username = -1; +static gint hf_s7comm_cpu_msgservice_almtype = -1; +static gint hf_s7comm_cpu_msgservice_req_reserved2 = -1; +static gint hf_s7comm_cpu_msgservice_res_result = -1; +static gint hf_s7comm_cpu_msgservice_res_reserved1 = -1; +static gint hf_s7comm_cpu_msgservice_res_reserved2 = -1; +static gint hf_s7comm_cpu_msgservice_res_reserved3 = -1; + +#define S7COMM_CPU_MSG_ALMTYPE_SCAN_ABORT 0 +#define S7COMM_CPU_MSG_ALMTYPE_SCAN_INITIATE 1 +#define S7COMM_CPU_MSG_ALMTYPE_ALARM_ABORT 4 +#define S7COMM_CPU_MSG_ALMTYPE_ALARM_INITIATE 5 +#define S7COMM_CPU_MSG_ALMTYPE_AR_SEND_ABORT 6 +#define S7COMM_CPU_MSG_ALMTYPE_AR_SEND_INITIATE 7 +#define S7COMM_CPU_MSG_ALMTYPE_ALARM_S_ABORT 8 +#define S7COMM_CPU_MSG_ALMTYPE_ALARM_S_INITIATE 9 + +static const value_string cpu_msgservice_almtype_names[] = { + { S7COMM_CPU_MSG_ALMTYPE_SCAN_ABORT, "SCAN_ABORT" }, + { S7COMM_CPU_MSG_ALMTYPE_SCAN_INITIATE, "SCAN_INITIATE" }, + { S7COMM_CPU_MSG_ALMTYPE_ALARM_ABORT, "ALARM_ABORT" }, + { S7COMM_CPU_MSG_ALMTYPE_ALARM_INITIATE, "ALARM_INITIATE" }, + { S7COMM_CPU_MSG_ALMTYPE_AR_SEND_ABORT, "AR_SEND_ABORT" }, + { S7COMM_CPU_MSG_ALMTYPE_AR_SEND_INITIATE, "AR_SEND_INITIATE" }, + { S7COMM_CPU_MSG_ALMTYPE_ALARM_S_ABORT, "ALARM_S_ABORT" }, + { S7COMM_CPU_MSG_ALMTYPE_ALARM_S_INITIATE, "ALARM_S_INITIATE" }, + { 0, NULL } +}; + +static gint hf_s7comm_modetrans_param_unknown1 = -1; +static gint hf_s7comm_modetrans_param_mode = -1; +static const value_string modetrans_param_mode_names[] = { + { 0, "STOP" }, + { 1, "Warm Restart" }, + { 2, "RUN" }, + { 3, "Hot Restart" }, + { 4, "HOLD" }, + { 6, "Cold Restart" }, + { 9, "RUN_R (H-System redundant)" }, + { 11, "LINK-UP" }, + { 12, "UPDATE" }, + { 0, NULL } +}; +static gint hf_s7comm_modetrans_param_unknown2 = -1; + +/* These fields used when reassembling S7COMM fragments */ +static gint hf_s7comm_fragments = -1; +static gint hf_s7comm_fragment = -1; +static gint hf_s7comm_fragment_overlap = -1; +static gint hf_s7comm_fragment_overlap_conflict = -1; +static gint hf_s7comm_fragment_multiple_tails = -1; +static gint hf_s7comm_fragment_too_long_fragment = -1; +static gint hf_s7comm_fragment_error = -1; +static gint hf_s7comm_fragment_count = -1; +static gint hf_s7comm_reassembled_in = -1; +static gint hf_s7comm_reassembled_length = -1; +static gint ett_s7comm_fragment = -1; +static gint ett_s7comm_fragments = -1; + +static const fragment_items s7comm_frag_items = { + /* Fragment subtrees */ + &ett_s7comm_fragment, + &ett_s7comm_fragments, + /* Fragment fields */ + &hf_s7comm_fragments, + &hf_s7comm_fragment, + &hf_s7comm_fragment_overlap, + &hf_s7comm_fragment_overlap_conflict, + &hf_s7comm_fragment_multiple_tails, + &hf_s7comm_fragment_too_long_fragment, + &hf_s7comm_fragment_error, + &hf_s7comm_fragment_count, + /* Reassembled in field */ + &hf_s7comm_reassembled_in, + /* Reassembled length field */ + &hf_s7comm_reassembled_length, + /* Reassembled data field */ + NULL, + /* Tag */ + "S7COMM fragments" +}; + +static reassembly_table s7comm_reassembly_table; + +/* These are the ids of the subtrees that we are creating */ +static gint ett_s7comm = -1; /* S7 communication tree, parent of all other subtree */ +static gint ett_s7comm_header = -1; /* Subtree for header block */ +static gint ett_s7comm_param = -1; /* Subtree for parameter block */ +static gint ett_s7comm_param_item = -1; /* Subtree for items in parameter block */ +static gint ett_s7comm_param_subitem = -1; /* Subtree for subitems under items in parameter block */ +static gint ett_s7comm_data = -1; /* Subtree for data block */ +static gint ett_s7comm_data_item = -1; /* Subtree for an item in data block */ +static gint ett_s7comm_item_address = -1; /* Subtree for an address (byte/bit) */ +static gint ett_s7comm_cpu_alarm_message = -1; /* Subtree for an alarm message */ +static gint ett_s7comm_cpu_alarm_message_object = -1; /* Subtree for an alarm message block*/ +static gint ett_s7comm_cpu_alarm_message_timestamp = -1; /* Subtree for an alarm message timestamp */ +static gint ett_s7comm_cpu_alarm_message_associated_value = -1; /* Subtree for an alarm message associated value */ +static gint ett_s7comm_cpu_diag_msg = -1; /* Subtree for a CPU diagnostic message */ +static gint ett_s7comm_prog_parameter = -1; +static gint ett_s7comm_prog_data = -1; + +static const char mon_names[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +/******************************************************************************************************* + * + * Converts a siemens special timestamp to a string of 25+1 bytes length (e.g. "Apr 15, 2009 12:49:30.520"). + * The timestamp is 6 bytes long, one word is the number of days since 1.1.1984, and 4 bytes milliseconds of the day + * + *******************************************************************************************************/ +static void +s7comm_get_timestring_from_s7time(tvbuff_t *tvb, guint offset, char *str, gint max) +{ + guint16 days; + guint32 day_msec; + struct tm *mt; + time_t t; + + day_msec = tvb_get_ntohl(tvb, offset); + days = tvb_get_ntohs(tvb, offset + 4); + + t = 441763200L; /* 1.1.1984 00:00:00 */ + t += (guint32)days * (24*60*60); + t += day_msec / 1000; + mt = gmtime(&t); + str[0] = '\0'; + if (mt != NULL) { + snprintf(str, max, "%s %2d, %d %02d:%02d:%02d.%03d", mon_names[mt->tm_mon], mt->tm_mday, + mt->tm_year + 1900, mt->tm_hour, mt->tm_min, mt->tm_sec, day_msec % 1000); + } +} + +/******************************************************************************************************* + * + * Helper for time functions + * Get int from bcd + * + *******************************************************************************************************/ +static guint8 +s7comm_guint8_from_bcd(guint8 i) +{ + return 10 * (i /16) + (i % 16); +} + +/******************************************************************************************************* + * + * Helper for time functions + * Add a BCD coded timestamp (10/8 Bytes length) to tree + * + *******************************************************************************************************/ +static guint32 +s7comm_add_timestamp_to_tree(tvbuff_t *tvb, + proto_tree *tree, + guint32 offset, + gboolean append_text, + gboolean has_ten_bytes) /* if this is false the [0] reserved and [1] year bytes are missing */ +{ + guint8 timestamp[10]; + guint8 i; + guint8 tmp; + guint8 year_org; + guint16 msec; + nstime_t tv; + proto_item *item = NULL; + proto_item *time_tree = NULL; + struct tm mt; + int timestamp_size = 10; + + if (has_ten_bytes) { + /* The low nibble of byte 10 is weekday, the high nibble the LSD of msec */ + for (i = 0; i < 9; i++) { + timestamp[i] = s7comm_guint8_from_bcd(tvb_get_guint8(tvb, offset + i)); + } + tmp = tvb_get_guint8(tvb, offset + 9) >> 4; + } else { + /* this is a 8 byte timestamp, where the reserved and the year byte is missing */ + timestamp_size = 8; + timestamp[0] = 0; + timestamp[1] = 19; /* start with 19.., will be corrected later */ + for (i = 0; i < 7; i++) { + timestamp[i + 2] = s7comm_guint8_from_bcd(tvb_get_guint8(tvb, offset + i)); + } + tmp = tvb_get_guint8(tvb, offset + 7) >> 4; + } + timestamp[9] = s7comm_guint8_from_bcd(tmp); + + msec = (guint16)timestamp[8] * 10 + (guint16)timestamp[9]; + year_org = timestamp[1]; + /* year special: ignore the first byte, since some cpus give 1914 for 2014 + * if second byte is below 89, it's 2000..2089, if over 90 it's 1990..1999 + */ + if (timestamp[2] < 89) { + timestamp[1] = 20; + } + /* convert time to nstime_t */ + mt.tm_year = (timestamp[1] * 100 + timestamp[2]) - 1900; + mt.tm_mon = timestamp[3] - 1; + mt.tm_mday = timestamp[4]; + mt.tm_hour = timestamp[5]; + mt.tm_min = timestamp[6]; + mt.tm_sec = timestamp[7]; + mt.tm_isdst = -1; + tv.secs = mktime(&mt); + tv.nsecs = msec * 1000000; + if (mt.tm_mon >= 0 && mt.tm_mon <= 11) { + item = proto_tree_add_time_format(tree, hf_s7comm_data_ts, tvb, offset, timestamp_size, &tv, + "S7 Timestamp: %s %2d, %d %02d:%02d:%02d.%03d", mon_names[mt.tm_mon], mt.tm_mday, + mt.tm_year + 1900, mt.tm_hour, mt.tm_min, mt.tm_sec, + msec); + time_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + + /* timefunction: s7 timestamp */ + if (has_ten_bytes) { + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_reserved, tvb, offset, 1, timestamp[0]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_year1, tvb, offset, 1, year_org); + offset += 1; + } + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_year2, tvb, offset, 1, timestamp[2]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_month, tvb, offset, 1, timestamp[3]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_day, tvb, offset, 1, timestamp[4]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_hour, tvb, offset, 1, timestamp[5]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_minute, tvb, offset, 1, timestamp[6]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_second, tvb, offset, 1, timestamp[7]); + offset += 1; + proto_tree_add_uint(time_tree, hf_s7comm_data_ts_millisecond, tvb, offset, 2, msec); + proto_tree_add_item(time_tree, hf_s7comm_data_ts_weekday, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + if (append_text == TRUE) { + proto_item_append_text(tree, "(Timestamp: %s %2d, %d %02d:%02d:%02d.%03d)", mon_names[mt.tm_mon], mt.tm_mday, + mt.tm_year + 1900, mt.tm_hour, mt.tm_min, mt.tm_sec, + msec); + } + } else { + /* If the timestamp is invalid, continue as best as we can */ + if (has_ten_bytes) { + offset += 10; + } + else { + offset += 8; + } + } + return offset; +} + +/******************************************************************************************************* + * + * Generate a comma separated string for registerflags + * + *******************************************************************************************************/ +static void +make_registerflag_string(gchar *str, guint8 flags, gint max) +{ + (void) g_strlcpy(str, "", max); + if (flags & 0x01) (void) g_strlcat(str, "STW, ", max); + if (flags & 0x02) (void) g_strlcat(str, "ACCU1, ", max); + if (flags & 0x04) (void) g_strlcat(str, "ACCU2, ", max); + if (flags & 0x08) (void) g_strlcat(str, "AR1, ", max); + if (flags & 0x10) (void) g_strlcat(str, "AR2, ", max); + if (flags & 0x20) (void) g_strlcat(str, "DB1, ", max); + if (flags & 0x40) (void) g_strlcat(str, "DB2, ", max); + if (strlen(str) > 2) + str[strlen(str) - 2 ] = '\0'; +} + +/******************************************************************************************************* + * + * Addressdefinition for Syntax ID S7-ANY (Step 7 Classic 300/400 or 1200/1500 not optimized) + * type == 0x12, length == 10, syntax-ID == 0x10 + * + *******************************************************************************************************/ +static guint32 +s7comm_syntaxid_s7any(tvbuff_t *tvb, + guint32 offset, + proto_tree *tree) +{ + guint32 t_size = 0; + guint32 len = 0; + guint32 db = 0; + guint32 area = 0; + guint32 a_address = 0; + guint32 bytepos = 0; + guint32 bitpos = 0; + proto_item *address_item = NULL; + proto_tree *address_item_tree = NULL; + + /* Transport size, 1 byte */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_transport_size, tvb, offset, 1, ENC_BIG_ENDIAN, &t_size); + offset += 1; + /* Special handling of data record */ + area = tvb_get_guint8(tvb, offset + 4); /* peek area first */ + if (area == S7COMM_AREA_DATARECORD) { + /* MLEN, 2 bytes */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_rdrec_mlen, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + /* INDEX, 2 bytes */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_rdrec_index, tvb, offset, 2, ENC_BIG_ENDIAN, &db); + offset += 2; + /* Area, 1 byte */ + proto_tree_add_uint(tree, hf_s7comm_item_area, tvb, offset, 1, area); + offset += 1; + /* ID, 3 bytes */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_rdrec_id, tvb, offset, 3, ENC_BIG_ENDIAN, &a_address); + offset += 3; + proto_item_append_text(tree, " (RECORD MLEN=%d INDEX=0x%04x ID=%d)", len, db, a_address); + } else { + /* Length, 2 bytes */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_length, tvb, offset, 2, ENC_BIG_ENDIAN, &len); + offset += 2; + /* DB number, 2 bytes */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_db, tvb, offset, 2, ENC_BIG_ENDIAN, &db); + offset += 2; + /* Area, 1 byte */ + proto_tree_add_uint(tree, hf_s7comm_item_area, tvb, offset, 1, area); + offset += 1; + /* Address, 3 bytes */ + address_item = proto_tree_add_item_ret_uint(tree, hf_s7comm_item_address, tvb, offset, 3, ENC_BIG_ENDIAN, &a_address); + address_item_tree = proto_item_add_subtree(address_item, ett_s7comm_item_address); + bytepos = a_address / 8; + bitpos = a_address % 8; + /* build a full address to show item data directly beside the item */ + proto_item_append_text(tree, " (%s", val_to_str(area, item_areanames_short, "unknown area 0x%02x")); + if (area == S7COMM_AREA_TIMER || area == S7COMM_AREA_COUNTER) { + proto_item_append_text(tree, " %d)", a_address); + proto_tree_add_uint(address_item_tree, hf_s7comm_item_address_nr, tvb, offset, 3, a_address); + } else { + proto_tree_add_uint(address_item_tree, hf_s7comm_item_address_byte, tvb, offset, 3, a_address); + proto_tree_add_uint(address_item_tree, hf_s7comm_item_address_bit, tvb, offset, 3, a_address); + if (area == S7COMM_AREA_DB) { + proto_item_append_text(tree, " %d.DBX", db); + } else if (area == S7COMM_AREA_DI) { + proto_item_append_text(tree, " %d.DIX", db); + } + proto_item_append_text(tree, " %d.%d %s %d)", + bytepos, bitpos, val_to_str(t_size, item_transportsizenames, "Unknown transport size: 0x%02x"), len); + } + offset += 3; + } + return offset; +} +/******************************************************************************************************* + * + * Addressdefinition to read a DB area (S7-400 special) + * type == 0x12, length >= 7, syntax-ID == 0xb0 + * + *******************************************************************************************************/ +static guint32 +s7comm_syntaxid_dbread(tvbuff_t *tvb, + guint32 offset, + proto_tree *tree) +{ + guint32 number_of_areas = 0; + guint32 len = 0; + guint32 db = 0; + guint32 bytepos = 0; + guint32 i; + proto_item *sub_item = NULL; + proto_tree *sub_item_tree = NULL; + + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_dbread_numareas, tvb, offset, 1, ENC_BIG_ENDIAN, &number_of_areas); + proto_item_append_text(tree, " (%d Data-Areas of Syntax-Id DBREAD)", number_of_areas); + offset += 1; + for (i = 0; i < number_of_areas; i++) { + sub_item = proto_tree_add_item(tree, hf_s7comm_param_subitem, tvb, offset, 5, ENC_NA); + sub_item_tree = proto_item_add_subtree(sub_item, ett_s7comm_param_subitem); + proto_tree_add_item_ret_uint(sub_item_tree, hf_s7comm_item_dbread_length, tvb, offset, 1, ENC_BIG_ENDIAN, &len); + offset += 1; + proto_tree_add_item_ret_uint(sub_item_tree, hf_s7comm_item_dbread_db, tvb, offset, 2, ENC_BIG_ENDIAN, &db); + offset += 2; + proto_tree_add_item_ret_uint(sub_item_tree, hf_s7comm_item_dbread_startadr, tvb, offset, 2, ENC_BIG_ENDIAN, &bytepos); + offset += 2; + /* Display in pseudo S7-Any Format */ + proto_item_append_text(sub_item, " [%d]: (DB%d.DBB %d BYTE %d)", i+1, db, bytepos, len); + } + return offset; +} + +/******************************************************************************************************* + * + * Addressdefinition for TIA S7 1200 symbolic address mode + * type == 0x12, length >= 14, syntax-ID == 0xb2 + * + *******************************************************************************************************/ +static guint32 +s7comm_syntaxid_1200sym(tvbuff_t *tvb, + guint32 offset, + proto_tree *tree, + guint8 varspec_length) +{ + guint32 tia_var_area1 = 0; + guint32 tia_var_area2 = 0; + guint8 tia_lid_flags = 0; + guint32 tia_value = 0; + guint16 i; + proto_item *sub_item = NULL; + proto_tree *sub_item_tree = NULL; + + proto_item_append_text(tree, " 1200 symbolic address"); + /* first byte in address seems always to be 0xff */ + proto_tree_add_item(tree, hf_s7comm_tia1200_item_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* When Bytes 2/3 == 0, then Bytes 4/5 defines the area as known from classic 300/400 address mode. + * When Bytes 2/3 == 0x8a0e then Bytes 4/5 are containing the DB number. + */ + proto_tree_add_item_ret_uint(tree, hf_s7comm_tia1200_item_area1, tvb, offset, 2, ENC_BIG_ENDIAN, &tia_var_area1); + offset += 2; + tia_var_area2 = tvb_get_ntohs(tvb, offset); + if (tia_var_area1 == S7COMM_TIA1200_VAR_ITEM_AREA1_IQMCT) { + proto_tree_add_uint(tree, hf_s7comm_tia1200_item_area2, tvb, offset, 2, tia_var_area2); + proto_item_append_text(tree, " - Accessing %s", val_to_str(tia_var_area2, tia1200_var_item_area2_names, "Unknown IQMCT Area: 0x%04x")); + offset += 2; + } else if (tia_var_area1 == S7COMM_TIA1200_VAR_ITEM_AREA1_DB) { + proto_tree_add_uint(tree, hf_s7comm_tia1200_item_dbnumber, tvb, offset, 2, tia_var_area2); + proto_item_append_text(tree, " - Accessing DB%d", tia_var_area2); + offset += 2; + } else { + /* for current unknown areas */ + proto_tree_add_uint(tree, hf_s7comm_tia1200_item_area2unknown, tvb, offset, 2, tia_var_area2); + proto_item_append_text(tree, " - Unknown area specification"); + offset += 2; + } + proto_tree_add_item(tree, hf_s7comm_tia1200_item_crc, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + for (i = 0; i < (varspec_length - 10) / 4; i++) { + sub_item = proto_tree_add_item(tree, hf_s7comm_tia1200_substructure_item, tvb, offset, 4, ENC_NA); + sub_item_tree = proto_item_add_subtree(sub_item, ett_s7comm_param_subitem); + tia_lid_flags = tvb_get_guint8(tvb, offset) >> 4; + proto_tree_add_item(sub_item_tree, hf_s7comm_tia1200_var_lid_flags, tvb, offset, 1, ENC_BIG_ENDIAN); + tia_value = tvb_get_ntohl(tvb, offset) & 0x0fffffff; + proto_item_append_text(sub_item, " [%d]: %s, Value: %u", i + 1, + val_to_str(tia_lid_flags, tia1200_var_lid_flag_names, "Unknown flags: 0x%02x"), + tia_value + ); + proto_tree_add_item(sub_item_tree, hf_s7comm_tia1200_item_value, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } + return offset; +} + +/******************************************************************************************************* + * + * Addressdefinition for Sinumeric NCK access + * type == 0x12, length == 8, syntax-ID == 0x82 or == 0x83 or == 0x84 + * + *******************************************************************************************************/ +static guint32 +s7comm_syntaxid_nck(tvbuff_t *tvb, + guint32 offset, + proto_tree *tree) +{ + guint32 area = 0; + guint32 nck_area = 0; + guint32 nck_unit = 0; + guint32 nck_column = 0; + guint32 nck_line = 0; + guint32 nck_module = 0; + + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_nck_areaunit, tvb, offset, 1, ENC_BIG_ENDIAN, &area); + nck_area = area >> 5; + nck_unit = area & 0x1f; + proto_tree_add_item(tree, hf_s7comm_item_nck_area, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_s7comm_item_nck_unit, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_nck_column, tvb, offset, 2, ENC_BIG_ENDIAN, &nck_column); + offset += 2; + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_nck_line, tvb, offset, 2, ENC_BIG_ENDIAN, &nck_line); + offset += 2; + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_nck_module, tvb, offset, 1, ENC_BIG_ENDIAN, &nck_module); + offset += 1; + proto_tree_add_item(tree, hf_s7comm_item_nck_linecount, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_item_append_text(tree, " (NCK Area:%d Unit:%d Column:%d Line:%d Module:0x%02x)", + nck_area, nck_unit, nck_column, nck_line, nck_module); + return offset; +} + +/******************************************************************************************************* + * + * Addressdefinition for accessing Multimaster / Sinamics frequency convertes via routing from DriveES. + * type == 0x12, length == 10, syntax-ID == 0x82 + * + *******************************************************************************************************/ +static guint32 +s7comm_syntaxid_driveesany(tvbuff_t *tvb, + guint32 offset, + proto_tree *tree) +{ + guint32 nr = 0; + guint32 idx = 0; + + proto_tree_add_item(tree, hf_s7comm_item_driveesany_unknown1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(tree, hf_s7comm_item_driveesany_unknown2, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_s7comm_item_driveesany_unknown3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_driveesany_parameter_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &nr); + offset += 2; + proto_tree_add_item_ret_uint(tree, hf_s7comm_item_driveesany_parameter_idx, tvb, offset, 2, ENC_BIG_ENDIAN, &idx); + offset += 2; + proto_item_append_text(tree, " (DriveES Parameter: %d[%d])", nr, idx); + return offset; +} + +/******************************************************************************************************* + * + * Dissect the parameter details of a read/write request (Items) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_param_item(tvbuff_t *tvb, + guint32 offset, + proto_tree *sub_tree, + guint8 item_no) +{ + proto_item *item = NULL; + proto_tree *item_tree = NULL; + guint8 var_spec_type = 0; + guint8 var_spec_length = 0; + guint8 var_spec_syntax_id = 0; + + var_spec_type = tvb_get_guint8(tvb, offset); + var_spec_length = tvb_get_guint8(tvb, offset + 1); + var_spec_syntax_id = tvb_get_guint8(tvb, offset + 2); + + /* Insert a new tree for every item */ + item = proto_tree_add_item(sub_tree, hf_s7comm_param_item, tvb, offset, var_spec_length + 2, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_param_item); + proto_item_append_text(item, " [%d]:", item_no + 1); + + /* Item head, constant 3 bytes */ + proto_tree_add_item(item_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + if (var_spec_type == 0x12 && var_spec_length == 10 && var_spec_syntax_id == S7COMM_SYNTAXID_S7ANY) { + /* Step 7 Classic 300 400 */ + offset = s7comm_syntaxid_s7any(tvb, offset, item_tree); + } else if (var_spec_type == 0x12 && var_spec_length >= 7 && var_spec_syntax_id == S7COMM_SYNTAXID_DBREAD) { + /* S7-400 special address mode (kind of cyclic read) */ + offset = s7comm_syntaxid_dbread(tvb, offset, item_tree); + } else if (var_spec_type == 0x12 && var_spec_length >= 14 && var_spec_syntax_id == S7COMM_SYNTAXID_1200SYM) { + /* TIA S7 1200 symbolic address mode */ + offset = s7comm_syntaxid_1200sym(tvb, offset, item_tree, var_spec_length); + } else if (var_spec_type == 0x12 && var_spec_length == 8 + && ((var_spec_syntax_id == S7COMM_SYNTAXID_NCK) + || (var_spec_syntax_id == S7COMM_SYNTAXID_NCK_METRIC) + || (var_spec_syntax_id == S7COMM_SYNTAXID_NCK_INCH))) { + /* Sinumerik NCK access */ + offset = s7comm_syntaxid_nck(tvb, offset, item_tree); + } else if (var_spec_type == 0x12 && var_spec_length == 10 && var_spec_syntax_id == S7COMM_SYNTAXID_DRIVEESANY) { + /* Accessing frequency inverter parameters (via routing) */ + offset = s7comm_syntaxid_driveesany(tvb, offset, item_tree); + } + else { + /* var spec, length and syntax id are still added to tree here */ + offset += var_spec_length - 1; + proto_item_append_text(item_tree, " Unknown variable specification"); + } + return offset; +} + +/******************************************************************************************************* + * + * Decode parameter part of a PDU for setup communication + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_pdu_setup_communication(tvbuff_t *tvb, + proto_tree *tree, + guint32 offset) +{ + proto_tree_add_item(tree, hf_s7comm_param_setup_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(tree, hf_s7comm_param_maxamq_calling, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_s7comm_param_maxamq_called, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tree, hf_s7comm_param_neg_pdu_length, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: Response -> Function Write -> Data part + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_response_write_data(tvbuff_t *tvb, + proto_tree *tree, + guint8 item_count, + guint32 offset) +{ + guint8 ret_val = 0; + guint8 i = 0; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + + for (i = 0; i < item_count; i++) { + ret_val = tvb_get_guint8(tvb, offset); + /* Insert a new tree for every item */ + item = proto_tree_add_item(tree, hf_s7comm_data_item, tvb, offset, 1, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_item_append_text(item, " [%d]: (%s)", i+1, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + proto_tree_add_uint(item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + offset += 1; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: Response -> Function Read -> Data part + * Request -> Function Write -> Data part + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_response_read_data(tvbuff_t *tvb, + proto_tree *tree, + guint8 item_count, + guint32 offset) +{ + guint8 ret_val = 0; + guint8 tsize = 0; + guint16 len = 0, len2 = 0; + guint16 head_len = 4; /* 1 byte res-code, 1 byte transp-size, 2 bytes len */ + guint8 i = 0; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + + /* Maybe this is only valid for Sinumerik NCK: Pre-check transport-size + * If transport size is 0x11 or 0x12, then an array with requested NCK areas will follow. + */ + tsize = tvb_get_guint8(tvb, offset + 1); + if (tsize == S7COMM_DATA_TRANSPORT_SIZE_NCKADDR1 || tsize == S7COMM_DATA_TRANSPORT_SIZE_NCKADDR2) { + proto_tree_add_item(tree, hf_s7comm_data_returncode, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_uint(tree, hf_s7comm_data_transport_size, tvb, offset + 1, 1, tsize); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_param_item(tvb, offset, tree, i); + } + } else { + /* Standard */ + for (i = 0; i < item_count; i++) { + ret_val = tvb_get_guint8(tvb, offset); + if (ret_val == S7COMM_ITEM_RETVAL_RESERVED || + ret_val == S7COMM_ITEM_RETVAL_DATA_OK || + ret_val == S7COMM_ITEM_RETVAL_DATA_ERR + ) { + tsize = tvb_get_guint8(tvb, offset + 1); + len = tvb_get_ntohs(tvb, offset + 2); + /* calculate length in bytes */ + if (tsize == S7COMM_DATA_TRANSPORT_SIZE_BBIT || + tsize == S7COMM_DATA_TRANSPORT_SIZE_BBYTE || + tsize == S7COMM_DATA_TRANSPORT_SIZE_BINT + ) { /* given length is in number of bits */ + if (len % 8) { /* len is not a multiple of 8, then round up to next number */ + len /= 8; + len = len + 1; + } else { + len /= 8; + } + } + + /* the PLC places extra bytes at the end of all but last result, if length is not a multiple of 2 */ + if ((len % 2) && (i < (item_count-1))) { + len2 = len + 1; + } else { + len2 = len; + } + } + /* Insert a new tree for every item */ + item = proto_tree_add_item(tree, hf_s7comm_data_item, tvb, offset, len + head_len, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_item_append_text(item, " [%d]: (%s)", i+1, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + + proto_tree_add_uint(item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + proto_tree_add_uint(item_tree, hf_s7comm_data_transport_size, tvb, offset + 1, 1, tsize); + proto_tree_add_uint(item_tree, hf_s7comm_data_length, tvb, offset + 2, 2, len); + offset += head_len; + + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK || ret_val == S7COMM_ITEM_RETVAL_RESERVED) { + proto_tree_add_item(item_tree, hf_s7comm_readresponse_data, tvb, offset, len, ENC_NA); + offset += len; + if (len != len2) { + proto_tree_add_item(item_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: Request or Response -> Function 0x29 (PLC control functions -> STOP) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_plc_controls_param_hex29(tvbuff_t *tvb, + proto_tree *tree, + guint32 offset) +{ + guint8 len; + + /* The first byte 0x29 is checked and inserted to tree outside, so skip it here */ + offset += 1; + /* Meaning of first 5 bytes (Part 1) is unknown */ + proto_tree_add_item(tree, hf_s7comm_piservice_unknown1, tvb, offset, 5, ENC_NA); + offset += 5; + /* Part 2 */ + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_s7comm_data_plccontrol_part2_len, tvb, offset, 1, len); + offset += 1; + /* Function as string */ + proto_tree_add_item(tree, hf_s7comm_piservice_servicename, tvb, offset, len, ENC_ASCII); + offset += len; + + return offset; +} + +/******************************************************************************************************* + * PI_START Parameters: Decodes a parameter array with string values. + *******************************************************************************************************/ +static guint32 +s7comm_decode_pistart_parameters(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + proto_tree *param_tree, + const guint8 *servicename, + guint8 nfields, /* number of fields used */ + guint hf[], /* array with header fields */ + guint32 offset) +{ + guint8 i; + guint8 len; + wmem_strbuf_t *args_buf; + args_buf = wmem_strbuf_create(pinfo->pool); + + for (i = 0; i < nfields; i++) { + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(param_tree, hf_s7comm_piservice_string_len, tvb, offset, 1, len); + offset += 1; + proto_tree_add_item(param_tree, hf[i], tvb, offset, len, ENC_ASCII|ENC_NA); + wmem_strbuf_append(args_buf, "\""); + wmem_strbuf_append(args_buf, tvb_format_text(pinfo->pool, tvb, offset, len)); + if (i < nfields-1) { + wmem_strbuf_append(args_buf, "\", "); + } else { + wmem_strbuf_append(args_buf, "\""); + } + offset += len + (len % 2 == 0); + } + proto_item_append_text(param_tree, ": (%s)", wmem_strbuf_get_str(args_buf)); + proto_item_append_text(tree, " -> %s(%s)", servicename, wmem_strbuf_get_str(args_buf)); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s(%s)", servicename, wmem_strbuf_get_str(args_buf)); + + return offset; +} + +/******************************************************************************************************* + * PI-Service + *******************************************************************************************************/ +static guint32 +s7comm_decode_pi_service(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + guint16 plength, + guint32 offset) +{ + guint16 len, paramlen; + guint32 startoffset; + guint32 paramoffset; + guint8 count; + guint8 i; + const guint8 *servicename; + const guint8 *str; + const guint8 *str1; + guint16 blocktype; + guint hf[13]; + int pi_servicename_idx; + const gchar *pi_servicename_descr; + + proto_item *item = NULL; + proto_item *itemadd = NULL; + proto_tree *param_tree = NULL; + proto_tree *file_tree = NULL; + + gint32 num = -1; + gboolean num_valid; + + startoffset = offset; + + /* The first byte is checked and inserted to tree outside, so skip it here */ + offset += 1; + + /* First part is unknown, 7 bytes */ + proto_tree_add_item(tree, hf_s7comm_piservice_unknown1, tvb, offset, 7, ENC_NA); + offset += 7; + + if (offset - startoffset >= plength) { + return offset; + } + /* Parameter block */ + paramlen = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(tree, hf_s7comm_piservice_parameterblock_len, tvb, offset, 2, paramlen); + offset += 2; + + paramoffset = offset; + item = proto_tree_add_item(tree, hf_s7comm_piservice_parameterblock, tvb, offset, paramlen, ENC_NA); + param_tree = proto_item_add_subtree(item, ett_s7comm_piservice_parameterblock); + offset += paramlen; + + /* PI servicename */ + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_s7comm_piservice_string_len, tvb, offset, 1, len); + offset += 1; + item = proto_tree_add_item_ret_string(tree, hf_s7comm_piservice_servicename, tvb, offset, len, ENC_ASCII|ENC_NA, pinfo->pool, &servicename); + offset += len; + + /* get the index position in pi_service_names, and add infotext with description to the item */ + pi_servicename_descr = try_str_to_str_idx((const gchar*)servicename, pi_service_names, &pi_servicename_idx); + if (pi_servicename_idx < 0) { + pi_servicename_idx = S7COMM_PI_UNKNOWN; + pi_servicename_descr = "Unknown PI Service"; + } + proto_item_append_text(item, " [%s]", pi_servicename_descr); + + /* Work parameter data, depending on servicename */ + switch (pi_servicename_idx) { + case S7COMM_PI_INSE: + case S7COMM_PI_INS2: + case S7COMM_PI_DELE: + count = tvb_get_guint8(tvb, paramoffset); /* number of blocks following */ + proto_tree_add_uint(param_tree, hf_s7comm_data_plccontrol_block_cnt, tvb, paramoffset, 1, count); + paramoffset += 1; + /* Unknown, is always 0x00 */ + proto_tree_add_item(param_tree, hf_s7comm_data_pi_inse_unknown, tvb, paramoffset, 1, ENC_BIG_ENDIAN); + paramoffset += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s(", servicename); + for (i = 0; i < count; i++) { + item = proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_filename, tvb, paramoffset, 8, ENC_ASCII); + file_tree = proto_item_add_subtree(item, ett_s7comm_plcfilename); + blocktype = tvb_get_ntohs(tvb, paramoffset); + itemadd = proto_tree_add_item(file_tree, hf_s7comm_data_blockcontrol_block_type, tvb, paramoffset, 2, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(blocktype, blocktype_names, "Unknown Block type: 0x%04x")); + paramoffset += 2; + proto_tree_add_item_ret_string(file_tree, hf_s7comm_data_blockcontrol_block_num, tvb, paramoffset, 5, ENC_ASCII|ENC_NA, pinfo->pool, &str); + paramoffset += 5; + num_valid = ws_strtoi32((const char*)str, NULL, &num); + proto_item_append_text(file_tree, " [%s ", + val_to_str(blocktype, blocktype_names, "Unknown Block type: 0x%04x")); + col_append_str(pinfo->cinfo, COL_INFO, + val_to_str(blocktype, blocktype_names, "Unknown Block type: 0x%04x")); + if (num_valid) { + proto_item_append_text(file_tree, "%d]", num); + col_append_fstr(pinfo->cinfo, COL_INFO, "%d", num); + } else { + expert_add_info(pinfo, file_tree, &ei_s7comm_data_blockcontrol_block_num_invalid); + proto_item_append_text(file_tree, "NaN]"); + col_append_str(pinfo->cinfo, COL_INFO, "NaN"); + } + if (i+1 < count) { + col_append_str(pinfo->cinfo, COL_INFO, ", "); + } + itemadd = proto_tree_add_item(file_tree, hf_s7comm_data_blockcontrol_dest_filesys, tvb, paramoffset, 1, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", char_val_to_str(tvb_get_guint8(tvb, paramoffset), blocktype_attribute2_names, "Unknown filesys")); + paramoffset += 1; + } + col_append_str(pinfo->cinfo, COL_INFO, ")"); + break; + case S7COMM_PIP_PROGRAM: + case S7COMM_PI_MODU: + case S7COMM_PI_GARB: + if (paramlen == 0) { + proto_item_append_text(param_tree, ": ()"); + proto_item_append_text(tree, " -> %s()", servicename); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s()", servicename); + } else { + proto_tree_add_item_ret_string(param_tree, hf_s7comm_data_plccontrol_argument, tvb, paramoffset, paramlen, ENC_ASCII|ENC_NA, pinfo->pool, &str1); + proto_item_append_text(param_tree, ": (\"%s\")", str1); + proto_item_append_text(tree, " -> %s(\"%s\")", servicename, str1); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s(\"%s\")", servicename, str1); + } + break; + case S7COMM_PI_N_LOGIN_: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_password; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_LOGOUT: + case S7COMM_PI_N_CANCEL: + case S7COMM_PI_N_DASAVE: + case S7COMM_PI_N_DIGIOF: + case S7COMM_PI_N_DIGION: + case S7COMM_PI_N_DZERO_: + case S7COMM_PI_N_ENDEXT: + case S7COMM_PI_N_OST_OF: + case S7COMM_PI_N_OST_ON: + case S7COMM_PI_N_SCALE_: + case S7COMM_PI_N_SETUFR: + case S7COMM_PI_N_STRTLK: + case S7COMM_PI_N_STRTUL: + case S7COMM_PI_N_TMRASS: + hf[0] = hf_s7comm_pi_n_x_addressident; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 1, hf, paramoffset); + break; + case S7COMM_PI_N_F_DELE: + case S7COMM_PI_N_EXTERN: + case S7COMM_PI_N_EXTMOD: + case S7COMM_PI_N_F_DELR: + case S7COMM_PI_N_F_XFER: + case S7COMM_PI_N_LOCKE_: + case S7COMM_PI_N_SELECT: + case S7COMM_PI_N_SRTEXT: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_filename; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_F_CLOS: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_editwindowname; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_F_OPEN: + case S7COMM_PI_N_F_OPER: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_filename; + hf[2] = hf_s7comm_pi_n_x_editwindowname; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_F_SEEK: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_editwindowname; + hf[2] = hf_s7comm_pi_n_x_seekpointer; + hf[3] = hf_s7comm_pi_n_x_windowsize; + hf[4] = hf_s7comm_pi_n_x_comparestring; + hf[5] = hf_s7comm_pi_n_x_skipcount; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 6, hf, paramoffset); + break; + case S7COMM_PI_N_ASUP__: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_interruptnr; + hf[2] = hf_s7comm_pi_n_x_priority; + hf[3] = hf_s7comm_pi_n_x_liftfast; + hf[4] = hf_s7comm_pi_n_x_blsync; + hf[5] = hf_s7comm_pi_n_x_filename; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 6, hf, paramoffset); + break; + case S7COMM_PI_N_CHEKDM: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_magnr; + hf[2] = hf_s7comm_pi_n_x_dnr; + hf[3] = hf_s7comm_pi_n_x_spindlenumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_CHKDNO: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_wznr; + hf[2] = hf_s7comm_pi_n_x_wznr; + hf[3] = hf_s7comm_pi_n_x_dnr; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_CONFIG: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_class; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_CRCEDN: + case S7COMM_PI_N_DELECE: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_tnr; + hf[2] = hf_s7comm_pi_n_x_dnr; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_CREACE: + case S7COMM_PI_N_CREATO: + case S7COMM_PI_N_DELETO: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolnumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_CRTOCE: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolnumber; + hf[2] = hf_s7comm_pi_n_x_cenumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_DELVAR: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_datablocknumber; + hf[2] = hf_s7comm_pi_n_x_firstcolumnnumber; + hf[3] = hf_s7comm_pi_n_x_lastcolumnnumber; + hf[4] = hf_s7comm_pi_n_x_firstrownumber; + hf[5] = hf_s7comm_pi_n_x_lastrownumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 6, hf, paramoffset); + break; + case S7COMM_PI_N_F_COPY: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_direction; + hf[2] = hf_s7comm_pi_n_x_sourcefilename; + hf[3] = hf_s7comm_pi_n_x_destinationfilename; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_F_DMDA: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_channelnumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_F_PROR: + case S7COMM_PI_N_F_PROT: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_filename; + hf[2] = hf_s7comm_pi_n_x_protection; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_F_RENA: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_oldfilename; + hf[2] = hf_s7comm_pi_n_x_newfilename; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_FINDBL: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_findmode; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_IBN_SS: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_switch; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_MMCSEM: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_functionnumber; + hf[2] = hf_s7comm_pi_n_x_semaphorevalue; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_NCKMOD: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_onoff; + hf[2] = hf_s7comm_pi_n_x_mode; + hf[3] = hf_s7comm_pi_n_x_factor; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_NEWPWD: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_password; + hf[2] = hf_s7comm_pi_n_x_passwordlevel; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_SEL_BL: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_linenumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 2, hf, paramoffset); + break; + case S7COMM_PI_N_SETTST: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_magnr; + hf[2] = hf_s7comm_pi_n_x_weargroup; + hf[3] = hf_s7comm_pi_n_x_toolstatus; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_TMAWCO: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_magnr; + hf[2] = hf_s7comm_pi_n_x_weargroup; + hf[3] = hf_s7comm_pi_n_x_wearsearchstrat; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_TMCRTC: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolid; + hf[2] = hf_s7comm_pi_n_x_toolnumber; + hf[3] = hf_s7comm_pi_n_x_duplonumber; + hf[4] = hf_s7comm_pi_n_x_edgenumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 5, hf, paramoffset); + break; + case S7COMM_PI_N_TMCRTO: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolid; + hf[2] = hf_s7comm_pi_n_x_toolnumber; + hf[3] = hf_s7comm_pi_n_x_duplonumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_TMFDPL: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolnumber; + hf[2] = hf_s7comm_pi_n_x_placenr; + hf[3] = hf_s7comm_pi_n_x_magnr; + hf[4] = hf_s7comm_pi_n_x_placerefnr; + hf[5] = hf_s7comm_pi_n_x_magrefnr; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 6, hf, paramoffset); + break; + case S7COMM_PI_N_TMFPBP: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_magnrfrom; + hf[2] = hf_s7comm_pi_n_x_placenrfrom; + hf[3] = hf_s7comm_pi_n_x_magnrto; + hf[4] = hf_s7comm_pi_n_x_placenrto; + hf[5] = hf_s7comm_pi_n_x_magrefnr; + hf[6] = hf_s7comm_pi_n_x_placerefnr; + hf[7] = hf_s7comm_pi_n_x_halfplacesleft; + hf[8] = hf_s7comm_pi_n_x_halfplacesright; + hf[9] = hf_s7comm_pi_n_x_halfplacesup; + hf[10] = hf_s7comm_pi_n_x_halfplacesdown; + hf[11] = hf_s7comm_pi_n_x_placetype; + hf[12] = hf_s7comm_pi_n_x_searchdirection; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 13, hf, paramoffset); + break; + case S7COMM_PI_N_TMGETT: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolname; + hf[2] = hf_s7comm_pi_n_x_duplonumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_TMMVTL: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolnumber; + hf[2] = hf_s7comm_pi_n_x_placenrsource; + hf[3] = hf_s7comm_pi_n_x_magnrsource; + hf[4] = hf_s7comm_pi_n_x_placenrdestination; + hf[5] = hf_s7comm_pi_n_x_magnrdestination; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 6, hf, paramoffset); + break; + case S7COMM_PI_N_TMPCIT: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_spindlenumber; + hf[2] = hf_s7comm_pi_n_x_incrementnumber; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 3, hf, paramoffset); + break; + case S7COMM_PI_N_TMPOSM: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolnumber; + hf[2] = hf_s7comm_pi_n_x_toolid; + hf[3] = hf_s7comm_pi_n_x_duplonumber; + hf[4] = hf_s7comm_pi_n_x_placenrsource; + hf[5] = hf_s7comm_pi_n_x_magnrsource; + hf[6] = hf_s7comm_pi_n_x_placenrdestination; + hf[7] = hf_s7comm_pi_n_x_magnrdestination; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 8, hf, paramoffset); + break; + case S7COMM_PI_N_TRESMO: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_toolnumber; + hf[2] = hf_s7comm_pi_n_x_dnr; + hf[3] = hf_s7comm_pi_n_x_monitoringmode; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 4, hf, paramoffset); + break; + case S7COMM_PI_N_TSEARC: + hf[0] = hf_s7comm_pi_n_x_addressident; + hf[1] = hf_s7comm_pi_n_x_magnrfrom; + hf[2] = hf_s7comm_pi_n_x_placenrfrom; + hf[3] = hf_s7comm_pi_n_x_magnrto; + hf[4] = hf_s7comm_pi_n_x_placenrto; + hf[5] = hf_s7comm_pi_n_x_magrefnr; + hf[6] = hf_s7comm_pi_n_x_placerefnr; + hf[7] = hf_s7comm_pi_n_x_searchdirection; + hf[8] = hf_s7comm_pi_n_x_kindofsearch; + s7comm_decode_pistart_parameters(tvb, pinfo, tree, param_tree, servicename, 9, hf, paramoffset); + break; + default: + /* Don't know how to interpret the parameters, show only the PI servicename */ + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", servicename); + } + return offset; +} + +/******************************************************************************************************* + * + * Decode a blockname/filename used in block/file upload/download + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_plc_controls_filename(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *param_tree, + guint32 offset) +{ + guint8 len; + const guint8 *str; + guint16 blocktype; + gboolean is_plcfilename; + proto_item *item = NULL; + proto_item *itemadd = NULL; + proto_tree *file_tree = NULL; + + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(param_tree, hf_s7comm_data_blockcontrol_filename_len, tvb, offset, 1, len); + offset += 1; + item = proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_filename, tvb, offset, len, ENC_ASCII); + /* The filename when uploading from PLC has a well known structure, which can be further dissected. + * An upload from a NC is a simple filename string with no deeper structure. + * Check for PLC filename, by checking some fixed fields. + */ + is_plcfilename = FALSE; + if (len == 9) { + blocktype = tvb_get_ntohs(tvb, offset + 1); + if ((tvb_get_guint8(tvb, offset) == '_') && (blocktype >= S7COMM_BLOCKTYPE_OB) && (blocktype <= S7COMM_BLOCKTYPE_SFB)) { + gint32 num = 1; + gboolean num_valid; + is_plcfilename = TRUE; + file_tree = proto_item_add_subtree(item, ett_s7comm_plcfilename); + itemadd = proto_tree_add_item(file_tree, hf_s7comm_data_blockcontrol_file_ident, tvb, offset, 1, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(tvb_get_guint8(tvb, offset), blocktype_attribute1_names, "Unknown identifier: %c")); + offset += 1; + itemadd = proto_tree_add_item(file_tree, hf_s7comm_data_blockcontrol_block_type, tvb, offset, 2, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(blocktype, blocktype_names, "Unknown Block type: 0x%04x")); + offset += 2; + proto_tree_add_item_ret_string(file_tree, hf_s7comm_data_blockcontrol_block_num, tvb, offset, 5, ENC_ASCII|ENC_NA, pinfo->pool, &str); + offset += 5; + num_valid = ws_strtoi32((const gchar*)str, NULL, &num); + proto_item_append_text(file_tree, " [%s", + val_to_str(blocktype, blocktype_names, "Unknown Block type: 0x%04x")); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> Block:[%s", + val_to_str(blocktype, blocktype_names, "Unknown Block type: 0x%04x")); + if (num_valid) { + proto_item_append_text(file_tree, "%d]", num); + col_append_fstr(pinfo->cinfo, COL_INFO, "%d]", num); + } else { + expert_add_info(pinfo, file_tree, &ei_s7comm_data_blockcontrol_block_num_invalid); + proto_item_append_text(file_tree, "NaN]"); + col_append_str(pinfo->cinfo, COL_INFO, "NaN]"); + } + itemadd = proto_tree_add_item(file_tree, hf_s7comm_data_blockcontrol_dest_filesys, tvb, offset, 1, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", char_val_to_str(tvb_get_guint8(tvb, offset), blocktype_attribute2_names, "Unknown filesys")); + offset += 1; + } + } + if (is_plcfilename == FALSE) { + str = tvb_get_string_enc(pinfo->pool, tvb, offset, len, ENC_ASCII); + col_append_fstr(pinfo->cinfo, COL_INFO, " File:[%s]", str); + offset += len; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: Request or Response -> Function 0x1d, 0x1e, 0x1f (block control functions) for upload + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_plc_controls_updownload(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + proto_tree *param_tree, + guint16 plength, + guint16 dlength, + guint32 offset, + guint8 rosctr) +{ + guint8 len; + guint8 function; + guint32 errorcode; + const gchar *errorcode_text; + proto_item *item = NULL; + proto_tree *data_tree = NULL; + + function = tvb_get_guint8(tvb, offset); + offset += 1; + errorcode = 0; + + switch (function) { + /*---------------------------------------------------------------------*/ + case S7COMM_FUNCREQUESTDOWNLOAD: + if (rosctr == S7COMM_ROSCTR_JOB) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + /* on upload this is the upload-id, here it is anything else (or not used ) */ + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 4, ENC_NA); + offset += 4; + offset = s7comm_decode_plc_controls_filename(tvb, pinfo, param_tree, offset); + if (plength > 18) { + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(param_tree, hf_s7comm_data_blockcontrol_part2_len, tvb, offset, 1, len); + offset += 1; + /* first byte unknown '1' */ + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_part2_unknown, tvb, offset, 1, ENC_ASCII); + offset += 1; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_loadmem_len, tvb, offset, 6, ENC_ASCII); + offset += 6; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_mc7code_len, tvb, offset, 6, ENC_ASCII); + offset += 6; + } + } else if (rosctr == S7COMM_ROSCTR_ACK_DATA) { + if (plength >= 2) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + } + } + break; + /*---------------------------------------------------------------------*/ + case S7COMM_FUNCSTARTUPLOAD: + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_uploadid, tvb, offset, 4, ENC_NA); + offset += 4; + if (rosctr == S7COMM_ROSCTR_JOB) { + offset = s7comm_decode_plc_controls_filename(tvb, pinfo, param_tree, offset); + } else if (rosctr == S7COMM_ROSCTR_ACK_DATA) { + if (plength > 8) { + /* If uploading from a PLC, the response has a string with the length + * of the complete module in bytes, which maybe transferred/split into many PDUs. + * On a NC file upload, there are no such fields. + */ + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(param_tree, hf_s7comm_data_blockcontrol_upl_lenstring_len, tvb, offset, 1, len); + offset += 1; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_upl_lenstring, tvb, offset, len, ENC_ASCII); + offset += len; + } + } + break; + /*---------------------------------------------------------------------*/ + case S7COMM_FUNCUPLOAD: + case S7COMM_FUNCDOWNLOADBLOCK: + if (rosctr == S7COMM_ROSCTR_JOB) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + if (function == S7COMM_FUNCUPLOAD) { + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_uploadid, tvb, offset, 4, ENC_NA); + offset += 4; + } else { + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 4, ENC_NA); + offset += 4; + offset = s7comm_decode_plc_controls_filename(tvb, pinfo, param_tree, offset); + } + } else if (rosctr == S7COMM_ROSCTR_ACK_DATA) { + if (plength >= 2) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + } + if (dlength > 0) { + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + proto_tree_add_item(data_tree, hf_s7comm_data_length, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_readresponse_data, tvb, offset, dlength - 4, ENC_NA); + offset += dlength - 4; + } + } + break; + /*---------------------------------------------------------------------*/ + case S7COMM_FUNCENDUPLOAD: + case S7COMM_FUNCDOWNLOADENDED: + if (rosctr == S7COMM_ROSCTR_JOB) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + item = proto_tree_add_item_ret_uint(param_tree, hf_s7comm_data_blockcontrol_errorcode, tvb, offset, 2, ENC_BIG_ENDIAN, &errorcode); + /* here it uses the same errorcode from parameter part */ + if ((errorcode_text = try_val_to_str_ext(errorcode, ¶m_errcode_names_ext))) { + proto_item_append_text(item, " (%s)", errorcode_text); + } + offset += 2; + if (function == S7COMM_FUNCENDUPLOAD) { + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_uploadid, tvb, offset, 4, ENC_NA); + offset += 4; + } else { + proto_tree_add_item(param_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 4, ENC_NA); + offset += 4; + offset = s7comm_decode_plc_controls_filename(tvb, pinfo, param_tree, offset); + } + } else if (rosctr == S7COMM_ROSCTR_ACK_DATA) { + if (plength >= 2) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + } + } + break; + } + /* if an error occurred show in info column */ + if (errorcode > 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, " -> Errorcode:[0x%04x]", errorcode); + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Block status (0x13 or 0x01) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_blockstat(tvbuff_t *tvb, + proto_tree *td_tree, + guint16 td_size, + guint8 type, + guint8 subfunc, + guint32 offset) +{ + proto_item *item = NULL; + proto_tree *item_tree = NULL; + guint16 line_nr; + guint16 line_cnt; + guint16 item_size = 4; + guint8 registerflags; + gchar str_flags[80]; + + if (type == S7COMM_UD_TYPE_REQ) { + if (subfunc == S7COMM_UD_SUBF_TIS_BLOCKSTAT2) { + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_flagsunknown, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + line_cnt = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_tis_blockstat_number_of_lines, tvb, offset, 1, line_cnt); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + } else { + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + line_cnt = (td_size - 2) / 2; + } + proto_tree_add_bitmask(td_tree, tvb, offset, hf_s7comm_diagdata_registerflag, + ett_s7comm_diagdata_registerflag, s7comm_diagdata_registerflag_fields, ENC_BIG_ENDIAN); + offset += 1; + + if (subfunc == S7COMM_UD_SUBF_TIS_BLOCKSTAT2) { + item_size = 4; + } else { + item_size = 2; + } + for (line_nr = 0; line_nr < line_cnt; line_nr++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, item_size, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + if (subfunc == S7COMM_UD_SUBF_TIS_BLOCKSTAT2) { + proto_tree_add_item(item_tree, hf_s7comm_tis_blockstat_line_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + proto_tree_add_item(item_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + registerflags = tvb_get_guint8(tvb, offset); + make_registerflag_string(str_flags, registerflags, sizeof(str_flags)); + proto_item_append_text(item, " [%d]: (%s)", line_nr+1, str_flags); + proto_tree_add_bitmask(item_tree, tvb, offset, hf_s7comm_diagdata_registerflag, + ett_s7comm_diagdata_registerflag, s7comm_diagdata_registerflag_fields, ENC_BIG_ENDIAN); + offset += 1; + } + } else if (type == S7COMM_UD_TYPE_IND) { + /* The response data can only be dissected when the requested registers for each line + * from the job setup is known. As the STW is only 16 Bits and all other registers 32 Bits, + * this has no fixed structure. + * The only thing that can be shown is the start address. Next the requested registers, + * the start address of next line with the requested registers and so on. + */ + proto_tree_add_item(td_tree, hf_s7comm_diagdata_req_startaddr_awl, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_data, tvb, offset, td_size - 2, ENC_NA); + offset += (td_size - 2); + } else { + /* TODO: Show unknown data as raw bytes */ + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, td_size, ENC_NA); + offset += td_size; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Item address + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_item_address(tvbuff_t *tvb, + guint32 offset, + proto_tree *sub_tree, + guint16 item_no, + gchar *add_text) +{ + guint32 bytepos = 0; + guint16 len = 0; + guint16 bitpos = 0; + guint16 db = 0; + guint8 area = 0; + proto_item *item = NULL; + + /* Insert a new tree with 6 bytes for every item */ + item = proto_tree_add_item(sub_tree, hf_s7comm_param_item, tvb, offset, 6, ENC_NA); + + sub_tree = proto_item_add_subtree(item, ett_s7comm_param_item); + + proto_item_append_text(item, " [%d]%s:", item_no + 1, add_text); + + /* Area, 1 byte */ + area = tvb_get_guint8(tvb, offset); + proto_tree_add_item(sub_tree, hf_s7comm_varstat_req_memory_area, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Length (repetition factor), 1 byte. If area is a bit address, then this is the bit number. + * The area is a bit address when the low nibble is zero. + */ + if (area & 0x0f) { + len = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(sub_tree, hf_s7comm_varstat_req_repetition_factor, tvb, offset, 1, len); + offset += 1; + } else { + bitpos = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(sub_tree, hf_s7comm_varstat_req_bitpos, tvb, offset, 1, bitpos); + offset += 1; + } + + /* DB number, 2 bytes */ + db = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(sub_tree, hf_s7comm_varstat_req_db_number, tvb, offset, 2, db); + offset += 2; + + /* byte offset, 2 bytes */ + bytepos = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(sub_tree, hf_s7comm_varstat_req_startaddress, tvb, offset, 2, bytepos); + offset += 2; + + /* build a full address to show item data directly beside the item */ + switch (area) { + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MX: + proto_item_append_text(sub_tree, " (M%d.%d)", bytepos, bitpos); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MB: + proto_item_append_text(sub_tree, " (M%d.0 BYTE %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MW: + proto_item_append_text(sub_tree, " (M%d.0 WORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_MD: + proto_item_append_text(sub_tree, " (M%d.0 DWORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EX: + proto_item_append_text(sub_tree, " (I%d.%d)", bytepos, bitpos); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EB: + proto_item_append_text(sub_tree, " (I%d.0 BYTE %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_EW: + proto_item_append_text(sub_tree, " (I%d.0 WORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_ED: + proto_item_append_text(sub_tree, " (I%d.0 DWORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AX: + proto_item_append_text(sub_tree, " (Q%d.%d)", bytepos, bitpos); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AB: + proto_item_append_text(sub_tree, " (Q%d.0 BYTE %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AW: + proto_item_append_text(sub_tree, " (Q%d.0 WORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_AD: + proto_item_append_text(sub_tree, " (Q%d.0 DWORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PEB: + proto_item_append_text(sub_tree, " (PI%d.0 BYTE %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PEW: + proto_item_append_text(sub_tree, " (PI%d.0 WORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_PED: + proto_item_append_text(sub_tree, " (PI%d.0 DWORD %d)", bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBX: + proto_item_append_text(sub_tree, " (DB%d.DBX%d.%d)", db, bytepos, bitpos); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBB: + proto_item_append_text(sub_tree, " (DB%d.DBX%d.0 BYTE %d)", db, bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBW: + proto_item_append_text(sub_tree, " (DB%d.DBX%d.0 WORD %d)", db, bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_DBD: + proto_item_append_text(sub_tree, " (DB%d.DBX%d.0 DWORD %d)", db, bytepos, len); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_T: + /* it's possible to read multiple timers */ + if (len >1) + proto_item_append_text(sub_tree, " (T %d..%d)", bytepos, bytepos + len - 1); + else + proto_item_append_text(sub_tree, " (T %d)", bytepos); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT_AREA_C: + /* it's possible to read multiple counters */ + if (len >1) + proto_item_append_text(sub_tree, " (C %d..%d)", bytepos, bytepos + len - 1); + else + proto_item_append_text(sub_tree, " (C %d)", bytepos); + break; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Item value + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_item_value(tvbuff_t *tvb, + guint32 offset, + proto_tree *sub_tree, + guint16 item_no, + gchar *add_text) +{ + guint16 len = 0, len2 = 0; + guint8 ret_val = 0; + guint8 tsize = 0; + guint8 head_len = 4; + + proto_item *item = NULL; + + ret_val = tvb_get_guint8(tvb, offset); + if (ret_val == S7COMM_ITEM_RETVAL_RESERVED || + ret_val == S7COMM_ITEM_RETVAL_DATA_OK || + ret_val == S7COMM_ITEM_RETVAL_DATA_ERR + ) { + tsize = tvb_get_guint8(tvb, offset + 1); + len = tvb_get_ntohs(tvb, offset + 2); + + if (tsize == S7COMM_DATA_TRANSPORT_SIZE_BBYTE || tsize == S7COMM_DATA_TRANSPORT_SIZE_BINT) { + len /= 8; + } + /* the PLC places extra bytes at the end if length is not a multiple of 2 */ + if (len % 2) { + len2 = len + 1; + } else { + len2 = len; + } + } + /* Insert a new tree for every item */ + item = proto_tree_add_item(sub_tree, hf_s7comm_data_item, tvb, offset, len + head_len, ENC_NA); + sub_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + + proto_item_append_text(item, " [%d]%s: (%s)", item_no + 1, add_text, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + + proto_tree_add_uint(sub_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + proto_tree_add_uint(sub_tree, hf_s7comm_data_transport_size, tvb, offset + 1, 1, tsize); + proto_tree_add_uint(sub_tree, hf_s7comm_data_length, tvb, offset + 2, 2, len); + + offset += head_len; + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK || ret_val == S7COMM_ITEM_RETVAL_RESERVED) { + proto_tree_add_item(sub_tree, hf_s7comm_readresponse_data, tvb, offset, len, ENC_NA); + offset += len; + if (len != len2) { + proto_tree_add_item(sub_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Force (0x09) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_force(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + guint16 item_count; + guint16 i; + guint8 ret_val = 0; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + + switch (type) { + case S7COMM_UD_TYPE_REQ: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_address(tvb, offset, td_tree, i, " Address to force"); + } + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_value(tvb, offset, td_tree, i, " Value to force"); + } + break; + case S7COMM_UD_TYPE_IND: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 1, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + ret_val = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + proto_item_append_text(item, " [%d]: (%s)", i + 1, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + offset += 1; + } + if (item_count % 2) { + proto_tree_add_item(item_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + break; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands / Test and installation functions + * Dissects the parameter part + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_param(tvbuff_t *tvb, + proto_tree *tree, + guint8 type, + guint16 tp_size, + guint32 offset) +{ + guint32 start_offset; + guint32 callenv_setup = 0; + proto_item *item = NULL; + proto_tree *tp_tree = NULL; + + start_offset = offset; + if (tp_size > 0) { + item = proto_tree_add_item(tree, hf_s7comm_tis_parameter, tvb, offset, tp_size, ENC_NA); + tp_tree = proto_item_add_subtree(item, ett_s7comm_prog_parameter); + if (type == S7COMM_UD_TYPE_REQ) { + if (tp_size >= 4) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_param1, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param2, tvb, offset, 2, ENC_NA); + offset += 2; + } + if (tp_size >= 20) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_param3, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_answersize, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param5, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param6, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param7, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param8, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param9, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_trgevent, tvb, offset, 2, ENC_NA); + offset += 2; + } + if (tp_size >= 26) { + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_block_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_block_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_startaddr_awl, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + if (tp_size >= 28) { + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_saz, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + if (tp_size >= 36) { + proto_tree_add_item_ret_uint(tp_tree, hf_s7comm_tis_p_callenv, tvb, offset, 2, ENC_BIG_ENDIAN, &callenv_setup); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + if (callenv_setup == 2) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + } else { + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + if (tp_size >= 38) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond_address, tvb, offset, 2, ENC_BIG_ENDIAN); + } + } + } + } else { + proto_tree_add_item(tp_tree, hf_s7comm_tis_res_param1, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_res_param2, tvb, offset, 2, ENC_NA); + } + } + /* May be we don't know all values when here, so set offset to the given length */ + return start_offset + tp_size; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Disable job (0x0d), Enable job (0x0e), + * Delete job (0x0f), Read job list (0x10), + * Read job (0x11) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_jobs(tvbuff_t *tvb, + proto_tree *td_tree, + guint16 td_size, + guint8 type, + guint8 subfunc, + guint32 offset) +{ + guint16 i; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + guint16 job_tp_size; + guint16 job_td_size; + proto_tree *job_td_tree = NULL; + guint8 job_subfunc; + + if (type == S7COMM_UD_TYPE_REQ) { + switch (subfunc) { + case S7COMM_UD_SUBF_TIS_DELETEJOB: + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + /* fallthrough */ + case S7COMM_UD_SUBF_TIS_ENABLEJOB: + case S7COMM_UD_SUBF_TIS_DISABLEJOB: + case S7COMM_UD_SUBF_TIS_READJOB: + proto_tree_add_item(td_tree, hf_s7comm_tis_job_function, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_job_seqnr, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case S7COMM_UD_SUBF_TIS_READJOBLIST: + /* 4 bytes, possible as filter? */ + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_SUBF_TIS_REPLACEJOB: + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + /* The job which has to be replaced */ + job_subfunc = tvb_get_guint8(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_job_function, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_job_seqnr, tvb, offset, 1, ENC_NA); + offset += 1; + job_tp_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_parametersize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + job_td_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_datasize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* New job parameter tree */ + if (job_tp_size > 0) { + offset = s7comm_decode_ud_tis_param(tvb, td_tree, S7COMM_UD_TYPE_REQ, job_tp_size, offset); + } + /* New job data tree */ + if (job_td_size > 0) { + offset = s7comm_decode_ud_tis_data(tvb, td_tree, S7COMM_UD_TYPE_REQ, job_subfunc, job_td_size, offset); + } + break; + } + } else { + switch (subfunc) { + case S7COMM_UD_SUBF_TIS_READJOBLIST: + /* 4 bytes each job: + * - 2 bytes job id + * - 2 bytes status: 1=active, 0=idle/pending? + */ + for (i = 0; i < td_size / 4; i++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 4, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_item_append_text(item, " [%d] Job", i + 1); + + proto_tree_add_item(item_tree, hf_s7comm_tis_job_function, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_job_seqnr, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + } + break; + case S7COMM_UD_SUBF_TIS_READJOB: + /* This includes the same data as in the job request. With the disadvantage that is does + * not contain information of the function, so the data can't be further dissected. + * We need to know the function from the request. + */ + job_tp_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_parametersize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + job_td_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_datasize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* Job parameter tree */ + if (job_tp_size > 0) { + offset = s7comm_decode_ud_tis_param(tvb, td_tree, S7COMM_UD_TYPE_REQ, job_tp_size, offset); + } + /* Job data tree */ + if (job_td_size > 0) { + item = proto_tree_add_item(td_tree, hf_s7comm_tis_data, tvb, offset, job_td_size, ENC_NA); + job_td_tree = proto_item_add_subtree(item, ett_s7comm_prog_data); + proto_tree_add_item(job_td_tree, hf_s7comm_tis_job_reserved, tvb, offset, job_td_size, ENC_NA); + offset += job_td_size; + } + break; + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Variable status (0x03) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_varstat(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + guint16 item_count; + guint16 i; + + switch (type) { + case S7COMM_UD_TYPE_REQ: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_address(tvb, offset, td_tree, i, " Address to read"); + } + break; + case S7COMM_UD_TYPE_IND: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_value(tvb, offset, td_tree, i, " Read data"); + } + break; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Modify variable (0x08) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_modvar(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + guint16 item_count; + guint16 i; + guint8 ret_val = 0; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + + switch (type) { + case S7COMM_UD_TYPE_REQ: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_address(tvb, offset, td_tree, i, " Address to write"); + } + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_value(tvb, offset, td_tree, i, " Data to write"); + } + break; + case S7COMM_UD_TYPE_IND: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 1, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + ret_val = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + proto_item_append_text(item, " [%d]: (%s)", i + 1, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + offset += 1; + } + if (item_count % 2) { + proto_tree_add_item(item_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + break; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Output ISTACK (0x03) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_istack(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + guint8 ob_number = 0; + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_TYPE_RES: + case S7COMM_UD_TYPE_IND: + proto_tree_add_item(td_tree, hf_s7comm_tis_continued_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_continued_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_continued_address, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu3, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu4, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_stw, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + /* read the OB number first */ + ob_number = tvb_get_guint8(tvb, offset + 3); + switch (ob_number) { + case 1: /* Cyclic execution */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_scan_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_prev_cycle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_min_cycle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_max_cycle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 10: /* Time of day interrupt 0..7 */ + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_period_exe, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 20: /* Time delay interrupt 0..3 */ + case 21: + case 22: + case 23: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_scan_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_sign, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_dtime, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 30: /* Cyclic interrupt 0..8 */ + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_phase_offset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_exec_freq, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 40: /* Hardware interrupt 0..8 */ + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_point_addr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 55: /* DP Statusalarm */ + case 56: /* DP Updatealarm */ + case 57: /* DP Specific alarm */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_inf_len, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_alarm_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_alarm_slot, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_alarm_spec, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 80: /* Cycle time fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_error_info, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_num, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_num, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 81: /* Power supply fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_rack_cpu, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 82: /* I/O Point fault 1 */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_8x_fault_flags, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_type_b, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_8x_fault_flags, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_8x_fault_flags, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 83: /* I/O Point fault 2 */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_rack_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_type_w, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 84: /* CPU fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4_dw, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 85: /* OB not loaded fault */ + case 87: /* Communication Fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_num, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_num, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 86: /* Loss of rack fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_racks_flt, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 90: /* Background cycle */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4_dw, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 100: /* Complete restart */ + case 101: /* Restart */ + case 102: /* Cold restart */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strtup, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_stop, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_info, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 121: /* Programming Error */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_sw_flt, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_blk_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_reg, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_blk_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_prg_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 122: /* Module Access Error */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_sw_flt, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_blk_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mem_area, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mem_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_blk_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_prg_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + default: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + } + offset = s7comm_add_timestamp_to_tree(tvb, td_tree, offset, FALSE, FALSE); + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Output BSTACK (0x04) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_bstack(tvbuff_t *tvb, + proto_tree *td_tree, + guint16 td_size, + guint8 type, + guint32 offset) +{ + guint16 i; + guint16 blocktype; + guint16 blocknumber; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + int rem; + guint32 replen; + + /* Possible firmware bug in IM151-8 CPU, where also the date size information + * in the header is 4 bytes too short. + */ + replen = tvb_reported_length_remaining(tvb, offset); + if (replen < td_size) { + /* TODO: Show this mismatch? We fix the length here. */ + td_size = replen; + } + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_TYPE_RES: + case S7COMM_UD_TYPE_IND: + rem = td_size; + i = 1; + while (rem > 16) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 16, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + blocktype = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + blocknumber = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db1_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db2_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + proto_item_append_text(item, " [%d] BSTACK entry for: %s %d", i++, + val_to_str(blocktype, subblktype_names, "Unknown Subblk type: 0x%02x"), blocknumber); + rem -= 16; + if (blocktype == S7COMM_SUBBLKTYPE_OB) { + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_prioclass, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + rem -= 4; + if (rem >= 8) { + offset = s7comm_add_timestamp_to_tree(tvb, item_tree, offset, FALSE, FALSE); + rem -= 8; + } else { + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, rem, ENC_NA); + offset += rem; + break; + } + } + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Output LSTACK (0x05) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_lstack(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + guint16 len; + + if (type == S7COMM_UD_TYPE_REQ) { + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_prioclass, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_bstack_nest_depth, tvb, offset, 1, ENC_NA); + offset += 1; + } else { + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_NA); + offset += 2; + len = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_size, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_data, tvb, offset, len, ENC_NA); + offset += len; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_prioclass, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + offset = s7comm_add_timestamp_to_tree(tvb, td_tree, offset, FALSE, FALSE); + } + return offset; +} +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Exit Hold (0x0b) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_exithold(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + /* Only request with data payload was seen */ + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_exithold_until, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_exithold_res1, tvb, offset, 1, ENC_NA); + offset += 1; + break; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Breakpoint (0x0a) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_breakpoint(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_TYPE_RES: + case S7COMM_UD_TYPE_IND: + /* Info: Both blocknumbers and addresses are the same on online-blockview inside a block. + * On return out of a block, the first address contains the current breakpoint, the second + * address the address from where it was returned (previous block). + */ + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_address, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_stw, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands / Test and installation functions + * Dissects the data part + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_data(tvbuff_t *tvb, + proto_tree *tree, + guint8 type, + guint8 subfunc, + guint16 td_size, + guint32 offset) +{ + proto_item *item = NULL; + proto_tree *td_tree = NULL; + + if (td_size > 0) { + item = proto_tree_add_item(tree, hf_s7comm_tis_data, tvb, offset, td_size, ENC_NA); + td_tree = proto_item_add_subtree(item, ett_s7comm_prog_data); + switch (subfunc) { + case S7COMM_UD_SUBF_TIS_OUTISTACK: + offset = s7comm_decode_ud_tis_istack(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_TIS_OUTBSTACK: + offset = s7comm_decode_ud_tis_bstack(tvb, td_tree, td_size, type, offset); + break; + case S7COMM_UD_SUBF_TIS_OUTLSTACK: + offset = s7comm_decode_ud_tis_lstack(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_TIS_BREAKPOINT: + offset = s7comm_decode_ud_tis_breakpoint(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_TIS_EXITHOLD: + offset = s7comm_decode_ud_tis_exithold(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_TIS_BLOCKSTAT: + case S7COMM_UD_SUBF_TIS_BLOCKSTAT2: + offset = s7comm_decode_ud_tis_blockstat(tvb, td_tree, td_size, type, subfunc, offset); + break; + case S7COMM_UD_SUBF_TIS_VARSTAT: + offset = s7comm_decode_ud_tis_varstat(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_TIS_DISABLEJOB: + case S7COMM_UD_SUBF_TIS_ENABLEJOB: + case S7COMM_UD_SUBF_TIS_DELETEJOB: + case S7COMM_UD_SUBF_TIS_READJOBLIST: + case S7COMM_UD_SUBF_TIS_READJOB: + case S7COMM_UD_SUBF_TIS_REPLACEJOB: + offset = s7comm_decode_ud_tis_jobs(tvb, td_tree, td_size, type, subfunc, offset); + break; + case S7COMM_UD_SUBF_TIS_MODVAR: + offset = s7comm_decode_ud_tis_modvar(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_TIS_FORCE: + offset = s7comm_decode_ud_tis_force(tvb, td_tree, type, offset); + break; + default: + proto_tree_add_item(td_tree, hf_s7comm_varstat_unknown, tvb, offset, td_size, ENC_NA); + offset += td_size; + break; + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands / Test and installation functions + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint32 offset) +{ + guint16 tp_size = 0; + guint16 td_size = 0; + + tp_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_tis_parametersize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + td_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_tis_datasize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* Parameter tree */ + offset = s7comm_decode_ud_tis_param(tvb, data_tree, type, tp_size, offset); + /* Data tree */ + offset = s7comm_decode_ud_tis_data(tvb, data_tree, type, subfunc, td_size, offset); + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 5 -> Security functions? + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_security_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint32 dlength, + guint32 offset) +{ + /* Display dataset as raw bytes. Maybe this part can be extended with further knowledge. */ + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV), before reassembly + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_pbc_bsend_pre_reass(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, + guint16 *dlength, + guint32 *r_id, /* R_ID of the PBC communication */ + guint32 offset) +{ + if ((type == S7COMM_UD_TYPE_REQ || type == S7COMM_UD_TYPE_RES) && (*dlength >= 8)) { + proto_tree_add_item(data_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* 0x00 when passive partners is sending, 0xcc when active partner is sending? */ + proto_tree_add_item(data_tree, hf_s7comm_pbc_unknown, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_pbc_bsend_r_id, tvb, offset, 4, ENC_BIG_ENDIAN); + *r_id = tvb_get_ntohl(tvb, offset); + col_append_fstr(pinfo->cinfo, COL_INFO, " R_ID=0x%X", *r_id); + offset += 4; + *dlength -= 8; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_pbc_bsend_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint32 dlength, + guint32 offset, + packet_info *pinfo, + proto_tree *tree) +{ + proto_tree_add_item(data_tree, hf_s7comm_pbc_bsend_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 2, ENC_NA); + + /* dissect data */ + if (tvb_reported_length_remaining(tvb, offset) > 0) { + struct tvbuff *next_tvb = tvb_new_subset_remaining(tvb, offset); + heur_dtbl_entry_t *hdtbl_entry; + if (!dissector_try_heuristic(s7comm_heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { + call_data_dissector(next_tvb, pinfo, data_tree); + } + } + + offset += (dlength - 2); + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> PBC, Programmable Block Function USEND + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_usend(tvbuff_t *tvb, + proto_tree *tree, + guint32 dlength, + guint32 offset) +{ + proto_item *item = NULL; + proto_tree *data_tree = NULL; + proto_tree *item_tree = NULL; + guint8 tsize; + guint16 len; + guint16 len2; + guint8 ret_val; + guint8 item_count; + guint8 i; + + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + + ret_val = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(data_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + offset += 1; + + proto_tree_add_item(data_tree, hf_s7comm_pbc_usend_unknown1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + item_count = tvb_get_guint8(tvb, offset + 1); /* max. 4 possible */ + proto_tree_add_uint(data_tree, hf_s7comm_param_itemcount, tvb, offset, 2, item_count); + offset += 2; + + for (i = 0; i < item_count; i++) { + tsize = tvb_get_guint8(tvb, offset + 1); + len = tvb_get_ntohs(tvb, offset + 2); + /* calculate length in bytes */ + if (tsize == S7COMM_DATA_TRANSPORT_SIZE_BBIT || + tsize == S7COMM_DATA_TRANSPORT_SIZE_BBYTE || + tsize == S7COMM_DATA_TRANSPORT_SIZE_BINT + ) { + if (len % 8) { + len /= 8; + len = len + 1; + } else { + len /= 8; + } + } + + if ((len % 2) && (i < (item_count-1))) { + len2 = len + 1; + } else { + len2 = len; + } + + item = proto_tree_add_item(data_tree, hf_s7comm_data_item, tvb, offset, len + 4, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_item_append_text(item, " [%d]", i+1); + proto_tree_add_item(item_tree, hf_s7comm_pbc_usend_unknown2, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_uint(item_tree, hf_s7comm_data_transport_size, tvb, offset + 1, 1, tsize); + proto_tree_add_uint(item_tree, hf_s7comm_data_length, tvb, offset + 2, 2, len); + offset += 4; + + proto_tree_add_item(item_tree, hf_s7comm_readresponse_data, tvb, offset, len, ENC_NA); + offset += len; + if (len != len2) { + proto_tree_add_item(item_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> NC programming functions (file download/upload), before reassembly + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_ncprg_pre_reass(tvbuff_t *tvb, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint16 *dlength, + guint32 offset) +{ + if ((type == S7COMM_UD_TYPE_RES || type == S7COMM_UD_TYPE_IND) && + (subfunc == S7COMM_NCPRG_FUNCDOWNLOADBLOCK || + subfunc == S7COMM_NCPRG_FUNCUPLOAD || + subfunc == S7COMM_NCPRG_FUNCSTARTUPLOAD)) { + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + *dlength -= 2; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> NC programming functions (file download/upload) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_ncprg_subfunc(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint32 dlength, + guint32 offset) +{ + const guint8 *str_filename; + guint32 string_end_offset; + guint32 string_len; + guint32 filelength; + guint32 start_offset; + + if (dlength >= 2) { + if (type == S7COMM_UD_TYPE_REQ && subfunc == S7COMM_NCPRG_FUNCREQUESTDOWNLOAD) { + proto_tree_add_item_ret_string(data_tree, hf_s7comm_data_blockcontrol_filename, tvb, offset, dlength, + ENC_ASCII|ENC_NA, pinfo->pool, &str_filename); + col_append_fstr(pinfo->cinfo, COL_INFO, " File:[%s]", str_filename); + offset += dlength; + } else if (type == S7COMM_UD_TYPE_REQ && subfunc == S7COMM_NCPRG_FUNCSTARTUPLOAD) { + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_unackcount, tvb, offset, 1, ENC_NA); + offset += 1; + dlength -= 1; + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 1, ENC_NA); + offset += 1; + dlength -= 1; + proto_tree_add_item_ret_string(data_tree, hf_s7comm_data_blockcontrol_filename, tvb, offset, dlength, + ENC_ASCII|ENC_NA, pinfo->pool, &str_filename); + col_append_fstr(pinfo->cinfo, COL_INFO, " File:[%s]", str_filename); + offset += dlength; + } else if (type == S7COMM_UD_TYPE_RES && subfunc == S7COMM_NCPRG_FUNCREQUESTDOWNLOAD) { + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_unackcount, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 1, ENC_NA); + offset += 1; + } else if (type == S7COMM_UD_TYPE_IND && (subfunc == S7COMM_NCPRG_FUNCCONTUPLOAD || subfunc == S7COMM_NCPRG_FUNCCONTDOWNLOAD)) { + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_unackcount, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 1, ENC_NA); + offset += 1; + } else if ((type == S7COMM_UD_TYPE_RES || type == S7COMM_UD_TYPE_IND) && + (subfunc == S7COMM_NCPRG_FUNCDOWNLOADBLOCK || + subfunc == S7COMM_NCPRG_FUNCUPLOAD || + subfunc == S7COMM_NCPRG_FUNCSTARTUPLOAD)) { + start_offset = offset; + /* file length may be contain only spaces when downloading a directory */ + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_filelength, tvb, offset, 8, ENC_ASCII); + offset += 8; + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_filetime, tvb, offset, 16, ENC_ASCII); + offset += 16; + /* File path and file data aren't always there */ + if (dlength > 24) { + if (subfunc == S7COMM_NCPRG_FUNCDOWNLOADBLOCK || subfunc == S7COMM_NCPRG_FUNCSTARTUPLOAD || subfunc == S7COMM_NCPRG_FUNCUPLOAD) { + string_end_offset = tvb_find_guint8(tvb, offset, dlength-8-16, 0x0a); + if (string_end_offset > 0) { + string_len = string_end_offset - offset + 1; /* include 0x0a */ + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_filepath, tvb, offset, string_len, ENC_ASCII); + offset += string_len; + filelength = dlength - (offset - start_offset); + proto_tree_add_item(data_tree, hf_s7comm_data_ncprg_filedata, tvb, offset, filelength, ENC_NA); + offset += filelength; + } + } + } + } else { + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + dlength -= 2; + if (dlength >= 4) { + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Data record routing to Profibus + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_drr_subfunc(tvbuff_t *tvb, + proto_tree *tree, + guint32 dlength, + guint32 offset) +{ + /* As a start add only a data block. At least there are min. 6 bytes of a header. + * At some point of the data, parts of the Profinet dissector may be reusable, + * as there's an overlap between the Profibus and Profinet Specification. + */ + if (dlength > 0) { + proto_tree_add_item(tree, hf_s7comm_data_drr_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Message services -> AR_SEND parameters on initiate/abort + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_message_service_ar_send_args(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + guint8 type, + guint32 offset) +{ + guint8 item_count; + guint8 i; + guint32 ar_id; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + + item_count = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_s7comm_param_itemcount, tvb, offset, 1, item_count); + offset += 1; + + for (i = 0; i < item_count; i++) { + if (type == S7COMM_UD_TYPE_REQ) { + item = proto_tree_add_item(tree, hf_s7comm_data_item, tvb, offset, 8, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_tree_add_item(item_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_pbc_arsend_unknown, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item_ret_uint(item_tree, hf_s7comm_pbc_arsend_ar_id, tvb, offset, 4, ENC_BIG_ENDIAN, &ar_id); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s0x%X", (i == 0) ? " AR_ID=" : ",", ar_id); + proto_item_append_text(item, " [%d]: AR_ID=0x%X", i+1, ar_id); + offset += 4; + } else if (type == S7COMM_UD_TYPE_RES) { + item = proto_tree_add_item(tree, hf_s7comm_data_item, tvb, offset, 1, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_item_append_text(item, " [%d]", i+1); + /* Kind of return code. But from what was captured, it doesn't matter if the AR_ID of the request is not available */ + proto_tree_add_item(item_tree, hf_s7comm_pbc_arsend_ret, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + /* Fill byte on response if number of items is uneven */ + if (type == S7COMM_UD_TYPE_RES && (item_count % 2)) { + proto_tree_add_item(tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Message services + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_message_service(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, + guint32 dlength, + guint32 offset) +{ + guint8 events; + guint8 almtype; + gchar events_string[42]; + + switch (type) { + case S7COMM_UD_TYPE_REQ: + events = tvb_get_guint8(tvb, offset); + proto_tree_add_bitmask(data_tree, tvb, offset, hf_s7comm_cpu_msgservice_subscribe_events, + ett_s7comm_cpu_msgservice_subscribe_events, s7comm_cpu_msgservice_subscribe_events_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_req_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + (void) g_strlcpy(events_string, "", sizeof(events_string)); + if (events & 0x01) (void) g_strlcat(events_string, "MODE,", sizeof(events_string)); /* Change in mode-transition: Stop, Run, by Push and Function-group=0, Subfunction: 0=Stop, 1=Warm Restart, 2=RUN */ + if (events & 0x02) (void) g_strlcat(events_string, "SYS,", sizeof(events_string)); /* System diagnostics */ + if (events & 0x04) (void) g_strlcat(events_string, "USR,", sizeof(events_string)); /* User-defined diagnostic messages */ + if (events & 0x08) (void) g_strlcat(events_string, "-4-,", sizeof(events_string)); /* currently unknown flag */ + if (events & 0x10) (void) g_strlcat(events_string, "-5-,", sizeof(events_string)); /* currently unknown flag */ + if (events & 0x20) (void) g_strlcat(events_string, "-6-,", sizeof(events_string)); /* currently unknown flag */ + if (events & 0x40) (void) g_strlcat(events_string, "-7-,", sizeof(events_string)); /* currently unknown flag */ + if (events & 0x80) (void) g_strlcat(events_string, "ALM,", sizeof(events_string)); /* Program block message, type of message in additional field */ + if (strlen(events_string) > 2) + events_string[strlen(events_string) - 1 ] = '\0'; + col_append_fstr(pinfo->cinfo, COL_INFO, " SubscribedEvents=(%s)", events_string); + + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_username, tvb, offset, 8, ENC_ASCII); + offset += 8; + if ((events & 0x80) && (dlength > 10)) { + almtype = tvb_get_guint8(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_almtype, tvb, offset, 1, ENC_BIG_ENDIAN); + col_append_fstr(pinfo->cinfo, COL_INFO, " AlmType=%s", val_to_str(almtype, cpu_msgservice_almtype_names, "Unknown type: 0x%02x")); + offset += 1; + if (almtype == S7COMM_CPU_MSG_ALMTYPE_AR_SEND_INITIATE || almtype == S7COMM_CPU_MSG_ALMTYPE_AR_SEND_ABORT) { + offset = s7comm_decode_message_service_ar_send_args(tvb, pinfo, data_tree, type, offset); + } else { + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_req_reserved2, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + break; + case S7COMM_UD_TYPE_RES: + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_res_result, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_res_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + if (dlength > 2) { + almtype = tvb_get_guint8(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_almtype, tvb, offset, 1, ENC_BIG_ENDIAN); + col_append_fstr(pinfo->cinfo, COL_INFO, " AlmType=%s", val_to_str(almtype, cpu_msgservice_almtype_names, "Unknown type: 0x%02x")); + offset += 1; + if (almtype == S7COMM_CPU_MSG_ALMTYPE_AR_SEND_INITIATE || almtype == S7COMM_CPU_MSG_ALMTYPE_AR_SEND_ABORT) { + offset = s7comm_decode_message_service_ar_send_args(tvb, pinfo, data_tree, type, offset); + } else { + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_res_reserved2, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_cpu_msgservice_res_reserved3, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + break; + } + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> AR_SEND, before reassembly + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_cpu_ar_send_pre_reass(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint16 *dlength, + guint32 offset) +{ + guint32 ar_id; + + if (*dlength >= 8) { + proto_tree_add_item(data_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_pbc_arsend_unknown, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item_ret_uint(data_tree, hf_s7comm_pbc_arsend_ar_id, tvb, offset, 4, ENC_BIG_ENDIAN, &ar_id); + col_append_fstr(pinfo->cinfo, COL_INFO, " AR_ID=0x%X", ar_id); + offset += 4; + + *dlength -= 8; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> AR_SEND + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_cpu_ar_send(tvbuff_t *tvb, + proto_tree *data_tree, + guint32 offset) +{ + guint32 len; + + /* Only the first fragment contains the length. As we get the length after reassembly, it's ok. */ + proto_tree_add_item_ret_uint(data_tree, hf_s7comm_pbc_arsend_len, tvb, offset, 2, ENC_LITTLE_ENDIAN, &len); + offset += 2; + + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, len, ENC_NA); + offset += len; + + return offset; +} +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 4 -> alarm, main tree for all except query response + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_cpu_alarm_main(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint32 offset) +{ + guint32 start_offset; + guint32 asc_start_offset; + guint32 msg_obj_start_offset; + guint32 ev_id; + proto_item *msg_item = NULL; + proto_tree *msg_item_tree = NULL; + proto_item *msg_obj_item = NULL; + proto_tree *msg_obj_item_tree = NULL; + proto_item *msg_work_item = NULL; + proto_tree *msg_work_item_tree = NULL; + guint8 nr_objects; + guint8 i; + guint8 syntax_id; + guint8 nr_of_additional_values; + guint8 signalstate; + guint8 sig_nr; + guint8 ret_val; + guint8 querytype; + guint8 varspec_length; + + start_offset = offset; + + msg_item = proto_tree_add_item(data_tree, hf_s7comm_cpu_alarm_message_item, tvb, offset, 0, ENC_NA); + msg_item_tree = proto_item_add_subtree(msg_item, ett_s7comm_cpu_alarm_message); + + switch (subfunc) { + case S7COMM_UD_SUBF_CPU_SCAN_IND: + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_scan_unknown1, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + msg_work_item = proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_timestamp_coming, tvb, offset, 8, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_timestamp); + offset = s7comm_add_timestamp_to_tree(tvb, msg_work_item_tree, offset, TRUE, FALSE); + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_scan_unknown2, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case S7COMM_UD_SUBF_CPU_ALARM8_IND: + case S7COMM_UD_SUBF_CPU_ALARMACK_IND: + case S7COMM_UD_SUBF_CPU_ALARMSQ_IND: + case S7COMM_UD_SUBF_CPU_ALARMS_IND: + case S7COMM_UD_SUBF_CPU_NOTIFY_IND: + case S7COMM_UD_SUBF_CPU_NOTIFY8_IND: + msg_work_item = proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_timestamp_coming, tvb, offset, 8, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_timestamp); + offset = s7comm_add_timestamp_to_tree(tvb, msg_work_item_tree, offset, TRUE, FALSE); + break; + } + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_function, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + nr_objects = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_item_tree, hf_s7comm_cpu_alarm_message_nr_objects, tvb, offset, 1, nr_objects); + offset += 1; + for (i = 0; i < nr_objects; i++) { + msg_obj_start_offset = offset; + msg_obj_item = proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_obj_item, tvb, offset, 0, ENC_NA); + msg_obj_item_tree = proto_item_add_subtree(msg_obj_item, ett_s7comm_cpu_alarm_message_object); + proto_item_append_text(msg_obj_item_tree, " [%d]", i+1); + if (type == S7COMM_UD_TYPE_REQ || type == S7COMM_UD_TYPE_IND) { + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + varspec_length = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, varspec_length); + offset += 1; + syntax_id = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, syntax_id); + offset += 1; + switch (syntax_id) { + case S7COMM_SYNTAXID_ALARM_LOCKFREESET: + case S7COMM_SYNTAXID_ALARM_INDSET: + case S7COMM_SYNTAXID_NOTIFY_INDSET: + case S7COMM_SYNTAXID_ALARM_ACKSET: + nr_of_additional_values = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_nr_add_values, tvb, offset, 1, nr_of_additional_values); + offset += 1; + ev_id = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_eventid, tvb, offset, 4, ev_id); + offset += 4; + proto_item_append_text(msg_obj_item_tree, ": EventID=0x%08x", ev_id); + col_append_fstr(pinfo->cinfo, COL_INFO, " EventID=0x%08x", ev_id); + if (syntax_id == S7COMM_SYNTAXID_ALARM_INDSET || syntax_id == S7COMM_SYNTAXID_NOTIFY_INDSET) { + signalstate = tvb_get_guint8(tvb, offset); + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_eventstate, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + /* show SIG with True values for a quick overview in info-column */ + if (signalstate > 0) { + col_append_str(pinfo->cinfo, COL_INFO, " On=["); + for (sig_nr = 0; sig_nr < 8; sig_nr++) { + if (signalstate & 0x01) { + signalstate >>= 1; + if (signalstate == 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, "SIG_%d", sig_nr + 1); + } else { + col_append_fstr(pinfo->cinfo, COL_INFO, "SIG_%d,", sig_nr + 1); + } + } else { + signalstate >>= 1; + } + } + col_append_str(pinfo->cinfo, COL_INFO, "]"); + } + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_state, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + } + if (syntax_id == S7COMM_SYNTAXID_ALARM_INDSET || syntax_id == S7COMM_SYNTAXID_ALARM_ACKSET || syntax_id == S7COMM_SYNTAXID_NOTIFY_INDSET) { + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_ackstate_going, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_ackstate_coming, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + } + if (syntax_id == S7COMM_SYNTAXID_NOTIFY_INDSET) { + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_event_going, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_event_coming, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_event_lastchanged, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_event_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + if (syntax_id == S7COMM_SYNTAXID_ALARM_INDSET || syntax_id == S7COMM_SYNTAXID_NOTIFY_INDSET) { + if (nr_of_additional_values > 0) { + asc_start_offset = offset; + msg_work_item = proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_associated_value, tvb, offset, 0, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_associated_value); + offset = s7comm_decode_response_read_data(tvb, msg_work_item_tree, nr_of_additional_values, offset); + proto_item_set_len(msg_work_item_tree, offset - asc_start_offset); + } + } + break; + case S7COMM_SYNTAXID_ALARM_QUERYREQSET: + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_unknown1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + querytype = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_querytype, tvb, offset, 1, querytype); + offset += 1; + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_unknown2, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + ev_id = tvb_get_ntohl(tvb, offset); + /* there is a querytype=8, which only occurs when a previous SZL request 0x131 index 0x10 has a missing flag in funk_1 */ + switch (querytype) { + case S7COMM_ALARM_MESSAGE_QUERYTYPE_BYALARMTYPE: + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_alarmtype, tvb, offset, 4, ENC_BIG_ENDIAN); + col_append_fstr(pinfo->cinfo, COL_INFO, " ByAlarmtype=%s", + val_to_str(ev_id, alarm_message_query_alarmtype_names, "Unknown Alarmtype: %u")); + break; + case S7COMM_ALARM_MESSAGE_QUERYTYPE_BYEVENTID: + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_eventid, tvb, offset, 4, ENC_BIG_ENDIAN); + col_append_fstr(pinfo->cinfo, COL_INFO, " ByEventID=0x%08x", ev_id); + break; + default: + break; + } + offset += 4; + break; + default: + /* for current unknown syntax id, set offset to end of dataset. The varspec_length includes + * the byte for the syntax_id, so minus one. + */ + offset += (varspec_length - 1); + break; + } + } else if (type == S7COMM_UD_TYPE_RES) { + ret_val = tvb_get_guint8(tvb, offset); + proto_item_append_text(msg_obj_item_tree, ": (%s)", val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + offset += 1; + } + proto_item_set_len(msg_obj_item_tree, offset - msg_obj_start_offset); + } + proto_item_set_len(msg_item_tree, offset - start_offset); + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 4 -> alarm query response + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_cpu_alarm_query_response(tvbuff_t *tvb, + proto_tree *data_tree, + guint32 offset) +{ + proto_item *msg_item = NULL; + proto_tree *msg_item_tree = NULL; + proto_item *msg_obj_item = NULL; + proto_tree *msg_obj_item_tree = NULL; + proto_item *msg_work_item = NULL; + proto_tree *msg_work_item_tree = NULL; + guint32 start_offset; + guint32 msg_obj_start_offset; + guint32 asc_start_offset; + guint32 ev_id; + guint8 returncode; + guint8 alarmtype; + guint16 complete_length; + gint32 remaining_length; + gboolean cont; + + start_offset = offset; + msg_item = proto_tree_add_item(data_tree, hf_s7comm_cpu_alarm_message_item, tvb, offset, 0, ENC_NA); + msg_item_tree = proto_item_add_subtree(msg_item, ett_s7comm_cpu_alarm_message); + + /* Maybe this value here is something different, always 0x00 or 0x01 */ + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_function, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_nr_objects, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + returncode = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_item_tree, hf_s7comm_data_returncode, tvb, offset, 1, returncode); + offset += 1; + proto_tree_add_item(msg_item_tree, hf_s7comm_data_transport_size, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + complete_length = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(msg_item_tree, hf_s7comm_cpu_alarm_query_completelen, tvb, offset, 2, complete_length); + remaining_length = (gint32)complete_length; + offset += 2; + + if (returncode == S7COMM_ITEM_RETVAL_DATA_OK) { + do { + msg_obj_start_offset = offset; + msg_obj_item = proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_alarm_message_obj_item, tvb, offset, 0, ENC_NA); + msg_obj_item_tree = proto_item_add_subtree(msg_obj_item, ett_s7comm_cpu_alarm_message_object); + + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_datasetlen, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_resunknown1, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* begin of count dataset length */ + alarmtype = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_alarmtype, tvb, offset, 1, alarmtype); + proto_item_append_text(msg_obj_item_tree, " (Alarmtype=%s)", val_to_str(alarmtype, alarm_message_query_alarmtype_names, "Unknown Alarmtype: %u")); + offset += 1; + ev_id = tvb_get_ntohl(tvb, offset); + proto_tree_add_uint(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_eventid, tvb, offset, 4, ev_id); + proto_item_append_text(msg_obj_item_tree, ": EventID=0x%08x", ev_id); + offset += 4; + proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_query_resunknown1, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_eventstate, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_ackstate_going, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_bitmask(msg_obj_item_tree, tvb, offset, hf_s7comm_cpu_alarm_message_ackstate_coming, + ett_s7comm_cpu_alarm_message_signal, s7comm_cpu_alarm_message_signal_fields, ENC_BIG_ENDIAN); + offset += 1; + if (alarmtype == S7COMM_ALARM_MESSAGE_QUERY_ALARMTYPE_ALARM_S) { + /* 8 bytes timestamp (coming)*/ + msg_work_item = proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_timestamp_coming, tvb, offset, 8, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_timestamp); + offset = s7comm_add_timestamp_to_tree(tvb, msg_work_item_tree, offset, TRUE, FALSE); + /* Associated value of coming alarm */ + asc_start_offset = offset; + msg_work_item = proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_associated_value, tvb, offset, 0, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_associated_value); + offset = s7comm_decode_response_read_data(tvb, msg_work_item_tree, 1, offset); + proto_item_set_len(msg_work_item_tree, offset - asc_start_offset); + /* 8 bytes timestamp (going) + * If all bytes in timestamp are zero, then the message is still active. */ + msg_work_item = proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_timestamp_going, tvb, offset, 8, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_timestamp); + offset = s7comm_add_timestamp_to_tree(tvb, msg_work_item_tree, offset, TRUE, FALSE); + /* Associated value of going alarm */ + asc_start_offset = offset; + msg_work_item = proto_tree_add_item(msg_obj_item_tree, hf_s7comm_cpu_alarm_message_associated_value, tvb, offset, 0, ENC_NA); + msg_work_item_tree = proto_item_add_subtree(msg_work_item, ett_s7comm_cpu_alarm_message_associated_value); + offset = s7comm_decode_response_read_data(tvb, msg_work_item_tree, 1, offset); + proto_item_set_len(msg_work_item_tree, offset - asc_start_offset); + } + remaining_length = remaining_length - (offset - msg_obj_start_offset); + proto_item_set_len(msg_obj_item_tree, offset - msg_obj_start_offset); + /* when complete_length is 0xffff, then loop until terminating null */ + if (complete_length == 0xffff) { + cont = (tvb_get_guint8(tvb, offset) > 0); + } else { + cont = (remaining_length > 0); + } + } while (cont); + } + proto_item_set_len(msg_item_tree, offset - start_offset); + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 4 -> diagnostic message + * Also used as a dataset in the diagnostic buffer, read with SZL-ID 0x00a0 index 0. + * + *******************************************************************************************************/ +guint32 +s7comm_decode_ud_cpu_diagnostic_message(tvbuff_t *tvb, + packet_info *pinfo, + gboolean add_info_to_col, + proto_tree *data_tree, + guint32 offset) +{ + proto_item *msg_item = NULL; + proto_tree *msg_item_tree = NULL; + guint16 eventid; + guint16 eventid_masked; + const gchar *event_text; + gboolean has_text = FALSE; + + msg_item = proto_tree_add_item(data_tree, hf_s7comm_cpu_diag_msg_item, tvb, offset, 20, ENC_NA); + msg_item_tree = proto_item_add_subtree(msg_item, ett_s7comm_cpu_diag_msg); + + eventid = tvb_get_ntohs(tvb, offset); + if ((eventid >= 0x8000) && (eventid <= 0x9fff)) { + eventid_masked = eventid & 0xf0ff; + if ((event_text = try_val_to_str_ext(eventid_masked, &cpu_diag_eventid_0x8_0x9_names_ext))) { + if (add_info_to_col) { + col_append_fstr(pinfo->cinfo, COL_INFO, " Event='%s'", event_text); + } + has_text = TRUE; + } else { + if (add_info_to_col) { + col_append_fstr(pinfo->cinfo, COL_INFO, " EventID=0x%04x", eventid); + } + } + } else if ((eventid >= 0x1000) && (eventid < 0x8000)) { + if ((event_text = try_val_to_str_ext(eventid, &cpu_diag_eventid_fix_names_ext))) { + if (add_info_to_col) { + col_append_fstr(pinfo->cinfo, COL_INFO, " Event='%s'", event_text); + } + has_text = TRUE; + } else { + if (add_info_to_col) { + col_append_fstr(pinfo->cinfo, COL_INFO, " EventID=0x%04x", eventid); + } + } + } else { + if (add_info_to_col) { + col_append_fstr(pinfo->cinfo, COL_INFO, " EventID=0x%04x", eventid); + } + } + proto_tree_add_bitmask(msg_item_tree, tvb, offset, hf_s7comm_cpu_diag_msg_eventid, + ett_s7comm_cpu_diag_msg_eventid, s7comm_cpu_diag_msg_eventid_fields, ENC_BIG_ENDIAN); + if (has_text) { + proto_item_append_text(msg_item_tree, ": Event='%s'", event_text); + } else { + proto_item_append_text(msg_item_tree, ": EventID=0x%04x", eventid); + } + offset += 2; + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_diag_msg_prioclass, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_diag_msg_obnumber, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_diag_msg_datid, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_diag_msg_info1, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(msg_item_tree, hf_s7comm_cpu_diag_msg_info2, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + offset = s7comm_add_timestamp_to_tree(tvb, msg_item_tree, offset, FALSE, FALSE); + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 7 -> time functions + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_time_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint8 ret_val, /* Return value in data part */ + guint32 dlength, + guint32 offset) +{ + gboolean know_data = FALSE; + + switch (subfunc) { + case S7COMM_UD_SUBF_TIME_READ: + case S7COMM_UD_SUBF_TIME_READF: + if (type == S7COMM_UD_TYPE_RES) { + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK) { + proto_item_append_text(data_tree, ": "); + offset = s7comm_add_timestamp_to_tree(tvb, data_tree, offset, TRUE, TRUE); + } + know_data = TRUE; + } + break; + case S7COMM_UD_SUBF_TIME_SET: + case S7COMM_UD_SUBF_TIME_SET2: + if (type == S7COMM_UD_TYPE_REQ) { + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK) { + proto_item_append_text(data_tree, ": "); + offset = s7comm_add_timestamp_to_tree(tvb, data_tree, offset, TRUE, TRUE); + } + know_data = TRUE; + } + break; + default: + break; + } + + if (know_data == FALSE && dlength > 0) { + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 3 -> block functions + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_block_subfunc(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint8 ret_val, /* Return value in data part */ + guint8 tsize, /* transport size in data part */ + guint32 dlength, + guint32 offset) +{ + guint32 count; + guint32 i; + const guint8 *pBlocknumber; + guint16 blocknumber; + guint8 blocktype; + guint16 blocktype16; + gboolean know_data = FALSE; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + proto_item *itemadd = NULL; + char str_timestamp[30]; + char str_version[10]; + + switch (subfunc) { + /************************************************* + * List blocks + */ + case S7COMM_UD_SUBF_BLOCK_LIST: + if (type == S7COMM_UD_TYPE_REQ) { + /* Is this a possible combination? Never seen it... */ + + } else if (type == S7COMM_UD_TYPE_RES) { + count = dlength / 4; + for (i = 0; i < count; i++) { + /* Insert a new tree of 4 byte length for every item */ + item = proto_tree_add_item(data_tree, hf_s7comm_data_item, tvb, offset, 4, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + blocktype16 = tvb_get_ntohs(tvb, offset); + proto_item_append_text(item, " [%d]: (Block type %s)", i+1, val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + itemadd = proto_tree_add_item(item_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 2, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_ud_blockinfo_block_cnt, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + know_data = TRUE; + } + break; + /************************************************* + * List blocks of type + */ + case S7COMM_UD_SUBF_BLOCK_LISTTYPE: + if (type == S7COMM_UD_TYPE_REQ) { + if (tsize != S7COMM_DATA_TRANSPORT_SIZE_NULL) { + blocktype16 = tvb_get_ntohs(tvb, offset); + itemadd = proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 2, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + col_append_fstr(pinfo->cinfo, COL_INFO, " Type:[%s]", + val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + proto_item_append_text(data_tree, ": (%s)", + val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + offset += 2; + } + know_data = TRUE; + + } else if (type == S7COMM_UD_TYPE_RES) { + if (tsize != S7COMM_DATA_TRANSPORT_SIZE_NULL) { + count = dlength / 4; + + for (i = 0; i < count; i++) { + /* Insert a new tree of 4 byte length for every item */ + item = proto_tree_add_item(data_tree, hf_s7comm_data_item, tvb, offset, 4, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + + proto_item_append_text(item, " [%d]: (Block number %d)", i+1, tvb_get_ntohs(tvb, offset)); + proto_tree_add_item(item_tree, hf_s7comm_ud_blockinfo_block_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* The first Byte is unknown, kind of flags? */ + proto_tree_add_item(item_tree, hf_s7comm_ud_blockinfo_block_flags, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_ud_blockinfo_block_lang, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + } + know_data = TRUE; + } + break; + /************************************************* + * Get block infos + */ + case S7COMM_UD_SUBF_BLOCK_BLOCKINFO: + if (type == S7COMM_UD_TYPE_REQ) { + if (tsize != S7COMM_DATA_TRANSPORT_SIZE_NULL) { + gint32 num = -1; + gboolean num_valid; + /* 8 Bytes of Data follow, 1./ 2. type, 3-7 blocknumber as ascii number */ + blocktype16 = tvb_get_ntohs(tvb, offset); + itemadd = proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 2, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + offset += 2; + proto_tree_add_item_ret_string(data_tree, hf_s7comm_ud_blockinfo_block_num_ascii, tvb, offset, 5, ENC_ASCII|ENC_NA, pinfo->pool, &pBlocknumber); + num_valid = ws_strtoi32((const gchar*)pBlocknumber, NULL, &num); + proto_item_append_text(data_tree, " [%s ", + val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> Block:[%s ", + val_to_str(blocktype16, blocktype_names, "Unknown Block type: 0x%04x")); + if (num_valid) { + proto_item_append_text(data_tree, "%d]", num); + col_append_fstr(pinfo->cinfo, COL_INFO, "%d]", num); + } else { + expert_add_info(pinfo, data_tree, &ei_s7comm_ud_blockinfo_block_num_ascii_invalid); + proto_item_append_text(data_tree, "NaN]"); + col_append_str(pinfo->cinfo, COL_INFO, "NaN]"); + } + offset += 5; + itemadd = proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_filesys, tvb, offset, 1, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", char_val_to_str(tvb_get_guint8(tvb, offset), blocktype_attribute2_names, "Unknown filesys")); + offset += 1; + } + know_data = TRUE; + + } else if (type == S7COMM_UD_TYPE_RES) { + /* 78 Bytes */ + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK) { + itemadd = proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 2, ENC_ASCII); + proto_item_append_text(itemadd, " (%s)", val_to_str(tvb_get_ntohs(tvb, offset), blocktype_names, "Unknown Block type: 0x%04x")); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_infolength, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_unknown2, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_const3, tvb, offset, 2, ENC_ASCII); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_unknown, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_bitmask(data_tree, tvb, offset, hf_s7comm_userdata_blockinfo_flags, + ett_s7comm_userdata_blockinfo_flags, s7comm_userdata_blockinfo_flags_fields, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_lang, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + blocktype = tvb_get_guint8(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_subblk_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + blocknumber = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(data_tree, hf_s7comm_ud_blockinfo_block_num, tvb, offset, 2, blocknumber); + /* Add block type and number to info column */ + col_append_fstr(pinfo->cinfo, COL_INFO, " -> Block:[%s %d]", + val_to_str(blocktype, subblktype_names, "Unknown Subblk type: 0x%02x"), + blocknumber); + proto_item_append_text(data_tree, ": (Block:[%s %d])", + val_to_str(blocktype, subblktype_names, "Unknown Subblk type: 0x%02x"), + blocknumber); + offset += 2; + /* "Length Load mem" -> the length in Step7 Manager seems to be this length +6 bytes */ + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_load_mem_len, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_blocksecurity, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + s7comm_get_timestring_from_s7time(tvb, offset, str_timestamp, sizeof(str_timestamp)); + proto_tree_add_string(data_tree, hf_s7comm_ud_blockinfo_code_timestamp, tvb, offset, 6, str_timestamp); + offset += 6; + s7comm_get_timestring_from_s7time(tvb, offset, str_timestamp, sizeof(str_timestamp)); + proto_tree_add_string(data_tree, hf_s7comm_ud_blockinfo_interface_timestamp, tvb, offset, 6, str_timestamp); + offset += 6; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_ssb_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_add_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_localdata_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_mc7_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_author, tvb, offset, 8, ENC_ASCII); + offset += 8; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_family, tvb, offset, 8, ENC_ASCII); + offset += 8; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_headername, tvb, offset, 8, ENC_ASCII); + offset += 8; + snprintf(str_version, sizeof(str_version), "%d.%d", ((tvb_get_guint8(tvb, offset) & 0xf0) >> 4), tvb_get_guint8(tvb, offset) & 0x0f); + proto_tree_add_string(data_tree, hf_s7comm_ud_blockinfo_headerversion, tvb, offset, 1, str_version); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_unknown, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_checksum(data_tree, tvb, offset, hf_s7comm_ud_blockinfo_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_reserved1, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_reserved2, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + } + know_data = TRUE; + } + break; + default: + break; + } + if (know_data == FALSE && dlength > 0) { + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 2 -> Read record + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_readrec(tvbuff_t *tvb, + proto_tree *tree, + guint8 type, + guint32 offset) +{ + guint32 ret_val; + guint32 statuslen; + guint32 reclen; + guint8 item_count; + + if (type == S7COMM_UD_TYPE_REQ) { + proto_tree_add_item(tree, hf_s7comm_rdrec_reserved1, tvb, offset, 1, ENC_NA); + offset += 1; + /* Although here is an item_count field, values above 1 aren't allowed or at least never seen */ + item_count = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_s7comm_param_itemcount, tvb, offset, 1, item_count); + offset += 1; + if (item_count > 0) { + offset = s7comm_decode_param_item(tvb, offset, tree, 0); + } + } else if (type == S7COMM_UD_TYPE_RES) { + /* The item with data is used for optional status code similar to the + * STATUS output of SFB52 RDREC used in Plc code. + */ + proto_tree_add_item(tree, hf_s7comm_rdrec_reserved1, tvb, offset, 1, ENC_NA); + offset += 1; + item_count = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(tree, hf_s7comm_param_itemcount, tvb, offset, 1, item_count); + offset += 1; + /* As all testsubjects have shown that no more than one item is allowed, + * we decode only the first item here. + */ + if (item_count > 0) { + proto_tree_add_item_ret_uint(tree, hf_s7comm_data_returncode, tvb, offset, 1, ENC_BIG_ENDIAN, &ret_val); + offset += 1; + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK) { + proto_tree_add_item(tree, hf_s7comm_data_transport_size, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + proto_tree_add_item_ret_uint(tree, hf_s7comm_rdrec_statuslen, tvb, offset, 1, ENC_BIG_ENDIAN, &statuslen); + offset += 1; + if (statuslen > 0) { + proto_tree_add_item(tree, hf_s7comm_rdrec_statusdata, tvb, offset, statuslen, ENC_NA); + offset += statuslen; + } else { + offset += 1; /* Fillbyte */ + } + if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK) { + proto_tree_add_item_ret_uint(tree, hf_s7comm_rdrec_recordlen, tvb, offset, 2, ENC_BIG_ENDIAN, &reclen); + offset += 2; + if (reclen > 0) { + proto_tree_add_item(tree, hf_s7comm_rdrec_data, tvb, offset, reclen, ENC_NA); + offset += reclen; + } + } + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 2 -> cyclic services + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_cyclic_subfunc(tvbuff_t *tvb, + packet_info *pinfo, + guint8 seq_num, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint32 dlength, + guint32 offset) +{ + gboolean know_data = FALSE; + guint32 offset_old; + guint32 len_item; + guint8 item_count; + guint8 i; + guint8 job_id; + + switch (subfunc) + { + case S7COMM_UD_SUBF_CYCLIC_CHANGE_MOD: + if (type == S7COMM_UD_TYPE_REQ) { + col_append_fstr(pinfo->cinfo, COL_INFO, " JobID=%d", seq_num); + } + /* fall through */ + case S7COMM_UD_SUBF_CYCLIC_TRANSF: + case S7COMM_UD_SUBF_CYCLIC_CHANGE: + item_count = tvb_get_guint8(tvb, offset + 1); /* first byte reserved??? */ + proto_tree_add_uint(data_tree, hf_s7comm_param_itemcount, tvb, offset, 2, item_count); + offset += 2; + if (type == S7COMM_UD_TYPE_REQ) { + proto_tree_add_item(data_tree, hf_s7comm_cycl_interval_timebase, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_cycl_interval_time, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + for (i = 0; i < item_count; i++) { + offset_old = offset; + offset = s7comm_decode_param_item(tvb, offset, data_tree, i); + /* if length is not a multiple of 2 and this is not the last item, then add a fill-byte */ + len_item = offset - offset_old; + if ((len_item % 2) && (i < (item_count-1))) { + offset += 1; + } + } + } else if (type == S7COMM_UD_TYPE_RES || type == S7COMM_UD_TYPE_IND) { + col_append_fstr(pinfo->cinfo, COL_INFO, " JobID=%d", seq_num); + offset = s7comm_decode_response_read_data(tvb, data_tree, item_count, offset); + } + know_data = TRUE; + break; + case S7COMM_UD_SUBF_CYCLIC_UNSUBSCRIBE: + if (type == S7COMM_UD_TYPE_REQ) { + proto_tree_add_item(data_tree, hf_s7comm_cycl_function, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_cycl_jobid, tvb, offset, 1, ENC_BIG_ENDIAN); + job_id = tvb_get_guint8(tvb, offset); + col_append_fstr(pinfo->cinfo, COL_INFO, " JobID=%d", job_id); + offset += 1; + know_data = TRUE; + } else if (type == S7COMM_UD_TYPE_RES) { + col_append_fstr(pinfo->cinfo, COL_INFO, " JobID=%d", seq_num); + } + break; + case S7COMM_UD_SUBF_CYCLIC_RDREC: + offset = s7comm_decode_ud_readrec(tvb, data_tree, type, offset); + know_data = TRUE; + break; + } + + if (know_data == FALSE && dlength > 0) { + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data: Data part and reassembly + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_data(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + guint16 dlength, + guint8 type, + guint8 funcgroup, + guint8 subfunc, + guint8 seq_num, + guint8 data_unit_ref, + guint8 last_data_unit, + guint32 offset, + proto_tree *root_tree) +{ + proto_item *item = NULL; + proto_tree *data_tree = NULL; + guint8 tsize; + guint16 len; + guint8 ret_val; + guint32 length_rem = 0; + gboolean save_fragmented; + guint32 frag_id = 0; + gboolean more_frags = FALSE; + gboolean is_fragmented = FALSE; + tvbuff_t* new_tvb = NULL; + tvbuff_t* next_tvb = NULL; + fragment_head *fd_head; + gchar str_fragadd[32]; + + /* The first 4 bytes of the data part of a userdata telegram are the same for all types. + * This is also the minumum length of the data part. + */ + if (dlength >= 4) { + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + + ret_val = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(data_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + offset += 1; + /* Not definitely known part, kind of "transport size"? constant 0x09, 1 byte + * The position is the same as in a data response/write telegram, + */ + tsize = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(data_tree, hf_s7comm_data_transport_size, tvb, offset, 1, tsize); + offset += 1; + len = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(data_tree, hf_s7comm_data_length, tvb, offset, 2, len); + offset += 2; + + if (len >= 2) { + more_frags = (last_data_unit == S7COMM_UD_LASTDATAUNIT_NO); + /* Some packets have an additional header before the payload, which must be + * extracted from the data before reassembly. + */ + switch (funcgroup) { + case S7COMM_UD_FUNCGROUP_NCPRG: + offset = s7comm_decode_ud_ncprg_pre_reass(tvb, data_tree, type, subfunc, &len, offset); + /* Unfortunately on NC programming the first PDU is always shown as reassembled also when not fragmented, + * because data_unit_ref may overflow and start again at 0 on big file transfers. + */ + is_fragmented = TRUE; + frag_id = seq_num; + break; + case S7COMM_UD_FUNCGROUP_PBC_BSEND: + /* The R_ID is used for fragment identification */ + offset = s7comm_decode_ud_pbc_bsend_pre_reass(tvb, pinfo, data_tree, type, &len, &frag_id, offset); + is_fragmented = data_unit_ref > 0 || seq_num > 0; + break; + case S7COMM_UD_FUNCGROUP_CPU: + if (subfunc == S7COMM_UD_SUBF_CPU_AR_SEND_IND) { + offset = s7comm_decode_ud_cpu_ar_send_pre_reass(tvb, pinfo, data_tree, &len, offset); + } + /* fragment identification is always the same here */ + is_fragmented = (data_unit_ref > 0); + frag_id = data_unit_ref; + break; + default: + is_fragmented = (data_unit_ref > 0); + frag_id = data_unit_ref; + break; + } + /* Reassembly of fragmented data part */ + save_fragmented = pinfo->fragmented; + if (is_fragmented) { /* fragmented */ + pinfo->fragmented = TRUE; + /* NC programming uses a different method of fragment indication. The sequence number is used as reference-id, + * the data unit reference number is increased with every packet, as the sender does not need to wait for + * the acknowledge of the packet. Also different in NC programming is, that also when a packet is not + * fragmented, data_unit_ref is > 0 and "reassembled" would be displayed even when not fragmented (count number of fragments?) + * Using fragment number does not work here, as it's only one byte. And if there are more than 255 fragments this would fail. + */ + fd_head = fragment_add_seq_next(&s7comm_reassembly_table, + tvb, offset, pinfo, + frag_id, /* ID for fragments belonging together */ + NULL, /* void *data */ + len, /* fragment length - to the end */ + more_frags); /* More fragments? */ + snprintf(str_fragadd, sizeof(str_fragadd), " id=%d", frag_id); + new_tvb = process_reassembled_data(tvb, offset, pinfo, + "Reassembled S7COMM", fd_head, &s7comm_frag_items, + NULL, tree); + if (new_tvb) { /* take it all */ + /* add reassembly info only when there's more than one fragment */ + if (fd_head && fd_head->next) { + col_append_fstr(pinfo->cinfo, COL_INFO, " (S7COMM reassembled%s)", str_fragadd); + proto_item_append_text(data_tree, " (S7COMM reassembled%s)", str_fragadd); + } + next_tvb = new_tvb; + offset = 0; + } else { /* make a new subset */ + next_tvb = tvb_new_subset_length(tvb, offset, -1); + col_append_fstr(pinfo->cinfo, COL_INFO, " (S7COMM fragment%s)", str_fragadd); + proto_item_append_text(data_tree, " (S7COMM fragment%s)", str_fragadd); + offset = 0; + } + } else { /* Not fragmented */ + next_tvb = tvb; + } + pinfo->fragmented = save_fragmented; + length_rem = tvb_reported_length_remaining(next_tvb, offset); + + if (last_data_unit == S7COMM_UD_LASTDATAUNIT_YES && length_rem > 0) { + switch (funcgroup) { + case S7COMM_UD_FUNCGROUP_TIS: + offset = s7comm_decode_ud_tis_subfunc(next_tvb, data_tree, type, subfunc, offset); + break; + case S7COMM_UD_FUNCGROUP_CYCLIC: + offset = s7comm_decode_ud_cyclic_subfunc(next_tvb, pinfo, seq_num, data_tree, type, subfunc, length_rem, offset); + break; + case S7COMM_UD_FUNCGROUP_BLOCK: + offset = s7comm_decode_ud_block_subfunc(next_tvb, pinfo, data_tree, type, subfunc, ret_val, tsize, length_rem, offset); + break; + case S7COMM_UD_FUNCGROUP_CPU: + switch (subfunc) { + case S7COMM_UD_SUBF_CPU_READSZL: + offset = s7comm_decode_ud_cpu_szl_subfunc(next_tvb, pinfo, data_tree, type, ret_val, length_rem, offset); + break; + case S7COMM_UD_SUBF_CPU_NOTIFY_IND: + case S7COMM_UD_SUBF_CPU_NOTIFY8_IND: + case S7COMM_UD_SUBF_CPU_ALARMSQ_IND: + case S7COMM_UD_SUBF_CPU_ALARMS_IND: + case S7COMM_UD_SUBF_CPU_SCAN_IND: + case S7COMM_UD_SUBF_CPU_ALARMACK: + case S7COMM_UD_SUBF_CPU_ALARMACK_IND: + case S7COMM_UD_SUBF_CPU_ALARM8_IND: + case S7COMM_UD_SUBF_CPU_ALARM8LOCK: + case S7COMM_UD_SUBF_CPU_ALARM8LOCK_IND: + case S7COMM_UD_SUBF_CPU_ALARM8UNLOCK: + case S7COMM_UD_SUBF_CPU_ALARM8UNLOCK_IND: + offset = s7comm_decode_ud_cpu_alarm_main(next_tvb, pinfo, data_tree, type, subfunc, offset); + break; + case S7COMM_UD_SUBF_CPU_ALARMQUERY: + if (type == S7COMM_UD_TYPE_RES) { + offset = s7comm_decode_ud_cpu_alarm_query_response(next_tvb, data_tree, offset); + } else { + offset = s7comm_decode_ud_cpu_alarm_main(next_tvb, pinfo, data_tree, type, subfunc, offset); + } + break; + case S7COMM_UD_SUBF_CPU_DIAGMSG: + offset = s7comm_decode_ud_cpu_diagnostic_message(next_tvb, pinfo, TRUE, data_tree, offset); + break; + case S7COMM_UD_SUBF_CPU_MSGS: + offset = s7comm_decode_message_service(next_tvb, pinfo, data_tree, type, length_rem, offset); + break; + case S7COMM_UD_SUBF_CPU_AR_SEND_IND: + offset = s7comm_decode_ud_cpu_ar_send(next_tvb, data_tree, offset); + break; + default: + /* print other currently unknown data as raw bytes */ + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, next_tvb, offset, length_rem, ENC_NA); + break; + } + break; + case S7COMM_UD_FUNCGROUP_SEC: + offset = s7comm_decode_ud_security_subfunc(next_tvb, data_tree, length_rem, offset); + break; + case S7COMM_UD_FUNCGROUP_PBC_BSEND: + offset = s7comm_decode_ud_pbc_bsend_subfunc(next_tvb, data_tree, length_rem, offset, pinfo, root_tree); + break; + case S7COMM_UD_FUNCGROUP_TIME: + offset = s7comm_decode_ud_time_subfunc(next_tvb, data_tree, type, subfunc, ret_val, length_rem, offset); + break; + case S7COMM_UD_FUNCGROUP_NCPRG: + offset = s7comm_decode_ud_ncprg_subfunc(next_tvb, pinfo, data_tree, type, subfunc, length_rem, offset); + break; + case S7COMM_UD_FUNCGROUP_DRR: + offset = s7comm_decode_ud_drr_subfunc(next_tvb, data_tree, length_rem, offset); + break; + default: + break; + } + } + } + } + return offset; +} + +/******************************************************************************************************* + ******************************************************************************************************* + * + * PDU Type: User Data + * + ******************************************************************************************************* + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + guint16 plength, + guint16 dlength, + guint32 offset, + proto_tree *root_tree) +{ + proto_item *item = NULL; + proto_tree *param_tree = NULL; + + guint32 errorcode; + guint32 offset_temp; + guint8 function; + guint8 type; + guint8 funcgroup; + guint8 subfunc; + guint8 mode; + guint8 data_unit_ref = 0; + guint8 last_data_unit = 0; + guint8 seq_num; + guint32 r_id; + guint8 varspec_syntax_id = 0; + + /* Add parameter tree */ + item = proto_tree_add_item(tree, hf_s7comm_param, tvb, offset, plength, ENC_NA); + param_tree = proto_item_add_subtree(item, ett_s7comm_param); + + offset_temp = offset; + + function = tvb_get_guint8(tvb, offset_temp); + proto_tree_add_uint(param_tree, hf_s7comm_param_service, tvb, offset_temp, 1, function); + offset_temp += 1; + + /* It's like an itemcounter, but only the value of 1 is allowed. */ + proto_tree_add_item(param_tree, hf_s7comm_param_itemcount, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + + if (function == S7COMM_SERV_MODETRANS) { + /* Mode transition indication needs a separate handling */ + proto_item_append_text(param_tree, ": ->(Mode transition indication)"); + col_append_fstr(pinfo->cinfo, COL_INFO, " Function:[Mode transition indication]"); + proto_tree_add_item(param_tree, hf_s7comm_modetrans_param_unknown1, tvb, offset_temp, 4, ENC_BIG_ENDIAN); + offset_temp += 4; + mode = tvb_get_guint8(tvb, offset_temp); + proto_tree_add_uint(param_tree, hf_s7comm_modetrans_param_mode, tvb, offset_temp, 1, mode); + offset_temp += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(mode, modetrans_param_mode_names, "Unknown mode: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(mode, modetrans_param_mode_names, "Unknown mode: 0x%02x")); + proto_tree_add_item(param_tree, hf_s7comm_modetrans_param_unknown2, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + /* No data part here */ + return offset_temp; + } + + proto_tree_add_item(param_tree, hf_s7comm_item_varspec, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + proto_tree_add_item(param_tree, hf_s7comm_item_varspec_length, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + varspec_syntax_id = tvb_get_guint8(tvb, offset_temp); + proto_tree_add_item(param_tree, hf_s7comm_item_syntax_id, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + + if (varspec_syntax_id == S7COMM_SYNTAXID_PBC_ID) { + /* When the R_ID occurs here, it's USEND and needs a separate handling */ + proto_item_append_text(param_tree, ": (Indication) ->(USEND)"); + col_append_fstr(pinfo->cinfo, COL_INFO, " Function:[Indication] -> [USEND]"); + proto_tree_add_item(param_tree, hf_s7comm_pbc_unknown, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + proto_tree_add_item_ret_uint(param_tree, hf_s7comm_pbc_usend_r_id, tvb, offset_temp, 4, ENC_BIG_ENDIAN, &r_id); + col_append_fstr(pinfo->cinfo, COL_INFO, " R_ID=0x%X", r_id); + /* USEND data must fit in a single PDU. Fragmentation is not possible and we can dissect the data part here. */ + offset += plength; /* To start of data part */ + offset = s7comm_decode_ud_usend(tvb, tree, dlength, offset); + /* Return here as all data is decoded */ + return offset; + } + + /* Left 2 bits for indication/request/response + * Right 6 bits for the function group + */ + type = (tvb_get_guint8(tvb, offset_temp) & 0xc0) >> 6; + funcgroup = (tvb_get_guint8(tvb, offset_temp) & 0x3f); + proto_tree_add_item(param_tree, hf_s7comm_userdata_param_type, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(param_tree, hf_s7comm_userdata_param_funcgroup, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + + col_append_fstr(pinfo->cinfo, COL_INFO, " Function:[%s] -> [%s]", + val_to_str(type, userdata_type_names, "Unknown type: 0x%02x"), + val_to_str(funcgroup, userdata_functiongroup_names, "Unknown function group: 0x%02x") + ); + proto_item_append_text(param_tree, ": (%s)", val_to_str(type, userdata_type_names, "Unknown type: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(funcgroup, userdata_functiongroup_names, "Unknown function group: 0x%02x")); + + /* 1 Byte subfunction */ + subfunc = tvb_get_guint8(tvb, offset_temp); + switch (funcgroup) { + case S7COMM_UD_FUNCGROUP_TIS: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_prog, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_tis_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_tis_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_CYCLIC: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_cyclic, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_cyclic_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_cyclic_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_BLOCK: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_block, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_block_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_block_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_CPU: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_cpu, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_cpu_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_cpu_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_SEC: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_sec, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_sec_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_sec_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_TIME: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_time, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_time_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_time_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_DRR: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_drr, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_drr_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_drr_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + case S7COMM_UD_FUNCGROUP_NCPRG: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc_ncprg, tvb, offset_temp, 1, subfunc); + col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", + val_to_str(subfunc, userdata_ncprg_subfunc_names, "Unknown subfunc: 0x%02x")); + proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_ncprg_subfunc_names, "Unknown subfunc: 0x%02x")); + break; + default: + proto_tree_add_uint(param_tree, hf_s7comm_userdata_param_subfunc, tvb, offset_temp, 1, subfunc); + break; + } + offset_temp += 1; + /* 1 Byte sequence number */ + seq_num = tvb_get_guint8(tvb, offset_temp); + proto_tree_add_item(param_tree, hf_s7comm_userdata_param_seq_num, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + if (varspec_syntax_id == S7COMM_SYNTAXID_EXT) { + /* 1 Byte data unit reference. If packet is fragmented, all packets with this number belong together. + * But there are function which use a different fragment identification methon. + */ + data_unit_ref = tvb_get_guint8(tvb, offset_temp); + proto_tree_add_item(param_tree, hf_s7comm_userdata_param_dataunitref, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + /* 1 Byte fragmented flag, if this is not the last data unit (telegram is fragmented) this is != 0 */ + last_data_unit = tvb_get_guint8(tvb, offset_temp); + proto_tree_add_item(param_tree, hf_s7comm_userdata_param_dataunit, tvb, offset_temp, 1, ENC_BIG_ENDIAN); + offset_temp += 1; + proto_tree_add_item_ret_uint(param_tree, hf_s7comm_param_errcod, tvb, offset_temp, 2, ENC_BIG_ENDIAN, &errorcode); + if (errorcode > 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, " -> Errorcode:[0x%04x]", errorcode); + } + } + offset += plength; + + offset = s7comm_decode_ud_data(tvb, pinfo, tree, dlength, type, funcgroup, subfunc, seq_num, data_unit_ref, last_data_unit, offset, root_tree); + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: Request or Response + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_req_resp(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + guint16 plength, + guint16 dlength, + guint32 offset, + guint8 rosctr) +{ + proto_item *item = NULL; + proto_tree *param_tree = NULL; + proto_tree *data_tree = NULL; + guint8 function = 0; + guint8 item_count = 0; + guint8 i; + guint32 offset_old; + guint32 len; + + if (plength > 0) { + /* Add parameter tree */ + item = proto_tree_add_item(tree, hf_s7comm_param, tvb, offset, plength, ENC_NA); + param_tree = proto_item_add_subtree(item, ett_s7comm_param); + /* Analyze function */ + function = tvb_get_guint8(tvb, offset); + /* add param.function to info column */ + col_append_fstr(pinfo->cinfo, COL_INFO, " Function:[%s]", val_to_str(function, param_functionnames, "Unknown function: 0x%02x")); + proto_tree_add_uint(param_tree, hf_s7comm_param_service, tvb, offset, 1, function); + /* show param.function code at the tree */ + proto_item_append_text(param_tree, ": (%s)", val_to_str(function, param_functionnames, "Unknown function: 0x%02x")); + offset += 1; + + if (rosctr == S7COMM_ROSCTR_JOB) { + switch (function){ + case S7COMM_SERV_READVAR: + case S7COMM_SERV_WRITEVAR: + item_count = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(param_tree, hf_s7comm_param_itemcount, tvb, offset, 1, item_count); + offset += 1; + /* parse item data */ + for (i = 0; i < item_count; i++) { + offset_old = offset; + offset = s7comm_decode_param_item(tvb, offset, param_tree, i); + /* if length is not a multiple of 2 and this is not the last item, then add a fill-byte */ + len = offset - offset_old; + if ((len % 2) && (i < (item_count-1))) { + offset += 1; + } + } + /* in write-function there is a data part */ + if ((function == S7COMM_SERV_WRITEVAR) && (dlength > 0)) { + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + /* Add returned data to data-tree */ + offset = s7comm_decode_response_read_data(tvb, data_tree, item_count, offset); + } + break; + case S7COMM_SERV_SETUPCOMM: + offset = s7comm_decode_pdu_setup_communication(tvb, param_tree, offset); + break; + /* Special functions */ + case S7COMM_FUNCREQUESTDOWNLOAD: + case S7COMM_FUNCDOWNLOADBLOCK: + case S7COMM_FUNCDOWNLOADENDED: + case S7COMM_FUNCSTARTUPLOAD: + case S7COMM_FUNCUPLOAD: + case S7COMM_FUNCENDUPLOAD: + offset = s7comm_decode_plc_controls_updownload(tvb, pinfo, tree, param_tree, plength, dlength, offset -1, rosctr); + break; + case S7COMM_FUNCPISERVICE: + offset = s7comm_decode_pi_service(tvb, pinfo, param_tree, plength, offset -1); + break; + case S7COMM_FUNC_PLC_STOP: + offset = s7comm_decode_plc_controls_param_hex29(tvb, param_tree, offset -1); + break; + + default: + /* Print unknown part as raw bytes */ + if (plength > 1) { + proto_tree_add_item(param_tree, hf_s7comm_param_data, tvb, offset, plength - 1, ENC_NA); + } + offset += plength - 1; /* 1 byte function code */ + if (dlength > 0) { + /* Add data tree + * First 2 bytes in data seem to be a length indicator of (dlength -4 ), so next 2 bytes + * seem to indicate something else. But I'm not sure, so leave it as it is..... + */ + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + proto_tree_add_item(data_tree, hf_s7comm_readresponse_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + break; + } + } else if (rosctr == S7COMM_ROSCTR_ACK_DATA) { + switch (function){ + case S7COMM_SERV_READVAR: + case S7COMM_SERV_WRITEVAR: + /* This is a read-response, so the requested data may follow when address in request was ok */ + item_count = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(param_tree, hf_s7comm_param_itemcount, tvb, offset, 1, item_count); + offset += 1; + /* Add data tree */ + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + /* Add returned data to data-tree */ + if ((function == S7COMM_SERV_READVAR) && (dlength > 0)) { + offset = s7comm_decode_response_read_data(tvb, data_tree, item_count, offset); + } else if ((function == S7COMM_SERV_WRITEVAR) && (dlength > 0)) { + offset = s7comm_decode_response_write_data(tvb, data_tree, item_count, offset); + } + break; + case S7COMM_SERV_SETUPCOMM: + offset = s7comm_decode_pdu_setup_communication(tvb, param_tree, offset); + break; + case S7COMM_FUNCREQUESTDOWNLOAD: + case S7COMM_FUNCDOWNLOADBLOCK: + case S7COMM_FUNCDOWNLOADENDED: + case S7COMM_FUNCSTARTUPLOAD: + case S7COMM_FUNCUPLOAD: + case S7COMM_FUNCENDUPLOAD: + offset = s7comm_decode_plc_controls_updownload(tvb, pinfo, tree, param_tree, plength, dlength, offset -1, rosctr); + break; + case S7COMM_FUNCPISERVICE: + if (plength >= 2) { + proto_tree_add_bitmask(param_tree, tvb, offset, hf_s7comm_data_blockcontrol_functionstatus, + ett_s7comm_data_blockcontrol_status, s7comm_data_blockcontrol_status_fields, ENC_BIG_ENDIAN); + offset += 1; + } + break; + default: + /* Print unknown part as raw bytes */ + if (plength > 1) { + proto_tree_add_item(param_tree, hf_s7comm_param_data, tvb, offset, plength - 1, ENC_NA); + } + offset += plength - 1; /* 1 byte function code */ + if (dlength > 0) { + /* Add data tree + * First 2 bytes in data seem to be a length indicator of (dlength -4 ), so next 2 bytes + * seem to indicate something else. But I'm not sure, so leave it as it is..... + */ + item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); + data_tree = proto_item_add_subtree(item, ett_s7comm_data); + proto_tree_add_item(data_tree, hf_s7comm_readresponse_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + } + break; + } + } + } + return offset; +} + +/******************************************************************************************************* + ******************************************************************************************************* + * + * S7-Protocol (main tree) + * + ******************************************************************************************************* + *******************************************************************************************************/ +static gboolean +dissect_s7comm(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + void *data _U_) +{ + proto_item *s7comm_item = NULL; + proto_item *s7comm_sub_item = NULL; + proto_tree *s7comm_tree = NULL; + proto_tree *s7comm_header_tree = NULL; + + guint32 offset = 0; + + guint8 rosctr = 0; + guint8 hlength = 10; /* Header 10 Bytes, when type 2 or 3 (Response) -> 12 Bytes */ + guint16 plength = 0; + guint16 dlength = 0; + guint16 errorcode = 0; + + /*----------------- Heuristic Checks - Begin */ + /* 1) check for minimum length */ + if(tvb_captured_length(tvb) < S7COMM_MIN_TELEGRAM_LENGTH) + return FALSE; + /* 2) first byte must be 0x32 */ + if (tvb_get_guint8(tvb, 0) != S7COMM_PROT_ID) + return FALSE; + /* 3) second byte is a type field and only can contain values between 0x01-0x07 (1/2/3/7) */ + if (tvb_get_guint8(tvb, 1) < 0x01 || tvb_get_guint8(tvb, 1) > 0x07) + return FALSE; + /*----------------- Heuristic Checks - End */ + + col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_S7COMM); + col_clear(pinfo->cinfo, COL_INFO); + col_append_sep_str(pinfo->cinfo, COL_INFO, " | ", ""); + + rosctr = tvb_get_guint8(tvb, 1); /* Get the type byte */ + if (rosctr == 2 || rosctr == 3) hlength = 12; /* Header 10 Bytes, when type 2 or 3 (response) -> 12 Bytes */ + + /* display some infos in info-column of wireshark */ + col_append_fstr(pinfo->cinfo, COL_INFO, "ROSCTR:[%-8s]", val_to_str(rosctr, rosctr_names, "Unknown: 0x%02x")); + + s7comm_item = proto_tree_add_item(tree, proto_s7comm, tvb, 0, -1, ENC_NA); + s7comm_tree = proto_item_add_subtree(s7comm_item, ett_s7comm); + + /* insert header tree */ + s7comm_sub_item = proto_tree_add_item(s7comm_tree, hf_s7comm_header, + tvb, offset, hlength, ENC_NA); + + /* insert sub-items in header tree */ + s7comm_header_tree = proto_item_add_subtree(s7comm_sub_item, ett_s7comm_header); + + /* Protocol Identifier, constant 0x32 */ + proto_tree_add_item(s7comm_header_tree, hf_s7comm_header_protid, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* ROSCTR (Remote Operating Service Control) - PDU Type */ + proto_tree_add_uint(s7comm_header_tree, hf_s7comm_header_rosctr, tvb, offset, 1, rosctr); + /* Show pdu type beside the header tree */ + proto_item_append_text(s7comm_header_tree, ": (%s)", val_to_str(rosctr, rosctr_names, "Unknown ROSCTR: 0x%02x")); + offset += 1; + /* Redundancy ID, reserved */ + proto_tree_add_item(s7comm_header_tree, hf_s7comm_header_redid, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* Protocol Data Unit Reference */ + proto_tree_add_item(s7comm_header_tree, hf_s7comm_header_pduref, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* Parameter length */ + plength = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(s7comm_header_tree, hf_s7comm_header_parlg, tvb, offset, 2, plength); + offset += 2; + /* Data length */ + dlength = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(s7comm_header_tree, hf_s7comm_header_datlg, tvb, offset, 2, dlength); + offset += 2; + /* when type is 2 or 3 there are 2 bytes with errorclass and errorcode */ + if (hlength == 12) { + errorcode = tvb_get_ntohs(tvb, offset); /* this uses the same errorcodes (combined) from parameter part */ + proto_tree_add_item(s7comm_header_tree, hf_s7comm_header_errcls, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(s7comm_header_tree, hf_s7comm_header_errcod, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* when there is an error, use the errorcode from parameterpart*/ + if (errorcode > 0) { + s7comm_item = proto_tree_add_item(s7comm_header_tree, hf_s7comm_param_errcod, tvb, offset-2, 2, ENC_BIG_ENDIAN); + proto_item_set_generated (s7comm_item); + } + } + + switch (rosctr) { + case S7COMM_ROSCTR_JOB: + case S7COMM_ROSCTR_ACK_DATA: + s7comm_decode_req_resp(tvb, pinfo, s7comm_tree, plength, dlength, offset, rosctr); + break; + case S7COMM_ROSCTR_USERDATA: + s7comm_decode_ud(tvb, pinfo, s7comm_tree, plength, dlength, offset, tree); + break; + } + /* Add the errorcode from header as last entry in info column */ + if (errorcode > 0) { + col_append_fstr(pinfo->cinfo, COL_INFO, " -> Errorcode:[0x%04x]", errorcode); + } + /* set fence as there may be more than one S7comm PDU in one frame */ + col_set_fence(pinfo->cinfo, COL_INFO); + return TRUE; +} + +/******************************************************************************************************* + * Reassembly of S7COMM + *******************************************************************************************************/ +static void +s7comm_defragment_init(void) +{ + reassembly_table_init(&s7comm_reassembly_table, + &addresses_ports_reassembly_table_functions); +} + +/******************************************************************************************************* + *******************************************************************************************************/ +void +proto_register_s7comm (void) +{ + expert_module_t* expert_s7comm; + + /* format: + * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}. + */ + static hf_register_info hf[] = { + { &hf_s7comm_header, + { "Header", "s7comm.header", FT_NONE, BASE_NONE, NULL, 0x0, + "This is the header of S7 communication", HFILL }}, + { &hf_s7comm_header_protid, + { "Protocol Id", "s7comm.header.protid", FT_UINT8, BASE_HEX, NULL, 0x0, + "Protocol Identification, 0x32 for S7", HFILL }}, + { &hf_s7comm_header_rosctr, + { "ROSCTR", "s7comm.header.rosctr", FT_UINT8, BASE_DEC, VALS(rosctr_names), 0x0, + "Remote Operating Service Control", HFILL }}, + { &hf_s7comm_header_redid, + { "Redundancy Identification (Reserved)", "s7comm.header.redid", FT_UINT16, BASE_HEX, NULL, 0x0, + "Redundancy Identification (Reserved), should be always 0x0000", HFILL }}, + { &hf_s7comm_header_pduref, + { "Protocol Data Unit Reference", "s7comm.header.pduref", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_header_parlg, + { "Parameter length", "s7comm.header.parlg", FT_UINT16, BASE_DEC, NULL, 0x0, + "Specifies the entire length of the parameter block in bytes", HFILL }}, + { &hf_s7comm_header_datlg, + { "Data length", "s7comm.header.datlg", FT_UINT16, BASE_DEC, NULL, 0x0, + "Specifies the entire length of the data block in bytes", HFILL }}, + { &hf_s7comm_header_errcls, + { "Error class", "s7comm.header.errcls", FT_UINT8, BASE_HEX, VALS(errcls_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_header_errcod, + { "Error code", "s7comm.header.errcod", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_param, + { "Parameter", "s7comm.param", FT_NONE, BASE_NONE, NULL, 0x0, + "This is the parameter part of S7 communication", HFILL }}, + { &hf_s7comm_param_errcod, + { "Error code", "s7comm.param.errcod", FT_UINT16, BASE_HEX | BASE_EXT_STRING, ¶m_errcode_names_ext, 0x0, + NULL, HFILL }}, + { &hf_s7comm_param_service, + { "Function", "s7comm.param.func", FT_UINT8, BASE_HEX, VALS(param_functionnames), 0x0, + "Indicates the function of parameter/data", HFILL }}, + { &hf_s7comm_param_maxamq_calling, + { "Max AmQ (parallel jobs with ack) calling", "s7comm.param.maxamq_calling", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_param_maxamq_called, + { "Max AmQ (parallel jobs with ack) called", "s7comm.param.maxamq_called", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_param_setup_reserved1, + { "Reserved", "s7comm.param.setup_reserved1", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_param_neg_pdu_length, + { "PDU length", "s7comm.param.pdu_length", FT_UINT16, BASE_DEC, NULL, 0x0, + "Negotiated PDU length", HFILL }}, + { &hf_s7comm_param_itemcount, + { "Item count", "s7comm.param.itemcount", FT_UINT8, BASE_DEC, NULL, 0x0, + "Number of Items in parameter/data part", HFILL }}, + { &hf_s7comm_param_data, + { "Parameter data", "s7comm.param.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_param_item, + { "Item", "s7comm.param.item", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_param_subitem, + { "Subitem", "s7comm.param.subitem", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_varspec, + { "Variable specification", "s7comm.param.item.varspec", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_varspec_length, + { "Length of following address specification", "s7comm.param.item.varspec_length", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_syntax_id, + { "Syntax Id", "s7comm.param.item.syntaxid", FT_UINT8, BASE_HEX, VALS(item_syntaxid_names), 0x0, + "Syntax Id, format type of following address specification", HFILL }}, + { &hf_s7comm_item_transport_size, + { "Transport size", "s7comm.param.item.transp_size", FT_UINT8, BASE_DEC, VALS(item_transportsizenames), 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_length, + { "Length", "s7comm.param.item.length", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_db, + { "DB number", "s7comm.param.item.db", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_area, + { "Area", "s7comm.param.item.area", FT_UINT8, BASE_HEX, VALS(item_areanames), 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_address, + { "Address", "s7comm.param.item.address", FT_UINT24, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_address_byte, + { "Byte Address", "s7comm.param.item.address.byte", FT_UINT24, BASE_DEC, NULL, 0x07fff8, + NULL, HFILL }}, + { &hf_s7comm_item_address_bit, + { "Bit Address", "s7comm.param.item.address.bit", FT_UINT24, BASE_DEC, NULL, 0x000007, + NULL, HFILL }}, + { &hf_s7comm_item_address_nr, + { "Number (T/C/BLOCK)", "s7comm.param.item.address.number", FT_UINT24, BASE_DEC, NULL, 0x00ffff, + NULL, HFILL }}, + /* Special variable read with Syntax-Id 0xb0 (DBREAD) */ + { &hf_s7comm_item_dbread_numareas, + { "Number of areas", "s7comm.param.item.dbread.numareas", FT_UINT8, BASE_DEC, NULL, 0x0, + "Number of area specifications following", HFILL }}, + { &hf_s7comm_item_dbread_length, + { "Bytes to read", "s7comm.param.item.dbread.length", FT_UINT8, BASE_DEC, NULL, 0x0, + "Number of bytes to read", HFILL }}, + { &hf_s7comm_item_dbread_db, + { "DB number", "s7comm.param.item.dbread.db", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_dbread_startadr, + { "Start address", "s7comm.param.item.dbread.startaddress", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + /* Reading frequency inverter parameters via routing */ + { &hf_s7comm_item_driveesany_unknown1, + { "DriveES Unknown 1", "s7comm.param.item.driveesany.unknown1", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_driveesany_unknown2, + { "DriveES Unknown 2", "s7comm.param.item.driveesany.unknown2", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_driveesany_unknown3, + { "DriveES Unknown 3", "s7comm.param.item.driveesany.unknown3", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_driveesany_parameter_nr, + { "DriveES Parameter number", "s7comm.param.item.driveesany.parameternr", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_driveesany_parameter_idx, + { "DriveES Parameter index", "s7comm.param.item.driveesany.parameteridx", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + /* NCK access with Syntax-Id 0x82 */ + { &hf_s7comm_item_nck_areaunit, + { "NCK Area/Unit", "s7comm.param.item.nck.area_unit", FT_UINT8, BASE_HEX, NULL, 0x0, + "NCK Area/Unit: Bitmask aaauuuuu: a=area, u=unit", HFILL }}, + { &hf_s7comm_item_nck_area, + { "NCK Area", "s7comm.param.item.nck.area", FT_UINT8, BASE_DEC, VALS(nck_area_names), 0xe0, + NULL, HFILL }}, + { &hf_s7comm_item_nck_unit, + { "NCK Unit", "s7comm.param.item.nck.unit", FT_UINT8, BASE_DEC, NULL, 0x1f, + NULL, HFILL }}, + { &hf_s7comm_item_nck_column, + { "NCK Column number", "s7comm.param.item.nck.column", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_nck_line, + { "NCK Line number", "s7comm.param.item.nck.line", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_nck_module, + { "NCK Module", "s7comm.param.item.nck.module", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &nck_module_names_ext, 0x0, + NULL, HFILL }}, + { &hf_s7comm_item_nck_linecount, + { "NCK Linecount", "s7comm.param.item.nck.linecount", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_data, + { "Data", "s7comm.data", FT_NONE, BASE_NONE, NULL, 0x0, + "This is the data part of S7 communication", HFILL }}, + { &hf_s7comm_data_returncode, + { "Return code", "s7comm.data.returncode", FT_UINT8, BASE_HEX, VALS(s7comm_item_return_valuenames), 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_transport_size, + { "Transport size", "s7comm.data.transportsize", FT_UINT8, BASE_HEX, VALS(data_transportsizenames), 0x0, + "Data type / Transport size. If 3, 4 or 5 the following length gives the number of bits, otherwise the number of bytes.", HFILL }}, + { &hf_s7comm_data_length, + { "Length", "s7comm.data.length", FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of data", HFILL }}, + + { &hf_s7comm_data_item, + { "Item", "s7comm.data.item", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_readresponse_data, + { "Data", "s7comm.resp.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_fillbyte, + { "Fill byte", "s7comm.data.fillbyte", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_userdata_data, + { "Data", "s7comm.data.userdata", FT_BYTES, BASE_NONE, NULL, 0x0, + "Userdata data", HFILL }}, + + /* Userdata parameter 8/12 Bytes len*/ + { &hf_s7comm_userdata_param_type, + { "Type", "s7comm.param.userdata.type", FT_UINT8, BASE_DEC, VALS(userdata_type_names), 0xc0, + "Type of parameter", HFILL }}, + { &hf_s7comm_userdata_param_funcgroup, + { "Function group", "s7comm.param.userdata.funcgroup", FT_UINT8, BASE_DEC, VALS(userdata_functiongroup_names), 0x3f, + NULL, HFILL }}, + + { &hf_s7comm_userdata_param_subfunc_prog, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_tis_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_cyclic, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_cyclic_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_block, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_block_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_cpu, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_cpu_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_sec, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_sec_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_time, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_time_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_ncprg, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_ncprg_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_userdata_param_subfunc_drr, + { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_drr_subfunc_names), 0x0, + NULL, HFILL }}, + + { &hf_s7comm_userdata_param_seq_num, + { "Sequence number", "s7comm.param.userdata.seq_num", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_userdata_param_dataunitref, + { "Data unit reference number", "s7comm.param.userdata.dataunitref", FT_UINT8, BASE_DEC, NULL, 0x0, + "Data unit reference number if PDU is fragmented", HFILL }}, + + { &hf_s7comm_userdata_param_dataunit, + { "Last data unit", "s7comm.param.userdata.lastdataunit", FT_UINT8, BASE_HEX, VALS(userdata_lastdataunit_names), 0x0, + NULL, HFILL }}, + + /* block functions / info */ + { &hf_s7comm_ud_blockinfo_block_type, + { "Block type", "s7comm.blockinfo.blocktype", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_block_cnt, + { "Block count", "s7comm.blockinfo.block_count", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_block_num, + { "Block number", "s7comm.blockinfo.block_num", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_block_flags, + { "Block flags (unknown)", "s7comm.blockinfo.flags", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_block_lang, + { "Block language", "s7comm.blockinfo.block_lang", FT_UINT8, BASE_DEC, VALS(blocklanguage_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_block_num_ascii, + { "Block number", "s7comm.data.blockinfo.block_number", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_filesys, + { "Filesystem", "s7comm.data.blockinfo.filesys", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_res_infolength, + { "Length of Info", "s7comm.blockinfo.res_infolength", FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of Info in bytes", HFILL }}, + { &hf_s7comm_ud_blockinfo_res_unknown2, + { "Unknown blockinfo 2", "s7comm.blockinfo.res_unknown2", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_res_const3, + { "Constant 3", "s7comm.blockinfo.res_const3", FT_STRING, BASE_NONE, NULL, 0x0, + "Possible constant 3, seems to be always 'pp'", HFILL }}, + { &hf_s7comm_ud_blockinfo_res_unknown, + { "Unknown byte(s) blockinfo", "s7comm.blockinfo.res_unknown", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_subblk_type, + { "Subblk type", "s7comm.blockinfo.subblk_type", FT_UINT8, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_load_mem_len, + { "Length load memory", "s7comm.blockinfo.load_mem_len", FT_UINT32, BASE_DEC, NULL, 0x0, + "Length of load memory in bytes", HFILL }}, + { &hf_s7comm_ud_blockinfo_blocksecurity, + { "Block Security", "s7comm.blockinfo.blocksecurity", FT_UINT32, BASE_DEC, VALS(blocksecurity_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_interface_timestamp, + { "Interface timestamp", "s7comm.blockinfo.interface_timestamp", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_code_timestamp, + { "Code timestamp", "s7comm.blockinfo.code_timestamp", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_ssb_len, + { "SSB length", "s7comm.blockinfo.ssb_len", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_add_len, + { "ADD length", "s7comm.blockinfo.add_len", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_localdata_len, + { "Localdata length", "s7comm.blockinfo.localdata_len", FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of localdata in bytes", HFILL }}, + { &hf_s7comm_ud_blockinfo_mc7_len, + { "MC7 code length", "s7comm.blockinfo.mc7_len", FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of MC7 code in bytes", HFILL }}, + { &hf_s7comm_ud_blockinfo_author, + { "Author", "s7comm.blockinfo.author", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_family, + { "Family", "s7comm.blockinfo.family", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_headername, + { "Name (Header)", "s7comm.blockinfo.headername", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_headerversion, + { "Version (Header)", "s7comm.blockinfo.headerversion", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_checksum, + { "Block checksum", "s7comm.blockinfo.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_reserved1, + { "Reserved 1", "s7comm.blockinfo.reserved1", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ud_blockinfo_reserved2, + { "Reserved 2", "s7comm.blockinfo.reserved2", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + /* Flags in blockinfo response */ + { &hf_s7comm_userdata_blockinfo_flags, + { "Block flags", "s7comm.param.userdata.blockinfo.flags", FT_UINT8, BASE_HEX, NULL, 0xff, + "Some block configuration flags", HFILL }}, + /* Bit : 0 -> DB Linked = true */ + { &hf_s7comm_userdata_blockinfo_linked, + { "Linked", "s7comm.param.userdata.blockinfo.linked", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL }}, + /* Bit : 1 -> Standard block = true */ + { &hf_s7comm_userdata_blockinfo_standard_block, + { "Standard block", "s7comm.param.userdata.blockinfo.standard_block", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL }}, + /* Bit : 5 -> DB Non Retain = true */ + { &hf_s7comm_userdata_blockinfo_nonretain, + { "Non Retain", "s7comm.param.userdata.blockinfo.nonretain", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL }}, + + /* Programmer commands / Test and installation (TIS) functions */ + { &hf_s7comm_tis_parameter, + { "TIS Parameter", "s7comm.tis.parameter", FT_NONE, BASE_NONE, NULL, 0x0, + "TIS Test and Installation: Parameter", HFILL }}, + { &hf_s7comm_tis_data, + { "TIS Data", "s7comm.cpu.tis.data", FT_NONE, BASE_NONE, NULL, 0x0, + "TIS Test and Installation: Data", HFILL }}, + { &hf_s7comm_tis_parametersize, + { "TIS Parameter size", "s7comm.tis.parametersize", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_datasize, + { "TIS Data size", "s7comm.tis.datasize", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param1, + { "TIS Parameter 1", "s7comm.tis.param1", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param2, + { "TIS Parameter 2 - Trigger type", "s7comm.tis.param2", FT_UINT16, BASE_DEC, VALS(tis_param2_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param3, + { "TIS Parameter 3 - Trigger frequency", "s7comm.tis.param3", FT_UINT16, BASE_DEC, VALS(tis_param3_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_answersize, + { "TIS Parameter 4 - Answer size", "s7comm.tis.answersize", FT_UINT16, BASE_DEC, NULL, 0x0, + "TIS Answer size: Expected data size of PLC answer to this job", HFILL }}, + { &hf_s7comm_tis_param5, + { "TIS Parameter 5", "s7comm.tis.param5", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param6, + { "TIS Parameter 6", "s7comm.tis.param6", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param7, + { "TIS Parameter 7", "s7comm.tis.param7", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param8, + { "TIS Parameter 8", "s7comm.tis.param8", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param9, + { "TIS Parameter 9", "s7comm.tis.param9", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_trgevent, + { "TIS Parameter 10 - Trigger event", "s7comm.varstat.trgevent", FT_UINT16, BASE_HEX, VALS(userdata_varstat_trgevent_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_res_param1, + { "TIS Response Parameter 1", "s7comm.tis.res.param1", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_res_param2, + { "TIS Response Parameter 2", "s7comm.tis.res.param2", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_job_function, + { "Job function", "s7comm.tis.job.function", FT_UINT8, BASE_DEC, VALS(userdata_tis_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_job_seqnr, + { "Job reference sequence number", "s7comm.tis.job.response_seq_num", FT_UINT8, BASE_DEC, NULL, 0x0, + "Job reference sequence number (find function setup with s7comm.param.userdata.seq_num)", HFILL }}, + { &hf_s7comm_tis_job_reserved, + { "Job Reserved / Unknown", "s7comm.tis.job.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_blocktype, + { "Interrupted block type", "s7comm.tis.interrupted.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_blocknr, + { "Interrupted block number", "s7comm.tis.interrupted.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_address, + { "Interrupted code address", "s7comm.tis.interrupted.address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_prioclass, + { "Interrupted priority class", "s7comm.tis.interrupted.priorityclass", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_continued_blocktype, + { "Continued block type", "s7comm.tis.continued.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_continued_blocknr, + { "Continued block number", "s7comm.tis.continued.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_continued_address, + { "Continued code address", "s7comm.tis.continued.address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_blocktype, + { "Breakpoint block type", "s7comm.tis.breakpoint.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_blocknr, + { "Breakpoint block number", "s7comm.tis.breakpoint.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_address, + { "Breakpoint code address", "s7comm.tis.breakpoint.address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_reserved, + { "Breakpoint Reserved / Unknown", "s7comm.tis.breakpoint.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_tis_p_callenv, + { "Call environment setup", "s7comm.tis.callenv_setup", FT_UINT16, BASE_DEC, VALS(tis_p_callenv_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond, + { "Call condition", "s7comm.tis.callenv_cond", FT_UINT16, BASE_DEC, VALS(tis_p_callcond_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond_blocktype, + { "Call condition block type", "s7comm.tis.callenv_cond_blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond_blocknr, + { "Call condition block number", "s7comm.tis.callenv_cond_blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond_address, + { "Call condition code address", "s7comm.tis.callenv_cond_blockaddress", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_tis_register_db1_type, + { "Register DB1 content type", "s7comm.tis.db1.type", FT_UINT8, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_db2_type, + { "Register DB2 content type", "s7comm.tis.db2.type", FT_UINT8, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_db1_nr, + { "Register DB1 block number", "s7comm.tis.db1.number", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_db2_nr, + { "Register DB2 block number", "s7comm.tis.db2.number", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu1, + { "Register ACCU1", "s7comm.tis.accu1", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu2, + { "Register ACCU2", "s7comm.tis.accu2", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu3, + { "Register ACCU3", "s7comm.tis.accu3", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu4, + { "Register ACCU4", "s7comm.tis.accu4", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_ar1, + { "Register AR1", "s7comm.tis.ar1", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_ar2, + { "Register AR2", "s7comm.tis.ar2", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_stw, + { "Register STW", "s7comm.tis.stw", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_exithold_until, + { "Exit HOLD state until", "s7comm.tis.exithold_until", FT_UINT8, BASE_DEC, VALS(tis_exithold_until_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_exithold_res1 , + { "Exit HOLD Reserved / Unknown", "s7comm.tis.exithold_res1", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_bstack_nest_depth, + { "BSTACK nesting depth", "s7comm.tis.bstack.neting_depth", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_bstack_reserved, + { "BSTACK Reserved / Unknown", "s7comm.tis.bstack.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_istack_reserved, + { "ISTACK Reserved / Unknown", "s7comm.tis.istack.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_lstack_reserved, + { "LSTACK Reserved / Unknown", "s7comm.tis.lstack.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_lstack_size, + { "Localdata stack size", "s7comm.tis.lstack.size", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_lstack_data, + { "Localdata stack data", "s7comm.tis.lstack.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_flagsunknown, + { "Blockstat flags", "s7comm.tis.blockstat.flagsunknown", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_number_of_lines, + { "Number of lines", "s7comm.tis.blockstat.number_of_lines", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_line_address, + { "Address", "s7comm.tis.blockstat.line_address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_data, + { "Blockstatus data", "s7comm.tis.blockstat.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_reserved, + { "Blockstatus Reserved / Unknown", "s7comm.tis.blockstat.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + /* Organization block local data */ + { &hf_s7comm_ob_ev_class, + { "OB Event class", "s7comm.ob.ev_class", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Event class (Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1))", HFILL }}, + { &hf_s7comm_ob_scan_1, + { "OB Scan 1", "s7comm.ob.scan_1", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Scan 1 (1=Cold restart scan 1 of OB 1), (3=Scan 2-n of OB 1)", HFILL }}, + { &hf_s7comm_ob_strt_inf, + { "OB Start info", "s7comm.ob.strt_info", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Start info (OB n has started)", HFILL }}, + { &hf_s7comm_ob_flt_id, + { "OB Fault identification code", "s7comm.ob.flt_id", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_priority, + { "OB Priority", "s7comm.ob.priority", FT_UINT8, BASE_DEC, NULL, 0x0, + "OB Priority (1 is lowest)", HFILL }}, + { &hf_s7comm_ob_number, + { "OB Number", "s7comm.ob.number", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_reserved_1, + { "OB Reserved 1", "s7comm.ob.reserved_1", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Reserved 1 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_2, + { "OB Reserved 2", "s7comm.ob.reserved_2", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Reserved 2 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_3, + { "OB Reserved 3", "s7comm.ob.reserved_3", FT_UINT16, BASE_HEX, NULL, 0x0, + "OB Reserved 3 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_4, + { "OB Reserved 4", "s7comm.ob.reserved_4", FT_UINT16, BASE_HEX, NULL, 0x0, + "OB Reserved 4 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_4_dw, + { "OB Reserved 4", "s7comm.ob.reserved_4_dw", FT_UINT32, BASE_HEX, NULL, 0x0, + "OB Reserved 4 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_prev_cycle, + { "OB Cycle time of previous OB scan (ms)", "s7comm.ob.prev_cycle", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_min_cycle, + { "OB Minimum cycle time of OB (ms)", "s7comm.ob.min_cycle", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_max_cycle, + { "OB Maximum cycle time of OB (ms)", "s7comm.ob.max_cycle", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_period_exe, + { "OB Period of execution", "s7comm.ob.period_exe", FT_UINT16, BASE_HEX, NULL, 0x0, + "OB Period of execution (once, per minute/hour/day/week/month/year)", HFILL }}, + { &hf_s7comm_ob_sign, + { "OB Identifier input (SIGN) attached to SRT_DINT", "s7comm.ob.sign", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_dtime, + { "OB Delay time (DTIME) input to SRT_DINT instruction", "s7comm.ob.dtime", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_phase_offset, + { "OB Phase offset (ms)", "s7comm.ob.phase_offset", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_exec_freq, + { "OB Frequency of execution (ms)", "s7comm.ob.exec_freq", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_io_flag, + { "OB IO flags", "s7comm.ob.io_flag", FT_UINT16, BASE_DEC, NULL, 0x0, + "OB IO flags (0x54=input module, 0x55=output module)", HFILL }}, + { &hf_s7comm_ob_mdl_addr, + { "OB Base address of module initiating interrupt", "s7comm.ob.mdl_addr", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_point_addr, + { "OB Address of interrupt point on module", "s7comm.ob.point_addr", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_inf_len, + { "OB Length of information", "s7comm.ob.inf_len", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_alarm_type, + { "OB Type of alarm", "s7comm.ob.alarm_type", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_alarm_slot, + { "OB Slot", "s7comm.ob.alarm_slot", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_alarm_spec, + { "OB Specifier", "s7comm.ob.alarm_spec", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_error_info, + { "OB Error information on event", "s7comm.ob.error_info", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ev_class, + { "OB Class of event causing error", "s7comm.ob.err_ev_class", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ev_num, + { "OB Number of event causing error", "s7comm.ob.err_ev_num", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ob_priority, + { "OB Priority of OB causing error", "s7comm.ob.err_ob_priority", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ob_num, + { "OB Number of OB causing error", "s7comm.ob.err_ob_num", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_rack_cpu, + { "OB Rack / CPU number", "s7comm.ob.rack_cpu", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_8x_fault_flags, + { "OB 8x Fault flags", "s7comm.ob.8x_fault_flags", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mdl_type_b, + { "OB Type of module", "s7comm.ob.mdl_type_b", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mdl_type_w, + { "OB Module type with point fault", "s7comm.ob.mdl_type_w", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_rack_num, + { "OB Number of rack that has module with point fault", "s7comm.ob.rack_num", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_racks_flt, + { "OB Racks in fault", "s7comm.ob.racks_flt", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_strtup, + { "OB Method of startup", "s7comm.ob.strtup", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_stop, + { "OB Event that caused CPU to stop", "s7comm.ob.stop", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_strt_info, + { "OB Information on how system started", "s7comm.ob.strt_info", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_sw_flt, + { "OB Software programming fault", "s7comm.ob.sw_flt", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_blk_type, + { "OB Type of block fault occurred in", "s7comm.ob.blk_type", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_flt_reg, + { "OB Specific register that caused fault", "s7comm.ob.flt_reg", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_flt_blk_num, + { "OB Number of block that programming fault occurred in", "s7comm.ob.flt_blk_num", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_prg_addr, + { "OB Address in block where programming fault occurred", "s7comm.ob.prg_addr", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mem_area, + { "OB Memory area where access error occurred", "s7comm.ob.mem_area", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mem_addr, + { "OB Memory address where access error occurred", "s7comm.ob.mem_addr", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_diagdata_req_block_type, + { "Block type", "s7comm.diagdata.req.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_diagdata_req_block_num, + { "Block number", "s7comm.diagdata.req.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_diagdata_req_startaddr_awl, + { "Start address AWL", "s7comm.diagdata.req.startaddr_awl", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_diagdata_req_saz, + { "Step address counter (SAZ)", "s7comm.diagdata.req.saz", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + /* Flags for requested registers in diagnostic data telegrams */ + { &hf_s7comm_diagdata_registerflag, + { "Registers", "s7comm.diagdata.register", FT_UINT8, BASE_HEX, NULL, 0x00, + "Requested registers", HFILL }}, + { &hf_s7comm_diagdata_registerflag_stw, + { "STW", "s7comm.diagdata.register.stw", FT_BOOLEAN, 8, NULL, 0x01, + "STW / Status word", HFILL }}, + { &hf_s7comm_diagdata_registerflag_accu1, + { "ACCU1", "s7comm.diagdata.register.accu1", FT_BOOLEAN, 8, NULL, 0x02, + "ACCU1 / Accumulator 1", HFILL }}, + { &hf_s7comm_diagdata_registerflag_accu2, + { "ACCU2", "s7comm.diagdata.register.accu2", FT_BOOLEAN, 8, NULL, 0x04, + "ACCU2 / Accumulator 2", HFILL }}, + { &hf_s7comm_diagdata_registerflag_ar1, + { "AR1", "s7comm.diagdata.register.ar1", FT_BOOLEAN, 8, NULL, 0x08, + "AR1 / Addressregister 1", HFILL }}, + { &hf_s7comm_diagdata_registerflag_ar2, + { "AR2", "s7comm.diagdata.register.ar2", FT_BOOLEAN, 8, NULL, 0x10, + "AR2 / Addressregister 2", HFILL }}, + { &hf_s7comm_diagdata_registerflag_db1, + { "DB1", "s7comm.diagdata.register.db1", FT_BOOLEAN, 8, NULL, 0x20, + "DB1 (global)/ Datablock register 1", HFILL }}, + { &hf_s7comm_diagdata_registerflag_db2, + { "DB2", "s7comm.diagdata.register.db2", FT_BOOLEAN, 8, NULL, 0x40, + "DB2 (instance) / Datablock register 2", HFILL }}, + + /* timefunction: s7 timestamp */ + { &hf_s7comm_data_ts, + { "S7 Timestamp", "s7comm.data.ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00, + "S7 Timestamp, BCD coded", HFILL }}, + { &hf_s7comm_data_ts_reserved, + { "S7 Timestamp - Reserved", "s7comm.data.ts_reserved", FT_UINT8, BASE_HEX, NULL, 0x00, + "S7 Timestamp: Reserved byte", HFILL }}, + { &hf_s7comm_data_ts_year1, + { "S7 Timestamp - Year 1", "s7comm.data.ts_year1", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded year thousands/hundreds, should be ignored (19 or 20)", HFILL }}, + { &hf_s7comm_data_ts_year2, + { "S7 Timestamp - Year 2", "s7comm.data.ts_year2", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded year, if 00...89 then it's 2000...2089, else 1990...1999", HFILL }}, + { &hf_s7comm_data_ts_month, + { "S7 Timestamp - Month", "s7comm.data.ts_month", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded month", HFILL }}, + { &hf_s7comm_data_ts_day, + { "S7 Timestamp - Day", "s7comm.data.ts_day", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded day", HFILL }}, + { &hf_s7comm_data_ts_hour, + { "S7 Timestamp - Hour", "s7comm.data.ts_hour", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded hour", HFILL }}, + { &hf_s7comm_data_ts_minute, + { "S7 Timestamp - Minute", "s7comm.data.ts_minute", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded minute", HFILL }}, + { &hf_s7comm_data_ts_second, + { "S7 Timestamp - Second", "s7comm.data.ts_second", FT_UINT8, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded second", HFILL }}, + { &hf_s7comm_data_ts_millisecond, + { "S7 Timestamp - Milliseconds", "s7comm.data.ts_millisecond", FT_UINT16, BASE_DEC, NULL, 0x00, + "S7 Timestamp: BCD coded milliseconds (left 3 nibbles)", HFILL }}, + { &hf_s7comm_data_ts_weekday, + { "S7 Timestamp - Weekday", "s7comm.data.ts_weekday", FT_UINT16, BASE_DEC, VALS(weekdaynames), 0x000f, + "S7 Timestamp: Weekday number (right nibble, 1=Su,2=Mo,..)", HFILL }}, + + /* Function 0x28 (PI service) and 0x29 */ + { &hf_s7comm_piservice_unknown1, + { "Unknown bytes", "s7comm.param.pistart.unknown1", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_piservice_parameterblock_len, + { "Parameter block length", "s7comm.param.pistart.parameterblock_len", FT_UINT16, BASE_DEC, NULL, 0x0, + "Length of Parameter block in bytes", HFILL }}, + { &hf_s7comm_piservice_parameterblock, + { "Parameter block", "s7comm.param.pistart.parameterblock", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_piservice_servicename, + { "PI (program invocation) Service", "s7comm.param.pistart.servicename", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + + /* PI Service parameters for NC services */ + { &hf_s7comm_piservice_string_len, + { "String length", "s7comm.param.pi.n_x.string_len", FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of the following string. If LengthByte + Stringlen is uneven, a fillbyte is added", HFILL }}, + { &hf_s7comm_pi_n_x_addressident, + { "Addressidentification", "s7comm.param.pi.n_x.addressident", FT_STRING, BASE_NONE, NULL, 0x0, + "Addressidentification (RangeID / Index)", HFILL }}, + { &hf_s7comm_pi_n_x_filename, + { "Filename", "s7comm.param.pi.n_x.filename", FT_STRING, BASE_NONE, NULL, 0x0, + "Name of the file or directory", HFILL }}, + { &hf_s7comm_pi_n_x_editwindowname, + { "Editor Window Name", "s7comm.param.pi.n_x.editwindowname", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pi_n_x_password, + { "Password", "s7comm.param.pi.n_x.password", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pi_n_x_seekpointer, + { "Seek pointer", "s7comm.param.pi.n_x.seekpointer", FT_STRING, BASE_NONE, NULL, 0x0, + "SeekPointer string with exact 9 digit/character(s)", HFILL }}, + { &hf_s7comm_pi_n_x_windowsize, + { "Window size", "s7comm.param.pi.n_x.windowsize", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pi_n_x_comparestring, + { "Compare String", "s7comm.param.pi.n_x.comparestring", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pi_n_x_skipcount, + { "Skip Count", "s7comm.param.pi.n_x.skipcount", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pi_n_x_interruptnr, + { "Interrupt Number", "s7comm.param.pi.n_x.interruptnr", FT_STRING, BASE_NONE, NULL, 0x0, + "Interrupt Number: Interrupt number corresponds to the input number which caused the interrupt" , HFILL }}, + { &hf_s7comm_pi_n_x_priority, + { "Priority", "s7comm.param.pi.n_x.priority", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_liftfast, + { "Liftfast", "s7comm.param.pi.n_x.liftfast", FT_STRING, BASE_NONE, NULL, 0x0, + "Liftfast: Indicates whether an interrupt routine should simultaneously cause a fast lift-off motion" , HFILL }}, + { &hf_s7comm_pi_n_x_blsync, + { "Blsync", "s7comm.param.pi.n_x.blsync", FT_STRING, BASE_NONE, NULL, 0x0, + "Blsync: Indicates whether the interrupt has to be synchronized to the next block end" , HFILL }}, + { &hf_s7comm_pi_n_x_magnr, + { "Magnr", "s7comm.param.pi.n_x.magnr", FT_STRING, BASE_NONE, NULL, 0x0, + "Magnr: Magazine number" , HFILL }}, + { &hf_s7comm_pi_n_x_dnr, + { "DNr", "s7comm.param.pi.n_x.dnr", FT_STRING, BASE_NONE, NULL, 0x0, + "DNr: D number" , HFILL }}, + { &hf_s7comm_pi_n_x_spindlenumber, + { "Spindle Number", "s7comm.param.pi.n_x.spindlenumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pi_n_x_wznr, + { "WZ-Nr", "s7comm.param.pi.n_x.wznr", FT_STRING, BASE_NONE, NULL, 0x0, + "WZ-Nr: Tool number" , HFILL }}, + { &hf_s7comm_pi_n_x_class, + { "Class", "s7comm.param.pi.n_x.class", FT_STRING, BASE_NONE, NULL, 0x0, + "Class: Classify machine data" , HFILL }}, + { &hf_s7comm_pi_n_x_tnr, + { "TNr", "s7comm.param.pi.n_x.tnr", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_toolnumber, + { "Tool Number", "s7comm.param.pi.n_x.toolnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_cenumber, + { "CE-Number", "s7comm.param.pi.n_x.cenumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_datablocknumber, + { "Datablock Number", "s7comm.param.pi.n_x.datablocknumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_firstcolumnnumber, + { "First Column Number", "s7comm.param.pi.n_x.firstcolumnnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_lastcolumnnumber, + { "Last Column Number", "s7comm.param.pi.n_x.lastcolumnnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_firstrownumber, + { "First Row Number", "s7comm.param.pi.n_x.firstrownnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_lastrownumber, + { "Last Row Number", "s7comm.param.pi.n_x.lastrownnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_direction, + { "Direction", "s7comm.param.pi.n_x.direction", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_sourcefilename, + { "Source-Filename", "s7comm.param.pi.n_x.sourcefilename", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_destinationfilename, + { "Destination-Filename", "s7comm.param.pi.n_x.destinationfilename", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_channelnumber, + { "Channel Number", "s7comm.param.pi.n_x.channelnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_protection, + { "Protection", "s7comm.param.pi.n_x.protection", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_oldfilename, + { "Old Filename", "s7comm.param.pi.n_x.oldfilename", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_newfilename, + { "New Filename", "s7comm.param.pi.n_x.newfilename", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_findmode, + { "Findmode", "s7comm.param.pi.n_x.findmode", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_switch, + { "Switch", "s7comm.param.pi.n_x.switch", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_functionnumber, + { "Function Number", "s7comm.param.pi.n_x.functionnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_semaphorevalue, + { "Semaphore Value", "s7comm.param.pi.n_x.semaphorevalue", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_onoff, + { "OnOff", "s7comm.param.pi.n_x.onoff", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_mode, + { "Mode", "s7comm.param.pi.n_x.mode", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_factor, + { "Factor", "s7comm.param.pi.n_x.factor", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_passwordlevel, + { "Password Level", "s7comm.param.pi.n_x.passwordlevel", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_linenumber, + { "Line Number", "s7comm.param.pi.n_x.linenumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_weargroup, + { "Wear Group", "s7comm.param.pi.n_x.weargroup", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_toolstatus, + { "Tool Status", "s7comm.param.pi.n_x.toolstatus", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_wearsearchstrat, + { "Search Strategy", "s7comm.param.pi.n_x.wearsearchstrat", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_toolid, + { "Tool ID", "s7comm.param.pi.n_x.toolid", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_duplonumber, + { "Duplo Number", "s7comm.param.pi.n_x.duplonumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_edgenumber, + { "Edge Number", "s7comm.param.pi.n_x.edgenumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placenr, + { "Place Number", "s7comm.param.pi.n_x.placenr", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placerefnr, + { "Place Reference Number", "s7comm.param.pi.n_x.placerefnr", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_magrefnr, + { "Magazine Reference Number", "s7comm.param.pi.n_x.magrefnr", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placenrfrom, + { "Place Number from", "s7comm.param.pi.n_x.placenrfrom", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_magnrfrom, + { "Magazine Number from", "s7comm.param.pi.n_x.magnrfrom", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placenrto, + { "Place Number to", "s7comm.param.pi.n_x.placenrto", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_magnrto, + { "Magazine Number to", "s7comm.param.pi.n_x.magnrto", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_halfplacesleft, + { "Half places left", "s7comm.param.pi.n_x.halfplacesleft", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_halfplacesright, + { "Half places right", "s7comm.param.pi.n_x.halfplacesright", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_halfplacesup, + { "Half places up", "s7comm.param.pi.n_x.halfplacesup", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_halfplacesdown, + { "Half places down", "s7comm.param.pi.n_x.halfplacesdown", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placetype, + { "Place type index", "s7comm.param.pi.n_x.placetype", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_searchdirection, + { "Search direction", "s7comm.param.pi.n_x.searchdirection", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_toolname, + { "Tool Name", "s7comm.param.pi.n_x.toolname", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placenrsource, + { "Place Number Source", "s7comm.param.pi.n_x.placenrsource", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_magnrsource, + { "Magazine Number Source", "s7comm.param.pi.n_x.magnrsource", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_placenrdestination, + { "Place Number Destination", "s7comm.param.pi.n_x.placenrdestination", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_magnrdestination, + { "Magazine Number Destination", "s7comm.param.pi.n_x.magnrdestination", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_incrementnumber, + { "Increment Number", "s7comm.param.pi.n_x.incrementnumber", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_monitoringmode, + { "Monitoring mode", "s7comm.param.pi.n_x.monitoringmode", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + { &hf_s7comm_pi_n_x_kindofsearch, + { "Kind of search", "s7comm.param.pi.n_x.kindofsearch", FT_STRING, BASE_NONE, NULL, 0x0, + NULL , HFILL }}, + + { &hf_s7comm_data_pi_inse_unknown, + { "Unknown byte", "s7comm.param.pi.inse.unknown", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_data_plccontrol_argument, + { "Argument", "s7comm.param.pistart.argument", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_plccontrol_block_cnt, + { "Number of blocks", "s7comm.data.plccontrol.block_cnt", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_plccontrol_part2_len, + { "Length part 2", "s7comm.data.plccontrol.part2_len", FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of part 2 in bytes", HFILL }}, + + /* block control functions */ + { &hf_s7comm_data_blockcontrol_unknown1, + { "Unknown byte(s) in blockcontrol", "s7comm.data.blockcontrol.unknown1", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_errorcode, + { "Errorcode", "s7comm.data.blockcontrol.errorcode", FT_UINT16, BASE_HEX, NULL, 0x0, + "Errorcode, 0 on success", HFILL }}, + { &hf_s7comm_data_blockcontrol_uploadid, + { "UploadID", "s7comm.data.blockcontrol.uploadid", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_file_ident, + { "File identifier", "s7comm.data.blockcontrol.file_identifier", FT_STRING, BASE_NONE, NULL, 0x0, + "File identifier: '_'=complete module; '$'=Module header for up-loading", HFILL }}, + { &hf_s7comm_data_blockcontrol_block_type, + { "Block type", "s7comm.data.blockcontrol.block_type", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_block_num, + { "Block number", "s7comm.data.blockcontrol.block_number", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_dest_filesys, + { "Destination filesystem", "s7comm.data.blockcontrol.dest_filesys", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_part2_len, + { "Length part 2", "s7comm.data.blockcontrol.part2_len", FT_UINT8, BASE_DEC, NULL, 0x0, + "Length of part 2 in bytes", HFILL }}, + { &hf_s7comm_data_blockcontrol_part2_unknown, + { "Unknown char before load mem", "s7comm.data.blockcontrol.part2_unknown", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_loadmem_len, + { "Length of load memory", "s7comm.data.blockcontrol.loadmem_len", FT_STRING, BASE_NONE, NULL, 0x0, + "Length of load memory in bytes", HFILL }}, + { &hf_s7comm_data_blockcontrol_mc7code_len, + { "Length of MC7 code", "s7comm.data.blockcontrol.mc7code_len", FT_STRING, BASE_NONE, NULL, 0x0, + "Length of MC7 code in bytes", HFILL }}, + + { &hf_s7comm_data_blockcontrol_filename_len, + { "Filename Length", "s7comm.param.blockcontrol.filename_len", FT_UINT8, BASE_DEC, NULL, 0x0, + "Length following filename in bytes", HFILL }}, + { &hf_s7comm_data_blockcontrol_filename, + { "Filename", "s7comm.param.blockcontrol.filename", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_blockcontrol_upl_lenstring_len, + { "Blocklengthstring Length", "s7comm.param.blockcontrol.upl_lenstring_len", FT_UINT8, BASE_DEC, NULL, 0x0, + "Length following blocklength string in bytes", HFILL }}, + { &hf_s7comm_data_blockcontrol_upl_lenstring, + { "Blocklength", "s7comm.param.blockcontrol.upl_lenstring", FT_STRING, BASE_NONE, NULL, 0x0, + "Length of the complete uploadblock in bytes, may be split into many PDUs", HFILL }}, + { &hf_s7comm_data_blockcontrol_functionstatus, + { "Function Status", "s7comm.param.blockcontrol.functionstatus", FT_UINT8, BASE_HEX, NULL, 0x0, + "0=no error, 1=more data, 2=error", HFILL }}, + { &hf_s7comm_data_blockcontrol_functionstatus_more, + { "More data following", "s7comm.param.blockcontrol.functionstatus.more", FT_BOOLEAN, 8, NULL, 0x01, + "More data of the block/file can be retrieved with another request", HFILL }}, + { &hf_s7comm_data_blockcontrol_functionstatus_error, + { "Error", "s7comm.param.blockcontrol.functionstatus.error", FT_BOOLEAN, 8, NULL, 0x02, + "An error occurred", HFILL }}, + + /* NC programming functions */ + { &hf_s7comm_data_ncprg_unackcount, + { "Number of telegrams sent without acknowledge", "s7comm.data.ncprg.unackcount", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_ncprg_filelength, + { "NC file length", "s7comm.data.ncprg.filelength", FT_STRING, BASE_NONE, NULL, 0x0, + "NC file length: length of file date + file path", HFILL }}, + { &hf_s7comm_data_ncprg_filetime, + { "NC file timestamp", "s7comm.data.ncprg.filetime", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_ncprg_filepath, + { "NC file path", "s7comm.data.ncprg.filepath", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_data_ncprg_filedata, + { "NC file data", "s7comm.data.ncprg.filedata", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + /* Data record routing to Profibus */ + { &hf_s7comm_data_drr_data, + { "DRR Data", "s7comm.data.drr.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + /* Variable status */ + { &hf_s7comm_varstat_unknown, + { "Unknown byte(s) varstat", "s7comm.varstat.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_varstat_item_count, + { "Item count", "s7comm.varstat.item_count", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_varstat_req_memory_area, + { "Memory area", "s7comm.varstat.req.memory_area", FT_UINT8, BASE_DEC, VALS(userdata_tis_varstat_area_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_varstat_req_repetition_factor, + { "Repetition factor", "s7comm.varstat.req.repetition_factor", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_varstat_req_db_number, + { "DB number", "s7comm.varstat.req.db_number", FT_UINT16, BASE_DEC, NULL, 0x0, + "DB number, when area is DB", HFILL }}, + { &hf_s7comm_varstat_req_startaddress, + { "Startaddress", "s7comm.varstat.req.startaddress", FT_UINT16, BASE_DEC, NULL, 0x0, + "Startaddress / byteoffset", HFILL }}, + { &hf_s7comm_varstat_req_bitpos, + { "Bitposition", "s7comm.varstat.req.bitpos", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + /* cyclic services */ + { &hf_s7comm_cycl_interval_timebase, + { "Interval timebase", "s7comm.cyclic.interval_timebase", FT_UINT8, BASE_DEC, VALS(cycl_interval_timebase_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_cycl_interval_time, + { "Interval time factor", "s7comm.cyclic.interval_time", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cycl_function, + { "Function", "s7comm.cyclic.function", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cycl_jobid, + { "Job-ID", "s7comm.cyclic.job_id", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + /* Read record */ + { &hf_s7comm_rdrec_mlen, + { "Rdrec Mlen", "s7comm.readrec.mlen", FT_UINT16, BASE_DEC, NULL, 0x0, + "MLEN, Max. length in bytes of the data record data to be read", HFILL }}, + { &hf_s7comm_rdrec_index, + { "Rdrec Index", "s7comm.readrec.index", FT_UINT16, BASE_HEX, NULL, 0x0, + "INDEX, Data record number", HFILL }}, + { &hf_s7comm_rdrec_id, + { "Rdrec ID", "s7comm.readrec.id", FT_UINT24, BASE_DEC, NULL, 0x0, + "ID, Diagnostic address", HFILL }}, + { &hf_s7comm_rdrec_statuslen, + { "Rdrec Status Len", "s7comm.readrec.statuslen", FT_UINT8, BASE_DEC, NULL, 0x0, + "STATUS LEN, Length of status data", HFILL }}, + { &hf_s7comm_rdrec_statusdata, + { "Rdrec Status", "s7comm.readrec.status", FT_BYTES, BASE_NONE, NULL, 0x0, + "STATUS, Status data", HFILL }}, + { &hf_s7comm_rdrec_recordlen, + { "Rdrec Len", "s7comm.readrec.len", FT_UINT16, BASE_DEC, NULL, 0x0, + "LEN, Length of data record data read", HFILL }}, + { &hf_s7comm_rdrec_data, + { "Rdrec Data", "s7comm.readrec.data", FT_BYTES, BASE_NONE, NULL, 0x0, + "DATA, The read data record", HFILL }}, + { &hf_s7comm_rdrec_reserved1, + { "Rdrec reserved", "s7comm.readrec.reserved1", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + /* PBC, Programmable Block Functions */ + { &hf_s7comm_pbc_unknown, + { "PBC unknown", "s7comm.pbc.unknown", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_bsend_r_id, + { "PBC BSEND R_ID", "s7comm.pbc.req.bsend.r_id", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_bsend_len, + { "PBC BSEND LEN", "s7comm.pbc.req.bsend.len", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_usend_unknown1, + { "PBC USEND unknown 1", "s7comm.pbc.usend.unknown1", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_usend_r_id, + { "PBC USEND R_ID", "s7comm.pbc.usend.r_id", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_usend_unknown2, + { "PBC USEND unknown 2", "s7comm.pbc.usend.unknown2", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_arsend_ret, + { "PBC AR_SEND Returncode", "s7comm.pbc.arsend.ret", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_arsend_unknown, + { "PBC AR_SEND unknown", "s7comm.pbc.arsend.unknown", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_arsend_ar_id, + { "PBC AR_SEND AR_ID", "s7comm.pbc.arsend.ar_id", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_pbc_arsend_len, + { "PBC AR_SEND LEN", "s7comm.pbc.arsend.len", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + /* CPU alarms */ + { &hf_s7comm_cpu_alarm_message_item, + { "Alarm message", "s7comm.alarm.message", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_obj_item, + { "Message object", "s7comm.alarm.message_object", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_function, + { "Function identifier", "s7comm.alarm.function", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_nr_objects, + { "Number of message objects", "s7comm.alarm.nr_objects", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_nr_add_values, + { "Number of associated values", "s7comm.alarm.nr_add_values", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_eventid, + { "EventID", "s7comm.alarm.event_id", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_timestamp_coming, + { "Timestamp message coming", "s7comm.alarm.timestamp_coming", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_timestamp_going, + { "Timestamp message going", "s7comm.alarm.timestamp_going", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_associated_value, + { "Associated value(s)", "s7comm.alarm.associated_value", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_eventstate, + { "EventState", "s7comm.alarm.eventstate", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig1, + { "SIG_1", "s7comm.alarm.signal.sig1", FT_BOOLEAN, 8, NULL, 0x01, + "Current state of Signal SIG_1", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig2, + { "SIG_2", "s7comm.alarm.signal.sig2", FT_BOOLEAN, 8, NULL, 0x02, + "Current state of Signal SIG_2", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig3, + { "SIG_3", "s7comm.alarm.signal.sig3", FT_BOOLEAN, 8, NULL, 0x04, + "Current state of Signal SIG_3", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig4, + { "SIG_4", "s7comm.alarm.signal.sig4", FT_BOOLEAN, 8, NULL, 0x08, + "Current state of Signal SIG_4", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig5, + { "SIG_5", "s7comm.alarm.signal.sig5", FT_BOOLEAN, 8, NULL, 0x10, + "Current state of Signal SIG_5", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig6, + { "SIG_6", "s7comm.alarm.signal.sig6", FT_BOOLEAN, 8, NULL, 0x20, + "Current state of Signal SIG_6", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig7, + { "SIG_7", "s7comm.alarm.signal.sig7", FT_BOOLEAN, 8, NULL, 0x40, + "Current state of Signal SIG_7", HFILL }}, + { &hf_s7comm_cpu_alarm_message_signal_sig8, + { "SIG_8", "s7comm.alarm.signal.sig8", FT_BOOLEAN, 8, NULL, 0x80, + "Current state of Signal SIG_8", HFILL }}, + { &hf_s7comm_cpu_alarm_message_state, + { "State", "s7comm.alarm.state", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_ackstate_coming, + { "AckState coming", "s7comm.alarm.ack_state.coming", FT_UINT8, BASE_HEX, NULL, 0x0, + "Acknowledge state coming (1=Event acknowledged, 0=Event not acknowledged)", HFILL }}, + { &hf_s7comm_cpu_alarm_message_ackstate_going, + { "AckState going", "s7comm.alarm.ack_state.going", FT_UINT8, BASE_HEX, NULL, 0x0, + "Acknowledge state going (1=Event acknowledged, 0=Event not acknowledged)", HFILL }}, + { &hf_s7comm_cpu_alarm_message_event_coming, + { "Event coming", "s7comm.alarm.event.coming", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_event_going, + { "Event going", "s7comm.alarm.event.going", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_event_lastchanged, + { "Event last changed", "s7comm.alarm.event.lastchanged", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_event_reserved, + { "Reserved", "s7comm.alarm.event.reserved", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_scan_unknown1, + { "SCAN unknown 1", "s7comm.alarm.scan.unknown1", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_message_scan_unknown2, + { "SCAN unknown 2", "s7comm.alarm.scan.unknown2", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + /* Alarm message query */ + { &hf_s7comm_cpu_alarm_query_unknown1, + { "Unknown/Reserved (1)", "s7comm.alarm.query.unknown1", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_query_querytype, + { "Querytype", "s7comm.alarm.query.querytype", FT_UINT8, BASE_DEC, VALS(alarm_message_querytype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_query_unknown2, + { "Unknown/Reserved (2)", "s7comm.alarm.query.unknown2", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_query_alarmtype, + { "Alarmtype", "s7comm.alarm.query.alarmtype", FT_UINT32, BASE_DEC, VALS(alarm_message_query_alarmtype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_query_completelen, + { "Complete data length", "s7comm.alarm.query.complete_length", FT_UINT32, BASE_DEC, NULL, 0x0, + "Complete data length (with ALARM_S this is 0xffff, as they might be split into many telegrams)", HFILL }}, + { &hf_s7comm_cpu_alarm_query_datasetlen, + { "Length of dataset", "s7comm.alarm.query.dataset_length", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_alarm_query_resunknown1, + { "Unknown", "s7comm.alarm.query.resunknown1", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + /* CPU diagnostic messages */ + { &hf_s7comm_cpu_diag_msg_item, + { "CPU diagnostic message", "s7comm.cpu.diag_msg", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid, + { "Event ID", "s7comm.cpu.diag_msg.eventid", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid_class, + { "Event class", "s7comm.cpu.diag_msg.eventid.class", FT_UINT16, BASE_HEX, VALS(cpu_diag_msg_eventid_class_names), 0xf000, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid_ident_entleave, + { "Event entering state", "s7comm.cpu.diag_msg.eventid.ident.entleave", FT_BOOLEAN, 16, TFS(&tfs_s7comm_cpu_diag_msg_eventid_ident_entleave), 0x0100, + "Event identifier: 0=Event leaving state,1=Event entering state", HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid_ident_diagbuf, + { "Entry in diagnostic buffer", "s7comm.cpu.diag_msg.eventid.ident.diagbuf", FT_BOOLEAN, 16, NULL, 0x0200, + "Event identifier: Entry in diagnostic buffer", HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid_ident_interr, + { "Internal error", "s7comm.cpu.diag_msg.eventid.ident.interr", FT_BOOLEAN, 16, NULL, 0x0400, + "Event identifier: Internal error", HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid_ident_exterr, + { "External error", "s7comm.cpu.diag_msg.eventid.ident.exterr", FT_BOOLEAN, 16, NULL, 0x0800, + "Event identifier: External error", HFILL }}, + { &hf_s7comm_cpu_diag_msg_eventid_nr, + { "Event number", "s7comm.cpu.diag_msg.eventid.nr", FT_UINT16, BASE_HEX, NULL, 0x00ff, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_prioclass, + { "Priority class", "s7comm.cpu.diag_msg.prioclass", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_obnumber, + { "OB number", "s7comm.cpu.diag_msg.obnumber", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_datid, + { "DatID", "s7comm.cpu.diag_msg.datid", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_info1, + { "INFO1 Additional information 1", "s7comm.cpu.diag_msg.info1", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_diag_msg_info2, + { "INFO2 Additional information 2", "s7comm.cpu.diag_msg.info2", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + /* CPU message service */ + { &hf_s7comm_cpu_msgservice_subscribe_events, + { "Subscribed events", "s7comm.cpu.msg.events", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_subscribe_events_modetrans, + { "Mode-transition", "s7comm.cpu.msg.events.modetrans", FT_BOOLEAN, 8, NULL, 0x01, + "MODE: Register for mode-transition events via func-group=0 and subfunction=state", HFILL }}, + { &hf_s7comm_cpu_msgservice_subscribe_events_system, + { "System-diagnostics", "s7comm.cpu.msg.events.system", FT_BOOLEAN, 8, NULL, 0x02, + "SYS: Register for system diagnostic events", HFILL }}, + { &hf_s7comm_cpu_msgservice_subscribe_events_userdefined, + { "Userdefined", "s7comm.cpu.msg.events.userdefined", FT_BOOLEAN, 8, NULL, 0x04, + "USR: Register system user-defined diagnostic messages", HFILL }}, + { &hf_s7comm_cpu_msgservice_subscribe_events_alarms, + { "Alarms", "s7comm.cpu.msg.events.alarms", FT_BOOLEAN, 8, NULL, 0x80, + "ALM: Register alarm events (ALARM, SCAN, ALARM_S) type of event defined in additional field", HFILL }}, + { &hf_s7comm_cpu_msgservice_req_reserved1, + { "Reserved/Unknown", "s7comm.cpu.msg.req_reserved1", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_username, + { "Username", "s7comm.cpu.msg.username", FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_almtype, + { "Alarm type", "s7comm.cpu.msg.almtype", FT_UINT8, BASE_DEC, VALS(cpu_msgservice_almtype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_req_reserved2, + { "Reserved/Unknown", "s7comm.cpu.msg.req_reserved2", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_res_result, + { "Result", "s7comm.cpu.msg.res_result", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_res_reserved1, + { "Reserved/Unknown", "s7comm.cpu.msg.res_reserved1", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_res_reserved2, + { "Reserved/Unknown", "s7comm.cpu.msg.res_reserved2", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_cpu_msgservice_res_reserved3, + { "Reserved/Unknown", "s7comm.cpu.msg.res_reserved3", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_modetrans_param_unknown1, + { "Reserved/Unknown", "s7comm.param.modetrans.unknown1", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_modetrans_param_mode, + { "Current mode", "s7comm.param.modetrans.mode", FT_UINT8, BASE_DEC, VALS(modetrans_param_mode_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_modetrans_param_unknown2, + { "Reserved/Unknown", "s7comm.param.modetrans.unknown2", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + /* TIA Portal stuff */ + { &hf_s7comm_tia1200_item_reserved1, + { "1200 sym Reserved", "s7comm.tiap.item.reserved1", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tia1200_item_area1, + { "1200 sym root area 1", "s7comm.tiap.item.area1", FT_UINT16, BASE_HEX, VALS(tia1200_var_item_area1_names), 0x0, + "Area from where to read: DB or Inputs, Outputs, etc.", HFILL }}, + { &hf_s7comm_tia1200_item_area2, + { "1200 sym root area 2", "s7comm.tiap.item.area2", FT_UINT16, BASE_HEX, VALS(tia1200_var_item_area2_names), 0x0, + "Specifies the area from where to read", HFILL }}, + { &hf_s7comm_tia1200_item_area2unknown, + { "1200 sym root area 2 unknown", "s7comm.tiap.item.area2unknown", FT_UINT16, BASE_HEX, NULL, 0x0, + "For current unknown areas", HFILL }}, + { &hf_s7comm_tia1200_item_dbnumber, + { "1200 sym root DB number", "s7comm.tiap.item.dbnumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tia1200_item_crc, + { "1200 sym CRC", "s7comm.tiap.item.crc", FT_UINT32, BASE_HEX, NULL, 0x0, + "CRC generated out of symbolic name with (x^32+x^31+x^30+x^29+x^28+x^26+x^23+x^21+x^19+x^18+x^15+x^14+x^13+x^12+x^9+x^8+x^4+x+1)", HFILL }}, + { &hf_s7comm_tia1200_var_lid_flags, + { "LID flags", "s7comm.tiap.item.lid_flags", FT_UINT8, BASE_DEC, VALS(tia1200_var_lid_flag_names), 0xf0, + NULL, HFILL }}, + { &hf_s7comm_tia1200_substructure_item, + { "Substructure", "s7comm.tiap.item.substructure", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tia1200_item_value, + { "Value", "s7comm.tiap.item.value", FT_UINT32, BASE_DEC, NULL, 0x0fffffff, + NULL, HFILL }}, + + /* Fragment fields */ + { &hf_s7comm_fragment_overlap, + { "Fragment overlap", "s7comm.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment overlaps with other fragments", HFILL }}, + { &hf_s7comm_fragment_overlap_conflict, + { "Conflicting data in fragment overlap", "s7comm.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Overlapping fragments contained conflicting data", HFILL }}, + { &hf_s7comm_fragment_multiple_tails, + { "Multiple tail fragments found", "s7comm.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Several tails were found when defragmenting the packet", HFILL }}, + { &hf_s7comm_fragment_too_long_fragment, + { "Fragment too long", "s7comm.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Fragment contained data past end of packet", HFILL }}, + { &hf_s7comm_fragment_error, + { "Defragmentation error", "s7comm.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "Defragmentation error due to illegal fragments", HFILL }}, + { &hf_s7comm_fragment_count, + { "Fragment count", "s7comm.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_reassembled_in, + { "Reassembled in", "s7comm.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "S7COMM fragments are reassembled in the given packet", HFILL }}, + { &hf_s7comm_reassembled_length, + { "Reassembled S7COMM length", "s7comm.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0, + "The total length of the reassembled payload", HFILL }}, + { &hf_s7comm_fragment, + { "S7COMM Fragment", "s7comm.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_fragments, + { "S7COMM Fragments", "s7comm.fragments", FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + }; + + static ei_register_info ei[] = { + { &ei_s7comm_data_blockcontrol_block_num_invalid, { "s7comm.data.blockcontrol.block_number.invalid", PI_MALFORMED, PI_ERROR, + "Block number must be a string containing an integer", EXPFILL }}, + { &ei_s7comm_ud_blockinfo_block_num_ascii_invalid, { "s7comm.data.blockinfo.block_number.invalid", PI_MALFORMED, PI_ERROR, + "Block info must be a string containing an integer", EXPFILL }} + }; + + static gint *ett[] = { + &ett_s7comm, + &ett_s7comm_header, + &ett_s7comm_param, + &ett_s7comm_param_item, + &ett_s7comm_param_subitem, + &ett_s7comm_data, + &ett_s7comm_data_item, + &ett_s7comm_item_address, + &ett_s7comm_diagdata_registerflag, + &ett_s7comm_userdata_blockinfo_flags, + &ett_s7comm_cpu_alarm_message, + &ett_s7comm_cpu_alarm_message_object, + &ett_s7comm_cpu_alarm_message_signal, + &ett_s7comm_cpu_alarm_message_timestamp, + &ett_s7comm_cpu_alarm_message_associated_value, + &ett_s7comm_cpu_diag_msg, + &ett_s7comm_cpu_diag_msg_eventid, + &ett_s7comm_cpu_msgservice_subscribe_events, + &ett_s7comm_piservice_parameterblock, + &ett_s7comm_data_blockcontrol_status, + &ett_s7comm_plcfilename, + &ett_s7comm_prog_parameter, + &ett_s7comm_prog_data, + &ett_s7comm_fragments, + &ett_s7comm_fragment, + }; + + proto_s7comm = proto_register_protocol ( + "S7 Communication", /* name */ + "S7COMM", /* short name */ + "s7comm" /* abbrev */ + ); + + proto_register_field_array(proto_s7comm, hf, array_length (hf)); + + s7comm_register_szl_types(proto_s7comm); + + proto_register_subtree_array(ett, array_length (ett)); + + expert_s7comm = expert_register_protocol(proto_s7comm); + expert_register_field_array(expert_s7comm, ei, array_length(ei)); + + register_init_routine(s7comm_defragment_init); + s7comm_heur_subdissector_list = register_heur_dissector_list("s7comm-bsend", proto_s7comm); +} + +/* Register this protocol */ +void +proto_reg_handoff_s7comm(void) +{ + /* register ourself as an heuristic cotp (ISO 8073) payload dissector */ + heur_dissector_add("cotp", dissect_s7comm, "S7 Communication over COTP", "s7comm_cotp", proto_s7comm, HEURISTIC_ENABLE); + heur_dissector_add("cotp_is", dissect_s7comm, "S7 Communication over COTP (inactive subset)", "s7comm_cotp_is", proto_s7comm, HEURISTIC_ENABLE); +} + +/* + * Editor modelines - https://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: + */ |