Allow floating point values for stats_tree
[gd/wireshark/.git] / epan / dissectors / packet-collectd.c
index 7983dd225b70d978153aadc8842fec6fad3dbc7a..823aa3a15a829f5471f682edb5f0be85b10bb7d8 100644 (file)
@@ -4,37 +4,23 @@
  * Copyright 2008 Bruno Premont <bonbons at linux-vserver.org>
  * Copyright 2009-2013 Florian Forster <octo at collectd.org>
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include "config.h"
 
-#include <string.h>
-#include <glib.h>
 #include <epan/packet.h>
-#include <epan/prefs.h>
 #include <epan/expert.h>
 #include <epan/stats_tree.h>
+#include <epan/to_str.h>
 
-#define STR_NONNULL(str) ((str) ? (str) : "(null)")
+#include <wsutil/str_util.h>
+
+#define STR_NONNULL(str) ((str) ? ((const gchar*)str) : "(null)")
 
 #define TYPE_HOST            0x0000
 #define TYPE_TIME            0x0001
 void proto_register_collectd(void);
 
 typedef struct value_data_s {
-       gchar *host;
+       const guint8 *host;
        gint host_off;
        gint host_len;
-       guint64 time;
+       guint64 time_value;
        gint time_off;
        guint64 interval;
        gint interval_off;
-       gchar *plugin;
+       const guint8 *plugin;
        gint plugin_off;
        gint plugin_len;
-       gchar *plugin_instance;
+       const guint8 *plugin_instance;
        gint plugin_instance_off;
        gint plugin_instance_len;
-       gchar *type;
+       const guint8 *type;
        gint type_off;
        gint type_len;
-       gchar *type_instance;
+       const guint8 *type_instance;
        gint type_instance_off;
        gint type_instance_len;
 } value_data_t;
 
 typedef struct notify_data_s {
-       gchar *host;
+       const guint8 *host;
        gint host_off;
        gint host_len;
-       guint64 time;
+       guint64 time_value;
        gint time_off;
        guint64 severity;
        gint severity_off;
-       gchar *message;
+       const guint8 *message;
        gint message_off;
        gint message_len;
 } notify_data_t;
