mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-29 21:38:10 +00:00
Make option state support more general.
This commit is contained in:
parent
0d252fd9bf
commit
c9605ddb0b
423
common/options.c
423
common/options.c
@ -22,7 +22,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: options.c,v 1.37 1999/03/16 05:50:35 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
|
||||
"$Id: options.c,v 1.38 1999/04/05 15:40:59 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#define DHCP_OPTION_DATA
|
||||
@ -40,8 +40,11 @@ int parse_options (packet)
|
||||
int i;
|
||||
struct option_cache *op = (struct option_cache *)0;
|
||||
|
||||
/* Initially, zero all option pointers. */
|
||||
memset (&packet -> options, 0, sizeof (packet -> options));
|
||||
/* Allocate a new option state. */
|
||||
if (!option_state_allocate (&packet -> options, "parse_options")) {
|
||||
packet -> options_valid = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we don't see the magic cookie, there's nothing to parse. */
|
||||
if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
|
||||
@ -59,7 +62,7 @@ int parse_options (packet)
|
||||
/* If we parsed a DHCP Option Overload option, parse more
|
||||
options out of the buffer(s) containing them. */
|
||||
if (packet -> options_valid &&
|
||||
(op = lookup_option (packet -> options.dhcp_hash,
|
||||
(op = lookup_option (&dhcp_universe, packet -> options,
|
||||
DHO_DHCP_OPTION_OVERLOAD))) {
|
||||
if (op -> data.data [0] & 1) {
|
||||
if (!parse_option_buffer
|
||||
@ -95,7 +98,7 @@ int parse_option_buffer (packet, buffer, length)
|
||||
struct buffer *bp = (struct buffer *)0;
|
||||
|
||||
if (!buffer_allocate (&bp, length, "parse_option_buffer")) {
|
||||
log_error ("parse_option_buffer: no memory for option buffer.");
|
||||
log_error ("no memory for option buffer.");
|
||||
return 0;
|
||||
}
|
||||
memcpy (bp -> data, buffer, length);
|
||||
@ -114,9 +117,8 @@ int parse_option_buffer (packet, buffer, length)
|
||||
|
||||
/* If the length is outrageous, the options are bad. */
|
||||
if (offset + len + 2 > length) {
|
||||
log_error ("Option %s length %d overflows input buffer.",
|
||||
dhcp_options [code].name,
|
||||
len);
|
||||
log_error ("Client option %s (%d) larger than buffer.",
|
||||
dhcp_options [code].name, len);
|
||||
buffer_dereference (&bp, "parse_option_buffer");
|
||||
return 0;
|
||||
}
|
||||
@ -126,7 +128,7 @@ int parse_option_buffer (packet, buffer, length)
|
||||
if (code == DHO_DHCP_AGENT_OPTIONS) {
|
||||
if (!parse_agent_information_option
|
||||
(packet, len, buffer + offset + 2)) {
|
||||
log_error ("malformed agent information option.");
|
||||
log_error ("bad agent information option.");
|
||||
buffer_dereference (&bp,
|
||||
"parse_option_buffer");
|
||||
return 0;
|
||||
@ -134,8 +136,8 @@ int parse_option_buffer (packet, buffer, length)
|
||||
} else {
|
||||
if (!option_cache_allocate (&op,
|
||||
"parse_option_buffer")) {
|
||||
log_error ("Can't allocate storage for option %s.",
|
||||
dhcp_options [code].name);
|
||||
log_error ("No memory for option %s.",
|
||||
dhcp_options [code].name);
|
||||
buffer_dereference (&bp,
|
||||
"parse_option_buffer");
|
||||
return 0;
|
||||
@ -161,7 +163,7 @@ int parse_option_buffer (packet, buffer, length)
|
||||
|
||||
op -> option = &dhcp_options [code];
|
||||
/* Now store the option. */
|
||||
save_option (packet -> options.dhcp_hash, op);
|
||||
save_option (&dhcp_universe, packet -> options, op);
|
||||
|
||||
/* And let go of our reference. */
|
||||
option_cache_dereference (&op,
|
||||
@ -196,7 +198,7 @@ int parse_agent_information_option (packet, len, data)
|
||||
dmalloc (op [1] + 1 + sizeof *t,
|
||||
"parse_agent_information_option");
|
||||
if (!t)
|
||||
log_fatal ("can't allocate space for option tag data.");
|
||||
log_fatal ("no memory for option tag data.");
|
||||
|
||||
/* Link it in at the tail of the list. */
|
||||
t -> next = (struct option_tag *)0;
|
||||
@ -215,7 +217,8 @@ int parse_agent_information_option (packet, len, data)
|
||||
log_fatal ("can't allocate space for agent option structure.");
|
||||
|
||||
/* Find the tail of the list. */
|
||||
for (tail = &packet -> options.agent_options;
|
||||
for (tail = ((struct agent_options **)
|
||||
&packet -> options -> universes [agent_universe.index]);
|
||||
*tail; tail = &((*tail) -> next))
|
||||
;
|
||||
*tail = a;
|
||||
@ -230,13 +233,12 @@ int parse_agent_information_option (packet, len, data)
|
||||
three seperate buffers if needed. This allows us to cons up a set
|
||||
of vendor options using the same routine. */
|
||||
|
||||
int cons_options (inpacket, outpacket, mms, options,
|
||||
agent_options, overload, terminate, bootpp, prl)
|
||||
int cons_options (inpacket, outpacket,
|
||||
mms, options, overload, terminate, bootpp, prl)
|
||||
struct packet *inpacket;
|
||||
struct dhcp_packet *outpacket;
|
||||
int mms;
|
||||
struct option_state *options;
|
||||
struct agent_options *agent_options;
|
||||
int overload; /* Overload flags that may be set. */
|
||||
int terminate;
|
||||
int bootpp;
|
||||
@ -253,7 +255,7 @@ int cons_options (inpacket, outpacket, mms, options,
|
||||
int i;
|
||||
struct option_cache *op;
|
||||
struct data_string ds;
|
||||
pair pp;
|
||||
pair pp, *hash;
|
||||
|
||||
memset (&ds, 0, sizeof ds);
|
||||
|
||||
@ -262,10 +264,10 @@ int cons_options (inpacket, outpacket, mms, options,
|
||||
one in the packet. */
|
||||
|
||||
if (!mms && inpacket &&
|
||||
(op = lookup_option (inpacket -> options.dhcp_hash,
|
||||
(op = lookup_option (&dhcp_universe, inpacket -> options,
|
||||
DHO_DHCP_MAX_MESSAGE_SIZE))) {
|
||||
evaluate_option_cache (&ds, inpacket,
|
||||
&inpacket -> options, op);
|
||||
inpacket -> options, op);
|
||||
if (ds.len >= sizeof (u_int16_t))
|
||||
mms = getUShort (ds.data);
|
||||
data_string_forget (&ds, "cons_options");
|
||||
@ -322,8 +324,8 @@ int cons_options (inpacket, outpacket, mms, options,
|
||||
/* Now just tack on the list of all the options we have,
|
||||
and any duplicates will be eliminated. */
|
||||
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
||||
for (pp = options -> dhcp_hash [i];
|
||||
pp; pp = pp -> cdr) {
|
||||
hash = options -> universes [dhcp_universe.index];
|
||||
for (pp = hash [i]; pp; pp = pp -> cdr) {
|
||||
op = (struct option_cache *)(pp -> car);
|
||||
if (priority_len < PRIORITY_COUNT)
|
||||
priority_list [priority_len++] =
|
||||
@ -409,14 +411,17 @@ int cons_options (inpacket, outpacket, mms, options,
|
||||
|
||||
/* We tack any agent options onto the end of the packet after
|
||||
we've put it together. */
|
||||
if (agent_options) {
|
||||
if (options -> universe_count > agent_universe.index &&
|
||||
options -> universes [agent_universe.index]) {
|
||||
int len = 0;
|
||||
struct agent_options *a;
|
||||
struct option_tag *o;
|
||||
|
||||
/* Cycle through the options, appending them to the
|
||||
buffer. */
|
||||
for (a = options -> agent_options; a; a = a -> next) {
|
||||
for (a = ((struct agent_options *)
|
||||
options -> universes [agent_universe.index]);
|
||||
a; a = a -> next) {
|
||||
if (agentix + a -> length + 3 + DHCP_FIXED_LEN <=
|
||||
dhcp_max_agent_option_packet_length) {
|
||||
outpacket -> options [agentix++]
|
||||
@ -491,7 +496,7 @@ int store_options (buffer, buflen, options, priority_list, priority_len,
|
||||
int length;
|
||||
|
||||
/* If no data is available for this option, skip it. */
|
||||
if (!(oc = lookup_option (options -> dhcp_hash, code))) {
|
||||
if (!(oc = lookup_option (&dhcp_universe, options, code))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -595,7 +600,7 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
|
||||
/* Figure out the size of the data. */
|
||||
for (i = 0; dhcp_options [code].format [i]; i++) {
|
||||
if (!numhunk) {
|
||||
log_error ("%s: Excess information in format string: %s\n",
|
||||
log_error ("%s: Extra codes in format string: %s\n",
|
||||
dhcp_options [code].name,
|
||||
&(dhcp_options [code].format [i]));
|
||||
break;
|
||||
@ -718,7 +723,8 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
|
||||
strcpy (op, *dp++ ? "true" : "false");
|
||||
break;
|
||||
default:
|
||||
log_error ("Unexpected format code %c", fmtbuf [j]);
|
||||
log_error ("Unexpected format code %c",
|
||||
fmtbuf [j]);
|
||||
}
|
||||
op += strlen (op);
|
||||
if (j + 1 < numelem && comma != ':')
|
||||
@ -753,20 +759,21 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
|
||||
tp.haddr = hfrom;
|
||||
|
||||
if (packet -> hlen > sizeof packet -> chaddr) {
|
||||
log_info ("Discarding packet with bogus hardware address length.");
|
||||
log_info ("Discarding packet with bogus hlen.");
|
||||
return;
|
||||
}
|
||||
if (!parse_options (&tp)) {
|
||||
option_state_dereference (&tp.options);
|
||||
if (tp.options)
|
||||
option_state_dereference (&tp.options, "do_packet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tp.options_valid &&
|
||||
(op = lookup_option (tp.options.dhcp_hash,
|
||||
(op = lookup_option (&dhcp_universe, tp.options,
|
||||
DHO_DHCP_MESSAGE_TYPE))) {
|
||||
struct data_string dp;
|
||||
memset (&dp, 0, sizeof dp);
|
||||
evaluate_option_cache (&dp, &tp, &tp.options, op);
|
||||
evaluate_option_cache (&dp, &tp, tp.options, op);
|
||||
if (dp.len > 0)
|
||||
tp.packet_type = dp.data [0];
|
||||
else
|
||||
@ -779,46 +786,57 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
|
||||
else
|
||||
bootp (&tp);
|
||||
|
||||
option_state_dereference (&tp.options);
|
||||
option_state_dereference (&tp.options, "do_packet");
|
||||
}
|
||||
|
||||
int dhcp_option_lookup (result, options, code)
|
||||
int hashed_option_get (result, universe, options, code)
|
||||
struct data_string *result;
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
struct option_cache *oc;
|
||||
|
||||
if (!(oc = lookup_option (options -> dhcp_hash, code)))
|
||||
if (!universe -> lookup_func)
|
||||
return 0;
|
||||
oc = ((*universe -> lookup_func)
|
||||
(universe, options -> universes [universe -> index], code));
|
||||
if (!oc)
|
||||
return 0;
|
||||
if (!evaluate_option_cache (result, (struct packet *)0, options, oc))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int agent_suboption_lookup (result, options, code)
|
||||
int agent_option_get (result, universe, options, code)
|
||||
struct data_string *result;
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
struct agent_options *ao;
|
||||
struct option_tag *t;
|
||||
|
||||
/* Make sure there's agent option state. */
|
||||
if (universe -> index >= options -> universe_count ||
|
||||
!(options -> universes [universe -> index]))
|
||||
return 0;
|
||||
ao = (struct agent_options *)options -> universes [universe -> index];
|
||||
|
||||
/* Find the last set of agent options and consider it definitive. */
|
||||
for (ao = options -> agent_options; ao -> next; ao = ao -> next)
|
||||
for (; ao -> next; ao = ao -> next)
|
||||
;
|
||||
if (ao) {
|
||||
for (t = ao -> first; t; t = t -> next) {
|
||||
if (t -> data [0] == code) {
|
||||
result -> len = t -> data [1];
|
||||
if (!buffer_allocate (&result -> buffer,
|
||||
result -> len + 1,
|
||||
"agent_suboption_lookup"
|
||||
)) {
|
||||
if (!(buffer_allocate
|
||||
(&result -> buffer, result -> len + 1,
|
||||
"agent_suboption_get"))) {
|
||||
result -> len = 0;
|
||||
buffer_dereference
|
||||
(&result -> buffer,
|
||||
"agent_suboption_lookup");
|
||||
"agent_suboption_get");
|
||||
return 0;
|
||||
}
|
||||
result -> data = &result -> buffer -> data [0];
|
||||
@ -833,34 +851,9 @@ int agent_suboption_lookup (result, options, code)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int server_option_lookup (result, options, code)
|
||||
struct data_string *result;
|
||||
void hashed_option_set (universe, options, option, op)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dhcp_option_set (options, option, op)
|
||||
struct option_state *options;
|
||||
struct option_cache *option;
|
||||
enum statement_op op;
|
||||
{
|
||||
struct option_cache *thecache;
|
||||
|
||||
do_option_set (options -> dhcp_hash, option, op);
|
||||
}
|
||||
|
||||
void server_option_set (options, option, op)
|
||||
struct option_state *options;
|
||||
struct option_cache *option;
|
||||
enum statement_op op;
|
||||
{
|
||||
do_option_set (options -> server_hash, option, op);
|
||||
}
|
||||
|
||||
static void do_option_set (hash, option, op)
|
||||
pair *hash;
|
||||
struct option_cache *option;
|
||||
enum statement_op op;
|
||||
{
|
||||
@ -876,22 +869,24 @@ static void do_option_set (hash, option, op)
|
||||
break;
|
||||
|
||||
case default_option_statement:
|
||||
oc = lookup_option (hash, option -> option -> code);
|
||||
oc = lookup_option (universe, options,
|
||||
option -> option -> code);
|
||||
if (oc)
|
||||
break;
|
||||
save_option (hash, option);
|
||||
save_option (universe, options, option);
|
||||
break;
|
||||
|
||||
case supersede_option_statement:
|
||||
/* Install the option, replacing any existing version. */
|
||||
save_option (hash, option);
|
||||
save_option (universe, options, option);
|
||||
break;
|
||||
|
||||
case append_option_statement:
|
||||
case prepend_option_statement:
|
||||
oc = lookup_option (hash, option -> option -> code);
|
||||
oc = lookup_option (universe, options,
|
||||
option -> option -> code);
|
||||
if (!oc) {
|
||||
save_option (hash, option);
|
||||
save_option (universe, options, option);
|
||||
break;
|
||||
}
|
||||
/* If it's not an expression, make it into one. */
|
||||
@ -928,18 +923,40 @@ static void do_option_set (hash, option, op)
|
||||
}
|
||||
}
|
||||
noc -> option = oc -> option;
|
||||
save_option (hash, noc);
|
||||
save_option (universe, options, noc);
|
||||
option_cache_dereference (&noc, "do_option_set");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct option_cache *lookup_option (hash, code)
|
||||
pair *hash;
|
||||
struct option_cache *lookup_option (universe, options, code)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
if (universe -> lookup_func)
|
||||
return (*universe -> lookup_func) (universe, options, code);
|
||||
else
|
||||
log_error ("can't look up options in %s space.",
|
||||
universe -> name);
|
||||
return (struct option_cache *)0;
|
||||
}
|
||||
|
||||
struct option_cache *lookup_hashed_option (universe, options, code)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
int hashix;
|
||||
pair bptr;
|
||||
pair *hash;
|
||||
|
||||
/* Make sure there's a hash table. */
|
||||
if (universe -> index >= options -> universe_count ||
|
||||
!(options -> universes [universe -> index]))
|
||||
return (struct option_cache *)0;
|
||||
|
||||
hash = options -> universes [universe -> index];
|
||||
|
||||
hashix = ((code & 31) + ((code >> 5) & 31)) % 17;
|
||||
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
|
||||
@ -950,49 +967,101 @@ struct option_cache *lookup_option (hash, code)
|
||||
return (struct option_cache *)0;
|
||||
}
|
||||
|
||||
void save_option (hash, oc)
|
||||
pair *hash;
|
||||
void save_option (universe, options, oc)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
struct option_cache *oc;
|
||||
{
|
||||
if (universe -> save_func)
|
||||
(*universe -> save_func) (universe, options, oc);
|
||||
else
|
||||
log_error ("can't store options in %s space.",
|
||||
universe -> name);
|
||||
}
|
||||
|
||||
void save_hashed_option (universe, options, oc)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
struct option_cache *oc;
|
||||
{
|
||||
int hashix;
|
||||
pair bptr;
|
||||
pair *hash = options -> universes [universe -> index];
|
||||
|
||||
/* Try to find an existing option matching the new one. */
|
||||
/* Compute the hash. */
|
||||
hashix = ((oc -> option -> code & 31) +
|
||||
((oc -> option -> code >> 5) & 31)) % 17;
|
||||
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
|
||||
if (((struct option_cache *)(bptr -> car)) -> option -> code ==
|
||||
oc -> option -> code)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we find one, dereference it and put the new one in its place. */
|
||||
if (bptr) {
|
||||
option_cache_dereference ((struct option_cache **)&bptr -> car,
|
||||
"save_option");
|
||||
option_cache_reference ((struct option_cache **)&bptr -> car,
|
||||
oc, "save_option");
|
||||
} else {
|
||||
/* Otherwise, just put the new one at the head of the list. */
|
||||
bptr = new_pair ("save_option");
|
||||
if (!bptr) {
|
||||
log_error ("No memory for option_cache reference.");
|
||||
/* If there's no hash table, make one. */
|
||||
if (!hash) {
|
||||
hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash,
|
||||
"save_hashed_options");
|
||||
if (!hash) {
|
||||
log_error ("no memory to store %s.%s",
|
||||
universe -> name, oc -> option -> name);
|
||||
return;
|
||||
}
|
||||
memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
|
||||
options -> universes [universe -> index] = (VOIDPTR)hash;
|
||||
} else {
|
||||
/* Try to find an existing option matching the new one. */
|
||||
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
|
||||
if (((struct option_cache *)
|
||||
(bptr -> car)) -> option -> code ==
|
||||
oc -> option -> code)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we find one, dereference it and put the new one
|
||||
in its place. */
|
||||
if (bptr) {
|
||||
option_cache_dereference
|
||||
((struct option_cache **)&bptr -> car,
|
||||
"save_option");
|
||||
option_cache_reference
|
||||
((struct option_cache **)&bptr -> car,
|
||||
oc, "save_option");
|
||||
return;
|
||||
}
|
||||
bptr -> cdr = hash [hashix];
|
||||
bptr -> car = 0;
|
||||
option_cache_reference ((struct option_cache **)&bptr -> car,
|
||||
oc, "save_option");
|
||||
hash [hashix] = bptr;
|
||||
}
|
||||
|
||||
/* Otherwise, just put the new one at the head of the list. */
|
||||
bptr = new_pair ("save_option");
|
||||
if (!bptr) {
|
||||
log_error ("No memory for option_cache reference.");
|
||||
return;
|
||||
}
|
||||
bptr -> cdr = hash [hashix];
|
||||
bptr -> car = 0;
|
||||
option_cache_reference ((struct option_cache **)&bptr -> car,
|
||||
oc, "save_option");
|
||||
hash [hashix] = bptr;
|
||||
}
|
||||
|
||||
void delete_option (hash, code)
|
||||
pair *hash;
|
||||
void delete_option (universe, options, code)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
if (universe -> delete_func)
|
||||
(*universe -> delete_func) (universe, options, code);
|
||||
else
|
||||
log_error ("can't delete options from %s space.",
|
||||
universe -> name);
|
||||
}
|
||||
|
||||
void delete_hashed_option (universe, options, code)
|
||||
struct universe *universe;
|
||||
struct option_state *options;
|
||||
int code;
|
||||
{
|
||||
int hashix;
|
||||
pair bptr, prev = (pair)0;
|
||||
pair *hash = options -> universes [universe -> index];
|
||||
|
||||
/* There may not be any options in this space. */
|
||||
if (!hash)
|
||||
return;
|
||||
|
||||
/* Try to find an existing option matching the new one. */
|
||||
hashix = ((code & 31) +
|
||||
@ -1023,7 +1092,8 @@ int option_cache_dereference (ptr, name)
|
||||
char *name;
|
||||
{
|
||||
if (!ptr || !*ptr) {
|
||||
log_error ("Null pointer in option_cache_dereference: %s", name);
|
||||
log_error ("Null pointer in option_cache_dereference: %s",
|
||||
name);
|
||||
abort ();
|
||||
}
|
||||
|
||||
@ -1041,3 +1111,150 @@ int option_cache_dereference (ptr, name)
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int hashed_option_state_dereference (universe, state)
|
||||
struct universe *universe;
|
||||
struct option_state *state;
|
||||
{
|
||||
pair *heads;
|
||||
pair cp, next;
|
||||
int i;
|
||||
|
||||
/* Get the pointer to the array of hash table bucket heads. */
|
||||
heads = (pair *)(state -> universes [universe -> index]);
|
||||
if (!heads)
|
||||
return 0;
|
||||
|
||||
/* For each non-null head, loop through all the buckets dereferencing
|
||||
the attached option cache structures and freeing the buckets. */
|
||||
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
||||
for (cp = heads [i]; cp; cp = next) {
|
||||
next = cp -> cdr;
|
||||
option_cache_dereference
|
||||
((struct option_cache **)&cp -> car,
|
||||
"option_state_dereference");
|
||||
free_pair (cp, "hashed_option_state_dereference");
|
||||
}
|
||||
}
|
||||
|
||||
dfree (heads, "hashed_option_state_dereference");
|
||||
state -> universes [universe -> index] = (void *)0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int agent_option_state_dereference (universe, state)
|
||||
struct universe *universe;
|
||||
struct option_state *state;
|
||||
{
|
||||
struct agent_options *a, *na;
|
||||
struct option_tag *ot, *not;
|
||||
|
||||
if (universe -> index >= state -> universe_count ||
|
||||
!state -> universes [universe -> index])
|
||||
return 0;
|
||||
|
||||
/* We can also release the agent options, if any... */
|
||||
for (a = (struct agent_options *)(state -> universes
|
||||
[universe -> index]); a; a = na) {
|
||||
na = a -> next;
|
||||
for (ot = a -> first; ot; ot = not) {
|
||||
not = ot -> next;
|
||||
free (ot);
|
||||
}
|
||||
}
|
||||
|
||||
dfree (state -> universes [universe -> index],
|
||||
"agent_option_state_dereference");
|
||||
state -> universes [universe -> index] = (void *)0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int store_option (result, universe, oc)
|
||||
struct data_string *result;
|
||||
struct universe *universe;
|
||||
struct option_cache *oc;
|
||||
{
|
||||
struct data_string d1, d2;
|
||||
|
||||
memset (&d1, 0, sizeof d1);
|
||||
memset (&d2, 0, sizeof d2);
|
||||
|
||||
if (evaluate_option_cache (&d2, (struct packet *)0,
|
||||
(struct option_state *)0, oc)) {
|
||||
if (!buffer_allocate (&d1.buffer,
|
||||
(result -> len +
|
||||
universe -> length_size +
|
||||
universe -> tag_size +
|
||||
d2.len), "store_option")) {
|
||||
data_string_forget (result, "store_option");
|
||||
data_string_forget (&d2, "store_option");
|
||||
return 0;
|
||||
}
|
||||
d1.data = &d1.buffer -> data [0];
|
||||
if (result -> len)
|
||||
memcpy (d1.data, result -> data, result -> len);
|
||||
d1.len = result -> len;
|
||||
(*universe -> store_tag) (&d1.data [d1.len],
|
||||
oc -> option -> code);
|
||||
d1.len += universe -> tag_size;
|
||||
(*universe -> store_length) (&d1.data [d1.len], d2.len);
|
||||
d1.len += universe -> length_size;
|
||||
memcpy (&d1.data [d1.len], d2.data, d2.len);
|
||||
d1.len += d2.len;
|
||||
data_string_forget (&d2, "store_option");
|
||||
data_string_forget (result, "store_option");
|
||||
data_string_copy (result, &d1, "store_option");
|
||||
data_string_forget (&d1, "store_option");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int option_space_encapsulate (result, options, name)
|
||||
struct data_string *result;
|
||||
struct option_state *options;
|
||||
struct data_string *name;
|
||||
{
|
||||
struct universe *u;
|
||||
|
||||
u = (struct universe *)hash_lookup (&universe_hash,
|
||||
name -> data, name -> len);
|
||||
if (!u) {
|
||||
log_error ("unknown option space %s.", name -> data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (u -> encapsulate)
|
||||
return (*u -> encapsulate) (result, options, u);
|
||||
log_error ("encapsulation requested for %s with no support.",
|
||||
name -> data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hashed_option_space_encapsulate (result, options, universe)
|
||||
struct data_string *result;
|
||||
struct option_state *options;
|
||||
struct universe *universe;
|
||||
{
|
||||
pair p, *hash;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
if (universe -> index >= options -> universe_count)
|
||||
return 0;
|
||||
|
||||
hash = options -> universes [universe -> index];
|
||||
if (!hash)
|
||||
return 0;
|
||||
|
||||
status = 0;
|
||||
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
||||
for (p = hash [i]; p; p = p -> cdr) {
|
||||
if (store_option (result, universe,
|
||||
(struct option_cache *)p -> car))
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user