Add sample strace output to illustrate the timeout problem.
[obnox/wireshark/wip.git] / dfilter-grammar.y
index 97b677d12864e8fdbc3dcf09f6ea90d592f256ec..55a05cbb7a7c7b14aaf53479d9d51068e9a0462c 100644 (file)
@@ -3,7 +3,7 @@
 /* dfilter-grammar.y
  * Parser for display filters
  *
- * $Id: dfilter-grammar.y,v 1.18 1999/09/15 06:13:19 gram Exp $
+ * $Id: dfilter-grammar.y,v 1.37 1999/11/15 06:32:11 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -51,6 +51,8 @@
 #endif
 
 #include <string.h>
+#include <errno.h>
+#include <math.h>
 
 #ifndef _STDLIB_H
 #include <stdlib.h>
@@ -78,30 +80,35 @@ static GNode* dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand,
 static GNode* dfilter_mknode_unary(int operand, GNode *n2);
 static GNode* dfilter_mknode_numeric_variable(gint id);
 static GNode* dfilter_mknode_numeric_value(guint32 val);
+static GNode* dfilter_mknode_floating_variable(gint id);
+static GNode* dfilter_mknode_floating_value(double val);
 static GNode* dfilter_mknode_ether_value(gchar*);
 static GNode* dfilter_mknode_ether_variable(gint id);
 static GNode* dfilter_mknode_ipxnet_value(guint32);
 static GNode* dfilter_mknode_ipxnet_variable(gint id);
-static GNode* dfilter_mknode_ipv4_value(char *host);
+static GNode* dfilter_mknode_ipv4_value(char *host, int nmask_bits);
 static GNode* dfilter_mknode_ipv4_variable(gint id);
+static GNode* dfilter_mknode_ipv6_value(char *host);
+static GNode* dfilter_mknode_ipv6_variable(gint id);
 static GNode* dfilter_mknode_existence(gint id);
 static GNode* dfilter_mknode_bytes_value(GByteArray *barray);
 static GNode* dfilter_mknode_bytes_variable(gint id, gint offset, guint length);
 
-static guint32 string_to_value(char *s);
+static guint32 string_to_guint32(char *s, gboolean *success);
+static double string_to_double(char *s, gboolean *success);
 static int ether_str_to_guint8_array(const char *s, guint8 *mac);
+static guint dfilter_get_bytes_variable_offset(GNode *gnode);
+static guint dfilter_get_bytes_value_length(GNode* gnode);
+static void dfilter_set_bytes_variable_length(GNode *gnode, guint length);
+static guint dfilter_get_bytes_variable_length(GNode *gnode);
+static gint dfilter_get_bytes_variable_field_registered_length(GNode *gnode);
+static char* dfilter_get_variable_abbrev(GNode *gnode);
+static int check_bytes_variable_sanity(GNode *gnode);
 
 /* This is the dfilter we're currently processing. It's how
  * dfilter_compile communicates with us.
  */
-dfilter *global_df = NULL;;
-
-/* list of GNodes allocated during parsing. If the parsing fails, we'll
- * use this list to free all the GNodes. If the parsing succeeds, we'll
- * just clear this list since dfilter_clear_filter() will take care of
- * freeing the GNodes when they're no longer needed.
- */
-GSList *gnode_slist = NULL;
+dfilter *global_df = NULL;
 
 %}
 
@@ -121,9 +128,11 @@ GSList *gnode_slist = NULL;
 
 %type <node>   statement expression relation
 %type <node>   numeric_value numeric_variable
+%type <node>   floating_value floating_variable
 %type <node>   ether_value ether_variable
 %type <node>   ipxnet_value ipxnet_variable
 %type <node>   ipv4_value ipv4_variable
+%type <node>   ipv6_value ipv6_variable
 %type <node>   variable_name
 %type <node>   bytes_value bytes_variable
 
@@ -136,26 +145,29 @@ GSList *gnode_slist = NULL;
 %token <variable>      T_FT_UINT8
 %token <variable>      T_FT_UINT16
 %token <variable>      T_FT_UINT32
+%token <variable>      T_FT_INT8
+%token <variable>      T_FT_INT16
+%token <variable>      T_FT_INT32
 %token <variable>      T_FT_ETHER
 %token <variable>      T_FT_IPv4