@@ -138,15 +124,14 @@ static const value_string valuetypenames[] = {
 #define SEVERITY_FAILURE  0x01
 #define SEVERITY_WARNING  0x02
 #define SEVERITY_OKAY     0x04
-static const value_string severity_names[] = {
+static const val64_string severity_names[] = {
        { SEVERITY_FAILURE,  "FAILURE" },
        { SEVERITY_WARNING,  "WARNING" },
        { SEVERITY_OKAY,     "OKAY" },
        { 0, NULL }
 };
 
-#define UDP_PORT_COLLECTD 25826
-static guint collectd_udp_port = UDP_PORT_COLLECTD;
+#define UDP_PORT_COLLECTD 25826 /* Not IANA registered */
 
 static gint proto_collectd             = -1;
 static gint tap_collectd                = -1;
@@ -194,13 +179,18 @@ static gint st_collectd_values_hosts   = -1;
 static gint st_collectd_values_plugins = -1;
 static gint st_collectd_values_types   = -1;
 
+static expert_field ei_collectd_type = EI_INIT;
+static expert_field ei_collectd_invalid_length = EI_INIT;
+static expert_field ei_collectd_data_valcnt = EI_INIT;
+static expert_field ei_collectd_garbage = EI_INIT;
+
 /* Prototype for the handoff function */
 void proto_reg_handoff_collectd (void);
 
 static nstime_t
 collectd_time_to_nstime (guint64 t)
 {
-       nstime_t nstime = { 0, 0 };
+       nstime_t nstime = NSTIME_INIT_ZERO;;
        nstime.secs = (time_t) (t / 1073741824);
        nstime.nsecs = (int) (((double) (t % 1073741824)) / 1.073741824);
 
@@ -210,8 +200,8 @@ collectd_time_to_nstime (guint64 t)
 static void
 collectd_stats_tree_init (stats_tree *st)
 {
-       st_collectd_packets = stats_tree_create_node (st, "Packets", 0, FALSE);
-       st_collectd_values = stats_tree_create_node (st, "Values", 0, TRUE);
+       st_collectd_packets = stats_tree_create_node (st, "Packets", 0, STAT_DT_INT, FALSE);
+       st_collectd_values = stats_tree_create_node (st, "Values", 0, STAT_DT_INT, TRUE);
 
        st_collectd_values_hosts = stats_tree_create_pivot (st, "By host",
                                                           st_collectd_values);
@@ -279,12 +269,10 @@ collectd_proto_tree_add_assembled_metric (tvbuff_t *tvb,
        proto_tree *subtree;
        nstime_t nstime;
 
-       root_item = proto_tree_add_text (root, tvb, offset + 6, length - 6,
-                       "Assembled metric");
+       subtree = proto_tree_add_subtree(root, tvb, offset + 6, length - 6,
+                       ett_collectd_dispatch, &root_item, "Assembled metric");
        PROTO_ITEM_SET_GENERATED (root_item);
 
-       subtree = proto_item_add_subtree (root_item, ett_collectd_dispatch);
-
        proto_tree_add_string (subtree, hf_collectd_data_host, tvb,
                        vdispatch->host_off, vdispatch->host_len,
                        STR_NONNULL (vdispatch->host));
@@ -311,7 +299,7 @@ collectd_proto_tree_add_assembled_metric (tvbuff_t *tvb,
                                vdispatch->type_instance_len,
                                vdispatch->type_instance);
 
-       nstime = collectd_time_to_nstime (vdispatch->time);
+       nstime = collectd_time_to_nstime (vdispatch->time_value);
        proto_tree_add_time (subtree, hf_collectd_data_time, tvb,
                        vdispatch->time_off, /* length = */ 8, &nstime);
 
@@ -329,17 +317,15 @@ collectd_proto_tree_add_assembled_notification (tvbuff_t *tvb,
        proto_tree *subtree;
        nstime_t nstime;
 
-       root_item = proto_tree_add_text (root, tvb, offset + 6, length - 6,
-                       "Assembled notification");
+       subtree = proto_tree_add_subtree(root, tvb, offset + 6, length - 6,
+                       ett_collectd_dispatch, &root_item, "Assembled notification");
        PROTO_ITEM_SET_GENERATED (root_item);
 
-       subtree = proto_item_add_subtree (root_item, ett_collectd_dispatch);
-
        proto_tree_add_string (subtree, hf_collectd_data_host, tvb,
                        ndispatch->host_off, ndispatch->host_len,
                        STR_NONNULL (ndispatch->host));
 
-       nstime = collectd_time_to_nstime (ndispatch->time);
+       nstime = collectd_time_to_nstime (ndispatch->time_value);
        proto_tree_add_time (subtree, hf_collectd_data_time, tvb,
                        ndispatch->time_off, /* length = */ 8, &nstime);
 
@@ -355,7 +341,7 @@ collectd_proto_tree_add_assembled_notification (tvbuff_t *tvb,
 static int
 dissect_collectd_string (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
                         gint offset, gint *ret_offset, gint *ret_length,
-                        gchar **ret_string, proto_tree *tree_root,
+                        const guint8 **ret_string, proto_tree *tree_root,
                         proto_item **ret_item)
 {
        proto_tree *pt;
@@ -375,13 +361,14 @@ dissect_collectd_string (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
        type   = tvb_get_ntohs(tvb, offset);
        length = tvb_get_ntohs(tvb, offset + 2);
 
+       pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                                 ett_collectd_string, &pi, "collectd %s segment: ",
+                                 val_to_str_const (type, part_names, "UNKNOWN"));
+
        if (length > size)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                         "collectd %s segment: Length = %i <BAD>",
-                                         val_to_str_const (type, part_names, "UNKNOWN"),
-                                         length);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
+               proto_item_append_text(pt, "Length = %i <BAD>", length);
+               expert_add_info_format(pinfo, pt, &ei_collectd_invalid_length,
                                        "String part with invalid part length: "
                                        "Part is longer than rest of package.");
                return (-1);
@@ -390,21 +377,15 @@ dissect_collectd_string (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
        *ret_offset = offset + 4;
        *ret_length = length - 4;
 
-       *ret_string = tvb_get_ephemeral_string (tvb, *ret_offset, *ret_length);
+       proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
+       proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
+       proto_tree_add_item_ret_string (pt, type_hf, tvb, *ret_offset, *ret_length, ENC_ASCII|ENC_NA, wmem_packet_scope(), ret_string);
 
-       pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                 "collectd %s segment: \"%s\"",
-                                 val_to_str_const (type, part_names, "UNKNOWN"),
-                                 *ret_string);
+       proto_item_append_text(pt, "\"%s\"", *ret_string);
 
        if (ret_item != NULL)
                *ret_item = pi;
 
-       pt = proto_item_add_subtree (pi, ett_collectd_string);
-       proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
-       proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
-       proto_tree_add_item (pt, type_hf, tvb, *ret_offset, *ret_length, ENC_ASCII|ENC_NA);
-
        return (0);
 } /* int dissect_collectd_string */
 
@@ -432,36 +413,32 @@ dissect_collectd_integer (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
 
        if (size < 12)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_integer, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_integer);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2,
                                     type);
                proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
                                     length);
-               pi = proto_tree_add_text (pt, tvb, offset + 4, -1,
+               proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
                                          "Garbage at end of packet: Length = %i <BAD>",
                                          size - 4);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
-                                       "Garbage at end of packet");
 
                return (-1);
        }
 
        if (length != 12)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_integer, &pi, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_integer);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2,
                                     type);
                pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
                                          offset + 2, 2, length);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
