*
* $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "ptvcursor.h"
#include "strutil.h"
#include "addr_resolv.h"
-#include "oid_resolv.h"
+#include "oids.h"
#include "plugins.h"
#include "proto.h"
#include "epan_dissect.h"
#include "slab.h"
#include "tvbuff.h"
#include "emem.h"
+#include "charsets.h"
+#include "asm_utils.h"
+#include "column-utils.h"
+
+#ifdef NEED_G_ASCII_STRCASECMP_H
+#include "g_ascii_strcasecmp.h"
+#endif
+
+#define SUBTREE_ONCE_ALLOCATION_NUMBER 8
+#define SUBTREE_MAX_LEVELS 256
+
+
+typedef struct __subtree_lvl {
+ gint cursor_offset;
+ proto_item * it;
+ proto_tree * tree;
+}subtree_lvl;
struct ptvcursor {
+ subtree_lvl *pushed_tree;
+ guint8 pushed_tree_index;
+ guint8 pushed_tree_max;
proto_tree *tree;
tvbuff_t *tvb;
gint offset;
};
+/* Candidates for assembler */
+int
+wrs_count_bitshift(guint32 bitmask)
+{
+ int bitshift = 0;
+
+ while ((bitmask & (1 << bitshift)) == 0)
+ bitshift++;
+ return bitshift;
+}
+
+
+
+#if GLIB_MAJOR_VERSION < 2
+static void *discard_const(const void *const_ptr)
+{
+ union {
+ const void *const_ptr;
+ void *ptr;
+ } stupid_const;
+
+ stupid_const.const_ptr = const_ptr;
+
+ return stupid_const.ptr;
+}
+#endif
+
#define cVALS(x) (const value_string*)(x)
#if 1
or else filtering will not work (they would be ignored since tree\
would be NULL). \
DONT try to fake a node where PITEM_FINFO(pi) is NULL \
- since dissectors that want to do proto_item_set_len() ot \
+ since dissectors that want to do proto_item_set_len() or \
other operations that dereference this would crash. \
We dont fake FT_PROTOCOL either since these are cheap and \
some stuff (proto hier stat) assumes they always exist. \
int hfinfo_bitwidth(header_field_info *hfinfo);
static const char* hfinfo_uint_vals_format(header_field_info *hfinfo);
static const char* hfinfo_uint_format(header_field_info *hfinfo);
+static const char* hfinfo_uint_value_format(header_field_info *hfinfo);
static const char* hfinfo_uint64_format(header_field_info *hfinfo);
static const char* hfinfo_int_vals_format(header_field_info *hfinfo);
static const char* hfinfo_int_format(header_field_info *hfinfo);
+static const char* hfinfo_int_value_format(header_field_info *hfinfo);
static const char* hfinfo_int64_format(header_field_info *hfinfo);
static proto_item*
static void
proto_tree_set_time(field_info *fi, nstime_t *value_ptr);
static void
-proto_tree_set_string(field_info *fi, const char* value, gboolean);
+proto_tree_set_string(field_info *fi, const char* value);
static void
proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
static void
+proto_tree_set_ebcdic_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
+static void
proto_tree_set_ether(field_info *fi, const guint8* value);
static void
proto_tree_set_ether_tvb(field_info *fi, tvbuff_t *tvb, gint start);
static void
proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start);
static void
-proto_tree_set_guid(field_info *fi, const guint8* value_ptr);
+proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr);
static void
-proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start);
+proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian);
static void
proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length);
static void
static void
proto_tree_set_uint64(field_info *fi, guint64 value);
static void
-proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian);
+proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, gboolean little_endian);
static int proto_register_field_init(header_field_info *hfinfo, int parent);
-/* Comparision function for tree insertion. A wrapper around strcmp() */
-static int g_strcmp(gconstpointer a, gconstpointer b);
-
/* special-case header field used within proto.c */
int hf_text_only = -1;
#define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \
DISSECTOR_ASSERT((guint)hfindex < gpa_hfinfo.len); \
- hfinfo=gpa_hfinfo.hfi[hfindex];
+ hfinfo=gpa_hfinfo.hfi[hfindex];
/* List which stores protocols and fields that have been registered */
/* Balanced tree of abbreviations and IDs */
static GTree *gpa_name_tree = NULL;
+static header_field_info *same_name_hfinfo;
+
+#if GLIB_MAJOR_VERSION >= 2
+static void save_same_name_hfinfo(gpointer data)
+{
+ same_name_hfinfo = (header_field_info*)data;
+}
+#endif
/* Points to the first element of an array of Booleans, indexed by
a subtree item type; that array element is TRUE if subtrees of
const protocol_t *p1 = p1_arg;
const protocol_t *p2 = p2_arg;
- return g_strcasecmp(p1->short_name, p2->short_name);
+ return g_ascii_strcasecmp(p1->short_name, p2->short_name);
}
/* initialize data structures and register protocols and fields */
void
-proto_init(const char *plugin_dir
-#ifndef HAVE_PLUGINS
- _U_
-#endif
- ,
- void (register_all_protocols)(void),
- void (register_all_protocol_handoffs)(void))
+proto_init(void (register_all_protocols)(register_cb cb, gpointer client_data),
+ void (register_all_protocol_handoffs)(register_cb cb, gpointer client_data),
+ register_cb cb,
+ gpointer client_data)
{
static hf_register_info hf[] = {
{ &hf_text_only,
- { "", "", FT_NONE, BASE_NONE, NULL, 0x0,
+ { "Text item", "", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
};
- proto_names = g_hash_table_new(g_int_hash, g_int_equal);
- proto_short_names = g_hash_table_new(g_int_hash, g_int_equal);
- proto_filter_names = g_hash_table_new(g_int_hash, g_int_equal);
+ proto_names = g_hash_table_new(g_int_hash, g_int_equal);
+ 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_cleanup();
gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
sizeof(header_field_info),
- INITIAL_NUM_PROTOCOL_HFINFO * sizeof(header_field_info),
- G_ALLOC_ONLY);
+ INITIAL_NUM_PROTOCOL_HFINFO * sizeof(header_field_info),
+ G_ALLOC_ONLY);
gpa_hfinfo.len=0;
gpa_hfinfo.allocated_len=0;
gpa_hfinfo.hfi=NULL;
- gpa_name_tree = g_tree_new(g_strcmp);
+#if GLIB_MAJOR_VERSION < 2
+ gpa_name_tree = g_tree_new(wrs_strcmp);
+#else
+ gpa_name_tree = g_tree_new_full(wrs_strcmp_with_data, NULL, NULL, save_same_name_hfinfo);
+#endif
/* Initialize the ftype subsystem */
ftypes_initialize();
/* Register one special-case FT_TEXT_ONLY field for use when
- converting ethereal to new-style proto_tree. These fields
+ converting wireshark to new-style proto_tree. These fields
are merely strings on the GUI tree; they are not filterable */
proto_register_field_array(-1, hf, array_length(hf));
dissector tables, and dissectors to be called through a
handle, and do whatever one-time initialization it needs to
do. */
- register_all_protocols();
+ register_all_protocols(cb, client_data);
#ifdef HAVE_PLUGINS
/* Now scan for plugins and load all the ones we find, calling
their register routines to do the stuff described above. */
- init_plugins(plugin_dir);
+ if(cb)
+ (*cb)(RA_PLUGIN_REGISTER, NULL, client_data);
+ init_plugins();
+ register_all_plugin_registrations();
#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_protocol_handoffs();
+ register_all_protocol_handoffs(cb, client_data);
#ifdef HAVE_PLUGINS
/* Now do the same with plugins. */
+ if(cb)
+ (*cb)(RA_PLUGIN_HANDOFF, NULL, client_data);
register_all_plugin_handoffs();
#endif
- /* sort the protocols by protocol name */
- protocols = g_list_sort(protocols, proto_compare_name);
+ /* sort the protocols by protocol name */
+ protocols = g_list_sort(protocols, proto_compare_name);
/* We've assigned all the subtree type values; allocate the array
for them, and zero it out. */
memset(tree_is_expanded, 0, num_tree_types*sizeof (gboolean));
}
-/* String comparison func for dfilter_token GTree */
-static int
-g_strcmp(gconstpointer a, gconstpointer b)
-{
- return strcmp((const char*)a, (const char*)b);
-}
-
void
proto_cleanup(void)
{
}
-typedef gboolean (*proto_tree_traverse_func)(proto_node *, gpointer);
-
static gboolean
proto_tree_traverse_pre_order(proto_tree *tree, proto_tree_traverse_func func,
gpointer data)
return FALSE;
}
-static gboolean
+gboolean
proto_tree_traverse_in_order(proto_tree *tree, proto_tree_traverse_func func,
gpointer data)
{
}
static void
-free_GPtrArray_value(gpointer key _U_, gpointer value, gpointer user_data _U_)
+free_GPtrArray_value(gpointer key, gpointer value, gpointer user_data _U_)
{
GPtrArray *ptrs = value;
- gint hfid = (gint)key;
+ gint hfid = (gint)(long)key;
header_field_info *hfinfo;
-
+
PROTO_REGISTRAR_GET_NTH(hfid, hfinfo);
if(hfinfo->ref_count){
- /* when a field is referenced by a filter this also
+ /* when a field is referenced by a filter this also
affects the refcount for the parent protocol so we need
to adjust the refcount for the parent as well
*/
/* Assume dissector set only its protocol fields.
This function is called by dissectors and allowes to speed up filtering
- in ethereal, if this function returns FALSE it is safe to reset tree to NULL
+ in wireshark, if this function returns FALSE it is safe to reset tree to NULL
and thus skip calling most of the expensive proto_tree_add_...()
functions.
If the tree is visible we implicitely assume the field is referenced.
proto_registrar_get_byname(const char *field_name)
{
DISSECTOR_ASSERT(field_name != NULL);
+#if GLIB_MAJOR_VERSION < 2
+ return g_tree_lookup(gpa_name_tree, discard_const(field_name));
+#else
return g_tree_lookup(gpa_name_tree, field_name);
+#endif
+}
+
+
+void ptvcursor_new_subtree_levels(ptvcursor_t * ptvc)
+{
+ subtree_lvl * pushed_tree;
+
+ DISSECTOR_ASSERT(ptvc->pushed_tree_max <= SUBTREE_MAX_LEVELS-SUBTREE_ONCE_ALLOCATION_NUMBER);
+ ptvc->pushed_tree_max += SUBTREE_ONCE_ALLOCATION_NUMBER;
+
+ pushed_tree = ep_alloc(sizeof(subtree_lvl) * ptvc->pushed_tree_max);
+ DISSECTOR_ASSERT(pushed_tree != NULL);
+ if (ptvc->pushed_tree)
+ memcpy(pushed_tree, ptvc->pushed_tree, ptvc->pushed_tree_max - SUBTREE_ONCE_ALLOCATION_NUMBER);
+ ptvc->pushed_tree = pushed_tree;
+}
+
+void ptvcursor_free_subtree_levels(ptvcursor_t * ptvc)
+{
+ ptvc->pushed_tree = NULL;
+ ptvc->pushed_tree_max = 0;
+ DISSECTOR_ASSERT(ptvc->pushed_tree_index ==0);
+ ptvc->pushed_tree_index = 0;
}
/* Allocates an initializes a ptvcursor_t with 3 variables:
{
ptvcursor_t *ptvc;
- ptvc = g_new(ptvcursor_t, 1);
+ ptvc = ep_alloc(sizeof(ptvcursor_t));
ptvc->tree = tree;
ptvc->tvb = tvb;
ptvc->offset = offset;
+ ptvc->pushed_tree= NULL;
+ ptvc->pushed_tree_max= 0;
+ ptvc->pushed_tree_index= 0;
return ptvc;
}
+
/* Frees memory for ptvcursor_t, but nothing deeper than that. */
void
ptvcursor_free(ptvcursor_t *ptvc)
{
- g_free(ptvc);
+ ptvcursor_free_subtree_levels(ptvc);
+ /*g_free(ptvc);*/
}
/* Returns tvbuff. */
proto_tree*
ptvcursor_tree(ptvcursor_t* ptvc)
{
- return ptvc->tree;
+ if (!ptvc)
+ return NULL;
+
+ return ptvc->tree;
}
void
ptvc->tree = tree;
}
+/* creates a subtree, sets it as the working tree and pushes the old working tree */
+proto_tree*
+ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree)
+{
+ subtree_lvl * subtree;
+ if (ptvc->pushed_tree_index >= ptvc->pushed_tree_max)
+ ptvcursor_new_subtree_levels(ptvc);
+
+ subtree = ptvc->pushed_tree+ptvc->pushed_tree_index;
+ subtree->tree = ptvc->tree;
+ subtree->it= NULL;
+ ptvc->pushed_tree_index++;
+ return ptvcursor_set_subtree(ptvc, it, ett_subtree);
+}
+
+/* pops a subtree */
+void
+ptvcursor_pop_subtree(ptvcursor_t *ptvc)
+{
+ subtree_lvl * subtree;
+ if (ptvc->pushed_tree_index <= 0)
+ return;
+
+ ptvc->pushed_tree_index--;
+ subtree = ptvc->pushed_tree+ptvc->pushed_tree_index;
+ if (subtree->it != NULL)
+ proto_item_set_len(subtree->it, ptvcursor_current_offset(ptvc) - subtree->cursor_offset);
+ ptvc->tree = subtree->tree;
+}
+
+/* saves the current tvb offset and the item in the current subtree level */
+void ptvcursor_subtree_set_item(ptvcursor_t * ptvc, proto_item * it)
+{
+ subtree_lvl * subtree;
+
+ DISSECTOR_ASSERT(ptvc->pushed_tree_index > 0);
+
+ subtree = ptvc->pushed_tree+ptvc->pushed_tree_index-1;
+ subtree->it = it;
+ subtree->cursor_offset = ptvcursor_current_offset(ptvc);
+}
+
+/* Creates a subtree and adds it to the cursor as the working tree but does not
+ * save the old working tree */
+proto_tree*
+ptvcursor_set_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree)
+{
+ ptvc->tree = proto_item_add_subtree(it, ett_subtree);
+ return ptvc->tree;
+}
+
+proto_tree* ptvcursor_add_subtree_item(ptvcursor_t * ptvc, proto_item * it, gint ett_subtree, gint length)
+{
+ ptvcursor_push_subtree(ptvc, it, ett_subtree);
+ if (length == SUBTREE_UNDEFINED_LENGTH)
+ ptvcursor_subtree_set_item(ptvc, it);
+ return ptvcursor_tree(ptvc);
+}
+
+/* Add an item to the tree and create a subtree
+ * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH.
+ * In this case, when the subtree will be closed, the parent item length will
+ * be equal to the advancement of the cursor since the creation of the subtree.
+ */
+proto_tree* ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length,
+gboolean little_endian, gint ett_subtree)
+{
+ proto_item * it;
+ it = ptvcursor_add_no_advance(ptvc, hfindex, length, little_endian);
+ return ptvcursor_add_subtree_item(ptvc, it, ett_subtree, length);
+}
+
+static proto_item *
+proto_tree_add_text_node(proto_tree *tree, tvbuff_t *tvb, gint start, gint length);
+
+/* Add a text node to the tree and create a subtree
+ * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH.
+ * In this case, when the subtree will be closed, the item length will be equal
+ * to the advancement of the cursor since the creation of the subtree.
+ */
+proto_tree * ptvcursor_add_text_with_subtree(ptvcursor_t * ptvc, gint length,
+ gint ett_subtree, const char *format, ...)
+{
+ proto_item * it;
+ va_list ap;
+
+ it = proto_tree_add_text_node(ptvcursor_tree(ptvc), ptvcursor_tvbuff(ptvc),
+ ptvcursor_current_offset(ptvc), length);
+
+ va_start(ap, format);
+ proto_tree_set_representation(it, format, ap);
+ va_end(ap);
+
+ return ptvcursor_add_subtree_item(ptvc, it, ett_subtree, length);
+}
+
/* Add a text-only node, leaving it to our caller to fill the text in */
static proto_item *
proto_tree_add_text_node(proto_tree *tree, tvbuff_t *tvb, gint start, gint length)
va_list ap;
pi = proto_tree_add_text_node(tree, NULL, 0, 0);
- if (pi == NULL)
- return(NULL);
va_start(ap, format);
- proto_tree_set_representation(pi, format, ap);
+ if (pi)
+ proto_tree_set_representation(pi, format, ap);
vprintf(format, ap);
va_end(ap);
printf("\n");
break;
default:
- THROW(ReportedBoundsError);
+ DISSECTOR_ASSERT_NOT_REACHED();
value = 0;
break;
}
break;
default:
- THROW(ReportedBoundsError);
+ DISSECTOR_ASSERT_NOT_REACHED();
value = 0;
break;
}
case FT_INT64:
case FT_UINT64:
- DISSECTOR_ASSERT(length == 8);
- proto_tree_set_uint64_tvb(new_fi, tvb, start, little_endian);
+ DISSECTOR_ASSERT( length <= 8 && length >= 1);
+ proto_tree_set_uint64_tvb(new_fi, tvb, start, length, little_endian);
break;
/* XXX - make these just FT_INT? */
case FT_GUID:
DISSECTOR_ASSERT(length == 16);
- proto_tree_set_guid_tvb(new_fi, tvb, start);
+ proto_tree_set_guid_tvb(new_fi, tvb, start, little_endian);
break;
case FT_OID:
break;
case FT_STRING:
- /* This g_strdup'ed memory is freed in proto_tree_free_node() */
proto_tree_set_string_tvb(new_fi, tvb, start, length);
break;
/* This can throw an exception */
length = tvb_strsize(tvb, start);
- /* This g_malloc'ed memory is freed
- in proto_tree_free_node() */
- string = g_malloc(length);
+ string = ep_alloc(length);
tvb_memcpy(tvb, string, start, length);
} else if (length == 0) {
- string = g_strdup("[Empty]");
+ string = "[Empty]";
} else {
/* In this case, length signifies
* the length of the string.
* we made string values counted
* rather than null-terminated.)
*/
-
- /* This g_malloc'ed memory is freed
- * in proto_tree_free_node() */
- string = tvb_get_string(tvb, start,
- length);
+ string = tvb_get_ephemeral_string(tvb,
+ start,
+ length);
}
new_fi->length = length;
- proto_tree_set_string(new_fi, string, TRUE);
+ proto_tree_set_string(new_fi, string);
+ break;
+
+ case FT_EBCDIC:
+ proto_tree_set_ebcdic_string_tvb(new_fi, tvb, start, length);
break;
case FT_UINT_STRING:
- /* This g_strdup'ed memory is freed in proto_tree_free_node() */
n = get_uint_value(tvb, start, length, little_endian);
proto_tree_set_string_tvb(new_fi, tvb, start + length, n);
/* If the proto_tree wants to keep a record of this finfo
* for quick lookup, then record it. */
if (new_fi->hfinfo->ref_count) {
+ /*HERE*/
hash = PTREE_DATA(tree)->interesting_hfids;
ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
if (ptrs) {
if (length > 0) {
g_byte_array_append(bytes, start_ptr, length);
}
+ col_custom_set_fstr(fi->hfinfo, "%s", bytes_to_str(bytes->data,
+ length));
fvalue_set(&fi->value, bytes, TRUE);
}
static void
proto_tree_set_time(field_info *fi, nstime_t *value_ptr)
{
+ header_field_info *hfinfo;
+
DISSECTOR_ASSERT(value_ptr != NULL);
+ hfinfo = fi->hfinfo;
+
+ if (hfinfo->type == FT_ABSOLUTE_TIME) {
+ col_custom_set_fstr(fi->hfinfo, "%s", abs_time_to_str(value_ptr));
+ } else if (hfinfo->type == FT_RELATIVE_TIME) {
+ col_custom_set_fstr(fi->hfinfo, "%s", rel_time_to_secs_str(value_ptr));
+ }
fvalue_set(&fi->value, value_ptr, FALSE);
}
static void
proto_tree_set_ipxnet(field_info *fi, guint32 value)
{
- fvalue_set_integer(&fi->value, value);
+ fvalue_set_uinteger(&fi->value, value);
}
/* Add a FT_IPv4 to a proto_tree */
static void
proto_tree_set_ipv4(field_info *fi, guint32 value)
{
- fvalue_set_integer(&fi->value, value);
+ col_custom_set_fstr(fi->hfinfo, "%s",
+ ip_to_str((guint8 *)&value));
+ fvalue_set_uinteger(&fi->value, value);
}
/* Add a FT_IPv6 to a proto_tree */
/* Add a FT_GUID to a proto_tree */
proto_item *
proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
- const guint8* value_ptr)
+ const e_guid_t *value_ptr)
{
proto_item *pi;
field_info *new_fi;
proto_item *
proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
- const guint8* value_ptr)
+ const e_guid_t *value_ptr)
{
proto_item *pi;
proto_item *
proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
- gint start, gint length, const guint8* value_ptr,
+ gint start, gint length, const e_guid_t *value_ptr,
const char *format, ...)
{
proto_item *pi;
proto_item *
proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
- const guint8* value_ptr, const char *format, ...)
+ const e_guid_t *value_ptr, const char *format, ...)
{
proto_item *pi;
va_list ap;
/* Set the FT_GUID value */
static void
-proto_tree_set_guid(field_info *fi, const guint8* value_ptr)
+proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr)
{
DISSECTOR_ASSERT(value_ptr != NULL);
+ col_custom_set_fstr(fi->hfinfo, "%s",
+ guid_to_str(value_ptr));
fvalue_set(&fi->value, (gpointer) value_ptr, FALSE);
}
static void
-proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start)
+proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian)
{
- proto_tree_set_guid(fi, tvb_get_ptr(tvb, start, 16));
+ e_guid_t guid;
+
+ tvb_get_guid(tvb, start, &guid, little_endian);
+ proto_tree_set_guid(fi, &guid);
}
/* Add a FT_OID to a proto_tree */
if (length > 0) {
g_byte_array_append(bytes, value_ptr, length);
}
+ col_custom_set_fstr(fi->hfinfo, "%s",
+ oid_resolved_from_encoded(value_ptr, length));
fvalue_set(&fi->value, bytes, TRUE);
}
static void
proto_tree_set_uint64(field_info *fi, guint64 value)
{
+ col_custom_set_fstr(fi->hfinfo, "%" G_GINT64_MODIFIER "u",
+ value);
fvalue_set_integer64(&fi->value, value);
}
static void
-proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian)
-{
- guint64 value;
-
- value = little_endian ? tvb_get_letoh64(tvb, start)
- : tvb_get_ntoh64(tvb, start);
+proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, gboolean little_endian)
+{
+ guint64 value = 0;
+ guint8* b = ep_tvb_memdup(tvb,start,length);
+
+ if(little_endian) {
+ b += length;
+ switch(length) {
+ default: DISSECTOR_ASSERT_NOT_REACHED();
+ case 8: value <<= 8; value += *--b;
+ case 7: value <<= 8; value += *--b;
+ case 6: value <<= 8; value += *--b;
+ case 5: value <<= 8; value += *--b;
+ case 4: value <<= 8; value += *--b;
+ case 3: value <<= 8; value += *--b;
+ case 2: value <<= 8; value += *--b;
+ case 1: value <<= 8; value += *--b;
+ break;
+ }
+ } else {
+ switch(length) {
+ default: DISSECTOR_ASSERT_NOT_REACHED();
+ case 8: value <<= 8; value += *b++;
+ case 7: value <<= 8; value += *b++;
+ case 6: value <<= 8; value += *b++;
+ case 5: value <<= 8; value += *b++;
+ case 4: value <<= 8; value += *b++;
+ case 3: value <<= 8; value += *b++;
+ case 2: value <<= 8; value += *b++;
+ case 1: value <<= 8; value += *b++;
+ break;
+ }
+ }
proto_tree_set_uint64(fi, value);
}
pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
DISSECTOR_ASSERT(length >= 0);
- proto_tree_set_string(new_fi, value, FALSE);
+ proto_tree_set_string(new_fi, value);
return pi;
}
* field info update instead of only updating the representation as does
* proto_item_append_text()
*/
-/* NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM()
+/* NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM()
* speed optimization.
- * Currently only WSP use this function so it is not that bad but try to
+ * Currently only WSP use this function so it is not that bad but try to
* avoid using this one if possible.
- * IF you must use this function you MUST also disable the
+ * IF you must use this function you MUST also disable the
* TRY_TO_FAKE_THIS_ITEM() optimization for your dissector/function
* using proto_item_append_string().
- * Do that by faking that the tree is visible by setting :
- * PTREE_DATA(tree)->visible=1; (see packet-wsp.c)
+ * Do that by faking that the tree is visible by calling
+ * proto_tree_set_visible(tree, TRUE) (see packet-wsp.c)
* BEFORE you create the item you are later going to use
* proto_item_append_string() on.
*/
}
DISSECTOR_ASSERT(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
old_str = fvalue_get(&fi->value);
- new_str = g_strdup_printf("%s%s", old_str, str);
- fvalue_set(&fi->value, new_str, TRUE);
+ new_str = ep_strdup_printf("%s%s", old_str, str);
+ fvalue_set(&fi->value, new_str, FALSE);
}
/* Set the FT_STRING value */
static void
-proto_tree_set_string(field_info *fi, const char* value,
- gboolean already_allocated)
+proto_tree_set_string(field_info *fi, const char* value)
{
- if (value)
- fvalue_set(&fi->value, (gpointer) value, already_allocated);
- else
- fvalue_set(&fi->value, (gpointer) "[ Null ]", already_allocated);
+ if (value) {
+ col_custom_set_fstr(fi->hfinfo, "%s",
+ format_text(value, strlen(value)));
+ fvalue_set(&fi->value, (gpointer) value, FALSE);
+ } else {
+ col_custom_set_fstr(fi->hfinfo, "[ Null ]");
+ fvalue_set(&fi->value, (gpointer) "[ Null ]", FALSE);
+ }
}
static void
length = tvb_ensure_length_remaining(tvb, start);
}
- /* This memory is freed in proto_tree_free_node() */
- string = tvb_get_string(tvb, start, length);
- proto_tree_set_string(fi, string, TRUE);
+ string = tvb_get_ephemeral_string(tvb, start, length);
+ proto_tree_set_string(fi, string);
+}
+
+static void
+proto_tree_set_ebcdic_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
+{
+ gchar *string;
+
+ if (length == -1) {
+ length = tvb_ensure_length_remaining(tvb, start);
+ }
+
+ string = tvb_get_ephemeral_string(tvb, start, length);
+ EBCDIC_to_ASCII(string, length);
+ proto_tree_set_string(fi, string);
}
/* Add a FT_ETHER to a proto_tree */
static void
proto_tree_set_ether(field_info *fi, const guint8* value)
{
+ col_custom_set_fstr(fi->hfinfo, "%s", bytes_to_str_punct(value, 6, ':'));
fvalue_set(&fi->value, (gpointer) value, FALSE);
}
static void
proto_tree_set_float(field_info *fi, float value)
{
+ col_custom_set_fstr(fi->hfinfo, "%." STRINGIFY(FLT_DIG) "f",
+ value);
fvalue_set_floating(&fi->value, value);
}
static void
proto_tree_set_double(field_info *fi, double value)
{
+ col_custom_set_fstr(fi->hfinfo, "%." STRINGIFY(DBL_DIG) "g",
+ value);
fvalue_set_floating(&fi->value, value);
}
integer >>= hfinfo->bitshift;
}
}
- fvalue_set_integer(&fi->value, integer);
+
+ if (hfinfo->type == FT_BOOLEAN) {
+ const true_false_string *tfstring = &tfs_true_false;
+ if (hfinfo->strings) {
+ tfstring = (const struct true_false_string*) hfinfo->strings;
+ }
+ col_custom_set_fstr(fi->hfinfo, "%s", value ? tfstring->true_string : tfstring->false_string);
+ } else if (hfinfo->strings) {
+ col_custom_set_fstr(fi->hfinfo, "%s", val_to_str(integer, cVALS(hfinfo->strings), "%d"));
+ } else if (IS_BASE_DUAL(hfinfo->display)) {
+ col_custom_set_fstr(fi->hfinfo, hfinfo_uint_value_format(hfinfo), integer, integer);
+ } else {
+ col_custom_set_fstr(fi->hfinfo, hfinfo_uint_value_format(hfinfo), integer);
+ }
+ fvalue_set_uinteger(&fi->value, integer);
}
/* Add FT_UINT64 to a proto_tree */
integer >>= hfinfo->bitshift;
}
}
- fvalue_set_integer(&fi->value, integer);
+
+ if (hfinfo->strings) {
+ col_custom_set_fstr(fi->hfinfo, "%s", val_to_str(integer, cVALS(hfinfo->strings), "%d"));
+ } else if (IS_BASE_DUAL(hfinfo->display)) {
+ col_custom_set_fstr(fi->hfinfo, hfinfo_int_value_format(hfinfo), integer, integer);
+ } else {
+ col_custom_set_fstr(fi->hfinfo, hfinfo_int_value_format(hfinfo), integer);
+ }
+ fvalue_set_sinteger(&fi->value, integer);
}
/* Add FT_INT64 to a proto_tree */
return pi;
}
-
+/* Throw an exception if we exceed this many tree items. */
+/* XXX - This should probably be a preference */
+#define MAX_TREE_ITEMS (1 * 1000 * 1000)
/* Add a field_info struct to the proto_tree, encapsulating it in a proto_node */
static proto_item *
proto_tree_add_node(proto_tree *tree, field_info *fi)
DISSECTOR_ASSERT(tfi == NULL ||
(tfi->tree_type >= 0 && tfi->tree_type < num_tree_types));
+ PTREE_DATA(tree)->count++;
+ if (PTREE_DATA(tree)->count > MAX_TREE_ITEMS) {
+ /* Let the exception handler add items to the tree */
+ PTREE_DATA(tree)->count = 0;
+ THROW_MESSAGE(DissectorError,
+ ep_strdup_printf("More than %d items in the tree -- possible infinite loop", MAX_TREE_ITEMS));
+ }
+
PROTO_NODE_NEW(pnode);
pnode->parent = tnode;
pnode->finfo = fi;
/* If the proto_tree wants to keep a record of this finfo
* for quick lookup, then record it. */
if (fi->hfinfo->ref_count) {
+ /*HERE*/
hash = PTREE_DATA(tree)->interesting_hfids;
ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
if (ptrs) {
* above) or goes past the end of the tvbuff,
* cut it short at the end of the tvbuff.
* That way, if this field is selected in
- * Ethereal, we don't highlight stuff past
+ * Wireshark, we don't highlight stuff past
* the end of the data.
*/
/* XXX - what to do, if we don't have a tvb? */
/* add the data source tvbuff */
fi->ds_tvb=tvb?TVB_GET_DS_TVB(tvb):NULL;
+ fi->appendix_start = 0;
+ fi->appendix_length = 0;
+
return fi;
}
}
fi = PITEM_FINFO(pi);
+ if (fi==NULL) {
+ return;
+ }
if (!PROTO_ITEM_IS_HIDDEN(pi)) {
va_start(ap, format);
fi = PITEM_FINFO(pi);
DISSECTOR_ASSERT(length >= 0);
fi->length = length;
+
+ if (fi->value.ftype->ftype == FT_BYTES)
+ fi->value.value.bytes->len = length;
}
/*
(fi->flags = (fi)->flags | (flags_in)); \
}
-gboolean
-proto_item_set_expert_flags(proto_item *pi, int group, int severity)
+gboolean
+proto_item_set_expert_flags(proto_item *pi, int group, guint severity)
{
if(pi == NULL || pi->finfo == NULL)
return FALSE;
* changed, then we'll find out very quickly. */
pnode->tree_data->visible = FALSE;
+ /* Keep track of the number of children */
+ pnode->tree_data->count = 0;
+
return (proto_tree*) pnode;
}
proto_item*
proto_item_get_parent(proto_item *ti) {
- /* dont bother if tree is not visible */
- if( (!ti) || (!(PTREE_DATA(ti)->visible)) )
+ if (!ti)
return (NULL);
return ti->parent;
}
proto_item*
proto_item_get_parent_nth(proto_item *ti, int gen) {
- /* dont bother if tree is not visible */
- if( (!ti) || (!(PTREE_DATA(ti)->visible)) )
+ if (!ti)
return (NULL);
while (gen--) {
ti = ti->parent;
}
-proto_item*
+proto_item*
proto_tree_get_parent(proto_tree *tree) {
- /* dont bother if tree is not visible */
- if( (!tree) || (!(PTREE_DATA(tree)->visible)) )
+ if (!tree)
return (NULL);
return (proto_item*) tree;
}
+proto_tree*
+proto_tree_get_root(proto_tree *tree) {
+ if (!tree)
+ return (NULL);
+ while (tree->parent) {
+ tree = tree->parent;
+ }
+ return tree;
+}
void
proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move)
/* fix last_child if required */
if(tree->last_child == item_to_move) {
tree->last_child = curr_item;
- }
+ }
}
/*** insert to_move after fixed ***/
}
}
+void
+proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start, gint length)
+{
+ field_info *fi;
+
+ if (tree == NULL)
+ return;
+
+ fi = tree->finfo;
+ start += TVB_RAW_OFFSET(tvb);
+ DISSECTOR_ASSERT(start >= 0);
+ DISSECTOR_ASSERT(length >= 0);
+
+ fi->appendix_start = start;
+ fi->appendix_length = length;
+}
int
proto_register_protocol(const char *name, const char *short_name, const char *filter_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,
+ * Drawback: As a hash value is used to reduce insert time,
* this might lead to a hash collision.
* However, as we have around 500+ protocols and we're using a 32 bit int this is very,
* very unlikely.
*/
key = g_malloc (sizeof(gint));
- *key = g_str_hash(name);
+ *key = wrs_str_hash(name);
existing_name = g_hash_table_lookup(proto_names, key);
if (existing_name != NULL) {
/* g_error will terminate the program */
}
g_hash_table_insert(proto_names, key, (gpointer)name);
- key = g_malloc (sizeof(gint));
- *key = g_str_hash(short_name);
- existing_name = g_hash_table_lookup(proto_short_names, key);
+ existing_name = g_hash_table_lookup(proto_short_names, (gpointer)short_name);
if (existing_name != NULL) {
g_error("Duplicate protocol short_name \"%s\"!"
" This might be caused by an inappropriate plugin or a development error.", short_name);
}
- g_hash_table_insert(proto_short_names, key, (gpointer)short_name);
+ g_hash_table_insert(proto_short_names, (gpointer)short_name, (gpointer)short_name);
found_invalid = FALSE;
for (i = 0; i < strlen(filter_name); i++) {
" Allowed are lower characters, digits, '-', '_' and '.'."
" This might be caused by an inappropriate plugin or a development error.", filter_name);
}
- key = g_malloc (sizeof(gint));
- *key = g_str_hash(filter_name);
- existing_name = g_hash_table_lookup(proto_filter_names, key);
+ existing_name = g_hash_table_lookup(proto_filter_names, (gpointer)filter_name);
if (existing_name != NULL) {
g_error("Duplicate protocol filter_name \"%s\"!"
" This might be caused by an inappropriate plugin or a development error.", filter_name);
}
- g_hash_table_insert(proto_filter_names, key, (gpointer)filter_name);
+ g_hash_table_insert(proto_filter_names, (gpointer)filter_name, (gpointer)filter_name);
/* Add this protocol to the list of known protocols; the list
is sorted by protocol short name. */
protocol->is_enabled = TRUE; /* protocol is enabled by default */
protocol->can_toggle = TRUE;
/* list will be sorted later by name, when all protocols completed registering */
- protocols = g_list_append(protocols, protocol);
+ protocols = g_list_prepend(protocols, protocol);
/* Here we do allocate a new header_field_info struct */
hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
GList *list_entry;
protocol_t *protocol;
+#if GLIB_MAJOR_VERSION < 2
+ list_entry = g_list_find_custom(protocols, discard_const(filter_name),
+ compare_filter_name);
+#else
list_entry = g_list_find_custom(protocols, filter_name,
compare_filter_name);
+#endif
if (list_entry == NULL)
return -1;
protocol = list_entry->data;
protocol_t *protocol;
protocol = find_protocol_by_id(proto_id);
+ if (protocol == NULL)
+ return "(none)";
return protocol->filter_name;
}
protocol->is_enabled = enabled;
}
+void
+proto_enable_all(void)
+{
+ protocol_t *protocol;
+ GList *list_item = protocols;
+
+ if (protocols == NULL)
+ return;
+
+ while (list_item) {
+ protocol = list_item->data;
+ if (protocol->can_toggle)
+ protocol->is_enabled = TRUE;
+ list_item = g_list_next(list_item);
+ }
+}
+
void
proto_set_cant_toggle(int proto_id)
{
}
}
-static int
-proto_register_field_init(header_field_info *hfinfo, int parent)
-{
- /* The field must have names */
- DISSECTOR_ASSERT(hfinfo->name);
+/* chars allowed in field abbrev */
+static
+const guchar fld_abbrev_chars[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, /* 0x20-0x2F '-', '.' */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F '0'-'9' */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F 'A'-'O' */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50-0x5F 'P'-'Z', '_' */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F 'a'-'o' */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70-0x7F 'p'-'z' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0-0xAF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0-0xBF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0-0xCF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0-0xDF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0-0xFF */
+};
+
+/* temporary function containing assert part for easier profiling */
+static void tmp_fld_check_assert(header_field_info *hfinfo) {
+ /* The field must have a name (with length > 0) */
+ DISSECTOR_ASSERT(hfinfo->name && hfinfo->name[0]);
+
+ /* fields with an empty string for an abbreviation aren't filterable */
DISSECTOR_ASSERT(hfinfo->abbrev);
/* These types of fields are allowed to have value_strings, true_false_strings or a protocol_t struct*/
default:
break;
}
+}
+
+static int
+proto_register_field_init(header_field_info *hfinfo, int parent)
+{
+
+ tmp_fld_check_assert(hfinfo);
+
/* if this is a bitfield, compute bitshift */
if (hfinfo->bitmask) {
- while ((hfinfo->bitmask & (1 << hfinfo->bitshift)) == 0)
- hfinfo->bitshift++;
+ hfinfo->bitshift = wrs_count_bitshift(hfinfo->bitmask);
}
hfinfo->parent = parent;
/* if we have real names, enter this field in the name tree */
if ((hfinfo->name[0] != 0) && (hfinfo->abbrev[0] != 0 )) {
- header_field_info *same_name_hfinfo, *same_name_next_hfinfo;
- const char *p;
+ header_field_info *same_name_next_hfinfo;
guchar c;
/* Check that the filter name (abbreviation) is legal;
* it must contain only alphanumerics, '-', "_", and ".". */
- for (p = hfinfo->abbrev; (c = *p) != '\0'; p++) {
- if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) {
- fprintf(stderr, "OOPS: '%c' in '%s'\n", c, hfinfo->abbrev);
- DISSECTOR_ASSERT(isalnum(c) || c == '-' || c == '_' ||
- c == '.');
- }
+ c = wrs_check_charset(fld_abbrev_chars, hfinfo->abbrev);
+ if (c) {
+ fprintf(stderr, "OOPS: '%c' in '%s'\n", c, hfinfo->abbrev);
+ DISSECTOR_ASSERT(!c);
}
+
/* We allow multiple hfinfo's to be registered under the same
* abbreviation. This was done for X.25, as, depending
* on whether it's modulo-8 or modulo-128 operation,
* a byte, and we want to be able to refer to that field
* with one name regardless of whether the packets
* are modulo-8 or modulo-128 packets. */
- same_name_hfinfo = g_tree_lookup(gpa_name_tree, hfinfo->abbrev);
+#if GLIB_MAJOR_VERSION < 2
+ same_name_hfinfo = g_tree_lookup(gpa_name_tree, discard_const(hfinfo->abbrev));
+#else
+ same_name_hfinfo = NULL;
+#endif
+ g_tree_insert(gpa_name_tree, (gpointer) (hfinfo->abbrev), hfinfo);
+ /* GLIB 2.x - if it is already present
+ * the previous hfinfo with the same name is saved
+ * to same_name_hfinfo by value destroy callback */
if (same_name_hfinfo) {
/* There's already a field with this name.
* Put it after that field in the list of
same_name_hfinfo->same_name_next = hfinfo;
hfinfo->same_name_prev = same_name_hfinfo;
}
- g_tree_insert(gpa_name_tree, (gpointer) (hfinfo->abbrev), hfinfo);
}
return hfinfo->id;
guint8 *bytes;
guint32 integer;
ipv4_addr *ipv4;
+ e_guid_t *guid;
guint32 n_addr; /* network-order IPv4 address */
const gchar *name;
int ret; /*tmp return value */
break;
case FT_IPXNET:
- integer = fvalue_get_integer(&fi->value);
+ integer = fvalue_get_uinteger(&fi->value);
ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s (0x%08X)", hfinfo->name,
get_ipxnet_name(integer), integer);
break;
case FT_GUID:
- bytes = fvalue_get(&fi->value);
+ guid = fvalue_get(&fi->value);
ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s", hfinfo->name,
- guid_to_str(bytes));
+ guid_to_str(guid));
if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
label_str[ITEM_LABEL_LENGTH - 1] = '\0';
break;
case FT_OID:
bytes = fvalue_get(&fi->value);
- name = (oid_resolv_enabled()) ? get_oid_name(bytes, fvalue_length(&fi->value)) : NULL;
+ name = oid_resolved_from_encoded(bytes, fvalue_length(&fi->value));
if (name) {
ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s (%s)", hfinfo->name,
- oid_to_str(bytes, fvalue_length(&fi->value)), name);
+ oid_encoded2string(bytes, fvalue_length(&fi->value)), name);
} else {
ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s", hfinfo->name,
- oid_to_str(bytes, fvalue_length(&fi->value)));
+ oid_encoded2string(bytes, fvalue_length(&fi->value)));
}
if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
label_str[ITEM_LABEL_LENGTH - 1] = '\0';
case FT_STRING:
case FT_STRINGZ:
+ case FT_EBCDIC:
case FT_UINT_STRING:
bytes = fvalue_get(&fi->value);
- if(strlen(bytes) > ITEM_LABEL_LENGTH) {
+ if(strlen(bytes) > ITEM_LABEL_LENGTH) {
ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
"%s [truncated]: %s", hfinfo->name,
format_text(bytes, strlen(bytes)));
int ret; /*tmp return value */
header_field_info *hfinfo = fi->hfinfo;
- static const true_false_string default_tf = { "True", "False" };
- const true_false_string *tfstring = &default_tf;
+ const true_false_string *tfstring = &tfs_true_false;
if (hfinfo->strings) {
tfstring = (const struct true_false_string*) hfinfo->strings;
}
- value = fvalue_get_integer(&fi->value);
+ value = fvalue_get_uinteger(&fi->value);
if (hfinfo->bitmask) {
/* Figure out the bit width */
bitwidth = hfinfo_bitwidth(hfinfo);
format = hfinfo_uint_vals_format(hfinfo);
/* Un-shift bits */
- unshifted_value = fvalue_get_integer(&fi->value);
+ unshifted_value = fvalue_get_uinteger(&fi->value);
value = unshifted_value;
if (hfinfo->bitshift > 0) {
unshifted_value <<= hfinfo->bitshift;
format = hfinfo_uint_format(hfinfo);
/* Un-shift bits */
- unshifted_value = fvalue_get_integer(&fi->value);
+ unshifted_value = fvalue_get_uinteger(&fi->value);
value = unshifted_value;
if (hfinfo->bitshift > 0) {
unshifted_value <<= hfinfo->bitshift;
/* Pick the proper format string */
format = hfinfo_uint_vals_format(hfinfo);
- value = fvalue_get_integer(&fi->value);
+ value = fvalue_get_uinteger(&fi->value);
/* Fill in the textual info */
- ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ if (hfinfo->display & BASE_RANGE_STRING) {
+ ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ format, hfinfo->name,
+ rval_to_str(value, hfinfo->strings, "Unknown"), value);
+ } else {
+ ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
format, hfinfo->name,
val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
+ }
if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
label_str[ITEM_LABEL_LENGTH - 1] = '\0';
}
/* Pick the proper format string */
format = hfinfo_uint_format(hfinfo);
- value = fvalue_get_integer(&fi->value);
+ value = fvalue_get_uinteger(&fi->value);
/* Fill in the textual info */
if (IS_BASE_DUAL(hfinfo->display)) {
/* Pick the proper format string */
format = hfinfo_int_vals_format(hfinfo);
- value = fvalue_get_integer(&fi->value);
+ value = fvalue_get_sinteger(&fi->value);
/* Fill in the textual info */
- ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ if (hfinfo->display & BASE_RANGE_STRING) {
+ ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+ format, hfinfo->name,
+ rval_to_str(value, hfinfo->strings, "Unknown"), value);
+ } else {
+ ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
format, hfinfo->name,
val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
+ }
if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
label_str[ITEM_LABEL_LENGTH - 1] = '\0';
}
/* Pick the proper format string */
format = hfinfo_int_format(hfinfo);
- value = fvalue_get_integer(&fi->value);
+ value = fvalue_get_sinteger(&fi->value);
/* Fill in the textual info */
if (IS_BASE_DUAL(hfinfo->display)) {
{
const char *format = NULL;
- switch(hfinfo->display) {
+ /* bit operation to reset the potential BASE_RANGE_STRING (or others in
+ * the future?) */
+ switch(hfinfo->display & BASE_STRUCTURE_RESET) {
case BASE_DEC:
case BASE_DEC_HEX:
format = "%s: %s (%u)";
}
static const char*
-hfinfo_int_vals_format(header_field_info *hfinfo)
-{
- const char *format = NULL;
-
- switch(hfinfo->display) {
- case BASE_DEC:
- case BASE_DEC_HEX:
- format = "%s: %s (%d)";
- break;
- case BASE_OCT: /* I'm lazy */
- format = "%s: %s (%o)";
- break;
- case BASE_HEX:
- case BASE_HEX_DEC:
- switch(hfinfo->type) {
- case FT_INT8:
- format = "%s: %s (0x%02x)";
- break;
- case FT_INT16:
- format = "%s: %s (0x%04x)";
- break;
- case FT_INT24:
- format = "%s: %s (0x%06x)";
- break;
- case FT_INT32:
- format = "%s: %s (0x%08x)";
- break;
- default:
- DISSECTOR_ASSERT_NOT_REACHED();
- ;
- }
- break;
- default:
- DISSECTOR_ASSERT_NOT_REACHED();
- ;
- }
- return format;
-}
-
-static const char*
-hfinfo_uint64_format(header_field_info *hfinfo)
+hfinfo_uint_value_format(header_field_info *hfinfo)
{
const char *format = NULL;
/* Pick the proper format string */
- switch(hfinfo->display) {
- case BASE_DEC:
- format = "%s: %" PRIu64;
- break;
- case BASE_DEC_HEX:
- format = "%s: %" PRIu64 " (%" PRIx64 ")";
- break;
- case BASE_OCT: /* I'm lazy */
- format = "%s: %" PRIo64;
- break;
- case BASE_HEX:
- format = "%s: 0x%016" PRIx64;
- break;
- case BASE_HEX_DEC:
- format = "%s: 0x%016" PRIx64 " (%" PRIu64 ")";
- break;
- default:
- DISSECTOR_ASSERT_NOT_REACHED();
- ;
- }
- return format;
+ if (hfinfo->type == FT_FRAMENUM) {
+ /*
+ * Frame numbers are always displayed in decimal.
+ */
+ format = "%u";
+ } else {
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ format = "%u";
+ break;
+ case BASE_DEC_HEX:
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ format = "%u (0x%02x)";
+ break;
+ case FT_UINT16:
+ format = "%u (0x%04x)";
+ break;
+ case FT_UINT24:
+ format = "%u (0x%06x)";
+ break;
+ case FT_UINT32:
+ format = "%u (0x%08x)";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ case BASE_OCT:
+ format = "%o";
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ format = "0x%02x";
+ break;
+ case FT_UINT16:
+ format = "0x%04x";
+ break;
+ case FT_UINT24:
+ format = "0x%06x";
+ break;
+ case FT_UINT32:
+ format = "0x%08x";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ case BASE_HEX_DEC:
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ format = "0x%02x (%u)";
+ break;
+ case FT_UINT16:
+ format = "0x%04x (%u)";
+ break;
+ case FT_UINT24:
+ format = "0x%06x (%u)";
+ break;
+ case FT_UINT32:
+ format = "0x%08x (%u)";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ }
+ return format;
+}
+
+static const char*
+hfinfo_int_vals_format(header_field_info *hfinfo)
+{
+ const char *format = NULL;
+
+ /* bit operation to reset the potential BASE_RANGE_STRING (or others in
+ * the future?)*/
+ switch(hfinfo->display & BASE_STRUCTURE_RESET) {
+ case BASE_DEC:
+ case BASE_DEC_HEX:
+ format = "%s: %s (%d)";
+ break;
+ case BASE_OCT: /* I'm lazy */
+ format = "%s: %s (%o)";
+ break;
+ case BASE_HEX:
+ case BASE_HEX_DEC:
+ switch(hfinfo->type) {
+ case FT_INT8:
+ format = "%s: %s (0x%02x)";
+ break;
+ case FT_INT16:
+ format = "%s: %s (0x%04x)";
+ break;
+ case FT_INT24:
+ format = "%s: %s (0x%06x)";
+ break;
+ case FT_INT32:
+ format = "%s: %s (0x%08x)";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ return format;
+}
+
+static const char*
+hfinfo_uint64_format(header_field_info *hfinfo)
+{
+ const char *format = NULL;
+
+ /* Pick the proper format string */
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ format = "%s: %" G_GINT64_MODIFIER "u";
+ break;
+ case BASE_DEC_HEX:
+ format = "%s: %" G_GINT64_MODIFIER "u (%" G_GINT64_MODIFIER "x)";
+ break;
+ case BASE_OCT: /* I'm lazy */
+ format = "%s: %" G_GINT64_MODIFIER "o";
+ break;
+ case BASE_HEX:
+ format = "%s: 0x%016" G_GINT64_MODIFIER "x";
+ break;
+ case BASE_HEX_DEC:
+ format = "%s: 0x%016" G_GINT64_MODIFIER "x (%" G_GINT64_MODIFIER "u)";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ return format;
}
static const char*
DISSECTOR_ASSERT_NOT_REACHED();
;
}
+ break;
case BASE_OCT: /* I'm lazy */
format = "%s: %o";
break;
DISSECTOR_ASSERT_NOT_REACHED();
;
}
+ break;
case BASE_HEX_DEC:
switch(hfinfo->type) {
case FT_INT8:
return format;
}
+static const char*
+hfinfo_int_value_format(header_field_info *hfinfo)
+{
+ const char *format = NULL;
+
+ /* Pick the proper format string */
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ format = "%d";
+ break;
+ case BASE_DEC_HEX:
+ switch(hfinfo->type) {
+ case FT_INT8:
+ format = "%d (0x%02x)";
+ break;
+ case FT_INT16:
+ format = "%d (0x%04x)";
+ break;
+ case FT_INT24:
+ format = "%d (0x%06x)";
+ break;
+ case FT_INT32:
+ format = "%d (0x%08x)";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ case BASE_OCT:
+ format = "%o";
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_INT8:
+ format = "0x%02x";
+ break;
+ case FT_INT16:
+ format = "0x%04x";
+ break;
+ case FT_INT24:
+ format = "0x%06x";
+ break;
+ case FT_INT32:
+ format = "0x%08x";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ case BASE_HEX_DEC:
+ switch(hfinfo->type) {
+ case FT_INT8:
+ format = "0x%02x (%d)";
+ break;
+ case FT_INT16:
+ format = "0x%04x (%d)";
+ break;
+ case FT_INT24:
+ format = "0x%06x (%d)";
+ break;
+ case FT_INT32:
+ format = "0x%08x (%d)";
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ ;
+ }
+ return format;
+}
+
static const char*
hfinfo_int64_format(header_field_info *hfinfo)
{
/* Pick the proper format string */
switch(hfinfo->display) {
case BASE_DEC:
- format = "%s: %" PRId64;
+ format = "%s: %" G_GINT64_MODIFIER "d";
break;
case BASE_DEC_HEX:
- format = "%s: %" PRId64 " (%" PRIx64 ")";
+ format = "%s: %" G_GINT64_MODIFIER "d (%" G_GINT64_MODIFIER "x)";
break;
case BASE_OCT: /* I'm lazy */
- format = "%s: %" PRIo64;
+ format = "%s: %" G_GINT64_MODIFIER "o";
break;
case BASE_HEX:
- format = "%s: 0x%016" PRIx64;
+ format = "%s: 0x%016" G_GINT64_MODIFIER "x";
break;
case BASE_HEX_DEC:
- format = "%s: 0x%016" PRIx64 " (%" PRId64 ")";
+ format = "%s: 0x%016" G_GINT64_MODIFIER "x (%" G_GINT64_MODIFIER "d)";
break;
default:
DISSECTOR_ASSERT_NOT_REACHED();
}
-/* Helper struct and function for proto_find_info() */
+/* Helper struct for proto_find_info() and proto_all_finfos() */
typedef struct {
GPtrArray *array;
int id;
} ffdata_t;
+/* Helper function for proto_find_info() */
static gboolean
find_finfo(proto_node *node, gpointer data)
{
}
/* Return GPtrArray* of field_info pointers for all hfindex that appear in a tree.
- * This works on any proto_tree, primed or unprimed, but actually searches
- * the tree, so it is slower than using proto_get_finfo_ptr_array on a primed tree.
- * The caller does need to free the returned GPtrArray with
- * g_ptr_array_free(<array>, FALSE).
- */
+* This works on any proto_tree, primed or unprimed, but actually searches
+* the tree, so it is slower than using proto_get_finfo_ptr_array on a primed tree.
+* The caller does need to free the returned GPtrArray with
+* g_ptr_array_free(<array>, FALSE).
+*/
GPtrArray*
proto_find_finfo(proto_tree *tree, int id)
{
proto_tree_traverse_pre_order(tree, find_finfo, &ffdata);
return ffdata.array;
-}
+}
+
+/* Helper function for proto_all_finfos() */
+static gboolean
+every_finfo(proto_node *node, gpointer data)
+{
+ field_info *fi = PITEM_FINFO(node);
+ if (fi && fi->hfinfo) {
+ g_ptr_array_add(((ffdata_t*)data)->array, fi);
+ }
+
+ /* Don't stop traversing. */
+ return FALSE;
+}
+
+/* Return GPtrArray* of field_info pointers containing all hfindexes that appear in a tree. */
+GPtrArray*
+proto_all_finfos(proto_tree *tree)
+{
+ ffdata_t ffdata;
+
+ ffdata.array = g_ptr_array_new();
+ ffdata.id = 0;
+
+ proto_tree_traverse_pre_order(tree, every_finfo, &ffdata);
+
+ return ffdata.array;
+}
typedef struct {
{
protocol_t *protocol;
int i;
- void *cookie;
+ void *cookie = NULL;
for (i = proto_get_first_protocol(&cookie); i != -1;
i = proto_get_next_protocol(&cookie)) {
PROTO_REGISTRAR_GET_NTH(i, hfinfo);
/*
- * Skip fields with zero-length names or abbreviations;
- * the pseudo-field for "proto_tree_add_text()" is such
- * a field, and we don't want it in the list of filterable
- * fields.
- *
- * XXX - perhaps the name and abbrev field should be null
- * pointers rather than null strings for that pseudo-field,
- * but we'd have to add checks for null pointers in some
- * places if we did that.
- *
- * Or perhaps protocol tree items added with
- * "proto_tree_add_text()" should have -1 as the field index,
- * with no pseudo-field being used, but that might also
- * require special checks for -1 to be added.
- */
- /* XXX - we could just skip the special text
- * pseudo-field by testing: if (hfinfo->id == hf_text_only)
- * */
- if (hfinfo->name[0] == 0 || hfinfo->abbrev[0] == 0)
+ * Skip the pseudo-field for "proto_tree_add_text()" since
+ * we don't want it in the list of filterable fields.
+ */
+ if (hfinfo->id == hf_text_only)
continue;
/* format for protocols */
hfinfo->type == FT_INT32 ||
hfinfo->type == FT_INT64) {
-
+
switch(hfinfo->display) {
case BASE_NONE:
base_name = "BASE_NONE";
format = "%s == %u";
break;
case FT_UINT64:
- format = "%s == %" PRIu64;
+ format = "%s == %" G_GINT64_MODIFIER "u";
break;
case FT_INT8:
case FT_INT16:
format = "%s == %d";
break;
case FT_INT64:
- format = "%s == %" PRId64;
+ format = "%s == %" G_GINT64_MODIFIER "d";
break;
default:
DISSECTOR_ASSERT_NOT_REACHED();
format = "%s == 0x%08x";
break;
case FT_UINT64:
- format = "%s == 0x%016" PRIx64;
+ format = "%s == 0x%016" G_GINT64_MODIFIER "x";
break;
default:
DISSECTOR_ASSERT_NOT_REACHED();
return format;
}
-/*
- * Returns TRUE if we can do a "match selected" on the field, FALSE
- * otherwise.
- */
-gboolean
-proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
-{
- header_field_info *hfinfo;
- gint length;
-
- hfinfo = finfo->hfinfo;
- DISSECTOR_ASSERT(hfinfo);
-
- switch(hfinfo->type) {
-
- case FT_BOOLEAN:
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
- case FT_INT8:
- case FT_INT16:
- case FT_INT24:
- case FT_INT32:
- case FT_FRAMENUM:
- case FT_UINT64:
- case FT_INT64:
- case FT_IPv4:
- case FT_IPXNET:
- case FT_IPv6:
- case FT_FLOAT:
- case FT_DOUBLE:
- case FT_ABSOLUTE_TIME:
- case FT_RELATIVE_TIME:
- case FT_STRING:
- case FT_STRINGZ:
- case FT_UINT_STRING:
- case FT_ETHER:
- case FT_BYTES:
- case FT_UINT_BYTES:
- case FT_PROTOCOL:
- case FT_GUID:
- case FT_OID:
- /*
- * These all have values, so we can match.
- */
- return TRUE;
-
- default:
- /*
- * This doesn't have a value, so we'd match
- * on the raw bytes at this address.
- *
- * Should we be allowed to access to the raw bytes?
- * If "edt" is NULL, the answer is "no".
- */
- if (edt == NULL)
- return FALSE;
-
- /*
- * Is this field part of the raw frame tvbuff?
- * If not, we can't use "frame[N:M]" to match
- * it.
- *
- * XXX - should this be frame-relative, or
- * protocol-relative?
- *
- * XXX - does this fallback for non-registered
- * fields even make sense?
- */
- if (finfo->ds_tvb != edt->tvb)
- return FALSE;
-
- /*
- * If the length is 0, there's nothing to match, so
- * we can't match. (Also check for negative values,
- * just in case, as we'll cast it to an unsigned
- * value later.)
- */
- length = finfo->length;
- if (length <= 0)
- return FALSE;
-
- /*
- * Don't go past the end of that tvbuff.
- */
- if ((guint)length > tvb_length(finfo->ds_tvb))
- length = tvb_length(finfo->ds_tvb);
- if (length <= 0)
- return FALSE;
- return TRUE;
- }
-}
-
-/* This function returns a string allocated with packet lifetime scope.
- * You do not need to [g_]free() this string since it will be automatically
+/* This function indicates whether it's possible to construct a
+ * "match selected" display filter string for the specified field,
+ * returns an indication of whether it's possible, and, if it's
+ * possible and "filter" is non-null, constructs the filter and
+ * sets "*filter" to point to it.
+ * You do not need to [g_]free() this string since it will be automatically
* freed once the next packet is dissected.
*/
-char*
-proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
+static gboolean
+construct_match_selected_string(field_info *finfo, epan_dissect_t *edt,
+ char **filter)
{
header_field_info *hfinfo;
int abbrev_len;
- char *buf, *ptr;
+ char *ptr;
int buf_len;
const char *format;
int dfilter_len, i;
gint start, length, length_remaining;
guint8 c;
+ gchar is_signed_num = FALSE;
hfinfo = finfo->hfinfo;
DISSECTOR_ASSERT(hfinfo);
*/
switch(hfinfo->type) {
- case FT_UINT8:
- case FT_UINT16:
- case FT_UINT24:
- case FT_UINT32:
case FT_INT8:
case FT_INT16:
case FT_INT24:
case FT_INT32:
+ is_signed_num = TRUE;
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
case FT_FRAMENUM:
/*
* 4 bytes for " == ".
*
* 1 byte for the trailing '\0'.
*/
- dfilter_len = abbrev_len + 4 + 11 + 1;
- buf = ep_alloc0(dfilter_len);
- format = hfinfo_numeric_format(hfinfo);
- g_snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer(&finfo->value));
+ if (filter != NULL) {
+ dfilter_len = abbrev_len + 4 + 11 + 1;
+ *filter = ep_alloc0(dfilter_len);
+ format = hfinfo_numeric_format(hfinfo);
+ if(is_signed_num) {
+ g_snprintf(*filter, dfilter_len, format,
+ hfinfo->abbrev,
+ fvalue_get_sinteger(&finfo->value));
+ } else {
+ g_snprintf(*filter, dfilter_len, format,
+ hfinfo->abbrev,
+ fvalue_get_uinteger(&finfo->value));
+ }
+ }
break;
case FT_INT64:
*
* 1 byte for the trailing '\0'.
*/
- dfilter_len = abbrev_len + 4 + 22 + 1;
- buf = ep_alloc0(dfilter_len);
- format = hfinfo_numeric_format(hfinfo);
- g_snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer64(&finfo->value));
- break;
-
- /* These use the fvalue's "to_string_repr" method. */
- case FT_IPXNET:
- case FT_BOOLEAN:
- case FT_STRING:
- case FT_ETHER:
- case FT_BYTES:
- case FT_UINT_BYTES:
- case FT_FLOAT:
- case FT_DOUBLE:
- case FT_ABSOLUTE_TIME:
- case FT_RELATIVE_TIME:
- case FT_IPv4:
- case FT_IPv6:
- case FT_GUID:
- case FT_OID:
- /* Figure out the string length needed.
- * The ft_repr length.
- * 4 bytes for " == ".
- * 1 byte for trailing NUL.
- */
- dfilter_len = fvalue_string_repr_len(&finfo->value,
- FTREPR_DFILTER);
- dfilter_len += abbrev_len + 4 + 1;
- buf = ep_alloc0(dfilter_len);
-
- /* Create the string */
- g_snprintf(buf, dfilter_len, "%s == ", hfinfo->abbrev);
- fvalue_to_string_repr(&finfo->value,
- FTREPR_DFILTER,
- &buf[abbrev_len + 4]);
+ if (filter != NULL) {
+ dfilter_len = abbrev_len + 4 + 22 + 1;
+ *filter = ep_alloc0(dfilter_len);
+ format = hfinfo_numeric_format(hfinfo);
+ g_snprintf(*filter, dfilter_len, format,
+ hfinfo->abbrev,
+ fvalue_get_integer64(&finfo->value));
+ }
break;
case FT_PROTOCOL:
- buf = ep_strdup(finfo->hfinfo->abbrev);
+ if (filter != NULL)
+ *filter = ep_strdup(finfo->hfinfo->abbrev);
break;
- default:
+ case FT_NONE:
+ case FT_PCRE:
+ /*
+ * If the length is 0, just match the name of the
+ * field.
+ *
+ * (Also check for negative values, just in case,
+ * as we'll cast it to an unsigned value later.)
+ */
+ length = finfo->length;
+ if (length == 0) {
+ if (filter != NULL)
+ *filter = ep_strdup(finfo->hfinfo->abbrev);
+ break;
+ }
+ if (length < 0)
+ return FALSE;
+
/*
* This doesn't have a value, so we'd match
* on the raw bytes at this address.
* If "edt" is NULL, the answer is "no".
*/
if (edt == NULL)
- return NULL;
+ return FALSE;
/*
* Is this field part of the raw frame tvbuff?
* fields even make sense?
*/
if (finfo->ds_tvb != edt->tvb)
- return NULL; /* you lose */
-
- /*
- * If the length is 0, there's nothing to match, so
- * we can't match. (Also check for negative values,
- * just in case, as we'll cast it to an unsigned
- * value later.)
- */
- length = finfo->length;
- if (length <= 0)
- return NULL;
+ return FALSE; /* you lose */
/*
* Don't go past the end of that tvbuff.
if (length > length_remaining)
length = length_remaining;
if (length <= 0)
- return NULL;
-
- start = finfo->start;
- buf_len = 32 + length * 3;
- buf = ep_alloc0(buf_len);
- ptr = buf;
-
- ptr += g_snprintf(ptr, buf_len-(ptr-buf), "frame[%d:%d] == ", finfo->start, length);
- for (i=0;i<length; i++) {
- c = tvb_get_guint8(finfo->ds_tvb, start);
- start++;
- if (i == 0 ) {
- ptr += g_snprintf(ptr, buf_len-(ptr-buf), "%02x", c);
+ return FALSE;
+
+ if (filter != NULL) {
+ start = finfo->start;
+ buf_len = 32 + length * 3;
+ *filter = ep_alloc0(buf_len);
+ ptr = *filter;
+
+ ptr += g_snprintf(ptr, buf_len-(ptr-*filter),
+ "frame[%d:%d] == ", finfo->start, length);
+ for (i=0;i<length; i++) {
+ c = tvb_get_guint8(finfo->ds_tvb, start);
+ start++;
+ if (i == 0 ) {
+ ptr += g_snprintf(ptr, buf_len-(ptr-*filter), "%02x", c);
+ }
+ else {
+ ptr += g_snprintf(ptr, buf_len-(ptr-*filter), ":%02x", c);
+ }
}
- else {
- ptr += snprintf(ptr, buf_len-(ptr-buf), ":%02x", c);
+ }
+ break;
+
+ /* By default, use the fvalue's "to_string_repr" method. */
+ default:
+ /* Figure out the string length needed.
+ * The ft_repr length.
+ * 4 bytes for " == ".
+ * 1 byte for trailing NUL.
+ */
+ if (filter != NULL) {
+ dfilter_len = fvalue_string_repr_len(&finfo->value,
+ FTREPR_DFILTER);
+ dfilter_len += abbrev_len + 4 + 1;
+ *filter = ep_alloc0(dfilter_len);
+
+ /* Create the string */
+ g_snprintf(*filter, dfilter_len, "%s == ",
+ hfinfo->abbrev);
+ fvalue_to_string_repr(&finfo->value,
+ FTREPR_DFILTER,
+ &(*filter)[abbrev_len + 4]);
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Returns TRUE if we can do a "match selected" on the field, FALSE
+ * otherwise.
+ */
+gboolean
+proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
+{
+ return construct_match_selected_string(finfo, edt, NULL);
+}
+
+/* This function attempts to construct a "match selected" display filter
+ * string for the specified field; if it can do so, it returns a pointer
+ * to the string, otherwise it returns NULL.
+ *
+ * The string is allocated with packet lifetime scope.
+ * You do not need to [g_]free() this string since it will be automatically
+ * freed once the next packet is dissected.
+ */
+char*
+proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt)
+{
+ char *filter;
+
+ if (!construct_match_selected_string(finfo, edt, &filter))
+ return NULL;
+ return filter;
+}
+
+
+/* This function will dissect a sequence of bytes that describe a
+ * bitmask.
+ * hf_hdr is a 8/16/24/32 bit integer that describes the bitmask to be dissected.
+ * This field will form an expansion under which the individual fields of the
+ * bitmask is dissected and displayed.
+ * This field must be of the type FT_[U]INT{8|16|24|32}.
+ *
+ * fields is an array of pointers to int that lists all the fields of the
+ * bitmask. These fields can be either of the type FT_BOOLEAN for flags
+ * or another integer of the same type/size as hf_hdr with a mask specified.
+ * This array is terminated by a NULL entry.
+ *
+ * FT_BOOLEAN bits that are set to 1 will have the name added to the expansion.
+ * FT_integer fields that have a value_string attached will have the
+ * matched string displayed on the expansion line.
+ */
+proto_item *
+proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian)
+{
+ proto_tree *tree=NULL;
+ proto_item *item=NULL;
+ header_field_info *hf_info;
+ int len=0;
+ guint32 value=0;
+
+ hf_info=proto_registrar_get_nth(hf_hdr);
+ switch(hf_info->type){
+ case FT_INT8:
+ case FT_UINT8:
+ len=1;
+ value=tvb_get_guint8(tvb, offset);
+ break;
+ case FT_INT16:
+ case FT_UINT16:
+ len=2;
+ if(little_endian){
+ value=tvb_get_letohs(tvb, offset);
+ } else {
+ value=tvb_get_ntohs(tvb, offset);
+ }
+ break;
+ case FT_INT24:
+ case FT_UINT24:
+ len=3;
+ if(little_endian){
+ value=tvb_get_letoh24(tvb, offset);
+ } else {
+ value=tvb_get_ntoh24(tvb, offset);
+ }
+ break;
+ case FT_INT32:
+ case FT_UINT32:
+ len=4;
+ if(little_endian){
+ value=tvb_get_letohl(tvb, offset);
+ } else {
+ value=tvb_get_ntohl(tvb, offset);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if(parent_tree){
+ item=proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian);
+ tree=proto_item_add_subtree(item, ett);
+ }
+
+ while(*fields){
+ header_field_info *hf_field;
+ guint32 tmpval, tmpmask;
+
+ hf_field=proto_registrar_get_nth(**fields);
+ switch(hf_field->type){
+ case FT_INT8:
+ case FT_UINT8:
+ case FT_INT16:
+ case FT_UINT16:
+ case FT_INT24:
+ case FT_UINT24:
+ case FT_INT32:
+ case FT_UINT32:
+ proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
+
+ /* Mask and shift out the value */
+ tmpmask=hf_field->bitmask;
+ tmpval=value;
+ if(tmpmask){
+ tmpval&=tmpmask;
+ while(!(tmpmask&0x00000001)){
+ tmpval>>=1;
+ tmpmask>>=1;
}
}
+ /* Show the value_string content (if there is one) */
+ if(hf_field->strings){
+ proto_item_append_text(item, ", %s", val_to_str(tmpval, hf_field->strings, "Unknown"));
+ }
+
+ break;
+ case FT_BOOLEAN:
+ proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
+ /* if the flag is set, show the name */
+ if(hf_field->bitmask&value){
+ proto_item_append_text(item, ", %s", hf_field->name);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ fields++;
+ }
+
+ return item;
+}
+
+proto_item *
+proto_tree_add_bits_item(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian)
+{
+ return proto_tree_add_bits_ret_val(tree, hf_index, tvb, bit_offset, no_of_bits, NULL, little_endian);
+
+}
+/*
+ * This function will dissect a sequence of bits that does not need to be byte aligned the bits
+ * set vill be shown in the tree as ..10 10.. and the integer value returned if return_value is set.
+ * Offset should be given in bits from the start of the tvb.
+ */
+
+proto_item *
+proto_tree_add_bits_ret_val(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, guint64 *return_value, gboolean little_endian)
+{
+ gint offset;
+ guint length;
+ guint8 tot_no_bits;
+ guint8 remaining_bits;
+ guint64 mask = 0,tmp;
+ char *str;
+ header_field_info *hf_field;
+ guint64 value = 0;
+ int bit;
+ int i;
+
+ hf_field = proto_registrar_get_nth(hf_index);
+
+ /* Byte align offset */
+ offset = bit_offset>>3;
+
+
+ /*
+ * Calculate the number of octets used to hold the bits
+ */
+ tot_no_bits = ((bit_offset&0x7)+no_of_bits);
+ length = tot_no_bits>>3;
+ remaining_bits = tot_no_bits % 8;
+ if ((remaining_bits)!=0)
+ length++;
+
+ if (no_of_bits < 9){
+ value = tvb_get_bits8(tvb, bit_offset, no_of_bits);
+ }else if(no_of_bits < 17){
+ value = tvb_get_bits16(tvb, bit_offset, no_of_bits, little_endian);
+ }else if(no_of_bits < 33){
+ value = tvb_get_bits32(tvb, bit_offset, no_of_bits, little_endian);
+ }else if(no_of_bits < 65){
+ value = tvb_get_bits64(tvb, bit_offset, no_of_bits, little_endian);
+ }else if(no_of_bits>64){
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return NULL;
+ }
+
+
+ mask = 1;
+ mask = mask << (no_of_bits-1);
+
+ /* prepare the string */
+ str=ep_alloc(256);
+ str[0]='\0';
+ for(bit=0;bit<((int)(bit_offset&0x07));bit++){
+ if(bit&&(!(bit%4))){
+ strcat(str, " ");
+ }
+ strcat(str,".");
+ }
+ /* read the bits for the int */
+ for(i=0;i<no_of_bits;i++){
+ if(bit&&(!(bit%4))){
+ strcat(str, " ");
+ }
+ if(bit&&(!(bit%8))){
+ strcat(str, " ");
+ }
+ bit++;
+ tmp = value & mask;
+ if(tmp != 0){
+ strcat(str, "1");
+ } else {
+ strcat(str, "0");
+ }
+ mask = mask>>1;
+ }
+ for(;bit%8;bit++){
+ if(bit&&(!(bit%4))){
+ strcat(str, " ");
+ }
+ strcat(str,".");
+ }
+
+ if(return_value){
+ *return_value=value;
+ }
+ if(hf_index == -1)
+ return NULL;
+
+ strcat(str," = ");
+ strcat(str,hf_field->name);
+
+ switch(hf_field->type){
+ case FT_BOOLEAN:
+ /* Boolean field */
+ if (hf_field->strings) {
+ const true_false_string *tfstring = &tfs_true_false;
+ tfstring = (const struct true_false_string*) hf_field->strings;
+
+ return proto_tree_add_boolean_format(tree, hf_index, tvb, offset, length, (guint32)value,
+ "%s: %s",
+ str,
+ (guint32)value ? tfstring->true_string : tfstring->false_string);
+ }else{
+ return proto_tree_add_boolean_format(tree, hf_index, tvb, offset, length, (guint32)value,
+ "%s: %u",
+ str,
+ (guint32)value);
+ }
+ break;
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ /* 1 - 32 bits field */
+ if (hf_field->strings) {
+ return proto_tree_add_uint_format(tree, hf_index, tvb, offset, length, (guint32)value,
+ "%s: %s (%u)",
+ str,
+ val_to_str((guint32)value, cVALS(hf_field->strings), "Unknown "),
+ (guint32)value);
break;
+ }
+ switch(hf_field->display){
+ case BASE_DEC:
+ return proto_tree_add_uint_format(tree, hf_index, tvb, offset, length, (guint32)value,
+ "%s: %u",
+ str,
+ (guint32)value);
+ break;
+ case BASE_HEX:
+ return proto_tree_add_uint_format(tree, hf_index, tvb, offset, length, (guint32)value,
+ "%s: 0x%x",
+ str,
+ (guint32)value);
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return NULL;
+ break;
+ }
+ break;
+ case FT_UINT64:
+ switch(hf_field->display){
+ case BASE_DEC:
+ return proto_tree_add_uint64_format(tree, hf_index, tvb, offset, length, value,
+ "%s: %" G_GINT64_MODIFIER "u",
+ str, value);
+ break;
+ case BASE_HEX:
+ return proto_tree_add_uint64_format(tree, hf_index, tvb, offset, length, value,
+ "%s: 0x%" G_GINT64_MODIFIER "x",
+ str, value);
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return NULL;
+ break;
+ }
+ break;
+ default:
+ DISSECTOR_ASSERT_NOT_REACHED();
+ return NULL;
+ break;
}
- return buf;
}