Make some arguments const, and remove casting-away of constness.
[metze/wireshark/wip.git] / epan / proto.c
index 92004047ca3930335b4ec4f1db4c000734fb840a..21471f08edba5cbb51bfd57c28ce9b9d65fde6d3 100644 (file)
@@ -5,19 +5,7 @@
  * 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"
@@ -31,6 +19,7 @@
 #include <wsutil/bits_ctz.h>
 #include <wsutil/bits_count_ones.h>
 #include <wsutil/sign_ext.h>
+#include <wsutil/utf8_entities.h>
 
 #include <ftypes/ftypes-int.h>
 
@@ -46,7 +35,6 @@
 #include "tvbuff.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"
@@ -55,8 +43,8 @@
 #include "show_exception.h"
 #include "in_cksum.h"
 
-#include <wsutil/plugins.h>
 #include <wsutil/ws_printf.h> /* ws_debug_printf/ws_g_warning */
+#include <wsutil/glib-compat.h>
 
 /* Ptvcursor limits */
 #define SUBTREE_ONCE_ALLOCATION_NUMBER 8
@@ -169,6 +157,13 @@ struct ptvcursor {
                 * items string representation */ \
                return; \
        }
+/* Similar to above, but allows a NULL tree */
+#define TRY_TO_FAKE_THIS_REPR_NESTED(pi)       \
+       if ((pi == NULL) || (!(PTREE_DATA(pi)->visible))) { \
+               /* If the tree (GUI) isn't visible it's pointless for us to generate the protocol \
+                * items string representation */ \
+               return pi; \
+       }
 
 static const char *hf_try_val_to_str(guint32 value, const header_field_info *hfinfo);
 static const char *hf_try_val64_to_str(guint64 value, const header_field_info *hfinfo);
@@ -181,6 +176,8 @@ static void fill_label_boolean(field_info *fi, gchar *label_str);
 static void fill_label_bitfield_char(field_info *fi, gchar *label_str);
 static void fill_label_bitfield(field_info *fi, gchar *label_str, gboolean is_signed);
 static void fill_label_bitfield64(field_info *fi, gchar *label_str, gboolean is_signed);
+static void fill_label_bitfield_varint(field_info *fi, gchar *label_str, gboolean is_signed);
+static void fill_label_bitfield_varint64(field_info *fi, gchar *label_str, gboolean is_signed);
 static void fill_label_char(field_info *fi, gchar *label_str);
 static void fill_label_number(field_info *fi, gchar *label_str, gboolean is_signed);
 static void fill_label_number64(field_info *fi, gchar *label_str, gboolean is_signed);
@@ -197,12 +194,14 @@ static const char *hfinfo_char_value_format(const header_field_info *hfinfo, cha
 static const char *hfinfo_numeric_value_format(const header_field_info *hfinfo, char buf[32], guint32 value);
 static const char *hfinfo_numeric_value_format64(const header_field_info *hfinfo, char buf[48], guint64 value);
 
+static void proto_cleanup_base(void);
+
 static proto_item *
 proto_tree_add_node(proto_tree *tree, field_info *fi);
 
 static void
 get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint *length,
-               gint *item_length);
+               gint *item_length, const guint encoding);
 
 static gint
 get_full_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start,
@@ -330,6 +329,9 @@ static GList *pino_protocols = NULL;
 static GPtrArray *deregistered_fields = NULL;
 static GPtrArray *deregistered_data = NULL;
 
+/* indexed by prefix, contains initializers */
+static GHashTable* prefixes = NULL;
+
 /* Contains information about a field when a dissector calls
  * proto_tree_add_item.  */
 #define FIELD_INFO_NEW(pool, fi)  fi = wmem_new(pool, field_info)
@@ -406,108 +408,64 @@ 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 inline guchar
+check_charset(const guint8 table[256], const char *str)
+{
+    const char *p = str;
+    guchar c;
+
+    do {
+      c = *(p++);
+    } while (table[c]);
+    return c;
+}
 
+#ifdef HAVE_PLUGINS
 static GSList *dissector_plugins = NULL;
 
-/*
- * Callback for each plugin found.
- */
-static gboolean
-check_for_dissector_plugin(GModule *handle)
+void
+proto_register_plugin(const proto_plugin *plug)
 {
-       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)) {
-DIAG_OFF(pedantic)
-               register_protoinfo = (void (*)(void))gp;
-DIAG_ON(pedantic)
-       }
-       else {
-               register_protoinfo = NULL;
-       }
-
-       /*
-        * Do we have a reg_handoff routine?
-        */
-       if (g_module_symbol(handle, "plugin_reg_handoff", &gp)) {
-DIAG_OFF(pedantic)
-               reg_handoff = (void (*)(void))gp;
-DIAG_ON(pedantic)
-       }
-       else {
-               reg_handoff = NULL;
+       if (!plug) {
+               /* XXX print useful warning */
+               return;
        }
-
-       /*
-        * 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_prepend(dissector_plugins, plugin);
-       return TRUE;
+       dissector_plugins = g_slist_prepend(dissector_plugins, (proto_plugin *)plug);
 }
 
 static void
-register_dissector_plugin(gpointer data, gpointer user_data _U_)
+call_plugin_register_protoinfo(gpointer data, gpointer user_data _U_)
 {
-       dissector_plugin *plugin = (dissector_plugin *)data;
+       proto_plugin *plug = (proto_plugin *)data;
 
-       if (plugin->register_protoinfo)
-               (plugin->register_protoinfo)();
+       if (plug->register_protoinfo) {
+               plug->register_protoinfo();
+       }
 }
 
 static void
-reg_handoff_dissector_plugin(gpointer data, gpointer user_data _U_)
+call_plugin_register_handoff(gpointer data, gpointer user_data _U_)
 {
-       dissector_plugin *plugin = (dissector_plugin *)data;
-
-       if (plugin->reg_handoff)
-               (plugin->reg_handoff)();
-}
+       proto_plugin *plug = (proto_plugin *)data;
 
-/*
- * Register dissector plugin type.
- */
-void
-register_dissector_plugin_type(void)
-{
-       add_plugin_type("dissector", check_for_dissector_plugin);
+       if (plug->register_handoff) {
+               plug->register_handoff();
+       }
 }
 #endif /* HAVE_PLUGINS */
 
 /* initialize data structures and register protocols and fields */
 void
-proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_data),
-          void (register_all_handoffs_func)(register_cb cb, gpointer client_data),
+proto_init(GSList *register_all_protocols_list,
+          GSList *register_all_handoffs_list,
           register_cb cb,
           gpointer client_data)
 {
-       proto_cleanup();
+       proto_cleanup_base();
 
-       proto_names        = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL);
-       proto_short_names  = g_hash_table_new(wrs_str_hash, g_str_equal);
-       proto_filter_names = g_hash_table_new(wrs_str_hash, g_str_equal);
+       proto_names        = g_hash_table_new(g_str_hash, g_str_equal);
+       proto_short_names  = g_hash_table_new(g_str_hash, g_str_equal);
+       proto_filter_names = g_hash_table_new(g_str_hash, g_str_equal);
 
        gpa_hfinfo.len           = 0;
        gpa_hfinfo.allocated_len = 0;
@@ -536,7 +494,9 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
           dissector tables, and dissectors to be called through a
           handle, and do whatever one-time initialization it needs to
           do. */
-       register_all_protocols_func(cb, client_data);
+       for (GSList *l = register_all_protocols_list; l != NULL; l = l->next) {
+               ((void (*)(register_cb, gpointer))l->data)(cb, client_data);
+       }
 
        /* Now that the VINES dissector has registered it's address
           type, grab the value for the field type */
@@ -546,20 +506,22 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
           plugins. */
        if (cb)
                (*cb)(RA_PLUGIN_REGISTER, NULL, client_data);
-       g_slist_foreach(dissector_plugins, register_dissector_plugin, NULL);
+       g_slist_foreach(dissector_plugins, call_plugin_register_protoinfo, NULL);
 #endif
 
        /* Now call the "handoff registration" routines of all built-in
           dissectors; those routines register the dissector in other
           dissectors' handoff tables, and fetch any dissector handles
           they need. */
-       register_all_handoffs_func(cb, client_data);
+       for (GSList *l = register_all_handoffs_list; l != NULL; l = l->next) {
+               ((void (*)(register_cb, gpointer))l->data)(cb, client_data);
+       }
 
 #ifdef HAVE_PLUGINS
        /* Now do the same with plugins. */
        if (cb)
                (*cb)(RA_PLUGIN_HANDOFF, NULL, client_data);
-       g_slist_foreach(dissector_plugins, reg_handoff_dissector_plugin, NULL);
+       g_slist_foreach(dissector_plugins, call_plugin_register_handoff, NULL);
 #endif
 
        /* sort the protocols by protocol name */