+               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                        "Invalid length field for an integer part.");
 
                return (-1);
@@ -483,9 +460,9 @@ dissect_collectd_integer (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
                gchar *strtime;
 
                nstime = collectd_time_to_nstime (*ret_value);
-               strtime = abs_time_to_str (&nstime, ABSOLUTE_TIME_LOCAL, /* show_zone = */ TRUE);
-               pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                         "collectd %s segment: %s",
+               strtime = abs_time_to_str (wmem_packet_scope(), &nstime, ABSOLUTE_TIME_LOCAL, /* show_zone = */ TRUE);
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                                         ett_collectd_integer, &pi, "collectd %s segment: %s",
                                          val_to_str_const (type, part_names, "UNKNOWN"),
                                          STR_NONNULL (strtime));
        }
@@ -495,16 +472,16 @@ dissect_collectd_integer (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
                gchar *strtime;
 
                nstime = collectd_time_to_nstime (*ret_value);
-               strtime = rel_time_to_str (&nstime);
-               pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                         "collectd %s segment: %s",
+               strtime = rel_time_to_str (wmem_packet_scope(), &nstime);
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                                         ett_collectd_integer, &pi, "collectd %s segment: %s",
                                          val_to_str_const (type, part_names, "UNKNOWN"),
                                          strtime);
        }
        else
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                         "collectd %s segment: %"G_GINT64_MODIFIER"u",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                                         ett_collectd_integer, &pi, "collectd %s segment: %"G_GINT64_MODIFIER"u",
                                          val_to_str_const (type, part_names, "UNKNOWN"),
                                          *ret_value);
        }
@@ -512,7 +489,6 @@ dissect_collectd_integer (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
        if (ret_item != NULL)
                *ret_item = pi;
 
-       pt = proto_item_add_subtree (pi, ett_collectd_integer);
        proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
        proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
                             length);