+%token <variable>      T_FT_IPv6
 %token <variable>      T_FT_NONE
 %token <variable>      T_FT_BYTES
 %token <variable>      T_FT_BOOLEAN
 %token <variable>      T_FT_STRING
 %token <variable>      T_FT_IPXNET
+%token <variable>      T_FT_DOUBLE
 
 %token <string>                T_VAL_UNQUOTED_STRING
 %token <string>                T_VAL_BYTE_STRING
-%token <string>                T_VAL_NUMBER_STRING
 %token <byte_range>    T_VAL_BYTE_RANGE
 
 %token <operand>       TOK_AND TOK_OR TOK_NOT TOK_XOR
 %token <operand>       TOK_EQ TOK_NE TOK_GT TOK_GE TOK_LT TOK_LE
-%token <operand>       TOK_TRUE TOK_FALSE
 
+%expect 4
 %left TOK_AND
-%left TOK_OR
-%left TOK_XOR
+%left TOK_OR TOK_XOR
 %nonassoc TOK_NOT
 
 %%
@@ -164,7 +176,7 @@ statement: expression
                {
                        global_df->dftree = $1;
                }
-       |       /* NULL */ { global_df->dftree = NULL; }
+       |       /* NULL */ { if (global_df != NULL) global_df->dftree = NULL; }
        ;
 
 expression:    '(' expression ')' { $$ = $2; }
@@ -174,6 +186,7 @@ expression: '(' expression ')' { $$ = $2; }
        |       TOK_NOT expression { $$ = dfilter_mknode_unary(TOK_NOT, $2); }
        |       relation { $$ = $1; }
        |       variable_name { $$ = $1; }
+       |       expression error { YYABORT; }
        ;
 
 relation:      numeric_variable numeric_relation numeric_value
@@ -185,6 +198,15 @@ relation:  numeric_variable numeric_relation numeric_value
                        $$ = dfilter_mknode_join($1, relation, $2, $3);
                }
 
+       |       floating_variable numeric_relation floating_value
+               {
+                       $$ = dfilter_mknode_join($1, relation, $2, $3);
+               }
+       |       floating_variable numeric_relation floating_variable
+               {
+                       $$ = dfilter_mknode_join($1, relation, $2, $3);
+               }
+
        |       ether_variable equality_relation ether_value
                {
                        $$ = dfilter_mknode_join($1, relation, $2, $3);
@@ -213,22 +235,82 @@ relation: numeric_variable numeric_relation numeric_value
                        $$ = dfilter_mknode_join($1, relation, $2, $3);
                }
 
+       |       ipv6_variable equality_relation ipv6_value
+               {
+                       $$ = dfilter_mknode_join($1, relation, $2, $3);
+               }
+       |       ipv6_variable equality_relation ipv6_variable
+               {
+                       $$ = dfilter_mknode_join($1, relation, $2, $3);
+               }
+
        |       bytes_variable bytes_relation bytes_value
                {
+                       int a_len, b_len;
+
+                       a_len = dfilter_get_bytes_variable_length($1);
+                       b_len = dfilter_get_bytes_value_length($3);
+
+                       if (a_len == 0) {
+                               dfilter_set_bytes_variable_length($1, b_len);
+                               a_len = b_len;
+                       }
+
+                       if (!check_bytes_variable_sanity($1)) {
+                               YYERROR;
+                       }
+
+                       if (a_len != b_len) {
+                               dfilter_fail("Field \"%s\" has %u byte%s being compared, but %u byte%s "
+                                       "%s supplied.",
+                                       dfilter_get_variable_abbrev($1),
+                                       a_len, plurality(a_len, "", "s"),
+                                       b_len, plurality(b_len, "", "s"),
+                                              plurality(b_len, "was", "were"));
+                               YYERROR;
+                       }
+
                        $$ = dfilter_mknode_join($1, relation, $2, $3);
                }
        |       bytes_variable bytes_relation bytes_variable
                {
+                       int a_len, b_len;
+
+                       a_len = dfilter_get_bytes_variable_length($1);
+                       b_len = dfilter_get_bytes_variable_length($3);
+
+                       if (!check_bytes_variable_sanity($1)) {
+                               YYERROR;
+                       }
+
+                       if (!check_bytes_variable_sanity($3)) {
+                               YYERROR;
+                       }
+
+                       if (a_len != b_len) {
+                               dfilter_fail("Fields \"%s\" and \"%s\" are being compared with "
+                                       "disparate lengths of %u byte%s and %u byte%s.",
+                                       dfilter_get_variable_abbrev($1),
+                                       dfilter_get_variable_abbrev($3),
+                                       a_len, plurality(a_len, "", "s"),
+                                       b_len, plurality(b_len, "", "s"));
+                               YYERROR;
+                       }
+
                        $$ = dfilter_mknode_join($1, relation, $2, $3);
                }
 
        ;
 
 