@@ -570,8 +532,8 @@ proto_init(void (register_all_protocols_func)(register_cb cb, gpointer client_da
        tree_is_expanded = g_new0(guint32, (num_tree_types/32)+1);
 }
 
-void
-proto_cleanup(void)
+static void
+proto_cleanup_base(void)
 {
        protocol_t *protocol;
        header_field_info *hfinfo;
@@ -643,6 +605,20 @@ proto_cleanup(void)
 
        g_free(tree_is_expanded);
        tree_is_expanded = NULL;
+
+       if (prefixes)
+               g_hash_table_destroy(prefixes);
+}
+
+void
+proto_cleanup(void)
+{
+       proto_cleanup_base();
+
+#ifdef HAVE_PLUGINS
+       g_slist_free(dissector_plugins);
+       dissector_plugins = NULL;
+#endif
 }
 
 static gboolean
@@ -904,11 +880,6 @@ prefix_equal (gconstpointer ap, gconstpointer bp) {
        return FALSE;
 }
 
-
-/* indexed by prefix, contains initializers */
-static GHashTable* prefixes = NULL;
-
-
 /* Register a new prefix for "delayed" initialization of field arrays */
 void
 proto_register_prefix(const char *prefix, prefix_initializer_t pi ) {
@@ -1210,12 +1181,10 @@ proto_tree_add_text_internal(proto_tree *tree, tvbuff_t *tvb, gint start, gint l
        header_field_info *hfinfo;
 
        if (length == -1) {
-               /* If we're fetching until the end of the TVB, only validate
-                * that the offset is within range.
-                */
-               length = 0;
+               length = tvb_captured_length(tvb) ? tvb_ensure_captured_length_remaining(tvb, start) : 0;
+       } else {
+               tvb_ensure_bytes_exist(tvb, start, length);
        }
-       tvb_ensure_bytes_exist(tvb, start, length);
 
        CHECK_FOR_NULL_TREE(tree);
 
@@ -1241,12 +1210,10 @@ proto_tree_add_text_valist_internal(proto_tree *tree, tvbuff_t *tvb, gint start,
        header_field_info *hfinfo;
 
        if (length == -1) {
-               /* If we're fetching until the end of the TVB, only validate
-                * that the offset is within range.
-                */
-               length = 0;
+               length = tvb_captured_length(tvb) ? tvb_ensure_captured_length_remaining(tvb, start) : 0;
+       } else {
+               tvb_ensure_bytes_exist(tvb, start, length);
        }
-       tvb_ensure_bytes_exist(tvb, start, length);
 
        CHECK_FOR_NULL_TREE(tree);
 
@@ -1388,11 +1355,21 @@ get_uint_value(proto_tree *tree, tvbuff_t *tvb, gint offset, gint length, const
 
        case 1:
                value = tvb_get_guint8(tvb, offset);
+               if (encoding & ENC_ZIGBEE) {
+                       if (value == 0xFF) { /* Invalid Zigbee length, set to 0 */
+                               value = 0;
+                       }
+               }
                break;
 
        case 2:
                value = (encoding & ENC_LITTLE_ENDIAN) ? tvb_get_letohs(tvb, offset)
                                                       : tvb_get_ntohs(tvb, offset);
+               if (encoding & ENC_ZIGBEE) {
+                       if (value == 0xFFFF) { /* Invalid Zigbee length, set to 0 */
+                               value = 0;
+                       }
+               }
                break;
 
        case 3:
@@ -1536,8 +1513,7 @@ get_int64_value(proto_tree *tree, tvbuff_t *tvb, gint start, guint length, const
 {
        guint64 value = get_uint64_value(tree, tvb, start, length, encoding);
 
-       switch(length)
-       {
+       switch (length) {
                case 7:
                        value = ws_sign_ext64(value, 56);
                        break;
@@ -1629,7 +1605,11 @@ get_uint_string_value(wmem_allocator_t *scope, proto_tree *tree,
        const guint8 *value;
 
        /* I believe it's ok if this is called with a NULL tree */
-       n = get_uint_value(tree, tvb, start, length, encoding & ~ENC_CHARENCODING_MASK);
+       if (encoding & ENC_ZIGBEE) {
+               n = get_uint_value(tree, tvb, start, length, encoding);
+       } else {
+               n = get_uint_value(tree, tvb, start, length, encoding & ~ENC_CHARENCODING_MASK);
+       }
        value = tvb_get_string_enc(scope, tvb, start + length, n, encoding);
        length += n;
        *ret_length = length;
@@ -1656,37 +1636,40 @@ get_stringzpad_value(wmem_allocator_t *scope, tvbuff_t *tvb, gint start,
        return tvb_get_string_enc(scope, tvb, start, length, encoding);
 }
 
-/* this can be called when there is no tree, so don't add that as a param */
+/*
+ * Epochs for various non-UN*X time stamp formats.
+ */
+#define NTP_BASETIME G_GUINT64_CONSTANT(2208988800)    /* NTP */
+#define TOD_BASETIME G_GUINT64_CONSTANT(2208988800)    /* System/3x0 and z/Architecture TOD clock */
+
+/* this can be called when there is no tree, so tree may be null */
 static void
-get_time_value(tvbuff_t *tvb, const gint start, const gint length, const guint encoding,
-              nstime_t *time_stamp, const gboolean is_relative)
+get_time_value(proto_tree *tree, tvbuff_t *tvb, const gint start,
+              const gint length, const guint encoding, nstime_t *time_stamp,
+              const gboolean is_relative)
 {
        guint32     tmpsecs;
        guint64     todsecs;
 
-       /* relative timestamps don't do TOD/NTP */
-       if (is_relative &&
-               (encoding != (ENC_TIME_TIMESPEC|ENC_BIG_ENDIAN)) &&
-               (encoding != (ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN)) )
-       {
-               /* XXX: I think this should call REPORT_DISSECTOR_BUG(), but
-                  the existing code didn't do that, so I'm not either */
-               return;
-       }
-
        switch (encoding) {
 
                case ENC_TIME_TIMESPEC|ENC_BIG_ENDIAN:
                        /*
-                        * 4-byte UNIX epoch, possibly followed by
-                        * 4-byte fractional time in nanoseconds,
-                        * both big-endian.
+                        * 4-byte seconds, followed by 4-byte fractional
+                        * time in nanoseconds, both big-endian.
+                        * For absolute times, the seconds are seconds
+                        * since the UN*X epoch.
                         */
                        time_stamp->secs  = (time_t)tvb_get_ntohl(tvb, start);
                        if (length == 8)
                                time_stamp->nsecs = tvb_get_ntohl(tvb, start+4);
-                       else
+                       else if (length == 4) {
+                               /*
+                                * Backwards compatibility.
+                                */
                                time_stamp->nsecs = 0;
+                       } else
+                               report_type_length_mismatch(tree, "a timespec", length, TRUE);
                        break;
 
                case ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN:
@@ -1694,42 +1677,27 @@ get_time_value(tvbuff_t *tvb, const gint start, const gint length, const guint e
                         * 4-byte UNIX epoch, possibly followed by
                         * 4-byte fractional time in nanoseconds,
                         * both little-endian.
+                        * For absolute times, the seconds are seconds
+                        * since the UN*X epoch.
                         */
                        time_stamp->secs  = (time_t)tvb_get_letohl(tvb, start);
                        if (length == 8)
                                time_stamp->nsecs = tvb_get_letohl(tvb, start+4);
-                       else
+                       else if (length == 4) {
+                               /*
+                                * Backwards compatibility.
+                                */
                                time_stamp->nsecs = 0;
-                       break;
-
-               case ENC_TIME_TOD|ENC_BIG_ENDIAN:
-                       /*
-                        * TOD time stamp, big-endian.
-                        */
-/* XXX - where should this go? */
-#define TOD_BASETIME G_GUINT64_CONSTANT(2208988800)
-
-                       todsecs  = tvb_get_ntoh64(tvb, start) >> 12;
-                       time_stamp->secs = (time_t)((todsecs  / 1000000) - TOD_BASETIME);
-                       time_stamp->nsecs = (int)((todsecs  % 1000000) * 1000);
-                       break;
-
-               case ENC_TIME_TOD|ENC_LITTLE_ENDIAN:
-                       /*
-                        * TOD time stamp, big-endian.
-                        */
-                       todsecs  = tvb_get_letoh64(tvb, start) >> 12 ;
-                       time_stamp->secs = (time_t)((todsecs  / 1000000) - TOD_BASETIME);
-                       time_stamp->nsecs = (int)((todsecs  % 1000000) * 1000);
+                       } else
+                               report_type_length_mismatch(tree, "a timespec", length, TRUE);
                        break;
 
                case ENC_TIME_NTP|ENC_BIG_ENDIAN:
                        /*
                         * NTP time stamp, big-endian.
+                        * Only supported for absolute times.
                         */
-
-/* XXX - where should this go? */
-#define NTP_BASETIME G_GUINT64_CONSTANT(2208988800)
+                       DISSECTOR_ASSERT(!is_relative);
 
                        /* We need a temporary variable here so the unsigned math
                         * works correctly (for years > 2036 according to RFC 2030
@@ -1743,22 +1711,25 @@ get_time_value(tvbuff_t *tvb, const gint start, const gint length, const guint e
 
                        if (length == 8) {
                                /*
-                                * We're using nanoseconds here (and we will
-                                * display nanoseconds), but NTP's timestamps
-                                * have a precision in microseconds or greater.
-                                * Round to 1 microsecond.
+                                * Convert 1/2^32s of a second to nanoseconds.
+                                */
+                               time_stamp->nsecs = (int)(1000000000*(tvb_get_ntohl(tvb, start+4)/4294967296.0));
+                       } else if (length == 4) {
+                               /*
+                                * Backwards compatibility.
                                 */
-                               time_stamp->nsecs = (int)(1000000*(tvb_get_ntohl(tvb, start+4)/4294967296.0));
-                               time_stamp->nsecs *= 1000;
-                       } else {
                                time_stamp->nsecs = 0;
-                       }
+                       } else
+                               report_type_length_mismatch(tree, "an NTP time stamp", length, TRUE);
                        break;
 
                case ENC_TIME_NTP|ENC_LITTLE_ENDIAN:
                        /*
-                        * NTP time stamp, big-endian.
+                        * NTP time stamp, little-endian.
+                        * Only supported for absolute times.
                         */
+                       DISSECTOR_ASSERT(!is_relative);
+
                        tmpsecs  = tvb_get_letohl(tvb, start);
                        if (tmpsecs)
                                time_stamp->secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME);
@@ -1767,68 +1738,273 @@ get_time_value(tvbuff_t *tvb, const gint start, const gint length, const guint e
 
                        if (length == 8) {
                                /*
-                                * We're using nanoseconds here (and we will
-                                * display nanoseconds), but NTP's timestamps
-                                * have a precision in microseconds or greater.
-                                * Round to 1 microsecond.
+                                * Convert 1/2^32s of a second to nanoseconds.
+                                */
+                               time_stamp->nsecs = (int)(1000000000*(tvb_get_letohl(tvb, start+4)/4294967296.0));
+                       } else if (length == 4) {
+                               /*
+                                * Backwards compatibility.
                                 */
-                               time_stamp->nsecs = (int)(1000000*(tvb_get_letohl(tvb, start+4)/4294967296.0));
-                               time_stamp->nsecs *= 1000;
-                       } else {
                                time_stamp->nsecs = 0;
-                       }
+                       } else
+                               report_type_length_mismatch(tree, "an NTP time stamp", length, TRUE);
+                       break;
+
+               case ENC_TIME_TOD|ENC_BIG_ENDIAN:
+                       /*
+                        * S/3x0 and z/Architecture TOD clock time stamp,
+                        * big-endian.
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
+                       DISSECTOR_ASSERT(length == 8);
+
+                       if (length == 8) {
+                               todsecs  = tvb_get_ntoh64(tvb, start) >> 12;
+                               time_stamp->secs = (time_t)((todsecs  / 1000000) - TOD_BASETIME);
+                               time_stamp->nsecs = (int)((todsecs  % 1000000) * 1000);
+                       } else
+                               report_type_length_mismatch(tree, "a TOD clock time stamp", length, TRUE);
                        break;
-               case ENC_TIME_NTP_BASE_ZERO|ENC_BIG_ENDIAN:
+
+               case ENC_TIME_TOD|ENC_LITTLE_ENDIAN:
                        /*
-                        * DDS NTP time stamp, big-endian.
+                        * S/3x0 and z/Architecture TOD clock time stamp,
+                        * little-endian.
+                        * Only supported for absolute times.
                         */
+                       DISSECTOR_ASSERT(!is_relative);
 
-#define NTP_BASETIME_ZERO G_GUINT64_CONSTANT(0)
+                       if (length == 8) {
+                               todsecs  = tvb_get_letoh64(tvb, start) >> 12 ;
+                               time_stamp->secs = (time_t)((todsecs  / 1000000) - TOD_BASETIME);
+                               time_stamp->nsecs = (int)((todsecs  % 1000000) * 1000);
+                       } else
+                               report_type_length_mismatch(tree, "a TOD clock time stamp", length, TRUE);
+                       break;
 
-                       tmpsecs  = tvb_get_ntohl(tvb, start);
-                       if (tmpsecs)
-                               time_stamp->secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME_ZERO);
-                       else
-                               time_stamp->secs = tmpsecs; /* 0 */
+               case ENC_TIME_RTPS|ENC_BIG_ENDIAN:
+                       /*
+                        * Time stamp using the same seconds/fraction format
+                        * as NTP, but with the origin of the time stamp being
+                        * the UNIX epoch rather than the NTP epoch; big-
+                        * endian.
+                        *
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
 
                        if (length == 8) {
+                               time_stamp->secs = (time_t)tvb_get_ntohl(tvb, start);
                                /*
-                                * We're using nanoseconds here (and we will
-                                * display nanoseconds), but NTP's timestamps
-                                * have a precision in microseconds or greater.
-                                * Round to 1 microsecond.
+                                * Convert 1/2^32s of a second to nanoseconds.
                                 */
-                               time_stamp->nsecs = (int)(1000000*(tvb_get_ntohl(tvb, start+4)/4294967296.0));
-                               time_stamp->nsecs *= 1000;
-                       } else {
+                               time_stamp->nsecs = (int)(1000000000*(tvb_get_ntohl(tvb, start+4)/4294967296.0));
+                       } else
+                               report_type_length_mismatch(tree, "an RTPS time stamp", length, TRUE);
+                       break;
+
+               case ENC_TIME_RTPS|ENC_LITTLE_ENDIAN:
+                       /*
+                        * Time stamp using the same seconds/fraction format
+                        * as NTP, but with the origin of the time stamp being
+                        * the UNIX epoch rather than the NTP epoch; little-
+                        * endian.
+                        *
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
+
+                       if (length == 8) {
+                               time_stamp->secs = (time_t)tvb_get_letohl(tvb, start);
+                               /*
+                                * Convert 1/2^32s of a second to nanoseconds.
+                                */
+                               time_stamp->nsecs = (int)(1000000000*(tvb_get_letohl(tvb, start+4)/4294967296.0));
+                       } else
+                               report_type_length_mismatch(tree, "an RTPS time stamp", length, TRUE);
+                       break;
+
+               case ENC_TIME_TIMEVAL|ENC_BIG_ENDIAN:
+                       /*
+                        * 4-byte seconds, followed by 4-byte fractional
+                        * time in microseconds, both big-endian.
+                        * For absolute times, the seconds are seconds
+                        * since the UN*X epoch.
+                        */
+                       if (length == 8) {
+                               time_stamp->secs  = (time_t)tvb_get_ntohl(tvb, start);
+                               time_stamp->nsecs = tvb_get_ntohl(tvb, start+4)*1000;
+                       } else
+                               report_type_length_mismatch(tree, "a timeval", length, TRUE);
+                       break;
+
+               case ENC_TIME_TIMEVAL|ENC_LITTLE_ENDIAN:
+                       /*
+                        * 4-byte seconds, followed by 4-byte fractional
+                        * time in microseconds, both little-endian.
+                        * For absolute times, the seconds are seconds
+                        * since the UN*X epoch.
+                        */
+                       if (length == 8) {
+                               time_stamp->secs  = (time_t)tvb_get_letohl(tvb, start);
+                               time_stamp->nsecs = tvb_get_letohl(tvb, start+4)*1000;
+                       } else
+                               report_type_length_mismatch(tree, "a timeval", length, TRUE);
+                       break;
+
+               case ENC_TIME_SECS|ENC_BIG_ENDIAN:
+               case ENC_TIME_SECS|ENC_LITTLE_ENDIAN:
+                       /*
+                        * Seconds, 1 to 8 bytes.
+                        * For absolute times, it's seconds since the
+                        * UN*X epoch.
+                        */
+                       if (length >= 1 && length <= 8) {
+                               time_stamp->secs  = (time_t)get_uint64_value(tree, tvb, start, length, encoding);
                                time_stamp->nsecs = 0;
-                       }
+                       } else
+                               report_type_length_mismatch(tree, "a time-in-seconds time stamp", length, TRUE);
                        break;
 
-               case ENC_TIME_NTP_BASE_ZERO|ENC_LITTLE_ENDIAN:
+               case ENC_TIME_MSECS|ENC_BIG_ENDIAN:
                        /*
-                        * NTP time stamp, big-endian.
+                        * Milliseconds, 1 to 8 bytes.
+                        * For absolute times, it's milliseconds since the
+                        * UN*X epoch.
                         */
-                       tmpsecs  = tvb_get_letohl(tvb, start);
-                       if (tmpsecs)
-                               time_stamp->secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME_ZERO);
-                       else
-                               time_stamp->secs = tmpsecs; /* 0 */
-                                               time_stamp->secs  = (time_t)tvb_get_letohl(tvb, start);
+                       if (length >= 1 && length <= 8) {
+                               guint64 msecs;
+
+                               msecs = get_uint64_value(tree, tvb, start, length, encoding);
+                               time_stamp->secs  = (time_t)(msecs / 1000);
+                               time_stamp->nsecs = (int)(msecs % 1000)*1000000;
+                       } else
+                               report_type_length_mismatch(tree, "a time-in-milliseconds time stamp", length, TRUE);
+                       break;
+
+               case ENC_TIME_RFC_3971|ENC_BIG_ENDIAN:
+                       /*
+                        * 1/64ths of a second since the UN*X epoch,
+                        * big-endian.
+                        *
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
+
                        if (length == 8) {
                                /*
-                                * We're using nanoseconds here (and we will
-                                * display nanoseconds), but NTP's timestamps
-                                * have a precision in microseconds or greater.
-                                * Round to 1 microsecond.
+                                * The upper 48 bits are seconds since the
+                                * UN*X epoch.
                                 */
-                               time_stamp->nsecs = (int)(1000000*(tvb_get_letohl(tvb, start+4)/4294967296.0));
-                               time_stamp->nsecs *= 1000;
-                       } else {
+                               time_stamp->secs  = tvb_get_ntoh48(tvb, start);
+                               /*
+                                * The lower 16 bits are 1/2^16s of a second;
+                                * convert them to nanoseconds.
+                                *
+                                * XXX - this may give the impression of higher
+                                * precision than you actually get.
+                                */
+                               time_stamp->nsecs = (int)(1000000000*(tvb_get_ntohs(tvb, start+6)/65536.0));
+                       } else
+                               report_type_length_mismatch(tree, "an RFC 3971-style time stamp", length, TRUE);
+                       break;
+
+               case ENC_TIME_RFC_3971|ENC_LITTLE_ENDIAN:
+                       /*
+                        * 1/64ths of a second since the UN*X epoch,
+                        * little-endian.
+                        *
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
+
+                       if (length == 8) {
+                               /*
+                                * XXX - this is assuming that, if anybody
+                                * were ever to use this format - RFC 3971
+                                * doesn't, because that's an Internet
+                                * protocol, and those use network byte
+                                * order, i.e. big-endian - they'd treat it
+                                * as a 64-bit count of 1/2^16s of a second,
+                                * putting the upper 48 bits at the end.
+                                *
+                                * The lower 48 bits are seconds since the
+                                * UN*X epoch.
+                                */
+                               time_stamp->secs  = tvb_get_letoh48(tvb, start+2);
+                               /*
+                                * The upper 16 bits are 1/2^16s of a second;
+                                * convert them to nanoseconds.
+                                *
+                                * XXX - this may give the impression of higher
+                                * precision than you actually get.
+                                */
+                               time_stamp->nsecs = (int)(1000000000*(tvb_get_letohs(tvb, start)/65536.0));
+                       } else
+                               report_type_length_mismatch(tree, "an RFC 3971-style time stamp", length, TRUE);
+                       break;
+
+               case ENC_TIME_SECS_NTP|ENC_BIG_ENDIAN:
+                       /*
+                        * NTP time stamp, with 1-second resolution (i.e.,
+                        * seconds since the NTP epoch), big-endian.
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
+
+                       if (length == 4) {
+                               /*
+                                * We need a temporary variable here so the
+                                * unsigned math works correctly (for
+                                * years > 2036 according to RFC 2030
+                                * chapter 3).
+                                */
+                               tmpsecs  = tvb_get_ntohl(tvb, start);
+                               if (tmpsecs)
+                                       time_stamp->secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME);
+                               else
+                                       time_stamp->secs = tmpsecs; /* 0 */
                                time_stamp->nsecs = 0;
-                       }
+                       } else
+                               report_type_length_mismatch(tree, "an NTP seconds-only time stamp", length, TRUE);
                        break;
 
+               case ENC_TIME_SECS_NTP|ENC_LITTLE_ENDIAN:
+                       /*
+                        * NTP time stamp, with 1-second resolution (i.e.,
+                        * seconds since the NTP epoch), little-endian.
+                        * Only supported for absolute times.
+                        */
+                       DISSECTOR_ASSERT(!is_relative);
+
+                       if (length == 4) {
+                               tmpsecs  = tvb_get_letohl(tvb, start);
+                               if (tmpsecs)
+                                       time_stamp->secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME);
+                               else
+                                       time_stamp->secs = tmpsecs; /* 0 */
+                               time_stamp->nsecs = 0;
+                       } else
+                               report_type_length_mismatch(tree, "an NTP seconds-only time stamp", length, TRUE);
+                       break;
+               case ENC_TIME_MSEC_NTP | ENC_BIG_ENDIAN:
+                       /*
+                       * Milliseconds, 1 to 8 bytes.
+                       * For absolute times, it's milliseconds since the
+                       * NTP epoch.
+                       */
+                       if (length >= 1 && length <= 8) {
+                               guint64 msecs;
+
+                               msecs = get_uint64_value(tree, tvb, start, length, encoding);
+                               tmpsecs = (guint32)(msecs / 1000);
+                               time_stamp->secs = (time_t)(tmpsecs - (guint32)NTP_BASETIME);
+                               time_stamp->nsecs = (int)(msecs % 1000)*1000000;
+                       }
+                       else
+                               report_type_length_mismatch(tree, "a time-in-milliseconds NTP time stamp", length, TRUE);
+                       break;
                default:
                        DISSECTOR_ASSERT_NOT_REACHED();
                        break;
@@ -1863,6 +2039,32 @@ tree_data_add_maybe_interesting_field(tree_data_t *tree_data, field_info *fi)
        }
 }
 
+
+/*
+ * Validates that field length bytes are available starting from
+ * start (pos/neg). Throws an exception if they aren't.
+ */
+static void
+test_length(header_field_info *hfinfo, tvbuff_t *tvb,
+           gint start, gint length, const guint encoding)
+{
+       gint size = length;
+
+       if (!tvb)
+               return;
+
+       if ((hfinfo->type == FT_STRINGZ) ||
+               ((encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) && (IS_FT_UINT(hfinfo->type) ||  IS_FT_UINT(hfinfo->type)))) {
+               /* If we're fetching until the end of the TVB, only validate
+                * that the offset is within range.
+                */
+               if (length == -1)
+                       size = 0;
+       }
+
+       tvb_ensure_bytes_exist(tvb, start, size);
+}
+
 /* Add an item to a proto_tree, using the text label registered to that item;
    the item is extracted from the tvbuff handed to it. */
 static proto_item *
