aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dfilter.c
diff options
context:
space:
mode:
authorGilbert Ramirez <gram@alumni.rice.edu>2000-09-27 04:55:05 +0000
committerGilbert Ramirez <gram@alumni.rice.edu>2000-09-27 04:55:05 +0000
commit83ec54675c19f25cfbb2e8a8863c6ee2191d8b0c (patch)
tree35d39e43d20aca160b96d8a85ddc2b80e4646f67 /epan/dfilter.c
parentf881e13932e0ba390c26cce15d1334b2154a8062 (diff)
First step in moving core Ethereal routines to libepan.
svn path=/trunk/; revision=2458
Diffstat (limited to 'epan/dfilter.c')
-rw-r--r--epan/dfilter.c1064
1 files changed, 1064 insertions, 0 deletions
diff --git a/epan/dfilter.c b/epan/dfilter.c
new file mode 100644
index 0000000000..73fe5253e0
--- /dev/null
+++ b/epan/dfilter.c
@@ -0,0 +1,1064 @@
+/* dfilter.c
+ * Routines for display filters
+ *
+ * $Id: dfilter.c,v 1.1 2000/09/27 04:54:48 gram Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include "proto.h"
+#include "dfilter.h"
+#include "util.h"
+#include "dfilter-int.h"
+#include "dfilter-grammar.h"
+
+int dfilter_parse(void); /* yacc entry-point */
+
+#define DFILTER_LEX_ABBREV_OFFSET 2000
+
+/* Balanced tree of abbreviations and IDs */
+GTree *dfilter_tokens = NULL;
+
+/* Comparision function for tree insertion. A wrapper around strcmp() */
+static int g_strcmp(gconstpointer a, gconstpointer b);
+
+/* Silly global variables used to pass parameter to check_relation_bytes() */
+int bytes_offset = 0;
+int bytes_length = 0;
+
+YYSTYPE yylval;
+
+/* Global error message space for dfilter_compile errors */
+gchar dfilter_error_msg_buf[1024];
+gchar *dfilter_error_msg; /* NULL when no error resulted */
+
+static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd);
+static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
+static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
+static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd);
+static GArray* get_values_from_dfilter(dfilter_node *dnode, GNode *gnode);
+static gboolean check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree);
+static void clear_byte_array(gpointer data, gpointer user_data);
+
+/* this is not so pretty. I need my own g_array "function" (macro) to
+ * retreive the pointer to the data stored in an array cell. I need this
+ * for type ether.. GArray makes it easy for me to store 6 bytes inside an array
+ * cell, but hard to retrieve it.
+ */
+#define g_array_index_ptr(a,s,i) (((guint8*) (a)->data) + (i*s))
+
+extern int hf_text_only; /* in proto.c */
+
+void
+dfilter_init(void)
+{
+ int i, num_symbols, symbol;
+ char *s;
+
+ dfilter_tokens = g_tree_new(g_strcmp);
+
+ /* Add the header field and protocol abbrevs to the symbol table */
+ num_symbols = proto_registrar_n();
+
+ for (i=0; i < num_symbols; i++) {
+ if (i == hf_text_only) {
+ continue;
+ }
+ s = proto_registrar_get_abbrev(i);
+ g_assert(s); /* Not Null */
+ g_assert(s[0] != 0); /* Not empty string */
+ /* Make sure we don't have duplicate abbreviation */
+ if (g_tree_lookup(dfilter_tokens, s)) {
+ g_message("Already have abbreviation \"%s\"", s);
+ g_assert(0);
+ }
+ symbol = DFILTER_LEX_ABBREV_OFFSET + i;
+ g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol));
+ }
+}
+
+void
+dfilter_cleanup(void)
+{
+ if (dfilter_tokens)
+ g_tree_destroy(dfilter_tokens);
+}
+
+/* Compiles the textual representation of the display filter into a tree
+ * of operations to perform. Can be called multiple times, compiling a new
+ * display filter each time, without having to clear any memory used, since
+ * dfilter_compile will take care of that automatically.
+ *
+ * Returns 0 on success, non-zero on failure.
+ *
+ * On success, sets the "dfilter *" pointed to by its second argument
+ * either to a null pointer (if the filter is a null filter, as
+ * generated by an all-blank string) or to a pointer to a newly-allocated
+ * dfilter structure (if the filter isn't null).
+ *
+ * On failure, "dfilter_error_msg" points to an appropriate error message.
+ * This error message is a global string, so another invocation of
+ * dfilter_compile will clear it. If the caller needs is stored, he
+ * needs to g_strdup it himself.
+ */
+int
+dfilter_compile(gchar *dfilter_text, dfilter **dfp)
+{
+ dfilter *df;
+ int retval;
+
+ g_assert(dfilter_text != NULL);
+
+ df = dfilter_new();
+
+ /* tell the scanner to use the filter string as input */
+ dfilter_scanner_text(dfilter_text);
+
+ /* Assign global variable so dfilter_parse knows which dfilter we're
+ * talking about. Reset the global error message.
+ */
+ global_df = df;
+ dfilter_error_msg = NULL;
+
+ /* The magic happens right here. */
+ retval = dfilter_parse();
+
+ /* clean up lex */
+ dfilter_scanner_cleanup();
+
+ /* Errors not found by the parser may not cause the parse to
+ * fail; if "dfilter_error_msg" is set, it means somebody
+ * else called "dfilter_fail()", e.g. the lexical analyzer,
+ * so treat that as a parse error. */
+ if (dfilter_error_msg != NULL)
+ retval = 1;
+
+ if (retval != 0) {
+ if (dfilter_error_msg == NULL) {
+ snprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
+ "Unable to parse filter string \"%s\".",
+ dfilter_text);
+ dfilter_error_msg = &dfilter_error_msg_buf[0];
+ }
+ }
+
+ /* Set global_df to NULL just to be tidy. */
+ global_df = NULL;
+
+ if (retval == 0) {
+ /* Success. Check if the filter is empty; if so, discard
+ * it and set "*dfp" to NULL, otherwise set "*dfp" to
+ * point to the filter. */
+ if (df->dftree == NULL) {
+ /* The filter is empty. */
+ dfilter_destroy(df);
+ df = NULL;
+ }
+ *dfp = df;
+ } else {
+ /* Failure. Destroy the filter. */
+ dfilter_destroy(df);
+ df = NULL;
+ }
+ return retval;
+}
+
+/* Allocates new dfilter, initializes values, and returns pointer to dfilter */
+dfilter*
+dfilter_new(void)
+{
+ dfilter *df;
+
+ df = g_malloc(sizeof(dfilter));
+
+ df->dftree = NULL;
+ df->node_memchunk = g_mem_chunk_new("df->node_memchunk",
+ sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
+ df->list_of_byte_arrays = NULL;
+ df->list_of_strings = NULL;
+
+ return df;
+}
+
+static void
+free_string(gpointer data, gpointer user_data)
+{
+ char *string = data;
+ if (string)
+ g_free(string);
+}
+
+/* Frees all memory used by dfilter, and frees dfilter itself */
+void
+dfilter_destroy(dfilter *df)
+{
+ if (!df)
+ return;
+
+ if (df->dftree != NULL)
+ g_node_destroy(df->dftree);
+
+ /* clear the memory that the tree was using for nodes */
+ if (df->node_memchunk)
+ g_mem_chunk_reset(df->node_memchunk);
+
+ /* clear the memory that the tree was using for byte arrays */
+ if (df->list_of_byte_arrays) {
+ g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL);
+ g_slist_free(df->list_of_byte_arrays);
+ }
+
+ /* clear the allocated strings */
+ if (df->list_of_strings) {
+ g_slist_foreach(df->list_of_strings, free_string, NULL);
+ g_slist_free(df->list_of_strings);
+ }
+
+ df->dftree = NULL;
+ df->list_of_byte_arrays = NULL;
+ df->list_of_strings = NULL;
+
+ /* Git rid of memchunk */
+ if (df->node_memchunk)
+ g_mem_chunk_destroy(df->node_memchunk);
+
+ g_free(df);
+}
+
+
+static void
+clear_byte_array(gpointer data, gpointer user_data)
+{
+ GByteArray *barray = data;
+ if (barray)
+ g_byte_array_free(barray, TRUE);
+}
+
+/* Called when the yacc grammar finds a parsing error */
+void
+dfilter_error(char *s)
+{
+}
+
+/* Called when an error other than a parsing error occurs. */
+void
+dfilter_fail(char *format, ...)
+{
+ va_list ap;
+
+ /* If we've already reported one error, don't overwrite it with this
+ * one. */
+ if (dfilter_error_msg != NULL)
+ return;
+
+ va_start(ap, format);
+ vsnprintf(dfilter_error_msg_buf, sizeof dfilter_error_msg_buf, format, ap);
+ dfilter_error_msg = dfilter_error_msg_buf;
+ va_end(ap);
+}
+
+/* lookup an abbreviation in our token tree, returing the ID #
+ * If the abbreviation doesn't exit, returns -1 */
+int dfilter_lookup_token(char *abbrev)
+{
+ int value;
+
+ g_assert(abbrev != NULL);
+ value = GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
+
+ if (value < DFILTER_LEX_ABBREV_OFFSET) {
+ return -1;
+ }
+ return value - DFILTER_LEX_ABBREV_OFFSET;
+}
+
+static int
+g_strcmp(gconstpointer a, gconstpointer b)
+{
+ return strcmp((const char*)a, (const char*)b);
+}
+
+
+gboolean
+dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd, guint pd_len)
+{
+ gboolean retval;
+ if (dfcode == NULL)
+ return FALSE;
+ retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
+ return retval;
+}
+
+static gboolean
+dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
+{
+ GNode *gnode_a, *gnode_b;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ /* We'll get 2 NULLs if we don't have children */
+ gnode_a = g_node_nth_child(gnode, 0);
+ gnode_b = g_node_nth_child(gnode, 1);
+
+ switch(dnode->ntype) {
+ case variable:
+ /* We'll never see this case because if the parser finds the name of
+ * a variable, it will cause it to be an 'existence' operation.
+ */
+ g_assert_not_reached();
+
+ case logical:
+ g_assert(gnode_a);
+ return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
+
+ case relation:
+ g_assert(gnode_a && gnode_b);
+ return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
+
+ case alternation:
+ g_assert_not_reached();
+ /* not coded yet */
+
+ case numeric:
+ case floating:
+ case ipv4:
+ case ipv6:
+ case boolean:
+ case ether:
+ case string:
+ case abs_time:
+ case bytes:
+ case ipxnet:
+ /* the only time we'll see these at this point is if the display filter
+ * is really wacky. (like simply "192.168.1.1"). The parser as it stands
+ * now let these by. Just return TRUE */
+ g_assert(!gnode_a && !gnode_b);
+ return TRUE;
+
+ case existence: /* checking the existence of a protocol or hf*/
+ g_assert(!gnode_a && !gnode_b);
+ return check_existence_in_ptree(dnode, ptree);
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+static gboolean
+check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
+{
+ gboolean val_a = dfilter_apply_node(a, ptree, pd);
+ gboolean val_b;
+
+ switch(operand) {
+ case TOK_AND:
+ g_assert(b);
+ return (val_a && dfilter_apply_node(b, ptree, pd));
+ case TOK_OR:
+ g_assert(b);
+ return (val_a || dfilter_apply_node(b, ptree, pd));
+ case TOK_XOR:
+ g_assert(b);
+ val_b = dfilter_apply_node(b, ptree, pd);
+ return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
+ case TOK_NOT:
+ return (!val_a);
+ default:
+ g_assert_not_reached();
+ }
+ g_assert_not_reached();
+ return FALSE;
+}
+
+
+static void
+free_array_of_byte_arrays(GArray *array)
+{
+ int i, len;
+ GByteArray *ba_ptr;
+
+ len = array->len;
+
+ for (i = 0; i < len ; i++) {
+ ba_ptr = g_array_index(array, GByteArray*, i);
+ g_byte_array_free(ba_ptr, TRUE);
+ }
+}
+
+/* this is inefficient. I get arrays for both a and b that represent all the values present. That is,
+ * if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol
+ * tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare
+ * them all. It makes my coding easier in the beginning, but I should change this to make it run
+ * faster.
+ */
+static gboolean
+check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
+{
+ dfilter_node *node_a = (dfilter_node*) (a->data);
+ dfilter_node *node_b = (dfilter_node*) (b->data);
+ GArray *vals_a, *vals_b;
+ gboolean retval;
+
+
+ bytes_length = MIN(node_a->length, node_b->length);
+ bytes_offset = MIN(node_a->offset, node_b->offset);
+ if (node_a->ntype == variable)
+ vals_a = get_values_from_ptree(node_a, ptree, pd);
+ else
+ vals_a = get_values_from_dfilter(node_a, a);
+
+ if (node_b->ntype == variable)
+ vals_b = get_values_from_ptree(node_b, ptree, pd);
+ else
+ vals_b = get_values_from_dfilter(node_b, b);
+
+ retval = node_a->check_relation_func(operand, vals_a, vals_b);
+
+ /* Free GByteArrays alloated by fill_array_bytes_variable() */
+ if (node_a->fill_array_variable_func == fill_array_bytes_variable) {
+ free_array_of_byte_arrays(vals_a);
+ }
+
+ if (node_b->fill_array_variable_func == fill_array_bytes_variable) {
+ free_array_of_byte_arrays(vals_b);
+ }
+
+ g_array_free(vals_a, FALSE);
+ g_array_free(vals_b, FALSE);
+
+ return retval;
+}
+
+
+static gboolean
+check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
+{
+ int target;
+
+ target = dnode->value.variable;
+ return proto_check_for_protocol_or_field(ptree, target);
+}
+
+static GArray*
+get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
+{
+ GArray *result_array;
+ GPtrArray *finfo_array;
+ int i, len;
+ field_info *finfo;
+
+ /* Prepare the array for results */
+ g_assert(dnode->elem_size > 0);
+ result_array = g_array_new(FALSE, FALSE, dnode->elem_size);
+
+ /* Cull the finfos from the proto_tree */
+ finfo_array = proto_get_finfo_ptr_array(ptree, dnode->value.variable);
+ if (!finfo_array) {
+ return result_array;
+ }
+
+ len = g_ptr_array_len(finfo_array);
+
+ for (i = 0; i < len; i++) {
+ finfo = g_ptr_array_index(finfo_array, i);
+ dnode->fill_array_variable_func(finfo, result_array, pd);
+ }
+
+ g_ptr_array_free(finfo_array, FALSE);
+
+ return result_array;
+}
+
+
+void
+fill_array_numeric_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ g_array_append_val(array, finfo->value.numeric);
+}
+
+void
+fill_array_floating_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ g_array_append_val(array, finfo->value.floating);
+}
+
+void
+fill_array_ether_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ /* hmmm, yes, I *can* copy a pointer instead of memcpy() */
+ g_array_append_val(array, finfo->value.ether);
+}
+
+void
+fill_array_ipv4_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ /* hmmm, yes, I *can* copy a pointer instead of memcpy() */
+ g_array_append_val(array, finfo->value.ipv4);
+}
+
+void
+fill_array_ipv6_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ /* hmmm, yes, I *can* copy a pointer instead of memcpy() */
+ g_array_append_val(array, finfo->value.ipv6);
+}
+
+void
+fill_array_string_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ g_array_append_val(array, finfo->value.string);
+}
+
+void
+fill_array_bytes_variable(field_info *finfo, GArray *array, const guint8 *pd)
+{
+ GByteArray *barray;
+ guint read_start, pkt_end;
+
+ if (bytes_offset < 0) {
+ /* Handle negative byte offsets */
+ bytes_offset = finfo->length + bytes_offset;
+ if (bytes_offset < 0) {
+ return;
+ }
+ }
+
+ /* Check to make sure offset exists for this field */
+ if (bytes_offset >= finfo->length) {
+ return;
+ }
+
+ pkt_end = finfo->start + finfo->length;
+ read_start = finfo->start + bytes_offset;
+
+ /* Check to make sure entire length requested is inside field */
+ if (pkt_end < read_start + bytes_length) {
+ return;
+ }
+
+ barray = g_byte_array_new();
+ g_byte_array_append(barray, pd + read_start, bytes_length);
+ g_array_append_val(array, barray);
+}
+
+static GArray*
+get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
+{
+ GArray *array;
+
+ g_assert(dnode->elem_size > 0);
+ array = g_array_new(FALSE, FALSE, dnode->elem_size);
+
+ g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1,
+ dnode->fill_array_value_func, array);
+ return array;
+}
+
+gboolean fill_array_numeric_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ g_array_append_val(array, dnode->value.numeric);
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_floating_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ g_array_append_val(array, dnode->value.floating);
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_ether_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ g_array_append_val(array, dnode->value.ether);
+
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_ipv4_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ g_array_append_val(array, dnode->value.ipv4);
+
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_ipv6_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ g_array_append_val(array, dnode->value.ipv6);
+
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+ GByteArray *barray = dnode->value.bytes;
+
+ g_array_append_val(array, barray);
+
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_string_value(GNode *gnode, gpointer data)
+{
+ GArray *array = (GArray*)data;
+ dfilter_node *dnode = (dfilter_node*) (gnode->data);
+
+ g_array_append_val(array, dnode->value.string);
+
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ guint32 val_a;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, guint32, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a == g_array_index(b, guint32, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, guint32, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a != g_array_index(b, guint32, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GT:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, guint32, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a > g_array_index(b, guint32, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GE:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, guint32, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a >= g_array_index(b, guint32, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LT:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, guint32, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a < g_array_index(b, guint32, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LE:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, guint32, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a <= g_array_index(b, guint32, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean check_relation_floating(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ double val_a;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, double, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a == g_array_index(b, double, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, double, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a != g_array_index(b, double, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GT:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, double, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a > g_array_index(b, double, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GE:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, double, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a >= g_array_index(b, double, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LT:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, double, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a < g_array_index(b, double, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LE:
+ for(i = 0; i < len_a; i++) {
+ val_a = g_array_index(a, double, i);
+ for (j = 0; j < len_b; j++) {
+ if (val_a <= g_array_index(b, double, j))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ ipv4_addr *ptr_a, *ptr_b;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+ if (ipv4_addr_eq(ptr_a, ptr_b))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+ if (ipv4_addr_ne(ptr_a, ptr_b))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GT:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+ if (ipv4_addr_gt(ptr_a, ptr_b))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+ if (ipv4_addr_ge(ptr_a, ptr_b))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LT:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+ if (ipv4_addr_lt(ptr_a, ptr_b))
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+ if (ipv4_addr_le(ptr_a, ptr_b))
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ guint8 *ptr_a, *ptr_b;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index_ptr(a, 16, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index_ptr(b, 16, j);
+ if (memcmp(ptr_a, ptr_b, 16) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index_ptr(a, 16, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index_ptr(b, 16, j);
+ if (memcmp(ptr_a, ptr_b, 16) != 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ guint8 *ptr_a, *ptr_b;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index_ptr(a, 6, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index_ptr(b, 6, j);
+ if (memcmp(ptr_a, ptr_b, 6) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index_ptr(a, 6, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index_ptr(b, 6, j);
+ if (memcmp(ptr_a, ptr_b, 6) != 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ GByteArray *ptr_a,*ptr_b;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index(a, GByteArray*, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index(b, GByteArray*, j);
+ if (memcmp(ptr_a->data, ptr_b->data, bytes_length) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index(a, GByteArray*, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index(b, GByteArray*, j);
+ if (memcmp(ptr_a->data, ptr_b->data, bytes_length) != 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_GT:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index(a, GByteArray*, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index(b, GByteArray*, j);
+ if (memcmp(ptr_a->data, ptr_b->data, bytes_length) > 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_LT:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index(a, GByteArray*, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index(b, GByteArray*, j);
+ if (memcmp(ptr_a->data, ptr_b->data, bytes_length) < 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+gboolean check_relation_string(gint operand, GArray *a, GArray *b)
+{
+ int i, j, len_a, len_b;
+ char *ptr_a, *ptr_b;
+
+ len_a = a->len;
+ len_b = b->len;
+
+
+ switch(operand) {
+ case TOK_EQ:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index(a, char*, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index(b, char*, j);
+ if (strcmp(ptr_a, ptr_b) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case TOK_NE:
+ for(i = 0; i < len_a; i++) {
+ ptr_a = g_array_index(a, char*, i);
+ for (j = 0; j < len_b; j++) {
+ ptr_b = g_array_index(b, char*, j);
+ if (strcmp(ptr_a, ptr_b) != 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+