-numeric_value: T_VAL_NUMBER_STRING
+numeric_value: T_VAL_UNQUOTED_STRING
        {
-               $$ = dfilter_mknode_numeric_value(string_to_value($1));
+               gboolean success;
+               $$ = dfilter_mknode_numeric_value(string_to_guint32($1, &success));
                g_free($1);
+               if (!success) {
+                       YYERROR;
+               }
         }
        ;
 
@@ -242,23 +324,129 @@ ether_value:     T_VAL_BYTE_STRING
        }
        ;
 
-ipxnet_value:  T_VAL_NUMBER_STRING
+ipxnet_value:  T_VAL_UNQUOTED_STRING
        {
-               $$ = dfilter_mknode_ipxnet_value(string_to_value($1));
+               gboolean success;
+               $$ = dfilter_mknode_ipxnet_value(string_to_guint32($1, &success));
                g_free($1);
+               if (!success) {
+                       YYERROR;
+               }
+       }
+       ;
+
+floating_value:        T_VAL_UNQUOTED_STRING
+       {
+               gboolean success;
+               $$ = dfilter_mknode_floating_value(string_to_double($1, &success));
+               g_free($1);
+               if (!success) {
+                       YYERROR;
+               }
+       }
+
+       |       T_VAL_BYTE_STRING
+       {
+               /* e.g., 0.0, 0.1, 0.01 ... */
+               gboolean success;
+               $$ = dfilter_mknode_floating_value(string_to_double($1, &success));
+               g_free($1);
+               if (!success) {
+                       YYERROR;
+               }
        }
        ;
 
 ipv4_value:    T_VAL_UNQUOTED_STRING
+       {
+               $$ = dfilter_mknode_ipv4_value($1, 32);
+               g_free($1);
+               if ($$ == NULL) {
+                       YYERROR;
+               }
+       }
+
+       |       T_VAL_BYTE_STRING
+       {
+               $$ = dfilter_mknode_ipv4_value($1, 32);
+               g_free($1);
+               if ($$ == NULL) {
+                       YYERROR;
+               }
+       }
+
+       |       T_VAL_UNQUOTED_STRING '/' T_VAL_UNQUOTED_STRING
+       {
+               gboolean        success;
+               guint32         nmask_bits;
+
+               nmask_bits = string_to_guint32($3, &success);
+               if (!success) {
+                       g_free($1);
+                       g_free($3);
+                       YYERROR;
+               }
+
+               if (nmask_bits > 32) {
+                       dfilter_fail("The number of netmask bits in \"%s/%s\" should "
+                               "be between 0 and 32.", $1, $3);
+                       g_free($1);
+                       g_free($3);
+                       YYERROR;
+               }
+
+               $$ = dfilter_mknode_ipv4_value($1, nmask_bits);
+               g_free($1);
+               g_free($3);
+               if ($$ == NULL) {
+                       YYERROR;
+               }
+       }
+
+       |       T_VAL_BYTE_STRING '/' T_VAL_UNQUOTED_STRING
+       {
+               gboolean        success;
+               guint32         nmask_bits;
+
+               nmask_bits = string_to_guint32($3, &success);
+               if (!success) {
+                       g_free($1);
+                       g_free($3);
+                       YYERROR;
+               }
+
+               if (nmask_bits > 32) {
+                       dfilter_fail("The number of netmask bits in \"%s/%s\" should "
+                               "be between 0 and 32.", $1, $3);
+                       g_free($1);
+                       g_free($3);
+                       YYERROR;
+               }
+               $$ = dfilter_mknode_ipv4_value($1, nmask_bits);
+               g_free($1);
+               g_free($3);
+               if ($$ == NULL) {
+                       YYERROR;
+               }
+       }
+       ;
+
+ipv6_value:    T_VAL_UNQUOTED_STRING
                {
-                       $$ = dfilter_mknode_ipv4_value($1);
+                       $$ = dfilter_mknode_ipv6_value($1);
                        g_free($1);
+                       if ($$ == NULL) {
+                               YYERROR;
+                       }
                }
 
        |       T_VAL_BYTE_STRING
                {
-                       $$ = dfilter_mknode_ipv4_value($1);
+                       $$ = dfilter_mknode_ipv6_value($1);
                        g_free($1);
+                       if ($$ == NULL) {
+                               YYERROR;
+                       }
                }
        ;
 
@@ -271,23 +459,58 @@ bytes_value:      T_VAL_BYTE_STRING
                $$ = dfilter_mknode_bytes_value(barray);
                g_free($1);
        }
-       ;
 
+       |       T_VAL_UNQUOTED_STRING
+       {
+               gboolean        success;
+               guint32         val32;
+               guint8          val8;
+               GByteArray      *barray;
+
+               val32 = string_to_guint32($1, &success);
+               if (!success) {
+                       g_free($1);
+                       YYERROR;
+               }
+               if (val32 > 0xff) {
+                       dfilter_fail("The value \"%s\" cannot be stored in a single-byte byte-string. "
+                               "Use the multi-byte \"xx:yy\" representation.", $1);
+                       g_free($1);
+                       YYERROR;
+               }
+               val8 = (guint8) val32;
+               barray = g_byte_array_new();
+               global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray);
+               g_byte_array_append(barray, &val8, 1);
+
+               $$ = dfilter_mknode_bytes_value(barray);
+               g_free($1);
+       }
+       ;
 
 numeric_variable:      T_FT_UINT8      { $$ = dfilter_mknode_numeric_variable($1.id); }
        |               T_FT_UINT16     { $$ = dfilter_mknode_numeric_variable($1.id); }
        |               T_FT_UINT32     { $$ = dfilter_mknode_numeric_variable($1.id); }
+       |               T_FT_INT8       { $$ = dfilter_mknode_numeric_variable($1.id); }
+       |               T_FT_INT16      { $$ = dfilter_mknode_numeric_variable($1.id); }
+       |               T_FT_INT32      { $$ = dfilter_mknode_numeric_variable($1.id); }
        ;
 
 ether_variable:                T_FT_ETHER      { $$ = dfilter_mknode_ether_variable($1.id); }
        ;
 
+floating_variable:     T_FT_DOUBLE     { $$ = dfilter_mknode_floating_variable($1.id); }
+       ;
+
 ipxnet_variable:       T_FT_IPXNET     { $$ = dfilter_mknode_ipxnet_variable($1.id); }
        ;
 
 ipv4_variable:         T_FT_IPv4       { $$ = dfilter_mknode_ipv4_variable($1.id); }
        ;
 
+ipv6_variable:         T_FT_IPv6       { $$ = dfilter_mknode_ipv6_variable($1.id); }
+       ;
+
 variable_name:         any_variable_type
        {
                GNode   *variable;
@@ -311,16 +534,21 @@ bytes_variable:           any_variable_type T_VAL_BYTE_RANGE
                }
        ;
 
-any_variable_type:     T_FT_UINT8 { $$ = $1; }
-       |               T_FT_UINT16 { $$ = $1; }
-       |               T_FT_UINT32 { $$ = $1; }
-       |               T_FT_ETHER { $$ = $1; }
-       |               T_FT_IPv4 { $$ = $1; }
-       |               T_FT_IPXNET { $$ = $1; }
-       |               T_FT_NONE { $$ = $1; }
-       |               T_FT_BYTES { $$ = $1; }
-       |               T_FT_BOOLEAN { $$ = $1; }
-       |               T_FT_STRING { $$ = $1; }
+any_variable_type:     T_FT_UINT8      { $$ = $1; }
+       |               T_FT_UINT16     { $$ = $1; }
+       |               T_FT_UINT32     { $$ = $1; }
+       |               T_FT_INT8       { $$ = $1; }
+       |               T_FT_INT16      { $$ = $1; }
+       |               T_FT_INT32      { $$ = $1; }
+       |               T_FT_DOUBLE     { $$ = $1; }
+       |               T_FT_ETHER      { $$ = $1; }
+       |               T_FT_IPv4       { $$ = $1; }
+       |               T_FT_IPv6       { $$ = $1; }
+       |               T_FT_IPXNET     { $$ = $1; }
+       |               T_FT_NONE       { $$ = $1; }
+       |               T_FT_BYTES      { $$ = $1; }
+       |               T_FT_BOOLEAN    { $$ = $1; }
+       |               T_FT_STRING     { $$ = $1; }
        ;
 
 numeric_relation:      TOK_EQ { $$ = TOK_EQ; }
@@ -368,7 +596,6 @@ dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2)
        g_node_append(gnode_root, n1);
        g_node_append(gnode_root, n2);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode_root);
        return gnode_root;
 }
 
@@ -388,7 +615,6 @@ dfilter_mknode_unary(int operand, GNode *n2)
        gnode_root = g_node_new(node_root);
        g_node_append(gnode_root, n2);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode_root);
        return gnode_root;
 }
 
@@ -407,7 +633,6 @@ dfilter_mknode_numeric_variable(gint id)
        node->value.variable = id;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
@@ -425,7 +650,23 @@ dfilter_mknode_ether_variable(gint id)
        node->value.variable = id;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
+       return gnode;
+}
+
+static GNode*
+dfilter_mknode_floating_variable(gint id)
+{
+       dfilter_node    *node;
+       GNode           *gnode;
+
+       node = g_mem_chunk_alloc(global_df->node_memchunk);
+       node->ntype = variable;
+       node->elem_size = sizeof(double);
+       node->fill_array_func = fill_array_floating_variable;
+       node->check_relation_func = check_relation_floating;
+       node->value.variable = id;
+       gnode = g_node_new(node);
+
        return gnode;
 }
 
@@ -443,7 +684,6 @@ dfilter_mknode_ipxnet_variable(gint id)
        node->value.variable = id;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
@@ -455,13 +695,29 @@ dfilter_mknode_ipv4_variable(gint id)
 
        node = g_mem_chunk_alloc(global_df->node_memchunk);
        node->ntype = variable;
