From 90b1d0f3e642d0764298243dc5638bbcc458a856 Mon Sep 17 00:00:00 2001 From: Thomas Wiens Date: Sat, 13 Jul 2019 23:32:55 +0200 Subject: s7comm: Adding and redesign of test and installation functions New decoded TIS-functions: Jobs, BSTACK, ISTACK, LSTACK, Forces, Variable status, block status, breakpoints Change-Id: I7902bfcfe8d622a3e19c0c3b77492e7ad4ddecf5 Reviewed-on: https://code.wireshark.org/review/33927 Petri-Dish: Anders Broman Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- epan/dissectors/packet-s7comm.c | 2016 +++++++++++++++++++++++++++++++++------ 1 file changed, 1742 insertions(+), 274 deletions(-) (limited to 'epan/dissectors/packet-s7comm.c') diff --git a/epan/dissectors/packet-s7comm.c b/epan/dissectors/packet-s7comm.c index 18a329824b..1b13455a19 100644 --- a/epan/dissectors/packet-s7comm.c +++ b/epan/dissectors/packet-s7comm.c @@ -35,6 +35,7 @@ static int proto_s7comm = -1; /* Forward declarations */ void proto_reg_handoff_s7comm(void); void proto_register_s7comm (void); +static guint32 s7comm_decode_ud_tis_data(tvbuff_t *tvb, proto_tree *tree, guint8 type, guint8 subfunc, guint16 td_size, guint32 offset); /************************************************************************** * PDU types @@ -687,18 +688,6 @@ static const value_string userdata_functiongroup_names[] = { /************************************************************************** * Variable status: Area of data request - */ -#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 0=BOOL @@ -806,6 +795,27 @@ static const value_string userdata_prog_subfunc_names[] = { { 0, NULL } }; +/************************************************************************** + * Variable status: Trigger point + */ +static const value_string userdata_varstat_trgevent_names[] = { + { 0x0000, "Immediately" }, + { 0x0100, "System Trigger" }, + { 0x0200, "System checkpoint main cycle start" }, + { 0x0300, "System checkpoint main cycle end" }, + { 0x0400, "Mode transition RUN-STOP" }, + { 0x0500, "After code address" }, + { 0x0600, "Code address area" }, + { 0x0601, "Code address area with call environment" }, /* Call conditions like opened DB/DI or called block */ + { 0x0700, "Data address" }, + { 0x0800, "Data address area" }, + { 0x0900, "Local data address" }, + { 0x0a00, "Local data address area" }, + { 0x0b00, "Range trigger" }, + { 0x0c00, "Before code address" }, + { 0, NULL } +}; + /************************************************************************** * Names of userdata subfunctions in group 2 (cyclic data) */ @@ -1240,17 +1250,159 @@ static const int *s7comm_userdata_blockinfo_flags_fields[] = { 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 */ +/* Programmer commands / Test and installation (TIS) functions */ +static gint hf_s7comm_tis_parameter = -1; +static gint hf_s7comm_tis_data = -1; +static gint hf_s7comm_tis_parametersize = -1; +static gint hf_s7comm_tis_datasize = -1; +static gint hf_s7comm_tis_param1 = -1; +static gint hf_s7comm_tis_param2 = -1; +static const value_string tis_param2_names[] = { /* Values and their meaning are not always clearly defined in every function */ + { 0, "Update Monitor Variables / Activate Modify Values"}, + { 1, "Monitor Variable / Modify Variable" }, + { 2, "Modify Variable permanent" }, + { 256, "Force immediately" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_param3 = -1; +static const value_string tis_param3_names[] = { + { 0, "Every cycle (permanent)" }, + { 1, "Once" }, + { 2, "Always (force)" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_answersize = -1; +static gint hf_s7comm_tis_param5 = -1; +static gint hf_s7comm_tis_param6 = -1; +static gint hf_s7comm_tis_param7 = -1; +static gint hf_s7comm_tis_param8 = -1; +static gint hf_s7comm_tis_param9 = -1; +static gint hf_s7comm_tis_trgevent = -1; +static gint hf_s7comm_tis_res_param1 = -1; +static gint hf_s7comm_tis_res_param2 = -1; +static gint hf_s7comm_tis_job_function = -1; +static gint hf_s7comm_tis_job_seqnr = -1; +static gint hf_s7comm_tis_job_reserved = -1; + + + +/* B/I/L Stack */ +static gint hf_s7comm_tis_interrupted_blocktype = -1; +static gint hf_s7comm_tis_interrupted_blocknr = -1; +static gint hf_s7comm_tis_interrupted_address = -1; +static gint hf_s7comm_tis_interrupted_prioclass = -1; +static gint hf_s7comm_tis_continued_blocktype = -1; +static gint hf_s7comm_tis_continued_blocknr = -1; +static gint hf_s7comm_tis_continued_address = -1; +static gint hf_s7comm_tis_breakpoint_blocktype = -1; +static gint hf_s7comm_tis_breakpoint_blocknr = -1; +static gint hf_s7comm_tis_breakpoint_address = -1; +static gint hf_s7comm_tis_breakpoint_reserved = -1; + +static gint hf_s7comm_tis_p_callenv = -1; +static const value_string tis_p_callenv_names[] = { + { 0, "Specified call environment"}, + { 2, "Specified global and/or instance data block"}, + { 0, NULL } +}; +static gint hf_s7comm_tis_p_callcond = -1; +static const value_string tis_p_callcond_names[] = { + { 0x0000, "Not set" }, + { 0x0001, "On block number" }, + { 0x0101, "On block number with code address" }, + { 0x0a00, "On DB1 (DB) content" }, + { 0x000a, "On DB2 (DI) content" }, + { 0x0a0a, "On DB1 (DB) and DB2 (DI) content" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_p_callcond_blocktype = -1; +static gint hf_s7comm_tis_p_callcond_blocknr = -1; +static gint hf_s7comm_tis_p_callcond_address = -1; + + +static gint hf_s7comm_tis_register_db1_type = -1; +static gint hf_s7comm_tis_register_db2_type = -1; +static gint hf_s7comm_tis_register_db1_nr = -1; +static gint hf_s7comm_tis_register_db2_nr = -1; +static gint hf_s7comm_tis_register_accu1 = -1; +static gint hf_s7comm_tis_register_accu2 = -1; +static gint hf_s7comm_tis_register_accu3 = -1; +static gint hf_s7comm_tis_register_accu4 = -1; +static gint hf_s7comm_tis_register_ar1 = -1; +static gint hf_s7comm_tis_register_ar2 = -1; +static gint hf_s7comm_tis_register_stw = -1; +static gint hf_s7comm_tis_exithold_until = -1; +static const value_string tis_exithold_until_names[] = { + { 0, "Next breakpoint" }, + { 1, "Next statement" }, + { 0, NULL } +}; +static gint hf_s7comm_tis_exithold_res1 = -1; +static gint hf_s7comm_tis_bstack_nest_depth = -1; +static gint hf_s7comm_tis_bstack_reserved = -1; +static gint hf_s7comm_tis_istack_reserved = -1; +static gint hf_s7comm_tis_lstack_reserved = -1; +static gint hf_s7comm_tis_lstack_size = -1; +static gint hf_s7comm_tis_lstack_data = -1; +static gint hf_s7comm_tis_blockstat_flagsunknown = -1; +static gint hf_s7comm_tis_blockstat_number_of_lines = -1; +static gint hf_s7comm_tis_blockstat_line_address = -1; +static gint hf_s7comm_tis_blockstat_data = -1; +static gint hf_s7comm_tis_blockstat_reserved = -1; + +/* Organization block local data */ +static gint hf_s7comm_ob_ev_class = -1; +static gint hf_s7comm_ob_scan_1 = -1; +static gint hf_s7comm_ob_strt_inf = -1; +static gint hf_s7comm_ob_flt_id = -1; +static gint hf_s7comm_ob_priority = -1; +static gint hf_s7comm_ob_number = -1; +static gint hf_s7comm_ob_reserved_1 = -1; +static gint hf_s7comm_ob_reserved_2 = -1; +static gint hf_s7comm_ob_reserved_3 = -1; +static gint hf_s7comm_ob_reserved_4 = -1; +static gint hf_s7comm_ob_reserved_4_dw = -1; +static gint hf_s7comm_ob_prev_cycle = -1; +static gint hf_s7comm_ob_min_cycle = -1; +static gint hf_s7comm_ob_max_cycle = -1; +static gint hf_s7comm_ob_period_exe = -1; +static gint hf_s7comm_ob_sign = -1; +static gint hf_s7comm_ob_dtime = -1; +static gint hf_s7comm_ob_phase_offset = -1; +static gint hf_s7comm_ob_exec_freq = -1; +static gint hf_s7comm_ob_io_flag = -1; +static gint hf_s7comm_ob_mdl_addr = -1; +static gint hf_s7comm_ob_point_addr = -1; +static gint hf_s7comm_ob_inf_len = -1; +static gint hf_s7comm_ob_alarm_type = -1; +static gint hf_s7comm_ob_alarm_slot = -1; +static gint hf_s7comm_ob_alarm_spec = -1; +static guint hf_s7comm_ob_error_info = -1; +static guint hf_s7comm_ob_err_ev_class = -1; +static guint hf_s7comm_ob_err_ev_num = -1; +static guint hf_s7comm_ob_err_ob_priority = -1; +static guint hf_s7comm_ob_err_ob_num = -1; +static guint hf_s7comm_ob_rack_cpu = -1; +static guint hf_s7comm_ob_8x_fault_flags = -1; +static guint hf_s7comm_ob_mdl_type_b = -1; +static guint hf_s7comm_ob_mdl_type_w = -1; +static guint hf_s7comm_ob_rack_num = -1; +static guint hf_s7comm_ob_racks_flt = -1; +static guint hf_s7comm_ob_strtup = -1; +static guint hf_s7comm_ob_stop = -1; +static guint hf_s7comm_ob_strt_info = -1; +static guint hf_s7comm_ob_sw_flt = -1; +static guint hf_s7comm_ob_blk_type = -1; +static guint hf_s7comm_ob_flt_reg = -1; +static guint hf_s7comm_ob_flt_blk_num = -1; +static guint hf_s7comm_ob_prg_addr = -1; +static guint hf_s7comm_ob_mem_area = -1; +static guint hf_s7comm_ob_mem_addr = -1; + +static gint hf_s7comm_diagdata_req_block_type = -1; +static gint hf_s7comm_diagdata_req_block_num = -1; +static gint hf_s7comm_diagdata_req_startaddr_awl = -1; +static gint hf_s7comm_diagdata_req_saz = -1; /* Flags for requested registers in diagnostic data telegrams */ static gint hf_s7comm_diagdata_registerflag = -1; /* Registerflags */ @@ -1540,8 +1692,6 @@ static gint hf_s7comm_data_ncprg_filepath = -1; static gint hf_s7comm_data_ncprg_filedata = -1; /* Variable status */ -static gint hf_s7comm_varstat_data_type = -1; /* Type of data, 1 byte, stringlist userdata_prog_vartab_type_names */ -static gint hf_s7comm_varstat_byte_count = -1; /* Byte count, 2 bytes, int */ static gint hf_s7comm_varstat_unknown = -1; /* Unknown byte(s), hex */ static gint hf_s7comm_varstat_item_count = -1; /* Item count, 2 bytes, int */ static gint hf_s7comm_varstat_req_memory_area = -1; /* Memory area, 1 byte, stringlist userdata_prog_varstat_area_names */ @@ -2342,6 +2492,8 @@ static gint ett_s7comm_cpu_alarm_message_object = -1; /* Subtree f static gint ett_s7comm_cpu_alarm_message_timestamp = -1; /* Subtree for an alarm message timestamp */ static gint ett_s7comm_cpu_alarm_message_associated_value = -1; /* Subtree for an alarm message associated value */ static gint ett_s7comm_cpu_diag_msg = -1; /* Subtree for a CPU diagnostic message */ +static gint ett_s7comm_prog_parameter = -1; +static gint ett_s7comm_prog_data = -1; static const char mon_names[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; @@ -3620,82 +3772,80 @@ s7comm_decode_plc_controls_updownload(tvbuff_t *tvb, /******************************************************************************************************* * - * PDU Type: User Data -> Function group 1 -> Programmer commands -> Request diagnostic data (0x13 or 0x01) + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Block status (0x13 or 0x01) * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_prog_reqdiagdata(tvbuff_t *tvb, - proto_tree *data_tree, - guint8 subfunc, /* Subfunction */ - guint32 offset) +s7comm_decode_ud_tis_blockstat(tvbuff_t *tvb, + proto_tree *td_tree, + guint16 td_size, + guint8 type, + guint8 subfunc, + guint32 offset) { proto_item *item = NULL; proto_tree *item_tree = NULL; guint16 line_nr; guint16 line_cnt; - guint16 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; + if (type == S7COMM_UD_TYPE_REQ) { + if (subfunc == S7COMM_UD_SUBF_PROG_BLOCKSTAT2) { + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_flagsunknown, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + line_cnt = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_tis_blockstat_number_of_lines, tvb, offset, 1, line_cnt); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + } else { + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + line_cnt = (td_size - 2) / 2; } - proto_tree_add_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, + proto_tree_add_bitmask(td_tree, tvb, offset, hf_s7comm_diagdata_registerflag, ett_s7comm_diagdata_registerflag, s7comm_diagdata_registerflag_fields, ENC_BIG_ENDIAN); offset += 1; - } + if (subfunc == S7COMM_UD_SUBF_PROG_BLOCKSTAT2) { + item_size = 4; + } else { + item_size = 2; + } + for (line_nr = 0; line_nr < line_cnt; line_nr++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, item_size, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + if (subfunc == S7COMM_UD_SUBF_PROG_BLOCKSTAT2) { + proto_tree_add_item(item_tree, hf_s7comm_tis_blockstat_line_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + proto_tree_add_item(item_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + registerflags = tvb_get_guint8(tvb, offset); + make_registerflag_string(str_flags, registerflags, sizeof(str_flags)); + proto_item_append_text(item, " [%d]: (%s)", line_nr+1, str_flags); + proto_tree_add_bitmask(item_tree, tvb, offset, hf_s7comm_diagdata_registerflag, + ett_s7comm_diagdata_registerflag, s7comm_diagdata_registerflag_fields, ENC_BIG_ENDIAN); + offset += 1; + } + } else if (type == S7COMM_UD_TYPE_PUSH) { + /* The response data can only be dissected when the requested registers for each line + * from the job setup is known. As the STW is only 16 Bits and all other registers 32 Bits, + * this has no fixed structure. + * The only thing that can be shown is the start address. Next the requested registers, + * the start address of next line with the requested registers and so on. + */ + proto_tree_add_item(td_tree, hf_s7comm_diagdata_req_startaddr_awl, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_data, tvb, offset, td_size - 2, ENC_NA); + offset += (td_size - 2); + } else { + /* TODO: Show unknown data as raw bytes */ + proto_tree_add_item(td_tree, hf_s7comm_tis_blockstat_reserved, tvb, offset, td_size, ENC_NA); + offset += td_size; + } return offset; } @@ -3708,7 +3858,8 @@ static guint32 s7comm_decode_ud_tis_item_address(tvbuff_t *tvb, guint32 offset, proto_tree *sub_tree, - guint16 item_no) + guint16 item_no, + gchar *add_text) { guint32 bytepos = 0; guint16 len = 0; @@ -3722,7 +3873,7 @@ s7comm_decode_ud_tis_item_address(tvbuff_t *tvb, sub_tree = proto_item_add_subtree(item, ett_s7comm_param_item); - proto_item_append_text(item, " [%d]:", item_no + 1); + proto_item_append_text(item, " [%d]%s:", item_no + 1, add_text); /* Area, 1 byte */ area = tvb_get_guint8(tvb, offset); @@ -3831,14 +3982,15 @@ s7comm_decode_ud_tis_item_address(tvbuff_t *tvb, /******************************************************************************************************* * - * PDU Type: User Data -> Function group 1 -> Programmer commands -> Variable table -> response + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Item value * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_prog_vartab_res_item(tvbuff_t *tvb, - guint32 offset, - proto_tree *sub_tree, - guint16 item_no) +s7comm_decode_ud_tis_item_value(tvbuff_t *tvb, + guint32 offset, + proto_tree *sub_tree, + guint16 item_no, + gchar *add_text) { guint16 len = 0, len2 = 0; guint8 ret_val = 0; @@ -3861,7 +4013,7 @@ s7comm_decode_ud_prog_vartab_res_item(tvbuff_t *tvb, /* the PLC places extra bytes at the end if length is not a multiple of 2 */ if (len % 2) { len2 = len + 1; - }else { + } else { len2 = len; } } @@ -3869,7 +4021,7 @@ s7comm_decode_ud_prog_vartab_res_item(tvbuff_t *tvb, 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_item_append_text(item, " [%d]%s: (%s)", item_no + 1, add_text, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); proto_tree_add_uint(sub_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); proto_tree_add_uint(sub_tree, hf_s7comm_data_transport_size, tvb, offset + 1, 1, tsize); @@ -3889,118 +4041,1225 @@ s7comm_decode_ud_prog_vartab_res_item(tvbuff_t *tvb, /******************************************************************************************************* * - * PDU Type: User Data -> Function group 5 -> Security functions? + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Force (0x09) * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_security_subfunc(tvbuff_t *tvb, - proto_tree *data_tree, - guint32 dlength, - guint32 offset) +s7comm_decode_ud_tis_force(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) { - /* Display dataset as raw bytes. Maybe this part can be extended with further knowledge. */ - proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); - offset += dlength; + guint16 item_count; + guint16 i; + guint8 ret_val = 0; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + switch (type) { + case S7COMM_UD_TYPE_REQ: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_address(tvb, offset, td_tree, i, " Address to force"); + } + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_value(tvb, offset, td_tree, i, " Value to force"); + } + break; + case S7COMM_UD_TYPE_PUSH: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 1, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + ret_val = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + proto_item_append_text(item, " [%d]: (%s)", i + 1, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + offset += 1; + } + if (item_count % 2) { + proto_tree_add_item(item_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + break; + } return offset; } /******************************************************************************************************* * - * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV), before reassembly + * PDU Type: User Data -> Function group 1 -> Programmer commands / Test and installation functions + * Dissects the parameter part * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_pbc_pre_reass(tvbuff_t *tvb, - packet_info *pinfo, - proto_tree *data_tree, - guint8 type, /* Type of data (request/response) */ - guint16 *dlength, - guint32 *r_id, /* R_ID of the PBC communication */ - guint32 offset) +s7comm_decode_ud_tis_param(tvbuff_t *tvb, + proto_tree *tree, + guint8 type, + guint16 tp_size, + guint32 offset) { - if ((type == S7COMM_UD_TYPE_REQ || type == S7COMM_UD_TYPE_RES) && (*dlength >= 8)) { - proto_tree_add_item(data_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); - offset += 1; - proto_tree_add_item(data_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, ENC_BIG_ENDIAN); - offset += 1; - proto_tree_add_item(data_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, ENC_BIG_ENDIAN); - offset += 1; - /* 0x00 when passive partners is sending, 0xcc when active partner is sending? */ - proto_tree_add_item(data_tree, hf_s7comm_pbc_unknown, tvb, offset, 1, ENC_BIG_ENDIAN); - offset += 1; - proto_tree_add_item(data_tree, hf_s7comm_pbc_r_id, tvb, offset, 4, ENC_BIG_ENDIAN); - *r_id = tvb_get_ntohl(tvb, offset); - col_append_fstr(pinfo->cinfo, COL_INFO, " R_ID=0x%X", *r_id); - offset += 4; - *dlength -= 8; + guint32 start_offset; + guint32 callenv_setup = 0; + proto_item *item = NULL; + proto_tree *tp_tree = NULL; + + start_offset = offset; + if (tp_size > 0) { + item = proto_tree_add_item(tree, hf_s7comm_tis_parameter, tvb, offset, tp_size, ENC_NA); + tp_tree = proto_item_add_subtree(item, ett_s7comm_prog_parameter); + if (type == S7COMM_UD_TYPE_REQ) { + if (tp_size >= 4) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_param1, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param2, tvb, offset, 2, ENC_NA); + offset += 2; + } + if (tp_size >= 20) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_param3, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_answersize, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param5, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param6, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param7, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param8, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_param9, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_trgevent, tvb, offset, 2, ENC_NA); + offset += 2; + } + if (tp_size >= 26) { + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_block_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_block_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_startaddr_awl, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + if (tp_size >= 28) { + proto_tree_add_item(tp_tree, hf_s7comm_diagdata_req_saz, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + if (tp_size >= 36) { + proto_tree_add_item_ret_uint(tp_tree, hf_s7comm_tis_p_callenv, tvb, offset, 2, ENC_BIG_ENDIAN, &callenv_setup); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + if (callenv_setup == 2) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } else { + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + if (tp_size >= 38) { + proto_tree_add_item(tp_tree, hf_s7comm_tis_p_callcond_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + } + } + } else { + proto_tree_add_item(tp_tree, hf_s7comm_tis_res_param1, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(tp_tree, hf_s7comm_tis_res_param2, tvb, offset, 2, ENC_NA); + offset += 2; + } + } + /* May be we don't know all values when here, so set offset to the given length */ + return start_offset + tp_size; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Disable job (0x0d), Enable job (0x0e), + * Delete job (0x0f), Read job list (0x10), + * Read job (0x11) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_jobs(tvbuff_t *tvb, + proto_tree *td_tree, + guint16 td_size, + guint8 type, + guint8 subfunc, + guint32 offset) +{ + guint16 i; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + guint16 job_tp_size; + guint16 job_td_size; + proto_tree *job_td_tree = NULL; + guint8 job_subfunc; + + if (type == S7COMM_UD_TYPE_REQ) { + switch (subfunc) { + case S7COMM_UD_SUBF_PROG_DELETEJOB: + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + /* fallthrough */ + case S7COMM_UD_SUBF_PROG_ENABLEJOB: + case S7COMM_UD_SUBF_PROG_DISABLEJOB: + case S7COMM_UD_SUBF_PROG_READJOB: + proto_tree_add_item(td_tree, hf_s7comm_tis_job_function, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_job_seqnr, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case S7COMM_UD_SUBF_PROG_READJOBLIST: + /* 4 bytes, possible as filter? */ + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_SUBF_PROG_REPLACEJOB: + proto_tree_add_item(td_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + /* The job which has to be replaced */ + job_subfunc = tvb_get_guint8(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_job_function, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_job_seqnr, tvb, offset, 1, ENC_NA); + offset += 1; + job_tp_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_parametersize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + job_td_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_datasize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* New job parameter tree */ + if (job_tp_size > 0) { + offset = s7comm_decode_ud_tis_param(tvb, td_tree, S7COMM_UD_TYPE_REQ, job_tp_size, offset); + } + /* New job data tree */ + if (job_td_size > 0) { + offset = s7comm_decode_ud_tis_data(tvb, td_tree, S7COMM_UD_TYPE_REQ, job_subfunc, job_td_size, offset); + } + break; + } + } else { + switch (subfunc) { + case S7COMM_UD_SUBF_PROG_READJOBLIST: + /* 4 bytes each job: + * - 2 bytes job id + * - 2 bytes status: 1=active, 0=idle/pending? + */ + for (i = 0; i < td_size / 4; i++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 4, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + proto_item_append_text(item, " [%d] Job", i + 1); + + proto_tree_add_item(item_tree, hf_s7comm_tis_job_function, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_job_seqnr, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_job_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + } + break; + case S7COMM_UD_SUBF_PROG_READJOB: + /* This includes the same data as in the job request. With the disadvantage that is does + * not contain information of the function, so the data can't be further dissected. + * We need to know the function from the request. + */ + job_tp_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_parametersize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + job_td_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_datasize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* Job parameter tree */ + if (job_tp_size > 0) { + offset = s7comm_decode_ud_tis_param(tvb, td_tree, S7COMM_UD_TYPE_REQ, job_tp_size, offset); + } + /* Job data tree */ + if (job_td_size > 0) { + item = proto_tree_add_item(td_tree, hf_s7comm_tis_data, tvb, offset, job_td_size, ENC_NA); + job_td_tree = proto_item_add_subtree(item, ett_s7comm_prog_data); + proto_tree_add_item(job_td_tree, hf_s7comm_tis_job_reserved, tvb, offset, job_td_size, ENC_NA); + offset += job_td_size; + } + break; + } } return offset; } /******************************************************************************************************* * - * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV) + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Variable status (0x03) * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_pbc_subfunc(tvbuff_t *tvb, - proto_tree *data_tree, - guint32 dlength, +s7comm_decode_ud_tis_varstat(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, guint32 offset) { - proto_tree_add_item(data_tree, hf_s7comm_pbc_len, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 2, ENC_NA); - offset += (dlength - 2); + guint16 item_count; + guint16 i; + switch (type) { + case S7COMM_UD_TYPE_REQ: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_address(tvb, offset, td_tree, i, " Address to read"); + } + break; + case S7COMM_UD_TYPE_PUSH: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_value(tvb, offset, td_tree, i, " Read data"); + } + break; + } return offset; } /******************************************************************************************************* * - * PDU Type: User Data -> NC programming functions (file download/upload), before reassembly + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Modify variable (0x08) * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_ncprg_pre_reass(tvbuff_t *tvb, - proto_tree *data_tree, - guint8 type, /* Type of data (request/response) */ - guint8 subfunc, /* Subfunction */ - guint16 *dlength, - guint32 offset) +s7comm_decode_ud_tis_modvar(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) { - if ((type == S7COMM_UD_TYPE_NCRES || type == S7COMM_UD_TYPE_NCPUSH) && - (subfunc == S7COMM_NCPRG_FUNCDOWNLOADBLOCK || - subfunc == S7COMM_NCPRG_FUNCUPLOAD || - subfunc == S7COMM_NCPRG_FUNCSTARTUPLOAD)) { - proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); - offset += 2; - *dlength -= 2; + guint16 item_count; + guint16 i; + guint8 ret_val = 0; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + + switch (type) { + case S7COMM_UD_TYPE_REQ: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_address(tvb, offset, td_tree, i, " Address to write"); + } + for (i = 0; i < item_count; i++) { + offset = s7comm_decode_ud_tis_item_value(tvb, offset, td_tree, i, " Data to write"); + } + break; + case S7COMM_UD_TYPE_PUSH: + item_count = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(td_tree, hf_s7comm_varstat_item_count, tvb, offset, 2, item_count); + offset += 2; + for (i = 0; i < item_count; i++) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 1, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + ret_val = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(item_tree, hf_s7comm_data_returncode, tvb, offset, 1, ret_val); + proto_item_append_text(item, " [%d]: (%s)", i + 1, val_to_str(ret_val, s7comm_item_return_valuenames, "Unknown code: 0x%02x")); + offset += 1; + } + if (item_count % 2) { + proto_tree_add_item(item_tree, hf_s7comm_data_fillbyte, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + break; } return offset; } /******************************************************************************************************* * - * PDU Type: User Data -> NC programming functions (file download/upload) + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Output ISTACK (0x03) * *******************************************************************************************************/ static guint32 -s7comm_decode_ud_ncprg_subfunc(tvbuff_t *tvb, - packet_info *pinfo, - proto_tree *data_tree, - guint8 type, /* Type of data (request/response) */ - guint8 subfunc, /* Subfunction */ - guint32 dlength, - guint32 offset) +s7comm_decode_ud_tis_istack(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) { - const guint8 *str_filename; - guint32 string_end_offset; - guint32 string_len; - guint32 filelength; - guint32 start_offset; - + guint8 ob_number = 0; + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_TYPE_RES: + case S7COMM_UD_TYPE_PUSH: + proto_tree_add_item(td_tree, hf_s7comm_tis_continued_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_continued_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_continued_address, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu3, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu4, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_stw, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + /* read the OB number first */ + ob_number = tvb_get_guint8(tvb, offset + 3); + switch (ob_number) { + case 1: /* Cyclic execution */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_scan_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_prev_cycle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_min_cycle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_max_cycle, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 10: /* Time of day interrupt 0..7 */ + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_period_exe, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 20: /* Time delay interrupt 0..3 */ + case 21: + case 22: + case 23: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_scan_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_sign, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_dtime, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 30: /* Cyclic interrupt 0..8 */ + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_phase_offset, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_exec_freq, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 40: /* Hardware interrupt 0..8 */ + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_point_addr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 55: /* DP Statusalarm */ + case 56: /* DP Updatealarm */ + case 57: /* DP Specific alarm */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_inf_len, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_alarm_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_alarm_slot, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_alarm_spec, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 80: /* Cycle time fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_error_info, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_num, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_num, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 81: /* Power supply fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_rack_cpu, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 82: /* I/O Point fault 1 */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_8x_fault_flags, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_type_b, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_8x_fault_flags, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_8x_fault_flags, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 83: /* I/O Point fault 2 */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_io_flag, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_rack_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_type_w, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 84: /* CPU fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4_dw, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 85: /* OB not loaded fault */ + case 87: /* Communication Fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ev_num, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_err_ob_num, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case 86: /* Loss of rack fault */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_id, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mdl_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_racks_flt, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 90: /* Background cycle */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_inf, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_3, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_4_dw, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 100: /* Complete restart */ + case 101: /* Restart */ + case 102: /* Cold restart */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_strtup, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_2, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_stop, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_strt_info, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + break; + case 121: /* Programming Error */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_sw_flt, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_blk_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_reserved_1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_reg, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_blk_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_prg_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + case 122: /* Module Access Error */ + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_sw_flt, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_blk_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mem_area, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_mem_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_flt_blk_num, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_ob_prg_addr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + break; + default: + proto_tree_add_item(td_tree, hf_s7comm_ob_ev_class, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_priority, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_ob_number, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_istack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + } + offset = s7comm_add_timestamp_to_tree(tvb, td_tree, offset, FALSE, FALSE); + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Output BSTACK (0x04) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_bstack(tvbuff_t *tvb, + proto_tree *td_tree, + guint16 td_size, + guint8 type, + guint32 offset) +{ + guint16 i; + guint16 blocktype; + guint16 blocknumber; + proto_item *item = NULL; + proto_tree *item_tree = NULL; + int rem; + guint32 replen; + + /* Possible firmware bug in IM151-8 CPU, where also the date size information + * in the header is 4 bytes too short. + */ + replen = tvb_reported_length_remaining(tvb, offset); + if (replen < td_size) { + /* TODO: Show this mismatch? We fix the length here. */ + td_size = replen; + } + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_TYPE_RES: + case S7COMM_UD_TYPE_PUSH: + rem = td_size; + i = 1; + while (rem > 16) { + item = proto_tree_add_item(td_tree, hf_s7comm_data_item, tvb, offset, 16, ENC_NA); + item_tree = proto_item_add_subtree(item, ett_s7comm_data_item); + blocktype = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + blocknumber = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db1_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db2_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 4, ENC_NA); + offset += 4; + proto_item_append_text(item, " [%d] BSTACK entry for: %s %d", i++, + val_to_str(blocktype, subblktype_names, "Unknown Subblk type: 0x%02x"), blocknumber); + rem -= 16; + if (blocktype == S7COMM_SUBBLKTYPE_OB) { + proto_tree_add_item(item_tree, hf_s7comm_tis_interrupted_prioclass, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + rem -= 4; + if (rem >= 8) { + offset = s7comm_add_timestamp_to_tree(tvb, item_tree, offset, FALSE, FALSE); + rem -= 8; + } else { + proto_tree_add_item(item_tree, hf_s7comm_tis_bstack_reserved, tvb, offset, rem, ENC_NA); + offset += rem; + rem = 0; + break; + } + } + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Output LSTACK (0x05) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_lstack(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + guint16 len; + + if (type == S7COMM_UD_TYPE_REQ) { + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_prioclass, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_bstack_nest_depth, tvb, offset, 1, ENC_NA); + offset += 1; + } else { + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_NA); + offset += 2; + len = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_size, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_data, tvb, offset, len, ENC_NA); + offset += len; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_prioclass, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_lstack_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + offset = s7comm_add_timestamp_to_tree(tvb, td_tree, offset, FALSE, FALSE); + } + return offset; +} +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Exit Hold (0x0b) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_exithold(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + /* Only request with data payload was seen */ + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_exithold_until, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_exithold_res1, tvb, offset, 1, ENC_NA); + offset += 1; + break; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands -> Breakpoint (0x0a) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_breakpoint(tvbuff_t *tvb, + proto_tree *td_tree, + guint8 type, + guint32 offset) +{ + switch (type) { + case S7COMM_UD_TYPE_REQ: + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + break; + case S7COMM_UD_TYPE_RES: + case S7COMM_UD_TYPE_PUSH: + /* Info: Both blocknumbers and addresses are the same on online-blockview inside a block. + * On return out of a block, the first address contains the current breakpoint, the second + * address the address from where it was returned (previous block). + */ + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_interrupted_address, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_blocktype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_blocknr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_address, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_breakpoint_reserved, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_stw, tvb, offset, 2, ENC_NA); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_accu2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar1, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_ar2, tvb, offset, 4, ENC_NA); + offset += 4; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db1_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(td_tree, hf_s7comm_tis_register_db2_nr, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands / Test and installation functions + * Dissects the data part + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_data(tvbuff_t *tvb, + proto_tree *tree, + guint8 type, + guint8 subfunc, + guint16 td_size, + guint32 offset) +{ + proto_item *item = NULL; + proto_tree *td_tree = NULL; + + if (td_size > 0) { + item = proto_tree_add_item(tree, hf_s7comm_tis_data, tvb, offset, td_size, ENC_NA); + td_tree = proto_item_add_subtree(item, ett_s7comm_prog_data); + switch (subfunc) { + case S7COMM_UD_SUBF_PROG_OUTISTACK: + offset = s7comm_decode_ud_tis_istack(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_PROG_OUTBSTACK: + offset = s7comm_decode_ud_tis_bstack(tvb, td_tree, td_size, type, offset); + break; + case S7COMM_UD_SUBF_PROG_OUTLSTACK: + offset = s7comm_decode_ud_tis_lstack(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_PROG_BREAKPOINT: + offset = s7comm_decode_ud_tis_breakpoint(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_PROG_EXITHOLD: + offset = s7comm_decode_ud_tis_exithold(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_PROG_BLOCKSTAT: + case S7COMM_UD_SUBF_PROG_BLOCKSTAT2: + offset = s7comm_decode_ud_tis_blockstat(tvb, td_tree, td_size, type, subfunc, offset); + break; + case S7COMM_UD_SUBF_PROG_VARSTAT: + offset = s7comm_decode_ud_tis_varstat(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_PROG_DISABLEJOB: + case S7COMM_UD_SUBF_PROG_ENABLEJOB: + case S7COMM_UD_SUBF_PROG_DELETEJOB: + case S7COMM_UD_SUBF_PROG_READJOBLIST: + case S7COMM_UD_SUBF_PROG_READJOB: + case S7COMM_UD_SUBF_PROG_REPLACEJOB: + offset = s7comm_decode_ud_tis_jobs(tvb, td_tree, td_size, type, subfunc, offset); + break; + case S7COMM_UD_SUBF_PROG_MODVAR: + offset = s7comm_decode_ud_tis_modvar(tvb, td_tree, type, offset); + break; + case S7COMM_UD_SUBF_PROG_FORCE: + offset = s7comm_decode_ud_tis_force(tvb, td_tree, type, offset); + break; + default: + proto_tree_add_item(td_tree, hf_s7comm_varstat_unknown, tvb, offset, td_size, ENC_NA); + offset += td_size; + break; + } + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 1 -> Programmer commands / Test and installation functions + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_tis_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint8 type, + guint8 subfunc, + guint32 offset) +{ + guint16 tp_size = 0; + guint16 td_size = 0; + + tp_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_tis_parametersize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + td_size = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(data_tree, hf_s7comm_tis_datasize, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + /* Parameter tree */ + offset = s7comm_decode_ud_tis_param(tvb, data_tree, type, tp_size, offset); + /* Data tree */ + offset = s7comm_decode_ud_tis_data(tvb, data_tree, type, subfunc, td_size, offset); + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 5 -> Security functions? + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_security_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint32 dlength, + guint32 offset) +{ + /* Display dataset as raw bytes. Maybe this part can be extended with further knowledge. */ + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); + offset += dlength; + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV), before reassembly + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_pbc_pre_reass(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, /* Type of data (request/response) */ + guint16 *dlength, + guint32 *r_id, /* R_ID of the PBC communication */ + guint32 offset) +{ + if ((type == S7COMM_UD_TYPE_REQ || type == S7COMM_UD_TYPE_RES) && (*dlength >= 8)) { + proto_tree_add_item(data_tree, hf_s7comm_item_varspec, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_item_varspec_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_item_syntax_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* 0x00 when passive partners is sending, 0xcc when active partner is sending? */ + proto_tree_add_item(data_tree, hf_s7comm_pbc_unknown, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + proto_tree_add_item(data_tree, hf_s7comm_pbc_r_id, tvb, offset, 4, ENC_BIG_ENDIAN); + *r_id = tvb_get_ntohl(tvb, offset); + col_append_fstr(pinfo->cinfo, COL_INFO, " R_ID=0x%X", *r_id); + offset += 4; + *dlength -= 8; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> Function group 6 -> PBC, Programmable Block Functions (e.g. BSEND/BRECV) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_pbc_subfunc(tvbuff_t *tvb, + proto_tree *data_tree, + guint32 dlength, + guint32 offset) +{ + proto_tree_add_item(data_tree, hf_s7comm_pbc_len, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength - 2, ENC_NA); + offset += (dlength - 2); + + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> NC programming functions (file download/upload), before reassembly + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_ncprg_pre_reass(tvbuff_t *tvb, + proto_tree *data_tree, + guint8 type, /* Type of data (request/response) */ + guint8 subfunc, /* Subfunction */ + guint16 *dlength, + guint32 offset) +{ + if ((type == S7COMM_UD_TYPE_NCRES || type == S7COMM_UD_TYPE_NCPUSH) && + (subfunc == S7COMM_NCPRG_FUNCDOWNLOADBLOCK || + subfunc == S7COMM_NCPRG_FUNCUPLOAD || + subfunc == S7COMM_NCPRG_FUNCSTARTUPLOAD)) { + proto_tree_add_item(data_tree, hf_s7comm_data_blockcontrol_unknown1, tvb, offset, 2, ENC_NA); + offset += 2; + *dlength -= 2; + } + return offset; +} + +/******************************************************************************************************* + * + * PDU Type: User Data -> NC programming functions (file download/upload) + * + *******************************************************************************************************/ +static guint32 +s7comm_decode_ud_ncprg_subfunc(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *data_tree, + guint8 type, /* Type of data (request/response) */ + guint8 subfunc, /* Subfunction */ + guint32 dlength, + guint32 offset) +{ + const guint8 *str_filename; + guint32 string_end_offset; + guint32 string_len; + guint32 filelength; + guint32 start_offset; + if (dlength >= 2) { if (type == S7COMM_UD_TYPE_NCREQ && subfunc == S7COMM_NCPRG_FUNCREQUESTDOWNLOAD) { proto_tree_add_item_ret_string(data_tree, hf_s7comm_data_blockcontrol_filename, tvb, offset, dlength, @@ -4849,96 +6108,6 @@ s7comm_decode_ud_cyclic_subfunc(tvbuff_t *tvb, 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 */ - guint32 dlength, - guint32 offset) -{ - gboolean know_data = FALSE; - - guint8 data_type; - guint16 byte_count; - guint16 item_count; - guint16 i; - - switch(subfunc) - { - case S7COMM_UD_SUBF_PROG_BLOCKSTAT: - case S7COMM_UD_SUBF_PROG_BLOCKSTAT2: - /* 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_VARSTAT: - /* 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_varstat_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_varstat_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_varstat_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_varstat_item_count, tvb, offset, 2, item_count); - offset += 2; - - /* parse item data */ - for (i = 0; i < item_count; i++) { - offset = s7comm_decode_ud_tis_item_address(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_varstat_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_varstat_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 > 0) { - proto_tree_add_item(data_tree, hf_s7comm_userdata_data, tvb, offset, dlength, ENC_NA); - offset += dlength; - } - return offset; -} /******************************************************************************************************* * * PDU Type: User Data: Data part and reassembly @@ -5059,7 +6228,7 @@ s7comm_decode_ud_data(tvbuff_t *tvb, if (last_data_unit == S7COMM_UD_LASTDATAUNIT_YES && length_rem > 0) { switch (funcgroup) { case S7COMM_UD_FUNCGROUP_PROG: - offset = s7comm_decode_ud_prog_subfunc(next_tvb, data_tree, type, subfunc, length_rem, offset); + offset = s7comm_decode_ud_tis_subfunc(next_tvb, data_tree, type, subfunc, offset); break; case S7COMM_UD_FUNCGROUP_CYCLIC: offset = s7comm_decode_ud_cyclic_subfunc(next_tvb, pinfo, seq_num, data_tree, type, subfunc, length_rem, offset); @@ -5892,21 +7061,330 @@ proto_register_s7comm (void) { "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, + /* Programmer commands / Test and installation (TIS) functions */ + { &hf_s7comm_tis_parameter, + { "TIS Parameter", "s7comm.tis.parameter", FT_NONE, BASE_NONE, NULL, 0x0, + "TIS Test and Installation: Parameter", HFILL }}, + { &hf_s7comm_tis_data, + { "TIS Data", "s7comm.cpu.tis.data", FT_NONE, BASE_NONE, NULL, 0x0, + "TIS Test and Installation: Data", HFILL }}, + { &hf_s7comm_tis_parametersize, + { "TIS Parameter size", "s7comm.tis.parametersize", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_datasize, + { "TIS Data size", "s7comm.tis.datasize", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param1, + { "TIS Parameter 1", "s7comm.tis.param1", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param2, + { "TIS Parameter 2 - Trigger type", "s7comm.tis.param2", FT_UINT16, BASE_DEC, VALS(tis_param2_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param3, + { "TIS Parameter 3 - Trigger frequency", "s7comm.tis.param3", FT_UINT16, BASE_DEC, VALS(tis_param3_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_answersize, + { "TIS Parameter 4 - Answer size", "s7comm.tis.answersize", FT_UINT16, BASE_DEC, NULL, 0x0, + "TIS Answer size: Expected data size of PLC answer to this job", HFILL }}, + { &hf_s7comm_tis_param5, + { "TIS Parameter 5", "s7comm.tis.param5", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param6, + { "TIS Parameter 6", "s7comm.tis.param6", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param7, + { "TIS Parameter 7", "s7comm.tis.param7", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param8, + { "TIS Parameter 8", "s7comm.tis.param8", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_param9, + { "TIS Parameter 9", "s7comm.tis.param9", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_trgevent, + { "TIS Parameter 10 - Trigger event", "s7comm.varstat.trgevent", FT_UINT16, BASE_HEX, VALS(userdata_varstat_trgevent_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_res_param1, + { "TIS Response Parameter 1", "s7comm.tis.res.param1", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_res_param2, + { "TIS Response Parameter 2", "s7comm.tis.res.param2", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_job_function, + { "Job function", "s7comm.tis.job.function", FT_UINT8, BASE_DEC, VALS(userdata_prog_subfunc_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_job_seqnr, + { "Job reference sequence number", "s7comm.tis.job.response_seq_num", FT_UINT8, BASE_DEC, NULL, 0x0, + "Job reference sequence number (find function setup with s7comm.param.userdata.seq_num)", HFILL }}, + { &hf_s7comm_tis_job_reserved, + { "Job Reserved / Unknown", "s7comm.tis.job.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_blocktype, + { "Interrupted block type", "s7comm.tis.interrupted.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_blocknr, + { "Interrupted block number", "s7comm.tis.interrupted.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_address, + { "Interrupted code address", "s7comm.tis.interrupted.address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_interrupted_prioclass, + { "Interrupted priority class", "s7comm.tis.interrupted.priorityclass", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_continued_blocktype, + { "Continued block type", "s7comm.tis.continued.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_continued_blocknr, + { "Continued block number", "s7comm.tis.continued.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_continued_address, + { "Continued code address", "s7comm.tis.continued.address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_blocktype, + { "Breakpoint block type", "s7comm.tis.breakpoint.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_blocknr, + { "Breakpoint block number", "s7comm.tis.breakpoint.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_address, + { "Breakpoint code address", "s7comm.tis.breakpoint.address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_breakpoint_reserved, + { "Breakpoint Reserved / Unknown", "s7comm.tis.breakpoint.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_tis_p_callenv, + { "Call environment setup", "s7comm.tis.callenv_setup", FT_UINT16, BASE_DEC, VALS(tis_p_callenv_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond, + { "Call condition", "s7comm.tis.callenv_cond", FT_UINT16, BASE_DEC, VALS(tis_p_callcond_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond_blocktype, + { "Call condition block type", "s7comm.tis.callenv_cond_blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond_blocknr, + { "Call condition block number", "s7comm.tis.callenv_cond_blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_p_callcond_address, + { "Call condition code address", "s7comm.tis.callenv_cond_blockaddress", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + + { &hf_s7comm_tis_register_db1_type, + { "Register DB1 content type", "s7comm.tis.db1.type", FT_UINT8, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_db2_type, + { "Register DB2 content type", "s7comm.tis.db2.type", FT_UINT8, BASE_DEC, VALS(subblktype_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_db1_nr, + { "Register DB1 block number", "s7comm.tis.db1.number", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_db2_nr, + { "Register DB2 block number", "s7comm.tis.db2.number", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu1, + { "Register ACCU1", "s7comm.tis.accu1", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu2, + { "Register ACCU2", "s7comm.tis.accu2", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu3, + { "Register ACCU3", "s7comm.tis.accu3", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_accu4, + { "Register ACCU4", "s7comm.tis.accu4", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_ar1, + { "Register AR1", "s7comm.tis.ar1", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_ar2, + { "Register AR2", "s7comm.tis.ar2", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_register_stw, + { "Register STW", "s7comm.tis.stw", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_exithold_until, + { "Exit HOLD state until", "s7comm.tis.exithold_until", FT_UINT8, BASE_DEC, VALS(tis_exithold_until_names), 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_exithold_res1 , + { "Exit HOLD Reserved / Unknown", "s7comm.tis.exithold_res1", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_bstack_nest_depth, + { "BSTACK nesting depth", "s7comm.tis.bstack.neting_depth", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_bstack_reserved, + { "BSTACK Reserved / Unknown", "s7comm.tis.bstack.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_istack_reserved, + { "ISTACK Reserved / Unknown", "s7comm.tis.istack.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_lstack_reserved, + { "LSTACK Reserved / Unknown", "s7comm.tis.lstack.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_lstack_size, + { "Localdata stack size", "s7comm.tis.lstack.size", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_lstack_data, + { "Localdata stack data", "s7comm.tis.lstack.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_flagsunknown, + { "Blockstat flags", "s7comm.tis.blockstat.flagsunknown", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_number_of_lines, + { "Number of lines", "s7comm.tis.blockstat.number_of_lines", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_line_address, + { "Address", "s7comm.tis.blockstat.line_address", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_data, + { "Blockstatus data", "s7comm.tis.blockstat.data", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_tis_blockstat_reserved, + { "Blockstatus Reserved / Unknown", "s7comm.tis.blockstat.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + /* Organization block local data */ + { &hf_s7comm_ob_ev_class, + { "OB Event class", "s7comm.ob.ev_class", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Event class (Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)", HFILL }}, + { &hf_s7comm_ob_scan_1, + { "OB Scan 1", "s7comm.ob.scan_1", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Scan 1 (1=Cold restart scan 1 of OB 1), 3=Scan 2-n of OB 1)", HFILL }}, + { &hf_s7comm_ob_strt_inf, + { "OB Start info", "s7comm.ob.strt_info", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Start info (OB n has started)", HFILL }}, + { &hf_s7comm_ob_flt_id, + { "OB Fault identifcation code", "s7comm.ob.flt_id", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_priority, + { "OB Priority", "s7comm.ob.priority", FT_UINT8, BASE_DEC, NULL, 0x0, + "OB Priority (1 is lowest)", HFILL }}, + { &hf_s7comm_ob_number, + { "OB Number", "s7comm.ob.number", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_reserved_1, + { "OB Reserved 1", "s7comm.ob.reserved_1", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Reserved 1 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_2, + { "OB Reserved 2", "s7comm.ob.reserved_2", FT_UINT8, BASE_HEX, NULL, 0x0, + "OB Reserved 2 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_3, + { "OB Reserved 3", "s7comm.ob.reserved_3", FT_UINT16, BASE_HEX, NULL, 0x0, + "OB Reserved 3 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_4, + { "OB Reserved 4", "s7comm.ob.reserved_4", FT_UINT16, BASE_HEX, NULL, 0x0, + "OB Reserved 4 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_reserved_4_dw, + { "OB Reserved 4", "s7comm.ob.reserved_4_dw", FT_UINT32, BASE_HEX, NULL, 0x0, + "OB Reserved 4 (Reserved for System)", HFILL }}, + { &hf_s7comm_ob_prev_cycle, + { "OB Cycle time of previous OB scan (ms)", "s7comm.ob.prev_cycle", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_min_cycle, + { "OB Minimum cycle time of OB (ms)", "s7comm.ob.min_cycle", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_max_cycle, + { "OB Maximum cycle time of OB (ms)", "s7comm.ob.max_cycle", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, - { &hf_s7comm_diagdata_req_asksize, - { "Ask size", "s7comm.diagdata.req.asksize", FT_UINT16, BASE_DEC, NULL, 0x0, + { &hf_s7comm_ob_period_exe, + { "OB Period of execution", "s7comm.ob.period_exe", FT_UINT16, BASE_HEX, NULL, 0x0, + "OB Period of execution (once, per minute/hour/day/week/month/year)", HFILL }}, + { &hf_s7comm_ob_sign, + { "OB Identifier input (SIGN) attached to SRT_DINT", "s7comm.ob.sign", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, - { &hf_s7comm_diagdata_req_unknown, - { "Unknown byte(s) diagdata", "s7comm.diagdata.req.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, + { &hf_s7comm_ob_dtime, + { "OB Delay time (DTIME) input to SRT_DINT instruction", "s7comm.ob.dtime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, - { &hf_s7comm_diagdata_req_answersize, - { "Answer size", "s7comm.diagdata.req.answersize", FT_UINT16, BASE_DEC, NULL, 0x0, + { &hf_s7comm_ob_phase_offset, + { "OB Phase offset (ms)", "s7comm.ob.phase_offset", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_exec_freq, + { "OB Frequency of execution (ms)", "s7comm.ob.exec_freq", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_io_flag, + { "OB IO flags", "s7comm.ob.io_flag", FT_UINT16, BASE_DEC, NULL, 0x0, + "OB IO flags (0x54=input module, 0x55=output module)", HFILL }}, + { &hf_s7comm_ob_mdl_addr, + { "OB Base address of module initiating interrupt", "s7comm.ob.mdl_addr", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_point_addr, + { "OB Address of interrupt point on module", "s7comm.ob.point_addr", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_inf_len, + { "OB Length of information", "s7comm.ob.inf_len", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_alarm_type, + { "OB Type of alarm", "s7comm.ob.alarm_type", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_alarm_slot, + { "OB Slot", "s7comm.ob.alarm_slot", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_alarm_spec, + { "OB Specifier", "s7comm.ob.alarm_spec", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_error_info, + { "OB Error information on event", "s7comm.ob.error_info", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ev_class, + { "OB Class of event causing error", "s7comm.ob.err_ev_class", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ev_num, + { "OB Number of event causing error", "s7comm.ob.err_ev_num", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ob_priority, + { "OB Priority of OB causing error", "s7comm.ob.err_ob_priority", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_err_ob_num, + { "OB Number of OB causing error", "s7comm.ob.err_ob_num", FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_rack_cpu, + { "OB Rack / CPU number", "s7comm.ob.rack_cpu", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_8x_fault_flags, + { "OB 8x Fault flags", "s7comm.ob.8x_fault_flags", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mdl_type_b, + { "OB Type of module", "s7comm.ob.mdl_type_b", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mdl_type_w, + { "OB Module type with point fault", "s7comm.ob.mdl_type_w", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_rack_num, + { "OB Number of rack that has module with point fault", "s7comm.ob.rack_num", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_racks_flt, + { "OB Racks in fault", "s7comm.ob.racks_flt", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_strtup, + { "OB Method of startup", "s7comm.ob.strtup", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_stop, + { "OB Event that caused CPU to stop", "s7comm.ob.stop", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_strt_info, + { "OB Information on how system started", "s7comm.ob.strt_info", FT_UINT32, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_sw_flt, + { "OB Software programming fault", "s7comm.ob.sw_flt", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_blk_type, + { "OB Type of block fault occured in", "s7comm.ob.blk_type", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_flt_reg, + { "OB Specific register that caused fault", "s7comm.ob.flt_reg", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_flt_blk_num, + { "OB Number of block that programming fault occured in", "s7comm.ob.flt_blk_num", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_prg_addr, + { "OB Address in block where programming fault occured", "s7comm.ob.prg_addr", FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mem_area, + { "OB Memory area where access error occured", "s7comm.ob.mem_area", FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + { &hf_s7comm_ob_mem_addr, + { "OB Memory address where access error occured", "s7comm.ob.mem_addr", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_block_type, - { "Block type", "s7comm.diagdata.req.blocktype", FT_UINT8, BASE_DEC, VALS(subblktype_names), 0x0, + { "Block type", "s7comm.diagdata.req.blocktype", FT_UINT16, BASE_DEC, VALS(subblktype_names), 0x0, NULL, HFILL }}, { &hf_s7comm_diagdata_req_block_num, { "Block number", "s7comm.diagdata.req.blocknumber", FT_UINT16, BASE_DEC, NULL, 0x0, @@ -5917,12 +7395,6 @@ proto_register_s7comm (void) { &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, @@ -6297,12 +7769,6 @@ proto_register_s7comm (void) NULL, HFILL }}, /* Variable status */ - { &hf_s7comm_varstat_data_type, - { "Type of data", "s7comm.varstat.data_type", FT_UINT8, BASE_DEC, VALS(userdata_prog_vartab_type_names), 0x0, - NULL, HFILL }}, - { &hf_s7comm_varstat_byte_count, - { "Byte count", "s7comm.varstat.byte_count", FT_UINT16, BASE_DEC, NULL, 0x0, - NULL, HFILL }}, { &hf_s7comm_varstat_unknown, { "Unknown byte(s) varstat", "s7comm.varstat.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, @@ -6629,6 +8095,8 @@ proto_register_s7comm (void) &ett_s7comm_piservice_parameterblock, &ett_s7comm_data_blockcontrol_status, &ett_s7comm_plcfilename, + &ett_s7comm_prog_parameter, + &ett_s7comm_prog_data, &ett_s7comm_fragments, &ett_s7comm_fragment, }; -- cgit v1.2.3