GSM A DTAP: add UMTS EVS to supported codecs list IE
[metze/wireshark/wip.git] / epan / dissectors / packet-tn3270.c
index a43aaa7820c2449ab924042b8ab38dcecaefeccd..b7bb18241c30e087aebefe1ef9a0298233593755 100644 (file)
  *
  * Copyright 2009, Robert Hogan <robert@roberthogan.net>
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <string.h>
+#include "config.h"
 
-#include <glib.h>
 
 #include <epan/packet.h>
-#include <epan/address.h>
 #include <epan/conversation.h>
-#include <epan/strutil.h>
+#include <epan/expert.h>
 
 #include "packet-tn3270.h"
 
+void proto_register_tn3270(void);
+
 /* Note well:
  *  In the IBM "3270 Information Display System: Data Stream Programmer's Reference"
  *  document, the references to bit numbers in the text and tables
 */
 
 /*--- 3270 Command Codes - "Local Attachment" ----- */
-#define CC_W        0x01
-#define CC_EW       0x05
-#define CC_EWA      0x0D
-#define CC_EAU      0x0F
-#define CC_WSF      0x11
+#define CC_LCL_W        0x01
+#define CC_LCL_EW       0x05
+#define CC_LCL_EWA      0x0D
+#define CC_LCL_EAU      0x0F
+#define CC_LCL_WSF      0x11
 
-#define CC_RB       0x02
-#define CC_RM       0x06
-#define CC_RMA      0x0E
+#define CC_LCL_RB       0x02
+#define CC_LCL_RM       0x06
+#define CC_LCL_RMA      0x0E  /* XXX Not valid ?? See 3174 Function Description 2.1.4 */
 
 #if 0  /* ??? */
 #define CC_NOP      0x03
 #endif
 
 
-/*--- 3.3 SNA 3270 Command Codes - "Remote Attachment" ----- */
-#define CC_SNA_W    0xF1
-#define CC_SNA_EW   0xF5
-#define CC_SNA_EWA  0x7E
-#define CC_SNA_EAU  0x6F
-#define CC_SNA_WSF  0xF3
+/*--- 3.3 3270 Command Codes - "Remote Attachment" ----- */
+#define CC_RMT_W    0xF1
+#define CC_RMT_EW   0xF5
+#define CC_RMT_EWA  0x7E
+#define CC_RMT_EAU  0x6F
+#define CC_RMT_WSF  0xF3
 
-#define CC_SNA_RB   0xF2
-#define CC_SNA_RM   0xF6
-#define CC_SNA_RMA  0x6E
+#define CC_RMT_RB   0xF2
+#define CC_RMT_RM   0xF6
+#define CC_RMT_RMA  0x6E
 
 #define CC_SNA_BSC  0xF7   /* local copy in a BSC environment */
 
 static const value_string vals_command_codes[] = {
-  { CC_W,       "Write" },
-  { CC_EW,      "Erase/Write" },
-  { CC_EWA,     "Erase/Write Alternate" },
-  { CC_EAU,     "Erase All Unprotected" },
-  { CC_WSF,     "Write Structured Field" },
-  { CC_RB,      "Read Buffer" },
-  { CC_RM,      "Read Modified" },
-  { CC_RMA,     "Read Modified All" },
-  { CC_SNA_W,   "Write" },
-  { CC_SNA_EW,  "Erase/Write" },
-  { CC_SNA_EWA, "Erase/Write Alternate" },
-  { CC_SNA_EAU, "Erase All Unprotected" },
-  { CC_SNA_WSF, "Write Structured Field" },
-  { CC_SNA_RB,  "Read Buffer" },
-  { CC_SNA_RM,  "Read Modified" },
-  { CC_SNA_RMA, "Read Modified All" },
+
+  { CC_LCL_W,   "Write (Local)" },
+  { CC_LCL_EW,  "Erase/Write (Local)" },
+  { CC_LCL_EWA, "Erase/Write Alternate (Local)" },
+  { CC_LCL_EAU, "Erase All Unprotected (Local)" },
+  { CC_LCL_WSF, "Write Structured Field (Local)" },
+  { CC_LCL_RB,  "Read Buffer (Local)" },
+  { CC_LCL_RM,  "Read Modified (Local)" },
+  { CC_LCL_RMA, "Read Modified All (Local)" },
+  { CC_RMT_W,   "Write" },
+  { CC_RMT_EW,  "Erase/Write" },
+  { CC_RMT_EWA, "Erase/Write Alternate" },
+  { CC_RMT_EAU, "Erase All Unprotected" },
+  { CC_RMT_WSF, "Write Structured Field" },
+  { CC_RMT_RB,  "Read Buffer" },
+  { CC_RMT_RM,  "Read Modified" },
+  { CC_RMT_RMA, "Read Modified All" },
   { CC_SNA_BSC, "BSC Copy" },
   { 0x00, NULL }
 };