@@ -536,16 +512,13 @@ static void
 dissect_collectd_values(tvbuff_t *tvb, gint msg_off, gint val_cnt,
                        proto_tree *collectd_tree)
 {
-       proto_item *pi;
        proto_tree *values_tree, *value_tree;
        gint i;
 
-       pi = proto_tree_add_text (collectd_tree, tvb, msg_off + 6, val_cnt * 9,
-                                 "%d value%s", val_cnt,
+       values_tree = proto_tree_add_subtree_format(collectd_tree, tvb, msg_off + 6, val_cnt * 9,
+                                 ett_collectd_value, NULL, "%d value%s", val_cnt,
                                  plurality (val_cnt, "", "s"));
 
-       values_tree = proto_item_add_subtree (pi, ett_collectd_value);
-
        for (i = 0; i < val_cnt; i++)
        {
                gint value_offset;
@@ -567,12 +540,10 @@ dissect_collectd_values(tvbuff_t *tvb, gint msg_off, gint val_cnt,
                        guint64 val64;
 
                        val64 = tvb_get_ntoh64 (tvb, value_offset);
-                       pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
-                                                 val_cnt * 9,
+                       value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
+                                                 val_cnt * 9, ett_collectd_valinfo, NULL,
                                                  "Counter: %"G_GINT64_MODIFIER"u", val64);
 
-                       value_tree = proto_item_add_subtree (pi,
-                                       ett_collectd_valinfo);
                        proto_tree_add_item (value_tree, hf_collectd_val_type,
                                             tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
                        proto_tree_add_item (value_tree,
@@ -586,12 +557,10 @@ dissect_collectd_values(tvbuff_t *tvb, gint msg_off, gint val_cnt,
                        gdouble val;
 
                        val = tvb_get_letohieee_double (tvb, value_offset);
-                       pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
-                                                 val_cnt * 9,
+                       value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
+                                                 val_cnt * 9, ett_collectd_valinfo, NULL,
                                                  "Gauge: %g", val);
 
-                       value_tree = proto_item_add_subtree (pi,
-                                       ett_collectd_valinfo);
                        proto_tree_add_item (value_tree, hf_collectd_val_type,
                                             tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
                        /* Set the `little endian' flag to TRUE here, because
@@ -606,12 +575,10 @@ dissect_collectd_values(tvbuff_t *tvb, gint msg_off, gint val_cnt,
                        gint64 val64;
 
                        val64 = tvb_get_ntoh64 (tvb, value_offset);
-                       pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
-                                                 val_cnt * 9,
+                       value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
+                                                 val_cnt * 9, ett_collectd_valinfo, NULL,
                                                  "Derive: %"G_GINT64_MODIFIER"i", val64);
 
-                       value_tree = proto_item_add_subtree (pi,
-                                       ett_collectd_valinfo);
                        proto_tree_add_item (value_tree, hf_collectd_val_type,
                                             tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
                        proto_tree_add_item (value_tree,
@@ -625,12 +592,10 @@ dissect_collectd_values(tvbuff_t *tvb, gint msg_off, gint val_cnt,
                        guint64 val64;
 
                        val64 = tvb_get_ntoh64 (tvb, value_offset);
-                       pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
-                                                 val_cnt * 9,
+                       value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
+                                                 val_cnt * 9, ett_collectd_valinfo, NULL,
                                                  "Absolute: %"G_GINT64_MODIFIER"u", val64);
 
-                       value_tree = proto_item_add_subtree (pi,
-                                       ett_collectd_valinfo);
                        proto_tree_add_item (value_tree, hf_collectd_val_type,
                                             tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
                        proto_tree_add_item (value_tree,
@@ -644,13 +609,11 @@ dissect_collectd_values(tvbuff_t *tvb, gint msg_off, gint val_cnt,
                        guint64 val64;
 
                        val64 = tvb_get_ntoh64 (tvb, value_offset);
-                       pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
-                                                 val_cnt * 9,
+                       value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
+                                                 val_cnt * 9, ett_collectd_valinfo, NULL,
                                                  "Unknown: %"G_GINT64_MODIFIER"x",
                                                  val64);
 
-                       value_tree = proto_item_add_subtree (pi,
-                                       ett_collectd_valinfo);
                        proto_tree_add_item (value_tree, hf_collectd_val_type,
                                             tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
                        proto_tree_add_item (value_tree, hf_collectd_val_unknown,
@@ -686,34 +649,29 @@ dissect_collectd_part_values (tvbuff_t *tvb, packet_info *pinfo, gint offset,
 
        if (size < 15)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_part_value, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_part_value);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
                                     length);
-               pi = proto_tree_add_text (pt, tvb, offset + 4, -1,
+               proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
                                          "Garbage at end of packet: Length = %i <BAD>",
                                          size - 4);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
-                                       "Garbage at end of packet");
-
                return (-1);
        }
 
        if ((length < 15) || ((length % 9) != 6))
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_part_value, &pi, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_part_value);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
                                          offset + 2, 2, length);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
+               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                        "Invalid length field for a values part.");
 
                return (-1);
@@ -724,7 +682,8 @@ dissect_collectd_part_values (tvbuff_t *tvb, packet_info *pinfo, gint offset,
 
        if (values_count != corrected_values_count)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, length,
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                     ett_collectd_part_value, NULL,
                                          "collectd %s segment: %d (%d) value%s <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"),
                                          values_count, corrected_values_count,
@@ -732,23 +691,21 @@ dissect_collectd_part_values (tvbuff_t *tvb, packet_info *pinfo, gint offset,
        }
        else
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, length,
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                     ett_collectd_part_value, NULL,
                                          "collectd %s segment: %d value%s",
                                          val_to_str_const (type, part_names, "UNKNOWN"),
                                          values_count,
                                          plurality(values_count, "", "s"));
        }
 
-       pt = proto_item_add_subtree (pi, ett_collectd_part_value);
        proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
        proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
 
        pi = proto_tree_add_item (pt, hf_collectd_data_valcnt, tvb,
                                  offset + 4, 2, ENC_BIG_ENDIAN);
        if (values_count != corrected_values_count)
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_WARN,
-                                       "Number of values and length of part do not match. "
-                                       "Assuming length is correct.");
+               expert_add_info(pinfo, pi, &ei_collectd_data_valcnt);
 
        values_count = corrected_values_count;
 
@@ -782,44 +739,38 @@ dissect_collectd_signature (tvbuff_t *tvb, packet_info *pinfo,
 
        if (size < 36) /* remaining packet size too small for signature */
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_signature, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_signature);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
                                     length);
-               pi = proto_tree_add_text (pt, tvb, offset + 4, -1,
+               proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
                                          "Garbage at end of packet: Length = %i <BAD>",
                                          size - 4);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
-                                       "Garbage at end of packet");
-
                return (-1);
        }
 
        if (length < 36)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_signature, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_signature);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
                                          offset + 2, 2, length);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
