/* dfilter.c * Routines for display filters * * $Id: dfilter.c,v 1.33 2000/03/20 22:52:41 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * 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 #endif #ifndef _STDIO_H #include #endif #ifndef _STRING_H #include #endif #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H # include # else # include # endif # include "snprintf.h" #endif #ifndef __G_LIB_H__ #include #endif #ifndef __PROTO_H__ #include "proto.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 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)) 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++) { 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); } /*g_message("Adding %s", s);*/ 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; 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 */ 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); } df->dftree = NULL; df->list_of_byte_arrays = 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) { 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; } /* 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); 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 *array; int parent_protocol; proto_tree_search_info sinfo; g_assert(dnode->elem_size > 0); array = g_array_new(FALSE, FALSE, dnode->elem_size); 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(sinfo.target)) { proto_find_protocol_multi(ptree, sinfo.target, (GNodeTraverseFunc)proto_get_field_values, &sinfo); } else { parent_protocol = proto_registrar_get_parent(sinfo.target); if (parent_protocol >= 0) { proto_find_protocol_multi(ptree, parent_protocol, (GNodeTraverseFunc)proto_get_field_values, &sinfo); } } return array; } 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_func, array); return array; } 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) { 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 */ } 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) { g_array_append_val(sinfo->result.array, fi->value.ether); } return FALSE; /* FALSE = do not end traversal of GNode tree */ } 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); 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); } 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; } 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 */ } 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 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_eq(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; }