@@ -1872,6 +2074,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
 {
        proto_item *pi;
        guint32     value, n;
+       guint64     value64;
        float       floatval;
        double      doubleval;
        const char *stringval;
@@ -1892,12 +2095,6 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        break;
 
                case FT_UINT_BYTES:
-                       /*
-                        * Map all non-zero values to little-endian for
-                        * backwards compatibility.
-                        */
-                       if (encoding)
-                               encoding = ENC_LITTLE_ENDIAN;
                        n = get_uint_value(tree, tvb, start, length, encoding);
                        proto_tree_set_bytes_tvb(new_fi, tvb, start + length, n);
 
@@ -1923,28 +2120,47 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                case FT_UINT16:
                case FT_UINT24:
                case FT_UINT32:
-                       /*
-                        * Map all non-zero values to little-endian for
-                        * backwards compatibility.
-                        */
-                       if (encoding)
-                               encoding = ENC_LITTLE_ENDIAN;
-                       proto_tree_set_uint(new_fi,
-                               get_uint_value(tree, tvb, start, length, encoding));
+                       if (encoding & ENC_VARINT_PROTOBUF) {
+                               new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding);
+                               new_fi->flags |= FI_VARINT;
+                               value = (guint32)value64;
+                       } else if (encoding & ENC_VARINT_QUIC) {
+                               new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding);
+                               value = (guint32)value64;
+                       } else {
+                               /*
+                                * Map all non-zero values to little-endian for
+                                * backwards compatibility.
+                                */
+                               if (encoding)
+                                       encoding = ENC_LITTLE_ENDIAN;
+
+                               value = get_uint_value(tree, tvb, start, length, encoding);
+                       }
+                       proto_tree_set_uint(new_fi, value);
                        break;
 
                case FT_UINT40:
                case FT_UINT48:
                case FT_UINT56:
                case FT_UINT64:
-                       /*
-                        * Map all non-zero values to little-endian for
-                        * backwards compatibility.
-                        */
-                       if (encoding)
-                               encoding = ENC_LITTLE_ENDIAN;
-                       proto_tree_set_uint64(new_fi,
-                               get_uint64_value(tree, tvb, start, length, encoding));
+
+                       if (encoding & ENC_VARINT_PROTOBUF) {
+                               new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding);
+                               new_fi->flags |= FI_VARINT;
+                       } else if (encoding & ENC_VARINT_QUIC) {
+                               new_fi->length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value64, encoding);
+                       } else {
+                               /*
+                                * Map all other non-zero values to little-endian for
+                                * backwards compatibility.
+                                */
+                               if (encoding)
+                                       encoding = ENC_LITTLE_ENDIAN;
+
+                               value64 = get_uint64_value(tree, tvb, start, length, encoding);
+                       }
+                       proto_tree_set_uint64(new_fi, value64);
                        break;
 
                /* XXX - make these just FT_INT? */
@@ -2237,125 +2453,534 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        if (encoding == TRUE)
                                encoding = ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN;
 
-                       if (length != 8 && length != 4) {
-                               length_error = length < 4 ? TRUE : FALSE;
-                               report_type_length_mismatch(tree, "an absolute time value", length, length_error);
-                       }
+                       if (length > 8 || length < 4) {
+                               length_error = length < 4 ? TRUE : FALSE;
+                               report_type_length_mismatch(tree, "an absolute time value", length, length_error);
+                       }
+
+                       get_time_value(tree, tvb, start, length, encoding, &time_stamp, FALSE);
+
+                       proto_tree_set_time(new_fi, &time_stamp);
+                       break;
+
+               case FT_RELATIVE_TIME:
+                       /*
+                        * Relative times can be in any of a number of
+                        * formats, and they can be big-endian or
+                        * little-endian.
+                        *
+                        * Historically FT_TIMEs were only timespecs;
+                        * the only question was whether they were stored
+                        * in big- or little-endian format.
+                        *
+                        * For backwards compatibility, we interpret an
+                        * encoding of 1 as meaning "little-endian timespec",
+                        * so that passing TRUE is interpreted as that.
+                        */
+                       if (encoding == TRUE)
+                               encoding = ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN;
+
+                       if (length != 8 && length != 4) {
+                               length_error = length < 4 ? TRUE : FALSE;
+                               report_type_length_mismatch(tree, "a relative time value", length, length_error);
+                       }
+
+                       get_time_value(tree, tvb, start, length, encoding, &time_stamp, TRUE);
+
+                       proto_tree_set_time(new_fi, &time_stamp);
+                       break;
+               case FT_IEEE_11073_SFLOAT:
+                       if (encoding)
+                               encoding = ENC_LITTLE_ENDIAN;
+                       if (length != 2) {
+                               length_error = length < 2 ? TRUE : FALSE;
+                               report_type_length_mismatch(tree, "a IEEE 11073 SFLOAT", length, length_error);
+                       }
+
+                       fvalue_set_uinteger(&new_fi->value, tvb_get_guint16(tvb, start, encoding));
+
+                       break;
+               case FT_IEEE_11073_FLOAT:
+                       if (encoding)
+                               encoding = ENC_LITTLE_ENDIAN;
+                       if (length != 4) {
+                               length_error = length < 4 ? TRUE : FALSE;
+                               report_type_length_mismatch(tree, "a IEEE 11073 FLOAT", length, length_error);
+                       }
+
+                       break;
+               default:
+                       g_error("new_fi->hfinfo->type %d (%s) not handled\n",
+                                       new_fi->hfinfo->type,
+                                       ftype_name(new_fi->hfinfo->type));
+                       DISSECTOR_ASSERT_NOT_REACHED();
+                       break;
+       }
+       FI_SET_FLAG(new_fi, (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN);
+
+       /* Don't add new node to proto_tree until now so that any exceptions
+        * raised by a tvbuff access method doesn't leave junk in the proto_tree. */
+       /* XXX. wouldn't be better to add this item to tree, with some special flag (FI_EXCEPTION?)
+        *      to know which item caused exception? */
+       pi = proto_tree_add_node(tree, new_fi);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_item_ret_int(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+                            const gint start, gint length,
+                            const guint encoding, gint32 *retval)
+{
+       header_field_info *hfinfo = proto_registrar_get_nth(hfindex);
+       field_info        *new_fi;
+       gint32             value;
+
+       DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
+
+       switch (hfinfo->type) {
+       case FT_INT8:
+       case FT_INT16:
+       case FT_INT24:
+       case FT_INT32:
+               break;
+       default:
+               DISSECTOR_ASSERT_NOT_REACHED();
+       }
+
+       /* length validation for native number encoding caught by get_uint_value() */
+       /* length has to be -1 or > 0 regardless of encoding */
+       if (length < -1 || length == 0)
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                       "Invalid length %d passed to proto_tree_add_item_ret_int",
+                       length));
+
+       if (encoding & ENC_STRING) {
+               REPORT_DISSECTOR_BUG("wrong encoding");
+       }
+       /* I believe it's ok if this is called with a NULL tree */
+       value = get_int_value(tree, tvb, start, length, encoding);
+
+       if (retval) {
+               gint no_of_bits;
+               *retval = value;
+               if (hfinfo->bitmask) {
+                       /* Mask out irrelevant portions */
+                       *retval &= (guint32)(hfinfo->bitmask);
+                       /* Shift bits */
+                       *retval >>= hfinfo_bitshift(hfinfo);
+               }
+               no_of_bits = ws_count_ones(hfinfo->bitmask);
+               *retval = ws_sign_ext32(*retval, no_of_bits);
+       }
+
+       CHECK_FOR_NULL_TREE(tree);
+
+       TRY_TO_FAKE_THIS_ITEM(tree, hfinfo->id, hfinfo);
+
+       new_fi = new_field_info(tree, hfinfo, tvb, start, length);
+
+       proto_tree_set_int(new_fi, value);
+
+       new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
+
+       return proto_tree_add_node(tree, new_fi);
+}
+
+proto_item *
+proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+                             const gint start, gint length,
+                             const guint encoding, guint32 *retval)
+{
+       header_field_info *hfinfo = proto_registrar_get_nth(hfindex);
+       field_info        *new_fi;
+       guint32            value;
+
+       DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
+
+       switch (hfinfo->type) {
+       case FT_CHAR:
+       case FT_UINT8:
+       case FT_UINT16:
+       case FT_UINT24:
+       case FT_UINT32:
+               break;
+       default:
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_CHAR, FT_UINT8, FT_UINT16, FT_UINT24, or FT_UINT32",
+                   hfinfo->abbrev));
+       }
+
+       /* length validation for native number encoding caught by get_uint_value() */
+       /* length has to be -1 or > 0 regardless of encoding */
+       if (length < -1 || length == 0)
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                       "Invalid length %d passed to proto_tree_add_item_ret_uint",
+                       length));
+
+       if (encoding & ENC_STRING) {
+               REPORT_DISSECTOR_BUG("wrong encoding");
+       }
+       /* I believe it's ok if this is called with a NULL tree */
+       /* XXX - modify if we ever support EBCDIC FT_CHAR */
+       if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) {
+               guint64 temp64;
+               tvb_get_varint(tvb, start, length, &temp64, encoding);
+               value = (guint32)temp64;
+       } else {
+               value = get_uint_value(tree, tvb, start, length, encoding);
+       }
+
+       if (retval) {
+               *retval = value;
+               if (hfinfo->bitmask) {
+                       /* Mask out irrelevant portions */
+                       *retval &= (guint32)(hfinfo->bitmask);
+                       /* Shift bits */
+                       *retval >>= hfinfo_bitshift(hfinfo);
+               }
+       }
+
+       CHECK_FOR_NULL_TREE(tree);
+
+       TRY_TO_FAKE_THIS_ITEM(tree, hfinfo->id, hfinfo);
+
+       new_fi = new_field_info(tree, hfinfo, tvb, start, length);
+
+       proto_tree_set_uint(new_fi, value);
+
+       new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
+       if (encoding & ENC_VARINT_PROTOBUF) {
+               new_fi->flags |= FI_VARINT;
+       }
+       return proto_tree_add_node(tree, new_fi);
+}
+
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+ * and returns proto_item* and uint value retreived*/
+proto_item *
+ptvcursor_add_ret_uint(ptvcursor_t *ptvc, int hfindex, gint length,
+             const guint encoding, guint32 *retval)
+{
+       field_info        *new_fi;
+       header_field_info *hfinfo;
+       gint               item_length;
+       int                offset;
+       guint32            value;
+
+       offset = ptvc->offset;
+       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
+
+       switch (hfinfo->type) {
+       case FT_CHAR:
+       case FT_UINT8:
+       case FT_UINT16:
+       case FT_UINT24:
+       case FT_UINT32:
+               break;
+       default:
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_CHAR, FT_UINT8, FT_UINT16, FT_UINT24, or FT_UINT32",
+                   hfinfo->abbrev));
+       }
+
+       get_hfi_length(hfinfo, ptvc->tvb, offset, &length, &item_length, encoding);
+       test_length(hfinfo, ptvc->tvb, offset, item_length, encoding);
+
+       /* I believe it's ok if this is called with a NULL tree */
+       /* XXX - modify if we ever support EBCDIC FT_CHAR */
+       value = get_uint_value(ptvc->tree, ptvc->tvb, offset, item_length, encoding);
+
+       if (retval) {
+               *retval = value;
+               if (hfinfo->bitmask) {
+                       /* Mask out irrelevant portions */
+                       *retval &= (guint32)(hfinfo->bitmask);
+                       /* Shift bits */
+                       *retval >>= hfinfo_bitshift(hfinfo);
+               }
+       }
+
+       ptvc->offset += get_full_length(hfinfo, ptvc->tvb, offset, length,
+           item_length, encoding);
+
+       CHECK_FOR_NULL_TREE(ptvc->tree);
+
+       /* Coast clear. Try and fake it */
+       TRY_TO_FAKE_THIS_ITEM(ptvc->tree, hfindex, hfinfo);
+
+       new_fi = new_field_info(ptvc->tree, hfinfo, ptvc->tvb, offset, item_length);
+
+       return proto_tree_new_item(new_fi, ptvc->tree, ptvc->tvb,
+               offset, length, encoding);
+}
+
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+ * and returns proto_item* and int value retreived*/
+proto_item *
+ptvcursor_add_ret_int(ptvcursor_t *ptvc, int hfindex, gint length,
+             const guint encoding, gint32 *retval)
+{
+       field_info        *new_fi;
+       header_field_info *hfinfo;
+       gint               item_length;
+       int                offset;
+       guint32            value;
+
+       offset = ptvc->offset;
+       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
+
+       switch (hfinfo->type) {
+       case FT_INT8:
+       case FT_INT16:
+       case FT_INT24:
+       case FT_INT32:
+               break;
+       default:
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_CHAR, FT_UINT8, FT_UINT16, FT_UINT24, or FT_UINT32",
+                   hfinfo->abbrev));
+       }
+
+       get_hfi_length(hfinfo, ptvc->tvb, offset, &length, &item_length, encoding);
+       test_length(hfinfo, ptvc->tvb, offset, item_length, encoding);
+
+       /* I believe it's ok if this is called with a NULL tree */
+       /* XXX - modify if we ever support EBCDIC FT_CHAR */
+       value = get_int_value(ptvc->tree, ptvc->tvb, offset, item_length, encoding);
+
+       if (retval) {
+               gint no_of_bits;
+               *retval = value;
+               if (hfinfo->bitmask) {
+                       /* Mask out irrelevant portions */
+                       *retval &= (guint32)(hfinfo->bitmask);
+                       /* Shift bits */
+                       *retval >>= hfinfo_bitshift(hfinfo);
+               }
+               no_of_bits = ws_count_ones(hfinfo->bitmask);
+               *retval = ws_sign_ext32(*retval, no_of_bits);
+       }
+
+       ptvc->offset += get_full_length(hfinfo, ptvc->tvb, offset, length,
+           item_length, encoding);
+
+       CHECK_FOR_NULL_TREE(ptvc->tree);
+
+       /* Coast clear. Try and fake it */
+       TRY_TO_FAKE_THIS_ITEM(ptvc->tree, hfindex, hfinfo);
+
+       new_fi = new_field_info(ptvc->tree, hfinfo, ptvc->tvb, offset, item_length);
+
+       return proto_tree_new_item(new_fi, ptvc->tree, ptvc->tvb,
+               offset, length, encoding);
+}
+
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+ * and returns proto_item* and string value retreived */
+proto_item*
+ptvcursor_add_ret_string(ptvcursor_t* ptvc, int hf, gint length, const guint encoding, wmem_allocator_t *scope, const guint8 **retval)
+{
+       header_field_info *hfinfo;
+       field_info              *new_fi;
+       const guint8    *value;
+       gint                    item_length;
+       int                             offset;
+
+       offset = ptvc->offset;
+
+       PROTO_REGISTRAR_GET_NTH(hf, hfinfo);
+
+       switch (hfinfo->type) {
+       case FT_STRING:
+               value = get_string_value(scope, ptvc->tvb, offset, length, &item_length, encoding);
+               break;
+       case FT_STRINGZ:
+               value = get_stringz_value(scope, ptvc->tree, ptvc->tvb, offset, length, &item_length, encoding);
+               break;
+       case FT_UINT_STRING:
+               value = get_uint_string_value(scope, ptvc->tree, ptvc->tvb, offset, length, &item_length, encoding);
+               break;
+       case FT_STRINGZPAD:
+               value = get_stringzpad_value(scope, ptvc->tvb, offset, length, &item_length, encoding);
+               break;
+       default:
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_STRING, FT_STRINGZ, FT_UINT_STRING, or FT_STRINGZPAD",
+                   hfinfo->abbrev));
+       }
+
+       if (retval)
+               *retval = value;
+
+       ptvc->offset += item_length;
+
+       CHECK_FOR_NULL_TREE(ptvc->tree);
+
+       TRY_TO_FAKE_THIS_ITEM(ptvc->tree, hfinfo->id, hfinfo);
+
+       new_fi = new_field_info(ptvc->tree, hfinfo, ptvc->tvb, offset, item_length);
+
+       return proto_tree_new_item(new_fi, ptvc->tree, ptvc->tvb,
+               offset, length, encoding);
+}
+
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+ * and returns proto_item* and boolean value retreived */
+proto_item*
+ptvcursor_add_ret_boolean(ptvcursor_t* ptvc, int hfindex, gint length, const guint encoding, gboolean *retval)
+{
+       header_field_info *hfinfo;
+       field_info              *new_fi;
+       gint                    item_length;
+       int                             offset;
+       guint64                 value, bitval;
+
+       offset = ptvc->offset;
+       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
+
+       if (hfinfo->type != FT_BOOLEAN) {
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_BOOLEAN", hfinfo->abbrev));
+       }
+
+       /* length validation for native number encoding caught by get_uint64_value() */
+       /* length has to be -1 or > 0 regardless of encoding */
+       if (length < -1 || length == 0)
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                       "Invalid length %d passed to proto_tree_add_item_ret_uint",
+                       length));
+
+       if (encoding & ENC_STRING) {
+               REPORT_DISSECTOR_BUG("wrong encoding");
+       }
+
+       get_hfi_length(hfinfo, ptvc->tvb, offset, &length, &item_length, encoding);
+       test_length(hfinfo, ptvc->tvb, offset, item_length, encoding);
+
+       /* I believe it's ok if this is called with a NULL tree */
+       value = get_uint64_value(ptvc->tree, ptvc->tvb, offset, length, encoding);
+
+       if (retval) {
+               bitval = value;
+               if (hfinfo->bitmask) {
+                       /* Mask out irrelevant portions */
+                       bitval &= hfinfo->bitmask;
+               }
+               *retval = (bitval != 0);
+       }
+
+       ptvc->offset += get_full_length(hfinfo, ptvc->tvb, offset, length,
+           item_length, encoding);
+
+       CHECK_FOR_NULL_TREE(ptvc->tree);
+
+       TRY_TO_FAKE_THIS_ITEM(ptvc->tree, hfinfo->id, hfinfo);
+
+       new_fi = new_field_info(ptvc->tree, hfinfo, ptvc->tvb, offset, item_length);
+
+       return proto_tree_new_item(new_fi, ptvc->tree, ptvc->tvb,
+               offset, length, encoding);
+}
+
+proto_item *
+proto_tree_add_item_ret_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+    const gint start, gint length, const guint encoding, guint64 *retval)
+{
+       header_field_info *hfinfo = proto_registrar_get_nth(hfindex);
+       field_info        *new_fi;
+       guint64            value;
+
+       DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
 
-                       get_time_value(tvb, start, length, encoding, &time_stamp, FALSE);
+       if (hfinfo->type != FT_UINT64) {
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_UINT64", hfinfo->abbrev));
+       }
 
-                       proto_tree_set_time(new_fi, &time_stamp);
-                       break;
+       /* length validation for native number encoding caught by get_uint64_value() */
+       /* length has to be -1 or > 0 regardless of encoding */
+       if (length < -1 || length == 0)
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                       "Invalid length %d passed to proto_tree_add_item_ret_uint",
+                       length));
 
-               case FT_RELATIVE_TIME:
-                       /*
-                        * Relative times can be in any of a number of
-                        * formats, and they can be big-endian or
-                        * little-endian.
-                        *
-                        * Historically FT_TIMEs were only timespecs;
-                        * the only question was whether they were stored
-                        * in big- or little-endian format.
-                        *
-                        * For backwards compatibility, we interpret an
-                        * encoding of 1 as meaning "little-endian timespec",
-                        * so that passing TRUE is interpreted as that.
-                        */
-                       if (encoding == TRUE)
-                               encoding = ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN;
+       if (encoding & ENC_STRING) {
+               REPORT_DISSECTOR_BUG("wrong encoding");
+       }
+       /* I believe it's ok if this is called with a NULL tree */
+       if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) {
+               tvb_get_varint(tvb, start, length, &value, encoding);
+       } else {
+               value = get_uint64_value(tree, tvb, start, length, encoding);
+       }
 
-                       if (length != 8 && length != 4) {
-                               length_error = length < 4 ? TRUE : FALSE;
-                               report_type_length_mismatch(tree, "a relative time value", length, length_error);
-                       }
+       if (retval) {
+               *retval = value;
+               if (hfinfo->bitmask) {
+                       /* Mask out irrelevant portions */
+                       *retval &= hfinfo->bitmask;
+                       /* Shift bits */
+                       *retval >>= hfinfo_bitshift(hfinfo);
+               }
+       }
 
-                       get_time_value(tvb, start, length, encoding, &time_stamp, TRUE);
+       CHECK_FOR_NULL_TREE(tree);
 
-                       proto_tree_set_time(new_fi, &time_stamp);
-                       break;
-               case FT_IEEE_11073_SFLOAT:
-                       if (encoding)
-                               encoding = ENC_LITTLE_ENDIAN;
-                       if (length != 2) {
-                               length_error = length < 2 ? TRUE : FALSE;
-                               report_type_length_mismatch(tree, "a IEEE 11073 SFLOAT", length, length_error);
-                       }
+       TRY_TO_FAKE_THIS_ITEM(tree, hfinfo->id, hfinfo);
 
-                       fvalue_set_uinteger(&new_fi->value, tvb_get_guint16(tvb, start, encoding));
+       new_fi = new_field_info(tree, hfinfo, tvb, start, length);
 
-                       break;
-               case FT_IEEE_11073_FLOAT:
-                       if (encoding)
-                               encoding = ENC_LITTLE_ENDIAN;
-                       if (length != 4) {
-                               length_error = length < 4 ? TRUE : FALSE;
-                               report_type_length_mismatch(tree, "a IEEE 11073 FLOAT", length, length_error);
-                       }
+       proto_tree_set_uint64(new_fi, value);
 
-                       break;
-               default:
-                       g_error("new_fi->hfinfo->type %d (%s) not handled\n",
-                                       new_fi->hfinfo->type,
-                                       ftype_name(new_fi->hfinfo->type));
-                       DISSECTOR_ASSERT_NOT_REACHED();
-                       break;
+       new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
+       if (encoding & ENC_VARINT_PROTOBUF) {
+               new_fi->flags |= FI_VARINT;
        }
-       FI_SET_FLAG(new_fi, (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN);
-
-       /* Don't add new node to proto_tree until now so that any exceptions
-        * raised by a tvbuff access method doesn't leave junk in the proto_tree. */
-       /* XXX. wouldn't be better to add this item to tree, with some special flag (FI_EXCEPTION?)
-        *      to know which item caused exception? */
-       pi = proto_tree_add_node(tree, new_fi);
 
-       return pi;
+       return proto_tree_add_node(tree, new_fi);
 }
 
 proto_item *
-proto_tree_add_item_ret_int(proto_tree *tree, int hfindex, tvbuff_t *tvb,
-                            const gint start, gint length,
-                            const guint encoding, gint32 *retval)
+proto_tree_add_item_ret_varint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+    const gint start, gint length, const guint encoding, guint64 *retval, gint *lenretval)
 {
        header_field_info *hfinfo = proto_registrar_get_nth(hfindex);
-       field_info        *new_fi;
-       gint32             value;
+       field_info      *new_fi;
+       guint64         value;
 
        DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
 
-       switch (hfinfo->type){
-       case FT_INT8:
-       case FT_INT16:
-       case FT_INT24:
-       case FT_INT32:
-               break;
-       default:
-               DISSECTOR_ASSERT_NOT_REACHED();
+       if ((!IS_FT_INT(hfinfo->type)) && (!IS_FT_UINT(hfinfo->type))) {
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                       "field %s is not of type FT_UINT or FT_INT", hfinfo->abbrev));
        }
 
-       /* length validation for native number encoding caught by get_uint_value() */
+       /* length validation for native number encoding caught by get_uint64_value() */
        /* length has to be -1 or > 0 regardless of encoding */
-       if (length < -1 || length == 0)
+       if (length == 0)
                REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
-                       "Invalid length %d passed to proto_tree_add_item_ret_int",
+                       "Invalid length %d passed to proto_tree_add_item_ret_varint",
                        length));
 
        if (encoding & ENC_STRING) {
                REPORT_DISSECTOR_BUG("wrong encoding");
        }
-       /* I believe it's ok if this is called with a NULL tree */
-       value = get_int_value(tree, tvb, start, length, encoding);
+
+       length = tvb_get_varint(tvb, start, (length == -1) ? FT_VARINT_MAX_LEN : length, &value, encoding);
 
        if (retval) {
-               gint no_of_bits;
                *retval = value;
                if (hfinfo->bitmask) {
                        /* Mask out irrelevant portions */
-                       *retval &= (guint32)(hfinfo->bitmask);
+                       *retval &= hfinfo->bitmask;
                        /* Shift bits */
                        *retval >>= hfinfo_bitshift(hfinfo);
                }
-               no_of_bits = ws_count_ones(hfinfo->bitmask);
-               *retval = ws_sign_ext32(*retval, no_of_bits);
+       }
+
+       if (lenretval) {
+               *lenretval = length;
        }
 
        CHECK_FOR_NULL_TREE(tree);
@@ -2364,36 +2989,34 @@ proto_tree_add_item_ret_int(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
        new_fi = new_field_info(tree, hfinfo, tvb, start, length);
 
-       proto_tree_set_int(new_fi, value);
+       proto_tree_set_uint64(new_fi, value);
 
        new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
+       if (encoding & ENC_VARINT_PROTOBUF) {
+               new_fi->flags |= FI_VARINT;
+       }
 
        return proto_tree_add_node(tree, new_fi);
+
 }
 
 proto_item *
-proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
-                             const gint start, gint length,
-                             const guint encoding, guint32 *retval)
+proto_tree_add_item_ret_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+                                const gint start, gint length,
+                                const guint encoding, gboolean *retval)
 {
        header_field_info *hfinfo = proto_registrar_get_nth(hfindex);
        field_info        *new_fi;
-       guint32            value;
+       guint64            value, bitval;
 
        DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
 
-       switch (hfinfo->type){
-       case FT_CHAR:
-       case FT_UINT8:
-       case FT_UINT16:
-       case FT_UINT24:
-       case FT_UINT32:
-               break;
-       default:
-               DISSECTOR_ASSERT_NOT_REACHED();
+       if (hfinfo->type != FT_BOOLEAN) {
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_BOOLEAN", hfinfo->abbrev));
        }
 
-       /* length validation for native number encoding caught by get_uint_value() */
+       /* length validation for native number encoding caught by get_uint64_value() */
        /* length has to be -1 or > 0 regardless of encoding */
        if (length < -1 || length == 0)
                REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
@@ -2404,17 +3027,15 @@ proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                REPORT_DISSECTOR_BUG("wrong encoding");
        }
        /* I believe it's ok if this is called with a NULL tree */
-       /* XXX - modify if we ever support EBCDIC FT_CHAR */
-       value = get_uint_value(tree, tvb, start, length, encoding);
+       value = get_uint64_value(tree, tvb, start, length, encoding);
 
        if (retval) {
-               *retval = value;
+               bitval = value;
                if (hfinfo->bitmask) {
                        /* Mask out irrelevant portions */
-                       *retval &= (guint32)(hfinfo->bitmask);
-                       /* Shift bits */
-                       *retval >>= hfinfo_bitshift(hfinfo);
+                       bitval &= hfinfo->bitmask;
                }
+               *retval = (bitval != 0);
        }
 
        CHECK_FOR_NULL_TREE(tree);
@@ -2423,7 +3044,7 @@ proto_tree_add_item_ret_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
        new_fi = new_field_info(tree, hfinfo, tvb, start, length);
 
-       proto_tree_set_uint(new_fi, value);
+       proto_tree_set_boolean(new_fi, value);
 
        new_fi->flags |= (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN;
 
@@ -2445,7 +3066,7 @@ proto_tree_add_item_ret_string_and_length(proto_tree *tree, int hfindex,
 
        DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
 
-       switch (hfinfo->type){
+       switch (hfinfo->type) {
        case FT_STRING:
                value = get_string_value(scope, tvb, start, length, lenretval, encoding);
                break;
@@ -2459,7 +3080,9 @@ proto_tree_add_item_ret_string_and_length(proto_tree *tree, int hfindex,
                value = get_stringzpad_value(scope, tvb, start, length, lenretval, encoding);
                break;
        default:
-               DISSECTOR_ASSERT_NOT_REACHED();
+               REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                   "field %s is not of type FT_STRING, FT_STRINGZ, FT_UINT_STRING, or FT_STRINGZPAD",
+                   hfinfo->abbrev));
        }
 
        if (retval)
@@ -2488,29 +3111,6 @@ proto_tree_add_item_ret_string(proto_tree *tree, int hfindex, tvbuff_t *tvb,
            tvb, start, length, encoding, scope, retval, &length);
 }
 
-/*
- * Validates that field length bytes are available starting from
- * start (pos/neg). Throws an exception if they aren't.
- */
-static void
-test_length(header_field_info *hfinfo, tvbuff_t *tvb,
-           gint start, gint length)
-{
-       gint size = length;
-
-       if (!tvb)
-               return;
-
-       if (hfinfo->type == FT_STRINGZ) {
-               /* If we're fetching until the end of the TVB, only validate
-                * that the offset is within range.
-                */
-               if (length == -1)
-                       size = 0;
-       }
-
-       tvb_ensure_bytes_exist(tvb, start, size);
-}
 
 /* Gets data from tvbuff, adds it to proto_tree, increments offset,
    and returns proto_item* */
@@ -2525,8 +3125,8 @@ ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
 
        offset = ptvc->offset;
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       get_hfi_length(hfinfo, ptvc->tvb, offset, &length, &item_length);
-       test_length(hfinfo, ptvc->tvb, offset, item_length);
+       get_hfi_length(hfinfo, ptvc->tvb, offset, &length, &item_length, encoding);
+       test_length(hfinfo, ptvc->tvb, offset, item_length, encoding);
 
        ptvc->offset += get_full_length(hfinfo, ptvc->tvb, offset, length,
            item_length, encoding);
@@ -2553,8 +3153,8 @@ 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, tvb, start, item_length);
+       get_hfi_length(hfinfo, tvb, start, &length, &item_length, encoding);
+       test_length(hfinfo, tvb, start, item_length, encoding);
 
        CHECK_FOR_NULL_TREE(tree);
 
@@ -2591,8 +3191,8 @@ proto_tree_add_item_new_ret_length(proto_tree *tree, header_field_info *hfinfo,
 
        DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!");
 
-       get_hfi_length(hfinfo, tvb, start, &length, &item_length);
-       test_length(hfinfo, tvb, start, item_length);
+       get_hfi_length(hfinfo, tvb, start, &length, &item_length, encoding);
+       test_length(hfinfo, tvb, start, item_length, encoding);
 
        if (!tree) {
                /*
@@ -2605,7 +3205,14 @@ proto_tree_add_item_new_ret_length(proto_tree *tree, header_field_info *hfinfo,
                return NULL;
        }
 
-       TRY_TO_FAKE_THIS_ITEM(tree, hfinfo->id, hfinfo);
+       TRY_TO_FAKE_THIS_ITEM_OR_FREE(tree, hfinfo->id, hfinfo, {
+               /*
+                * Even if the tree item is not referenced (and thus faked),
+                * the caller must still be informed of the actual length.
+                */
+               *lenretval = get_full_length(hfinfo, tvb, start, length,
+                   item_length, encoding);
+       });
 
        new_fi = new_field_info(tree, hfinfo, tvb, start, item_length);
 
@@ -2793,9 +3400,9 @@ proto_tree_add_time_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
        }
        else {
                const gboolean is_relative = (hfinfo->type == FT_RELATIVE_TIME) ? TRUE : FALSE;
+               const gboolean length_error = length < 4 ? TRUE : FALSE;
 
-               if (length != 8 && length != 4) {
-                       const gboolean length_error = length < 4 ? TRUE : FALSE;
+               if (length > 8 || length < 4) {
                        if (is_relative)
                            report_type_length_mismatch(tree, "a relative time value", length, length_error);
                        else
@@ -2803,7 +3410,7 @@ proto_tree_add_time_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                }
 
                tvb_ensure_bytes_exist(tvb, start, length);
-               get_time_value(tvb, start, length, encoding, &time_stamp, is_relative);
+               get_time_value(tree, tvb, start, length, encoding, &time_stamp, is_relative);
                if (endoff) *endoff = length;
        }
 
@@ -2936,8 +3543,8 @@ proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        gint              item_length;
 
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       get_hfi_length(hfinfo, tvb, start, &length, &item_length);
-       test_length(hfinfo, tvb, start, item_length);
+       get_hfi_length(hfinfo, tvb, start, &length, &item_length, ENC_NA);
+       test_length(hfinfo, tvb, start, item_length, ENC_NA);
 
        CHECK_FOR_NULL_TREE(tree);
 
@@ -2961,8 +3568,8 @@ proto_tree_add_bytes_with_length(proto_tree *tree, int hfindex, tvbuff_t *tvb, g
        gint          item_length;
 
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       get_hfi_length(hfinfo, tvb, start, &tvbuff_length, &item_length);
-       test_length(hfinfo, tvb, start, item_length);
+       get_hfi_length(hfinfo, tvb, start, &tvbuff_length, &item_length, ENC_NA);
+       test_length(hfinfo, tvb, start, item_length, ENC_NA);
 
        CHECK_FOR_NULL_TREE(tree);
 
@@ -2984,23 +3591,13 @@ proto_tree_add_bytes_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 {
        proto_item        *pi;
        va_list            ap;
-       header_field_info *hfinfo;
-       gint              item_length;
-
-       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       get_hfi_length(hfinfo, tvb, start, &length, &item_length);
-       test_length(hfinfo, tvb, start, item_length);
 
-       CHECK_FOR_NULL_TREE(tree);
+       if (start_ptr == NULL)
+               start_ptr = tvb_get_ptr(tvb, start, length);
 
-       TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hfinfo);
+       pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length, start_ptr);
 
-       if (start_ptr)
-               pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length,
-                                         start_ptr);
-       else
-               pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length,
-                                         tvb_get_ptr(tvb, start, length));
+       TRY_TO_FAKE_THIS_REPR_NESTED(pi);
 
        va_start(ap, format);
        proto_tree_set_representation_value(pi, format, ap);
