Make FT_STRINGZ items work as apply/prepare as filter menu items
[obnox/wireshark/wip.git] / epan / proto.c
index f3411740b59e893b41fbcc813d684decdc87b370..9be193a7a923bb73735785e6ce243528081dad37 100644 (file)
@@ -3,8 +3,8 @@
  *
  * $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
@@ -151,9 +151,9 @@ 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);
 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
@@ -240,7 +240,7 @@ static SLAB_FREE_LIST_DEFINE(item_label_t)
 
 #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 */
@@ -314,7 +314,7 @@ proto_init(const char *plugin_dir
        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));
 
@@ -484,10 +484,10 @@ free_GPtrArray_value(gpointer key _U_, gpointer value, gpointer user_data _U_)
        gint hfid = (gint)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
                */
@@ -557,7 +557,7 @@ proto_tree_set_visible(proto_tree *tree, gboolean visible)
 
 /* 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.
@@ -902,7 +902,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
 
                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:
@@ -1033,6 +1033,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
        /* 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) {
@@ -1637,7 +1638,7 @@ proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start)
 /* 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;
@@ -1659,7 +1660,7 @@ proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
 
 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;
 
@@ -1674,7 +1675,7 @@ proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 
 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;
@@ -1693,7 +1694,7 @@ proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
 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;
@@ -1711,16 +1712,19 @@ proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 
 /* 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);
        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 */
@@ -1917,11 +1921,11 @@ proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
  * 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 :
@@ -2639,7 +2643,9 @@ proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
        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)
@@ -2667,6 +2673,14 @@ 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;
@@ -2705,6 +2719,7 @@ proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        /* 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) {
@@ -2835,7 +2850,7 @@ get_hfi_and_length(int hfindex, tvbuff_t *tvb, gint start, gint *length,
                         * 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? */
@@ -3043,7 +3058,7 @@ proto_item_get_len(proto_item *pi)
        (fi->flags = (fi)->flags | (flags_in)); \
 }
 
-gboolean 
+gboolean
 proto_item_set_expert_flags(proto_item *pi, int group, int severity)
 {
        if(pi == NULL || pi->finfo == NULL)
@@ -3083,6 +3098,9 @@ proto_tree_create_root(void)
         * 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;
 }
 
@@ -3161,7 +3179,7 @@ proto_item_get_parent_nth(proto_item *ti, int gen) {
 }
 
 
-proto_item* 
+proto_item*
 proto_tree_get_parent(proto_tree *tree) {
        /* dont bother if tree is not visible */
        if( (!tree) || (!(PTREE_DATA(tree)->visible)) )
@@ -3169,6 +3187,16 @@ proto_tree_get_parent(proto_tree *tree) {
        return (proto_item*) tree;
 }
 
+proto_tree*
+proto_tree_get_root(proto_tree *tree) {
+       /* dont bother if tree is not visible */
+       if( (!tree) || (!(PTREE_DATA(tree)->visible)) )
+               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)
@@ -3197,7 +3225,7 @@ proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_
         /* fix last_child if required */
         if(tree->last_child == item_to_move) {
             tree->last_child = curr_item;
-        } 
+        }
     }
 
     /*** insert to_move after fixed ***/
@@ -3231,7 +3259,7 @@ proto_register_protocol(const char *name, const char *short_name, const char *fi
      * 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.
@@ -3669,6 +3697,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
        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 */
@@ -3827,10 +3856,10 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        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;
@@ -4414,6 +4443,7 @@ hfinfo_int_format(header_field_info *hfinfo)
                                        DISSECTOR_ASSERT_NOT_REACHED();
                                        ;
                        }
+                       break;
                case BASE_HEX_DEC:
                        switch(hfinfo->type) {
                                case FT_INT8:
@@ -4568,12 +4598,13 @@ proto_get_finfo_ptr_array(proto_tree *tree, int id)
 }
 
 
-/* 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)
 {
@@ -4589,11 +4620,11 @@ 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)
 {
@@ -4605,7 +4636,34 @@ 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 {
@@ -4669,7 +4727,7 @@ proto_registrar_dump_protocols(void)
 {
        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)) {
@@ -4845,25 +4903,10 @@ proto_registrar_dump_fields(int format)
                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 */
@@ -4904,7 +4947,7 @@ proto_registrar_dump_fields(int format)
                                        hfinfo->type == FT_INT32 ||
                                        hfinfo->type == FT_INT64) {
 
-                                       
+
                                        switch(hfinfo->display) {
                                                case BASE_NONE:
                                                        base_name = "BASE_NONE";
@@ -5074,7 +5117,12 @@ proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
                         * These all have values, so we can match.
                         */
                        return TRUE;
-
+               case FT_NONE:
+                       /*
+                        * Doesn't have a value, but may still want to test
+                        * for its presence in a trace
+                        */
+                       return TRUE;
                default:
                        /*
                         * This doesn't have a value, so we'd match
@@ -5122,7 +5170,7 @@ proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
 }
 
 /* This function returns a string allocated with packet lifetime scope.
- * You do not need to [g_]free() this string since it will be automatically 
+ * You do not need to [g_]free() this string since it will be automatically
  * freed once the next packet is dissected.
  */
 char*
@@ -5222,9 +5270,11 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                case FT_IPXNET:
                case FT_BOOLEAN:
                case FT_STRING:
+               case FT_STRINGZ:
                case FT_ETHER:
                case FT_BYTES:
                case FT_UINT_BYTES:
+               case FT_UINT_STRING:
                case FT_FLOAT:
                case FT_DOUBLE:
                case FT_ABSOLUTE_TIME:
@@ -5280,13 +5330,18 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                                return NULL;    /* you lose */
 
                        /*
-                        * If the length is 0, there's nothing to match, so
-                        * we can't match.  (Also check for negative values,
+                        * 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 (length == 0)
+                       {
+                               buf = ep_strdup(finfo->hfinfo->abbrev);
+                               break;
+                       }
+                       if (length < 0)
                                return NULL;
 
                        /*
@@ -5297,7 +5352,7 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                                length = length_remaining;
                        if (length <= 0)
                                return NULL;
-                       
+
                        start = finfo->start;
                        buf_len = 32 + length * 3;
                        buf = ep_alloc0(buf_len);
@@ -5311,7 +5366,7 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                                        ptr += g_snprintf(ptr, buf_len-(ptr-buf), "%02x", c);
                                }
                                else {
-                                       ptr += snprintf(ptr, buf_len-(ptr-buf), ":%02x", c);
+                                       ptr += g_snprintf(ptr, buf_len-(ptr-buf), ":%02x", c);
                                }
                        }
                        break;