+               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                        "Invalid length field for a signature part.");
 
                return (-1);
        }
 
-       pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                 "collectd %s segment: HMAC-SHA-256",
+       pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                                 ett_collectd_signature, NULL, "collectd %s segment: HMAC-SHA-256",
                                  val_to_str_const (type, part_names, "UNKNOWN"));
 
-       pt = proto_item_add_subtree (pi, ett_collectd_signature);
        proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
        proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
                             length);
@@ -853,34 +804,29 @@ dissect_collectd_encrypted (tvbuff_t *tvb, packet_info *pinfo,
 
        if (size < 42) /* remaining packet size too small for signature */
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_encryption, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_encryption);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
                                     length);
-               pi = proto_tree_add_text (pt, tvb, offset + 4, -1,
+               proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
                                          "Garbage at end of packet: Length = %i <BAD>",
                                          size - 4);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
-                                       "Garbage at end of packet");
-
                return (-1);
        }
 
        if (length < 42)
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_encryption, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_encryption);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
                                          offset + 2, 2, length);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
+               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                        "Invalid length field for an encryption part.");
 
                return (-1);
@@ -889,27 +835,25 @@ dissect_collectd_encrypted (tvbuff_t *tvb, packet_info *pinfo,
        username_length = tvb_get_ntohs (tvb, offset + 4);
        if (username_length > (length - 42))
        {
-               pi = proto_tree_add_text (tree_root, tvb, offset, -1,
-                                         "collectd %s segment: <BAD>",
+               pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
+                                         ett_collectd_encryption, NULL, "collectd %s segment: <BAD>",
                                          val_to_str_const (type, part_names, "UNKNOWN"));
 
-               pt = proto_item_add_subtree (pi, ett_collectd_encryption);
                proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
                proto_tree_add_uint (pt, hf_collectd_length, tvb,
                                     offset + 2, 2, length);
                pi = proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb,
                                          offset + 4, 2, length);
-               expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_ERROR,
+               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                        "Invalid username length field for an encryption part.");
 
                return (-1);
        }
 
