Squelch a complaint from Visual C++ 6.0 (the code was OK beforehand, at
[obnox/wireshark/wip.git] / dfilter.c
index 4e53b8f6e36184a979e5e0fd216bca3717915be5..f948246535d7a1321caa941fb5e3c3963945c4e3 100644 (file)
--- a/dfilter.c
+++ b/dfilter.c
@@ -1,7 +1,7 @@
 /* dfilter.c
  * Routines for display filters
  *
- * $Id: dfilter.c,v 1.7 1999/08/12 15:10:48 gram Exp $
+ * $Id: dfilter.c,v 1.32 1999/11/15 06:32:13 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 #include <string.h>
 #endif
 
+#ifdef NEED_SNPRINTF_H
+# ifdef HAVE_STDARG_H
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+# include "snprintf.h"
+#endif
+
 #ifndef __G_LIB_H__
 #include <glib.h>
 #endif
 #ifndef __DFILTER_H__
 #include "dfilter.h"
 #endif
+
+#ifndef __UTIL_H__
+#include "util.h"
+#endif
+
+#include "dfilter-int.h"
 #include "dfilter-grammar.h"
 
-int yyparse(void); /* yacc entry-point */
+int dfilter_parse(void); /* yacc entry-point */
 
 #define DFILTER_LEX_ABBREV_OFFSET      2000
 
@@ -68,14 +83,9 @@ int bytes_length = 0;
 
 YYSTYPE yylval;
 
-/* in dfilter-grammar.y */
-extern GMemChunk *gmc_dfilter_nodes; 
-extern GNode *dfilter_tree;
-extern GSList *dfilter_list_byte_arrays;
-
-/* in dfilter-scanner.l */
-void dfilter_scanner_text(char*);
-void dfilter_scanner_cleanup(void);
+/* 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);
@@ -110,43 +120,140 @@ dfilter_init(void)
                }
        }
 }
-/* I should eventually g_tree_destroy(dfilter_tokens), when ethereal shuts down */
+
+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.
+ * 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(char *dfilter_text, GNode **p_dfcode)
+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);
 
-       if (dfilter_tree) {
-               /* clear tree */
-               dfilter_tree = NULL;
+       /* 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;
+
+       return df;
+}
+
+/* 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 */
-       g_mem_chunk_reset(gmc_dfilter_nodes);
+       if (df->node_memchunk)
+               g_mem_chunk_reset(df->node_memchunk);
 
        /* clear the memory that the tree was using for byte arrays */
-       if (dfilter_list_byte_arrays) {
-               g_slist_foreach(dfilter_list_byte_arrays, clear_byte_array, NULL);
-               g_slist_free(dfilter_list_byte_arrays);
-               dfilter_list_byte_arrays = NULL;
+       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);
        }
 
-       if (*p_dfcode != NULL)
-               g_node_destroy(*p_dfcode);
+       df->dftree = NULL;
+       df->list_of_byte_arrays = NULL;
 
-       retval = yyparse();
-       dfilter_scanner_cleanup();
-       *p_dfcode = dfilter_tree;
+       /* Git rid of memchunk */
+       if (df->node_memchunk)
+               g_mem_chunk_destroy(df->node_memchunk);
 
-       return retval;
+       g_free(df);
 }
 
+
 static void
 clear_byte_array(gpointer data, gpointer user_data)
 {
@@ -155,22 +262,31 @@ clear_byte_array(gpointer data, gpointer user_data)
                g_byte_array_free(barray, TRUE);
 }
 
+/* Called when the yacc grammar finds a parsing error */
 void
-yyerror(char *s)
+dfilter_error(char *s)
 {
-/*     fprintf(stderr, "%s\n", s);
-       Do not report the error, just let yyparse() return 1 */
 }
 
+/* Called when an error other than a parsing error occurs. */
 void
-dfilter_yyerror(char *fmt, ...)
+dfilter_fail(char *format, ...)
 {
-       dfilter_tree = NULL;
-       yyerror(fmt);
+       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 0 */
+ * If the abbreviation doesn't exit, returns -1 */
 int dfilter_lookup_token(char *abbrev)
 {
        int value;
@@ -179,7 +295,7 @@ int dfilter_lookup_token(char *abbrev)
        value =  GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
 
        if (value < DFILTER_LEX_ABBREV_OFFSET) {
-               return 0;
+               return -1;
        }
        return value - DFILTER_LEX_ABBREV_OFFSET;
 }
@@ -192,10 +308,12 @@ g_strcmp(gconstpointer a, gconstpointer b)
 
 
 gboolean
-dfilter_apply(GNode *dfcode, proto_tree *ptree, const guint8* pd)
+dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd)
 {
        gboolean retval;
-       retval = dfilter_apply_node(dfcode, ptree, pd);
+       if (dfcode == NULL)
+               return FALSE;
+       retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
        return retval;
 }
 
@@ -217,6 +335,7 @@ dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
                g_assert_not_reached();
 
        case logical:
+               g_assert(gnode_a);
                return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
 
        case relation:
@@ -228,7 +347,9 @@ dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
                /* not coded yet */
        
        case numeric:
+       case floating:
        case ipv4:
+       case ipv6:
        case boolean:
        case ether:
        case string:
@@ -258,10 +379,13 @@ check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8
 
        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:
@@ -311,16 +435,10 @@ check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8
 static gboolean
 check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
 {
-       int             target_field;
-       proto_tree      *subtree;
+       int             target;
 
-       target_field = dnode->value.variable;
-       subtree = proto_find_field(ptree, target_field);
-
-       if (subtree)
-               return TRUE;
-       else
-               return FALSE;
+       target = dnode->value.variable;
+       return proto_check_for_protocol_or_field(ptree, target);
 }
 
 static GArray*
@@ -328,33 +446,29 @@ get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
 {
        GArray          *array;
        int             parent_protocol;
-       int             target_field;
-       proto_tree      *subtree = NULL; /* where the parent protocol's sub-tree starts */
        proto_tree_search_info sinfo;
 
        g_assert(dnode->elem_size > 0);
        array = g_array_new(FALSE, FALSE, dnode->elem_size);
 
-       target_field = dnode->value.variable;
+       sinfo.target = dnode->value.variable;
+       sinfo.result.array = array;
+       sinfo.packet_data = pd;
+       sinfo.traverse_func = dnode->fill_array_func;
 
        /* Find the proto_tree subtree where we should start searching.*/
-       if (proto_registrar_is_protocol(target_field)) {
-               subtree = proto_find_protocol(ptree, target_field);
+       if (proto_registrar_is_protocol(sinfo.target)) {
+               proto_find_protocol_multi(ptree, sinfo.target,
+                               (GNodeTraverseFunc)proto_get_field_values, &sinfo);
        }
        else {
-               parent_protocol = proto_registrar_get_parent(target_field);
+               parent_protocol = proto_registrar_get_parent(sinfo.target);
                if (parent_protocol >= 0) {
-                       subtree = proto_find_protocol(ptree, parent_protocol);
+                       proto_find_protocol_multi(ptree, parent_protocol,
+                                       (GNodeTraverseFunc)proto_get_field_values, &sinfo);
                }
        }
 
-       if (subtree) {
-               sinfo.target_field = target_field;
-               sinfo.result_array = array;
-               sinfo.packet_data = pd;
-               proto_get_field_values(subtree, dnode->fill_array_func, &sinfo);
-       }
-
        return array;
 }
 
@@ -367,7 +481,6 @@ get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
        array = g_array_new(FALSE, FALSE, dnode->elem_size);
 
        g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, dnode->fill_array_func, array);
-/*     dnode->fill_array_func(gnode, array);*/
        return array;
 }
 
@@ -376,8 +489,20 @@ gboolean fill_array_numeric_variable(GNode *gnode, gpointer data)
        proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
        field_info              *fi = (field_info*) (gnode->data);
 
