/* packet-s7comm.c * * Author: Thomas Wiens, 2014 (th.wiens@gmx.de) * Description: Wireshark dissector for S7-Communication * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #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); /************************************************************************** * Function call tree of the dissect process dissect_s7comm() + +-------s7comm_decode_req_resp() + + + + response request + + + + + +------ s7comm_decode_param_item() + + + s7comm_decode_response_read_data() + + + + + +------ s7comm_decode_pdu_setup_communication() + + +------ s7comm_decode_plc_controls_param_hex1x() + + +------ s7comm_decode_plc_controls_param_hex28() + + +------ s7comm_decode_plc_controls_param_hex29() + + + +------ s7comm_decode_response_read_data() + +------ s7comm_decode_response_write_data() + +------ s7comm_decode_pdu_setup_communication() + + +-------s7comm_decode_ud() + +------ s7comm_decode_ud_prog_subfunc() + + + +------- s7comm_decode_ud_prog_vartab_req_item() + +------- s7comm_decode_ud_prog_vartab_res_item() + +------- s7comm_decode_ud_prog_reqdiagdata() + +------ s7comm_decode_ud_cyclic_subfunc() + + + +------- s7comm_decode_param_item() + +------- s7comm_decode_response_read_data() + +------ s7comm_decode_ud_block_subfunc() +------ s7comm_decode_ud_szl_subfunc() + + + +------- s7comm_decode_szl_id_XXXX_idx_XXXX() + +------ s7comm_decode_ud_security_subfunc() +------ s7comm_decode_ud_time_subfunc() **************************************************************************/ /************************************************************************** * 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_RESSOURCE 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_RESSOURCE, "No ressources 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 */ #define S7COMM_PERRCOD_NO_ERROR 0x0000 #define S7COMM_PERRCOD_INVALID_BLOCK_TYPE_NUM 0x0110 #define S7COMM_PERRCOD_INVALID_PARAM 0x0112 #define S7COMM_PERRCOD_PG_RESOURCE_ERROR 0x011A #define S7COMM_PERRCOD_PLC_RESOURCE_ERROR 0x011B #define S7COMM_PERRCOD_PROTOCOL_ERROR 0x011C #define S7COMM_PERRCOD_USER_BUFFER_TOO_SHORT 0x011F #define S7COMM_PERRCOD_REQ_INI_ERR 0x0141 #define S7COMM_PERRCOD_VERSION_MISMATCH 0x01C0 #define S7COMM_PERRCOD_NOT_IMPLEMENTED 0x01F0 #define S7COMM_PERRCOD_L7_INVALID_CPU_STATE 0x8001 #define S7COMM_PERRCOD_L7_PDU_SIZE_ERR 0x8500 #define S7COMM_PERRCOD_L7_INVALID_SZL_ID 0xD401 #define S7COMM_PERRCOD_L7_INVALID_INDEX 0xD402 #define S7COMM_PERRCOD_L7_DGS_CONN_ALREADY_ANNOU 0xD403 #define S7COMM_PERRCOD_L7_MAX_USER_NB 0xD404 #define S7COMM_PERRCOD_L7_DGS_FKT_PAR_SYNTAX_ERR 0xD405 #define S7COMM_PERRCOD_L7_NO_INFO 0xD406 #define S7COMM_PERRCOD_L7_PRT_FKT_PAR_SYNTAX_ERR 0xD601 #define S7COMM_PERRCOD_L7_INVALID_VAR_ADDR 0xD801 #define S7COMM_PERRCOD_L7_UNKNOWN_REQ 0xD802 #define S7COMM_PERRCOD_L7_INVALID_REQ_STATUS 0xD803 static const value_string param_errcode_names[] = { { S7COMM_PERRCOD_NO_ERROR, "No error" }, { S7COMM_PERRCOD_INVALID_BLOCK_TYPE_NUM, "Invalid block type number" }, { S7COMM_PERRCOD_INVALID_PARAM, "Invalid parameter" }, { S7COMM_PERRCOD_PG_RESOURCE_ERROR, "PG ressource error" }, { S7COMM_PERRCOD_PLC_RESOURCE_ERROR, "PLC ressource error" }, { S7COMM_PERRCOD_PROTOCOL_ERROR, "Protocol error" }, { S7COMM_PERRCOD_USER_BUFFER_TOO_SHORT, "User buffer too short" }, { S7COMM_PERRCOD_REQ_INI_ERR, "Request error" }, { S7COMM_PERRCOD_VERSION_MISMATCH, "Version mismatch" }, { S7COMM_PERRCOD_NOT_IMPLEMENTED, "Not implemented" }, { S7COMM_PERRCOD_L7_INVALID_CPU_STATE, "L7 invalid CPU state" }, { S7COMM_PERRCOD_L7_PDU_SIZE_ERR, "L7 PDU size error" }, { S7COMM_PERRCOD_L7_INVALID_SZL_ID, "L7 invalid SZL ID" }, { S7COMM_PERRCOD_L7_INVALID_INDEX, "L7 invalid index" }, { S7COMM_PERRCOD_L7_DGS_CONN_ALREADY_ANNOU, "L7 DGS Connection already announced" }, { S7COMM_PERRCOD_L7_MAX_USER_NB, "L7 Max user NB" }, { S7COMM_PERRCOD_L7_DGS_FKT_PAR_SYNTAX_ERR, "L7 DGS function parameter syntax error" }, { S7COMM_PERRCOD_L7_NO_INFO, "L7 no info" }, { S7COMM_PERRCOD_L7_PRT_FKT_PAR_SYNTAX_ERR, "L7 PRT function parameter syntax error" }, { S7COMM_PERRCOD_L7_INVALID_VAR_ADDR, "L7 invalid variable address" }, { S7COMM_PERRCOD_L7_UNKNOWN_REQ, "L7 unknown request" }, { S7COMM_PERRCOD_L7_INVALID_REQ_STATUS, "L7 invalid request status" }, { 0, NULL } }; /************************************************************************** * Function codes in parameter part */ #define S7COMM_SERV_CPU 0x00 #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_FUNC_PLC_CONTROL 0x28 #define S7COMM_FUNC_PLC_STOP 0x29 static const value_string param_functionnames[] = { { S7COMM_SERV_CPU, "CPU services" }, { 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_FUNC_PLC_CONTROL, "PLC Control" }, { S7COMM_FUNC_PLC_STOP, "PLC Stop" }, { 0, NULL } }; /************************************************************************** * Area names */ #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_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 } }; /************************************************************************** * 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_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_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 */ #define S7COMM_SYNTAXID_NCK 0x82 /* Sinumerik NCK HMI access */ static const value_string item_syntaxid_names[] = { { S7COMM_SYNTAXID_S7ANY, "S7ANY" }, { 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_DRIVEESANY, "DRIVEESANY" }, { S7COMM_SYNTAXID_1200SYM, "1200SYM" }, { S7COMM_SYNTAXID_DBREAD, "DBREAD" }, { S7COMM_SYNTAXID_NCK, "NCK" }, { 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 */ 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" }, { 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 */ #define S7COMM_BLOCKTYPE_OB '8' #define S7COMM_BLOCKTYPE_DB 'A' #define S7COMM_BLOCKTYPE_SDB 'B' #define S7COMM_BLOCKTYPE_FC 'C' #define S7COMM_BLOCKTYPE_SFC 'D' #define S7COMM_BLOCKTYPE_FB 'E' #define S7COMM_BLOCKTYPE_SFB 'F' static const value_string blocktype_names[] = { { S7COMM_BLOCKTYPE_OB, "OB" }, { 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 } }; /************************************************************************** * Subblk types */ #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_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_PUSH, "Push" }, /* this type occurs when 2 telegrams follow after another from the same partner, or initiated from PLC */ { S7COMM_UD_TYPE_REQ, "Request" }, { S7COMM_UD_TYPE_RES, "Response" }, { 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_MODETRANS 0x0 #define S7COMM_UD_FUNCGROUP_PROG 0x1 #define S7COMM_UD_FUNCGROUP_CYCLIC 0x2 #define S7COMM_UD_FUNCGROUP_BLOCK 0x3 #define S7COMM_UD_FUNCGROUP_CPU 0x4 #define S7COMM_UD_FUNCGROUP_SEC 0x5 /* Security functions e.g. plc password */ #define S7COMM_UD_FUNCGROUP_PBC 0x6 /* PBC = Programmable Block Communication (PBK in german) */ #define S7COMM_UD_FUNCGROUP_TIME 0x7 static const value_string userdata_functiongroup_names[] = { { S7COMM_UD_FUNCGROUP_MODETRANS, "Mode-transition" }, { S7COMM_UD_FUNCGROUP_PROG, "Programmer commands" }, { S7COMM_UD_FUNCGROUP_CYCLIC, "Cyclic data" }, /* 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, "PBC BSEND/BRECV" }, { S7COMM_UD_FUNCGROUP_TIME, "Time functions" }, { 0, NULL } }; /************************************************************************** * Vartab: Typ of data in data part, first two bytes */ #define S7COMM_UD_SUBF_PROG_VARTAB_TYPE_REQ 0x14 #define S7COMM_UD_SUBF_PROG_VARTAB_TYPE_RES 0x04 static const value_string userdata_prog_vartab_type_names[] = { { S7COMM_UD_SUBF_PROG_VARTAB_TYPE_REQ, "Request" }, /* Request of data areas */ { S7COMM_UD_SUBF_PROG_VARTAB_TYPE_RES, "Response" }, /* Response from plc with data */ { 0, NULL } }; /************************************************************************** * Vartab: area of data request * * Low Hi * 0=M 1=BYTE * 1=E 2=WORD * 2=A 3=DWORD * 3=PEx * 7=DB * 54=TIMER * 64=COUNTER */ #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_MB 0x01 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_MW 0x02 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_MD 0x03 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_EB 0x11 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_EW 0x12 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_ED 0x13 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_AB 0x21 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_AW 0x22 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_AD 0x23 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_PEB 0x31 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_PEW 0x32 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_PED 0x33 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBB 0x71 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBW 0x72 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBD 0x73 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_T 0x54 #define S7COMM_UD_SUBF_PROG_VARTAB_AREA_C 0x64 static const value_string userdata_prog_vartab_area_names[] = { { S7COMM_UD_SUBF_PROG_VARTAB_AREA_MB, "MB" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_MW, "MW" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_MD, "MD" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_EB, "IB" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_EW, "IW" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_ED, "ID" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_AB, "QB" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_AW, "QW" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_AD, "QD" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_PEB, "PIB" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_PEW, "PIW" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_PED, "PID" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBB, "DBB" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBW, "DBW" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBD, "DBD" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_T, "TIMER" }, { S7COMM_UD_SUBF_PROG_VARTAB_AREA_C, "COUNTER" }, { 0, NULL } }; /************************************************************************** * Names of userdata subfunctions in group 1 (Programmer commands) */ #define S7COMM_UD_SUBF_PROG_REQDIAGDATA1 0x01 #define S7COMM_UD_SUBF_PROG_VARTAB1 0x02 #define S7COMM_UD_SUBF_PROG_ERASE 0x0c #define S7COMM_UD_SUBF_PROG_READDIAGDATA 0x0e #define S7COMM_UD_SUBF_PROG_REMOVEDIAGDATA 0x0f #define S7COMM_UD_SUBF_PROG_FORCE 0x10 #define S7COMM_UD_SUBF_PROG_REQDIAGDATA2 0x13 static const value_string userdata_prog_subfunc_names[] = { { S7COMM_UD_SUBF_PROG_REQDIAGDATA1, "Request diag data (Type 1)" }, /* Start online block view */ { S7COMM_UD_SUBF_PROG_VARTAB1, "VarTab" }, /* Variable table */ { S7COMM_UD_SUBF_PROG_READDIAGDATA, "Read diag data" }, /* online block view */ { S7COMM_UD_SUBF_PROG_REMOVEDIAGDATA, "Remove diag data" }, /* Stop online block view */ { S7COMM_UD_SUBF_PROG_ERASE, "Erase" }, { S7COMM_UD_SUBF_PROG_FORCE, "Forces" }, { S7COMM_UD_SUBF_PROG_REQDIAGDATA2, "Request diag data (Type 2)" }, /* Start online block view */ { 0, NULL } }; /************************************************************************** * Names of userdata subfunctions in group 2 (cyclic data) */ #define S7COMM_UD_SUBF_CYCLIC_MEM 0x01 #define S7COMM_UD_SUBF_CYCLIC_UNSUBSCRIBE 0x04 static const value_string userdata_cyclic_subfunc_names[] = { { S7COMM_UD_SUBF_CYCLIC_MEM, "Memory" }, /* read data from memory (DB/M/etc.) */ { S7COMM_UD_SUBF_CYCLIC_UNSUBSCRIBE, "Unsubscribe" }, /* Unsubscribe (disable) cyclic data */ { 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) */ 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_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 magatine place data" }, { 0x40, "TF - Parametrizing, 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 - Aplication-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*/ /* 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_head = -1; static gint hf_s7comm_userdata_param_len = -1; static gint hf_s7comm_userdata_param_reqres2 = -1; /* unknown */ 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 = -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, 1 byte, stringlist blocktype_names */ 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_const1 = -1; /* Constant 1, 1 byte, HEX*/ 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 const int *s7comm_userdata_blockinfo_flags_fields[] = { &hf_s7comm_userdata_blockinfo_linked, &hf_s7comm_userdata_blockinfo_standard_block, &hf_s7comm_userdata_blockinfo_nonretain, NULL }; /* Programmer commands, diagnostic data */ static gint hf_s7comm_diagdata_req_askheadersize = -1; /* Ask header size, 2 bytes as int */ static gint hf_s7comm_diagdata_req_asksize = -1; /* Ask size, 2 bytes as int */ static gint hf_s7comm_diagdata_req_unknown = -1; /* for all unknown bytes */ static gint hf_s7comm_diagdata_req_answersize = -1; /* Answer size, 2 bytes as int */ static gint hf_s7comm_diagdata_req_block_type = -1; /* Block type, 1 byte, stringlist subblktype_names */ static gint hf_s7comm_diagdata_req_block_num = -1; /* Block number, 2 bytes as int */ static gint hf_s7comm_diagdata_req_startaddr_awl = -1; /* Start address AWL, 2 bytes as int */ static gint hf_s7comm_diagdata_req_saz = -1; /* Step address counter (SAZ), 2 bytes as int */ static gint hf_s7comm_diagdata_req_number_of_lines = -1; /* Number of lines, 1 byte as int */ static gint hf_s7comm_diagdata_req_line_address = -1; /* Address, 2 bytes as int */ /* 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 const int *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 }; /* Function 0x28 (PLC control functions) */ static gint hf_s7comm_data_plccontrol_part1_unknown = -1; /* Unknown bytes */ static gint hf_s7comm_data_plccontrol_part1_len = -1; /* Length part 1 in bytes, 2 Bytes Int */ 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_plccontrol_part1_unknown2 = -1; /* Unknown 1 byte */ static gint hf_s7comm_data_plccontrol_block_unknown = -1; /* Unknown 1 byte, as ASCII */ static gint hf_s7comm_data_plccontrol_block_type = -1; /* Block type, 1 Byte, stringlist blocktype_names */ static gint hf_s7comm_data_plccontrol_block_num = -1; /* Block number, 5 Bytes as ASCII */ static gint hf_s7comm_data_plccontrol_dest_filesys = -1; /* Destination filesystem, 1 Byte as ASCII */ static gint hf_s7comm_data_plccontrol_part2_len = -1; /* Length part 2 in bytes, 1 Byte as Int */ static gint hf_s7comm_data_plccontrol_pi_service = -1; /* PI (program invocation) Service, String as ASCII */ /* 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_part1_len = -1; /* Length of part 1, 1 byte as int */ static gint hf_s7comm_data_blockcontrol_file_ident = -1; /* File identifier, as ASCII */ static gint hf_s7comm_data_blockcontrol_block_unknown = -1; /* unknown prefix before block type, ASCII */ static gint hf_s7comm_data_blockcontrol_block_type = -1; /* Block type, 1 Byte, stringlist blocktype_names */ static gint hf_s7comm_data_blockcontrol_block_num = -1; /* Block number, 5 Bytes, als 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 */ /* Variable table */ static gint hf_s7comm_vartab_data_type = -1; /* Type of data, 1 byte, stringlist userdata_prog_vartab_type_names */ static gint hf_s7comm_vartab_byte_count = -1; /* Byte count, 2 bytes, int */ static gint hf_s7comm_vartab_unknown = -1; /* Unknown byte(s), hex */ static gint hf_s7comm_vartab_item_count = -1; /* Item count, 2 bytes, int */ static gint hf_s7comm_vartab_req_memory_area = -1; /* Memory area, 1 byte, stringlist userdata_prog_vartab_area_names */ static gint hf_s7comm_vartab_req_repetition_factor = -1; /* Repetition factor, 1 byte as int */ static gint hf_s7comm_vartab_req_db_number = -1; /* DB number, 2 bytes as int */ static gint hf_s7comm_vartab_req_startaddress = -1; /* Startaddress, 2 bytes as int */ /* cyclic data */ 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 */ /* PBC, Programmable Block Functions */ static gint hf_s7comm_pbc_unknown = -1; /* unknown, 1 byte */ static gint hf_s7comm_pbc_r_id = -1; /* Request ID R_ID, 4 bytes as hex */ /* 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_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 const int *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 const int *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" }, { 0x3984, "Interface module removed" }, { 0x3981, "Interface error entering state" }, { 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" }, { 0x597C, "DP command Global Control failure 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" }, { 0x6390, "Formatting of Micro Memory Card complete" }, { 0x6353, "Firmware update: Start of firmware download over the network" }, { 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" }, { 0x73E0, "Loss of redundancy in communication" }, { 0x73DB, "Safety program: safety mode enabled" }, { 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 const int *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; static const value_string cpu_msgservice_almtype_names[] = { { 0, "SCAN_ABORT" }, { 1, "SCAN_INITIATE" }, { 4, "ALARM_ABORT" }, { 5, "ALARM_INITIATE" }, { 8, "ALARM_S_ABORT" }, { 9, "ALARM_S_INITIATE" }, { 0, NULL } }; static gint hf_s7comm_modetrans_param_subfunc = -1; static const value_string modetrans_param_subfunc_names[] = { { 0, "STOP" }, { 1, "Warm Restart" }, { 2, "RUN" }, { 0, NULL } }; /* 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 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 += days * (24*60*60); t += day_msec / 1000; mt = gmtime(&t); str[0] = '\0'; if (mt != NULL) { g_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; 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); } return offset; } /******************************************************************************************************* * * Generate a comma separated string for registerflags * *******************************************************************************************************/ static void make_registerflag_string(gchar *str, guint8 flags, gint max) { g_strlcpy(str, "", max); if (flags & 0x01) g_strlcat(str, "STW, ", max); if (flags & 0x02) g_strlcat(str, "ACCU1, ", max); if (flags & 0x04) g_strlcat(str, "ACCU2, ", max); if (flags & 0x08) g_strlcat(str, "AR1, ", max); if (flags & 0x10) g_strlcat(str, "AR2, ", max); if (flags & 0x20) g_strlcat(str, "DB1, ", max); if (flags & 0x40) g_strlcat(str, "DB2, ", max); if (strlen(str) > 2) str[strlen(str) - 2 ] = '\0'; } /******************************************************************************************************* * * 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) { guint32 a_address = 0; guint32 bytepos = 0; guint32 bitpos = 0; guint8 t_size = 0; guint16 len = 0; guint16 db = 0; guint16 i; guint8 area = 0; proto_item *item = NULL; proto_tree *item_tree = NULL; proto_tree *sub_item_tree = NULL; proto_item *address_item = NULL; proto_tree *address_item_tree = NULL; guint8 number_of_areas = 0; guint8 var_spec_type = 0; guint8 var_spec_length = 0; guint8 var_spec_syntax_id = 0; proto_item *sub_item = NULL; guint16 tia_var_area1 = 0; guint16 tia_var_area2 = 0; guint8 tia_lid_flags = 0; guint32 tia_value = 0; guint8 nck_area = 0; guint8 nck_unit = 0; guint16 nck_column = 0; guint16 nck_line = 0; guint8 nck_module = 0; /* At first check type and length of variable specification */ 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); /* Classic S7: type = 0x12, len=10, syntax-id=0x10 for ANY-Pointer * TIA S7-1200: type = 0x12, len=14, syntax-id=0xb2 (symbolic addressing??) * Drive-ES Starter with routing: type = 0x12, len=10, syntax-id=0xa2 for ANY-Pointer */ /* 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; /****************************************************************************/ /************************** Step 7 Classic 300 400 **************************/ if (var_spec_type == 0x12 && var_spec_length == 10 && var_spec_syntax_id == S7COMM_SYNTAXID_S7ANY) { /* Transport size, 1 byte */ t_size = tvb_get_guint8(tvb, offset); proto_tree_add_uint(item_tree, hf_s7comm_item_transport_size, tvb, offset, 1, t_size); offset += 1; /* Length, 2 bytes */ len = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(item_tree, hf_s7comm_item_length, tvb, offset, 2, len); offset += 2; /* DB number, 2 bytes */ db = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(item_tree, hf_s7comm_item_db, tvb, offset, 2, db); offset += 2; /* Area, 1 byte */ area = tvb_get_guint8(tvb, offset); proto_tree_add_uint(item_tree, hf_s7comm_item_area, tvb, offset, 1, area); offset += 1; /* Address, 3 bytes */ a_address = tvb_get_ntoh24(tvb, offset); address_item = proto_tree_add_uint(item_tree, hf_s7comm_item_address, tvb, offset, 3, 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 */ switch (area) { case (S7COMM_AREA_P): proto_item_append_text(item_tree, " (P"); break; case (S7COMM_AREA_INPUTS): proto_item_append_text(item_tree, " (I"); break; case (S7COMM_AREA_OUTPUTS): proto_item_append_text(item_tree, " (Q"); break; case (S7COMM_AREA_FLAGS): proto_item_append_text(item_tree, " (M"); break; case (S7COMM_AREA_DB): proto_item_append_text(item_tree, " (DB%d.DBX", db); break; case (S7COMM_AREA_DI): proto_item_append_text(item_tree, " (DI%d.DIX", db); break; case (S7COMM_AREA_LOCAL): proto_item_append_text(item_tree, " (L"); break; case (S7COMM_AREA_COUNTER): proto_item_append_text(item_tree, " (C"); break; case (S7COMM_AREA_TIMER): proto_item_append_text(item_tree, " (T"); break; default: proto_item_append_text(item_tree, " (unknown area"); break; } if (area == S7COMM_AREA_TIMER || area == S7COMM_AREA_COUNTER) { proto_item_append_text(item_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); proto_item_append_text(item_tree, " %d.%d %s %d)", bytepos, bitpos, val_to_str(t_size, item_transportsizenames, "Unknown transport size: 0x%02x"), len); } offset += 3; /****************************************************************************/ /******************** S7-400 special address mode (kind of cyclic read) *****/ /* The response to this kind of request can't be decoded, because in the response * the data fields don't contain any header information. There is only one byte */ } else if (var_spec_type == 0x12 && var_spec_length >= 7 && var_spec_syntax_id == S7COMM_SYNTAXID_DBREAD) { /* Number of data area specifications following, 1 Byte */ number_of_areas = tvb_get_guint8(tvb, offset); proto_tree_add_uint(item_tree, hf_s7comm_item_dbread_numareas, tvb, offset, 1, number_of_areas); proto_item_append_text(item_tree, " (%d Data-Areas of Syntax-Id DBREAD)", number_of_areas); offset += 1; for (i = 1; i <= number_of_areas; i++) { sub_item = proto_tree_add_item(item_tree, hf_s7comm_param_subitem, tvb, offset, 5, ENC_NA); sub_item_tree = proto_item_add_subtree(sub_item, ett_s7comm_param_subitem); /* Number of Bytes to read, 1 Byte */ len = tvb_get_guint8(tvb, offset); proto_tree_add_uint(sub_item_tree, hf_s7comm_item_dbread_length, tvb, offset, 1, len); offset += 1; /* DB number, 2 Bytes */ db = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(sub_item_tree, hf_s7comm_item_dbread_db, tvb, offset, 2, db); offset += 2; /* Start address, 2 Bytes */ bytepos = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(sub_item_tree, hf_s7comm_item_dbread_startadr, tvb, offset, 2, bytepos); offset += 2; /* Display as pseudo S7-Any Format */ proto_item_append_text(sub_item, " [%d]: (DB%d.DBB %d BYTE %d)", i, db, bytepos, len); } /****************************************************************************/ /******************** TIA S7 1200 symbolic address mode *********************/ } else if (var_spec_type == 0x12 && var_spec_length >= 14 && var_spec_syntax_id == S7COMM_SYNTAXID_1200SYM) { proto_item_append_text(item_tree, " 1200 symbolic address"); /* first byte in address seems always be 0xff */ proto_tree_add_item(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 */ tia_var_area1 = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(item_tree, hf_s7comm_tia1200_item_area1, tvb, offset, 2, 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(item_tree, hf_s7comm_tia1200_item_area2, tvb, offset, 2, tia_var_area2); proto_item_append_text(item_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(item_tree, hf_s7comm_tia1200_item_dbnumber, tvb, offset, 2, tia_var_area2); proto_item_append_text(item_tree, " - Accessing DB%d", tia_var_area2); offset += 2; } else { /* for current unknown areas, I don't know if there are other valid areas */ proto_tree_add_uint(item_tree, hf_s7comm_tia1200_item_area2unknown, tvb, offset, 2, tia_var_area2); proto_item_append_text(item_tree, " - Unknown area specification"); offset += 2; } proto_tree_add_item(item_tree, hf_s7comm_tia1200_item_crc, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; for (i = 0; i < (var_spec_length - 10) / 4; i++) { /* Insert a new tree for every sub-struct */ sub_item = proto_tree_add_item(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; } /****************************************************************************/ /******************** Sinumerik NCK access **********************************/ } else if (var_spec_type == 0x12 && var_spec_length == 8 && var_spec_syntax_id == S7COMM_SYNTAXID_NCK) { area = tvb_get_guint8(tvb, offset); nck_area = area >> 5; nck_unit = area & 0x1f; proto_tree_add_item(item_tree, hf_s7comm_item_nck_areaunit, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(item_tree, hf_s7comm_item_nck_area, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(item_tree, hf_s7comm_item_nck_unit, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; nck_column = tvb_get_ntohs(tvb, offset); proto_tree_add_item(item_tree, hf_s7comm_item_nck_column, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; nck_line = tvb_get_ntohs(tvb, offset); proto_tree_add_item(item_tree, hf_s7comm_item_nck_line, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; nck_module = tvb_get_guint8(tvb, offset); proto_tree_add_item(item_tree, hf_s7comm_item_nck_module, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(item_tree, hf_s7comm_item_nck_linecount, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_item_append_text(item_tree, " (NCK Area:%d Unit:%d Column:%d Line:%d Module:0x%02x)", nck_area, nck_unit, nck_column, nck_line, nck_module); } 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 = 1; 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, 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; for (i = 1; 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)) { 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, 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 0x28 (PLC control functions) * *******************************************************************************************************/ static guint32 s7comm_decode_plc_controls_param_hex28(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset) { guint16 len; guint8 count; guint8 i; guint8 *str; /* The first byte 0x28 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_data_plccontrol_part1_unknown, tvb, offset, 7, ENC_NA); offset += 7; /* Part 1 */ len = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(tree, hf_s7comm_data_plccontrol_part1_len, tvb, offset, 2, len); offset += 2; /* no block function, cold start e.g. */ if (len == 2) { /* C = cold start */ proto_tree_add_item(tree, hf_s7comm_data_plccontrol_argument, tvb, offset, 2, ENC_ASCII|ENC_NA); offset +=2; } else if (len > 2) { count = tvb_get_guint8(tvb, offset); /* number of blocks following */ proto_tree_add_uint(tree, hf_s7comm_data_plccontrol_block_cnt, tvb, offset, 1, count); offset += 1; /* Next byte reserved? is 0x00 */ proto_tree_add_item(tree, hf_s7comm_data_plccontrol_part1_unknown2, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; for (i = 0; i < count; i++) { /* First byte of block type seems to be every time '0' as single char*/ proto_tree_add_item(tree, hf_s7comm_data_plccontrol_block_unknown, tvb, offset, 1, ENC_ASCII|ENC_NA); offset +=1; proto_tree_add_item(tree, hf_s7comm_data_plccontrol_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Type:[%s]", val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); offset += 1; proto_tree_add_item(tree, hf_s7comm_data_plccontrol_block_num, tvb, offset, 5, ENC_ASCII|ENC_NA); str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 5, ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " No.:[%s]", str); offset += 5; /* 'P', 'B' or 'A' is following Destination filesystem? P = passive filesystem A = active filesystem? */ proto_tree_add_item(tree, hf_s7comm_data_plccontrol_dest_filesys, tvb, offset, 1, ENC_ASCII|ENC_NA); offset += 1; } } /* 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 (PI_SERVICE) as string (program invocation) * Known functions: * _INSE = Activate a module * _DELE = Delete a passive module * _PROGRAM = Start/Stop the PLC * _PLC_MEMORYRESET = Reset the PLC memory */ proto_tree_add_item(tree, hf_s7comm_data_plccontrol_pi_service, tvb, offset, len, ENC_ASCII|ENC_NA); offset += len; 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_data_plccontrol_part1_unknown, 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_data_plccontrol_pi_service, tvb, offset, len, ENC_ASCII|ENC_NA); offset += len; return offset; } /******************************************************************************************************* * * PDU Type: Request or Response -> Function 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f (block control functions) * *******************************************************************************************************/ static guint32 s7comm_decode_plc_controls_param_hex1x(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint16 plength, guint32 offset) { guint8 len; guint8 function; guint8 *str; function = tvb_get_guint8(tvb, offset); offset += 1; /* Meaning of first byte is unknown */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 1, ENC_NA); offset += 1; /* These 2 bytes seems to be an error code. If an upload fails, this value is also shown in Manager as errorcode. Zero on success. */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_errorcode, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* unknown 4 bytes */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 4, ENC_NA); offset += 4; if (plength <= 8) { /* Upload or End upload functions have no other data */ return offset; } /* Part 1: Block information*/ len = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_s7comm_data_blockcontrol_part1_len, tvb, offset, 1, len); offset += 1; /* Prefix * File identifier: * _ means: "complete module" * $ means: "Module header for up-loading" */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_file_ident, tvb, offset, 1, ENC_ASCII|ENC_NA); offset += 1; /* First byte of block type is every time '0' */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_block_unknown, tvb, offset, 1, ENC_ASCII|ENC_NA); offset += 1; proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Type:[%s]", val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); offset += 1; str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 5, ENC_ASCII); proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_block_num, tvb, offset, 5, ENC_ASCII|ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, " No.:[%s]", str); offset += 5; /* 'P', 'B' or 'A' is following */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_dest_filesys, tvb, offset, 1, ENC_ASCII|ENC_NA); offset += 1; /* Part 2, only available in "request download" */ if (function == S7COMM_FUNCREQUESTDOWNLOAD && plength > 18) { len = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_s7comm_data_blockcontrol_part2_len, tvb, offset, 1, len); offset += 1; /* first byte unknown '1' */ proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_part2_unknown, tvb, offset, 1, ENC_ASCII|ENC_NA); offset += 1; proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_loadmem_len, tvb, offset, 6, ENC_ASCII|ENC_NA); offset += 6; proto_tree_add_item(tree, hf_s7comm_data_blockcontrol_mc7code_len, tvb, offset, 6, ENC_ASCII|ENC_NA); offset += 6; } return offset; } /******************************************************************************************************* * * PDU Type: User Data -> Function group 1 -> Programmer commands -> Request diagnostic data (0x13 or 0x01) * *******************************************************************************************************/ static guint32 s7comm_decode_ud_prog_reqdiagdata(tvbuff_t *tvb, proto_tree *data_tree, guint8 subfunc, /* Subfunction */ guint32 offset) /* Offset on data part +4 */ { proto_item *item = NULL; proto_tree *item_tree = NULL; guint16 line_nr; guint16 line_cnt; guint16 ask_size; guint16 item_size = 4; guint8 registerflags; gchar str_flags[80]; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_askheadersize, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; ask_size = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(data_tree, hf_s7comm_diagdata_req_asksize, tvb, offset, 2, ask_size); offset += 2; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_unknown, tvb, offset, 6, ENC_NA); offset += 6; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_answersize, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_unknown, tvb, offset, 13, ENC_NA); offset += 13; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_block_num, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_startaddr_awl, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_saz, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_unknown, tvb, offset, 1, ENC_NA); offset += 1; if (subfunc == 0x13) { line_cnt = tvb_get_guint8(tvb, offset); proto_tree_add_uint(data_tree, hf_s7comm_diagdata_req_number_of_lines, tvb, offset, 2, line_cnt); offset += 1; proto_tree_add_item(data_tree, hf_s7comm_diagdata_req_unknown, tvb, offset, 1, ENC_NA); offset += 1; } else { line_cnt = (ask_size - 2) / 2; } proto_tree_add_bitmask(data_tree, tvb, offset, hf_s7comm_diagdata_registerflag, ett_s7comm_diagdata_registerflag, s7comm_diagdata_registerflag_fields, ENC_BIG_ENDIAN); offset += 1; if (subfunc == 0x13) { item_size = 4; } else { item_size = 2; } for (line_nr = 0; line_nr < line_cnt; line_nr++) { item = proto_tree_add_item(data_tree, hf_s7comm_data_item, tvb, offset, item_size, ENC_NA); item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); if (subfunc == 0x13) { proto_tree_add_item(item_tree, hf_s7comm_diagdata_req_line_address, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } proto_tree_add_item(item_tree, hf_s7comm_diagdata_req_unknown, 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; } return offset; } /******************************************************************************************************* * * PDU Type: User Data -> Function group 1 -> Programmer commands -> Variable table -> request * *******************************************************************************************************/ static guint32 s7comm_decode_ud_prog_vartab_req_item(tvbuff_t *tvb, guint32 offset, proto_tree *sub_tree, guint16 item_no) { guint32 bytepos = 0; guint16 len = 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]:", item_no + 1); /* Area, 1 byte */ area = tvb_get_guint8(tvb, offset); proto_tree_add_item(sub_tree, hf_s7comm_vartab_req_memory_area, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* Length (repetition factor), 1 byte */ len = tvb_get_guint8(tvb, offset); proto_tree_add_uint(sub_tree, hf_s7comm_vartab_req_repetition_factor, tvb, offset, 1, len); offset += 1; /* DB number, 2 bytes */ db = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(sub_tree, hf_s7comm_vartab_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_vartab_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_PROG_VARTAB_AREA_MB: proto_item_append_text(sub_tree, " (M%d.0 BYTE %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_MW: proto_item_append_text(sub_tree, " (M%d.0 WORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_MD: proto_item_append_text(sub_tree, " (M%d.0 DWORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_EB: proto_item_append_text(sub_tree, " (I%d.0 BYTE %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_EW: proto_item_append_text(sub_tree, " (I%d.0 WORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_ED: proto_item_append_text(sub_tree, " (I%d.0 DWORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_AB: proto_item_append_text(sub_tree, " (Q%d.0 BYTE %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_AW: proto_item_append_text(sub_tree, " (Q%d.0 WORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_AD: proto_item_append_text(sub_tree, " (Q%d.0 DWORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_PEB: proto_item_append_text(sub_tree, " (PI%d.0 BYTE %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_PEW: proto_item_append_text(sub_tree, " (PI%d.0 WORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_PED: proto_item_append_text(sub_tree, " (PI%d.0 DWORD %d)", bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBB: proto_item_append_text(sub_tree, " (DB%d.DX%d.0 BYTE %d)", db, bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBW: proto_item_append_text(sub_tree, " (DB%d.DX%d.0 WORD %d)", db, bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_AREA_DBD: proto_item_append_text(sub_tree, " (DB%d.DX%d.0 DWORD %d)", db, bytepos, len); break; case S7COMM_UD_SUBF_PROG_VARTAB_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_PROG_VARTAB_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 -> Variable table -> response * *******************************************************************************************************/ static guint32 s7comm_decode_ud_prog_vartab_res_item(tvbuff_t *tvb, guint32 offset, proto_tree *sub_tree, guint16 item_no) { 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)", item_no + 1, 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 5 -> Security functions? * *******************************************************************************************************/ static guint32 s7comm_decode_ud_security_subfunc(tvbuff_t *tvb, proto_tree *data_tree, guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { /* 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 - 4, ENC_NA); offset += dlength; return offset; } /******************************************************************************************************* * * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV) * *******************************************************************************************************/ static guint32 s7comm_decode_ud_pbc_subfunc(tvbuff_t *tvb, proto_tree *data_tree, guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { 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_unknown, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(data_tree, hf_s7comm_pbc_r_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* Only in the first telegram of possible several segments, an int16 of full data length is following. * As the dissector can't check this, don't display the information * and display the data as payload bytes. */ dlength = dlength - 4 - 8; /* 4 bytes data header, 8 bytes varspec */ if (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 -> Message services * *******************************************************************************************************/ static guint32 s7comm_decode_message_service(tvbuff_t *tvb, packet_info *pinfo, proto_tree *data_tree, guint8 type, /* Type of data (request/response) */ guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { 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; g_strlcpy(events_string, "", sizeof(events_string)); if (events & 0x01) 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) g_strlcat(events_string, "SYS,", sizeof(events_string)); /* System diagnostics */ if (events & 0x04) g_strlcat(events_string, "USR,", sizeof(events_string)); /* User-defined diagnostic messages */ if (events & 0x08) g_strlcat(events_string, "-4-,", sizeof(events_string)); /* currently unknown flag */ if (events & 0x10) g_strlcat(events_string, "-5-,", sizeof(events_string)); /* currently unknown flag */ if (events & 0x20) g_strlcat(events_string, "-6-,", sizeof(events_string)); /* currently unknown flag */ if (events & 0x40) g_strlcat(events_string, "-7-,", sizeof(events_string)); /* currently unknown flag */ if (events & 0x80) 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|ENC_NA); 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; 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; 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 -> 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, /* Type of data (request/response) */ guint8 subfunc, /* Subfunction */ guint32 offset) /* Offset on data part +4 */ { 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); if (subfunc == S7COMM_UD_SUBF_CPU_ALARM8_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMACK_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMSQ_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMS_IND || subfunc == S7COMM_UD_SUBF_CPU_NOTIFY_IND || subfunc == 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); } 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 = 1; 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); if (type == S7COMM_UD_TYPE_REQ || type == S7COMM_UD_TYPE_PUSH) { 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_fstr(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_fstr(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, packet_info *pinfo, proto_tree *data_tree, guint32 offset) /* Offset on data part +4 */ { 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; guint8 n_blocks; guint8 func; 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); /* An alarm response may take more that one response telegram. If it's split into many telegrams, * then the inner telegrams begins with the dataset parts without any header. * The last telegrams of this sequence has the first two bytes zero. */ func = tvb_get_guint8(tvb, offset); n_blocks = tvb_get_guint8(tvb, offset + 1); if (func == 0) { 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; if (n_blocks == 0) { col_append_fstr(pinfo->cinfo, COL_INFO, " [Last]"); proto_item_set_len(msg_item_tree, offset - start_offset); return offset; } } if (func > 0) { col_append_fstr(pinfo->cinfo, COL_INFO, " [Continuation]"); complete_length = func; remaining_length = (gint32)complete_length; returncode = S7COMM_ITEM_RETVAL_DATA_OK; } else { 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; /* As with ALARM_S it's only possible to send one alarm description in a single response telegram, * they are splitted into many telegrams. Therefore the complete length field is set to 0xffff. * To reuse the following dissect-loop, the remaining length is set to zero. */ 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; if (remaining_length == 0xffff) { remaining_length = 0; } 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); } while (remaining_length > 0); } 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, /* Type of data (request/response) */ guint8 subfunc, /* Subfunction */ guint8 ret_val, /* Return value in data part */ guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { gboolean know_data = FALSE; switch (subfunc) { case S7COMM_UD_SUBF_TIME_READ: case S7COMM_UD_SUBF_TIME_READF: if (type == S7COMM_UD_TYPE_RES) { /*** Response ***/ 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) { /*** Request ***/ 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 > 4) { proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 4, 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, /* Type of data (request/response) */ guint8 subfunc, /* Subfunction */ guint8 ret_val, /* Return value in data part */ guint8 tsize, /* transport size in data part */ guint16 len, /* length given in data part */ guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { guint16 count; guint16 i; guint8 *pBlocknumber; guint16 blocknumber; guint8 blocktype; gboolean know_data = FALSE; proto_item *item = NULL; proto_tree *item_tree = NULL; char str_timestamp[30]; char str_number[10]; char str_version[10]; switch (subfunc) { /************************************************* * List blocks */ case S7COMM_UD_SUBF_BLOCK_LIST: if (type == S7COMM_UD_TYPE_REQ) { /*** Request ***/ /* Is this a possible combination? Never seen it... */ } else if (type == S7COMM_UD_TYPE_RES) { /*** Response ***/ count = len / 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); offset += 1; /* skip first byte */ proto_item_append_text(item, " [%d]: (Block type %s)", i+1, val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); proto_tree_add_item(item_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; 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) { /*** Request ***/ if (tsize != S7COMM_DATA_TRANSPORT_SIZE_NULL) { offset += 1; /* skip first byte */ proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, " Type:[%s]", val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); proto_item_append_text(data_tree, ": (%s)", val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); offset += 1; } know_data = TRUE; }else if (type == S7COMM_UD_TYPE_RES) { /*** Response ***/ if (tsize != S7COMM_DATA_TRANSPORT_SIZE_NULL) { count = len / 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) { /*** Request ***/ if (tsize != S7COMM_DATA_TRANSPORT_SIZE_NULL) { /* 8 Bytes of Data follow, 1./ 2. type, 3-7 blocknumber as ascii number */ offset += 1; /* skip first byte */ proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); proto_item_append_text(data_tree, ": (Block type: %s", val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); /* Add block type and number to info column */ col_append_fstr(pinfo->cinfo, COL_INFO, " Type:[%s]", val_to_str(tvb_get_guint8(tvb, offset), blocktype_names, "Unknown Block type: 0x%02x")); offset += 1; proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_num_ascii, tvb, offset, 5, ENC_ASCII|ENC_NA); pBlocknumber = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 5, ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " No.:[%s]", pBlocknumber); proto_item_append_text(data_tree, ", Number: %s)", pBlocknumber); offset += 5; proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_filesys, tvb, offset, 1, ENC_ASCII|ENC_NA); offset += 1; } know_data = TRUE; }else if (type == S7COMM_UD_TYPE_RES) { /*** Response ***/ /* 78 Bytes */ if (ret_val == S7COMM_ITEM_RETVAL_DATA_OK) { proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_const1, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_block_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; 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|ENC_NA); offset += 2; proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_res_unknown, tvb, offset, 1, ENC_NA); offset += 1; /* Configuration flags or Bits? * Bits: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * Pos : 31 .. ..0 * * Bit : 0 -> DB Linked = true * Bit : 5 -> DB Non Retain = true * Standard FC/FC/DB -> 0x0101 0x0100 -> is this bit (8) in FBs for multiinstance? * SFC: 0x0009 SFB: 0x0109 or 0x010d (e.g. SFB8, 414) */ 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); /* Add block type and number to info column */ col_append_fstr(pinfo->cinfo, COL_INFO, " Type:[%s]", val_to_str(blocktype, subblktype_names, "Unknown Subblk type: 0x%02x")); proto_item_append_text(data_tree, ": (Subblk type: %s", val_to_str(blocktype, subblktype_names, "Unknown Subblk type: 0x%02x")); offset += 1; blocknumber = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(data_tree, hf_s7comm_ud_blockinfo_block_num, tvb, offset, 2, blocknumber); g_snprintf(str_number, sizeof(str_number), "%05d", blocknumber); col_append_fstr(pinfo->cinfo, COL_INFO, " No.:[%s]", str_number); proto_item_append_text(data_tree, ", Number: %05d)", 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|ENC_NA); offset += 8; proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_family, tvb, offset, 8, ENC_ASCII|ENC_NA); offset += 8; proto_tree_add_item(data_tree, hf_s7comm_ud_blockinfo_headername, tvb, offset, 8, ENC_ASCII|ENC_NA); offset += 8; g_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_item(data_tree, hf_s7comm_ud_blockinfo_checksum, tvb, offset, 2, ENC_BIG_ENDIAN); 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 > 4) { proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 4, ENC_NA); offset += dlength; } return offset; } /******************************************************************************************************* * * PDU Type: User Data -> Function group 2 -> cyclic data * *******************************************************************************************************/ static guint32 s7comm_decode_ud_cyclic_subfunc(tvbuff_t *tvb, proto_tree *data_tree, guint8 type, /* Type of data (request/response) */ guint8 subfunc, /* Subfunction */ guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { gboolean know_data = FALSE; guint32 offset_old; guint32 len_item; guint8 item_count; guint8 i; switch (subfunc) { case S7COMM_UD_SUBF_CYCLIC_MEM: 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) { /* Request to PLC to send cyclic data */ 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; /* parse item data */ 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)) { offset += 1; } } } else if (type == S7COMM_UD_TYPE_RES || type == S7COMM_UD_TYPE_PUSH) { /* Response from PLC with the requested data */ /* parse item data */ offset = s7comm_decode_response_read_data(tvb, data_tree, item_count, offset); } know_data = TRUE; break; } if (know_data == FALSE && dlength > 4) { proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 4, ENC_NA); offset += dlength; } return offset; } /******************************************************************************************************* * * PDU Type: User Data -> Function group 1 -> Programmer commands * *******************************************************************************************************/ static guint32 s7comm_decode_ud_prog_subfunc(tvbuff_t *tvb, proto_tree *data_tree, guint8 type, /* Type of data (request/response) */ guint8 subfunc, /* Subfunction */ guint16 dlength, /* length of data part given in header */ guint32 offset) /* Offset on data part +4 */ { gboolean know_data = FALSE; guint8 data_type; guint16 byte_count; guint16 item_count; guint16 i; switch(subfunc) { case S7COMM_UD_SUBF_PROG_REQDIAGDATA1: case S7COMM_UD_SUBF_PROG_REQDIAGDATA2: /* start variable table or block online view */ /* TODO: Can only handle requests/response, not the "following" telegrams because it's necessary to correlate them with the previous request */ if (type != S7COMM_UD_TYPE_PUSH) { offset = s7comm_decode_ud_prog_reqdiagdata(tvb, data_tree, subfunc, offset); know_data = TRUE; } break; case S7COMM_UD_SUBF_PROG_VARTAB1: /* online status in variable table */ offset += 1; /* 1 Byte const 0, skip */ data_type = tvb_get_guint8(tvb, offset); /* 1 Byte type: 0x14 = Request, 0x04 = Response */ proto_tree_add_uint(data_tree, hf_s7comm_vartab_data_type, tvb, offset, 1, data_type); offset += 1; byte_count = tvb_get_ntohs(tvb, offset); /* 2 Bytes: Number of bytes of item-data including item-count */ proto_tree_add_uint(data_tree, hf_s7comm_vartab_byte_count, tvb, offset, 2, byte_count); offset += 2; switch (data_type) { case S7COMM_UD_SUBF_PROG_VARTAB_TYPE_REQ: /*** Request of data areas ***/ /* 20 Bytes unknown part */ proto_tree_add_item(data_tree, hf_s7comm_vartab_unknown, tvb, offset, 20, ENC_NA); offset += 20; item_count = tvb_get_ntohs(tvb, offset); /* 2 Bytes header: number of items following */ proto_tree_add_uint(data_tree, hf_s7comm_vartab_item_count, tvb, offset, 2, item_count); offset += 2; /* parse item data */ for (i = 0; i < item_count; i++) { offset = s7comm_decode_ud_prog_vartab_req_item(tvb, offset, data_tree, i); } know_data = TRUE; break; case S7COMM_UD_SUBF_PROG_VARTAB_TYPE_RES: /*** Response of PLC to requested data-areas ***/ /* 4 Bytes unknown part */ proto_tree_add_item(data_tree, hf_s7comm_vartab_unknown, tvb, offset, 4, ENC_NA); offset += 4; item_count = tvb_get_ntohs(tvb, offset); /* 2 Bytes: number of items following */ proto_tree_add_uint(data_tree, hf_s7comm_vartab_item_count, tvb, offset, 2, item_count); offset += 2; /* parse item data */ for (i = 0; i < item_count; i++) { offset = s7comm_decode_ud_prog_vartab_res_item(tvb, offset, data_tree, i); } know_data = TRUE; break; } } if (know_data == FALSE && dlength > 4) { proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 4, ENC_NA); offset += dlength; } 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_item *item = NULL; proto_tree *param_tree = NULL; proto_tree *data_tree = NULL; guint8 ret_val; guint8 tsize; guint16 len; guint32 offset_temp; guint8 type; guint8 funcgroup; guint8 subfunc; guint8 data_unit_ref = 0; guint8 last_data_unit = 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); /* Try do decode some functions... * Some functions may use data that doesn't fit one telegram */ offset_temp = offset; /* Save offset */ /* 3 bytes constant head */ proto_tree_add_item(param_tree, hf_s7comm_userdata_param_head, tvb, offset_temp, 3, ENC_BIG_ENDIAN); offset_temp += 3; /* 1 byte length of following parameter (8 or 12 bytes) */ proto_tree_add_item(param_tree, hf_s7comm_userdata_param_len, tvb, offset_temp, 1, ENC_BIG_ENDIAN); offset_temp += 1; /* 1 byte unknown, maybe indicating request/response */ proto_tree_add_item(param_tree, hf_s7comm_userdata_param_reqres2, tvb, offset_temp, 1, ENC_BIG_ENDIAN); offset_temp += 1; /* High nibble (following/request/response) */ type = (tvb_get_guint8(tvb, offset_temp) & 0xf0) >> 4; funcgroup = (tvb_get_guint8(tvb, offset_temp) & 0x0f); proto_tree_add_item(param_tree, hf_s7comm_userdata_param_type, tvb, offset_temp, 1, ENC_BIG_ENDIAN); 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: 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: 0x%02x")); /* Low nibble function group */ proto_tree_add_item(param_tree, hf_s7comm_userdata_param_funcgroup, tvb, offset_temp, 1, ENC_BIG_ENDIAN); offset_temp += 1; /* 1 Byte subfunction */ subfunc = tvb_get_guint8(tvb, offset_temp); switch (funcgroup){ case S7COMM_UD_FUNCGROUP_PROG: 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_prog_subfunc_names, "Unknown subfunc: 0x%02x")); proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, userdata_prog_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_MODETRANS: proto_tree_add_uint(param_tree, hf_s7comm_modetrans_param_subfunc, tvb, offset_temp, 1, subfunc); col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", val_to_str(subfunc, modetrans_param_subfunc_names, "Unknown subfunc: 0x%02x")); proto_item_append_text(param_tree, " ->(%s)", val_to_str(subfunc, modetrans_param_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 */ proto_tree_add_item(param_tree, hf_s7comm_userdata_param_seq_num, tvb, offset_temp, 1, ENC_BIG_ENDIAN); offset_temp += 1; if (plength >= 12) { /* 1 Byte data unit reference. If packet is fragmented, all packets with this number belong together */ 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(param_tree, hf_s7comm_param_errcod, tvb, offset_temp, 2, ENC_BIG_ENDIAN); } /********************************** * Add data tree */ offset += plength; /* set offset to the beginning of the data part */ item = proto_tree_add_item(tree, hf_s7comm_data, tvb, offset, dlength, ENC_NA); data_tree = proto_item_add_subtree(item, ett_s7comm_data); /* the first 4 bytes of the data part of a userdata telegram are the same for all types */ if (dlength >= 4) { 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; /* Call function to decode the rest of the data part * decode only when there is a data part length greater 4 bytes */ if (dlength > 4) { switch (funcgroup){ case S7COMM_UD_FUNCGROUP_PROG: offset = s7comm_decode_ud_prog_subfunc(tvb, data_tree, type, subfunc, dlength, offset); break; case S7COMM_UD_FUNCGROUP_CYCLIC: offset = s7comm_decode_ud_cyclic_subfunc(tvb, data_tree, type, subfunc, dlength, offset); break; case S7COMM_UD_FUNCGROUP_BLOCK: offset = s7comm_decode_ud_block_subfunc(tvb, pinfo, data_tree, type, subfunc, ret_val, tsize, len, dlength, offset); break; case S7COMM_UD_FUNCGROUP_CPU: if (subfunc == S7COMM_UD_SUBF_CPU_READSZL) { offset = s7comm_decode_ud_cpu_szl_subfunc(tvb, pinfo, data_tree, type, ret_val, len, dlength, data_unit_ref, last_data_unit, offset); } else if (subfunc == S7COMM_UD_SUBF_CPU_NOTIFY_IND || subfunc == S7COMM_UD_SUBF_CPU_NOTIFY8_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARM8_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMSQ_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMS_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMACK_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARMACK || subfunc == S7COMM_UD_SUBF_CPU_ALARM8LOCK || subfunc == S7COMM_UD_SUBF_CPU_ALARM8LOCK_IND || subfunc == S7COMM_UD_SUBF_CPU_ALARM8UNLOCK || subfunc == S7COMM_UD_SUBF_CPU_ALARM8UNLOCK_IND || (subfunc == S7COMM_UD_SUBF_CPU_ALARMQUERY && type != S7COMM_UD_TYPE_RES)) { offset = s7comm_decode_ud_cpu_alarm_main(tvb, pinfo, data_tree, type, subfunc, offset); } else if (subfunc == S7COMM_UD_SUBF_CPU_ALARMQUERY && type == S7COMM_UD_TYPE_RES) { offset = s7comm_decode_ud_cpu_alarm_query_response(tvb, pinfo, data_tree, offset); } else if (subfunc == S7COMM_UD_SUBF_CPU_DIAGMSG) { offset = s7comm_decode_ud_cpu_diagnostic_message(tvb, pinfo, TRUE, data_tree, offset); } else if (subfunc == S7COMM_UD_SUBF_CPU_MSGS) { offset = s7comm_decode_message_service(tvb, pinfo, data_tree, type, dlength - 4, offset); } else { /* print other currently unknown data as raw bytes */ proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 4, ENC_NA); } break; case S7COMM_UD_FUNCGROUP_SEC: offset = s7comm_decode_ud_security_subfunc(tvb, data_tree, dlength, offset); break; case S7COMM_UD_FUNCGROUP_PBC: offset = s7comm_decode_ud_pbc_subfunc(tvb, data_tree, dlength, offset); break; case S7COMM_UD_FUNCGROUP_TIME: offset = s7comm_decode_ud_time_subfunc(tvb, data_tree, type, subfunc, ret_val, dlength, offset); break; default: break; } } } 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)) { 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_param_hex1x(tvb, pinfo, param_tree, plength, offset -1); break; case S7COMM_FUNC_PLC_CONTROL: offset = s7comm_decode_plc_controls_param_hex28(tvb, pinfo, param_tree, 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; 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; /*----------------- 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); 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_add_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) { 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; } 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); break; } /*else { Unknown pdu, maybe passed to another dissector? } */ return TRUE; } /******************************************************************************************************* *******************************************************************************************************/ void proto_register_s7comm (void) { /* 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, VALS(param_errcode_names), 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, 0x7fff8, 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 }}, /* 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_head, { "Parameter head", "s7comm.param.userdata.head", FT_UINT24, BASE_HEX, NULL, 0x0, "Header before parameter (constant 0x000112)", HFILL }}, { &hf_s7comm_userdata_param_len, { "Parameter length", "s7comm.param.userdata.length", FT_UINT8, BASE_DEC, NULL, 0x0, "Length of following parameter data (without head)", HFILL }}, { &hf_s7comm_userdata_param_reqres2, { "Unknown (Request/Response)", "s7comm.param.userdata.reqres1", FT_UINT8, BASE_HEX, NULL, 0x0, "Unknown part, possible request/response (0x11, 0x12), but not in programmer commands", HFILL }}, { &hf_s7comm_userdata_param_type, { "Type", "s7comm.param.userdata.type", FT_UINT8, BASE_DEC, VALS(userdata_type_names), 0xf0, "Type of parameter", HFILL }}, { &hf_s7comm_userdata_param_funcgroup, { "Function group", "s7comm.param.userdata.funcgroup", FT_UINT8, BASE_DEC, VALS(userdata_functiongroup_names), 0x0f, NULL, HFILL }}, { &hf_s7comm_userdata_param_subfunc_prog, { "Subfunction", "s7comm.param.userdata.subfunc", FT_UINT8, BASE_DEC, VALS(userdata_prog_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_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_UINT8, BASE_DEC, VALS(blocktype_names), 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_const1, { "Constant 1", "s7comm.blockinfo.res_const1", FT_UINT8, BASE_HEX, NULL, 0x0, "Possible constant 1", 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, diagnostic data */ { &hf_s7comm_diagdata_req_askheadersize, { "Ask header size", "s7comm.diagdata.req.askheadersize", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_asksize, { "Ask size", "s7comm.diagdata.req.asksize", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_unknown, { "Unknown byte(s) diagdata", "s7comm.diagdata.req.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_answersize, { "Answer size", "s7comm.diagdata.req.answersize", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_block_type, { "Block type", "s7comm.diagdata.req.blocktype", FT_UINT8, 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 }}, { &hf_s7comm_diagdata_req_number_of_lines, { "Number of lines", "s7comm.diagdata.req.number_of_lines", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_line_address, { "Address", "s7comm.diagdata.req.line_address", 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 (PLC control functions) ans 0x29 */ { &hf_s7comm_data_plccontrol_part1_unknown, { "Part 1 unknown bytes", "s7comm.data.plccontrol.part1_unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_data_plccontrol_part1_len, { "Length part 1", "s7comm.data.plccontrol.part1_len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of part 1 in bytes", HFILL }}, { &hf_s7comm_data_plccontrol_argument, { "Argument", "s7comm.data.plccontrol.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_part1_unknown2, { "Unknown byte", "s7comm.data.plccontrol.part1_unknown2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_data_plccontrol_block_unknown, { "Unknown char before Block type", "s7comm.data.plccontrol.block_unknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_data_plccontrol_block_type, { "Block type", "s7comm.data.plccontrol.block_type", FT_UINT8, BASE_DEC, VALS(blocktype_names), 0x0, NULL, HFILL }}, { &hf_s7comm_data_plccontrol_block_num, { "Block number", "s7comm.data.plccontrol.block_number", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_data_plccontrol_dest_filesys, { "Destination filesystem", "s7comm.data.plccontrol.dest_filesys", FT_STRING, BASE_NONE, 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 }}, { &hf_s7comm_data_plccontrol_pi_service, { "PI (program invocation) Service", "s7comm.data.plccontrol.pi_service", FT_STRING, BASE_NONE, NULL, 0x0, "Known: _INSE = Activate a module, _DELE = Delete a passive module, _PROGRAM = Start/Stop the PLC, _PLC_MEMORYRESET = Reset the PLC memory" , 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_part1_len, { "Length part 1", "s7comm.data.blockcontrol.part1_len", FT_UINT8, BASE_DEC, NULL, 0x0, "Length of part 1 in bytes", 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_unknown, { "Unknown char before Block type", "s7comm.data.blockcontrol.block_unknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_data_blockcontrol_block_type, { "Block type", "s7comm.data.blockcontrol.block_type", FT_UINT8, BASE_DEC, VALS(blocktype_names), 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 }}, /* Variable table */ { &hf_s7comm_vartab_data_type, { "Type of data", "s7comm.vartab.data_type", FT_UINT8, BASE_DEC, VALS(userdata_prog_vartab_type_names), 0x0, NULL, HFILL }}, { &hf_s7comm_vartab_byte_count, { "Byte count", "s7comm.vartab.byte_count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_vartab_unknown, { "Unknown byte(s) vartab", "s7comm.vartab.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_vartab_item_count, { "Item count", "s7comm.vartab.item_count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_vartab_req_memory_area, { "Memory area", "s7comm.vartab.req.memory_area", FT_UINT8, BASE_DEC, VALS(userdata_prog_vartab_area_names), 0x0, NULL, HFILL }}, { &hf_s7comm_vartab_req_repetition_factor, { "Repetition factor", "s7comm.vartab.req.repetition_factor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_vartab_req_db_number, { "DB number", "s7comm.vartab.req.db_number", FT_UINT16, BASE_DEC, NULL, 0x0, "DB number, when area is DB", HFILL }}, { &hf_s7comm_vartab_req_startaddress, { "Startaddress", "s7comm.vartab.req.startaddress", FT_UINT16, BASE_DEC, NULL, 0x0, "Startaddress / byteoffset", HFILL }}, /* cyclic data */ { &hf_s7comm_cycl_interval_timebase, { "Interval timebase", "s7comm.cyclic.interval_timebase", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_cycl_interval_time, { "Interval time", "s7comm.cyclic.interval_time", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, /* PBC, Programmable Block Functions */ { &hf_s7comm_pbc_unknown, { "PBC BSEND/BRECV unknown", "s7comm.pbc.bsend.unknown", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_pbc_r_id, { "PBC BSEND/BRECV R_ID", "s7comm.pbc.req.bsend.r_id", FT_UINT32, BASE_HEX, 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 }}, /* 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 splitted 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_subfunc, { "Current mode", "s7comm.param.modetrans.subfunc", FT_UINT8, BASE_DEC, VALS(modetrans_param_subfunc_names), 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 }}, }; 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 }; 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)); } /* 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", "s7comm_cotp_is", proto_s7comm, HEURISTIC_ENABLE); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */