GSM A DTAP: add UMTS EVS to supported codecs list IE
[metze/wireshark/wip.git] / epan / dissectors / packet-tn3270.c
index ee75785cfac4ad56b1d8e6dc65c292758b909c1c..b7bb18241c30e087aebefe1ef9a0298233593755 100644 (file)
  * 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"
 
@@ -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;
@@ -2101,7 +2084,7 @@ dissect_outbound_3270ds(proto_tree *tn3270_tree, tvbuff_t *tvb, gint 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;
@@ -2192,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;
 
@@ -2227,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,
@@ -4383,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) */
@@ -4427,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);
@@ -4648,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,
@@ -4670,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;
@@ -4719,7 +4698,7 @@ 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;
     }
@@ -4739,7 +4718,6 @@ dissect_structured_fields(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset,
     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);
@@ -4964,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 */
 
@@ -4975,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,
@@ -5012,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 */
     }
@@ -5043,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);
@@ -5094,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);
@@ -5122,6 +5101,13 @@ 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_LCL_W:
     case CC_LCL_EW:
@@ -5131,25 +5117,13 @@ dissect_outbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
     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:
@@ -5157,17 +5131,9 @@ dissect_outbound_stream(proto_tree *tn3270_tree, tvbuff_t *tvb, gint offset, tn3
     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;
   }
 
@@ -5178,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,
@@ -5193,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:
@@ -5203,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:
@@ -5239,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;
   }
@@ -5251,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;
@@ -5265,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 = (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);
@@ -5285,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");
@@ -5297,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
@@ -5325,12 +5291,8 @@ add_tn3270_conversation(packet_info *pinfo, int tn3270e, gint model)
      */
     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);
   }
 
@@ -5370,9 +5332,7 @@ 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 = (tn3270_conv_info_t *)conversation_get_proto_data(conversation, proto_tn3270);
     if (tn3270_info != NULL) {
@@ -6662,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)",
@@ -7481,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",
@@ -7675,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));
 
 }