/epan/proto.c
C | 7564 lines | 5237 code | 1162 blank | 1165 comment | 898 complexity | 949f7def75a5a6f0cc4c3a4d9679517f MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /* proto.c
- * Routines for protocol tree
- *
- * $Id$
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include "config.h"
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <glib.h>
- #include <float.h>
- #include "packet.h"
- #include "ptvcursor.h"
- #include "strutil.h"
- #include "addr_resolv.h"
- #include "oids.h"
- #include "plugins.h"
- #include "proto.h"
- #include "epan_dissect.h"
- #include "tvbuff.h"
- #include "emem.h"
- #include "charsets.h"
- #include "asm_utils.h"
- #include "column-utils.h"
- #include "to_str.h"
- #include "expert.h"
- #include "show_exception.h"
- #include "wspython/wspy_register.h"
- #define SUBTREE_ONCE_ALLOCATION_NUMBER 8
- #define SUBTREE_MAX_LEVELS 256
- /* Throw an exception if we exceed this many tree items. */
- /* XXX - This should probably be a preference */
- #define MAX_TREE_ITEMS (1 * 1000 * 1000)
- 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;
- };
- #define cVALS(x) (const value_string*)(x)
- /** See inlined comments.
- @param tree the tree to append this item to
- @param hfindex field index
- @param hfinfo header_field
- @return the header field matching 'hfinfo' */
- #define TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hfinfo) \
- /* If this item is not referenced we dont have to do much work \
- at all but we should still return a node so that field items \
- below this node (think proto_item_add_subtree()) will still \
- have somewhere to attach to or else filtering will not work \
- (they would be ignored since tree would be NULL). \
- DONT try to fake a node where PTREE_FINFO(tree) is NULL \
- since dissectors that want to do proto_item_set_len() or \
- other operations that dereference this would crash. \
- We fake FT_PROTOCOL unless some clients have requested us \
- not to do so. \
- */ \
- if (!tree) \
- return NULL; \
- PTREE_DATA(tree)->count++; \
- if (PTREE_DATA(tree)->count > MAX_TREE_ITEMS) { \
- if (getenv("WIRESHARK_ABORT_ON_TOO_MANY_ITEMS") != NULL) \
- g_error("More than %d items in the tree -- possible infinite loop", 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_REGISTRAR_GET_NTH(hfindex, hfinfo); \
- if (!(PTREE_DATA(tree)->visible)) { \
- if (PTREE_FINFO(tree)) { \
- if ((hfinfo->ref_type != HF_REF_TYPE_DIRECT) \
- && (hfinfo->type != FT_PROTOCOL || \
- PTREE_DATA(tree)->fake_protocols)) { \
- /* just return tree back to the caller */\
- return tree; \
- } \
- } \
- }
- /** See inlined comments.
- @param pi the created protocol item we're about to return */
- #define TRY_TO_FAKE_THIS_REPR(pi) \
- g_assert(pi); \
- if (!(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 void fill_label_boolean(field_info *fi, gchar *label_str);
- static void fill_label_bitfield(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);
- static const char *hfinfo_number_value_format_display(const header_field_info *hfinfo, int display, char buf[32], guint32 value);
- static const char *hfinfo_number_vals_format(const header_field_info *hfinfo, char buf[32], guint32 value);
- static const char *hfinfo_number_value_format(const header_field_info *hfinfo, char buf[32], guint32 value);
- static const char *hfinfo_numeric_value_format(const header_field_info *hfinfo, char buf[32], guint32 value);
- static const char* hfinfo_uint64_format(const header_field_info *hfinfo);
- static const char* hfinfo_int64_format(const header_field_info *hfinfo);
- 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);
- static field_info *
- new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
- const gint start, const gint item_length);
- static field_info *
- alloc_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
- const gint start, gint *length);
- static proto_item *
- proto_tree_add_pi(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
- gint start, gint *length, field_info **pfi);
- static void
- proto_tree_set_representation_value(proto_item *pi, const char *format, va_list ap);
- static void
- proto_tree_set_representation(proto_item *pi, const char *format, va_list ap);
- static void
- proto_tree_set_protocol_tvb(field_info *fi, tvbuff_t *tvb);
- static void
- proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length);
- static void
- proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length);
- static void
- proto_tree_set_time(field_info *fi, nstime_t *value_ptr);
- static void
- 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, gint encoding);
- static void
- proto_tree_set_ax25(field_info *fi, const guint8* value);
- static void
- proto_tree_set_ax25_tvb(field_info *fi, tvbuff_t *tvb, gint start);
- static void
- proto_tree_set_vines(field_info *fi, const guint8* value);
- static void
- proto_tree_set_vines_tvb(field_info *fi, tvbuff_t *tvb, gint start);
- 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_ipxnet(field_info *fi, guint32 value);
- static void
- proto_tree_set_ipv4(field_info *fi, guint32 value);
- static void
- proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr);
- static void
- proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
- static void
- 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, const guint encoding);
- static void
- proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length);
- static void
- proto_tree_set_oid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
- static void
- proto_tree_set_boolean(field_info *fi, guint32 value);
- static void
- proto_tree_set_float(field_info *fi, float value);
- static void
- proto_tree_set_double(field_info *fi, double value);
- static void
- proto_tree_set_uint(field_info *fi, guint32 value);
- static void
- proto_tree_set_int(field_info *fi, gint32 value);
- static void
- proto_tree_set_uint64(field_info *fi, guint64 value);
- static void
- proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, const guint encoding);
- static void
- proto_tree_set_eui64(field_info *fi, const guint64 value);
- static void
- proto_tree_set_eui64_tvb(field_info *fi, tvbuff_t *tvb, gint start, const guint encoding);
- static gboolean
- proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
- const int len, const gint ett, const gint **fields,
- const guint encoding, const int flags,
- gboolean first);
- static int proto_register_field_init(header_field_info *hfinfo, const int parent);
- /* special-case header field used within proto.c */
- static header_field_info hfi_text_only =
- { "Text item", "text", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL };
- int hf_text_only = -1;
- /* Structure for information about a protocol */
- struct _protocol {
- const char *name; /* long description */
- const char *short_name; /* short description */
- const char *filter_name; /* name of this protocol in filters */
- int proto_id; /* field ID for this protocol */
- GSList *fields; /* fields for this protocol */
- GSList *last_field; /* pointer to end of list of fields */
- gboolean is_enabled; /* TRUE if protocol is enabled */
- gboolean can_toggle; /* TRUE if is_enabled can be changed */
- gboolean is_private; /* TRUE is protocol is private */
- };
- /* List of all protocols */
- static GList *protocols = NULL;
- #define INITIAL_NUM_PROTOCOL_HFINFO 1500
- /* Contains information about a field when a dissector calls
- * proto_tree_add_item. */
- #define FIELD_INFO_NEW(fi) fi = g_slice_new(field_info)
- #define FIELD_INFO_FREE(fi) g_slice_free(field_info, fi)
- /* Contains the space for proto_nodes. */
- #define PROTO_NODE_NEW(node) \
- node = g_slice_new(proto_node); \
- node->first_child = NULL; \
- node->last_child = NULL; \
- node->next = NULL;
- #define PROTO_NODE_FREE(node) \
- g_slice_free(proto_node, node)
- /* String space for protocol and field items for the GUI */
- #define ITEM_LABEL_NEW(il) \
- il = g_slice_new(item_label_t);
- #define ITEM_LABEL_FREE(il) \
- g_slice_free(item_label_t, il);
- #define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \
- if((guint)hfindex >= gpa_hfinfo.len && getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG")) \
- g_error("Unregistered hf! index=%d", hfindex); \
- DISSECTOR_ASSERT_HINT((guint)hfindex < gpa_hfinfo.len, "Unregistered hf!"); \
- hfinfo = gpa_hfinfo.hfi[hfindex];
- /* List which stores protocols and fields that have been registered */
- typedef struct _gpa_hfinfo_t {
- guint32 len;
- guint32 allocated_len;
- header_field_info **hfi;
- } gpa_hfinfo_t;
- static gpa_hfinfo_t gpa_hfinfo;
- /* Balanced tree of abbreviations and IDs */
- static GTree *gpa_name_tree = NULL;
- static header_field_info *same_name_hfinfo;
- static void save_same_name_hfinfo(gpointer data)
- {
- same_name_hfinfo = (header_field_info*)data;
- }
- /* Points to the first element of an array of bits, indexed by
- a subtree item type; that array element is TRUE if subtrees of
- an item of that type are to be expanded. */
- static guint32 *tree_is_expanded;
- /* Number of elements in that array. */
- int num_tree_types;
- /* Name hashtables for fast detection of duplicate names */
- static GHashTable* proto_names = NULL;
- static GHashTable* proto_short_names = NULL;
- static GHashTable* proto_filter_names = NULL;
- static gint
- proto_compare_name(gconstpointer p1_arg, gconstpointer p2_arg)
- {
- const protocol_t *p1 = (const protocol_t *)p1_arg;
- const protocol_t *p2 = (const protocol_t *)p2_arg;
- return g_ascii_strcasecmp(p1->short_name, p2->short_name);
- }
- /* 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),
- register_cb cb,
- gpointer client_data)
- {
- proto_cleanup();
- 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);
- gpa_hfinfo.len = 0;
- gpa_hfinfo.allocated_len = 0;
- gpa_hfinfo.hfi = NULL;
- gpa_name_tree = g_tree_new_full(wrs_strcmp_with_data, NULL, NULL, save_same_name_hfinfo);
- /* Initialize the ftype subsystem */
- ftypes_initialize();
- /* Register one special-case FT_TEXT_ONLY field for use when
- converting wireshark to new-style proto_tree. These fields
- are merely strings on the GUI tree; they are not filterable */
- hf_text_only = proto_register_field_init(&hfi_text_only, -1);
- /* Register the pseudo-protocols used for exceptions. */
- register_show_exception();
- /* Have each built-in dissector register its protocols, fields,
- 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);
- #ifdef HAVE_PYTHON
- /* Now scan for python protocols */
- if (cb)
- (*cb)(RA_PYTHON_REGISTER, NULL, client_data);
- register_all_py_protocols_func();
- #endif
- #ifdef HAVE_PLUGINS
- /* Now scan for plugins and load all the ones we find, calling
- their register routines to do the stuff described above. */
- 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_handoffs_func(cb, client_data);
- #ifdef HAVE_PYTHON
- /* Now do the same with python dissectors */
- if (cb)
- (*cb)(RA_PYTHON_HANDOFF, NULL, client_data);
- register_all_py_handoffs_func();
- #endif
- #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);
- /* We've assigned all the subtree type values; allocate the array
- for them, and zero it out. */
- tree_is_expanded = g_new0(guint32, (num_tree_types/32)+1);
- }
- void
- proto_cleanup(void)
- {
- /* Free the abbrev/ID GTree */
- if (gpa_name_tree) {
- g_tree_destroy(gpa_name_tree);
- gpa_name_tree = NULL;
- }
- while (protocols) {
- protocol_t *protocol = (protocol_t *)protocols->data;
- header_field_info *hfinfo;
- PROTO_REGISTRAR_GET_NTH(protocol->proto_id, hfinfo);
- DISSECTOR_ASSERT(protocol->proto_id == hfinfo->id);
- g_slice_free(header_field_info, hfinfo);
- g_slist_free(protocol->fields);
- protocols = g_list_remove(protocols, protocol);
- g_free(protocol);
- }
- if (proto_names) {
- g_hash_table_destroy(proto_names);
- proto_names = NULL;
- }
- if (proto_short_names) {
- g_hash_table_destroy(proto_short_names);
- proto_short_names = NULL;
- }
- if (proto_filter_names) {
- g_hash_table_destroy(proto_filter_names);
- proto_filter_names = NULL;
- }
- if (gpa_hfinfo.allocated_len) {
- gpa_hfinfo.len = 0;
- gpa_hfinfo.allocated_len = 0;
- g_free(gpa_hfinfo.hfi);
- gpa_hfinfo.hfi = NULL;
- }
- g_free(tree_is_expanded);
- tree_is_expanded = NULL;
- }
- static gboolean
- proto_tree_traverse_pre_order(proto_tree *tree, proto_tree_traverse_func func,
- gpointer data)
- {
- proto_node *pnode = tree;
- proto_node *child;
- proto_node *current;
- if (func(pnode, data))
- return TRUE;
- child = pnode->first_child;
- while (child != NULL) {
- /*
- * The routine we call might modify the child, e.g. by
- * freeing it, so we get the child's successor before
- * calling that routine.
- */
- current = child;
- child = current->next;
- if (proto_tree_traverse_pre_order((proto_tree *)current, func, data))
- return TRUE;
- }
- return FALSE;
- }
- gboolean
- proto_tree_traverse_post_order(proto_tree *tree, proto_tree_traverse_func func,
- gpointer data)
- {
- proto_node *pnode = tree;
- proto_node *child;
- proto_node *current;
- child = pnode->first_child;
- while (child != NULL) {
- /*
- * The routine we call might modify the child, e.g. by
- * freeing it, so we get the child's successor before
- * calling that routine.
- */
- current = child;
- child = current->next;
- if (proto_tree_traverse_post_order((proto_tree *)current, func, data))
- return TRUE;
- }
- if (func(pnode, data))
- return TRUE;
- return FALSE;
- }
- void
- proto_tree_children_foreach(proto_tree *tree, proto_tree_foreach_func func,
- gpointer data)
- {
- proto_node *node = tree;
- proto_node *current;
- if (!node)
- return;
- node = node->first_child;
- while (node != NULL) {
- current = node;
- node = current->next;
- func((proto_tree *)current, data);
- }
- }
- static void
- free_GPtrArray_value(gpointer key, gpointer value, gpointer user_data _U_)
- {
- GPtrArray *ptrs = (GPtrArray *)value;
- gint hfid = (gint)(long)key;
- header_field_info *hfinfo;
- PROTO_REGISTRAR_GET_NTH(hfid, hfinfo);
- if (hfinfo->ref_type != HF_REF_TYPE_NONE) {
- /* 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
- */
- if (hfinfo->parent != -1) {
- header_field_info *parent_hfinfo;
- PROTO_REGISTRAR_GET_NTH(hfinfo->parent, parent_hfinfo);
- parent_hfinfo->ref_type = HF_REF_TYPE_NONE;
- }
- hfinfo->ref_type = HF_REF_TYPE_NONE;
- }
- g_ptr_array_free(ptrs, TRUE);
- }
- static void
- free_node_tree_data(tree_data_t *tree_data)
- {
- if (tree_data->interesting_hfids) {
- /* Free all the GPtrArray's in the interesting_hfids hash. */
- g_hash_table_foreach(tree_data->interesting_hfids,
- free_GPtrArray_value, NULL);
- /* And then destroy the hash. */
- g_hash_table_destroy(tree_data->interesting_hfids);
- }
- if (tree_data->fi_tmp)
- FIELD_INFO_FREE(tree_data->fi_tmp);
- /* And finally the tree_data_t itself. */
- g_free(tree_data);
- }
- #define FREE_NODE_FIELD_INFO(finfo) \
- if (finfo->rep) { \
- ITEM_LABEL_FREE(finfo->rep); \
- } \
- FVALUE_CLEANUP(&finfo->value); \
- FIELD_INFO_FREE(finfo);
- static void
- proto_tree_free_node(proto_node *node, gpointer data _U_)
- {
- field_info *finfo = PNODE_FINFO(node);
- proto_tree_children_foreach(node, proto_tree_free_node, NULL);
- /* free the field_info data. */
- FREE_NODE_FIELD_INFO(finfo);
- node->finfo = NULL;
- /* Free the proto_node. */
- PROTO_NODE_FREE(node);
- }
- /* frees the resources that the dissection a proto_tree uses */
- void
- proto_tree_free(proto_tree *tree)
- {
- tree_data_t *tree_data = PTREE_DATA(tree);
- proto_tree_children_foreach(tree, proto_tree_free_node, NULL);
- /* free root node */
- PROTO_NODE_FREE(tree);
- /* free tree data */
- free_node_tree_data(tree_data);
- }
- /* Is the parsing being done for a visible proto_tree or an invisible one?
- * By setting this correctly, the proto_tree creation is sped up by not
- * having to call g_vsnprintf and copy strings around.
- */
- gboolean
- proto_tree_set_visible(proto_tree *tree, gboolean visible)
- {
- gboolean old_visible = PTREE_DATA(tree)->visible;
- PTREE_DATA(tree)->visible = visible;
- return old_visible;
- }
- void
- proto_tree_set_fake_protocols(proto_tree *tree, gboolean fake_protocols)
- {
- PTREE_DATA(tree)->fake_protocols = fake_protocols;
- }
- /* Assume dissector set only its protocol fields.
- This function is called by dissectors and allows the speeding up of filtering
- 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 implicitly assume the field is referenced.
- */
- gboolean
- proto_field_is_referenced(proto_tree *tree, int proto_id)
- {
- register header_field_info *hfinfo;
- if (!tree)
- return FALSE;
- if (PTREE_DATA(tree)->visible)
- return TRUE;
- PROTO_REGISTRAR_GET_NTH(proto_id, hfinfo);
- if (hfinfo->ref_type != HF_REF_TYPE_NONE)
- return TRUE;
- if (hfinfo->type == FT_PROTOCOL && !PTREE_DATA(tree)->fake_protocols)
- return TRUE;
- return FALSE;
- }
- /* Finds a record in the hfinfo array by id. */
- header_field_info *
- proto_registrar_get_nth(guint hfindex)
- {
- register header_field_info *hfinfo;
- PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
- return hfinfo;
- }
- /* Prefix initialization
- * this allows for a dissector to register a display filter name prefix
- * so that it can delay the initialization of the hf array as long as
- * possible.
- */
- /* compute a hash for the part before the dot of a display filter */
- static guint
- prefix_hash (gconstpointer key) {
- /* end the string at the dot and compute its hash */
- gchar* copy = ep_strdup((const gchar *)key);
- gchar* c = copy;
- for (; *c; c++) {
- if (*c == '.') {
- *c = 0;
- break;
- }
- }
- return g_str_hash(copy);
- }
- /* are both strings equal up to the end or the dot? */
- static gboolean
- prefix_equal (gconstpointer ap, gconstpointer bp) {
- const gchar* a = (const gchar *)ap;
- const gchar* b = (const gchar *)bp;
- do {
- gchar ac = *a++;
- gchar bc = *b++;
- if ( (ac == '.' || ac == '\0') && (bc == '.' || bc == '\0') ) return TRUE;
- if ( (ac == '.' || ac == '\0') && ! (bc == '.' || bc == '\0') ) return FALSE;
- if ( (bc == '.' || bc == '\0') && ! (ac == '.' || ac == '\0') ) return FALSE;
- if (ac != bc) return FALSE;
- } while (1);
- 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 ) {
- if (! prefixes ) {
- prefixes = g_hash_table_new(prefix_hash, prefix_equal);
- }
- g_hash_table_insert(prefixes, (gpointer)prefix, pi);
- }
- /* helper to call all prefix initializers */
- static gboolean
- initialize_prefix(gpointer k, gpointer v, gpointer u _U_) {
- ((prefix_initializer_t)v)((const char *)k);
- return TRUE;
- }
- /** Initialize every remaining uninitialized prefix. */
- void
- proto_initialize_all_prefixes(void) {
- g_hash_table_foreach_remove(prefixes, initialize_prefix, NULL);
- }
- /* Finds a record in the hfinfo array by name.
- * If it fails to find it in the already registered fields,
- * it tries to find and call an initializer in the prefixes
- * table and if so it looks again.
- */
- header_field_info *
- proto_registrar_get_byname(const char *field_name)
- {
- header_field_info *hfinfo;
- prefix_initializer_t pi;
- if (!field_name)
- return NULL;
- hfinfo = (header_field_info *)g_tree_lookup(gpa_name_tree, field_name);
- if (hfinfo)
- return hfinfo;
- if (!prefixes)
- return NULL;
- if ((pi = (prefix_initializer_t)g_hash_table_lookup(prefixes, field_name) ) != NULL) {
- pi(field_name);
- g_hash_table_remove(prefixes, field_name);
- } else {
- return NULL;
- }
- return (header_field_info *)g_tree_lookup(gpa_name_tree, field_name);
- }
- int
- proto_registrar_get_id_byname(const char *field_name)
- {
- header_field_info *hfinfo;
- hfinfo = proto_registrar_get_byname(field_name);
- if (!hfinfo)
- return -1;
- return hfinfo->id;
- }
- static 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 = (subtree_lvl *)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;
- }
- static 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:
- * proto_tree, tvbuff, and offset. */
- ptvcursor_t *
- ptvcursor_new(proto_tree *tree, tvbuff_t *tvb, gint offset)
- {
- ptvcursor_t *ptvc;
- ptvc = (ptvcursor_t *)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)
- {
- ptvcursor_free_subtree_levels(ptvc);
- /*g_free(ptvc);*/
- }
- /* Returns tvbuff. */
- tvbuff_t *
- ptvcursor_tvbuff(ptvcursor_t *ptvc)
- {
- return ptvc->tvb;
- }
- /* Returns current offset. */
- gint
- ptvcursor_current_offset(ptvcursor_t *ptvc)
- {
- return ptvc->offset;
- }
- proto_tree *
- ptvcursor_tree(ptvcursor_t *ptvc)
- {
- if (!ptvc)
- return NULL;
- return ptvc->tree;
- }
- void
- ptvcursor_set_tree(ptvcursor_t *ptvc, proto_tree *tree)
- {
- 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 */
- static 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;
- }
- static 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,
- const guint encoding, gint ett_subtree)
- {
- proto_item *it;
- it = ptvcursor_add_no_advance(ptvc, hfindex, length, encoding);
- 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 *pi;
- va_list ap;
- header_field_info *hfinfo;
- proto_tree *tree;
- tree = ptvcursor_tree(ptvc);
- TRY_TO_FAKE_THIS_ITEM(tree, hf_text_only, hfinfo);
- pi = proto_tree_add_text_node(tree, ptvcursor_tvbuff(ptvc),
- ptvcursor_current_offset(ptvc), length);
- TRY_TO_FAKE_THIS_REPR(pi);
- va_start(ap, format);
- proto_tree_set_representation(pi, format, ap);
- va_end(ap);
- return ptvcursor_add_subtree_item(ptvc, pi, 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)
- {
- proto_item *pi;
- field_info *new_fi;
- if (tree == NULL)
- return NULL;
- pi = proto_tree_add_pi(tree, &hfi_text_only, tvb, start, &length, &new_fi);
- return pi;
- }
- /* Add a text-only node to the proto_tree */
- proto_item *
- proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length,
- const char *format, ...)
- {
- proto_item *pi;
- va_list ap;
- header_field_info *hfinfo;
- TRY_TO_FAKE_THIS_ITEM(tree, hf_text_only, hfinfo);
- pi = proto_tree_add_text_node(tree, tvb, start, length);
- TRY_TO_FAKE_THIS_REPR(pi);
- va_start(ap, format);
- proto_tree_set_representation(pi, format, ap);
- va_end(ap);
- return pi;
- }
- /* Add a text-only node to the proto_tree (va_list version) */
- proto_item *
- proto_tree_add_text_valist(proto_tree *tree, tvbuff_t *tvb, gint start,
- gint length, const char *format, va_list ap)
- {
- proto_item *pi;
- header_field_info *hfinfo;
- TRY_TO_FAKE_THIS_ITEM(tree, hf_text_only, hfinfo);
- pi = proto_tree_add_text_node(tree, tvb, start, length);
- TRY_TO_FAKE_THIS_REPR(pi);
- proto_tree_set_representation(pi, format, ap);
- return pi;
- }
- /* Add a text-only node for debugging purposes. The caller doesn't need
- * to worry about tvbuff, start, or length. Debug message gets sent to
- * STDOUT, too */
- proto_item *
- proto_tree_add_debug_text(proto_tree *tree, const char *format, ...)
- {
- proto_item *pi;
- va_list ap;
- pi = proto_tree_add_text_node(tree, NULL, 0, 0);
- if (pi) {
- va_start(ap, format);
- proto_tree_set_representation(pi, format, ap);
- va_end(ap);
- }
- va_start(ap, format);
- vprintf(format, ap);
- va_end(ap);
- printf("\n");
- return pi;
- }
- /* We could probably get away with changing is_error to a minimum length value. */
- static void
- report_type_length_mismatch(proto_tree *tree, const gchar *descr, int length, gboolean is_error) {
- if (tree) {
- tree_data_t *tree_data = PTREE_DATA(tree);
- field_info *fi_save = tree_data->fi_tmp;
- /* Keep the current item from getting freed by proto_tree_new_item. */
- tree_data->fi_tmp = NULL;
- expert_add_info_format(NULL, tree, PI_MALFORMED, is_error ? PI_ERROR : PI_WARN, "Trying to fetch %s with length %d", descr, length);
- tree_data->fi_tmp = fi_save;
- }
- if (is_error) {
- THROW(ReportedBoundsError);
- }
- }
- static guint32
- get_uint_value(proto_tree *tree, tvbuff_t *tvb, gint offset, gint length, const guint encoding)
- {
- guint32 value;
- gboolean length_error;
- switch (length) {
- case 1:
- value = tvb_get_guint8(tvb, offset);
- break;
- case 2:
- value = (encoding & ENC_LITTLE_ENDIAN) ? tvb_get_letohs(tvb, offset)
- : tvb_get_ntohs(tvb, offset);
- break;
- case 3:
- value = (encoding & ENC_LITTLE_ENDIAN) ? tvb_get_letoh24(tvb, offset)
- : tvb_get_ntoh24(tvb, offset);
- break;
- case 4:
- value = (encoding & ENC_LITTLE_ENDIAN) ? tvb_get_letohl(tvb, offset)
- : tvb_get_ntohl(tvb, offset);
- break;
- default:
- if (length < 1) {
- length_error = TRUE;
- value = 0;
- } else {
- length_error = FALSE;
- value = (encoding & ENC_LITTLE_ENDIAN) ? tvb_get_letohl(tvb, offset)
- : tvb_get_ntohl(tvb, offset);
- }
- report_type_length_mismatch(tree, "an unsigned integer", length, length_error);
- break;
- }
- return value;
- }
- /*
- * NOTE: to support code written when proto_tree_add_item() took a
- * gboolean as its last argument, with FALSE meaning "big-endian"
- * and TRUE meaning "little-endian", we treat any non-zero value of
- * "encoding" as meaning "little-endian".
- */
- static gint32
- get_int_value(proto_tree *tree, tvbuff_t *tvb, gint offset, gint length, const guint encoding)
- {
- gint32 value;
- gboolean length_error;
- switch (length) {
- case 1:
- value = (gint8)tvb_get_guint8(tvb, offset);
- break;
- case 2:
- value = (gint16) (encoding ? tvb_get_letohs(tvb, offset)
- : tvb_get_ntohs(tvb, offset));
- break;
- case 3:
- value = encoding ? tvb_get_letoh24(tvb, offset)
- : tvb_get_ntoh24(tvb, offset);
- if (value & 0x00800000) {
- /* Sign bit is set; sign-extend it. */
- value |= 0xFF000000;
- }
- break;
- case 4:
- value = encoding ? tvb_get_letohl(tvb, offset)
- : tvb_get_ntohl(tvb, offset);
- break;
- default:
- if (length < 1) {
- length_error = TRUE;
- value = 0;
- } else {
- length_error = FALSE;
- value = encoding ? tvb_get_letohl(tvb, offset)
- : tvb_get_ntohl(tvb, offset);
- }
- report_type_length_mismatch(tree, "a signed integer", length, length_error);
- break;
- }
- return value;
- }
- static void
- tree_data_add_maybe_interesting_field(tree_data_t *tree_data, field_info *fi)
- {
- const header_field_info *hfinfo = fi->hfinfo;
- if (hfinfo->ref_type == HF_REF_TYPE_DIRECT) {
- GPtrArray *ptrs = NULL;
- if (tree_data->interesting_hfids == NULL) {
- /* Initialize the hash because we now know that it is needed */
- tree_data->interesting_hfids =
- g_hash_table_new(g_direct_hash, NULL /* g_direct_equal */);
- } else
- ptrs = (GPtrArray *)g_hash_table_lookup(tree_data->interesting_hfids,
- GINT_TO_POINTER(hfinfo->id));
- if (!ptrs) {
- /* First element triggers the creation of pointer array */
- ptrs = g_ptr_array_new();
- g_hash_table_insert(tree_data->interesting_hfids,
- GINT_TO_POINTER(hfinfo->id), ptrs);
- }
- g_ptr_array_add(ptrs, fi);
- }
- }
- /* 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 *
- proto_tree_new_item(field_info *new_fi, proto_tree *tree,
- tvbuff_t *tvb, gint start, gint length,
- guint encoding)
- {
- tree_data_t *tree_data = PTREE_DATA(tree);
- proto_item *pi;
- guint32 value, n;
- float floatval;
- double doubleval;
- const char *string;
- nstime_t time_stamp;
- guint32 tmpsecs;
- gboolean length_error;
- /* there is a possibility here that we might raise an exception
- * and thus would lose track of the field_info.
- * store it in a temp so that if we come here again we can reclaim
- * the field_info without leaking memory.
- */
- if (tree_data->fi_tmp) {
- /* oops, last one we got must have been lost due
- * to an exception.
- * good thing we saved it, now we can reverse the
- * memory leak and reclaim it.
- */
- FIELD_INFO_FREE(tree_data->fi_tmp);
- }
- /* we might throw an exception, keep track of this one
- * across the "dangerous" section below.
- */
- tree_data->fi_tmp = new_fi;
- switch (new_fi->hfinfo->type) {
- case FT_NONE:
- /* no value to set for FT_NONE */
- break;
- case FT_PROTOCOL:
- proto_tree_set_protocol_tvb(new_fi, tvb);
- break;
- case FT_BYTES:
- proto_tree_set_bytes_tvb(new_fi, tvb, start, length);
- 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);
- /* Instead of calling proto_item_set_len(), since we don't yet
- * have a proto_item, we set the field_info's length ourselves. */
- new_fi->length = n + length;
- break;
- case FT_BOOLEAN:
- /*
- * Map all non-zero values to little-endian for
- * backwards compatibility.
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- proto_tree_set_boolean(new_fi,
- get_uint_value(tree, tvb, start, length, encoding));
- break;
- /* XXX - make these just FT_UINT? */
- case FT_UINT8:
- 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));
- break;
- case FT_INT64:
- case FT_UINT64:
- /*
- * Map all non-zero values to little-endian for
- * backwards compatibility.
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- if (length < 1 || length > 8) {
- length_error = length < 1 ? TRUE : FALSE;
- report_type_length_mismatch(tree, "a 64-bit integer", length, length_error);
- }
- proto_tree_set_uint64_tvb(new_fi, tvb, start, length, encoding);
- break;
- /* XXX - make these just FT_INT? */
- case FT_INT8:
- case FT_INT16:
- case FT_INT24:
- case FT_INT32:
- /*
- * Map all non-zero values to little-endian for
- * backwards compatibility.
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- proto_tree_set_int(new_fi,
- get_int_value(tree, tvb, start, length, encoding));
- break;
- case FT_IPv4:
- /*
- * Map all non-zero values to little-endian for
- * backwards compatibility.
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- if (length != FT_IPv4_LEN) {
- length_error = length < FT_IPv4_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "an IPv4 address", length, length_error);
- }
- value = tvb_get_ipv4(tvb, start);
- /*
- * NOTE: to support code written when
- * proto_tree_add_item() took a gboolean as its
- * last argument, with FALSE meaning "big-endian"
- * and TRUE meaning "little-endian", we treat any
- * non-zero value of "encoding" as meaning
- * "little-endian".
- */
- proto_tree_set_ipv4(new_fi, encoding ? GUINT32_SWAP_LE_BE(value) : value);
- break;
- case FT_IPXNET:
- if (length != FT_IPXNET_LEN) {
- length_error = length < FT_IPXNET_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "an IPXNET address", length, length_error);
- }
- proto_tree_set_ipxnet(new_fi,
- get_uint_value(tree, tvb, start, FT_IPXNET_LEN, ENC_BIG_ENDIAN));
- break;
- case FT_IPv6:
- if (length != FT_IPv6_LEN) {
- length_error = length < FT_IPv6_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "an IPv6 address", length, length_error);
- }
- proto_tree_set_ipv6_tvb(new_fi, tvb, start, length);
- break;
- case FT_AX25:
- if (length != 7) {
- length_error = length < 7 ? TRUE : FALSE;
- report_type_length_mismatch(tree, "an AX.25 address", length, length_error);
- }
- proto_tree_set_ax25_tvb(new_fi, tvb, start);
- break;
- case FT_VINES:
- if (length != VINES_ADDR_LEN) {
- length_error = length < VINES_ADDR_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "a Vines address", length, length_error);
- }
- proto_tree_set_vines_tvb(new_fi, tvb, start);
- break;
- case FT_ETHER:
- if (length != FT_ETHER_LEN) {
- length_error = length < FT_ETHER_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "an Ethernet", length, length_error);
- }
- proto_tree_set_ether_tvb(new_fi, tvb, start);
- break;
- case FT_EUI64:
- /*
- * Map all non-zero values to little-endian for
- * backwards compatibility.
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- if (length != FT_EUI64_LEN) {
- length_error = length < FT_EUI64_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "an EUI-64 address", length, length_error);
- }
- proto_tree_set_eui64_tvb(new_fi, tvb, start, encoding);
- break;
- case FT_GUID:
- /*
- * Map all non-zero values to little-endian for
- * backwards compatibility.
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- if (length != FT_GUID_LEN) {
- length_error = length < FT_GUID_LEN ? TRUE : FALSE;
- report_type_length_mismatch(tree, "a GUID", length, length_error);
- }
- proto_tree_set_guid_tvb(new_fi, tvb, start, encoding);
- break;
- case FT_OID:
- proto_tree_set_oid_tvb(new_fi, tvb, start, length);
- break;
- case FT_FLOAT:
- /*
- * NOTE: to support code written when
- * proto_tree_add_item() took a gboolean as its
- * last argument, with FALSE meaning "big-endian"
- * and TRUE meaning "little-endian", we treat any
- * non-zero value of "encoding" as meaning
- * "little-endian".
- *
- * At some point in the future, we might
- * support non-IEEE-binary floating-point
- * formats in the encoding as well
- * (IEEE decimal, System/3x0, VAX).
- */
- if (encoding)
- encoding = ENC_LITTLE_ENDIAN;
- if (length != 4) {
- length_error = length < 4 ? TRUE : FALSE;
- report_type_length_mismatch(tree, "a single-precision floating point number", length, length_error);
- }
- if (encoding)
- floatval = tvb_get_letohieee_float(tvb, start);
- else
- floatval = tvb_get_ntohieee_float(tvb, start);
- proto_tree_set_float(new_fi, floatval);
- break;
- case FT_DOUBLE:
- /*
- * NOTE: to support code written when
- * proto_tree_add_item() took a gboolean as its
- * last argument, with FALSE meaning "big-endian"
- * and TRUE meaning "little-endian", we treat any
- * non-zero value of "encoding" as meaning
- * "little-endian".
- *
- * At some point in the future, we might
- * support non-IEEE-binary floating-point
- * formats in the encoding as well
- * (IEEE decimal, System/3x0, VAX).
- */
- if (encoding == TRUE)
- encoding = ENC_LITTLE_ENDIAN;
- if (length != 8) {
- length_error = length < 8 ? TRUE : FALSE;
- report_type_length_mismatch(tree, "a double-precision floating point number", length, length_error);
- }
- if (encoding)
- doubleval = tvb_get_letohieee_double(tvb, start);
- else
- doubleval = tvb_get_ntohieee_double(tvb, start);
- proto_tree_set_double(new_fi, doubleval);
- break;
- case FT_STRING:
- proto_tree_set_string_tvb(new_fi, tvb, start, length,
- encoding);
- break;
- case FT_STRINGZ:
- if (length < -1 ) {
- report_type_length_mismatch(tree, "a string", length, TRUE);
- }
- /* Instead of calling proto_item_set_len(),
- * since we don't yet have a proto_item, we
- * set the field_info's length ourselves.
- *
- * XXX - our caller can't use that length to
- * advance an offset unless they arrange that
- * there always be a protocol tree into which
- * we're putting this item.
- */
- if (length == -1) {
- /* This can throw an exception */
- string = tvb_get_stringz_enc(tvb, start, &length, encoding);
- } else if (length == 0) {
- string = "[Empty]";
- } else {
- /* In this case, length signifies
- * the length of the string.
- *
- * This could either be a null-padded
- * string, which doesn't necessarily
- * have a '\0' at the end, or a
- * null-terminated string, with a
- * trailing '\0'. (Yes, there are
- * cases where you have a string
- * that's both counted and null-
- * terminated.)
- *
- * In the first case, we must
- * allocate a buffer of length
- * "length+1", to make room for
- * a trailing '\0'.
- *
- * In the second case, we don't
- * assume that there is a trailing
- * '\0' there, as the packet might
- * be malformed. (XXX - should we
- * throw an exception if there's no
- * trailing '\0'?) Therefore, we
- * allocate a buffer of length
- * "length+1", and put in a trailing
- * '\0', just to be safe.
- *
- * (XXX - this would change if
- * we made string values counted
- * rather than null-terminated.)
- */
- string = tvb_get_ephemeral_string_enc(tvb, start, length, encoding);
- }
- new_fi->length = length;
- proto_tree_set_string(new_fi, string);
- break;
- case FT_UINT_STRING:
- /*
- * NOTE: to support code written when
- * proto_tree_add_item() took a gboolean as its
- * last argument, with FALSE meaning "big-endian"
- * and TRUE meaning "little-endian", if the
- * encoding value is TRUE, treat that as
- * ASCII with a little-endian length.
- *
- * This won't work for code that passes
- * arbitrary non-zero values; that code
- * will need to be fixed.
- */
- if (encoding == TRUE)
- encoding = ENC_ASCII|ENC_LITTLE_ENDIAN;
- n = get_uint_value(tree, tvb, start, length, encoding & ~ENC_CHARENCODING_MASK);
- proto_tree_set_string_tvb(new_fi, tvb, start + length, n,
- encoding);
- /* Instead of calling proto_item_set_len(), since we
- * don't yet have a proto_item, we set the
- * field_info's length ourselves.
- *
- * XXX - our caller can't use that length to
- * advance an offset unless they arrange that
- * there always be a protocol tree into which
- * we're putting this item.
- */
- new_fi->length = n + length;
- break;
- case FT_ABSOLUTE_TIME:
- /*
- * Absolute 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, "an absolute time value", length, length_error);
- }
- 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.
- */
- time_stamp.secs = tvb_get_ntohl(tvb, start);
- if (length == 8)
- time_stamp.nsecs = tvb_get_ntohl(tvb, start+4);
- else
- time_stamp.nsecs = 0;
- break;
- case ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN:
- /*
- * 4-byte UNIX epoch, possibly followed by
- * 4-byte fractional time in nanoseconds,
- * both little-endian.
- */
- time_stamp.secs = tvb_get_letohl(tvb, start);
- if (length == 8)
- time_stamp.nsecs = tvb_get_letohl(tvb, start+4);
- else
- time_stamp.nsecs = 0;
- break;
- case ENC_TIME_NTP|ENC_BIG_ENDIAN:
- /*
- * NTP time stamp, big-endian.
- */
- /* XXX - where should this go? */
- #define NTP_BASETIME 2208988800ul
- /* 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 = tmpsecs - (guint32)NTP_BASETIME;
- else
- time_stamp.secs = tmpsecs; /* 0 */
- 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.
- */
- time_stamp.nsecs = (int)(1000000*(tvb_get_ntohl(tvb, start+4)/4294967296.0));
- time_stamp.nsecs *= 1000;
- } else {
- time_stamp.nsecs = 0;
- }
- break;
- case ENC_TIME_NTP|ENC_LITTLE_ENDIAN:
- /*
- * NTP time stamp, big-endian.
- */
- tmpsecs = tvb_get_letohl(tvb, start);
- if (tmpsecs)
- time_stamp.secs = tmpsecs - (guint32)NTP_BASETIME;
- else
- time_stamp.secs = tmpsecs; /* 0 */
- 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.
- */
- time_stamp.nsecs = (int)(1000000*(tvb_get_letohl(tvb, start+4)/4294967296.0));
- time_stamp.nsecs *= 1000;
- } else {
- time_stamp.nsecs = 0;
- }
- break;
- default:
- DISSECTOR_ASSERT_NOT_REACHED();
- time_stamp.secs = 0;
- time_stamp.nsecs = 0;
- break;
- }
- 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;
- switch (encoding) {
- if (length != 8 && length != 4) {
- length_error = length < 4 ? TRUE : FALSE;
- report_type_length_mismatch(tree, "a relative time value", length, length_error);
- }
- case ENC_TIME_TIMESPEC|ENC_BIG_ENDIAN:
- /*
- * 4-byte UNIX epoch, possibly followed by
- * 4-byte fractional time in nanoseconds,
- * both big-endian.
- */
- time_stamp.secs = tvb_get_ntohl(tvb, start);
- if (length == 8)
- time_stamp.nsecs = tvb_get_ntohl(tvb, start+4);
- else
- time_stamp.nsecs = 0;
- break;
- case ENC_TIME_TIMESPEC|ENC_LITTLE_ENDIAN:
- /*
- * 4-byte UNIX epoch, possibly followed by
- * 4-byte fractional time in nanoseconds,
- * both little-endian.
- */
- time_stamp.secs = tvb_get_letohl(tvb, start);
- if (length == 8)
- time_stamp.nsecs = tvb_get_letohl(tvb, start+4);
- else
- time_stamp.nsecs = 0;
- break;
- }
- proto_tree_set_time(new_fi, &time_stamp);
- 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);
- /* we did not raise an exception so we dont have to remember this
- * field_info struct any more.
- */
- tree_data->fi_tmp = NULL;
- return pi;
- }
- /* Gets data from tvbuff, adds it to proto_tree, increments offset,
- and returns proto_item* */
- proto_item *
- ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
- const guint encoding)
- {
- field_info *new_fi;
- header_field_info *hfinfo;
- gint item_length;
- guint32 n;
- int offset;
- /* We can't fake it just yet. We have to advance the cursor
- TRY_TO_FAKE_THIS_ITEā¦
Large files files are truncated, but you can click here to view the full file