#ifndef lint
static char copyright[] =
-"$Id: tree.c,v 1.11 1998/04/09 04:31:21 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
+"$Id: tree.c,v 1.12 1998/06/25 03:10:32 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
-static TIME tree_evaluate_recurse PROTO ((int *, unsigned char **, int *,
- struct tree *));
-static TIME do_host_lookup PROTO ((int *, unsigned char **, int *,
- struct dns_host_entry *));
-static void do_data_copy PROTO ((int *, unsigned char **, int *,
- unsigned char *, int));
+static struct data_string do_host_lookup PROTO ((struct dns_host_entry *));
pair cons (car, cdr)
caddr_t car;
return foo;
}
-struct tree_cache *tree_cache (tree)
- struct tree *tree;
-{
- struct tree_cache *tc;
-
- tc = new_tree_cache ("tree_cache");
- if (!tc)
- return 0;
- tc -> value = (unsigned char *)0;
- tc -> len = tc -> buf_size = 0;
- tc -> timeout = 0;
- tc -> tree = tree;
- return tc;
-}
-
-struct tree *tree_host_lookup (name)
+struct expression *make_host_lookup (name)
char *name;
{
- struct tree *nt;
- nt = new_tree ("tree_host_lookup");
+ struct expression *nt;
+ nt = new_expression ("make_host_lookup");
if (!nt)
error ("No memory for host lookup tree node.");
- nt -> op = TREE_HOST_LOOKUP;
- nt -> data.host_lookup.host = enter_dns_host (name);
+ nt -> op = expr_host_lookup;
+ nt -> data.host_lookup = enter_dns_host (name);
return nt;
}
struct dns_host_entry *dh;
if (!(dh = (struct dns_host_entry *)dmalloc
- (sizeof (struct dns_host_entry), "enter_dns_host"))
- || !(dh -> hostname = dmalloc (strlen (name) + 1,
- "enter_dns_host")))
+ (sizeof (struct dns_host_entry), "enter_dns_host")))
error ("Can't allocate space for new host.");
+ memset (dh, 0, sizeof *dh);
+
+ dh -> hostname = dmalloc (strlen (name) + 1, "enter_dns_host");
strcpy (dh -> hostname, name);
- dh -> data = (unsigned char *)0;
- dh -> data_len = 0;
- dh -> buf_len = 0;
- dh -> timeout = 0;
return dh;
}
-struct tree *tree_const (data, len)
+struct expression *make_const_data (data, len, terminated, allocate)
unsigned char *data;
int len;
+ int terminated;
+ int allocate;
{
- struct tree *nt;
- if (!(nt = new_tree ("tree_const")))
+ struct expression *nt;
+ if (!(nt = new_expression ("tree_const")))
error ("No memory for constant data tree node.");
+ memset (nt, 0, sizeof *nt);
if (len) {
- if (!(nt -> data.const_val.data =
- (unsigned char *)dmalloc (len, "tree_const")))
- error ("No memory for constant data tree data.");
- memcpy (nt -> data.const_val.data, data, len);
+ if (allocate) {
+ if (!(nt -> data.const_data.data =
+ (unsigned char *)dmalloc (len + terminated,
+ "tree_const")))
+ error ("No memory for const_data node.");
+ memcpy (nt -> data.const_data.data,
+ data, len + terminated);
+ nt -> data.const_data.buffer =
+ nt -> data.const_data.data;
+ } else
+ nt -> data.const_data.data = data;
+ nt -> data.const_data.terminated = terminated;
} else
- nt -> data.const_val.data = 0;
+ nt -> data.const_data.data = 0;
- nt -> op = TREE_CONST;
- nt -> data.const_val.len = len;
+ nt -> op = expr_const_data;
+ nt -> data.const_data.len = len;
return nt;
}
-struct tree *tree_concat (left, right)
- struct tree *left, *right;
+struct expression *make_concat (left, right)
+ struct expression *left, *right;
{
- struct tree *nt;
+ struct expression *nt;
/* If we're concatenating a null tree to a non-null tree, just
return the non-null tree; if both trees are null, return
if (!right)
return left;
- /* If both trees are constant, combine them. */
- if (left -> op == TREE_CONST && right -> op == TREE_CONST) {
- unsigned char *buf = dmalloc (left -> data.const_val.len
- + right -> data.const_val.len,
- "tree_concat");
+ /* If both expressions are constant, combine them. */
+ if (left -> op == expr_const_data &&
+ right -> op == expr_const_data) {
+ unsigned char *buf =
+ dmalloc (left -> data.const_data.len
+ + right -> data.const_data.len
+ + right -> data.const_data.terminated,
+ "tree_concat");
if (!buf)
error ("No memory to concatenate constants.");
- memcpy (buf, left -> data.const_val.data,
- left -> data.const_val.len);
- memcpy (buf + left -> data.const_val.len,
- right -> data.const_val.data,
- right -> data.const_val.len);
- dfree (left -> data.const_val.data, "tree_concat");
- dfree (right -> data.const_val.data, "tree_concat");
- left -> data.const_val.data = buf;
- left -> data.const_val.len += right -> data.const_val.len;
- free_tree (right, "tree_concat");
+ memcpy (buf, left -> data.const_data.data,
+ left -> data.const_data.len);
+ memcpy (buf + left -> data.const_data.len,
+ right -> data.const_data.data,
+ right -> data.const_data.len);
+ if (left -> data.const_data.buffer)
+ dfree (left -> data.const_data.buffer, "make_concat");
+ if (right -> data.const_data.buffer)
+ dfree (right -> data.const_data.buffer, "make_concat");
+ left -> data.const_data.data = buf;
+ left -> data.const_data.buffer = buf;
+ left -> data.const_data.len += right -> data.const_data.len;
+ free_expression (right, "make_concat");
return left;
}
/* Otherwise, allocate a new node to concatenate the two. */
- if (!(nt = new_tree ("tree_concat")))
- error ("No memory for data tree concatenation node.");
- nt -> op = TREE_CONCAT;
- nt -> data.concat.left = left;
- nt -> data.concat.right = right;
+ if (!(nt = new_expression ("make_concat")))
+ error ("No memory for concatenation expression node.");
+ nt -> op = expr_concat;
+ nt -> data.concat [0] = left;
+ nt -> data.concat [1] = right;
return nt;
}
-struct tree *tree_limit (tree, limit)
- struct tree *tree;
- int limit;
+struct expression *make_substring (expr, offset, length)
+ struct expression *expr;
+ struct expression *offset;
+ struct expression *length;
{
- struct tree *rv;
+ struct expression *rv;
+
+ /* If the expression we're limiting is constant, limit it now. */
+ if (expr -> op == expr_const_data &&
+ offset -> op == expr_const_int &&
+ length -> op == expr_const_int) {
+ int off = offset -> data.const_int;
+ int len = length -> data.const_int;
+ if (expr -> data.const_data.len > off) {
+ expr -> data.const_data.data += off;
+ expr -> data.const_data.len -= off;
+ if (expr -> data.const_data.len > len) {
+ expr -> data.const_data.len = len;
+ expr -> data.const_data.terminated = 0;
+ }
+ } else {
+ expr -> data.const_data.len = 0;
+ expr -> data.const_data.terminated = 0;
+ }
- /* If the tree we're limiting is constant, limit it now. */
- if (tree -> op == TREE_CONST) {
- if (tree -> data.const_val.len > limit)
- tree -> data.const_val.len = limit;
- return tree;
+ free_expression (offset, "make_substring");
+ free_expression (length, "make_substring");
+ return expr;
}
/* Otherwise, put in a node which enforces the limit on evaluation. */
- rv = new_tree ("tree_limit");
+ rv = new_expression ("make_substring");
if (!rv)
- return (struct tree *)0;
- rv -> op = TREE_LIMIT;
- rv -> data.limit.tree = tree;
- rv -> data.limit.limit = limit;
+ error ("no memory for substring expression.");
+ memset (rv, 0, sizeof *rv);
+ rv -> op = expr_substring;
+ rv -> data.substring.expr = expr;
+ rv -> data.substring.offset = offset;
+ rv -> data.substring.len = length;
return rv;
}
-int tree_evaluate (tree_cache)
- struct tree_cache *tree_cache;
+struct expression *make_limit (expr, limit)
+ struct expression *expr;
+ int limit;
{
- unsigned char *bp = tree_cache -> value;
- int bc = tree_cache -> buf_size;
- int bufix = 0;
-
- /* If there's no tree associated with this cache, it evaluates
- to a constant and that was detected at startup. */
- if (!tree_cache -> tree)
- return 1;
-
- /* Try to evaluate the tree without allocating more memory... */
- tree_cache -> timeout = tree_evaluate_recurse (&bufix, &bp, &bc,
- tree_cache -> tree);
-
- /* No additional allocation needed? */
- if (bufix <= bc) {
- tree_cache -> len = bufix;
- return 1;
+ struct expression *rv;
+
+ /* If the expression we're limiting is constant, limit it now. */
+ if (expr -> op == expr_const_data) {
+ if (expr -> data.const_data.len > limit) {
+ expr -> data.const_data.len = limit;
+ expr -> data.const_data.terminated = 0;
+ }
+ return expr;
}
- /* If we can't allocate more memory, return with what we
- have (maybe nothing). */
- if (!(bp = (unsigned char *)dmalloc (bufix, "tree_evaluate")))
- return 0;
+ /* Otherwise, put in a node which enforces the limit on evaluation. */
+ rv = new_expression ("make_limit 1");
+ if (!rv)
+ error ("no memory for limit expression");
+ memset (rv, 0, sizeof *rv);
+ rv -> op = expr_substring;
+ rv -> data.substring.expr = expr;
+
+ /* Offset is a constant 0. */
+ rv -> data.substring.offset = new_expression ("make_limit 2");
+ if (!rv -> data.substring.offset)
+ error ("no memory for limit offset expression");
+ memset (rv -> data.substring.offset, 0, sizeof *rv);
+ rv -> data.substring.offset -> op = expr_const_int;
+ rv -> data.substring.offset -> data.const_int = 0;
+
+ /* Length is a constant: the specified limit. */
+ rv -> data.substring.len = new_expression ("make_limit 2");
+ if (!rv -> data.substring.len)
+ error ("no memory for limit length expression");
+ memset (rv -> data.substring.len, 0, sizeof *rv);
+ rv -> data.substring.offset -> op = expr_const_int;
+ rv -> data.substring.offset -> data.const_int = limit;
- /* Record the change in conditions... */
- bc = bufix;
- bufix = 0;
-
- /* Note that the size of the result shouldn't change on the
- second call to tree_evaluate_recurse, since we haven't
- changed the ``current'' time. */
- tree_evaluate_recurse (&bufix, &bp, &bc, tree_cache -> tree);
-
- /* Free the old buffer if needed, then store the new buffer
- location and size and return. */
- if (tree_cache -> value)
- dfree (tree_cache -> value, "tree_evaluate");
- tree_cache -> value = bp;
- tree_cache -> len = bufix;
- tree_cache -> buf_size = bc;
- return 1;
+ return rv;
}
-static TIME tree_evaluate_recurse (bufix, bufp, bufcount, tree)
- int *bufix;
- unsigned char **bufp;
- int *bufcount;
- struct tree *tree;
+struct option_cache *option_cache (expr, option)
+ struct expression *expr;
+ struct option *option;
{
- int limit;
- TIME t1, t2;
-
- switch (tree -> op) {
- case TREE_CONCAT:
- t1 = tree_evaluate_recurse (bufix, bufp, bufcount,
- tree -> data.concat.left);
- t2 = tree_evaluate_recurse (bufix, bufp, bufcount,
- tree -> data.concat.right);
- if (t1 > t2)
- return t2;
- return t1;
-
- case TREE_HOST_LOOKUP:
- return do_host_lookup (bufix, bufp, bufcount,
- tree -> data.host_lookup.host);
-
- case TREE_CONST:
- if (tree -> data.const_val.data)
- do_data_copy (bufix, bufp, bufcount,
- tree -> data.const_val.data,
- tree -> data.const_val.len);
- t1 = MAX_TIME;
- return t1;
-
- case TREE_LIMIT:
- limit = *bufix + tree -> data.limit.limit;
- t1 = tree_evaluate_recurse (bufix, bufp, bufcount,
- tree -> data.limit.tree);
- *bufix = limit;
- return t1;
-
- default:
- warn ("Bad node id in tree: %d.");
- t1 = MAX_TIME;
- return t1;
+ struct option_cache *oc = new_option_cache ("option_cache");
+ if (!oc) {
+ warn ("no memory for option cache.");
+ return (struct option_cache *)0;
}
+ memset (oc, 0, sizeof *oc);
+ oc -> expression = expr;
+ oc -> option = option;
+ return oc;
}
-static TIME do_host_lookup (bufix, bufp, bufcount, dns)
- int *bufix;
- unsigned char **bufp;
- int *bufcount;
+static struct data_string do_host_lookup (dns)
struct dns_host_entry *dns;
{
struct hostent *h;
int i;
int new_len;
+ struct data_string result;
+
+ memset (&result, 0, sizeof result);
#ifdef DEBUG_EVAL
debug ("time: now = %d dns = %d %d diff = %d",
/* If the record hasn't timed out, just copy the data and return. */
if (cur_time <= dns -> timeout) {
#ifdef DEBUG_EVAL
- debug ("easy copy: %x %d %x",
- dns -> data, dns -> data_len,
- dns -> data ? *(int *)(dns -> data) : 0);
+ debug ("easy copy: %x %d %s",
+ dns -> data, dns -> data.len,
+ dns -> data.data
+ ? inet_ntoa (*(struct in_addr *)(dns -> data.data))
+ : 0);
#endif
- do_data_copy (bufix, bufp, bufcount,
- dns -> data, dns -> data_len);
- return dns -> timeout;
+ result.data = dns -> buffer;
+ result.len = dns -> data_len;
+ return result;
}
#ifdef DEBUG_EVAL
debug ("Looking up %s", dns -> hostname);
#endif /* !NO_H_ERRNO */
/* Okay to try again after a minute. */
- return cur_time + 60;
+ dns -> timeout = cur_time + 60;
+ return result;
}
#ifdef DEBUG_EVAL
- debug ("Lookup succeeded; first address is %x",
- h -> h_addr_list [0]);
+ debug ("Lookup succeeded; first address is %s",
+ inet_ntoa (h -> h_addr_list [0]));
#endif
/* Count the number of addresses we got... */
new_len = dns -> buf_len;
if (!dns -> buf_len) {
dns -> timeout = cur_time + 60;
- return dns -> timeout;
+ return result;
}
} else {
- if (dns -> data)
- dfree (dns -> data, "do_host_lookup");
- dns -> data = buf;
+ if (dns -> buffer)
+ dfree (dns -> buffer, "do_host_lookup");
+ dns -> buffer = buf;
dns -> buf_len = new_len;
}
}
/* Addresses are conveniently stored one to the buffer, so we
have to copy them out one at a time... :'( */
for (i = 0; i < new_len / h -> h_length; i++) {
- memcpy (dns -> data + h -> h_length * i,
+ memcpy (dns -> buffer + h -> h_length * i,
h -> h_addr_list [i], h -> h_length);
}
#ifdef DEBUG_EVAL
debug ("dns -> data: %x h -> h_addr_list [0]: %x",
- *(int *)(dns -> data), h -> h_addr_list [0]);
+ *(int *)(dns -> buffer), h -> h_addr_list [0]);
#endif
dns -> data_len = new_len;
debug ("hard copy: %x %d %x",
dns -> data, dns -> data_len, *(int *)(dns -> data));
#endif
- do_data_copy (bufix, bufp, bufcount, dns -> data, dns -> data_len);
- return dns -> timeout;
+ result.data = dns -> buffer;
+ result.len = dns -> data_len;
+ return result;
}
-static void do_data_copy (bufix, bufp, bufcount, data, len)
- int *bufix;
- unsigned char **bufp;
- int *bufcount;
- unsigned char *data;
- int len;
+int evaluate_boolean_expression (packet, expr)
+ struct packet *packet;
+ struct expression *expr;
{
- int space = *bufcount - *bufix;
+ struct data_string left, right;
+ int result;
+
+ switch (expr -> op) {
+ case expr_check:
+ return check_collection (packet, expr -> data.check);
+
+ case expr_equal:
+ left = evaluate_data_expression (packet,
+ expr -> data.equal [0]);
+ right = evaluate_data_expression (packet,
+ expr -> data.equal [1]);
+ if (left.len == right.len && !memcmp (left.data,
+ right.data, left.len))
+ result = 1;
+ else
+ result = 0;
+ if (left.buffer)
+ dfree ("evaluate_boolean_expression", left.buffer);
+ if (right.buffer)
+ dfree ("evaluate_boolean_expression", right.buffer);
+ return result;
+
+ case expr_and:
+ return (evaluate_boolean_expression (packet,
+ expr -> data.and [0]) &&
+ evaluate_boolean_expression (packet,
+ expr -> data.and [1]));
+
+ case expr_or:
+ return (evaluate_boolean_expression (packet,
+ expr -> data.or [0]) ||
+ evaluate_boolean_expression (packet,
+ expr -> data.or [1]));
+
+ case expr_not:
+ return (!evaluate_boolean_expression (packet,
+ expr -> data.not));
+
+ case expr_substring:
+ case expr_suffix:
+ case expr_option:
+ case expr_hardware:
+ case expr_const_data:
+ case expr_packet:
+ case expr_concat:
+ case expr_host_lookup:
+ warn ("Data opcode in evaluate_boolean_expression: %d",
+ expr -> op);
+ return 0;
- /* If there's more space than we need, use only what we need. */
- if (space > len)
- space = len;
+ case expr_extract_int8:
+ case expr_extract_int16:
+ case expr_extract_int32:
+ case expr_const_int:
+ warn ("Numeric opcode in evaluate_boolean_expression: %d",
+ expr -> op);
+ return 0;
+ }
- /* Copy as much data as will fit, then increment the buffer index
- by the amount we actually had to copy, which could be more. */
- if (space > 0)
- memcpy (*bufp + *bufix, data, space);
- *bufix += len;
+ warn ("Bogus opcode in evaluate_boolean_expression: %d", expr -> op);
+ return 0;
}
+
+struct data_string evaluate_data_expression (packet, expr)
+ struct packet *packet;
+ struct expression *expr;
+{
+ struct data_string result, data, other;
+ int offset, len;
+
+ switch (expr -> op) {
+ /* Extract N bytes starting at byte M of a data string. */
+ case expr_substring:
+ data = evaluate_data_expression (packet,
+ expr -> data.substring.expr);
+
+ /* Evaluate the offset and length. */
+ offset = evaluate_numeric_expression
+ (packet, expr -> data.substring.offset);
+ len = evaluate_numeric_expression
+ (packet, expr -> data.substring.len);
+
+ /* If the offset is after end of the string, return
+ an empty string. */
+ if (data.len <= offset) {
+ if (data.buffer)
+ dfree ("expr_substring", data.buffer);
+ memset (&result, 0, sizeof result);
+ return result;
+ }
+
+ /* Otherwise, do the adjustments and return what's left. */
+ data.len -= offset;
+ if (data.len > len) {
+ data.len = len;
+ data.terminated = 0;
+ }
+ data.data += offset;
+ return data;
+
+ /* Extract the last N bytes of a data string. */
+ case expr_suffix:
+ data = evaluate_data_expression (packet,
+ expr -> data.suffix.expr);
+
+ /* Evaluate the length. */
+ len = evaluate_numeric_expression
+ (packet, expr -> data.substring.len);
+
+ /* If we are returning the last N bytes of a string whose
+ length is <= N, just return the string. */
+ if (data.len <= len)
+ return data;
+ data.data += data.len - len;
+ data.len = len;
+ return data;
+
+ /* Extract an option. */
+ case expr_option:
+ return ((*expr -> data.option -> universe -> lookup_func)
+ (packet, expr -> data.option -> code));
+
+ /* Combine the hardware type and address. */
+ case expr_hardware:
+ result.len = packet -> raw -> hlen + 1;
+ result.buffer = dmalloc (result.len,
+ "expr_hardware");
+ if (!result.buffer) {
+ warn ("no memory for expr_hardware");
+ result.len = 0;
+ } else {
+ result.buffer [0] = packet -> raw -> htype;
+ memcpy (&result.buffer [1], packet -> raw -> chaddr,
+ packet -> raw -> hlen);
+ }
+ result.data = result.buffer;
+ result.terminated = 0;
+ return result;
+
+ /* Extract part of the raw packet. */
+ case expr_packet:
+ len = evaluate_numeric_expression (packet,
+ expr -> data.packet.len);
+ offset = evaluate_numeric_expression (packet,
+ expr -> data.packet.len);
+ if (offset > packet -> packet_length) {
+ warn ("expr_packet on %s: length %d + offset %d > %d",
+ print_hw_addr (packet -> raw -> htype,
+ packet -> raw -> hlen,
+ packet -> raw -> chaddr),
+ len, offset, packet -> packet_length);
+ memset (&result, 0, sizeof result);
+ return result;
+ }
+ if (offset + len > packet -> packet_length)
+ result.len = packet -> packet_length - offset;
+ else
+ result.len = len;
+ result.data = ((unsigned char *)(packet -> raw)) + offset;
+ result.buffer = (unsigned char *)0;
+ result.terminated = 0;
+ return result;
+
+ /* Some constant data... */
+ case expr_const_data:
+ return expr -> data.const_data;
+
+ /* Hostname lookup... */
+ case expr_host_lookup:
+ return do_host_lookup (expr -> data.host_lookup);
+ break;
+
+ /* Concatenation... */
+ case expr_concat:
+ data = evaluate_data_expression (packet,
+ expr -> data.concat [0]);
+ other = evaluate_data_expression (packet,
+ expr -> data.concat [1]);
+
+ memset (&result, 0, sizeof result);
+ result.buffer = dmalloc (data.len + other.len +
+ other.terminated, "expr_concat");
+ if (!result.buffer) {
+ warn ("out of memory doing concatenation.");
+ return result;
+ }
+
+ result.len = (data.len + other.len);
+ result.data = result.buffer;
+ memcpy (result.data, data.data, data.len);
+ memcpy (&result.data [data.len], other.data,
+ other.len + other.terminated);
+ if (data.buffer)
+ dfree (data.buffer, "expr_concat");
+ if (other.buffer)
+ dfree (other.buffer, "expr_concat");
+ return result;
+ break;
+
+ case expr_check:
+ case expr_equal:
+ case expr_and:
+ case expr_or:
+ case expr_not:
+ warn ("Boolean opcode in evaluate_data_expression: %d",
+ expr -> op);
+ goto null_return;
+
+ case expr_extract_int8:
+ case expr_extract_int16:
+ case expr_extract_int32:
+ case expr_const_int:
+ warn ("Numeric opcode in evaluate_data_expression: %d",
+ expr -> op);
+ goto null_return;
+ }
+
+ warn ("Bogus opcode in evaluate_data_expression: %d", expr -> op);
+ null_return:
+ memset (&result, 0, sizeof result);
+ return result;
+}
+
+unsigned long evaluate_numeric_expression (packet, expr)
+ struct packet *packet;
+ struct expression *expr;
+{
+ struct data_string data;
+ unsigned long result;
+
+ switch (expr -> op) {
+ case expr_check:
+ case expr_equal:
+ case expr_and:
+ case expr_or:
+ case expr_not:
+ warn ("Boolean opcode in evaluate_numeric_expression: %d",
+ expr -> op);
+ return 0;
+
+ case expr_substring:
+ case expr_suffix:
+ case expr_option:
+ case expr_hardware:
+ case expr_const_data:
+ case expr_packet:
+ case expr_concat:
+ case expr_host_lookup:
+ warn ("Data opcode in evaluate_numeric_expression: %d",
+ expr -> op);
+ return 0;
+
+ case expr_extract_int8:
+ data = evaluate_data_expression (packet,
+ expr ->
+ data.extract_int.expr);
+ if (data.len < 1)
+ return 0;
+ result = data.data [0];
+ if (data.buffer)
+ dfree (data.buffer, "expr_extract_int8");
+ return result;
+
+ case expr_extract_int16:
+ data = evaluate_data_expression (packet,
+ expr ->
+ data.extract_int.expr);
+ if (data.len < 2)
+ return 0;
+ result = getUShort (data.data);
+ if (data.buffer)
+ dfree (data.buffer, "expr_extract_int16");
+ return result;
+
+ case expr_extract_int32:
+ data = evaluate_data_expression (packet,
+ expr ->
+ data.extract_int.expr);
+ if (data.len < 4)
+ return 0;
+ result = getULong (data.data);
+ if (data.buffer)
+ dfree (data.buffer, "expr_extract_int32");
+ return result;
+
+ case expr_const_int:
+ return expr -> data.const_int;
+ }
+
+ warn ("Bogus opcode in evaluate_numeric_expression: %d", expr -> op);
+ return 0;
+}
+
+void free_oc_ephemeral_state (oc)
+ struct option_cache *oc;
+{
+ if (free_ephemeral_outer_tree (expr))
+ free_option_cache (oc, "free_oc_ephemeral_state");
+}
+
+/* Recursively free any ephemeral subexpressions of the passed expression,
+ and then free that expression. */
+
+int free_ephemeral_outer_tree (expr)
+ struct expression *expr;
+{
+ /* If this expression isn't ephemeral, notify the caller. */
+ if (!(expr -> flags & EXPR_EPHEMERAL))
+ return 0;
+
+ /* Free any ephemeral subexpressions... */
+ switch (expr -> op) {
+ /* All the binary operators can be handled the same way. */
+ case expr_equal:
+ case expr_concat:
+ case expr_and:
+ case expr_or:
+ free_ephemeral_outer_tree (expr -> data.equal [0]);
+ free_ephemeral_outer_tree (expr -> data.equal [1]);
+ break;
+
+ case expr_substring:
+ free_ephemeral_outer_tree (expr -> data.substring.expr);
+ free_ephemeral_outer_tree (expr -> data.substring.offset);
+ free_ephemeral_outer_tree (expr -> data.substring.len);
+ break;
+
+ case expr_suffix:
+ free_ephemeral_outer_tree (expr -> data.suffix.expr);
+ free_ephemeral_outer_tree (expr -> data.suffix.len);
+ break;
+
+ case expr_not:
+ free_ephemeral_outer_tree (expr -> data.not);
+ break;
+
+ case expr_packet:
+ free_ephemeral_outer_tree (expr -> data.packet.offset);
+ free_ephemeral_outer_tree (expr -> data.packet.len);
+ break;
+
+ case expr_extract_int8:
+ case expr_extract_int16:
+ case expr_extract_int32:
+ free_ephemeral_outer_tree (expr -> data.extract_int.expr);
+ free_ephemeral_outer_tree (expr -> data.extract_int.width);
+ break;
+
+ /* No subexpressions. */
+ case expr_const_int:
+ case expr_check:
+ case expr_host_lookup:
+ case expr_option:
+ case expr_const_data:
+ case expr_hardware:
+ break;
+
+ default:
+ break;
+ }
+
+ free_expression (expr, "free_expr_outer_tree");
+ return 1;
+}
+
+/* Free all of the state in an option state buffer. The buffer itself is
+ not freed, since these buffers are always contained in other structures. */
+
+void free_option_state (state)
+ struct option_state *state;
+{
+ int i;
+ struct agent_option *ao;