@@ -3016,25 +3613,13 @@ proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 {
        proto_item        *pi;
        va_list            ap;
-       header_field_info *hfinfo;
-       gint              item_length;
-
-       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       get_hfi_length(hfinfo, tvb, start, &length, &item_length);
-       test_length(hfinfo, tvb, start, item_length);
-
-       CHECK_FOR_NULL_TREE(tree);
 
-       TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hfinfo);
+       if (start_ptr == NULL)
+               start_ptr = tvb_get_ptr(tvb, start, length);
 
-       if (start_ptr)
-               pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length,
-                                         start_ptr);
-       else
-               pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length,
-                                         tvb_get_ptr(tvb, start, length));
+       pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length, start_ptr);
 
-       TRY_TO_FAKE_THIS_REPR(pi);
+       TRY_TO_FAKE_THIS_REPR_NESTED(pi);
 
        va_start(ap, format);
        proto_tree_set_representation(pi, format, ap);
@@ -3276,7 +3861,7 @@ proto_tree_set_ipv4(field_info *fi, guint32 value)
 /* Add a FT_IPv6 to a proto_tree */
 proto_item *
 proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
-                   gint length, const struct e_in6_addr *value_ptr)
+                   gint length, const ws_in6_addr *value_ptr)
 {
        proto_item        *pi;
        header_field_info *hfinfo;
@@ -3296,7 +3881,7 @@ proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
 proto_item *
 proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                                 gint start, gint length,
-                                const struct e_in6_addr *value_ptr,
+                                const ws_in6_addr *value_ptr,
                                 const char *format, ...)
 {
        proto_item        *pi;
@@ -3315,7 +3900,7 @@ proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 proto_item *
 proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                           gint start, gint length,
-                          const struct e_in6_addr *value_ptr,
+                          const ws_in6_addr *value_ptr,
                           const char *format, ...)
 {
        proto_item        *pi;
@@ -3842,6 +4427,50 @@ decode_bitfield_value(char *buf, const guint64 val, const guint64 mask, const in
        return p;
 }
 
+static char *
+other_decode_bitfield_varint_value(char *buf, guint64 val, guint64 mask, const int width)
+{
+       int i = 0;
+       guint64 bit;
+       char *p;
+
+       p = buf;
+       bit = G_GUINT64_CONSTANT(1) << (width - 1);
+       for (;;) {
+               if (((8-(i % 8)) != 8) && /* MSB is never used for value. */
+                       (mask & bit)) {
+                       /* This bit is part of the field.  Show its value. */
+                       if (val & bit)
+                               *p++ = '1';
+                       else
+                               *p++ = '0';
+               } else {
+                       /* This bit is not part of the field. */
+                       *p++ = '.';
+               }
+               bit >>= 1;
+               i++;
+               if (i >= width)
+                       break;
+               if (i % 4 == 0)
+                       *p++ = ' ';
+       }
+
+       *p = '\0';
+       return p;
+}
+
+static char *
+decode_bitfield_varint_value(char *buf, const guint64 val, const guint64 mask, const int width)
+{
+       char *p;
+
+       p = other_decode_bitfield_varint_value(buf, val, mask, width);
+       p = g_stpcpy(p, " = ");
+
+       return p;
+}
+
 /* Add a FT_FLOAT to a proto_tree */
 proto_item *
 proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
@@ -3996,7 +4625,9 @@ proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                        break;
 
                default:
-                       DISSECTOR_ASSERT_NOT_REACHED();
+                       REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                           "field %s is not of type FT_CHAR, FT_UINT8, FT_UINT16, FT_UINT24, FT_UINT32, or FT_FRAMENUM",
+                           hfinfo->abbrev));
        }
 
        return pi;
@@ -4084,7 +4715,9 @@ proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                        break;
 
                default:
-                       DISSECTOR_ASSERT_NOT_REACHED();
+                       REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                           "field %s is not of type FT_UINT40, FT_UINT48, FT_UINT56, FT_UINT64, or FT_FRAMENUM",
+                           hfinfo->abbrev));
        }
 
        return pi;
@@ -4171,7 +4804,9 @@ proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                        break;
 
                default:
-                       DISSECTOR_ASSERT_NOT_REACHED();
+                       REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                           "field %s is not of type FT_INT8, FT_INT16, FT_INT24, or FT_INT32",
+                           hfinfo->abbrev));
        }
 
        return pi;
@@ -4262,7 +4897,9 @@ proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                        break;
 
                default:
-                       DISSECTOR_ASSERT_NOT_REACHED();
+                       REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
+                           "field %s is not of type FT_INT40, FT_INT48, FT_INT56, or FT_INT64",
+                           hfinfo->abbrev));
        }
 
        return pi;
@@ -4444,7 +5081,7 @@ proto_tree_add_node(proto_tree *tree, field_info *fi)
        tfi = PNODE_FINFO(tnode);
        if (tfi != NULL && (tfi->tree_type < 0 || tfi->tree_type >= num_tree_types)) {
                REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(),
-                                    "\"%s\" - \"%s\" tfi->tree_type: %u invalid (%s:%u)",
+                                    "\"%s\" - \"%s\" tfi->tree_type: %d invalid (%s:%u)",
                                     fi->hfinfo->name, fi->hfinfo->abbrev, tfi->tree_type, __FILE__, __LINE__));
                /* XXX - is it safe to continue here? */
        }
@@ -4479,7 +5116,7 @@ proto_tree_add_pi(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb, gi
        field_info *fi;
        gint            item_length;
 
-       get_hfi_length(hfinfo, tvb, start, length, &item_length);
+       get_hfi_length(hfinfo, tvb, start, length, &item_length, ENC_NA);
        fi = new_field_info(tree, hfinfo, tvb, start, item_length);
        pi = proto_tree_add_node(tree, fi);
 
@@ -4489,7 +5126,7 @@ proto_tree_add_pi(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb, gi
 
 static void
 get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint *length,
-                  gint *item_length)
+                  gint *item_length, const guint encoding)
 {
        gint length_remaining;
 
@@ -4542,6 +5179,9 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint
                 * of the string", and if the tvbuff if short, we just
                 * throw an exception.
                 *
+                * For ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC, it means "find the end of the string",
+                * and if the tvbuff if short, we just throw an exception.
+                *
                 * It's not valid for any other type of field.  For those
                 * fields, we treat -1 the same way we treat other
                 * negative values - we assume the length is a Really
@@ -4549,6 +5189,33 @@ get_hfi_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start, gint
                 * exception, under the assumption that the Really Big
                 * Length would run past the end of the packet.
                 */
+               if ((IS_FT_INT(hfinfo->type)) || (IS_FT_UINT(hfinfo->type))) {
+                       if (encoding & ENC_VARINT_PROTOBUF) {
+                               /*
+                                * Leave the length as -1, so our caller knows
+                                * it was -1.
+                                */
+                               *item_length = *length;
+                               return;
+                       } else if (encoding & ENC_VARINT_QUIC) {
+                               switch (tvb_get_guint8(tvb, start) >> 6)
+                               {
+                               case 0: /* 0b00 => 1 byte length (6 bits Usable) */
+                                       *item_length = 1;
+                                       break;
+                               case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
+                                       *item_length = 2;
+                                       break;
+                               case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
+                                       *item_length = 4;
+                                       break;
+                               case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
+                                       *item_length = 8;
+                                       break;
+                               }
+                       }
+               }
+
                switch (hfinfo->type) {
 
                case FT_PROTOCOL:
@@ -4637,17 +5304,10 @@ get_full_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start,
                break;
 
        case FT_UINT_BYTES:
-               /*
-                * Map all non-zero values to little-endian for
-                * backwards compatibility.
-                */
-               n = get_uint_value(NULL, tvb, start, length,
-                   encoding ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN);
+               n = get_uint_value(NULL, tvb, start, length, encoding);
                item_length += n;
                break;
 
-       case FT_BOOLEAN:
-       case FT_CHAR:
        /* XXX - make these just FT_UINT? */
        case FT_UINT8:
        case FT_UINT16:
@@ -4666,6 +5326,30 @@ get_full_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start,
        case FT_INT48:
        case FT_INT56:
        case FT_INT64:
+               if (encoding & (ENC_VARINT_PROTOBUF|ENC_VARINT_QUIC)) {
+                       if (length < -1) {
+                               report_type_length_mismatch(NULL, "a FT_[U]INT", length, TRUE);
+                       }
+                       if (length == -1) {
+                               guint64 dummy;
+                               /* This can throw an exception */
+                               /* XXX - do this without fetching the varint? */
+                               length = tvb_get_varint(tvb, start, FT_VARINT_MAX_LEN, &dummy, encoding);
+                               if (length == 0) {
+                                       THROW(ReportedBoundsError);
+                               }
+                       }
+                       item_length = length;
+                       break;
+               }
+
+               /*
+                * The length is the specified length.
+                */
+               break;
+
+       case FT_BOOLEAN:
+       case FT_CHAR:
        case FT_IPv4:
        case FT_IPXNET:
        case FT_IPv6:
@@ -4699,7 +5383,11 @@ get_full_length(header_field_info *hfinfo, tvbuff_t *tvb, const gint start,
                break;
 
        case FT_UINT_STRING:
-               n = get_uint_value(NULL, tvb, start, length, encoding & ~ENC_CHARENCODING_MASK);
+               if (encoding & ENC_ZIGBEE) {
+                       n = get_uint_value(NULL, tvb, start, length, encoding);
+               } else {
+                       n = get_uint_value(NULL, tvb, start, length, encoding & ~ENC_CHARENCODING_MASK);
+               }
                item_length += n;
                break;
 
@@ -4776,7 +5464,7 @@ proto_tree_set_representation_value(proto_item *pi, const char *format, va_list
                        guint64 val;
                        char *p;
 
-                       if (IS_FT_UINT(hf->type))
+                       if (IS_FT_UINT32(hf->type))
                                val = fvalue_get_uinteger(&fi->value);
                        else
                                val = fvalue_get_uinteger64(&fi->value);
@@ -4901,10 +5589,9 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
        guint32             number;
        guint64             number64;
        guint8             *bytes;
-       ipv4_addr_and_mask *ipv4;
-       struct e_in6_addr  *ipv6;
+       guint32             ipv4;
+       ws_in6_addr        *ipv6;
        address             addr;
-       guint32             n_addr; /* network-order IPv4 address */
 
        const true_false_string  *tfstring;
 
@@ -4984,27 +5671,19 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                if (offset_e && (offset_e < (size - 2)))
                                        expr[offset_e++] = ',';
 
-                               switch (hfinfo->type) {
-
-                                       case FT_NONE: /* Nothing to add */
-                                               if (offset_r == 0) {
-                                                       result[0] = '\0';
-                                               } else if (result[offset_r-1] == ',') {
-                                                       result[offset_r-1] = '\0';
-                                               }
-                                               break;
+                               switch (hfinfo->type) {
 
+                                       case FT_NONE:
                                        case FT_PROTOCOL:
-                                               /* prevent multiple "yes" entries by setting result directly */
-                                               g_strlcpy(result, "Yes", size);
+                                               /* prevent multiple check marks by setting result directly */
+                                               g_strlcpy(result, UTF8_CHECK_MARK, size);
                                                break;
 
                                        case FT_UINT_BYTES:
                                        case FT_BYTES:
                                                bytes = (guint8 *)fvalue_get(&finfo->value);
                                                if (bytes) {
-                                                       switch(hfinfo->display)
-                                                       {
+                                                       switch (hfinfo->display) {
                                                        case SEP_DOT:
                                                                str = bytestring_to_str(NULL, bytes, fvalue_length(&finfo->value), '.');
                                                                break;
@@ -5019,12 +5698,9 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                                break;
                                                        case BASE_NONE:
                                                        default:
-                                                               if (prefs.display_byte_fields_with_spaces)
-                                                               {
+                                                               if (prefs.display_byte_fields_with_spaces) {
                                                                        str = bytestring_to_str(NULL, bytes, fvalue_length(&finfo->value), ' ');
-                                                               }
-                                                               else
-                                                               {
+                                                               } else {
                                                                        str = bytes_to_str(NULL, bytes, fvalue_length(&finfo->value));
                                                                }
                                                                break;
@@ -5076,7 +5752,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                hf_str_val = NULL;
                                                number = fvalue_get_uinteger(&finfo->value);
 
-                                               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM) {
+                                               if (FIELD_DISPLAY(hfinfo->display) == BASE_CUSTOM) {
                                                        gchar tmp[ITEM_LABEL_LENGTH];
                                                        custom_fmt_func_t fmtfunc = (custom_fmt_func_t)hfinfo->strings;
 
@@ -5099,7 +5775,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
                                                }
 
-                                               if (hf_str_val && (hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
+                                               if (hf_str_val && FIELD_DISPLAY(hfinfo->display) == BASE_NONE) {
                                                        g_snprintf(expr+offset_e, size-offset_e, "\"%s\"", hf_str_val);
                                                } else {
                                                        number_out = hfinfo_char_value_format(hfinfo, number_buf, number);
@@ -5125,7 +5801,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        (guint32) fvalue_get_sinteger(&finfo->value) :
                                                        fvalue_get_uinteger(&finfo->value);
 
-                                               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM) {
+                                               if (FIELD_DISPLAY(hfinfo->display) == BASE_CUSTOM) {
                                                        gchar tmp[ITEM_LABEL_LENGTH];
                                                        custom_fmt_func_t fmtfunc = (custom_fmt_func_t)hfinfo->strings;
 
@@ -5140,12 +5816,11 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                                offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
                                                                hf_str_val = hf_try_val_to_str(number, hfinfo);
                                                                offset_r += protoo_strlcpy(result+offset_r, hf_str_val, size-offset_r);
-                                                       }
-                                                       else {
+                                                       } else {
                                                                number_out = hf_str_val = hf_try_val_to_str(number, hfinfo);
 
                                                                if (!number_out)
-                                                                       number_out = hfinfo_number_value_format_display(hfinfo, BASE_DEC, number_buf, number);
+                                                                       number_out = hfinfo_number_value_format_display(hfinfo, hfinfo->display, number_buf, number);
 
                                                                offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
                                                        }
@@ -5155,7 +5830,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
                                                }
 
-                                               if (hf_str_val && (hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
+                                               if (hf_str_val && FIELD_DISPLAY(hfinfo->display) == 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);
@@ -5179,7 +5854,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        (guint64) fvalue_get_sinteger64(&finfo->value) :
                                                        fvalue_get_uinteger64(&finfo->value);
 
-                                               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM) {
+                                               if (FIELD_DISPLAY(hfinfo->display) == BASE_CUSTOM) {
                                                        gchar tmp[ITEM_LABEL_LENGTH];
                                                        custom_fmt_func_64_t fmtfunc64 = (custom_fmt_func_64_t)hfinfo->strings;
 
@@ -5187,20 +5862,26 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        fmtfunc64(tmp, number64);
                                                        offset_r += protoo_strlcpy(result+offset_r, tmp, size-offset_r);
                                                } else if (hfinfo->strings) {
-                                                       number_out = hf_str_val = hf_try_val64_to_str(number64, hfinfo);
-
-                                                       if (!number_out)
-                                                               number_out = hfinfo_number_value_format_display64(hfinfo, BASE_DEC, number_buf, number64);
+                                                       if (hfinfo->display & BASE_UNIT_STRING) {
+                                                               number_out = hfinfo_numeric_value_format64(hfinfo, number_buf, number64);
+                                                               offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
+                                                               hf_str_val = hf_try_val64_to_str(number64, hfinfo);
+                                                               offset_r += protoo_strlcpy(result+offset_r, hf_str_val, size-offset_r);
+                                                       } else {
+                                                               number_out = hf_str_val = hf_try_val64_to_str(number64, hfinfo);
 
-                                                       offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
+                                                               if (!number_out)
+                                                                       number_out = hfinfo_number_value_format_display64(hfinfo, hfinfo->display, number_buf, number64);
 
+                                                               offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
+                                                       }
                                                } else {
                                                        number_out = hfinfo_number_value_format64(hfinfo, number_buf, number64);
 
                                                        offset_r += protoo_strlcpy(result+offset_r, number_out, size-offset_r);
                                                }
 
-                                               if (hf_str_val && (hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
+                                               if (hf_str_val && FIELD_DISPLAY(hfinfo->display) == BASE_NONE) {
                                                        g_snprintf(expr+offset_e, size-offset_e, "\"%s\"", hf_str_val);
                                                } else {
                                                        number_out = hfinfo_numeric_value_format64(hfinfo, number_buf, number64);
@@ -5218,16 +5899,15 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                break;
 
                                        case FT_IPv4:
-                                               ipv4 = (ipv4_addr_and_mask *)fvalue_get(&finfo->value);
-                                               n_addr = ipv4_get_net_order_addr(ipv4);
-                                               set_address (&addr, AT_IPv4, 4, &n_addr);
+                                               ipv4 = fvalue_get_uinteger(&finfo->value);
+                                               set_address (&addr, AT_IPv4, 4, &ipv4);
                                                address_to_str_buf(&addr, result+offset_r, size-offset_r);
                                                offset_r = (int)strlen(result);
                                                break;
 
                                        case FT_IPv6:
-                                               ipv6 = (struct e_in6_addr *)fvalue_get(&finfo->value);
-                                               set_address (&addr, AT_IPv6, sizeof(struct e_in6_addr), ipv6);
+                                               ipv6 = (ws_in6_addr *)fvalue_get(&finfo->value);
+                                               set_address (&addr, AT_IPv6, sizeof(ws_in6_addr), ipv6);
                                                address_to_str_buf(&addr, result+offset_r, size-offset_r);
                                                offset_r = (int)strlen(result);
                                                break;
@@ -5285,7 +5965,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        double d_value = fvalue_get_floating(&finfo->value);
                                                        g_snprintf(result+offset_r, size-offset_r,
                                                                        "%." G_STRINGIFY(FLT_DIG) "g%s", d_value,
-                                                                       unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+                                                                       unit_name_string_get_double(d_value, (const unit_name_string*)hfinfo->strings));
                                                } else {
                                                        g_snprintf(result+offset_r, size-offset_r,
                                                                        "%." G_STRINGIFY(FLT_DIG) "g", fvalue_get_floating(&finfo->value));
@@ -5298,7 +5978,7 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                        double d_value = fvalue_get_floating(&finfo->value);
                                                        g_snprintf(result+offset_r, size-offset_r,
                                                                        "%." G_STRINGIFY(DBL_DIG) "g%s", d_value,
-                                                                       unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+                                                                       unit_name_string_get_double(d_value, (const unit_name_string*)hfinfo->strings));
                                                } else {
                                                        g_snprintf(result+offset_r, size-offset_r,
                                                                        "%." G_STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
@@ -5317,32 +5997,17 @@ proto_custom_set(proto_tree* tree, GSList *field_ids, gint occurrence,
                                                wmem_free(NULL, str);
                                                break;
 
-                                       case FT_IEEE_11073_SFLOAT:
-                                               str = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, hfinfo->display);
-                                               g_snprintf(result+offset_r, size-offset_r,
-                                                                               "%s: %s",
-                                                                               hfinfo->name, str);
-                                               wmem_free(NULL, str);
-                                               offset_r = (int)strlen(result);
-                                               break;
-
-                                       case FT_IEEE_11073_FLOAT:
+                                       default:
+                                               /* First try ftype string representation */
                                                str = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, hfinfo->display);
-                                               g_snprintf(result+offset_r, size-offset_r,
-                                                                               "%s: %s",
-                                                                               hfinfo->name, str);
-                                               offset_r = (int)strlen(result);
+                                               if (!str) {
+                                                       /* Default to show as bytes */
+                                                       bytes = (guint8 *)fvalue_get(&finfo->value);
+                                                       str = bytes_to_str(NULL, bytes, fvalue_length(&finfo->value));
+                                               }
+                                               offset_r += protoo_strlcpy(result+offset_r, str, size-offset_r);
                                                wmem_free(NULL, str);
                                                break;
-
-                                       case FT_IPXNET: /*XXX really No column custom ?*/
-                                       case FT_PCRE:
-                                       default:
-                                               g_error("hfinfo->type %d (%s) not handled\n",
-                                                               hfinfo->type,
-                                                               ftype_name(hfinfo->type));
-                                               DISSECTOR_ASSERT_NOT_REACHED();
-                                               break;
                                }
                                i++;
                        }
@@ -5493,16 +6158,22 @@ proto_item_prepend_text(proto_item *pi, const char *format, ...)
 static void
 finfo_set_len(field_info *fi, const gint length)
 {
+       gint length_remaining;
+
        DISSECTOR_ASSERT(length >= 0);
-       fi->length = length;
+       length_remaining = tvb_captured_length_remaining(fi->ds_tvb, fi->start);
+       if (length > length_remaining)
+               fi->length = length_remaining;
+       else
+               fi->length = length;
 
        /*
         * You cannot just make the "len" field of a GByteArray
         * larger, if there's no data to back that length;
         * you can only make it smaller.
         */
-       if (fi->value.ftype->ftype == FT_BYTES && length <= (gint)fi->value.value.bytes->len)
-               fi->value.value.bytes->len = length;
+       if (fi->value.ftype->ftype == FT_BYTES && fi->length <= (gint)fi->value.value.bytes->len)
+               fi->value.value.bytes->len = fi->length;
 }
 
 void
@@ -5589,7 +6260,7 @@ proto_tree_create_root(packet_info *pinfo)
 /* "prime" a proto_tree with a single hfid that a dfilter
  * is interested in. */
 void
-proto_tree_prime_hfid(proto_tree *tree _U_, const gint hfid)
+proto_tree_prime_with_hfid(proto_tree *tree _U_, const gint hfid)
 {
        header_field_info *hfinfo;
 
@@ -5721,7 +6392,7 @@ proto_tree_move_item(proto_tree *tree, proto_item *fixed_item,
        } else {
                proto_item *curr_item;
                /* find previous and change it's next */
-               for(curr_item = tree->first_child; curr_item != NULL; curr_item = curr_item->next) {
+               for (curr_item = tree->first_child; curr_item != NULL; curr_item = curr_item->next) {
                        if (curr_item->next == item_to_move) {
                                break;
                        }
@@ -5771,11 +6442,7 @@ 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;
-       const char *existing_name;
-       gint *key;
        guint i;
        gchar c;
        gboolean found_invalid;
@@ -5786,29 +6453,15 @@ proto_register_protocol(const char *name, const char *short_name,
         * or an inappropriate plugin.
         * This situation has to be fixed to not register more than one
         * protocol with the same name.
-        *
-        * This is done by reducing the number of strcmp (and alike) calls
-        * as much as possible, as this significally slows down startup time.
-        *
-        * Drawback: As a hash value is used to reduce insert time,
-        * this might lead to a hash collision.
-        * However, although we have somewhat over 1000 protocols, we're using
-        * a 32 bit int so this is very, very unlikely.
         */
 
-       key  = (gint *)g_malloc (sizeof(gint));
-       *key = wrs_str_hash(name);
-
-       existing_name = (const char *)g_hash_table_lookup(proto_names, key);
-       if (existing_name != NULL) {
+       if (g_hash_table_lookup(proto_names, name)) {
                /* g_error will terminate the program */
                g_error("Duplicate protocol name \"%s\"!"
                        " This might be caused by an inappropriate plugin or a development error.", name);
        }
-       g_hash_table_insert(proto_names, key, (gpointer)name);
 
-       existing_protocol = (const protocol_t *)g_hash_table_lookup(proto_short_names, short_name);
-       if (existing_protocol != NULL) {
+       if (g_hash_table_lookup(proto_short_names, short_name)) {
                g_error("Duplicate protocol short_name \"%s\"!"
                        " This might be caused by an inappropriate plugin or a development error.", short_name);
        }
@@ -5825,28 +6478,30 @@ 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_protocol = (const protocol_t *)g_hash_table_lookup(proto_filter_names, filter_name);
-       if (existing_protocol != NULL) {
+
+       if (g_hash_table_lookup(proto_filter_names, filter_name)) {
                g_error("Duplicate protocol filter_name \"%s\"!"
                        " This might be caused by an inappropriate plugin or a development error.", filter_name);
        }
 
-       /* Add this protocol to the list of known protocols; the list
-          is sorted by protocol short name. */
+       /*
+        * Add this protocol to the list of known protocols;
+        * the list is sorted by protocol short name.
+        */
        protocol = g_new(protocol_t, 1);
        protocol->name = name;
        protocol->short_name = short_name;
        protocol->filter_name = filter_name;
-       /*protocol->fields = g_ptr_array_new();*/
-       /* Delegate until actually needed and use g_ptr_array_sized_new*/
-       protocol->fields = NULL;
+       protocol->fields = NULL; /* Delegate until actually needed */
        protocol->is_enabled = TRUE; /* protocol is enabled by default */
        protocol->enabled_by_default = TRUE; /* see previous comment */
        protocol->can_toggle = TRUE;
        protocol->parent_proto_id = -1;
        protocol->heur_list = NULL;
-       /* list will be sorted later by name, when all protocols completed registering */
+
+       /* List will be sorted later by name, when all protocols completed registering */
        protocols = g_list_prepend(protocols, protocol);
+       g_hash_table_insert(proto_names, (gpointer)name, protocol);
        g_hash_table_insert(proto_filter_names, (gpointer)filter_name, protocol);
        g_hash_table_insert(proto_short_names, (gpointer)short_name, protocol);
 
@@ -5860,11 +6515,10 @@ proto_register_protocol(const char *name, const char *short_name,
        hfinfo->bitmask = 0;
        hfinfo->ref_type = HF_REF_TYPE_NONE;
        hfinfo->blurb = NULL;
-       hfinfo->parent = -1; /* this field differentiates protos and fields */
+       hfinfo->parent = -1; /* This field differentiates protos and fields */
 
-       proto_id = proto_register_field_init(hfinfo, hfinfo->parent);
-       protocol->proto_id = proto_id;
-       return proto_id;
+       protocol->proto_id = proto_register_field_init(hfinfo, hfinfo->parent);
+       return protocol->proto_id;
 }
 
 int
@@ -5906,7 +6560,7 @@ proto_register_protocol_in_name_only(const char *name, const char *short_name, c
        protocol->name = name;
        protocol->short_name = short_name;
        protocol->filter_name = filter_name;
-       protocol->fields = NULL;
+       protocol->fields = NULL; /* Delegate until actually needed */
 
        /* Enabling and toggling is really determined by parent protocol,
           but provide default values here */
@@ -5916,7 +6570,8 @@ proto_register_protocol_in_name_only(const char *name, const char *short_name, c
 
        protocol->parent_proto_id = parent_proto;
        protocol->heur_list = NULL;
-       /* list will be sorted later by name, when all protocols completed registering */
+
+       /* List will be sorted later by name, when all protocols completed registering */
        pino_protocols = g_list_prepend(pino_protocols, protocol);
 
        /* Here we allocate a new header_field_info struct */
@@ -5932,7 +6587,7 @@ proto_register_protocol_in_name_only(const char *name, const char *short_name, c
        hfinfo->bitmask = 0;
        hfinfo->ref_type = HF_REF_TYPE_NONE;
        hfinfo->blurb = NULL;
-       hfinfo->parent = -1; /* this field differentiates protos and fields */
+       hfinfo->parent = -1; /* This field differentiates protos and fields */
 
        protocol->proto_id = proto_register_field_init(hfinfo, hfinfo->parent);
        return protocol->proto_id;
@@ -5944,7 +6599,6 @@ proto_deregister_protocol(const char *short_name)
        protocol_t *protocol;
        header_field_info *hfinfo;
        int proto_id;
-       gint key;
        guint i;
 
        proto_id = proto_get_id_by_short_name(short_name);
@@ -5952,9 +6606,7 @@ proto_deregister_protocol(const char *short_name)
        if (protocol == NULL)
                return FALSE;
 
-       key = wrs_str_hash(protocol->name);
-       g_hash_table_remove(proto_names, &key);
-
+       g_hash_table_remove(proto_names, protocol->name);
        g_hash_table_remove(proto_short_names, (gpointer)short_name);
        g_hash_table_remove(proto_filter_names, (gpointer)protocol->filter_name);
 
@@ -6035,7 +6687,7 @@ proto_get_first_protocol_field(const int proto_id, void **cookie)
 {
        protocol_t *protocol = find_protocol_by_id(proto_id);
 
-       if ((protocol == NULL) || (protocol->fields == NULL))
+       if ((protocol == NULL) || (protocol->fields == NULL) || (protocol->fields->len == 0))
                return NULL;
 
        *cookie = GUINT_TO_POINTER(0 + 1);
@@ -6081,12 +6733,9 @@ proto_get_id(const protocol_t *protocol)
 gboolean
 proto_name_already_registered(const gchar *name)
 {
-       gint key;
-
        DISSECTOR_ASSERT_HINT(name, "No name present");
 
-       key = wrs_str_hash(name);
-       if (g_hash_table_lookup(proto_names, &key) != NULL)
+       if (g_hash_table_lookup(proto_names, name) != NULL)
                return TRUE;
        return FALSE;
 }
@@ -6255,6 +6904,9 @@ proto_is_pino(const protocol_t *protocol)
 gboolean
 proto_is_protocol_enabled(const protocol_t *protocol)
 {
+       if (protocol == NULL)
+               return FALSE;
+
        //parent protocol determines enable/disable for helper dissectors
        if (proto_is_pino(protocol))
                return proto_is_protocol_enabled(find_protocol_by_id(protocol->parent_proto_id));
@@ -6309,7 +6961,7 @@ proto_set_decoding(const int proto_id, const gboolean enabled)
 }
 
 void
-proto_enable_all(void)
+proto_reenable_all(void)
 {
        protocol_t *protocol;
        GList      *list_item = protocols;
@@ -6497,8 +7149,18 @@ free_deregistered_field (gpointer data, gpointer user_data _U_)
                                g_free ((gchar *)tf->false_string);
                                break;
                        }
+                       case FT_UINT40:
+                       case FT_INT40:
+                       case FT_UINT48:
+                       case FT_INT48:
+                       case FT_UINT56:
+                       case FT_INT56:
                        case FT_UINT64:
                        case FT_INT64: {
+                               /*
+                                * XXX - if it's BASE_RANGE_STRING, or
+                                * BASE_EXT_STRING, should we free it?
+                                */
                                if (hfi->display & BASE_UNIT_STRING) {
                                        unit_name_string *unit = (unit_name_string*)hfi->strings;
                                        g_free ((gchar *)unit->singular);
@@ -6512,8 +7174,21 @@ free_deregistered_field (gpointer data, gpointer user_data _U_)
                                }
                                break;
                        }
-                       default: {
-                               /* Other Integer types */
+                       case FT_CHAR:
+                       case FT_UINT8:
+                       case FT_INT8:
+                       case FT_UINT16:
+                       case FT_INT16:
+                       case FT_UINT24:
+                       case FT_INT24:
+                       case FT_UINT32:
+                       case FT_INT32:
+                       case FT_FLOAT:
+                       case FT_DOUBLE: {
+                               /*
+                                * XXX - if it's BASE_RANGE_STRING, or
+                                * BASE_EXT_STRING, should we free it?
+                                */
                                if (hfi->display & BASE_UNIT_STRING) {
                                        unit_name_string *unit = (unit_name_string*)hfi->strings;
                                        g_free ((gchar *)unit->singular);
@@ -6526,6 +7201,8 @@ free_deregistered_field (gpointer data, gpointer user_data _U_)
                                        }
                                }
                                break;
+                       default:
+                               break;
                        }
                }
                if (hfi->type != FT_FRAMENUM) {
@@ -6613,6 +7290,7 @@ static const value_string hf_display[] = {
        { BASE_PT_TCP,                    "BASE_PT_TCP"                    },
        { BASE_PT_DCCP,                   "BASE_PT_DCCP"                   },
        { BASE_PT_SCTP,                   "BASE_PT_SCTP"                   },
+       { BASE_OUI,                       "BASE_OUI"                       },
        { 0,                              NULL } };
 
 const char* proto_field_display_to_string(int field_display)
@@ -6663,7 +7341,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
         *  true_false_strings or a protocol_t struct
         */
        if (hfinfo->strings != NULL) {
-               switch(hfinfo->type) {
+               switch (hfinfo->type) {
                case FT_CHAR:
                case FT_UINT8:
                case FT_UINT16:
@@ -6708,12 +7386,13 @@ tmp_fld_check_assert(header_field_info *hfinfo)
        /* TODO: This check may slow down startup, and output quite a few warnings.
           It would be good to be able to enable this (and possibly other checks?)
           in non-release builds.   */
-#if 0
+#if ENABLE_CHECK_FILTER
        /* Check for duplicate value_string values.
           There are lots that have the same value *and* string, so for now only
           report those that have same value but different string. */
        if ((hfinfo->strings != NULL) &&
            !(hfinfo->display & BASE_RANGE_STRING) &&
+           !(hfinfo->display & BASE_UNIT_STRING) &&
            !((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM) &&
            (
                    (hfinfo->type == FT_CHAR)  ||
@@ -6724,8 +7403,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                    (hfinfo->type == FT_INT8)   ||
                    (hfinfo->type == FT_INT16)  ||
                    (hfinfo->type == FT_INT24)  ||
-                   (hfinfo->type == FT_INT32)  ||
-                   (hfinfo->type == FT_FRAMENUM) )) {
+                   (hfinfo->type == FT_INT32)  )) {
 
                int n, m;
                const value_string *start_values;
@@ -6812,7 +7490,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 & FIELD_DISPLAY_E_MASK) {
+                       switch (FIELD_DISPLAY(hfinfo->display)) {
                                case BASE_HEX:
                                case BASE_OCT:
                                case BASE_DEC_HEX:
@@ -6853,6 +7531,27 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                                break;
                        }
 
+                       if (hfinfo->display == BASE_OUI) {
+                               tmp_str = val_to_str_wmem(NULL, hfinfo->display, hf_display, "(Unknown: 0x%x)");
+                               if (hfinfo->type != FT_UINT24) {
+                                       g_error("Field '%s' (%s) has 'display' value %s but it can only be used with FT_UINT24, not %s\n",
+                                               hfinfo->name, hfinfo->abbrev,
+                                               tmp_str, ftype_name(hfinfo->type));
+                               }
+                               if (hfinfo->strings != NULL) {
+                                       g_error("Field '%s' (%s) is an %s (%s) but has a strings value\n",
+                                               hfinfo->name, hfinfo->abbrev,
+                                               ftype_name(hfinfo->type), tmp_str);
+                               }
+                               if (hfinfo->bitmask != 0) {
+                                       g_error("Field '%s' (%s) is an %s (%s) but has a bitmask\n",
+                                               hfinfo->name, hfinfo->abbrev,
+                                               ftype_name(hfinfo->type), tmp_str);
+                               }
+                               wmem_free(NULL, tmp_str);
+                               break;
+                       }
+
                        /*  Require integral types (other than frame number,
                         *  which is always displayed in decimal) to have a
                         *  number base.
@@ -6863,7 +7562,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                         *  meaningless; we'll avoid showing the value to the
                         *  user.
                         */
-                       switch (hfinfo->display & FIELD_DISPLAY_E_MASK) {
+                       switch (FIELD_DISPLAY(hfinfo->display)) {
                                case BASE_DEC:
                                case BASE_HEX:
                                case BASE_OCT:
@@ -6879,6 +7578,13 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                                                        hfinfo->name, hfinfo->abbrev,
                                                        ftype_name(hfinfo->type));
                                        }
+                                       if (hfinfo->display & BASE_SPECIAL_VALS) {
+                                               g_error("Field '%s' (%s) is an integral value (%s)"
+                                                       " that is being displayed as BASE_NONE but"
+                                                       " with BASE_SPECIAL_VALS",
+                                                       hfinfo->name, hfinfo->abbrev,
+                                                       ftype_name(hfinfo->type));
+                                       }
                                        break;
 
                                default:
@@ -6891,6 +7597,7 @@ tmp_fld_check_assert(header_field_info *hfinfo)
                        }
                        break;
                case FT_BYTES:
+               case FT_UINT_BYTES:
                        /*  Require bytes to have a "display type" that could
                         *  add a character between displayed bytes.
                         */
@@ -7136,7 +7843,7 @@ register_number_string_decoding_error(void)
        proto_set_cant_toggle(proto_number_string_decoding_error);
 }
 
-#define PROTO_PRE_ALLOC_HF_FIELDS_MEM (183000+PRE_ALLOC_EXPERT_FIELDS_MEM)
+#define PROTO_PRE_ALLOC_HF_FIELDS_MEM (195000+PRE_ALLOC_EXPERT_FIELDS_MEM)
 static int
 proto_register_field_init(header_field_info *hfinfo, const int parent)
 {
@@ -7171,7 +7878,7 @@ proto_register_field_init(header_field_info *hfinfo, const int parent)
 
                /* Check that the filter name (abbreviation) is legal;
                 * it must contain only alphanumerics, '-', "_", and ".". */
-               c = wrs_check_charset(fld_abbrev_chars, hfinfo->abbrev);
+               c = check_charset(fld_abbrev_chars, hfinfo->abbrev);
                if (c) {
                        if (g_ascii_isprint(c))
                                fprintf(stderr, "Invalid character '%c' in filter name '%s'\n", c, hfinfo->abbrev);
@@ -7368,9 +8075,8 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
        guint8             *bytes;
        guint32             integer;
        guint64             integer64;
-       ipv4_addr_and_mask *ipv4;
+       guint32             ipv4;
        e_guid_t           *guid;
-       guint32             n_addr; /* network-order IPv4 address */
        gchar              *name;
        address             addr;
        char               *addr_str;
@@ -7400,8 +8106,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        bytes = (guint8 *)fvalue_get(&fi->value);
                        if (bytes) {
                                char* str = NULL;
-                               switch(hfinfo->display)
-                               {
+                               switch (hfinfo->display) {
                                case SEP_DOT:
                                        str = bytestring_to_str(NULL, bytes, fvalue_length(&fi->value), '.');
                                        break;
@@ -7416,12 +8121,9 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                                        break;
                                case BASE_NONE:
                                default:
-                                       if (prefs.display_byte_fields_with_spaces)
-                                       {
+                                       if (prefs.display_byte_fields_with_spaces) {
                                                str = bytestring_to_str(NULL, bytes, fvalue_length(&fi->value), ' ');
-                                       }
-                                       else
-                                       {
+                                       } else {
                                                str = bytes_to_str(NULL, bytes, fvalue_length(&fi->value));
                                        }
                                        break;
@@ -7456,7 +8158,11 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_UINT24:
                case FT_UINT32:
                        if (hfinfo->bitmask) {
-                               fill_label_bitfield(fi, label_str, FALSE);
+                               if (fi->flags & FI_VARINT) {
+                                       fill_label_bitfield_varint(fi, label_str, FALSE);
+                               } else {
+                                       fill_label_bitfield(fi, label_str, FALSE);
+                               }
                        } else {
                                fill_label_number(fi, label_str, FALSE);
                        }
@@ -7471,7 +8177,11 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_UINT56:
                case FT_UINT64:
                        if (hfinfo->bitmask) {
-                               fill_label_bitfield64(fi, label_str, FALSE);
+                               if (fi->flags & FI_VARINT) {
+                                       fill_label_bitfield_varint64(fi, label_str, FALSE);
+                               } else {
+                                       fill_label_bitfield64(fi, label_str, FALSE);
+                               }
                        } else {
                                fill_label_number64(fi, label_str, FALSE);
                        }
@@ -7482,7 +8192,11 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_INT24:
                case FT_INT32:
                        if (hfinfo->bitmask) {
-                               fill_label_bitfield(fi, label_str, TRUE);
+                               if (fi->flags & FI_VARINT) {
+                                       fill_label_bitfield_varint(fi, label_str, TRUE);
+                               } else {
+                                       fill_label_bitfield(fi, label_str, TRUE);
+                               }
                        } else {
                                fill_label_number(fi, label_str, TRUE);
                        }
@@ -7493,41 +8207,47 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_INT56:
                case FT_INT64:
                        if (hfinfo->bitmask) {
-                               fill_label_bitfield64(fi, label_str, TRUE);
+                               if (fi->flags & FI_VARINT) {
+                                       fill_label_bitfield_varint64(fi, label_str, TRUE);
+                               } else {
+                                       fill_label_bitfield64(fi, label_str, TRUE);
+                               }
                        } else {
                                fill_label_number64(fi, label_str, TRUE);
                        }
                        break;
 
-               case FT_FLOAT: {
+               case FT_FLOAT:
+               {
                        double d_value = fvalue_get_floating(&fi->value);
                        if (hfinfo->display & BASE_UNIT_STRING) {
                                g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                           "%s: %." G_STRINGIFY(FLT_DIG) "g%s",
                                           hfinfo->name, d_value,
-                                          unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+                                          unit_name_string_get_double(d_value, (const unit_name_string*)hfinfo->strings));
                        } else {
                                g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                           "%s: %." G_STRINGIFY(FLT_DIG) "g",
                                           hfinfo->name, d_value);
                        }
-                       }
                        break;
+               }
 
-               case FT_DOUBLE: {
+               case FT_DOUBLE:
+               {
                        double d_value = fvalue_get_floating(&fi->value);
                        if (hfinfo->display & BASE_UNIT_STRING) {
                                g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                           "%s: %." G_STRINGIFY(DBL_DIG) "g%s",
                                           hfinfo->name, d_value,
-                                          unit_name_string_get_value64((guint64)d_value, (unit_name_string*)hfinfo->strings));
+                                          unit_name_string_get_double(d_value, (const unit_name_string*)hfinfo->strings));
                        } else {
                                g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                           "%s: %." G_STRINGIFY(DBL_DIG) "g",
                                           hfinfo->name, d_value);
                        }
-                       }
                        break;
+               }
 
                case FT_ABSOLUTE_TIME:
                        tmp = abs_time_to_str(NULL, (const nstime_t *)fvalue_get(&fi->value), (absolute_time_display_e)hfinfo->display, TRUE);
@@ -7587,19 +8307,15 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_IPv4:
-                       ipv4 = (ipv4_addr_and_mask *)fvalue_get(&fi->value);
-                       n_addr = ipv4_get_net_order_addr(ipv4);
+                       ipv4 = fvalue_get_uinteger(&fi->value);
 
                        addr.type = AT_IPv4;
                        addr.len  = 4;
-                       addr.data = &n_addr;
+                       addr.data = &ipv4;
 
-                       if (hfinfo->display == BASE_NETMASK)
-                       {
+                       if (hfinfo->display == BASE_NETMASK) {
                                addr_str = (char*)address_to_str(NULL, &addr);
-                       }
-                       else
-                       {
+                       } else {
                                addr_str = (char*)address_with_resolution_to_str(NULL, &addr);
                        }
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
@@ -7690,12 +8406,6 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_IEEE_11073_SFLOAT:
-                       tmp = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, hfinfo->display);
-                       g_snprintf(label_str, ITEM_LABEL_LENGTH,
-                                               "%s: %s",
-                                               hfinfo->name, tmp);
-                       wmem_free(NULL, tmp);
-                       break;
                case FT_IEEE_11073_FLOAT:
                        tmp = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, hfinfo->display);
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
@@ -7758,7 +8468,7 @@ hf_try_val_to_str(guint32 value, const header_field_info *hfinfo)
                return try_val64_to_str(value, (const val64_string *) hfinfo->strings);
 
        if (hfinfo->display & BASE_UNIT_STRING)
-               return unit_name_string_get_value(value, (struct unit_name_string*) hfinfo->strings);
+               return unit_name_string_get_value(value, (const struct unit_name_string*) hfinfo->strings);
 
        return try_val_to_str(value, (const value_string *) hfinfo->strings);
 }
@@ -7773,7 +8483,7 @@ hf_try_val64_to_str(guint64 value, const header_field_info *hfinfo)
                return try_rval64_to_str(value, (const range_string *) hfinfo->strings);
 
        if (hfinfo->display & BASE_UNIT_STRING)
-               return unit_name_string_get_value64(value, (struct unit_name_string*) hfinfo->strings);
+               return unit_name_string_get_value64(value, (const struct unit_name_string*) hfinfo->strings);
 
        /* If this is reached somebody registered a 64-bit field with a 32-bit
         * value-string, which isn't right. */
@@ -7968,6 +8678,110 @@ fill_label_bitfield64(field_info *fi, gchar *label_str, gboolean is_signed)
        }
 }
 
+static void
+fill_label_bitfield_varint(field_info *fi, gchar *label_str, gboolean is_signed)
+{
+       char       *p;
+       int         bitfield_byte_length;
+       guint32     value, unshifted_value;
+       char        buf[48];
+       const char *out;
+
+       header_field_info *hfinfo = fi->hfinfo;
+
+       /* Un-shift bits */
+       if (is_signed) {
+               value = fvalue_get_sinteger(&fi->value);
+       } else {
+               value = fvalue_get_uinteger(&fi->value);
+       }
+       unshifted_value = value;
+       if (hfinfo->bitmask) {
+               unshifted_value <<= hfinfo_bitshift(hfinfo);
+       }
+
+       /* Create the bitfield first */
+       p = decode_bitfield_varint_value(label_str, unshifted_value, hfinfo->bitmask, fi->length*8);
+       bitfield_byte_length = (int) (p - label_str);
+
+       /* Fill in the textual info using stored (shifted) value */
+       if (hfinfo->display == BASE_CUSTOM) {
+               gchar tmp[ITEM_LABEL_LENGTH];
+               const custom_fmt_func_t fmtfunc = (const custom_fmt_func_t)hfinfo->strings;
+
+               DISSECTOR_ASSERT(fmtfunc);
+               fmtfunc(tmp, value);
+               label_fill(label_str, bitfield_byte_length, hfinfo, tmp);
+       }
+       else if (hfinfo->strings) {
+               const char *val_str = hf_try_val_to_str_const(value, hfinfo, "Unknown");
+
+               out = hfinfo_number_vals_format(hfinfo, buf, value);
+               if (out == NULL) /* BASE_NONE so don't put integer in descr */
+                       label_fill(label_str, bitfield_byte_length, hfinfo, val_str);
+               else
+                       label_fill_descr(label_str, bitfield_byte_length, hfinfo, val_str, out);
+       }
+       else {
+               out = hfinfo_number_value_format(hfinfo, buf, value);
+
+               label_fill(label_str, bitfield_byte_length, hfinfo, out);
+       }
+}
+
+static void
+fill_label_bitfield_varint64(field_info *fi, gchar *label_str, gboolean is_signed)
+{
+       char       *p;
+       int         bitfield_byte_length;
+       guint64     unshifted_value;
+       guint64     value;
+
+       char        buf[48];
+       const char *out;
+
+       header_field_info *hfinfo = fi->hfinfo;
+
+       /* Un-shift bits */
+       if (is_signed) {
+               value = fvalue_get_sinteger64(&fi->value);
+       } else {
+               value = fvalue_get_uinteger64(&fi->value);
+       }
+       unshifted_value = value;
+       if (hfinfo->bitmask) {
+               unshifted_value <<= hfinfo_bitshift(hfinfo);
+       }
+
+       /* Create the bitfield first */
+       p = decode_bitfield_varint_value(label_str, unshifted_value, hfinfo->bitmask, fi->length*8);
+       bitfield_byte_length = (int) (p - label_str);
+
+       /* Fill in the textual info using stored (shifted) value */
+       if (hfinfo->display == BASE_CUSTOM) {
+               gchar tmp[ITEM_LABEL_LENGTH];
+               const custom_fmt_func_64_t fmtfunc64 = (const custom_fmt_func_64_t)hfinfo->strings;
+
+               DISSECTOR_ASSERT(fmtfunc64);
+               fmtfunc64(tmp, value);
+               label_fill(label_str, bitfield_byte_length, hfinfo, tmp);
+       }
+       else if (hfinfo->strings) {
+               const char *val_str = hf_try_val64_to_str_const(value, hfinfo, "Unknown");
+
+               out = hfinfo_number_vals_format64(hfinfo, buf, value);
+               if (out == NULL) /* BASE_NONE so don't put integer in descr */
+                       label_fill(label_str, bitfield_byte_length, hfinfo, val_str);
+               else
+                       label_fill_descr(label_str, bitfield_byte_length, hfinfo, val_str, out);
+       }
+       else {
+               out = hfinfo_number_value_format64(hfinfo, buf, value);
+
+               label_fill(label_str, bitfield_byte_length, hfinfo, out);
+       }
+}
+
 static void
 fill_label_char(field_info *fi, gchar *label_str)
 {
@@ -8030,13 +8844,28 @@ fill_label_number(field_info *fi, gchar *label_str, gboolean is_signed)
                 * frame-number field - they're just integers giving
                 * the ordinal frame number.
                 */
-               const char *val_str = hf_try_val_to_str_const(value, hfinfo, "Unknown");
+               const char *val_str = hf_try_val_to_str(value, hfinfo);
 
                out = hfinfo_number_vals_format(hfinfo, buf, value);
-               if (out == NULL) /* BASE_NONE so don't put integer in descr */
-                       label_fill(label_str, 0, hfinfo, val_str);
-               else
-                       label_fill_descr(label_str, 0, hfinfo, val_str, out);
+               if (hfinfo->display & BASE_SPECIAL_VALS) {
+                       /*
+                        * Unique values only display value_string string
+                        * if there is a match.  Otherwise it's just a number
+                        */
+                       if (val_str) {
+                               label_fill_descr(label_str, 0, hfinfo, val_str, out);
+                       } else {
+                               label_fill(label_str, 0, hfinfo, out);
+                       }
+               } else {
+                       if (val_str == NULL)
+                               val_str = "Unknown";
+
+                       if (out == NULL) /* BASE_NONE so don't put integer in descr */
+                               label_fill(label_str, 0, hfinfo, val_str);
+                       else
+                               label_fill_descr(label_str, 0, hfinfo, val_str, out);
+               }
        }
        else if (IS_BASE_PORT(hfinfo->display)) {
                gchar tmp[ITEM_LABEL_LENGTH];
@@ -8249,7 +9078,7 @@ hfinfo_char_value_format_display(int display, char buf[7], guint32 value)
                        break;
 
                default:
-                       switch (display & FIELD_DISPLAY_E_MASK) {
+                       switch (FIELD_DISPLAY(display)) {
 
                        case BASE_OCT:
                                *(--ptr) = (value & 0x7) + '0';
@@ -8284,7 +9113,7 @@ hfinfo_number_value_format_display(const header_field_info *hfinfo, int display,
 
        *ptr = '\0';
        /* Properly format value */
-       switch (display & FIELD_DISPLAY_E_MASK) {
+       switch (FIELD_DISPLAY(display)) {
                case BASE_DEC:
                        return isint ? int_to_str_back(ptr, (gint32) value) : uint_to_str_back(ptr, value);
 
@@ -8317,6 +9146,27 @@ hfinfo_number_value_format_display(const header_field_info *hfinfo, int display,
                        port_with_resolution_to_str_buf(buf, 32,
                                        display_to_port_type((field_display_e)display), value);
                        return buf;
+               case BASE_OUI:
+                       {
+                       guint8 p_oui[3];
+                       const gchar *manuf_name;
+
+                       p_oui[0] = value >> 16 & 0xFF;
+                       p_oui[1] = value >> 8 & 0xFF;
+                       p_oui[2] = value & 0xFF;
+
+                       /* Attempt an OUI lookup. */
+                       manuf_name = uint_get_manuf_name_if_known(value);
+                       if (manuf_name == NULL) {
+                               /* Could not find an OUI. */
+                               g_snprintf(buf, 32, "%02x:%02x:%02x", p_oui[0], p_oui[1], p_oui[2]);
+                       }
+                       else {
+                               /* Found an address string. */
+                               g_snprintf(buf, 32, "%02x:%02x:%02x (%s)", p_oui[0], p_oui[1], p_oui[2], manuf_name);
+                       }
+                       return buf;
+                       }
 
                default:
                        g_assert_not_reached();
@@ -8332,35 +9182,36 @@ hfinfo_number_value_format_display64(const header_field_info *hfinfo, int displa
 
        *ptr = '\0';
        /* Properly format value */
-               switch (display) {
-                       case BASE_DEC:
-                               return isint ? int64_to_str_back(ptr, (gint64) value) : uint64_to_str_back(ptr, value);
-
-                       case BASE_DEC_HEX:
-                               *(--ptr) = ')';
-                               ptr = hex64_to_str_back(ptr, hfinfo_hex_digits(hfinfo), value);
-                               *(--ptr) = '(';
-                               *(--ptr) = ' ';
-                               ptr = isint ? int64_to_str_back(ptr, (gint64) value) : uint64_to_str_back(ptr, value);
-                               return ptr;
+       switch (FIELD_DISPLAY(display)) {
+               case BASE_DEC:
+                       return isint ? int64_to_str_back(ptr, (gint64) value) : uint64_to_str_back(ptr, value);
 
-                       case BASE_OCT:
-                               return oct64_to_str_back(ptr, value);
+               case BASE_DEC_HEX:
+                       *(--ptr) = ')';
+                       ptr = hex64_to_str_back(ptr, hfinfo_hex_digits(hfinfo), value);
+                       *(--ptr) = '(';
+                       *(--ptr) = ' ';
+                       ptr = isint ? int64_to_str_back(ptr, (gint64) value) : uint64_to_str_back(ptr, value);
+                       return ptr;
 
-                       case BASE_HEX:
-                               return hex64_to_str_back(ptr, hfinfo_hex_digits(hfinfo), value);
+               case BASE_OCT:
+                       return oct64_to_str_back(ptr, value);
 
-                       case BASE_HEX_DEC:
-                               *(--ptr) = ')';
-                               ptr = isint ? int64_to_str_back(ptr, (gint64) value) : uint64_to_str_back(ptr, value);
-                               *(--ptr) = '(';
-                               *(--ptr) = ' ';
-                               ptr = hex64_to_str_back(ptr, hfinfo_hex_digits(hfinfo), value);
-                               return ptr;
+               case BASE_HEX:
+                       return hex64_to_str_back(ptr, hfinfo_hex_digits(hfinfo), value);
+
+               case BASE_HEX_DEC:
+                       *(--ptr) = ')';
+                       ptr = isint ? int64_to_str_back(ptr, (gint64) value) : uint64_to_str_back(ptr, value);
+                       *(--ptr) = '(';
+                       *(--ptr) = ' ';
+                       ptr = hex64_to_str_back(ptr, hfinfo_hex_digits(hfinfo), value);
+                       return ptr;
+
+               default:
+                       g_assert_not_reached();
+       }
 
-                       default:
-                               g_assert_not_reached();
-               }
        return ptr;
 }
 
@@ -8398,7 +9249,7 @@ static const char *
 hfinfo_char_value_format(const header_field_info *hfinfo, char buf[32], guint32 value)
 {
        /* Get the underlying BASE_ value */
-       int display = hfinfo->display & FIELD_DISPLAY_E_MASK;
+       int display = FIELD_DISPLAY(hfinfo->display);
 
        return hfinfo_char_value_format_display(display, buf, value);
 }
@@ -8407,7 +9258,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 & FIELD_DISPLAY_E_MASK;
+       int display = FIELD_DISPLAY(hfinfo->display);
 
        if (hfinfo->type == FT_FRAMENUM) {
                /*
@@ -8418,6 +9269,8 @@ hfinfo_numeric_value_format(const header_field_info *hfinfo, char buf[32], guint
 
        if (IS_BASE_PORT(display)) {
                display = BASE_DEC;
+       } else if (display == BASE_OUI) {
+               display = BASE_HEX;
        }
 
        switch (display) {
@@ -8442,7 +9295,7 @@ static const char *
 hfinfo_numeric_value_format64(const header_field_info *hfinfo, char buf[64], guint64 value)
 {
        /* Get the underlying BASE_ value */
-       int display = hfinfo->display & FIELD_DISPLAY_E_MASK;
+       int display = FIELD_DISPLAY(hfinfo->display);
 
        if (hfinfo->type == FT_FRAMENUM) {
                /*
@@ -8473,7 +9326,7 @@ static const char *
 hfinfo_char_vals_format(const header_field_info *hfinfo, char buf[32], guint32 value)
 {
        /* Get the underlying BASE_ value */
-       int display = hfinfo->display & FIELD_DISPLAY_E_MASK;
+       int display = FIELD_DISPLAY(hfinfo->display);
 
        return hfinfo_char_value_format_display(display, buf, value);
 }
@@ -8482,7 +9335,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 & FIELD_DISPLAY_E_MASK;
+       int display = FIELD_DISPLAY(hfinfo->display);
 
        if (display == BASE_NONE)
                return NULL;
@@ -8499,7 +9352,7 @@ static const char *
 hfinfo_number_vals_format64(const header_field_info *hfinfo, char buf[64], guint64 value)
 {
        /* Get the underlying BASE_ value */
-       int display = hfinfo->display & FIELD_DISPLAY_E_MASK;
+       int display = FIELD_DISPLAY(hfinfo->display);
 
        if (display == BASE_NONE)
                return NULL;
@@ -8645,11 +9498,14 @@ find_first_finfo(proto_node *node, gpointer data)
        if (fi && fi->hfinfo) {
                if (fi->hfinfo->id == ((ffdata_t*)data)->id) {
                        g_ptr_array_add(((ffdata_t*)data)->array, fi);
+
+                       /* Stop traversing. */
+                       return TRUE;
                }
        }
 
-       /* Stop traversing. */
-       return TRUE;
+       /* Continue traversing. */
+       return FALSE;
 }
 
 /* Return GPtrArray* of field_info pointers for all hfindex that appear in a tree.
@@ -8765,21 +9621,25 @@ proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb)
        return offsearch.finfo;
 }
 
+typedef struct {
+       gint length;
+       gchar *buf;
+} decoded_data_t;
 
 static gboolean
 check_for_undecoded(proto_node *node, gpointer data)
 {
        field_info *fi = PNODE_FINFO(node);
-       gchar* decoded = (gchar*)data;
+       decoded_data_t* decoded = (decoded_data_t*)data;
        gint i;
        guint byte;
        guint bit;
 
        if (fi && fi->hfinfo->type != FT_PROTOCOL) {
-               for (i = fi->start; i < fi->start + fi->length; i++) {
+               for (i = fi->start; i < fi->start + fi->length && i < decoded->length; i++) {
                        byte = i / 8;
                        bit = i % 8;
-                       decoded[byte] |= (1 << bit);
+                       decoded->buf[byte] |= (1 << bit);
                }
        }
 
@@ -8789,10 +9649,12 @@ check_for_undecoded(proto_node *node, gpointer data)
 gchar*
 proto_find_undecoded_data(proto_tree *tree, guint length)
 {
-       gchar* decoded = (gchar*)wmem_alloc0(wmem_packet_scope(), length / 8 + 1);
+       decoded_data_t decoded;
+       decoded.length = length;
+       decoded.buf = (gchar*)wmem_alloc0(wmem_packet_scope(), length / 8 + 1);
 
-       proto_tree_traverse_pre_order(tree, check_for_undecoded, decoded);
-       return decoded;
+       proto_tree_traverse_pre_order(tree, check_for_undecoded, &decoded);
+       return decoded.buf;
 }
 
 /* Dumps the protocols in the registration database to stdout. An independent
@@ -8881,9 +9743,9 @@ proto_registrar_dump_values(void)
 
                PROTO_REGISTRAR_GET_NTH(i, hfinfo);
 
-                if (hfinfo->id == hf_text_only) {
-                        continue;
-                }
+               if (hfinfo->id == hf_text_only) {
+                       continue;
+               }
 
                /* ignore protocols */
                if (proto_registrar_is_protocol(i)) {
@@ -8913,7 +9775,7 @@ proto_registrar_dump_values(void)
                units  = NULL;
 
                if (hfinfo->strings != NULL) {
-                       if ((hfinfo->display & FIELD_DISPLAY_E_MASK) != BASE_CUSTOM &&
+                       if (FIELD_DISPLAY(hfinfo->display) != BASE_CUSTOM &&
                            (hfinfo->type == FT_CHAR  ||
                             hfinfo->type == FT_UINT8  ||
                             hfinfo->type == FT_UINT16 ||
@@ -8930,12 +9792,14 @@ proto_registrar_dump_values(void)
                             hfinfo->type == FT_INT40  ||
                             hfinfo->type == FT_INT48  ||
                             hfinfo->type == FT_INT56  ||
-                            hfinfo->type == FT_INT64)) {
+                            hfinfo->type == FT_INT64  ||
+                            hfinfo->type == FT_FLOAT  ||
+                            hfinfo->type == FT_DOUBLE)) {
 
                                if (hfinfo->display & BASE_RANGE_STRING) {
                                        range = (const range_string *)hfinfo->strings;
                                } else if (hfinfo->display & BASE_EXT_STRING) {
-                                       vals = VALUE_STRING_EXT_VS_P((value_string_ext *)hfinfo->strings);
+                                       vals = VALUE_STRING_EXT_VS_P((const value_string_ext *)hfinfo->strings);
                                } else if (hfinfo->display & BASE_VAL64_STRING) {
                                        vals64 = (const val64_string *)hfinfo->strings;
                                } else if (hfinfo->display & BASE_UNIT_STRING) {
@@ -9020,7 +9884,7 @@ proto_registrar_dump_values(void)
                        vi = 0;
                        while (range[vi].strptr) {
                                /* Print in the proper base */
-                               if ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_HEX) {
+                               if (FIELD_DISPLAY(hfinfo->display) == BASE_HEX) {
                                        ws_debug_printf("R\t%s\t0x%x\t0x%x\t%s\n",
                                               hfinfo->abbrev,
                                               range[vi].value_min,
@@ -9207,6 +10071,7 @@ proto_registrar_dump_fields(void)
                                        case BASE_PT_TCP:
                                        case BASE_PT_DCCP:
                                        case BASE_PT_SCTP:
+                                       case BASE_OUI:
                                                base_name = val_to_str_const(FIELD_DISPLAY(hfinfo->display), hf_display, "????");
                                                break;
                                        default:
@@ -9280,7 +10145,7 @@ construct_match_selected_string(field_info *finfo, epan_dissect_t *edt,
        DISSECTOR_ASSERT(hfinfo);
        abbrev_len = (int) strlen(hfinfo->abbrev);
 
-       if (hfinfo->strings && (hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_NONE) {
+       if (hfinfo->strings && FIELD_DISPLAY(hfinfo->display) == BASE_NONE) {
                const gchar *str = NULL;
 
                switch (hfinfo->type) {
@@ -9682,7 +10547,7 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
 
                                out = hfinfo_number_value_format(hf, buf, (guint32) tmpval);
                                if (hf->display & BASE_UNIT_STRING) {
-                                       proto_item_append_text(item, "%s: %s%s", hf->name, out, unit_name_string_get_value((guint32) tmpval, (unit_name_string*)hf->strings));
+                                       proto_item_append_text(item, "%s: %s%s", hf->name, out, unit_name_string_get_value((guint32) tmpval, (const unit_name_string*)hf->strings));
                                } else {
                                        proto_item_append_text(item, "%s: %s", hf->name, out);
                                }
@@ -9725,7 +10590,7 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
 
                                out = hfinfo_number_value_format(hf, buf, (gint32) integer32);
                                if ((hf->strings) &&(!(hf->display & BASE_UNIT_STRING))) {
-                                       proto_item_append_text(item, "%s: %s%s", hf->name, out, unit_name_string_get_value((guint32) tmpval, (unit_name_string*)hf->strings));
+                                       proto_item_append_text(item, "%s: %s%s", hf->name, out, unit_name_string_get_value((guint32) tmpval, (const unit_name_string*)hf->strings));
                                } else {
                                        proto_item_append_text(item, "%s: %s", hf->name, out);
                                }
@@ -10114,7 +10979,7 @@ proto_tree_add_bits_item(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
 
        octet_length = (no_of_bits + 7) >> 3;
        octet_offset = bit_offset >> 3;
-       test_length(hfinfo, tvb, octet_offset, octet_length);
+       test_length(hfinfo, tvb, octet_offset, octet_length, encoding);
 
        /* 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
@@ -10787,7 +11652,7 @@ proto_tree_add_boolean_bits_format_value64(proto_tree *tree, const int hfindex,
 
        TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hf_field);
 
-       DISSECTOR_ASSERT(hf_field->type == FT_BOOLEAN);
+       DISSECTOR_ASSERT_FIELD_TYPE(hf_field, FT_BOOLEAN);
 
        CREATE_VALUE_STRING(dst, format, ap);
 
@@ -10891,7 +11756,7 @@ proto_tree_add_checksum(proto_tree *tree, tvbuff_t *tvb, const guint offset,
                return ti;
        }
 
-       switch (hfinfo->type){
+       switch (hfinfo->type) {
        case FT_UINT8:
                len = 1;
                break;
@@ -10966,12 +11831,15 @@ proto_tree_add_checksum(proto_tree *tree, tvbuff_t *tvb, const guint offset,
 guchar
 proto_check_field_name(const gchar *field_name)
 {
-       return wrs_check_charset(fld_abbrev_chars, field_name);
+       return check_charset(fld_abbrev_chars, field_name);
 }
 
 gboolean
 tree_expanded(int tree_type)
 {
+       if (tree_type == -1) {
+               return FALSE;
+       }
        g_assert(tree_type >= 0 && tree_type < num_tree_types);
        return tree_is_expanded[tree_type >> 5] & (1U << (tree_type & 31));
 }