aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dfilter
diff options
context:
space:
mode:
authorJoão Valverde <j@v6e.pt>2022-03-27 15:26:46 +0100
committerA Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2022-03-29 12:36:31 +0000
commit260942e17041a79cb2ca27b6e016867da3c60735 (patch)
treebce62e73e0172242fd53951adcbe3ef4c8b77499 /epan/dfilter
parent431cb43b815d837f7ccd1dfba164ba0e758456a0 (diff)
dfilter: Refactor macro tree references
This replaces the current macro reference system with a completely different implementation. Instead of a macro a reference is a syntax element. A reference is a constant that can be filled in the dfilter code after compilation from an existing protocol tree. It is best understood as a field value that can be read from a fixed tree that is not the frame being filtered. Usually this fixed tree is the currently selected frame when the filter is applied. This allows comparing fields in the filtered frame with fields in the selected frame. Because the field reference syntax uses the same sigil notation as a macro we have to use a heuristic to distinguish them: if the name has a dot it is a field reference, otherwise it is a macro name. The reference is synctatically validated at compile time. There are two main advantages to this implementation (and a couple of minor ones): The protocol tree for each selected frame is only walked if we have a display filter and if the display filter uses references. Also only the actual reference values are copied, intead of loading the entire tree into a hash table (in textual form even). The other advantage is that the reference is tested like a protocol field against all the values in the selected frame (if there is more than one). Currently the reference fields are not "primed" during dissection, so the entire tree is walked to find a particular reference (this is similar to the previous implementation). If the display filter contains a valid reference and the reference is not loaded at the time the filter is run the result is the same as a non existing field for a regular READ_TREE instruction. Fixes #17599.
Diffstat (limited to 'epan/dfilter')
-rw-r--r--epan/dfilter/dfilter-int.h3
-rw-r--r--epan/dfilter/dfilter-macro.c83
-rw-r--r--epan/dfilter/dfilter-macro.h3
-rw-r--r--epan/dfilter/dfilter.c77
-rw-r--r--epan/dfilter/dfilter.h5
-rw-r--r--epan/dfilter/dfvm.c73
-rw-r--r--epan/dfilter/dfvm.h3
-rw-r--r--epan/dfilter/gencode.c57
-rw-r--r--epan/dfilter/grammar.lemon10
-rw-r--r--epan/dfilter/scanner.l20
-rw-r--r--epan/dfilter/semcheck.c19
-rw-r--r--epan/dfilter/sttype-pointer.c12
-rw-r--r--epan/dfilter/syntax-tree.h1
13 files changed, 287 insertions, 79 deletions
diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h
index aaaf4b0f53..6ff14f43f1 100644
--- a/epan/dfilter/dfilter-int.h
+++ b/epan/dfilter/dfilter-int.h
@@ -27,6 +27,7 @@ struct epan_dfilter {
int num_interesting_fields;
GPtrArray *deprecated;
char *expanded_text;
+ GHashTable *references;
};
typedef struct {
@@ -40,6 +41,8 @@ typedef struct {
int next_insn_id;
int next_register;
GPtrArray *deprecated;
+ GHashTable *references; /* hfinfo -> pointer to GSList of const fvalues */
+ GHashTable *loaded_references;
} dfwork_t;
/*
diff --git a/epan/dfilter/dfilter-macro.c b/epan/dfilter/dfilter-macro.c
index 16f5ff2bfc..3ce0f668cf 100644
--- a/epan/dfilter/dfilter-macro.c
+++ b/epan/dfilter/dfilter-macro.c
@@ -23,16 +23,10 @@
#include <epan/proto.h>
#include <wsutil/glib-compat.h>
-typedef struct {
- const char* name;
- gboolean usable;
- char* repr;
-} fvt_cache_entry_t;
static uat_t* dfilter_macro_uat = NULL;
static dfilter_macro_t* macros = NULL;
static guint num_macros;
-static GHashTable* fvt_cache = NULL;
/* #define DUMP_DFILTER_MACRO */
#ifdef DUMP_DFILTER_MACRO
@@ -42,51 +36,10 @@ void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const
#define DUMP_MACRO(m)
#endif
-static gboolean fvt_cache_cb(proto_node * node, gpointer data _U_) {
- field_info* finfo = PNODE_FINFO(node);
- fvt_cache_entry_t* e;
-
- if (!finfo) return FALSE;
-
- if ((e = (fvt_cache_entry_t*)g_hash_table_lookup(fvt_cache,finfo->hfinfo->abbrev))) {
- e->usable = FALSE;
- } else {
- switch (finfo->hfinfo->type) {
- case FT_NONE:
- case FT_PROTOCOL:
- return FALSE;
- default:
- break;
- }
- char *repr = fvalue_to_string_repr(NULL, &(finfo->value), FTREPR_DFILTER, finfo->hfinfo->display);
- if (repr) {
- e = g_new(fvt_cache_entry_t,1);
- e->name = finfo->hfinfo->abbrev;
- e->repr = repr;
- e->usable = TRUE;
- g_hash_table_insert(fvt_cache,(void*)finfo->hfinfo->abbrev,e);
- }
- }
- return FALSE;
-}
-
-static void dfilter_free_fvt_entry(gpointer v)
-{
- fvt_cache_entry_t* e = (fvt_cache_entry_t*)v;
- wmem_free(NULL, e->repr);
- g_free(e);
-}
-
-void dfilter_macro_build_ftv_cache(void* tree_root) {
- g_hash_table_remove_all(fvt_cache);
- proto_tree_traverse_post_order((proto_tree *)tree_root, fvt_cache_cb, NULL);
-}
-
static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) {
GString* text;
int argc = 0;
dfilter_macro_t* m = NULL;
- fvt_cache_entry_t* e;
int* arg_pos_p;
gchar** parts;
gchar* ret;
@@ -101,20 +54,9 @@ static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) {
}
if (!m) {
- if (fvt_cache &&
- (e = (fvt_cache_entry_t *)g_hash_table_lookup(fvt_cache,name)) != NULL) {
- if(e->usable) {
- return wmem_strdup(NULL, e->repr);
- } else {
- if (error != NULL)
- *error = ws_strdup_printf("macro '%s' is unusable", name);
- return NULL;
- }
- } else {
- if (error != NULL)
- *error = ws_strdup_printf("macro '%s' does not exist", name);
- return NULL;
- }
+ if (error != NULL)
+ *error = g_strdup_printf("macro '%s' does not exist", name);
+ return NULL;
}
DUMP_MACRO(m);
@@ -205,6 +147,22 @@ static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gchar*
} case STARTING: {
switch (c) {
case '{': {
+ /* If the name has a dot it's a field reference,
+ * and conversely if it doesn't have a dot it's a macro. */
+ const char *sep = r;
+ char cc;
+ while ((cc = *sep++) != '\0') {
+ if (cc == '.' || cc == ':' || cc == '}') {
+ break;
+ }
+ }
+ if (cc == '.') {
+ /* Field reference, preserve */
+ g_string_append(out,"${");
+ state = OUTSIDE;
+ break;
+ }
+
args = g_ptr_array_new();
arg = g_string_sized_new(32);
name = g_string_sized_new(32);
@@ -575,8 +533,6 @@ void dfilter_macro_init(void) {
NULL, /* Note: This is set in macros_init () */
NULL,
uat_fields);
-
- fvt_cache = g_hash_table_new_full(g_str_hash,g_str_equal, NULL, dfilter_free_fvt_entry);
}
void dfilter_macro_get_uat(uat_t **dfmu_ptr_ptr) {
@@ -680,7 +636,6 @@ void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const
void dfilter_macro_cleanup(void)
{
- g_hash_table_destroy(fvt_cache);
}
/*
diff --git a/epan/dfilter/dfilter-macro.h b/epan/dfilter/dfilter-macro.h
index 2a9bee3494..24fd429c92 100644
--- a/epan/dfilter/dfilter-macro.h
+++ b/epan/dfilter/dfilter-macro.h
@@ -39,9 +39,6 @@ struct epan_uat;
WS_DLL_PUBLIC
void dfilter_macro_get_uat(struct epan_uat **dfmu_ptr_ptr);
-WS_DLL_PUBLIC
-void dfilter_macro_build_ftv_cache(void* tree_root);
-
void dfilter_macro_cleanup(void);
#ifdef __cplusplus
diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c
index a185956b12..987653cfdc 100644
--- a/epan/dfilter/dfilter.c
+++ b/epan/dfilter/dfilter.c
@@ -199,6 +199,8 @@ dfilter_free(dfilter_t *df)
g_free(df->interesting_fields);
+ g_hash_table_destroy(df->references);
+
if (df->deprecated)
g_ptr_array_unref(df->deprecated);
@@ -209,11 +211,30 @@ dfilter_free(dfilter_t *df)
g_free(df);
}
+static void free_reference(gpointer data)
+{
+ /* List data is not owned by us. */
+ GSList **fvalues_ptr = data;
+ if (*fvalues_ptr)
+ g_slist_free(*fvalues_ptr);
+ g_free(fvalues_ptr);
+}
+
static dfwork_t*
dfwork_new(void)
{
- return g_new0(dfwork_t, 1);
+ dfwork_t *dfw = g_new0(dfwork_t, 1);
+
+ dfw->references =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, free_reference);
+
+ dfw->loaded_references =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify)dfvm_value_unref);
+
+ return dfw;
}
static void
@@ -231,6 +252,14 @@ dfwork_free(dfwork_t *dfw)
g_hash_table_destroy(dfw->interesting_fields);
}
+ if (dfw->references) {
+ g_hash_table_destroy(dfw->references);
+ }
+
+ if (dfw->loaded_references) {
+ g_hash_table_destroy(dfw->loaded_references);
+ }
+
if (dfw->insns) {
free_insns(dfw->insns);
}
@@ -279,6 +308,9 @@ const char *tokenstr(int token)
case TOKEN_DOTDOT: return "DOTDOT";
case TOKEN_LPAREN: return "LPAREN";
case TOKEN_RPAREN: return "RPAREN";
+ case TOKEN_REFERENCE: return "REFERENCE";
+ case TOKEN_REF_OPEN: return "REF_OPEN";
+ case TOKEN_REF_CLOSE: return "REF_CLOSE";
}
return "<unknown>";
}
@@ -446,6 +478,8 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
dfilter->interesting_fields = dfw_interesting_fields(dfw,
&dfilter->num_interesting_fields);
dfilter->expanded_text = ws_strdup(expanded_text);
+ dfilter->references = dfw->references;
+ dfw->references = NULL;
/* Initialize run-time space */
dfilter->num_registers = dfw->next_register;
@@ -559,7 +593,7 @@ dfilter_log_full(const char *domain, enum ws_log_level level,
return;
}
- char *str = dfvm_dump_str(NULL, df);
+ char *str = dfvm_dump_str(NULL, df, TRUE);
if (G_UNLIKELY(msg == NULL))
ws_log_write_always_full(domain, level, file, line, func, "\n%s", str);
else
@@ -567,6 +601,45 @@ dfilter_log_full(const char *domain, enum ws_log_level level,
g_free(str);
}
+void
+dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
+{
+ GHashTableIter iter;
+ GPtrArray *finfos;
+ field_info *finfo;
+ header_field_info *hfinfo;
+ GSList **fvalues_ptr;
+ int i, len;
+
+ if (g_hash_table_size(df->references) == 0) {
+ /* Nothing to do. */
+ return;
+ }
+
+ g_hash_table_iter_init( &iter, df->references);
+ while (g_hash_table_iter_next (&iter, (void **)&hfinfo, (void **)&fvalues_ptr)) {
+ /* If we have a previous list free it leaving the data alone */
+ g_slist_free(*fvalues_ptr);
+ *fvalues_ptr = NULL;
+
+ while (hfinfo) {
+ finfos = proto_find_finfo(tree, hfinfo->id);
+ if ((finfos == NULL) || (g_ptr_array_len(finfos) == 0)) {
+ hfinfo = hfinfo->same_name_next;
+ continue;
+ }
+
+ len = finfos->len;
+ for (i = 0; i < len; i++) {
+ finfo = g_ptr_array_index(finfos, i);
+ *fvalues_ptr = g_slist_prepend(*fvalues_ptr, &finfo->value);
+ }
+
+ hfinfo = hfinfo->same_name_next;
+ }
+ }
+}
+
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h
index 3c4286bd33..03c7d924d4 100644
--- a/epan/dfilter/dfilter.h
+++ b/epan/dfilter/dfilter.h
@@ -73,6 +73,11 @@ dfilter_apply(dfilter_t *df, proto_tree *tree);
void
dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree);
+/* Refresh references in a compiled display filter. */
+WS_DLL_PUBLIC
+void
+dfilter_load_field_references(const dfilter_t *df, proto_tree *tree);
+
/* Check if dfilter has interesting fields */
gboolean
dfilter_has_interesting_fields(const dfilter_t *df);
diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c
index dcd03cd444..0f2a3dc823 100644
--- a/epan/dfilter/dfvm.c
+++ b/epan/dfilter/dfvm.c
@@ -181,13 +181,16 @@ dfvm_value_tostr(dfvm_value_t *v)
}
char *
-dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df)
+dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
{
int id, length;
dfvm_insn_t *insn;
dfvm_value_t *arg1, *arg2, *arg3, *arg4;
char *arg1_str, *arg2_str, *arg3_str, *arg4_str;
wmem_strbuf_t *buf;
+ GHashTableIter ref_iter;
+ gpointer key, value;
+ char *str;
buf = wmem_strbuf_new(alloc, NULL);
@@ -219,6 +222,11 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df)
id, arg1_str, arg2_str);
break;
+ case READ_REFERENCE:
+ wmem_strbuf_append_printf(buf, "%05d READ_REFERENCE\t${%s} -> %s\n",
+ id, arg1_str, arg2_str);
+ break;
+
case CALL_FUNCTION:
wmem_strbuf_append_printf(buf, "%05d CALL_FUNCTION\t%s(",
id, arg1_str);
@@ -337,13 +345,37 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df)
g_free(arg4_str);
}
+ if (print_references && g_hash_table_size(df->references) > 0) {
+ wmem_strbuf_append(buf, "\nReferences:\n");
+ g_hash_table_iter_init(&ref_iter, df->references);
+ while (g_hash_table_iter_next(&ref_iter, &key, &value)) {
+ const char *abbrev = ((header_field_info *)key)->abbrev;
+ GSList *fvalues = *(GSList **)value;
+
+ wmem_strbuf_append_printf(buf, "${%s} = {", abbrev);
+
+ if (fvalues != NULL) {
+ str = fvalue_to_debug_repr(NULL, fvalues->data);
+ wmem_strbuf_append_printf(buf, "%s <%s>", str, fvalue_type_name(fvalues->data));
+ g_free(str);
+
+ for (fvalues = fvalues->next; fvalues != NULL; fvalues = fvalues->next) {
+ str = fvalue_to_debug_repr(NULL, fvalues->data);
+ wmem_strbuf_append_printf(buf, ", %s <%s>", str, fvalue_type_name(fvalues->data));
+ g_free(str);
+ }
+ }
+ wmem_strbuf_append(buf, "}\n");
+ }
+ }
+
return wmem_strbuf_finalize(buf);
}
void
dfvm_dump(FILE *f, dfilter_t *df)
{
- char *str = dfvm_dump_str(NULL, df);
+ char *str = dfvm_dump_str(NULL, df, FALSE);
fputs(str, f);
wmem_free(NULL, str);
}
@@ -404,6 +436,39 @@ read_tree(dfilter_t *df, proto_tree *tree,
return TRUE;
}
+static gboolean
+read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2)
+{
+ GSList **fvalues_ptr;
+
+ header_field_info *hfinfo = arg1->value.hfinfo;
+ int reg = arg2->value.numeric;
+
+ /* Already loaded in this run of the dfilter? */
+ if (df->attempted_load[reg]) {
+ if (df->registers[reg]) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ df->attempted_load[reg] = TRUE;
+
+ fvalues_ptr = g_hash_table_lookup(df->references, hfinfo);
+ if (*fvalues_ptr == NULL) {
+ df->registers[reg] = NULL;
+ return FALSE;
+ }
+
+ /* Shallow copy */
+ df->registers[reg] = g_slist_copy(*fvalues_ptr);
+ /* These values are referenced only, do not try to free it later. */
+ df->free_registers[reg] = NULL;
+ return TRUE;
+}
+
enum match_how {
MATCH_ANY,
MATCH_ALL
@@ -787,6 +852,10 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
accum = read_tree(df, tree, arg1, arg2);
break;
+ case READ_REFERENCE:
+ accum = read_reference(df, arg1, arg2);
+ break;
+
case CALL_FUNCTION:
accum = call_function(df, arg1, arg2, arg3, arg4);
break;
diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h
index 7056f7847c..d5507c0830 100644
--- a/epan/dfilter/dfvm.h
+++ b/epan/dfilter/dfvm.h
@@ -53,6 +53,7 @@ typedef enum {
NOT,
RETURN,
READ_TREE,
+ READ_REFERENCE,
ALL_EQ,
ANY_EQ,
ALL_NE,
@@ -119,7 +120,7 @@ void
dfvm_dump(FILE *f, dfilter_t *df);
char *
-dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df);
+dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references);
gboolean
dfvm_apply(dfilter_t *df, proto_tree *tree);
diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c
index bdfb0fe42d..3c8c0c995a 100644
--- a/epan/dfilter/gencode.c
+++ b/epan/dfilter/gencode.c
@@ -92,6 +92,53 @@ dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo)
/* returns register number */
static dfvm_value_t *
+dfw_append_read_reference(dfwork_t *dfw, header_field_info *hfinfo)
+{
+ dfvm_insn_t *insn;
+ dfvm_value_t *reg_val, *val1;
+ GSList **fvalues_ptr;
+ gboolean added_new_hfinfo = FALSE;
+
+ /* Rewind to find the first field of this name. */
+ while (hfinfo->same_name_prev_id != -1) {
+ hfinfo = proto_registrar_get_nth(hfinfo->same_name_prev_id);
+ }
+
+ /* Keep track of which registers
+ * were used for which hfinfo's so that we
+ * can re-use registers. */
+ reg_val = g_hash_table_lookup(dfw->loaded_references, hfinfo);
+ if (!reg_val) {
+ reg_val = dfvm_value_new_register(dfw->next_register++);
+ g_hash_table_insert(dfw->loaded_references, hfinfo, dfvm_value_ref(reg_val));
+ added_new_hfinfo = TRUE;
+ }
+
+ insn = dfvm_insn_new(READ_REFERENCE);
+ val1 = dfvm_value_new_hfinfo(hfinfo);
+ insn->arg1 = dfvm_value_ref(val1);
+ insn->arg2 = dfvm_value_ref(reg_val);
+ dfw_append_insn(dfw, insn);
+
+ fvalues_ptr = g_new(GSList *, 1);
+ *fvalues_ptr = NULL;
+ g_hash_table_insert(dfw->references, hfinfo, fvalues_ptr);
+
+ if (added_new_hfinfo) {
+ while (hfinfo) {
+ /* Record the FIELD_ID in hash of interesting fields. */
+ g_hash_table_insert(dfw->interesting_fields,
+ GINT_TO_POINTER(hfinfo->id),
+ GUINT_TO_POINTER(TRUE));
+ hfinfo = hfinfo->same_name_next;
+ }
+ }
+
+ return reg_val;
+}
+
+/* returns register number */
+static dfvm_value_t *
dfw_append_mk_range(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
{
stnode_t *entity;
@@ -352,6 +399,16 @@ gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr)
dfw_append_insn(dfw, insn);
*jumps_ptr = g_slist_prepend(*jumps_ptr, jmp);
}
+ else if (e_type == STTYPE_REFERENCE) {
+ hfinfo = stnode_data(st_arg);
+ val = dfw_append_read_reference(dfw, hfinfo);
+
+ insn = dfvm_insn_new(IF_FALSE_GOTO);
+ jmp = dfvm_value_new(INSN_NUMBER);
+ insn->arg1 = dfvm_value_ref(jmp);
+ dfw_append_insn(dfw, insn);
+ *jumps_ptr = g_slist_prepend(*jumps_ptr, jmp);
+ }
else if (e_type == STTYPE_FVALUE) {
val = dfvm_value_new_fvalue(stnode_steal_data(st_arg));
}
diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon
index 8e4a3ed331..d0b7315f11 100644
--- a/epan/dfilter/grammar.lemon
+++ b/epan/dfilter/grammar.lemon
@@ -166,6 +166,16 @@ atom(E) ::= IDENTIFIER(F).
df_lval_free(F, FALSE);
}
entity(E) ::= atom(A). { E = A; }
+entity(E) ::= REF_OPEN REFERENCE(F) REF_CLOSE.
+{
+ char *name = df_lval_value(F);
+ header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, name);
+ if (hfinfo == NULL) {
+ dfilter_fail(dfw, "\"%s\" is not a valid protocol or protocol field.", name);
+ }
+ E = stnode_new(STTYPE_REFERENCE, hfinfo, df_lval_value(F));
+ df_lval_free(F, FALSE);
+}
entity(E) ::= range(R). { E = R; }
entity(E) ::= function(F). { E = F; }
diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l
index 626a19a068..494a1e0dc1 100644
--- a/epan/dfilter/scanner.l
+++ b/epan/dfilter/scanner.l
@@ -103,6 +103,7 @@ WORD_CHAR [[:alnum:]_:/+-]
%x RANGE
%x DQUOTE
%x SQUOTE
+%x REFERENCE
%%
@@ -153,6 +154,25 @@ WORD_CHAR [[:alnum:]_:/+-]
"&" return simple(TOKEN_BITWISE_AND);
"bitwise_and" return simple(TOKEN_BITWISE_AND);
+"${" {
+ BEGIN(REFERENCE);
+ return simple(TOKEN_REF_OPEN);
+}
+
+<REFERENCE>[^}]+ {
+ return set_lval_str(TOKEN_REFERENCE, yytext);
+}
+
+<REFERENCE>"}" {
+ BEGIN(INITIAL);
+ return simple(TOKEN_REF_CLOSE);
+}
+
+<REFERENCE><<EOF>> {
+ dfilter_fail(yyextra->dfw, "Right brace missing from field reference.");
+ return SCAN_FAILED;
+}
+
"[" {
BEGIN(RANGE);
return simple(TOKEN_LBRACKET);
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index 210d78c547..968e46827f 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -464,6 +464,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
case STTYPE_FIELD:
/* This is OK */
break;
+ case STTYPE_REFERENCE:
case STTYPE_STRING:
case STTYPE_UNPARSED:
case STTYPE_LITERAL:
@@ -623,7 +624,7 @@ again:
stnode_todisplay(st_node));
}
- if (type2 == STTYPE_FIELD) {
+ if (type2 == STTYPE_FIELD || type2 == STTYPE_REFERENCE) {
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
@@ -747,7 +748,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, test_op_t st_op,
again:
type2 = stnode_type_id(st_arg2);
- if (type2 == STTYPE_FIELD) {
+ if (type2 == STTYPE_FIELD || type2 == STTYPE_REFERENCE) {
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
@@ -865,7 +866,7 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
again:
type2 = stnode_type_id(st_arg2);
- if (type2 == STTYPE_FIELD) {
+ if (type2 == STTYPE_FIELD || type2 == STTYPE_REFERENCE) {
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
@@ -980,7 +981,8 @@ check_relation_LHS_BITWISE(dfwork_t *dfw, test_op_t st_op _U_,
sttype_test_get(st_arg1, NULL, &bitwise_entity, NULL);
bitwise_entity_type = stnode_type_id(bitwise_entity);
- if (bitwise_entity_type == STTYPE_FIELD) {
+ if (bitwise_entity_type == STTYPE_FIELD ||
+ bitwise_entity_type == STTYPE_REFERENCE) {
check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, bitwise_entity, st_arg2);
}
else if (bitwise_entity_type == STTYPE_RANGE) {
@@ -1008,7 +1010,7 @@ check_relation_LHS_ARITHMETIC(dfwork_t *dfw, test_op_t st_op _U_,
sttype_test_get(st_arg1, NULL, &entity, NULL);
entity_type = stnode_type_id(entity);
- if (entity_type == STTYPE_FIELD) {
+ if (entity_type == STTYPE_FIELD || entity_type == STTYPE_REFERENCE) {
check_arithmetic_operation(dfw, st_arg1, FT_NONE);
check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, entity, st_arg2);
@@ -1036,6 +1038,7 @@ check_relation(dfwork_t *dfw, test_op_t st_op,
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
+ case STTYPE_REFERENCE:
check_relation_LHS_FIELD(dfw, st_op, can_func,
allow_partial_value, st_node, st_arg1, st_arg2);
break;
@@ -1071,6 +1074,7 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node,
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
+ case STTYPE_REFERENCE:
check_relation_LHS_FIELD(dfw, TEST_OP_CONTAINS, ftype_can_contains,
TRUE, st_node, st_arg1, st_arg2);
break;
@@ -1119,6 +1123,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
+ case STTYPE_REFERENCE:
check_relation_LHS_FIELD(dfw, TEST_OP_MATCHES, ftype_can_matches,
TRUE, st_node, st_arg1, st_arg2);
break;
@@ -1259,7 +1264,7 @@ check_bitwise_entity(dfwork_t *dfw, stnode_t *st_node, stnode_t *st_arg, ftenum_
resolve_unparsed(dfw, st_arg);
type = stnode_type_id(st_arg);
- if (type == STTYPE_FIELD) {
+ if (type == STTYPE_FIELD || type == STTYPE_REFERENCE) {
hfinfo = stnode_data(st_arg);
ftype = hfinfo->type;
@@ -1381,7 +1386,7 @@ check_arithmetic_operation(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
stnode_replace(st_node, STTYPE_FVALUE, new_fv);
}
}
- else if (type == STTYPE_FIELD) {
+ else if (type == STTYPE_FIELD || type == STTYPE_REFERENCE) {
header_field_info *hfinfo = stnode_data(st_arg);
ftype = hfinfo->type;
diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c
index f97c76bd53..8f51d9cfd4 100644
--- a/epan/dfilter/sttype-pointer.c
+++ b/epan/dfilter/sttype-pointer.c
@@ -105,6 +105,17 @@ sttype_register_pointer(void)
NULL,
field_tostr
};
+ /* A field reference is a *constant* prototocol field value read directly
+ * from the currently selected frame in the protocol tree when a filter is
+ * applied to it. */
+ static sttype_t reference_type = {
+ STTYPE_REFERENCE,
+ "REFERENCE",
+ NULL,
+ NULL,
+ NULL,
+ field_tostr
+ };
static sttype_t fvalue_type = {
STTYPE_FVALUE,
"FVALUE",
@@ -131,6 +142,7 @@ sttype_register_pointer(void)
};
sttype_register(&field_type);
+ sttype_register(&reference_type);
sttype_register(&fvalue_type);
sttype_register(&pcre_type);
sttype_register(&charconst_type);
diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h
index 8b3b0b6971..2993ea1882 100644
--- a/epan/dfilter/syntax-tree.h
+++ b/epan/dfilter/syntax-tree.h
@@ -24,6 +24,7 @@ typedef enum {
STTYPE_TEST,
STTYPE_LITERAL,
STTYPE_UNPARSED,
+ STTYPE_REFERENCE,
STTYPE_STRING,
STTYPE_CHARCONST,
STTYPE_FIELD,