-       if (fi->hfinfo->id == sinfo->target_field) {
-               g_array_append_val(sinfo->result_array, fi->value.numeric);
+       if (fi->hfinfo->id == sinfo->target) {
+               g_array_append_val(sinfo->result.array, fi->value.numeric);
+       }
+
+       return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_floating_variable(GNode *gnode, gpointer data)
+{
+       proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
+       field_info              *fi = (field_info*) (gnode->data);
+
+       if (fi->hfinfo->id == sinfo->target) {
+               g_array_append_val(sinfo->result.array, fi->value.floating);
        }
 
        return FALSE; /* FALSE = do not end traversal of GNode tree */
@@ -388,38 +513,71 @@ gboolean fill_array_ether_variable(GNode *gnode, gpointer data)
        proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
        field_info              *fi = (field_info*) (gnode->data);
 
-       if (fi->hfinfo->id == sinfo->target_field) {
-               g_array_append_val(sinfo->result_array, fi->value.ether);
+       if (fi->hfinfo->id == sinfo->target) {
+               g_array_append_val(sinfo->result.array, fi->value.ether);
        }
 
        return FALSE; /* FALSE = do not end traversal of GNode tree */
 }
 
-gboolean fill_array_bytes_variable(GNode *gnode, gpointer data)
+gboolean fill_array_ipv4_variable(GNode *gnode, gpointer data)
 {
        proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
        field_info              *fi = (field_info*) (gnode->data);
-       GByteArray              *barray;
 
-       if (fi->hfinfo->id == sinfo->target_field) {
-               barray = g_byte_array_new();
-               /*dfilter_list_byte_arrays = g_slist_append(dfilter_list_byte_arrays, barray);*/
-               g_byte_array_append(barray, sinfo->packet_data + fi->start + bytes_offset, bytes_length);
-               g_array_append_val(sinfo->result_array, barray);
+       if (fi->hfinfo->id == sinfo->target) {
+               g_array_append_val(sinfo->result.array, fi->value.ipv4);
        }
 
        return FALSE; /* FALSE = do not end traversal of GNode tree */
 }
+gboolean fill_array_ipv6_variable(GNode *gnode, gpointer data)
+{
+       proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
+       field_info              *fi = (field_info*) (gnode->data);
+
+       if (fi->hfinfo->id == sinfo->target) {
+               g_array_append_val(sinfo->result.array, fi->value.ipv6);
+       }
 
-gboolean fill_array_boolean_variable(GNode *gnode, gpointer data)
+       return FALSE; /* FALSE = do not end traversal of GNode tree */
+}
+
+gboolean fill_array_bytes_variable(GNode *gnode, gpointer data)
 {
        proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
        field_info              *fi = (field_info*) (gnode->data);
+       GByteArray              *barray;
+       guint                   read_start, pkt_end;
+
+       if (fi->hfinfo->id == sinfo->target) {
+               if (bytes_offset < 0) {
+                       /* Handle negative byte offsets */
+                       bytes_offset = fi->length + bytes_offset;
+                       if (bytes_offset < 0) {
+                               goto FAIL;
+                       }
+               }
+
+               /* Check to make sure offset exists for this field */
+               if (bytes_offset >= fi->length) {
+                       goto FAIL;
+               }
 
-       if (fi->hfinfo->id == sinfo->target_field) {
-               g_array_append_val(sinfo->result_array, fi->value.boolean);
+               pkt_end = fi->start + fi->length;
+               read_start = fi->start + bytes_offset;
+
+               /* Check to make sure entire length requested is inside field */
+               if (pkt_end < read_start + bytes_length) {
+                       goto FAIL;
+               }
+
+               barray = g_byte_array_new();
+               g_byte_array_append(barray, sinfo->packet_data + read_start, bytes_length);
+               g_array_append_val(sinfo->result.array, barray);
        }
 
+ FAIL:
        return FALSE; /* FALSE = do not end traversal of GNode tree */
 }
 
@@ -429,7 +587,15 @@ gboolean fill_array_numeric_value(GNode *gnode, gpointer 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 */
 }
 
@@ -443,27 +609,36 @@ gboolean fill_array_ether_value(GNode *gnode, gpointer data)
        return FALSE; /* FALSE = do not end traversal of GNode tree */
 }
 
-gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
+gboolean fill_array_ipv4_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);
+       g_array_append_val(array, dnode->value.ipv4);
 
        return FALSE; /* FALSE = do not end traversal of GNode tree */
 }
 
-gboolean fill_array_boolean_value(GNode *gnode, gpointer data)
+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.boolean);
+       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 check_relation_numeric(gint operand, GArray *a, GArray *b)
 {
@@ -543,11 +718,10 @@ gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
        return FALSE;
 }
 
-
-gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
+gboolean check_relation_floating(gint operand, GArray *a, GArray *b)
 {
        int     i, j, len_a, len_b;
-       guint8  *ptr_a, *ptr_b;
+       double  val_a;
 
        len_a = a->len;
        len_b = b->len;
@@ -556,10 +730,9 @@ gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
        switch(operand) {
        case TOK_EQ:
                for(i = 0; i < len_a; i++) {
-                       ptr_a = g_array_index_ptr(a, 6, i);
+                       val_a = g_array_index(a, double, 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)
+                               if (val_a == g_array_index(b, double, j))
                                        return TRUE;
                        }
                }
@@ -567,24 +740,66 @@ gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
 
        case TOK_NE:
                for(i = 0; i < len_a; i++) {
-                       ptr_a = g_array_index_ptr(a, 6, i);
+                       val_a = g_array_index(a, double, 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)
+                               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_bytes(gint operand, GArray *a, GArray *b)
+gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b)
 {
-       int     i, j, len_a, len_b;
-       GByteArray      *ptr_a,*ptr_b;
+       int             i, j, len_a, len_b;
+       ipv4_addr       *ptr_a, *ptr_b;
 
        len_a = a->len;
        len_b = b->len;
@@ -593,10 +808,10 @@ gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
        switch(operand) {
        case TOK_EQ:
                for(i = 0; i < len_a; i++) {
-                       ptr_a = g_array_index(a, GByteArray*, i);
+                       ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), 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)
+                               ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+                               if (ipv4_addr_eq(ptr_a, ptr_b))
                                        return TRUE;
                        }
                }
@@ -604,10 +819,10 @@ gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
 
        case TOK_NE:
                for(i = 0; i < len_a; i++) {
-                       ptr_a = g_array_index(a, GByteArray*, i);
+                       ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), 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)
+                               ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
+                               if (!ipv4_addr_eq(ptr_a, ptr_b))
                                        return TRUE;
                        }
                }
@@ -615,10 +830,21 @@ gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
 
        case TOK_GT:
                for(i = 0; i < len_a; i++) {
-                       ptr_a = g_array_index(a, GByteArray*, i);
+                       ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), 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)
+                               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;
                        }
                }
@@ -626,10 +852,21 @@ gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
 
        case TOK_LT:
                for(i = 0; i < len_a; i++) {
-                       ptr_a = g_array_index(a, GByteArray*, i);
+                       ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), 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)
+                               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;
                        }
                }
@@ -640,10 +877,10 @@ gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
        return FALSE;
 }
 
-gboolean check_relation_boolean(gint operand, GArray *a, GArray *b)
+gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b)
 {
        int     i, j, len_a, len_b;
-       guint32 val_a;
+       guint8  *ptr_a, *ptr_b;
 
        len_a = a->len;
        len_b = b->len;
@@ -652,9 +889,10 @@ gboolean check_relation_boolean(gint operand, GArray *a, GArray *b)
        switch(operand) {
        case TOK_EQ:
                for(i = 0; i < len_a; i++) {
-                       val_a = g_array_index(a, guint32, i);
+                       ptr_a = g_array_index_ptr(a, 16, i);
                        for (j = 0; j < len_b; j++) {
-                               if (val_a == g_array_index(b, guint32, j))
+                               ptr_b = g_array_index_ptr(b, 16, j);
+                               if (memcmp(ptr_a, ptr_b, 16) == 0)
                                        return TRUE;
                        }
                }
@@ -662,19 +900,112 @@ gboolean check_relation_boolean(gint operand, GArray *a, GArray *b)
 
        case TOK_NE:
                for(i = 0; i < len_a; i++) {
-                       val_a = g_array_index(a, guint32, i);
+                       ptr_a = g_array_index_ptr(a, 16, i);
                        for (j = 0; j < len_b; j++) {
-                               if (val_a != g_array_index(b, guint32, j))
+                               ptr_b = g_array_index_ptr(b, 16, j);
+                               if (memcmp(ptr_a, ptr_b, 16) != 0)
                                        return TRUE;
                        }
                }
                return FALSE;
+       }
 
-       default:
-               g_assert_not_reached();
+       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;
+}