2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-31 22:35:25 +00:00

Update all the names to reflect the unification of expression evaluation and dns lookup evaluation. Add expression evaluator.

This commit is contained in:
Ted Lemon
1998-06-25 03:10:32 +00:00
parent 383a87e2e3
commit 33e712eab3

View File

@@ -42,17 +42,12 @@
#ifndef lint #ifndef lint
static char copyright[] = 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 */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
static TIME tree_evaluate_recurse PROTO ((int *, unsigned char **, int *, static struct data_string do_host_lookup PROTO ((struct dns_host_entry *));
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));
pair cons (car, cdr) pair cons (car, cdr)
caddr_t car; caddr_t car;
@@ -66,30 +61,15 @@ pair cons (car, cdr)
return foo; return foo;
} }
struct tree_cache *tree_cache (tree) struct expression *make_host_lookup (name)
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)
char *name; char *name;
{ {
struct tree *nt; struct expression *nt;
nt = new_tree ("tree_host_lookup"); nt = new_expression ("make_host_lookup");
if (!nt) if (!nt)
error ("No memory for host lookup tree node."); error ("No memory for host lookup tree node.");
nt -> op = TREE_HOST_LOOKUP; nt -> op = expr_host_lookup;
nt -> data.host_lookup.host = enter_dns_host (name); nt -> data.host_lookup = enter_dns_host (name);
return nt; return nt;
} }
@@ -99,42 +79,50 @@ struct dns_host_entry *enter_dns_host (name)
struct dns_host_entry *dh; struct dns_host_entry *dh;
if (!(dh = (struct dns_host_entry *)dmalloc if (!(dh = (struct dns_host_entry *)dmalloc
(sizeof (struct dns_host_entry), "enter_dns_host")) (sizeof (struct dns_host_entry), "enter_dns_host")))
|| !(dh -> hostname = dmalloc (strlen (name) + 1,
"enter_dns_host")))
error ("Can't allocate space for new 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); strcpy (dh -> hostname, name);
dh -> data = (unsigned char *)0;
dh -> data_len = 0;
dh -> buf_len = 0;
dh -> timeout = 0;
return dh; return dh;
} }
struct tree *tree_const (data, len) struct expression *make_const_data (data, len, terminated, allocate)
unsigned char *data; unsigned char *data;
int len; int len;
int terminated;
int allocate;
{ {
struct tree *nt; struct expression *nt;
if (!(nt = new_tree ("tree_const"))) if (!(nt = new_expression ("tree_const")))
error ("No memory for constant data tree node."); error ("No memory for constant data tree node.");
memset (nt, 0, sizeof *nt);
if (len) { if (len) {
if (!(nt -> data.const_val.data = if (allocate) {
(unsigned char *)dmalloc (len, "tree_const"))) if (!(nt -> data.const_data.data =
error ("No memory for constant data tree data."); (unsigned char *)dmalloc (len + terminated,
memcpy (nt -> data.const_val.data, data, len); "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 } else
nt -> data.const_val.data = 0; nt -> data.const_data.data = data;
nt -> data.const_data.terminated = terminated;
} else
nt -> data.const_data.data = 0;
nt -> op = TREE_CONST; nt -> op = expr_const_data;
nt -> data.const_val.len = len; nt -> data.const_data.len = len;
return nt; return nt;
} }
struct tree *tree_concat (left, right) struct expression *make_concat (left, right)
struct tree *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 /* If we're concatenating a null tree to a non-null tree, just
return the non-null tree; if both trees are null, return return the non-null tree; if both trees are null, return
@@ -144,158 +132,149 @@ struct tree *tree_concat (left, right)
if (!right) if (!right)
return left; return left;
/* If both trees are constant, combine them. */ /* If both expressions are constant, combine them. */
if (left -> op == TREE_CONST && right -> op == TREE_CONST) { if (left -> op == expr_const_data &&
unsigned char *buf = dmalloc (left -> data.const_val.len right -> op == expr_const_data) {
+ right -> data.const_val.len, unsigned char *buf =
dmalloc (left -> data.const_data.len
+ right -> data.const_data.len
+ right -> data.const_data.terminated,
"tree_concat"); "tree_concat");
if (!buf) if (!buf)
error ("No memory to concatenate constants."); error ("No memory to concatenate constants.");
memcpy (buf, left -> data.const_val.data, memcpy (buf, left -> data.const_data.data,
left -> data.const_val.len); left -> data.const_data.len);
memcpy (buf + left -> data.const_val.len, memcpy (buf + left -> data.const_data.len,
right -> data.const_val.data, right -> data.const_data.data,
right -> data.const_val.len); right -> data.const_data.len);
dfree (left -> data.const_val.data, "tree_concat"); if (left -> data.const_data.buffer)
dfree (right -> data.const_val.data, "tree_concat"); dfree (left -> data.const_data.buffer, "make_concat");
left -> data.const_val.data = buf; if (right -> data.const_data.buffer)
left -> data.const_val.len += right -> data.const_val.len; dfree (right -> data.const_data.buffer, "make_concat");
free_tree (right, "tree_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; return left;
} }
/* Otherwise, allocate a new node to concatenate the two. */ /* Otherwise, allocate a new node to concatenate the two. */
if (!(nt = new_tree ("tree_concat"))) if (!(nt = new_expression ("make_concat")))
error ("No memory for data tree concatenation node."); error ("No memory for concatenation expression node.");
nt -> op = TREE_CONCAT; nt -> op = expr_concat;
nt -> data.concat.left = left; nt -> data.concat [0] = left;
nt -> data.concat.right = right; nt -> data.concat [1] = right;
return nt; return nt;
} }
struct tree *tree_limit (tree, limit) struct expression *make_substring (expr, offset, length)
struct tree *tree; struct expression *expr;
int limit; struct expression *offset;
struct expression *length;
{ {
struct tree *rv; struct expression *rv;
/* If the tree we're limiting is constant, limit it now. */ /* If the expression we're limiting is constant, limit it now. */
if (tree -> op == TREE_CONST) { if (expr -> op == expr_const_data &&
if (tree -> data.const_val.len > limit) offset -> op == expr_const_int &&
tree -> data.const_val.len = limit; length -> op == expr_const_int) {
return tree; 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;
}
free_expression (offset, "make_substring");
free_expression (length, "make_substring");
return expr;
} }
/* Otherwise, put in a node which enforces the limit on evaluation. */ /* Otherwise, put in a node which enforces the limit on evaluation. */
rv = new_tree ("tree_limit"); rv = new_expression ("make_substring");
if (!rv) if (!rv)
return (struct tree *)0; error ("no memory for substring expression.");
rv -> op = TREE_LIMIT; memset (rv, 0, sizeof *rv);
rv -> data.limit.tree = tree; rv -> op = expr_substring;
rv -> data.limit.limit = limit; rv -> data.substring.expr = expr;
rv -> data.substring.offset = offset;
rv -> data.substring.len = length;
return rv; return rv;
} }
int tree_evaluate (tree_cache) struct expression *make_limit (expr, limit)
struct tree_cache *tree_cache; struct expression *expr;
{
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;
}
/* If we can't allocate more memory, return with what we
have (maybe nothing). */
if (!(bp = (unsigned char *)dmalloc (bufix, "tree_evaluate")))
return 0;
/* 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;
}
static TIME tree_evaluate_recurse (bufix, bufp, bufcount, tree)
int *bufix;
unsigned char **bufp;
int *bufcount;
struct tree *tree;
{
int limit; int limit;
TIME t1, t2; {
struct expression *rv;
switch (tree -> op) { /* If the expression we're limiting is constant, limit it now. */
case TREE_CONCAT: if (expr -> op == expr_const_data) {
t1 = tree_evaluate_recurse (bufix, bufp, bufcount, if (expr -> data.const_data.len > limit) {
tree -> data.concat.left); expr -> data.const_data.len = limit;
t2 = tree_evaluate_recurse (bufix, bufp, bufcount, expr -> data.const_data.terminated = 0;
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;
} }
return expr;
}
/* 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;
return rv;
} }
static TIME do_host_lookup (bufix, bufp, bufcount, dns) struct option_cache *option_cache (expr, option)
int *bufix; struct expression *expr;
unsigned char **bufp; struct option *option;
int *bufcount; {
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 struct data_string do_host_lookup (dns)
struct dns_host_entry *dns; struct dns_host_entry *dns;
{ {
struct hostent *h; struct hostent *h;
int i; int i;
int new_len; int new_len;
struct data_string result;
memset (&result, 0, sizeof result);
#ifdef DEBUG_EVAL #ifdef DEBUG_EVAL
debug ("time: now = %d dns = %d %d diff = %d", debug ("time: now = %d dns = %d %d diff = %d",
@@ -305,13 +284,15 @@ static TIME do_host_lookup (bufix, bufp, bufcount, dns)
/* If the record hasn't timed out, just copy the data and return. */ /* If the record hasn't timed out, just copy the data and return. */
if (cur_time <= dns -> timeout) { if (cur_time <= dns -> timeout) {
#ifdef DEBUG_EVAL #ifdef DEBUG_EVAL
debug ("easy copy: %x %d %x", debug ("easy copy: %x %d %s",
dns -> data, dns -> data_len, dns -> data, dns -> data.len,
dns -> data ? *(int *)(dns -> data) : 0); dns -> data.data
? inet_ntoa (*(struct in_addr *)(dns -> data.data))
: 0);
#endif #endif
do_data_copy (bufix, bufp, bufcount, result.data = dns -> buffer;
dns -> data, dns -> data_len); result.len = dns -> data_len;
return dns -> timeout; return result;
} }
#ifdef DEBUG_EVAL #ifdef DEBUG_EVAL
debug ("Looking up %s", dns -> hostname); debug ("Looking up %s", dns -> hostname);
@@ -341,12 +322,13 @@ static TIME do_host_lookup (bufix, bufp, bufcount, dns)
#endif /* !NO_H_ERRNO */ #endif /* !NO_H_ERRNO */
/* Okay to try again after a minute. */ /* Okay to try again after a minute. */
return cur_time + 60; dns -> timeout = cur_time + 60;
return result;
} }
#ifdef DEBUG_EVAL #ifdef DEBUG_EVAL
debug ("Lookup succeeded; first address is %x", debug ("Lookup succeeded; first address is %s",
h -> h_addr_list [0]); inet_ntoa (h -> h_addr_list [0]));
#endif #endif
/* Count the number of addresses we got... */ /* Count the number of addresses we got... */
@@ -363,12 +345,12 @@ static TIME do_host_lookup (bufix, bufp, bufcount, dns)
new_len = dns -> buf_len; new_len = dns -> buf_len;
if (!dns -> buf_len) { if (!dns -> buf_len) {
dns -> timeout = cur_time + 60; dns -> timeout = cur_time + 60;
return dns -> timeout; return result;
} }
} else { } else {
if (dns -> data) if (dns -> buffer)
dfree (dns -> data, "do_host_lookup"); dfree (dns -> buffer, "do_host_lookup");
dns -> data = buf; dns -> buffer = buf;
dns -> buf_len = new_len; dns -> buf_len = new_len;
} }
} }
@@ -376,12 +358,12 @@ static TIME do_host_lookup (bufix, bufp, bufcount, dns)
/* Addresses are conveniently stored one to the buffer, so we /* Addresses are conveniently stored one to the buffer, so we
have to copy them out one at a time... :'( */ have to copy them out one at a time... :'( */
for (i = 0; i < new_len / h -> h_length; i++) { 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); h -> h_addr_list [i], h -> h_length);
} }
#ifdef DEBUG_EVAL #ifdef DEBUG_EVAL
debug ("dns -> data: %x h -> h_addr_list [0]: %x", 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 #endif
dns -> data_len = new_len; dns -> data_len = new_len;
@@ -393,26 +375,386 @@ static TIME do_host_lookup (bufix, bufp, bufcount, dns)
debug ("hard copy: %x %d %x", debug ("hard copy: %x %d %x",
dns -> data, dns -> data_len, *(int *)(dns -> data)); dns -> data, dns -> data_len, *(int *)(dns -> data));
#endif #endif
do_data_copy (bufix, bufp, bufcount, dns -> data, dns -> data_len); result.data = dns -> buffer;
return dns -> timeout; result.len = dns -> data_len;
return result;
} }
static void do_data_copy (bufix, bufp, bufcount, data, len) int evaluate_boolean_expression (packet, expr)
int *bufix; struct packet *packet;
unsigned char **bufp; struct expression *expr;
int *bufcount;
unsigned char *data;
int len;
{ {
int space = *bufcount - *bufix; struct data_string left, right;
int result;
/* If there's more space than we need, use only what we need. */ switch (expr -> op) {
if (space > len) case expr_check:
space = len; return check_collection (packet, expr -> data.check);
/* Copy as much data as will fit, then increment the buffer index case expr_equal:
by the amount we actually had to copy, which could be more. */ left = evaluate_data_expression (packet,
if (space > 0) expr -> data.equal [0]);
memcpy (*bufp + *bufix, data, space); right = evaluate_data_expression (packet,
*bufix += len; 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;
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;
}
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;