@@ -1243,14 +1226,10 @@ static const value_string vals_tn3270_header_response_flags_response[] = {
 };
 
 /*
- * 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;
@@ -1625,7 +1604,11 @@ static gint ett_tn3270_msr_state_mask = -1;
 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 {
@@ -2045,7 +2028,7 @@ dissect_outbound_text_header(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset
   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);
@@ -2055,7 +2038,7 @@ dissect_outbound_text_header(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset
 
 /* 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;
@@ -2088,19 +2071,20 @@ dissect_outbound_3270ds(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
                           ENC_BIG_ENDIAN);
       offset += 2;
       break;
-    case CC_W:
-    case CC_EW:
-    case CC_EWA:
-    case CC_EAU:
-    case CC_SNA_W:
-    case CC_SNA_EW:
-    case CC_SNA_EWA:
-    case CC_SNA_EAU:
+      /* XXX: are "local" commands valid for Outbound 3270DS ? */
+    case CC_LCL_W:
+    case CC_LCL_EW:
+    case CC_LCL_EWA:
+    case CC_LCL_EAU:
+    case CC_RMT_W:
+    case CC_RMT_EW:
+    case CC_RMT_EWA:
+    case CC_RMT_EAU:
       /* WCC */
       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;
@@ -2191,7 +2175,6 @@ dissect_read_partition(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
 {
   gint        start = offset;
   gint        type;
-  proto_item *pi;
   proto_tree *query_list_tree;
   gint        qcode_list_len, i;
 
@@ -2226,9 +2209,8 @@ dissect_read_partition(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
 
     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,
@@ -2681,6 +2663,7 @@ dissect_exception_or_status_sd_parms(proto_tree *tn3270_tree, tvbuff_t *tvb, gin
     case 0x0C04: /*Format status*/
       offset += tn3270_add_hf_items(tn3270_tree, tvb, offset,
                                     sdp4);
+      break;
     case 0x1405: /*Group status*/
       offset += tn3270_add_hf_items(tn3270_tree, tvb, offset,
                                     sdp5);
@@ -4381,7 +4364,7 @@ process_inbound_structured_field(proto_tree *sf_tree, tvbuff_t *tvb, gint offset
 /* 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) */
@@ -4425,7 +4408,7 @@ process_outbound_structured_field(proto_tree *sf_tree, tvbuff_t *tvb, gint offse
       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);
@@ -4646,12 +4629,10 @@ static proto_tree *
 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,
@@ -4668,7 +4649,7 @@ display_sf_hdr(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
 }
 
 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;
@@ -4707,7 +4688,7 @@ dissect_structured_fields(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
       sf_id_len = 2;
     }
 
-    sf_id_str = match_strval(sf_id, direction_inbound ?
+    sf_id_str = try_val_to_str(sf_id, direction_inbound ?
                              vals_inbound_structured_fields : vals_outbound_structured_fields);
     if (sf_id_str != NULL) {
       sf_tree = display_sf_hdr(tn3270_tree, tvb, offset,
@@ -4717,13 +4698,13 @@ dissect_structured_fields(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
         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;
     }
 
     /* Not found above: See if an "outbound-inbound" field */
-    sf_id_str = match_strval(sf_id, vals_outbound_inbound_structured_fields);
+    sf_id_str = try_val_to_str(sf_id, vals_outbound_inbound_structured_fields);
     if (sf_id_str != NULL) {
       sf_tree = display_sf_hdr(tn3270_tree, tvb, offset,
                                sf_length, sf_id, sf_id_len, sf_id_str);
@@ -4733,11 +4714,10 @@ dissect_structured_fields(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
     }
 
     /* Not found */
-    sf_id_str = ep_strdup_printf("Unknown [%0*x]", sf_id_len*2, sf_id);
+    sf_id_str = wmem_strdup_printf(wmem_packet_scope(), "Unknown [%0*x]", sf_id_len*2, sf_id);
     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);
@@ -4962,10 +4942,11 @@ dissect_field_attribute_pairs(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offse
 }
 
 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 */
 
@@ -4973,7 +4954,7 @@ dissect_orders_and_data(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
   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,
@@ -5010,7 +4991,7 @@ dissect_orders_and_data(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
         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 */
     }
@@ -5041,10 +5022,9 @@ dissect_tn3270e_header(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset)
 
   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);
@@ -5092,10 +5072,11 @@ dissect_tn3270e_header(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset)
 
 /* 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);
@@ -5106,13 +5087,13 @@ dissect_outbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
   /*      "state" needs to be associated in some manner with each      */
   /*      frame of a conversation.                                     */
   switch (command_code) {
-    case CC_EW:
-    case CC_SNA_EW:
+    case CC_LCL_EW:
+    case CC_RMT_EW:
       tn3270_info->rows = 24;
       tn3270_info->cols = 80;
       break;
-    case CC_EWA:
-    case CC_SNA_EWA:
+    case CC_LCL_EWA:
+    case CC_RMT_EWA:
       tn3270_info->rows = tn3270_info->altrows;
       tn3270_info->cols = tn3270_info->altcols;
       break;
@@ -5120,39 +5101,39 @@ dissect_outbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
       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_W:
-    case CC_EW:
-    case CC_EWA:
-    case CC_EAU:
-    case CC_SNA_W:
-    case CC_SNA_EW:
-    case CC_SNA_EWA:
-    case CC_SNA_EAU:
-      proto_tree_add_item(tn3270_tree,
-                          hf_tn3270_command_code,
-                          tvb, offset,
-                          1,
-                          ENC_BIG_ENDIAN);
-      offset += 1;
+    case CC_LCL_W:
+    case CC_LCL_EW:
+    case CC_LCL_EWA:
+    case CC_LCL_EAU:
+    case CC_RMT_W:
+    case CC_RMT_EW:
+    case CC_RMT_EWA:
+    case CC_RMT_EAU:
       /* 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_WSF:
-    case CC_SNA_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);
+    case CC_LCL_WSF:
+    case CC_RMT_WSF:
+      offset += dissect_structured_fields(tn3270_tree, pinfo, tvb, offset, tn3270_info, FALSE);
+      break;
+    case CC_LCL_RB:
+    case CC_LCL_RM:
+    case CC_LCL_RMA:
+    case CC_RMT_RB:
+    case CC_RMT_RM:
+    case CC_RMT_RMA:
       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;
   }
 
@@ -5163,14 +5144,15 @@ dissect_outbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
 /* 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,
@@ -5178,7 +5160,7 @@ dissect_inbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn32
   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:
@@ -5188,7 +5170,7 @@ dissect_inbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn32
       /* 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:
@@ -5224,10 +5206,10 @@ dissect_inbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn32
     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;
   }
@@ -5236,8 +5218,8 @@ dissect_inbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn32
 }
 
 
-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;
@@ -5250,16 +5232,14 @@ dissect_tn3270(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   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 = conversation_get_proto_data(conversation, proto_tn3270);
+    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);
@@ -5270,7 +5250,7 @@ dissect_tn3270(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   }
 
   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");
@@ -5282,14 +5262,15 @@ dissect_tn3270(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   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
@@ -5303,19 +5284,15 @@ add_tn3270_conversation(packet_info *pinfo, int tn3270e, gint model)
   /*
    * Do we already have a type and mechanism?
    */
-  tn3270_info = conversation_get_proto_data(conversation, proto_tn3270);
+  tn3270_info = (tn3270_conv_info_t *)conversation_get_proto_data(conversation, proto_tn3270);
   if (tn3270_info == NULL) {
     /* No.  Attach that information to the conversation, and add
      * it to the list of information structures.
      */
-    tn3270_info = se_alloc(sizeof(tn3270_conv_info_t));
+    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);
   }
 
@@ -5355,11 +5332,9 @@ find_tn3270_conversation(packet_info *pinfo)
   /*
    * 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 = conversation_get_proto_data(conversation, proto_tn3270);
+    tn3270_info = (tn3270_conv_info_t *)conversation_get_proto_data(conversation, proto_tn3270);
     if (tn3270_info != NULL) {
       /*
        * Do we already have a type and mechanism?
@@ -5559,7 +5534,7 @@ proto_register_tn3270(void)
     { &hf_tn3270_character_set,
       { "Character Set",
         "tn3270.character_set",
-        FT_UINT8, BASE_HEX, RVALS(rvals_at_character_set), 0x0,
+        FT_UINT8, BASE_RANGE_STRING|BASE_HEX, RVALS(rvals_at_character_set), 0x0,
         NULL, HFILL }
     },
     { &hf_tn3270_field_outlining,
@@ -6647,20 +6622,20 @@ proto_register_tn3270(void)
          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)",
@@ -7466,18 +7441,16 @@ proto_register_tn3270(void)
          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",
@@ -7660,10 +7633,20 @@ proto_register_tn3270(void)
     &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));
 
 }