* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
-#include <string.h>
-
-#include <glib.h>
#include <epan/packet.h>
-#include <epan/address.h>
-#include <epan/wmem/wmem.h>
#include <epan/conversation.h>
-#include <epan/strutil.h>
+#include <epan/expert.h>
#include "packet-tn3270.h"
};
/*
- * Data structure attached to a conversation, giving authentication
- * information from a bind request.
+ * Data structure attached to a conversation, giving session information.
*/
typedef struct tn3270_conv_info_t {
- address outbound_addr;
guint32 outbound_port;
- address inbound_addr;
- guint32 inbound_port;
gint extended;
guint8 altrows;
guint8 altcols;
static gint ett_tn3270_data_chain_fields = -1;
static gint ett_tn3270_query_list = -1;
-static gint dissect_orders_and_data(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info);
+static expert_field ei_tn3270_order_code = EI_INIT;
+static expert_field ei_tn3270_command_code = EI_INIT;
+static expert_field ei_tn3270_aid = EI_INIT;
+
+static gint dissect_orders_and_data(proto_tree *tn3270_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info);
static gint dissect_buffer_address(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, gint hf, tn3270_conv_info_t *tn3270_info);
typedef struct hf_items {
offset += 2;
proto_tree_add_item(tn3270_tree, hf_tn3270_outbound_text_header_hdr,
- tvb, offset, hdr_length, ENC_BIG_ENDIAN);
+ tvb, offset, hdr_length, ENC_NA);
offset += hdr_length;
offset += dissect_unknown_data(tn3270_tree, tvb, offset, start, sf_body_length);
/* 5.16 Outbound 3270DS */
static gint
-dissect_outbound_3270ds(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
+dissect_outbound_3270ds(proto_tree *tn3270_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset,
tn3270_conv_info_t *tn3270_info, gint sf_body_length )
{
gint start = offset;
if ((offset - start) < sf_body_length)
offset += dissect_wcc(tn3270_tree, tvb, offset);
if ((offset - start) < sf_body_length)
- offset += dissect_orders_and_data(tn3270_tree, tvb, offset, tn3270_info);
+ offset += dissect_orders_and_data(tn3270_tree, pinfo, tvb, offset, tn3270_info);
break;
default:
break;
{
gint start = offset;
gint type;
- proto_item *pi;
proto_tree *query_list_tree;
gint qcode_list_len, i;
if (sf_body_length > (offset - start)) {
qcode_list_len = sf_body_length - (offset - start);
- pi = proto_tree_add_text(tn3270_tree, tvb, offset, qcode_list_len,
- "Query List");
- query_list_tree = proto_item_add_subtree(pi, ett_tn3270_query_list);
+ query_list_tree = proto_tree_add_subtree(tn3270_tree, tvb, offset, qcode_list_len,
+ ett_tn3270_query_list, NULL, "Query List");
for (i = 0; i < qcode_list_len; i++) {
proto_tree_add_item(query_list_tree,
hf_tn3270_sf_query_reply,
/* sf_body_length is the total length of the structured field including the sf_len and sf_id fields */
/* call only with valid sf_id */
static gint
-process_outbound_structured_field(proto_tree *sf_tree, tvbuff_t *tvb, gint offset,
+process_outbound_structured_field(proto_tree *sf_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset,
tn3270_conv_info_t *tn3270_info, guint sf_id, gint sf_body_length)
{
gint start = offset; /* start of structured field param(s) */
offset += dissect_load_programmed_symbols(sf_tree, tvb, offset, sf_body_length);
break;
case SF_OB_OUTBOUND_3270DS:
- offset += dissect_outbound_3270ds(sf_tree, tvb, offset, tn3270_info, sf_body_length);
+ offset += dissect_outbound_3270ds(sf_tree, pinfo, tvb, offset, tn3270_info, sf_body_length);
break;
case SF_OB_PRESENT_ABSOLUTE_FORMAT:
offset += dissect_present_absolute_format(sf_tree, tvb, offset, sf_body_length);
display_sf_hdr(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
gint sf_length, guint sf_id, guint sf_id_len, const gchar *sf_id_str)
{
- proto_item *pi;
proto_tree *sf_tree;
- pi = proto_tree_add_text(tn3270_tree, tvb, offset, sf_length,
- "Structured Field: %s", sf_id_str);
- sf_tree = proto_item_add_subtree(pi, ett_sf);
+ sf_tree = proto_tree_add_subtree_format(tn3270_tree, tvb, offset, sf_length,
+ ett_sf, NULL, "Structured Field: %s", sf_id_str);
proto_tree_add_item(sf_tree,
hf_tn3270_sf_length,
}
static gint
-dissect_structured_fields(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
+dissect_structured_fields(proto_tree *tn3270_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset,
tn3270_conv_info_t *tn3270_info, gboolean direction_inbound)
{
proto_tree *sf_tree;
offset += process_inbound_structured_field(sf_tree, tvb, offset, tn3270_info, sf_id, sf_length-2-sf_id_len);
}
else {
- offset += process_outbound_structured_field(sf_tree, tvb, offset, tn3270_info, sf_id, sf_length-2-sf_id_len);
+ offset += process_outbound_structured_field(sf_tree, pinfo, tvb, offset, tn3270_info, sf_id, sf_length-2-sf_id_len);
}
continue;
}
display_sf_hdr(tn3270_tree, tvb, offset, sf_length,
sf_length, sf_id_len, sf_id_str);
offset += sf_length;
- continue;
} /* while */
return (offset - start);
}
static gint
-dissect_orders_and_data(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info)
+dissect_orders_and_data(proto_tree *tn3270_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info)
{
gint start = offset;
gint order_code;
+ proto_item* item;
/* Order Code */
while (tvb_reported_length_remaining(tvb, offset) > 0) {
order_code = tvb_get_guint8(tvb, offset);
if ((order_code > 0) && (order_code <= OC_MAX)) { /* XXX: also 0xFF ?? */
- proto_tree_add_item(tn3270_tree,
+ item = proto_tree_add_item(tn3270_tree,
hf_tn3270_order_code,
tvb, offset,
1,
case OC_IC:
break;
default:
- proto_tree_add_text(tn3270_tree, tvb, offset, 1, "Bogus value: %u", order_code);
+ expert_add_info(pinfo, item, &ei_tn3270_order_code);
break;
} /* switch */
}
data_type = tvb_get_guint8(tvb, offset);
- pi = proto_tree_add_text(tn3270_tree, tvb, offset, -1,
- "TN3270E Header (Data Type: %s)",
+ tn3270e_hdr_tree = proto_tree_add_subtree_format(tn3270_tree, tvb, offset, -1,
+ ett_tn3270e_hdr, &pi, "TN3270E Header (Data Type: %s)",
val_to_str_const(data_type, vals_tn3270_header_data_types, "Unknown"));
- tn3270e_hdr_tree = proto_item_add_subtree(pi, ett_tn3270e_hdr);
offset += tn3270_add_hf_items(tn3270e_hdr_tree, tvb, offset,
fields);
/* Detect and Handle Direction of Stream */
static gint
-dissect_outbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info)
+dissect_outbound_stream(proto_tree *tn3270_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info)
{
gint command_code;
gint start = offset;
+ proto_item* item;
/* Command Code*/
command_code = tvb_get_guint8(tvb, offset);
break;
}
+ item = proto_tree_add_item(tn3270_tree,
+ hf_tn3270_command_code,
+ tvb, offset,
+ 1,
+ ENC_BIG_ENDIAN);
+ offset += 1;
+
switch (command_code) {
case CC_LCL_W:
case CC_LCL_EW:
case CC_RMT_EW:
case CC_RMT_EWA:
case CC_RMT_EAU:
- proto_tree_add_item(tn3270_tree,
- hf_tn3270_command_code,
- tvb, offset,
- 1,
- ENC_BIG_ENDIAN);
- offset += 1;
/* WCC */
offset += dissect_wcc(tn3270_tree, tvb, offset);
- offset += dissect_orders_and_data(tn3270_tree, tvb, offset, tn3270_info);
+ offset += dissect_orders_and_data(tn3270_tree, pinfo, tvb, offset, tn3270_info);
break;
case CC_LCL_WSF:
case CC_RMT_WSF:
- proto_tree_add_item(tn3270_tree,
- hf_tn3270_command_code,
- tvb, offset,
- 1,
- ENC_BIG_ENDIAN);
- offset += 1;
- offset += dissect_structured_fields(tn3270_tree, tvb, offset, tn3270_info, FALSE);
+ offset += dissect_structured_fields(tn3270_tree, pinfo, tvb, offset, tn3270_info, FALSE);
break;
case CC_LCL_RB:
case CC_LCL_RM:
case CC_RMT_RB:
case CC_RMT_RM:
case CC_RMT_RMA:
- proto_tree_add_item(tn3270_tree,
- hf_tn3270_command_code,
- tvb, offset,
- 1,
- ENC_BIG_ENDIAN);
- offset += 1;
break;
default:
- /* XXX: Add expert item ? */
- proto_tree_add_text(tn3270_tree, tvb, offset, 1, "Bogus value: %u", command_code);
- offset += 1;
+ expert_add_info(pinfo, item, &ei_tn3270_command_code);
break;
}
/* INBOUND DATA STREAM (DISPLAY -> MAINFRAME PROGRAM) */
/* Dissect tvb as inbound */
static gint
-dissect_inbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info)
+dissect_inbound_stream(proto_tree *tn3270_tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, tn3270_conv_info_t *tn3270_info)
{
gint start = offset;
gint aid;
+ proto_item* item;
/* Command Code*/
aid = tvb_get_guint8(tvb, offset);
- proto_tree_add_item(tn3270_tree,
+ item = proto_tree_add_item(tn3270_tree,
hf_tn3270_aid,
tvb, offset,
1,
offset += 1;
switch (aid) {
case AID_STRUCTURED_FIELD:
- offset += dissect_structured_fields(tn3270_tree, tvb, offset, tn3270_info, TRUE);
+ offset += dissect_structured_fields(tn3270_tree, pinfo, tvb, offset, tn3270_info, TRUE);
break;
case AID_PA1_KEY:
case AID_PA2_KEY_CNCL:
/* XXX: Is this the correct/complete set of AID bytes for this case ? */
if (tvb_reported_length_remaining(tvb, offset) <= 0)
break;
- /* fall into next */
+ /* FALL THROUGH */
case AID_READ_PARTITION_AID:
case AID_NO_AID_GENERATED:
case AID_NO_AID_GENERATED_PRINTER_ONLY:
case AID_OPERATOR_ID_READER:
case AID_MAG_READER_NUMBER:
offset += dissect_buffer_address(tn3270_tree, tvb, offset, hf_tn3270_cursor_address, tn3270_info);
- offset += dissect_orders_and_data(tn3270_tree, tvb, offset, tn3270_info);
+ offset += dissect_orders_and_data(tn3270_tree, pinfo, tvb, offset, tn3270_info);
break;
default:
- proto_tree_add_text(tn3270_tree, tvb, offset, 1, "Bogus value: %u", aid);
+ expert_add_info(pinfo, item, &ei_tn3270_aid);
offset += 1;
break;
}
}
-static void
-dissect_tn3270(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_tn3270(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_tree *tn3270_tree;
proto_item *pi;
pinfo->fd->flags.encoding = PACKET_CHAR_ENC_CHAR_EBCDIC;
/* Do we have a conversation for this connection? */
- conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
- pinfo->ptype, pinfo->srcport,
- pinfo->destport, 0);
+ conversation = find_conversation_pinfo(pinfo, 0);
if (conversation != NULL) {
/* Do we already have a type and mechanism? */
tn3270_info = (tn3270_conv_info_t *)conversation_get_proto_data(conversation, proto_tn3270);
}
if (tn3270_info == NULL)
- return;
+ return 0;
pi = proto_tree_add_item(tree, proto_tn3270, tvb, offset, -1, ENC_NA);
tn3270_tree = proto_item_add_subtree(pi, ett_tn3270);
}
if (tvb_reported_length_remaining(tvb, offset) <= 0)
- return;
+ return offset;
if (pinfo->srcport == tn3270_info->outbound_port) {
col_set_str(pinfo->cinfo, COL_INFO, "TN3270 Data from Mainframe");
if(tree) {
while (tvb_reported_length_remaining(tvb, offset) > 0) {
if (pinfo->srcport == tn3270_info->outbound_port) {
- offset += dissect_outbound_stream(tn3270_tree, tvb, offset, tn3270_info);
+ offset += dissect_outbound_stream(tn3270_tree, pinfo, tvb, offset, tn3270_info);
}
else {
- offset += dissect_inbound_stream(tn3270_tree, tvb, offset, tn3270_info);
+ offset += dissect_inbound_stream(tn3270_tree, pinfo, tvb, offset, tn3270_info);
}
}
}
+ return tvb_captured_length(tvb);
}
void
*/
tn3270_info = wmem_new(wmem_file_scope(), tn3270_conv_info_t);
- COPY_ADDRESS(&(tn3270_info->outbound_addr), &(pinfo->dst));
tn3270_info->outbound_port = pinfo->destport;
- COPY_ADDRESS(&(tn3270_info->inbound_addr), &(pinfo->src));
- tn3270_info->inbound_port = pinfo->srcport;
-
conversation_add_proto_data(conversation, proto_tn3270, tn3270_info);
}
/*
* Do we have a conversation for this connection?
*/
- conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst,
- pinfo->ptype, pinfo->srcport,
- pinfo->destport, 0);
+ conversation = find_conversation_pinfo(pinfo, 0);
if (conversation != NULL) {
tn3270_info = (tn3270_conv_info_t *)conversation_get_proto_data(conversation, proto_tn3270);
if (tn3270_info != NULL) {
NULL, HFILL }
},
{ &hf_tn3270_cs_form_type1,
- { "18-byte form; the first 2 bytes contain a 16-bit vertical slice,"
- " the following 16 bytes contain 8-bit horizontal slices. For a 9"
- " x 12 character matrix the last 4 bytes contain binary zero.",
+ { "18-byte form",
"tn3270.cs_form_type1",
FT_BOOLEAN, 8, NULL, 0x80,
- NULL, HFILL }
+ "the first 2 bytes contain a 16-bit vertical slice,"
+ " the following 16 bytes contain 8-bit horizontal slices. For a 9"
+ " x 12 character matrix the last 4 bytes contain binary zero.", HFILL }
},
{ &hf_tn3270_cs_form_type2,
- { "18-byte form; the first 2 bytes contain a 16-bit vertical slice,"
- " the following 16 bytes contain 8-bit horizontal slices. For a 9"
- " x 12 character matrix the last 4 bytes contain binary zero. (COMPRESSED)",
+ { "18-byte form (COMPRESSED)",
"tn3270.cs_form_type2",
FT_BOOLEAN, 8, NULL, 0x40,
- NULL, HFILL }
+ "the first 2 bytes contain a 16-bit vertical slice,"
+ " the following 16 bytes contain 8-bit horizontal slices. For a 9"
+ " x 12 character matrix the last 4 bytes contain binary zero. (COMPRESSED)", HFILL }
},
{ &hf_tn3270_cs_form_type3,
{ "Row loading (from top to bottom)",
NULL, HFILL }
},
{ &hf_tn3270_ua_xr,
- { "Distance between points in X direction as a fraction, measured in UNITS, with 2-byte"
- " numerator and 2-byte denominator",
+ { "Distance between points in X direction as a fraction",
"tn3270.ua_xr",
FT_UINT32, BASE_HEX, NULL, 0x0,
- NULL, HFILL }
+ "measured in UNITS, with 2-byte numerator and 2-byte denominator", HFILL }
},
{ &hf_tn3270_ua_yr,
- { "Distance between points in Y direction as a fraction, measured in UNITS, with 2-byte"
- " numerator and 2-byte denominator",
+ { "Distance between points in Y direction as a fraction",
"tn3270.ua_xr",
FT_UINT32, BASE_HEX, NULL, 0x0,
- NULL, HFILL }
+ "measured in UNITS, with 2-byte numerator and 2-byte denominator", HFILL }
},
{ &hf_tn3270_ua_aw,
{ "Number of X units in default cell",
&ett_tn3270_query_list
};
+ static ei_register_info ei[] = {
+ { &ei_tn3270_order_code, { "tn3270.order_code.bogus", PI_PROTOCOL, PI_WARN, "Bogus value", EXPFILL }},
+ { &ei_tn3270_command_code, { "tn3270.command_code.bogus", PI_PROTOCOL, PI_WARN, "Bogus value", EXPFILL }},
+ { &ei_tn3270_aid, { "tn3270.aid.bogus", PI_PROTOCOL, PI_WARN, "Bogus value", EXPFILL }},
+ };
+
+ expert_module_t* expert_tn3270;
+
proto_tn3270 = proto_register_protocol("TN3270 Protocol", "TN3270", "tn3270");
register_dissector("tn3270", dissect_tn3270, proto_tn3270);
proto_register_field_array(proto_tn3270, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ expert_tn3270 = expert_register_protocol(proto_tn3270);
+ expert_register_field_array(expert_tn3270, ei, array_length(ei));
}