X-Git-Url: http://git.samba.org/?p=metze%2Fwireshark%2Fwip.git;a=blobdiff_plain;f=epan%2Fproto.c;h=21471f08edba5cbb51bfd57c28ce9b9d65fde6d3;hp=92004047ca3930335b4ec4f1db4c000734fb840a;hb=238550b9c5aad47448cc5ac537108ee23125a252;hpb=51a30142251e377ec28eb8584c56386c2481d6c0 diff --git a/epan/proto.c b/epan/proto.c index 92004047ca..21471f08ed 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -5,19 +5,7 @@ * By Gerald Combs * 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 #include #include +#include #include @@ -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 #include /* ws_debug_printf/ws_g_warning */ +#include /* 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)); }