-       node->elem_size = sizeof(guint32);
-       node->fill_array_func = fill_array_numeric_variable; /* cheating ! */
-       node->check_relation_func = check_relation_numeric; /* cheating ! */
+       node->elem_size = sizeof(ipv4_addr);
+       node->fill_array_func = fill_array_ipv4_variable;
+       node->check_relation_func = check_relation_ipv4;
+       node->value.variable = id;
+       gnode = g_node_new(node);
+
+       return gnode;
+}
+
+static GNode*
+dfilter_mknode_ipv6_variable(gint id)
+{
+       dfilter_node    *node;
+       GNode           *gnode;
+
+       node = g_mem_chunk_alloc(global_df->node_memchunk);
+       node->ntype = variable;
+       node->elem_size = 16;
+       node->fill_array_func = fill_array_ipv6_variable;
+       node->check_relation_func = check_relation_ipv6; 
        node->value.variable = id;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
@@ -481,10 +737,65 @@ dfilter_mknode_bytes_variable(gint id, gint offset, guint length)
        node->length = length;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
+/* Gets length of variable represented by node from proto_register */
+static gint
+dfilter_get_bytes_variable_field_registered_length(GNode *gnode)
+{
+       dfilter_node    *node = gnode->data;
+
+       /* Is this really a bytes_variable? */
+       g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+       return proto_registrar_get_length(node->value.variable);
+}
+
+/* Sets the length of a bytes_variable node */
+static void
+dfilter_set_bytes_variable_length(GNode *gnode, guint length)
+{
+       dfilter_node    *node = gnode->data;
+
+       /* Is this really a bytes_variable? */
+       g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+       node->length = length;
+}
+
+/* Gets the length of a bytes_variable node */
+static guint
+dfilter_get_bytes_variable_length(GNode *gnode)
+{
+       dfilter_node    *node = gnode->data;
+
+       /* Is this really a bytes_variable? */
+       g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+       return node->length;
+}
+
+/* Gets the offset of a bytes_variable node */
+static guint
+dfilter_get_bytes_variable_offset(GNode *gnode)
+{
+       dfilter_node    *node = gnode->data;
+
+       /* Is this really a bytes_variable? */
+       g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+       return node->offset;
+}
+
+static char*
+dfilter_get_variable_abbrev(GNode *gnode)
+{
+       dfilter_node    *node = gnode->data;
+
+       return proto_registrar_get_abbrev(node->value.variable);
+}
+
 static GNode*
 dfilter_mknode_numeric_value(guint32 val)
 {
@@ -499,7 +810,23 @@ dfilter_mknode_numeric_value(guint32 val)
        node->value.numeric = val;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
+       return gnode;
+}
+
+static GNode*
+dfilter_mknode_floating_value(double val)
+{
+       dfilter_node    *node;
+       GNode           *gnode;
+
+       node = g_mem_chunk_alloc(global_df->node_memchunk);
+       node->ntype = floating;
+       node->elem_size = sizeof(double);
+       node->fill_array_func = fill_array_floating_value;
+       node->check_relation_func = check_relation_floating;
+       node->value.floating = val;
+       gnode = g_node_new(node);
+
        return gnode;
 }
 
@@ -518,16 +845,14 @@ dfilter_mknode_ether_value(gchar *byte_string)
 
        if (!ether_str_to_guint8_array(byte_string, &node->value.ether[0])) {
                /* Rather than free the mem_chunk allocation, let it
-                * stay. It will be cleaned up in the next call to
-                * dfilter_clear() */
-               dfilter_error_msg = &dfilter_error_msg_buf[0];
-               snprintf(dfilter_error_msg, sizeof(dfilter_error_msg_buf),
-                       "\"%s\" is not a valid hardware address.", byte_string);
+                * stay. It will be cleaned up when "dfilter_compile()"
+                * calls "dfilter_destroy()". */
+               dfilter_fail("\"%s\" is not a valid hardware address.",
+                   byte_string);
                return NULL;
        }
 
        gnode = g_node_new(node);
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
@@ -545,26 +870,60 @@ dfilter_mknode_ipxnet_value(guint32 ipx_net_val)
        node->value.numeric = ipx_net_val;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
+/* Returns NULL on bad parse of IP value */
 static GNode*
-dfilter_mknode_ipv4_value(char *host)
+dfilter_mknode_ipv4_value(char *host, int nmask_bits)
 {
        dfilter_node    *node;
        GNode           *gnode;
+       guint32         addr;
 
        node = g_mem_chunk_alloc(global_df->node_memchunk);
        node->ntype = numeric;
-       node->elem_size = sizeof(guint32);
-       node->fill_array_func = fill_array_numeric_value; /* cheating ! */
-       node->check_relation_func = check_relation_numeric; /* cheating ! */
-       node->value.numeric = get_host_ipaddr(host);
-       node->value.numeric = htonl(node->value.numeric);
+       node->elem_size = sizeof(ipv4_addr);
+       node->fill_array_func = fill_array_ipv4_value;
+       node->check_relation_func = check_relation_ipv4;
+       if (!get_host_ipaddr(host, &addr)) {
+               /* Rather than free the mem_chunk allocation, let it
+                * stay. It will be cleaned up when "dfilter_compile()"
+                * calls "dfilter_destroy()". */
+               dfilter_fail("\"%s\" isn't a valid host name or IP address.",
+                   host);
+               return NULL;
+       }
+       ipv4_addr_set_host_order_addr(&node->value.ipv4, addr);
+       ipv4_addr_set_netmask_bits(&node->value.ipv4, nmask_bits);
+
        gnode = g_node_new(node);
+       return gnode;
+}
+
+/* Returns NULL on bad parse of IPv6 value */
+static GNode*
+dfilter_mknode_ipv6_value(char *host)
+{
+       dfilter_node    *node;
+       GNode           *gnode;
+
+       node = g_mem_chunk_alloc(global_df->node_memchunk);
+       node->ntype = ipv6;
+       node->elem_size = 16;
+       node->fill_array_func = fill_array_ipv6_value;
+       node->check_relation_func = check_relation_ipv6;
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
+       if (!get_host_ipaddr6(host, (struct e_in6_addr*)&node->value.ipv6[0])) {
+               /* Rather than free the mem_chunk allocation, let it
+                * stay. It will be cleaned up when "dfilter_compile()"
+                * calls "dfilter_destroy()". */
+               dfilter_fail("\"%s\" isn't a valid IPv6 address.",
+                   host);
+               return NULL;
+       }
+
+       gnode = g_node_new(node);
        return gnode;
 }
 
@@ -584,21 +943,74 @@ dfilter_mknode_bytes_value(GByteArray *barray)
        node->length = barray->len;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
+/* Given a node representing a bytes_value, returns
+ * the length of the byte array */
+static guint
+dfilter_get_bytes_value_length(GNode* gnode)
+{
+       dfilter_node    *node = gnode->data;
+
+       g_assert(node->ntype == bytes);
+       return node->length;
+}
+
 static guint32
-string_to_value(char *s)
+string_to_guint32(char *s, gboolean *success)
 {
        char    *endptr;
        guint32 val;
 
        val = strtoul(s, &endptr, 0);
-       /* I should probably check errno here */
+       *success = TRUE;
+       if (endptr == s || *endptr != '\0') {
+               /* This isn't a valid number. */
+               dfilter_fail("\"%s\" is not a valid number.", s);
+               *success = FALSE;
+       }
+       if (errno == ERANGE) {
+               *success = FALSE;
+               if (val == ULONG_MAX) {
+                       dfilter_fail("\"%s\" causes an integer overflow.", s);
+               }
+               else {
+                       dfilter_fail("\"%s\" is not an integer.", s);
+               }
+       }
 
        return (guint32)val;
 }
+
+static double
+string_to_double(char *s, gboolean *success)
+{
+       char    *endptr = NULL;
+       double  retval;
+
+       retval = strtod(s, &endptr);
+       *success = TRUE;
+
+       if (endptr == s) {
+               dfilter_fail("\"%s\" is not a valid floating-point number.", s);
+               *success = FALSE;
+       }
+
+       if (errno == ERANGE) {
+               *success = FALSE;
+               if (retval == 0) {
+                       dfilter_fail("\"%s\" causes a floating-point underflow.", s);
+               }
+               else if (retval == HUGE_VAL) {
+                       dfilter_fail("\"%s\" causes a floating-point overflow.", s);
+               }
+               else {
+                       dfilter_fail("\"%s\" is not a valid floating-point.", s);
+               }
+       }
+       return retval;
+}
        
 static GNode*
 dfilter_mknode_existence(gint id)
@@ -614,7 +1026,6 @@ dfilter_mknode_existence(gint id)
        node->value.variable = id;
        gnode = g_node_new(node);
 
-       gnode_slist = g_slist_append(gnode_slist, gnode);
        return gnode;
 }
 
@@ -652,3 +1063,27 @@ ether_str_to_guint8_array(const char *s, guint8 *mac)
                return 1;       /* read exactly 6 hex pairs */
 }
 
+
+static int
+check_bytes_variable_sanity(GNode *gnode)
+{
+       int a_off, a_len, reg_len, t_off;
+
+       a_off = dfilter_get_bytes_variable_offset(gnode);
+       a_len = dfilter_get_bytes_variable_length(gnode);
+       reg_len = dfilter_get_bytes_variable_field_registered_length(gnode);
+
+       if (reg_len > 0) {
+               t_off = a_off >= 0 ? a_off : reg_len + a_off;
+               if (t_off + a_len > reg_len) {
+                       dfilter_fail("The \"%s\" field is only %u byte%s wide, but "
+                               "%u byte%s %s supplied.",
+                               dfilter_get_variable_abbrev(gnode),
+                               reg_len, plurality(reg_len, "", "s"),
+                               a_len, plurality(a_len, "", "s"),
+                                      plurality(a_len, "was", "were"));
+                       return 0;
+               }
+       }
+       return 1;
+}