aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dfilter
diff options
context:
space:
mode:
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,