-       pi = proto_tree_add_text (tree_root, tvb, offset, length,
-                                 "collectd %s segment: AES-256",
+       pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
+                                 ett_collectd_encryption, NULL, "collectd %s segment: AES-256",
                                  val_to_str_const (type, part_names, "UNKNOWN"));
 
-       pt = proto_item_add_subtree (pi, ett_collectd_encryption);
        proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
        proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
        proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb, offset + 4, 2, username_length);
@@ -941,8 +885,8 @@ stats_account_string (string_counter_t **ret_list, const gchar *new_value)
                        return (0);
                }
 
-       entry = (string_counter_t *)ep_alloc0 (sizeof (*entry));
-       entry->string = ep_strdup (new_value);
+       entry = (string_counter_t *)wmem_alloc0 (wmem_packet_scope(), sizeof (*entry));
+       entry->string = wmem_strdup (wmem_packet_scope(), new_value);
        entry->count = 1;
        entry->next = *ret_list;
 
@@ -951,14 +895,14 @@ stats_account_string (string_counter_t **ret_list, const gchar *new_value)
        return (0);
 }
 
-static void
-dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
 {
        static tap_data_t tap_data;
 
        gint offset;
        gint size;
-       gchar *pkt_host = NULL;
+       const guint8 *pkt_host = NULL;
        gint pkt_plugins = 0, pkt_values = 0, pkt_messages = 0, pkt_unknown = 0, pkt_errors = 0;
        value_data_t vdispatch;
        notify_data_t ndispatch;
@@ -1015,8 +959,8 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
                        switch (part_type) {
                        case TYPE_HOST:
-                               vdispatch.host = tvb_get_ephemeral_string (tvb,
-                                               offset + 4, part_length - 4);
+                               vdispatch.host = tvb_get_string_enc(wmem_packet_scope(), tvb,
+                                               offset + 4, part_length - 4, ENC_ASCII);
                                if (pkt_host == NULL)
                                        pkt_host = vdispatch.host;
                                break;
@@ -1024,15 +968,15 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        case TYPE_TIME_HR:
                                break;
                        case TYPE_PLUGIN:
-                               vdispatch.plugin = tvb_get_ephemeral_string (tvb,
-                                               offset + 4, part_length - 4);
+                               vdispatch.plugin = tvb_get_string_enc(wmem_packet_scope(), tvb,
+                                               offset + 4, part_length - 4, ENC_ASCII);
                                pkt_plugins++;
                                break;
                        case TYPE_PLUGIN_INSTANCE:
                                break;
                        case TYPE_TYPE:
-                               vdispatch.type = tvb_get_ephemeral_string (tvb,
-                                               offset + 4, part_length - 4);
+                               vdispatch.type = tvb_get_string_enc(wmem_packet_scope(), tvb,
+                                               offset + 4, part_length - 4, ENC_ASCII);
                                break;
                        case TYPE_TYPE_INSTANCE:
                                break;
@@ -1075,13 +1019,10 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                 * at the end of the packet. */
                if (size < 4)
                {
-                       pi = proto_tree_add_text (collectd_tree, tvb,
+                       proto_tree_add_expert_format(pi, pinfo, &ei_collectd_garbage, tvb,
                                                  offset, -1,
                                                  "Garbage at end of packet: Length = %i <BAD>",
                                                  size);
-                       expert_add_info_format (pinfo, pi, PI_MALFORMED,
-                                               PI_ERROR,
-                                               "Garbage at end of packet");
                        pkt_errors++;
                        break;
                }
@@ -1095,26 +1036,23 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                 * provided in the packet.. */
                if ((part_length < 4) || (part_length > size))
                {
-                       pi = proto_tree_add_text (collectd_tree, tvb,
-                                                 offset, part_length,
+                       pt = proto_tree_add_subtree_format(collectd_tree, tvb,
+                                                 offset, part_length, ett_collectd_invalid_length, NULL,
                                                  "collectd %s segment: Length = %i <BAD>",
                                                  val_to_str_const (part_type, part_names, "UNKNOWN"),
                                                  part_length);
 
-                       pt = proto_item_add_subtree (pi, ett_collectd_invalid_length);
                        proto_tree_add_uint (pt, hf_collectd_type, tvb, offset,
                                             2, part_type);
                        pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
                                             offset + 2, 2, part_length);
 
                        if (part_length < 4)
-                               expert_add_info_format (pinfo, pi,
-                                                       PI_MALFORMED, PI_ERROR,
+                               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                                        "Bad part length: Is %i, expected at least 4",
                                                        part_length);
                        else
-                               expert_add_info_format (pinfo, pi,
-                                                       PI_MALFORMED, PI_ERROR,
+                               expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
                                                        "Bad part length: Larger than remaining packet size.");
 
                        pkt_errors++;
@@ -1217,7 +1155,7 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                                        hf_collectd_data_time,
                                        offset,
                                        &vdispatch.time_off,
-                                       &vdispatch.time,
+                                       &vdispatch.time_value,
                                        collectd_tree, &pi);
                        if (status != 0)
                                pkt_errors++;
@@ -1304,7 +1242,7 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                                proto_item_set_text (pi,
                                                "collectd SEVERITY segment: "
                                                "%s (%"G_GINT64_MODIFIER"u)",
-                                               val_to_str_const ((gint32)ndispatch.severity, severity_names, "UNKNOWN"),
+                                               val64_to_str_const (ndispatch.severity, severity_names, "UNKNOWN"),
                                                ndispatch.severity);
                        }
 
@@ -1335,13 +1273,12 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                default:
                {
                        pkt_unknown++;
-                       pi = proto_tree_add_text (collectd_tree, tvb,
-                                                 offset, part_length,
+                       pt = proto_tree_add_subtree_format(collectd_tree, tvb,
+                                                 offset, part_length, ett_collectd_unknown, NULL,
                                                  "collectd %s segment: %i bytes",
                                                  val_to_str_const(part_type, part_names, "UNKNOWN"),
                                                  part_length);
 
-                       pt = proto_item_add_subtree(pi, ett_collectd_unknown);
                        pi = proto_tree_add_uint (pt, hf_collectd_type, tvb,
                                                  offset, 2, part_type);
                        proto_tree_add_uint (pt, hf_collectd_length, tvb,
@@ -1349,8 +1286,7 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        proto_tree_add_item (pt, hf_collectd_data, tvb,
                                             offset + 4, part_length - 4, ENC_NA);
 
-                       expert_add_info_format (pinfo, pi,
-                                               PI_UNDECODED, PI_NOTE,
+                       expert_add_info_format(pinfo, pi, &ei_collectd_type,
                                                "Unknown part type %#x. Cannot decode data.",
                                                part_type);
                }
@@ -1393,11 +1329,12 @@ dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
        /* Dispatch tap data. */
        tap_queue_packet (tap_collectd, pinfo, &tap_data);
+       return tvb_captured_length(tvb);
 } /* void dissect_collectd */
 
 void proto_register_collectd(void)
 {
-       module_t *collectd_module;
+       expert_module_t* expert_collectd;
 
        /* Setup list of header fields */
        static hf_register_info hf[] = {
@@ -1470,8 +1407,8 @@ void proto_register_collectd(void)
                                NULL, 0x0, NULL, HFILL }
                },
                { &hf_collectd_data_severity,
-                       { "Severity", "collectd.data.severity", FT_UINT64, BASE_HEX,
-                               VALS(severity_names),
+                       { "Severity", "collectd.data.severity", FT_UINT64, BASE_HEX | BASE_VAL64_STRING,
+                               VALS64(severity_names),
                                0x0, NULL, HFILL }
                },
                { &hf_collectd_data_message,
@@ -1515,50 +1452,44 @@ void proto_register_collectd(void)
                &ett_collectd_unknown,
        };
 
+       static ei_register_info ei[] = {
+               { &ei_collectd_invalid_length, { "collectd.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
+               { &ei_collectd_garbage, { "collectd.garbage", PI_MALFORMED, PI_ERROR, "Garbage at end of packet", EXPFILL }},
+               { &ei_collectd_data_valcnt, { "collectd.data.valcnt.mismatch", PI_MALFORMED, PI_WARN, "Number of values and length of part do not match. Assuming length is correct.", EXPFILL }},
+               { &ei_collectd_type, { "collectd.type.unknown", PI_UNDECODED, PI_NOTE, "Unknown part type", EXPFILL }},
+       };
+
        /* Register the protocol name and description */
-       proto_collectd = proto_register_protocol("collectd network data",
-                                                "collectd", "collectd");
+       proto_collectd = proto_register_protocol("collectd network data", "collectd", "collectd");
 
        /* Required function calls to register the header fields and subtrees used */
        proto_register_field_array(proto_collectd, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
+       expert_collectd = expert_register_protocol(proto_collectd);
+       expert_register_field_array(expert_collectd, ei, array_length(ei));
 
        tap_collectd = register_tap ("collectd");
-
-       /*
-        * Create an unsigned integer preference to allow the user to specify the
-        * UDP port on which to capture DIS packets.
-        */
-       collectd_module = prefs_register_protocol (proto_collectd,
-                                                  proto_reg_handoff_collectd);
-
-       prefs_register_uint_preference (collectd_module, "udp.port",
-                                       "collectd UDP port",
-                                       "Set the UDP port for collectd messages",
-                                       10, &collectd_udp_port);
-} /* void proto_register_collectd */
+}
 
 void proto_reg_handoff_collectd (void)
 {
-       static gboolean first_run = TRUE;
-       static gint registered_udp_port = -1;
-       static dissector_handle_t collectd_handle;
-
-       if (first_run)
-               collectd_handle = create_dissector_handle (dissect_collectd,
-                                                          proto_collectd);
-
-       /* Change the dissector registration if the preferences have been
-        * changed. */
-       if (registered_udp_port != -1)
-               dissector_delete_uint ("udp.port", registered_udp_port,
-                                 collectd_handle);
-
-       dissector_add_uint ("udp.port", collectd_udp_port, collectd_handle);
-       registered_udp_port = collectd_udp_port;
+       dissector_handle_t collectd_handle;
 
-       if (first_run)
-               collectd_stats_tree_register ();
+       collectd_handle = create_dissector_handle(dissect_collectd, proto_collectd);
+       dissector_add_uint_with_preference("udp.port", UDP_PORT_COLLECTD, collectd_handle);
 
-       first_run = FALSE;
+       collectd_stats_tree_register ();
 } /* void proto_reg_handoff_collectd */
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */