Add back the fix from revision 54693.
[metze/wireshark/wip.git] / epan / proto.c
index a80ce026a0619e3cfc415e8a9d3c294def712973..22842273453be55a9c4ae74924787ea8235fac04 100644 (file)
 #include <ctype.h>
 #include <glib.h>
 #include <float.h>
-#include <wsutil/swar.h>
+
+#include <wsutil/bits_ctz.h>
+#include <wsutil/bits_count_ones.h>
+#include <wsutil/sign_ext.h>
+
+#include <ftypes/ftypes-int.h>
 
 #include "packet.h"
+#include "exceptions.h"
 #include "ptvcursor.h"
 #include "strutil.h"
 #include "addr_resolv.h"
 #include "oids.h"
-#include "plugins.h"
 #include "proto.h"
 #include "epan_dissect.h"
 #include "tvbuff.h"
 #include "emem.h"
+#include "wmem/wmem.h"
 #include "charsets.h"
 #include "asm_utils.h"
 #include "column-utils.h"
+#include "to_str-int.h"
 #include "to_str.h"
+#include "osi-utils.h"
 #include "expert.h"
 #include "show_exception.h"
 
 #include "wspython/wspy_register.h"
 
+#include <wsutil/plugins.h>
+
 #define SUBTREE_ONCE_ALLOCATION_NUMBER 8
 #define SUBTREE_MAX_LEVELS 256
 /* Throw an exception if we exceed this many tree items. */
@@ -170,7 +180,7 @@ proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length);
 static void
 proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length);
 static void
-proto_tree_set_time(field_info *fi, nstime_t *value_ptr);
+proto_tree_set_time(field_info *fi, const nstime_t *value_ptr);
 static void
 proto_tree_set_string(field_info *fi, const char* value);
 static void
@@ -204,6 +214,10 @@ proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length);
 static void
 proto_tree_set_oid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
 static void
+proto_tree_set_system_id(field_info *fi, const guint8* value_ptr, gint length);
+static void
+proto_tree_set_system_id_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
+static void
 proto_tree_set_boolean(field_info *fi, guint32 value);
 static void
 proto_tree_set_float(field_info *fi, float value);
@@ -214,6 +228,8 @@ proto_tree_set_uint(field_info *fi, guint32 value);
 static void
 proto_tree_set_int(field_info *fi, gint32 value);
 static void
+proto_tree_set_int64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, const guint encoding);
+static void
 proto_tree_set_uint64(field_info *fi, guint64 value);
 static void
 proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, const guint encoding);
@@ -221,11 +237,12 @@ static void
 proto_tree_set_eui64(field_info *fi, const guint64 value);
 static void
 proto_tree_set_eui64_tvb(field_info *fi, tvbuff_t *tvb, gint start, const guint encoding);
-static gboolean
-proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
-                           const int len, const gint ett, const gint **fields,
-                           const guint encoding, const int flags,
-                           gboolean first);
+
+/* Handle type length mismatch (now filterable) expert info */
+static int proto_type_length_mismatch = -1;
+static expert_field ei_type_length_mismatch_error = EI_INIT;
+static expert_field ei_type_length_mismatch_warn = EI_INIT;
+static void register_type_length_mismatch(void);
 
 static int proto_register_field_init(header_field_info *hfinfo, const int parent);
 
@@ -239,9 +256,9 @@ struct _protocol {
        const char *name;         /* long description */
        const char *short_name;   /* short description */
        const char *filter_name;  /* name of this protocol in filters */
-       int         proto_id;     /* field ID for this protocol */
        GSList     *fields;       /* fields for this protocol */
        GSList     *last_field;   /* pointer to end of list of fields */
+       int         proto_id;     /* field ID for this protocol */
        gboolean    is_enabled;   /* TRUE if protocol is enabled */
        gboolean    can_toggle;   /* TRUE if is_enabled can be changed */
        gboolean    is_private;   /* TRUE is protocol is private */
@@ -250,28 +267,25 @@ struct _protocol {
 /* List of all protocols */
 static GList *protocols = NULL;
 
-#define INITIAL_NUM_PROTOCOL_HFINFO    1500
-
 /* Contains information about a field when a dissector calls
  * proto_tree_add_item.  */
-#define FIELD_INFO_NEW(fi)  fi = g_slice_new(field_info)
-#define FIELD_INFO_FREE(fi) g_slice_free(field_info, fi)
+#define FIELD_INFO_NEW(pool, fi)  fi = wmem_new(pool, field_info)
+#define FIELD_INFO_FREE(pool, fi) wmem_free(pool, fi)
 
 /* Contains the space for proto_nodes. */
-#define PROTO_NODE_NEW(node)                           \
-       node = g_slice_new(proto_node);                 \
-       node->first_child = NULL;                       \
-       node->last_child = NULL;                        \
+#define PROTO_NODE_INIT(node)                  \
+       node->first_child = NULL;               \
+       node->last_child = NULL;                \
        node->next = NULL;
 
-#define PROTO_NODE_FREE(node)                          \
-       g_slice_free(proto_node, node)
+#define PROTO_NODE_FREE(pool, node)                    \
+       wmem_free(pool, node)
 
 /* String space for protocol and field items for the GUI */
-#define ITEM_LABEL_NEW(il)                             \
-       il = g_slice_new(item_label_t);
-#define ITEM_LABEL_FREE(il)                            \
-       g_slice_free(item_label_t, il);
+#define ITEM_LABEL_NEW(pool, il)                       \
+       il = wmem_new(pool, item_label_t);
+#define ITEM_LABEL_FREE(pool, il)                      \
+       wmem_free(pool, il);
 
 #define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo)                                               \
        if((guint)hfindex >= gpa_hfinfo.len && getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG"))      \
@@ -319,6 +333,87 @@ proto_compare_name(gconstpointer p1_arg, gconstpointer p2_arg)
        return g_ascii_strcasecmp(p1->short_name, p2->short_name);
 }
 
+#ifdef HAVE_PLUGINS
+/*
+ * List of dissector plugins.
+ */
+typedef struct {
+       void (*register_protoinfo)(void);       /* routine to call to register protocol information */
+       void (*reg_handoff)(void);              /* routine to call to register dissector handoff */
+} dissector_plugin;
+
+static GSList *dissector_plugins = NULL;
+
+/*
+ * Callback for each plugin found.
+ */
+static gboolean
+check_for_dissector_plugin(GModule *handle)
+{
+       gpointer gp;
+       void (*register_protoinfo)(void);
+       void (*reg_handoff)(void);
+       dissector_plugin *plugin;
+
+       /*
+        * Do we have a register routine?
+        */
+       if (g_module_symbol(handle, "plugin_register", &gp))
+               register_protoinfo = (void (*)(void))gp;
+       else
+               register_protoinfo = NULL;
+
+       /*
+        * Do we have a reg_handoff routine?
+        */
+       if (g_module_symbol(handle, "plugin_reg_handoff", &gp))
+               reg_handoff = (void (*)(void))gp;
+       else
+               reg_handoff = NULL;
+
+       /*
+        * If we have neither, we're not a dissector plugin.
+        */
+       if (register_protoinfo == NULL && reg_handoff == NULL)
+               return FALSE;
+
+       /*
+        * Add this one to the list of dissector plugins.
+        */
+       plugin = (dissector_plugin *)g_malloc(sizeof (dissector_plugin));
+       plugin->register_protoinfo = register_protoinfo;
+       plugin->reg_handoff = reg_handoff;
+       dissector_plugins = g_slist_append(dissector_plugins, plugin);
+       return TRUE;
+}
+
+static void
+register_dissector_plugin(gpointer data, gpointer user_data _U_)
+{
+       dissector_plugin *plugin = (dissector_plugin *)data;
+
+       if (plugin->register_protoinfo)
+               (plugin->register_protoinfo)();
+}
+
+static void
+reg_handoff_dissector_plugin(gpointer data, gpointer user_data _U_)
+{
+       dissector_plugin *plugin = (dissector_plugin *)data;
+
+       if (plugin->reg_handoff)
+               (plugin->reg_handoff)();
+}
+
+/*
+ * Register dissector plugin type.
+ */
+void
+register_dissector_plugin_type(void)
+{
+       add_plugin_type("dissector", check_for_dissector_plugin);
+}
+#endif /* HAVE_PLUGINS */
 
 /* initialize data structures and register protocols and fields */
 void
@@ -348,6 +443,7 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
 
        /* Register the pseudo-protocols used for exceptions. */
        register_show_exception();
+       register_type_length_mismatch();
 
        /* Have each built-in dissector register its protocols, fields,
           dissector tables, and dissectors to be called through a
@@ -362,12 +458,11 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
 #endif
 
 #ifdef HAVE_PLUGINS
-       /* Now scan for plugins and load all the ones we find, calling
-          their register routines to do the stuff described above. */
+       /* Now call the registration routines for all disssector
+          plugins. */
        if (cb)
                (*cb)(RA_PLUGIN_REGISTER, NULL, client_data);
-       init_plugins();
-       register_all_plugin_registrations();
+       g_slist_foreach(dissector_plugins, register_dissector_plugin, NULL);
 #endif
 
        /* Now call the "handoff registration" routines of all built-in
@@ -387,7 +482,7 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
        /* Now do the same with plugins. */
        if (cb)
                (*cb)(RA_PLUGIN_HANDOFF, NULL, client_data);
-       register_all_plugin_handoffs();
+       g_slist_foreach(dissector_plugins, reg_handoff_dissector_plugin, NULL);
 #endif
 
        /* sort the protocols by protocol name */
@@ -540,8 +635,23 @@ free_GPtrArray_value(gpointer key, gpointer value, gpointer user_data _U_)
 }
 
 static void
-free_node_tree_data(tree_data_t *tree_data)
+proto_tree_free_node(proto_node *node, gpointer data _U_)
+{
+       field_info *finfo  = PNODE_FINFO(node);
+
+       proto_tree_children_foreach(node, proto_tree_free_node, NULL);
+
+       FVALUE_CLEANUP(&finfo->value);
+}
+
+void
+proto_tree_reset(proto_tree *tree)
 {
+       tree_data_t *tree_data = PTREE_DATA(tree);
+
+       proto_tree_children_foreach(tree, proto_tree_free_node, NULL);
+
+       /* free tree data */
        if (tree_data->interesting_hfids) {
                /* Free all the GPtrArray's in the interesting_hfids hash. */
                g_hash_table_foreach(tree_data->interesting_hfids,
@@ -549,34 +659,14 @@ free_node_tree_data(tree_data_t *tree_data)
 
                /* And then destroy the hash. */
                g_hash_table_destroy(tree_data->interesting_hfids);
-       }
-       if (tree_data->fi_tmp)
-               FIELD_INFO_FREE(tree_data->fi_tmp);
 
-       /* And finally the tree_data_t itself. */
-       g_free(tree_data);
-}
-
-#define FREE_NODE_FIELD_INFO(finfo)    \
-       if (finfo->rep) {                       \
-               ITEM_LABEL_FREE(finfo->rep);    \
-       }                               \
-       FVALUE_CLEANUP(&finfo->value);  \
-       FIELD_INFO_FREE(finfo);
-
-static void
-proto_tree_free_node(proto_node *node, gpointer data _U_)
-{
-       field_info *finfo  = PNODE_FINFO(node);
-
-       proto_tree_children_foreach(node, proto_tree_free_node, NULL);
+               tree_data->interesting_hfids = NULL;
+       }
 
-       /* free the field_info data. */
-       FREE_NODE_FIELD_INFO(finfo);
-       node->finfo = NULL;
+       /* Reset track of the number of children */
+       tree_data->count = 0;
 
-       /* Free the proto_node. */
-       PROTO_NODE_FREE(node);
+       PROTO_NODE_INIT(tree);
 }
 
 /* frees the resources that the dissection a proto_tree uses */
@@ -587,11 +677,19 @@ proto_tree_free(proto_tree *tree)
 
        proto_tree_children_foreach(tree, proto_tree_free_node, NULL);
 
-       /* free root node */
-       PROTO_NODE_FREE(tree);
-
        /* free tree data */
-       free_node_tree_data(tree_data);
+       if (tree_data->interesting_hfids) {
+               /* Free all the GPtrArray's in the interesting_hfids hash. */
+               g_hash_table_foreach(tree_data->interesting_hfids,
+                       free_GPtrArray_value, NULL);
+
+               /* And then destroy the hash. */
+               g_hash_table_destroy(tree_data->interesting_hfids);
+       }
+
+       g_slice_free(tree_data_t, tree_data);
+
+       g_slice_free(proto_tree, tree);
 }
 
 /* Is the parsing being done for a visible proto_tree or an invisible one?
@@ -665,8 +763,9 @@ proto_registrar_get_nth(guint hfindex)
 static guint
 prefix_hash (gconstpointer key) {
        /* end the string at the dot and compute its hash */
-       gchar* copy = ep_strdup((const gchar *)key);
+       gchar* copy = g_strdup((const gchar *)key);
        gchar* c    = copy;
+       guint tmp;
 
        for (; *c; c++) {
                if (*c == '.') {
@@ -675,7 +774,9 @@ prefix_hash (gconstpointer key) {
                }
        }
 
-       return g_str_hash(copy);
+       tmp = g_str_hash(copy);
+       g_free(copy);
+       return tmp;
 }
 
 /* are both strings equal up to the end or the dot? */
@@ -1042,19 +1143,22 @@ proto_tree_add_debug_text(proto_tree *tree, const char *format, ...)
        return pi;
 }
 
+void proto_report_dissector_bug(const char *message)
+{
+       if (getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG") != NULL)
+               abort();
+       else
+               THROW_MESSAGE(DissectorError, message);
+}
+
 /* We could probably get away with changing is_error to a minimum length value. */
 static void
 report_type_length_mismatch(proto_tree *tree, const gchar *descr, int length, gboolean is_error) {
-       if (tree) {
-               tree_data_t *tree_data = PTREE_DATA(tree);
-               field_info *fi_save = tree_data->fi_tmp;
-
-               /* Keep the current item from getting freed by proto_tree_new_item. */
-               tree_data->fi_tmp = NULL;
-
-               expert_add_info_format_internal(NULL, tree, PI_MALFORMED, is_error ? PI_ERROR : PI_WARN, "Trying to fetch %s with length %d", descr, length);
 
-               tree_data->fi_tmp = fi_save;
+       if (is_error) {
+               expert_add_info_format(NULL, tree, &ei_type_length_mismatch_error, "Trying to fetch %s with length %d", descr, length);
+       } else {
+               expert_add_info_format(NULL, tree, &ei_type_length_mismatch_warn, "Trying to fetch %s with length %d", descr, length);
        }
 
        if (is_error) {
@@ -1189,7 +1293,6 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                    tvbuff_t *tvb, gint start, gint length,
                    guint encoding)
 {
-       tree_data_t *tree_data = PTREE_DATA(tree);
        proto_item *pi;
        guint32     value, n;
        float       floatval;
@@ -1200,24 +1303,6 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
        guint64     todsecs;
        gboolean    length_error;
 
-       /* there is a possibility here that we might raise an exception
-        * and thus would lose track of the field_info.
-        * store it in a temp so that if we come here again we can reclaim
-        * the field_info without leaking memory.
-        */
-       if (tree_data->fi_tmp) {
-               /* oops, last one we got must have been lost due
-                * to an exception.
-                * good thing we saved it, now we can reverse the
-                * memory leak and reclaim it.
-                */
-               FIELD_INFO_FREE(tree_data->fi_tmp);
-       }
-       /* we might throw an exception, keep track of this one
-        * across the "dangerous" section below.
-       */
-       tree_data->fi_tmp = new_fi;
-
        switch (new_fi->hfinfo->type) {
                case FT_NONE:
                        /* no value to set for FT_NONE */
@@ -1284,7 +1369,14 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                length_error = length < 1 ? TRUE : FALSE;
                                report_type_length_mismatch(tree, "a 64-bit integer", length, length_error);
                        }
-                       proto_tree_set_uint64_tvb(new_fi, tvb, start, length, encoding);
+                       if (new_fi->hfinfo->type == FT_INT64)
+                       {
+                               proto_tree_set_int64_tvb(new_fi, tvb, start, length, encoding);
+                       }
+                       else
+                       {
+                               proto_tree_set_uint64_tvb(new_fi, tvb, start, length, encoding);
+                       }
                        break;
 
                /* XXX - make these just FT_INT? */
@@ -1394,9 +1486,14 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        break;
 
                case FT_OID:
+               case FT_REL_OID:
                        proto_tree_set_oid_tvb(new_fi, tvb, start, length);
                        break;
 
+               case FT_SYSTEM_ID:
+                       proto_tree_set_system_id_tvb(new_fi, tvb, start, length);
+                       break;
+
                case FT_FLOAT:
                        /*
                         * NOTE: to support code written when
@@ -1471,7 +1568,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                         */
                        if (length == -1) {
                                /* This can throw an exception */
-                               string = tvb_get_stringz_enc(tvb, start, &length, encoding);
+                               string = tvb_get_stringz_enc(wmem_packet_scope(), tvb, start, &length, encoding);
                        } else if (length == 0) {
                                string = "[Empty]";
                        } else {
@@ -1506,7 +1603,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 * we made string values counted
                                 * rather than null-terminated.)
                                 */
-                               string = tvb_get_ephemeral_string_enc(tvb, start, length, encoding);
+                               string = tvb_get_string_enc(wmem_packet_scope(), tvb, start, length, encoding);
                        }
                        new_fi->length = length;
                        proto_tree_set_string(new_fi, string);
@@ -1573,7 +1670,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 * 4-byte fractional time in nanoseconds,
                                 * both big-endian.
                                 */
-                               time_stamp.secs  = tvb_get_ntohl(tvb, start);
+                               time_stamp.secs  = (time_t)tvb_get_ntohl(tvb, start);
                                if (length == 8)
                                        time_stamp.nsecs = tvb_get_ntohl(tvb, start+4);
                                else
@@ -1586,7 +1683,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 * 4-byte fractional time in nanoseconds,
                                 * both little-endian.
                                 */
-                               time_stamp.secs  = tvb_get_letohl(tvb, start);
+                               time_stamp.secs  = (time_t)tvb_get_letohl(tvb, start);
                                if (length == 8)
                                        time_stamp.nsecs = tvb_get_letohl(tvb, start+4);
                                else
@@ -1598,7 +1695,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 * TOD time stamp, big-endian.
                                 */
 /* XXX - where should this go? */
-#define TOD_BASETIME 2208988800ul
+#define TOD_BASETIME G_GUINT64_CONSTANT(2208988800)
 
                                todsecs  = tvb_get_ntoh64(tvb, start) >> 12;
                                time_stamp.secs = (time_t)((todsecs  / 1000000) - TOD_BASETIME);
@@ -1620,7 +1717,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 */
 
 /* XXX - where should this go? */
-#define NTP_BASETIME 2208988800ul
+#define NTP_BASETIME G_GUINT64_CONSTANT(2208988800)
 
                                /* We need a temporary variable here so the unsigned math
                                 * works correctly (for years > 2036 according to RFC 2030
@@ -1628,7 +1725,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 */
                                tmpsecs  = tvb_get_ntohl(tvb, start);
                                if (tmpsecs)
-                                       time_stamp.secs = tmpsecs - (guint32)NTP_BASETIME;
+                                       time_stamp.secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME);
                                else
                                        time_stamp.secs = tmpsecs; /* 0 */
 
@@ -1652,7 +1749,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 */
                                tmpsecs  = tvb_get_letohl(tvb, start);
                                if (tmpsecs)
-                                       time_stamp.secs = tmpsecs - (guint32)NTP_BASETIME;
+                                       time_stamp.secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME);
                                else
                                        time_stamp.secs = tmpsecs; /* 0 */
 
@@ -1672,7 +1769,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
 
                        default:
                                DISSECTOR_ASSERT_NOT_REACHED();
-                               time_stamp.secs = 0;
+                               time_stamp.secs = (time_t)0;
                                time_stamp.nsecs = 0;
                                break;
                        }
@@ -1708,7 +1805,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 * 4-byte fractional time in nanoseconds,
                                 * both big-endian.
                                 */
-                               time_stamp.secs  = tvb_get_ntohl(tvb, start);
+                               time_stamp.secs  = (time_t)tvb_get_ntohl(tvb, start);
                                if (length == 8)
                                        time_stamp.nsecs = tvb_get_ntohl(tvb, start+4);
                                else
@@ -1721,7 +1818,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                                 * 4-byte fractional time in nanoseconds,
                                 * both little-endian.
                                 */
-                               time_stamp.secs  = tvb_get_letohl(tvb, start);
+                               time_stamp.secs  = (time_t)tvb_get_letohl(tvb, start);
                                if (length == 8)
                                        time_stamp.nsecs = tvb_get_letohl(tvb, start+4);
                                else
@@ -1746,11 +1843,6 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
         *      to know which item caused exception? */
        pi = proto_tree_add_node(tree, new_fi);
 
-       /* we did not raise an exception so we dont have to remember this
-        * field_info struct any more.
-        */
-       tree_data->fi_tmp = NULL;
-
        return pi;
 }
 
@@ -1796,30 +1888,15 @@ ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
  * start (pos/neg). Throws an exception if they aren't.
  */
 static void
-test_length(header_field_info *hfinfo, proto_tree *tree, tvbuff_t *tvb,
-           gint start, gint length, const guint encoding)
+test_length(header_field_info *hfinfo, tvbuff_t *tvb,
+           gint start, gint length)
 {
        gint size = length;
 
        if (!tvb)
                return;
 
-       if (hfinfo->type == FT_UINT_BYTES || hfinfo->type == FT_UINT_STRING) {
-               guint32 n;
-
-               n = get_uint_value(tree, tvb, start, length, encoding);
-               if (n > size + n) {
-                       /* If n > size + n then we have an integer overflow, so
-                        * set size to -1, which will force the
-                        * tvb_ensure_bytes_exist call below to throw a
-                        * ReportedBoundsError
-                        */
-                       size = -1;
-               }
-               else {
-                       size += n;
-               }
-       } else if (hfinfo->type == FT_STRINGZ) {
+       if (hfinfo->type == FT_STRINGZ) {
                /* If we're fetching until the end of the TVB, only validate
                 * that the offset is within range.
                 */
@@ -1842,7 +1919,7 @@ proto_tree_add_item_new(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *t
        DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
 
        get_hfi_length(hfinfo, tvb, start, &length, &item_length);
-       test_length(hfinfo, tree, tvb, start, item_length, encoding);
+       test_length(hfinfo, tvb, start, item_length);
 
        TRY_TO_FAKE_THIS_ITEM(tree, hfinfo->id, hfinfo);
 
@@ -1858,7 +1935,7 @@ proto_item *
 proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                    const gint start, gint length, const guint encoding)
 {
-        return proto_tree_add_item_new(tree, proto_registrar_get_nth(hfindex), tvb, start, length, encoding);
+       return proto_tree_add_item_new(tree, proto_registrar_get_nth(hfindex), tvb, start, length, encoding);
 }
 
 /* Add a FT_NONE to a proto_tree */
@@ -1913,7 +1990,7 @@ ptvcursor_advance(ptvcursor_t* ptvc, gint length)
 static void
 proto_tree_set_protocol_tvb(field_info *fi, tvbuff_t *tvb)
 {
-       fvalue_set(&fi->value, tvb, TRUE);
+       fvalue_set_tvbuff(&fi->value, tvb);
 }
 
 /* Add a FT_PROTOCOL to a proto_tree */
@@ -2019,11 +2096,13 @@ proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length)
 {
        GByteArray *bytes;
 
+       DISSECTOR_ASSERT(start_ptr != NULL || length == 0);
+
        bytes = g_byte_array_new();
        if (length > 0) {
                g_byte_array_append(bytes, start_ptr, length);
        }
-       fvalue_set(&fi->value, bytes, TRUE);
+       fvalue_set_byte_array(&fi->value, bytes);
 }
 
 
@@ -2036,7 +2115,7 @@ proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length
 /* Add a FT_*TIME to a proto_tree */
 proto_item *
 proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
-                   gint length, nstime_t *value_ptr)
+                   gint length, const nstime_t *value_ptr)
 {
        proto_item        *pi;
        header_field_info *hfinfo;
@@ -2092,11 +2171,11 @@ proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
 /* Set the FT_*TIME value */
 static void
-proto_tree_set_time(field_info *fi, nstime_t *value_ptr)
+proto_tree_set_time(field_info *fi, const nstime_t *value_ptr)
 {
        DISSECTOR_ASSERT(value_ptr != NULL);
 
-       fvalue_set(&fi->value, value_ptr, FALSE);
+       fvalue_set_time(&fi->value, value_ptr);
 }
 
 /* Add a FT_IPXNET to a proto_tree */
@@ -2287,7 +2366,7 @@ static void
 proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr)
 {
        DISSECTOR_ASSERT(value_ptr != NULL);
-       fvalue_set(&fi->value, (gpointer) value_ptr, FALSE);
+       fvalue_set_bytes(&fi->value, value_ptr);
 }
 
 static void
@@ -2358,7 +2437,7 @@ static void
 proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr)
 {
        DISSECTOR_ASSERT(value_ptr != NULL);
-       fvalue_set(&fi->value, (gpointer) value_ptr, FALSE);
+       fvalue_set_guid(&fi->value, value_ptr);
 }
 
 static void
@@ -2434,13 +2513,13 @@ proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length)
 {
        GByteArray *bytes;
 
-       DISSECTOR_ASSERT(value_ptr != NULL);
+       DISSECTOR_ASSERT(value_ptr != NULL || length == 0);
 
        bytes = g_byte_array_new();
        if (length > 0) {
                g_byte_array_append(bytes, value_ptr, length);
        }
-       fvalue_set(&fi->value, bytes, TRUE);
+       fvalue_set_byte_array(&fi->value, bytes);
 }
 
 static void
@@ -2449,6 +2528,27 @@ proto_tree_set_oid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
        proto_tree_set_oid(fi, tvb_get_ptr(tvb, start, length), length);
 }
 
+/* Set the FT_SYSTEM_ID value */
+static void
+proto_tree_set_system_id(field_info *fi, const guint8* value_ptr, gint length)
+{
+       GByteArray *bytes;
+
+       DISSECTOR_ASSERT(value_ptr != NULL || length == 0);
+
+       bytes = g_byte_array_new();
+       if (length > 0) {
+               g_byte_array_append(bytes, value_ptr, length);
+       }
+       fvalue_set_byte_array(&fi->value, bytes);
+}
+
+static void
+proto_tree_set_system_id_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
+{
+       proto_tree_set_system_id(fi, tvb_get_ptr(tvb, start, length), length);
+}
+
 static void
 proto_tree_set_uint64(field_info *fi, guint64 value)
 {
@@ -2466,7 +2566,7 @@ proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start,
                          guint length, const guint encoding)
 {
        guint64 value = 0;
-       guint8* b = (guint8 *)ep_tvb_memdup(tvb, start, length);
+       guint8* b = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, start, length);
 
        if (encoding) {
                b += length;
@@ -2500,6 +2600,70 @@ proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start,
        proto_tree_set_uint64(fi, value);
 }
 
+static void
+proto_tree_set_int64_tvb(field_info *fi, tvbuff_t *tvb, gint start,
+                         guint length, const guint encoding)
+{
+       guint64 value = 0;
+       guint8* b = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, start, length);
+
+       if (encoding) {
+               b += length;
+               switch (length) {
+                       default: DISSECTOR_ASSERT_NOT_REACHED();
+                       case 8: value <<= 8; value += *--b;
+                       case 7: value <<= 8; value += *--b;
+                       case 6: value <<= 8; value += *--b;
+                       case 5: value <<= 8; value += *--b;
+                       case 4: value <<= 8; value += *--b;
+                       case 3: value <<= 8; value += *--b;
+                       case 2: value <<= 8; value += *--b;
+                       case 1: value <<= 8; value += *--b;
+                               break;
+               }
+       } else {
+               switch (length) {
+                       default: DISSECTOR_ASSERT_NOT_REACHED();
+                       case 8: value <<= 8; value += *b++;
+                       case 7: value <<= 8; value += *b++;
+                       case 6: value <<= 8; value += *b++;
+                       case 5: value <<= 8; value += *b++;
+                       case 4: value <<= 8; value += *b++;
+                       case 3: value <<= 8; value += *b++;
+                       case 2: value <<= 8; value += *b++;
+                       case 1: value <<= 8; value += *b++;
+                               break;
+               }
+       }
+
+       switch(length)
+       {
+               case 7:
+                       value = ws_sign_ext64(value, 56);
+                       break;
+               case 6:
+                       value = ws_sign_ext64(value, 48);
+                       break;
+               case 5:
+                       value = ws_sign_ext64(value, 40);
+                       break;
+               case 4:
+                       value = ws_sign_ext64(value, 32);
+                       break;
+               case 3:
+                       value = ws_sign_ext64(value, 24);
+                       break;
+               case 2:
+                       value = ws_sign_ext64(value, 16);
+                       break;
+               case 1:
+                       value = ws_sign_ext64(value, 8);
+                       break;
+       }
+
+       proto_tree_set_uint64(fi, value);
+}
+
 /* Add a FT_STRING or FT_STRINGZ to a proto_tree. Creates own copy of string,
  * and frees it when the proto_tree is destroyed. */
 proto_item *
@@ -2513,6 +2677,10 @@ proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
 
        DISSECTOR_ASSERT(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
 
+       if (hfinfo->display == STR_UNICODE) {
+               DISSECTOR_ASSERT(g_utf8_validate(value, -1, NULL));
+       }
+
        pi = proto_tree_add_pi(tree, hfinfo, tvb, start, &length);
        DISSECTOR_ASSERT(length >= 0);
        proto_tree_set_string(PNODE_FINFO(pi), value);
@@ -2520,14 +2688,6 @@ proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        return pi;
 }
 
-proto_item *
-proto_tree_add_unicode_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
-                     gint length, const char* value)
-{
-       DISSECTOR_ASSERT(g_utf8_validate(value, -1, NULL));
-       return proto_tree_add_string_format_value(tree, hfindex, tvb, start, length, value, "%s", value);
-}
-
 proto_item *
 proto_tree_add_string_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                                   gint start, gint length, const char* value,
@@ -2609,7 +2769,7 @@ proto_item_append_string(proto_item *pi, const char *str)
                new_str = ep_strconcat(old_str, str, NULL);
        else
                new_str = str;
-       fvalue_set(&fi->value, (gpointer) new_str, FALSE);
+       fvalue_set_string(&fi->value, new_str);
 }
 
 /* Set the FT_STRING value */
@@ -2617,9 +2777,9 @@ static void
 proto_tree_set_string(field_info *fi, const char* value)
 {
        if (value) {
-               fvalue_set(&fi->value, (gpointer) value, FALSE);
+               fvalue_set_string(&fi->value, value);
        } else {
-               fvalue_set(&fi->value, (gpointer) "[ Null ]", FALSE);
+               fvalue_set_string(&fi->value, "[ Null ]");
        }
 }
 
@@ -2632,7 +2792,7 @@ proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length
                length = tvb_ensure_length_remaining(tvb, start);
        }
 
-       string = tvb_get_ephemeral_string_enc(tvb, start, length, encoding);
+       string = tvb_get_string_enc(wmem_packet_scope(), tvb, start, length, encoding);
        proto_tree_set_string(fi, string);
 }
 
@@ -2659,7 +2819,7 @@ proto_tree_add_ax25(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
 static void
 proto_tree_set_ax25(field_info *fi, const guint8* value)
 {
-       fvalue_set(&fi->value, (gpointer) value, FALSE);
+       fvalue_set_bytes(&fi->value, value);
 }
 
 static void
@@ -2672,7 +2832,7 @@ proto_tree_set_ax25_tvb(field_info *fi, tvbuff_t *tvb, gint start)
 static void
 proto_tree_set_vines(field_info *fi, const guint8* value)
 {
-       fvalue_set(&fi->value, (gpointer) value, FALSE);
+       fvalue_set_bytes(&fi->value, value);
 }
 
 static void
@@ -2741,7 +2901,7 @@ proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 static void
 proto_tree_set_ether(field_info *fi, const guint8* value)
 {
-       fvalue_set(&fi->value, (gpointer) value, FALSE);
+       fvalue_set_bytes(&fi->value, value);
 }
 
 static void
@@ -3163,9 +3323,8 @@ proto_tree_set_int(field_info *fi, gint32 value)
                /* Shift bits */
                integer >>= hfinfo_bitshift(hfinfo);
 
-               no_of_bits = swar_count_bits(hfinfo->bitmask);
-               if (integer & (1 << (no_of_bits-1)))
-                       integer |= (-1 << no_of_bits);
+               no_of_bits = ws_count_ones(hfinfo->bitmask);
+               integer = ws_sign_ext32(integer, no_of_bits);
        }
 
        fvalue_set_sinteger(&fi->value, integer);
@@ -3323,7 +3482,8 @@ proto_tree_add_node(proto_tree *tree, field_info *fi)
                /* XXX - is it safe to continue here? */
        }
 
-       PROTO_NODE_NEW(pnode);
+       pnode = wmem_new(PNODE_POOL(tree), proto_node);
+       PROTO_NODE_INIT(pnode);
        pnode->parent = tnode;
        PNODE_FINFO(pnode) = fi;
        pnode->tree_data = PTREE_DATA(tree);
@@ -3493,7 +3653,7 @@ new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
 {
        field_info *fi;
 
-       FIELD_INFO_NEW(fi);
+       FIELD_INFO_NEW(PNODE_POOL(tree), fi);
 
        fi->hfinfo     = hfinfo;
        fi->start      = start;
@@ -3556,7 +3716,7 @@ proto_tree_set_representation_value(proto_item *pi, const char *format, va_list
 
                hf = fi->hfinfo;
 
-               ITEM_LABEL_NEW(fi->rep);
+               ITEM_LABEL_NEW(PNODE_POOL(pi), fi->rep);
                if (hf->bitmask && (hf->type == FT_BOOLEAN || IS_FT_UINT(hf->type))) {
                        guint32 val;
                        char *p;
@@ -3598,7 +3758,7 @@ proto_tree_set_representation(proto_item *pi, const char *format, va_list ap)
        DISSECTOR_ASSERT(fi);
 
        if (!PROTO_ITEM_IS_HIDDEN(pi)) {
-               ITEM_LABEL_NEW(fi->rep);
+               ITEM_LABEL_NEW(PNODE_POOL(pi), fi->rep);
                ret = g_vsnprintf(fi->rep->representation, ITEM_LABEL_LENGTH,
                                  format, ap);
                if (ret >= ITEM_LABEL_LENGTH) {
@@ -3610,6 +3770,24 @@ proto_tree_set_representation(proto_item *pi, const char *format, va_list ap)
        }
 }
 
+static const char *
+hfinfo_format_text(const header_field_info *hfinfo, const guchar *string)
+{
+       switch (hfinfo->display) {
+               case STR_ASCII:
+                       return format_text(string, strlen(string));
+/*
+               case STR_ASCII_WSP
+                       return format_text_wsp(string, strlen(string));
+ */
+               case STR_UNICODE:
+                       /* XXX, format_unicode_text() */
+                       return string;
+       }
+
+       return format_text(string, strlen(string));
+}
+
 static int
 protoo_strlcpy(gchar *dest, const gchar *src, gsize dest_size)
 {
@@ -3732,21 +3910,20 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
                        case FT_BYTES:
                                bytes = (guint8 *)fvalue_get(&finfo->value);
                                offset_r += protoo_strlcpy(result+offset_r,
-                                                          bytes_to_str(bytes,
-                                                                       fvalue_length(&finfo->value)),
-                                                          size-offset_r);
+                                               bytes ?  bytes_to_ep_str(bytes, fvalue_length(&finfo->value)) : "<MISSING>",
+                                               size-offset_r);
                                break;
 
                        case FT_ABSOLUTE_TIME:
                                offset_r += protoo_strlcpy(result+offset_r,
-                                                          abs_time_to_str((const nstime_t *)fvalue_get(&finfo->value),
+                                                          abs_time_to_ep_str((const nstime_t *)fvalue_get(&finfo->value),
                                                                           (absolute_time_display_e)hfinfo->display, TRUE),
                                                           size-offset_r);
                                break;
 
                        case FT_RELATIVE_TIME:
                                offset_r += protoo_strlcpy(result+offset_r,
-                                                          rel_time_to_secs_str((const nstime_t *)fvalue_get(&finfo->value)),
+                                                          rel_time_to_secs_ep_str((const nstime_t *)fvalue_get(&finfo->value)),
                                                           size-offset_r);
                                break;
 
@@ -3776,11 +3953,11 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
                        case FT_UINT32:
                        case FT_FRAMENUM:
                                hf_str_val = NULL;
-                               number = IS_FT_INT(hfinfo->type) ? 
+                               number = IS_FT_INT(hfinfo->type) ?
                                                (guint32) fvalue_get_sinteger(&finfo->value) :
                                                fvalue_get_uinteger(&finfo->value);
 
-                               if ((hfinfo->display & BASE_DISPLAY_E_MASK) == BASE_CUSTOM) {
+                               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM) {
                                        gchar tmp[ITEM_LABEL_LENGTH];
                                        custom_fmt_func_t fmtfunc = (custom_fmt_func_t)hfinfo->strings;
 
@@ -3803,7 +3980,7 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
                                        offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
                                }
 
-                               if (hf_str_val && (hfinfo->display & BASE_DISPLAY_E_MASK) == BASE_NONE) {
+                               if (hf_str_val && (hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
                                        g_snprintf(expr+offset_e, size-offset_e, "\"%s\"", hf_str_val);
                                } else {
                                        number_out = hfinfo_numeric_value_format(hfinfo, number_buf, number);
@@ -3851,17 +4028,28 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
 
                        case FT_ETHER:
                                offset_r += protoo_strlcpy(result+offset_r,
-                                                          bytes_to_str_punct((const guint8 *)fvalue_get(&finfo->value),
+                                                          bytes_to_ep_str_punct((const guint8 *)fvalue_get(&finfo->value),
                                                                              FT_ETHER_LEN, ':'),
                                                           size-offset_r);
                                break;
 
                        case FT_GUID:
                                offset_r += protoo_strlcpy(result+offset_r,
-                                                          guid_to_str((e_guid_t *)fvalue_get(&finfo->value)),
+                                                          guid_to_ep_str((e_guid_t *)fvalue_get(&finfo->value)),
                                                           size-offset_r);
                                break;
 
+                       case FT_REL_OID:
+                               bytes = (guint8 *)fvalue_get(&finfo->value);
+                               offset_r += protoo_strlcpy(result+offset_r,
+                                                          rel_oid_resolved_from_encoded(bytes,
+                                                                                    fvalue_length(&finfo->value)),
+                                                          size-offset_r);
+                               offset_e += protoo_strlcpy(expr+offset_e,
+                                                          rel_oid_encoded2string(bytes, fvalue_length(&finfo->value)),
+                                                          size-offset_e);
+                               break;
+
                        case FT_OID:
                                bytes = (guint8 *)fvalue_get(&finfo->value);
                                offset_r += protoo_strlcpy(result+offset_r,
@@ -3873,15 +4061,25 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
                                                           size-offset_e);
                                break;
 
+                       case FT_SYSTEM_ID:
+                               bytes = (guint8 *)fvalue_get(&finfo->value);
+                               offset_r += protoo_strlcpy(result+offset_r,
+                                                          print_system_id(bytes, fvalue_length(&finfo->value)),
+                                                          size-offset_r);
+                               offset_e += protoo_strlcpy(expr+offset_e,
+                                                          print_system_id(bytes, fvalue_length(&finfo->value)),
+                                                          size-offset_e);
+                               break;
+
                        case FT_FLOAT:
                                g_snprintf(result+offset_r, size-offset_r,
-                                          "%." STRINGIFY(FLT_DIG) "g", fvalue_get_floating(&finfo->value));
+                                          "%." G_STRINGIFY(FLT_DIG) "g", fvalue_get_floating(&finfo->value));
                                offset_r = (int)strlen(result);
                                break;
 
                        case FT_DOUBLE:
                                g_snprintf(result+offset_r, size-offset_r,
-                                          "%." STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
+                                          "%." G_STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
                                offset_r = (int)strlen(result);
                                break;
 
@@ -3890,7 +4088,7 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
                        case FT_UINT_STRING:
                                bytes = (guint8 *)fvalue_get(&finfo->value);
                                offset_r += protoo_strlcpy(result+offset_r,
-                                                          format_text(bytes, strlen(bytes)),
+                                                          hfinfo_format_text(hfinfo, bytes),
                                                           size-offset_r);
                                break;
 
@@ -3919,6 +4117,8 @@ proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
                case FT_INT24:
                case FT_INT32:
                case FT_OID:
+               case FT_REL_OID:
+               case FT_SYSTEM_ID:
                        /* for these types, "expr" is filled in the loop above */
                        break;
 
@@ -3961,7 +4161,7 @@ proto_item_set_text(proto_item *pi, const char *format, ...)
                return;
 
        if (fi->rep) {
-               ITEM_LABEL_FREE(fi->rep);
+               ITEM_LABEL_FREE(PNODE_POOL(pi), fi->rep);
                fi->rep = NULL;
        }
 
@@ -3993,7 +4193,7 @@ proto_item_append_text(proto_item *pi, const char *format, ...)
                 * generate the default representation.
                 */
                if (fi->rep == NULL) {
-                       ITEM_LABEL_NEW(fi->rep);
+                       ITEM_LABEL_NEW(PNODE_POOL(pi), fi->rep);
                        proto_item_fill_label(fi, fi->rep->representation);
                }
 
@@ -4030,7 +4230,7 @@ proto_item_prepend_text(proto_item *pi, const char *format, ...)
                 * generate the default representation.
                 */
                if (fi->rep == NULL) {
-                       ITEM_LABEL_NEW(fi->rep);
+                       ITEM_LABEL_NEW(PNODE_POOL(pi), fi->rep);
                        proto_item_fill_label(fi, representation);
                } else
                        g_strlcpy(representation, fi->rep->representation, ITEM_LABEL_LENGTH);
@@ -4104,10 +4304,11 @@ proto_tree_create_root(packet_info *pinfo)
        proto_node *pnode;
 
        /* Initialize the proto_node */
-       PROTO_NODE_NEW(pnode);
+       pnode = g_slice_new(proto_tree);
+       PROTO_NODE_INIT(pnode);
        pnode->parent = NULL;
        PNODE_FINFO(pnode) = NULL;
-       pnode->tree_data = g_new(tree_data_t, 1);
+       pnode->tree_data = g_slice_new(tree_data_t);
 
        /* Make sure we can access pinfo everywhere */
        pnode->tree_data->pinfo = pinfo;
@@ -4127,8 +4328,6 @@ proto_tree_create_root(packet_info *pinfo)
        /* Keep track of the number of children */
        pnode->tree_data->count = 0;
 
-       pnode->tree_data->fi_tmp = NULL;
-
        return (proto_tree *)pnode;
 }
 
@@ -4180,7 +4379,7 @@ proto_item_add_subtree(proto_item *pi,    const gint idx) {
 }
 
 proto_tree *
-proto_item_get_subtree(const proto_item *pi) {
+proto_item_get_subtree(proto_item *pi) {
        field_info *fi;
 
        if (!pi)
@@ -4212,7 +4411,7 @@ proto_item_get_parent_nth(proto_item *ti, int gen) {
 
 
 proto_item *
-proto_tree_get_parent(const proto_tree *tree) {
+proto_tree_get_parent(proto_tree *tree) {
        if (!tree)
                return NULL;
        return (proto_item *)tree;
@@ -4305,9 +4504,10 @@ proto_register_protocol(const char *name, const char *short_name,
                        const char *filter_name)
 {
        protocol_t *protocol;
+       const protocol_t *existing_protocol = NULL;
        header_field_info *hfinfo;
        int proto_id;
-       char *existing_name;
+       const char *existing_name;
        gint *key;
        guint i;
        guchar c;
@@ -4332,7 +4532,7 @@ proto_register_protocol(const char *name, const char *short_name,
        key  = (gint *)g_malloc (sizeof(gint));
        *key = wrs_str_hash(name);
 
-       existing_name = (char *)g_hash_table_lookup(proto_names, key);
+       existing_name = (const char *)g_hash_table_lookup(proto_names, key);
        if (existing_name != NULL) {
                /* g_error will terminate the program */
                g_error("Duplicate protocol name \"%s\"!"
@@ -4340,7 +4540,7 @@ proto_register_protocol(const char *name, const char *short_name,
        }
        g_hash_table_insert(proto_names, key, (gpointer)name);
 
-       existing_name = (char *)g_hash_table_lookup(proto_short_names, (gpointer)short_name);
+       existing_name = (const char *)g_hash_table_lookup(proto_short_names, (gpointer)short_name);
        if (existing_name != NULL) {
                g_error("Duplicate protocol short_name \"%s\"!"
                        " This might be caused by an inappropriate plugin or a development error.", short_name);
@@ -4359,12 +4559,11 @@ proto_register_protocol(const char *name, const char *short_name,
                        " Allowed are lower characters, digits, '-', '_' and '.'."
                        " This might be caused by an inappropriate plugin or a development error.", filter_name);
        }
-       existing_name = (char *)g_hash_table_lookup(proto_filter_names, (gpointer)filter_name);
-       if (existing_name != NULL) {
+       existing_protocol = (const protocol_t *)g_hash_table_lookup(proto_filter_names, (gpointer)filter_name);
+       if (existing_protocol != NULL) {
                g_error("Duplicate protocol filter_name \"%s\"!"
                        " This might be caused by an inappropriate plugin or a development error.", filter_name);
        }
-       g_hash_table_insert(proto_filter_names, (gpointer)filter_name, (gpointer)filter_name);
 
        /* Add this protocol to the list of known protocols; the list
           is sorted by protocol short name. */
@@ -4378,6 +4577,7 @@ proto_register_protocol(const char *name, const char *short_name,
        protocol->is_private = FALSE;
        /* list will be sorted later by name, when all protocols completed registering */
        protocols = g_list_prepend(protocols, protocol);
+       g_hash_table_insert(proto_filter_names, (gpointer)filter_name, protocol);
 
        /* Here we allocate a new header_field_info struct */
        hfinfo = g_slice_new(header_field_info);
@@ -4494,15 +4694,6 @@ find_protocol_by_id(const int proto_id)
        return (protocol_t *)hfinfo->strings;
 }
 
-static gint compare_filter_name(gconstpointer proto_arg,
-                               gconstpointer filter_name)
-{
-       const protocol_t *protocol = (const protocol_t *)proto_arg;
-       const gchar      *f_name   = (const gchar *)filter_name;
-
-       return (strcmp(protocol->filter_name, f_name));
-}
-
 int
 proto_get_id(const protocol_t *protocol)
 {
@@ -4511,20 +4702,17 @@ proto_get_id(const protocol_t *protocol)
 
 int proto_get_id_by_filter_name(const gchar* filter_name)
 {
-       GList      *list_entry;
-       protocol_t *protocol;
+       const protocol_t *protocol = NULL;
 
        if(!filter_name){
                fprintf(stderr, "No filter name present");
                DISSECTOR_ASSERT(filter_name);
        }
 
-       list_entry = g_list_find_custom(protocols, filter_name,
-               compare_filter_name);
+       protocol = (const protocol_t *)g_hash_table_lookup(proto_filter_names, (gpointer)filter_name);
 
-       if (list_entry == NULL)
+       if (protocol == NULL)
                return -1;
-       protocol = (protocol_t *)list_entry->data;
        return protocol->proto_id;
 }
 
@@ -4567,6 +4755,38 @@ proto_get_protocol_filter_name(const int proto_id)
        return protocol->filter_name;
 }
 
+void
+proto_get_frame_protocols(const wmem_list_t *layers,
+               gboolean *is_ip, gboolean *is_tcp, gboolean *is_udp, gboolean *is_sctp, gboolean *is_ssl) {
+       wmem_list_frame_t *protos = wmem_list_head(layers);
+       int         proto_id;
+       const char *proto_name;
+
+       /* Walk the list of a available protocols in the packet and
+          find "major" ones. */
+       /* It might make more sense to assemble and return a bitfield. */
+       while (protos != NULL)
+       {
+               proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
+               proto_name = proto_get_protocol_filter_name(proto_id);
+
+               if (is_ip && ((!strcmp(proto_name, "ip")) ||
+                             (!strcmp(proto_name, "ipv6")))) {
+                       *is_ip = TRUE;
+               } else if (is_tcp && !strcmp(proto_name, "tcp")) {
+                       *is_tcp = TRUE;
+               } else if (is_udp && !strcmp(proto_name, "udp")) {
+                       *is_udp = TRUE;
+               } else if (is_sctp && !strcmp(proto_name, "sctp")) {
+                       *is_sctp = TRUE;
+               } else if (is_ssl && !strcmp(proto_name, "ssl")) {
+                       *is_ssl = TRUE;
+               }
+
+               protos = wmem_list_frame_next(protos);
+       }
+}
+
 gboolean
 proto_is_protocol_enabled(const protocol_t *protocol)
 {
@@ -4618,14 +4838,30 @@ proto_set_cant_toggle(const int proto_id)
        protocol->can_toggle = FALSE;
 }
 
+static int
+proto_register_field_common(protocol_t *proto, header_field_info *hfi, const int parent)
+{
+       if (proto != NULL) {
+               if (proto->fields == NULL) {
+                       proto->fields = g_slist_append(NULL, hfi);
+                       proto->last_field = proto->fields;
+               } else {
+                       proto->last_field =
+                               g_slist_append(proto->last_field, hfi)->next;
+               }
+       }
+
+       return proto_register_field_init(hfi, parent);
+}
+
 /* for use with static arrays only, since we don't allocate our own copies
 of the header_field_info struct contained within the hf_register_info struct */
 void
 proto_register_field_array(const int parent, hf_register_info *hf, const int num_records)
 {
-       int               field_id, i;
        hf_register_info *ptr = hf;
        protocol_t       *proto;
+       int               i;
 
        proto = find_protocol_by_id(parent);
        for (i = 0; i < num_records; i++, ptr++) {
@@ -4644,22 +4880,34 @@ proto_register_field_array(const int parent, hf_register_info *hf, const int num
                        return;
                }
 
-               if (proto != NULL) {
-                       if (proto->fields == NULL) {
-                               proto->fields = g_slist_append(NULL, &ptr->hfinfo);
-                               proto->last_field = proto->fields;
-                       } else {
-                               proto->last_field =
-                                       g_slist_append(proto->last_field, &ptr->hfinfo)->next;
-                       }
+               *ptr->p_id = proto_register_field_common(proto, &ptr->hfinfo, parent);
+       }
+}
+
+void
+proto_register_fields_section(const int parent, header_field_info *hfi, const int num_records)
+{
+       int               i;
+       protocol_t       *proto;
+
+       proto = find_protocol_by_id(parent);
+       for (i = 0; i < num_records; i++) {
+               /*
+                * Make sure we haven't registered this yet.
+                */
+               if (hfi[i].id != -1) {
+                       fprintf(stderr,
+                               "Duplicate field detected in call to proto_register_fields: %s is already registered\n",
+                               hfi[i].abbrev);
+                       return;
                }
-               field_id = proto_register_field_init(&ptr->hfinfo, parent);
-               *ptr->p_id = field_id;
+
+               proto_register_field_common(proto, &hfi[i], parent);
        }
 }
 
 void
-proto_register_fields(const int parent, header_field_info **hfi, const int num_records)
+proto_register_fields_manual(const int parent, header_field_info **hfi, const int num_records)
 {
        int               i;
        protocol_t       *proto;
@@ -4671,21 +4919,12 @@ proto_register_fields(const int parent, header_field_info **hfi, const int num_r
                 */
                if (hfi[i]->id != -1) {
                        fprintf(stderr,
-                               "Duplicate field detected in call to proto_register_field_array: %s is already registered\n",
+                               "Duplicate field detected in call to proto_register_fields: %s is already registered\n",
                                hfi[i]->abbrev);
                        return;
                }
 
-               if (proto != NULL) {
-                       if (proto->fields == NULL) {
-                               proto->fields = g_slist_append(NULL, hfi[i]);
-                               proto->last_field = proto->fields;
-                       } else {
-                               proto->last_field =
-                                       g_slist_append(proto->last_field, hfi[i])->next;
-                       }
-               }
-               proto_register_field_init(hfi[i], parent);
+               proto_register_field_common(proto, hfi[i], parent);
        }
 }
 
@@ -4771,6 +5010,8 @@ static const value_string hf_types[] = {
        { FT_PCRE,          "FT_PCR"           },
        { FT_GUID,          "FT_GUID"          },
        { FT_OID,           "FT_OID"           },
+       { FT_REL_OID,       "FT_REL_OID"       },
+       { FT_SYSTEM_ID,     "FT_SYSTEM_ID"       },
        { 0,                NULL } };
 
 static const value_string hf_display[] = {
@@ -4795,6 +5036,8 @@ static const value_string hf_display[] = {
        { BASE_DEC_HEX|BASE_VAL64_STRING, "BASE_DEC_HEX|BASE_VAL64_STRING" },
        { BASE_HEX_DEC|BASE_VAL64_STRING, "BASE_HEX_DEC|BASE_VAL64_STRING" },
        { BASE_CUSTOM|BASE_VAL64_STRING,  "BASE_CUSTOM|BASE_VAL64_STRING"  },
+       /* { STR_ASCII,                   "STR_ASCII" }, */
+       { STR_UNICODE,                    "STR_UNICODE" },
        { ABSOLUTE_TIME_LOCAL,            "ABSOLUTE_TIME_LOCAL"            },
        { ABSOLUTE_TIME_UTC,              "ABSOLUTE_TIME_UTC"              },
        { ABSOLUTE_TIME_DOY_UTC,          "ABSOLUTE_TIME_DOY_UTC"          },
@@ -4850,7 +5093,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
           report those that have same value but different string. */
        if ((hfinfo->strings != NULL) &&
            !(hfinfo->display & BASE_RANGE_STRING) &&
-           !((hfinfo->display & BASE_DISPLAY_E_MASK) == BASE_CUSTOM) &&
+           !((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM) &&
            (
                    (hfinfo->type == FT_UINT8)  ||
                    (hfinfo->type == FT_UINT16) ||
@@ -4907,7 +5150,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                         *      signed field to be displayed unsigned.  (Else how would
                         *      we display negative values?)
                         */
-                       switch (hfinfo->display & BASE_DISPLAY_E_MASK) {
+                       switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
                                case BASE_HEX:
                                case BASE_OCT:
                                case BASE_DEC_HEX:
@@ -4930,7 +5173,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                         *  normally used except when constructing a display
                         *  filter for a value not found in the strings lookup.
                         */
-                       switch (hfinfo->display & BASE_DISPLAY_E_MASK) {
+                       switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
                                case BASE_DEC:
                                case BASE_HEX:
                                case BASE_OCT:
@@ -4977,6 +5220,32 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                                        val_to_str(hfinfo->type, hf_types, "(Unknown: %d)"));
                        break;
 
+               case FT_STRING:
+               case FT_STRINGZ:
+               case FT_UINT_STRING:
+                       switch (hfinfo->display) {
+                               case STR_ASCII:
+                               case STR_UNICODE:
+                                       break;
+
+                               default:
+                                       g_error("Field '%s' (%s) is an string value (%s)"
+                                               " but is being displayed as %s\n",
+                                               hfinfo->name, hfinfo->abbrev,
+                                               val_to_str(hfinfo->type, hf_types, "(Unknown: %d)"),
+                                               val_to_str(hfinfo->display, hf_display, "(Unknown: 0x%x)"));
+                       }
+
+                       if (hfinfo->bitmask != 0)
+                               g_error("Field '%s' (%s) is an %s but has a bitmask\n",
+                                       hfinfo->name, hfinfo->abbrev,
+                                       val_to_str(hfinfo->type, hf_types, "(Unknown: %d)"));
+                       if (hfinfo->strings != NULL)
+                               g_error("Field '%s' (%s) is an %s but has a strings value\n",
+                                       hfinfo->name, hfinfo->abbrev,
+                                       val_to_str(hfinfo->type, hf_types, "(Unknown: %d)"));
+                       break;
+
                default:
                        if (hfinfo->display != BASE_NONE)
                                g_error("Field '%s' (%s) is an %s but is being displayed as %s instead of BASE_NONE\n",
@@ -4995,7 +5264,27 @@ tmp_fld_check_assert(header_field_info *hfinfo)
        }
 }
 
-#define PROTO_PRE_ALLOC_HF_FIELDS_MEM (120000+PRE_ALLOC_EXPERT_FIELDS_MEM)
+static void
+register_type_length_mismatch(void)
+{
+       static ei_register_info ei[] = {
+               { &ei_type_length_mismatch_error, { "_ws.type_length.mismatch", PI_MALFORMED, PI_ERROR, "Trying to fetch X with length Y", EXPFILL }},
+               { &ei_type_length_mismatch_warn, { "_ws.type_length.mismatch", PI_MALFORMED, PI_WARN, "Trying to fetch X with length Y", EXPFILL }},
+       };
+
+       expert_module_t* expert_type_length_mismatch;
+
+       proto_type_length_mismatch = proto_register_protocol("Type Length Mismatch", "Type length mismatch", "_ws.type_length");
+
+       expert_type_length_mismatch = expert_register_protocol(proto_type_length_mismatch);
+       expert_register_field_array(expert_type_length_mismatch, ei, array_length(ei));
+
+       /* "Type Length Mismatch" isn't really a protocol, it's an error indication;
+          disabling them makes no sense. */
+       proto_set_cant_toggle(proto_type_length_mismatch);
+}
+
+#define PROTO_PRE_ALLOC_HF_FIELDS_MEM (144000+PRE_ALLOC_EXPERT_FIELDS_MEM)
 static int
 proto_register_field_init(header_field_info *hfinfo, const int parent)
 {
@@ -5222,7 +5511,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_UINT_BYTES:
                        bytes = (guint8 *)fvalue_get(&fi->value);
                        label_fill(label_str, 0, hfinfo,
-                                       (bytes) ? bytes_to_str(bytes, fvalue_length(&fi->value)) : "<MISSING>");
+                                       (bytes) ? bytes_to_ep_str(bytes, fvalue_length(&fi->value)) : "<MISSING>");
                        break;
 
                /* Four types of integers to take care of:
@@ -5267,26 +5556,26 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                case FT_FLOAT:
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
-                                  "%s: %." STRINGIFY(FLT_DIG) "g",
+                                  "%s: %." G_STRINGIFY(FLT_DIG) "g",
                                   hfinfo->name, fvalue_get_floating(&fi->value));
                        break;
 
                case FT_DOUBLE:
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
-                                  "%s: %." STRINGIFY(DBL_DIG) "g",
+                                  "%s: %." G_STRINGIFY(DBL_DIG) "g",
                                   hfinfo->name, fvalue_get_floating(&fi->value));
                        break;
 
                case FT_ABSOLUTE_TIME:
                        label_fill(label_str, 0, hfinfo,
-                                  abs_time_to_str((const nstime_t *)fvalue_get(&fi->value),
+                                  abs_time_to_ep_str((const nstime_t *)fvalue_get(&fi->value),
                                                (absolute_time_display_e)hfinfo->display, TRUE));
                        break;
 
                case FT_RELATIVE_TIME:
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                   "%s: %s seconds", hfinfo->name,
-                                  rel_time_to_secs_str((const nstime_t *)fvalue_get(&fi->value)));
+                                  rel_time_to_secs_ep_str((const nstime_t *)fvalue_get(&fi->value)));
                        break;
 
                case FT_IPXNET:
@@ -5310,7 +5599,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                   "%s: %s", hfinfo->name,
-                                  address_to_str( &addr ));
+                                  ep_address_to_str( &addr ));
                        break;
 
                case FT_ETHER:
@@ -5337,7 +5626,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                case FT_GUID:
                        guid = (e_guid_t *)fvalue_get(&fi->value);
-                       label_fill(label_str, 0, hfinfo, guid_to_str(guid));
+                       label_fill(label_str, 0, hfinfo, guid_to_ep_str(guid));
                        break;
 
                case FT_OID:
@@ -5351,6 +5640,24 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                                         oid_encoded2string(bytes, fvalue_length(&fi->value)));
                        }
                        break;
+
+               case FT_REL_OID:
+                       bytes = (guint8 *)fvalue_get(&fi->value);
+                       name = rel_oid_resolved_from_encoded(bytes, fvalue_length(&fi->value));
+                       if (name) {
+                               label_fill_descr(label_str, 0, hfinfo,
+                                        rel_oid_encoded2string(bytes, fvalue_length(&fi->value)), name);
+                       } else {
+                               label_fill(label_str, 0, hfinfo,
+                                        rel_oid_encoded2string(bytes, fvalue_length(&fi->value)));
+                       }
+                       break;
+
+               case FT_SYSTEM_ID:
+                       bytes = (guint8 *)fvalue_get(&fi->value);
+                       label_fill(label_str, 0, hfinfo, print_system_id(bytes, fvalue_length(&fi->value)));
+                       break;
+
                case FT_EUI64:
                        integer64 = fvalue_get_integer64(&fi->value);
                        label_fill_descr(label_str, 0, hfinfo,
@@ -5361,7 +5668,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_STRINGZ:
                case FT_UINT_STRING:
                        bytes = (guint8 *)fvalue_get(&fi->value);
-                       label_fill(label_str, 0, hfinfo, format_text(bytes, strlen(bytes)));
+                       label_fill(label_str, 0, hfinfo, hfinfo_format_text(hfinfo, bytes));
                        break;
 
                default:
@@ -5573,7 +5880,7 @@ fill_label_number64(field_info *fi, gchar *label_str, gboolean is_signed)
        if (hfinfo->strings) {
                const char *val_str = hf_try_val64_to_str_const(value, hfinfo, "Unknown");
 
-               if ((hfinfo->display & BASE_DISPLAY_E_MASK) == BASE_NONE) {
+               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
                        label_fill(label_str, 0, hfinfo, val_str);
                }
                else {
@@ -5588,21 +5895,7 @@ fill_label_number64(field_info *fi, gchar *label_str, gboolean is_signed)
 int
 hfinfo_bitshift(const header_field_info *hfinfo)
 {
-       const guint32 bitmask = hfinfo->bitmask;
-
-#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-       g_assert(bitmask != 0);
-
-       return __builtin_ctz(bitmask);
-#else
-       /* From http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup */
-       static const int table[32] = {
-               0,   1, 28,  2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17,  4, 8,
-               31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18,  6, 11,  5, 10, 9
-       };
-
-       return table[((guint32)((bitmask & -(gint32)bitmask) * 0x077CB531U)) >> 27];
-#endif
+       return ws_ctz(hfinfo->bitmask);
 }
 
 int
@@ -5668,12 +5961,6 @@ _hfinfo_type_hex_octet(int type)
        return -1;
 }
 
-/* private to_str.c API don't export to .h! */
-char *oct_to_str_back(char *ptr, guint32 value);
-char *hex_to_str_back(char *ptr, int pad, guint32 value);
-char *uint_to_str_back(char *ptr, guint32 value);
-char *int_to_str_back(char *ptr, gint32 value);
-
 static const char *
 hfinfo_number_value_format_display(const header_field_info *hfinfo, int display, char buf[32], guint32 value)
 {
@@ -5734,7 +6021,7 @@ static const char *
 hfinfo_numeric_value_format(const header_field_info *hfinfo, char buf[32], guint32 value)
 {
        /* Get the underlying BASE_ value */
-       int display = hfinfo->display & BASE_DISPLAY_E_MASK;
+       int display = hfinfo->display & FIELD_DISPLAY_E_MASK;
 
        if (hfinfo->type == FT_FRAMENUM) {
                /*
@@ -5765,7 +6052,7 @@ static const char *
 hfinfo_number_vals_format(const header_field_info *hfinfo, char buf[32], guint32 value)
 {
        /* Get the underlying BASE_ value */
-       int display = hfinfo->display & BASE_DISPLAY_E_MASK;
+       int display = hfinfo->display & FIELD_DISPLAY_E_MASK;
 
        if (display == BASE_NONE)
                return NULL;
@@ -5784,7 +6071,7 @@ hfinfo_uint64_format(const header_field_info *hfinfo)
        const char *format = NULL;
 
        /* Pick the proper format string */
-       switch (hfinfo->display & BASE_DISPLAY_E_MASK) {
+       switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
                case BASE_DEC:
                        format = "%" G_GINT64_MODIFIER "u";
                        break;
@@ -5813,7 +6100,7 @@ hfinfo_int64_format(const header_field_info *hfinfo)
        const char *format = NULL;
 
        /* Pick the proper format string */
-       switch (hfinfo->display & BASE_DISPLAY_E_MASK) {
+       switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
                case BASE_DEC:
                        format = "%" G_GINT64_MODIFIER "d";
                        break;
@@ -6172,7 +6459,7 @@ proto_registrar_dump_values(void)
                        tfs    = NULL;
 
                        if (hfinfo->strings != NULL) {
-                               if ((hfinfo->display & BASE_DISPLAY_E_MASK) != BASE_CUSTOM &&
+                               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) != BASE_CUSTOM &&
                                    (hfinfo->type == FT_UINT8  ||
                                     hfinfo->type == FT_UINT16 ||
                                     hfinfo->type == FT_UINT24 ||
@@ -6248,7 +6535,7 @@ proto_registrar_dump_values(void)
                                vi = 0;
                                while (range[vi].strptr) {
                                        /* Print in the proper base */
-                                       if ((hfinfo->display & BASE_DISPLAY_E_MASK) == BASE_HEX) {
+                                       if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_HEX) {
                                                printf("R\t%s\t0x%x\t0x%x\t%s\n",
                                                       hfinfo->abbrev,
                                                       range[vi].value_min,
@@ -6357,7 +6644,7 @@ proto_registrar_dump_fields(void)
                            hfinfo->type == FT_INT32  ||
                            hfinfo->type == FT_INT64) {
 
-                               switch (hfinfo->display & BASE_DISPLAY_E_MASK) {
+                               switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
                                        case BASE_NONE:
                                                base_name = "BASE_NONE";
                                                break;
@@ -6426,40 +6713,40 @@ hfinfo_numeric_format(const header_field_info *hfinfo)
 {
        const char *format = NULL;
 
-               /* Get the underlying BASE_ value */
-               switch (hfinfo->display & BASE_DISPLAY_E_MASK) {
-                       case BASE_DEC:
-                       case BASE_DEC_HEX:
-                       case BASE_OCT: /* I'm lazy */
-                       case BASE_CUSTOM:
-                               switch (hfinfo->type) {
-                                       case FT_UINT64:
-                                               format = "%s == %" G_GINT64_MODIFIER "u";
-                                               break;
-                                       case FT_INT64:
-                                               format = "%s == %" G_GINT64_MODIFIER "d";
-                                               break;
-                                       default:
-                                               DISSECTOR_ASSERT_NOT_REACHED();
-                                               ;
-                               }
-                               break;
-                       case BASE_HEX:
-                       case BASE_HEX_DEC:
-                               switch (hfinfo->type) {
-                                       case FT_UINT64:
-                                       case FT_INT64:
-                                               format = "%s == 0x%016" G_GINT64_MODIFIER "x";
-                                               break;
-                                       default:
-                                               DISSECTOR_ASSERT_NOT_REACHED();
-                                               ;
-                               }
-                               break;
-                       default:
-                               DISSECTOR_ASSERT_NOT_REACHED();
-                               ;
-               }
+       /* Get the underlying BASE_ value */
+       switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
+               case BASE_DEC:
+               case BASE_DEC_HEX:
+               case BASE_OCT: /* I'm lazy */
+               case BASE_CUSTOM:
+                       switch (hfinfo->type) {
+                               case FT_UINT64:
+                                       format = "%s == %" G_GINT64_MODIFIER "u";
+                                       break;
+                               case FT_INT64:
+                                       format = "%s == %" G_GINT64_MODIFIER "d";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               case BASE_HEX:
+               case BASE_HEX_DEC:
+                       switch (hfinfo->type) {
+                               case FT_UINT64:
+                               case FT_INT64:
+                                       format = "%s == 0x%016" G_GINT64_MODIFIER "x";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               default:
+                       DISSECTOR_ASSERT_NOT_REACHED();
+                       ;
+       }
        return format;
 }
 
@@ -6484,14 +6771,14 @@ construct_match_selected_string(field_info *finfo, epan_dissect_t *edt,
        guint8             c;
        gchar              is_signed_num = FALSE;
 
-        if (!finfo)
-                return FALSE;
+       if (!finfo)
+               return FALSE;
 
        hfinfo     = finfo->hfinfo;
        DISSECTOR_ASSERT(hfinfo);
        abbrev_len = (int) strlen(hfinfo->abbrev);
 
-       if (hfinfo->strings && (hfinfo->display & BASE_DISPLAY_E_MASK) == BASE_NONE) {
+       if (hfinfo->strings && (hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
                const gchar *str = NULL;
 
                switch (hfinfo->type) {
@@ -6906,44 +7193,45 @@ proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb,
 proto_item *
 proto_tree_add_bitmask_len(proto_tree *parent_tree, tvbuff_t *tvb,
                       const guint offset,  const guint len, const int hf_hdr,
-                      const gint ett, const int **fields,
+                      const gint ett, const int **fields, struct expert_field* exp,
                       const guint encoding)
 {
        proto_item        *item = NULL;
        header_field_info *hf;
+       guint   decodable_len;
+       guint   decodable_offset;
+       guint32 decodable_value;
 
        hf = proto_registrar_get_nth(hf_hdr);
        DISSECTOR_ASSERT(IS_FT_INT(hf->type) || IS_FT_UINT(hf->type));
 
-       if (parent_tree) {
-               guint   decodable_len;
-               guint   decodable_offset;
-               guint32 decodable_value;
-
-               decodable_offset = offset;
-               decodable_len = MIN(len, (guint) ftype_length(hf->type));
+       decodable_offset = offset;
+       decodable_len = MIN(len, (guint) ftype_length(hf->type));
 
-               /* If we are ftype_length-limited,
-                * make sure we decode as many LSBs as possible.
-                */
-               if (encoding == ENC_BIG_ENDIAN) {
-                       decodable_offset += (len - decodable_len);
-               }
+       /* If we are ftype_length-limited,
+        * make sure we decode as many LSBs as possible.
+        */
+       if (encoding == ENC_BIG_ENDIAN) {
+               decodable_offset += (len - decodable_len);
+       }
 
+       if (parent_tree) {
                decodable_value = get_uint_value(parent_tree, tvb, decodable_offset,
                                                 decodable_len, encoding);
 
                /* The root item covers all the bytes even if we can't decode them all */
                item = proto_tree_add_uint(parent_tree, hf_hdr, tvb, offset, len,
                                           decodable_value);
+       }
 
-               if (decodable_len < len) {
-                       /* Dissector likely requires updating for new protocol revision */
-                       expert_add_info_format_internal(NULL, item, PI_UNDECODED, PI_WARN,
-                                              "Only least-significant %d of %d bytes decoded",
-                                              decodable_len, len);
-               }
+       if (decodable_len < len) {
+               /* Dissector likely requires updating for new protocol revision */
+               expert_add_info_format(NULL, item, exp,
+                                      "Only least-significant %d of %d bytes decoded",
+                                      decodable_len, len);
+       }
 
+       if (item) {
                proto_item_add_bitmask_tree(item, tvb, decodable_offset, decodable_len,
                                            ett, fields, encoding, BMT_NO_INT|BMT_NO_TFS, FALSE);
        }
@@ -6979,14 +7267,14 @@ proto_tree_add_bits_item(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
                         const guint encoding)
 {
        header_field_info *hfinfo;
-       gint              octet_length;
-       gint              octet_offset;
+       gint               octet_length;
+       gint               octet_offset;
 
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
 
        octet_length = (no_of_bits + 7) >> 3;
        octet_offset = bit_offset >> 3;
-       test_length(hfinfo, tree, tvb, octet_offset, octet_length, encoding);
+       test_length(hfinfo, tvb, octet_offset, octet_length);
 
        /* Yes, we try to fake this item again in proto_tree_add_bits_ret_val()
         * but only after doing a bunch more work (which we can, in the common
@@ -7054,8 +7342,7 @@ _proto_tree_add_bits_ret_val(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
                case FT_INT24:
                case FT_INT32:
                case FT_INT64:
-                       if (value & (G_GINT64_CONSTANT(1) << (no_of_bits-1)))
-                               value |= (G_GINT64_CONSTANT(-1) << no_of_bits);
+                       value = ws_sign_ext64(value, no_of_bits);
                        break;
 
                default:
@@ -7199,8 +7486,7 @@ proto_tree_add_split_bits_item_ret_val(proto_tree *tree, const int hfindex, tvbu
                case FT_INT24:
                case FT_INT32:
                case FT_INT64:
-                       if (no_of_bits && (value & (G_GINT64_CONSTANT(1) << (no_of_bits-1))))
-                               value |= (G_GINT64_CONSTANT(-1) << no_of_bits);
+                       value = ws_sign_ext64(value, no_of_bits);
                        break;
                default:
                        break;
@@ -7536,6 +7822,36 @@ proto_tree_add_boolean_bits_format_value(proto_tree *tree, const int hfindex,
        return proto_tree_add_bits_format_value(tree, hfindex, tvb, bit_offset, no_of_bits, &value, dst);
 }
 
+proto_item *
+proto_tree_add_ts_23_038_7bits_item(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
+       const guint bit_offset, const gint no_of_chars)
+{
+       proto_item        *pi;
+       header_field_info *hfinfo;
+       gint               byte_length;
+       gint               byte_offset;
+       gchar             *string;
+
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hfinfo);
+
+       DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
+
+       byte_length = (((no_of_chars + 1) * 7) + (bit_offset & 0x07)) >> 3;
+       byte_offset = bit_offset >> 3;
+
+       string = tvb_get_ts_23_038_7bits_string(wmem_packet_scope(), tvb, bit_offset, no_of_chars);
+
+       if (hfinfo->display == STR_UNICODE) {
+               DISSECTOR_ASSERT(g_utf8_validate(string, -1, NULL));
+       }
+
+       pi = proto_tree_add_pi(tree, hfinfo, tvb, byte_offset, &byte_length);
+       DISSECTOR_ASSERT(byte_length >= 0);
+       proto_tree_set_string(PNODE_FINFO(pi), string);
+
+       return pi;
+}
+
 guchar
 proto_check_field_name(const gchar *field_name)
 {