mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-30 22:05:23 +00:00
Make option state support more general.
This commit is contained in:
423
common/options.c
423
common/options.c
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
static char copyright[] =
|
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 */
|
#endif /* not lint */
|
||||||
|
|
||||||
#define DHCP_OPTION_DATA
|
#define DHCP_OPTION_DATA
|
||||||
@@ -40,8 +40,11 @@ int parse_options (packet)
|
|||||||
int i;
|
int i;
|
||||||
struct option_cache *op = (struct option_cache *)0;
|
struct option_cache *op = (struct option_cache *)0;
|
||||||
|
|
||||||
/* Initially, zero all option pointers. */
|
/* Allocate a new option state. */
|
||||||
memset (&packet -> options, 0, sizeof (packet -> options));
|
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 we don't see the magic cookie, there's nothing to parse. */
|
||||||
if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
|
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
|
/* If we parsed a DHCP Option Overload option, parse more
|
||||||
options out of the buffer(s) containing them. */
|
options out of the buffer(s) containing them. */
|
||||||
if (packet -> options_valid &&
|
if (packet -> options_valid &&
|
||||||
(op = lookup_option (packet -> options.dhcp_hash,
|
(op = lookup_option (&dhcp_universe, packet -> options,
|
||||||
DHO_DHCP_OPTION_OVERLOAD))) {
|
DHO_DHCP_OPTION_OVERLOAD))) {
|
||||||
if (op -> data.data [0] & 1) {
|
if (op -> data.data [0] & 1) {
|
||||||
if (!parse_option_buffer
|
if (!parse_option_buffer
|
||||||
@@ -95,7 +98,7 @@ int parse_option_buffer (packet, buffer, length)
|
|||||||
struct buffer *bp = (struct buffer *)0;
|
struct buffer *bp = (struct buffer *)0;
|
||||||
|
|
||||||
if (!buffer_allocate (&bp, length, "parse_option_buffer")) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy (bp -> data, buffer, length);
|
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 the length is outrageous, the options are bad. */
|
||||||
if (offset + len + 2 > length) {
|
if (offset + len + 2 > length) {
|
||||||
log_error ("Option %s length %d overflows input buffer.",
|
log_error ("Client option %s (%d) larger than buffer.",
|
||||||
dhcp_options [code].name,
|
dhcp_options [code].name, len);
|
||||||
len);
|
|
||||||
buffer_dereference (&bp, "parse_option_buffer");
|
buffer_dereference (&bp, "parse_option_buffer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -126,7 +128,7 @@ int parse_option_buffer (packet, buffer, length)
|
|||||||
if (code == DHO_DHCP_AGENT_OPTIONS) {
|
if (code == DHO_DHCP_AGENT_OPTIONS) {
|
||||||
if (!parse_agent_information_option
|
if (!parse_agent_information_option
|
||||||
(packet, len, buffer + offset + 2)) {
|
(packet, len, buffer + offset + 2)) {
|
||||||
log_error ("malformed agent information option.");
|
log_error ("bad agent information option.");
|
||||||
buffer_dereference (&bp,
|
buffer_dereference (&bp,
|
||||||
"parse_option_buffer");
|
"parse_option_buffer");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -134,8 +136,8 @@ int parse_option_buffer (packet, buffer, length)
|
|||||||
} else {
|
} else {
|
||||||
if (!option_cache_allocate (&op,
|
if (!option_cache_allocate (&op,
|
||||||
"parse_option_buffer")) {
|
"parse_option_buffer")) {
|
||||||
log_error ("Can't allocate storage for option %s.",
|
log_error ("No memory for option %s.",
|
||||||
dhcp_options [code].name);
|
dhcp_options [code].name);
|
||||||
buffer_dereference (&bp,
|
buffer_dereference (&bp,
|
||||||
"parse_option_buffer");
|
"parse_option_buffer");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -161,7 +163,7 @@ int parse_option_buffer (packet, buffer, length)
|
|||||||
|
|
||||||
op -> option = &dhcp_options [code];
|
op -> option = &dhcp_options [code];
|
||||||
/* Now store the option. */
|
/* Now store the option. */
|
||||||
save_option (packet -> options.dhcp_hash, op);
|
save_option (&dhcp_universe, packet -> options, op);
|
||||||
|
|
||||||
/* And let go of our reference. */
|
/* And let go of our reference. */
|
||||||
option_cache_dereference (&op,
|
option_cache_dereference (&op,
|
||||||
@@ -196,7 +198,7 @@ int parse_agent_information_option (packet, len, data)
|
|||||||
dmalloc (op [1] + 1 + sizeof *t,
|
dmalloc (op [1] + 1 + sizeof *t,
|
||||||
"parse_agent_information_option");
|
"parse_agent_information_option");
|
||||||
if (!t)
|
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. */
|
/* Link it in at the tail of the list. */
|
||||||
t -> next = (struct option_tag *)0;
|
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.");
|
log_fatal ("can't allocate space for agent option structure.");
|
||||||
|
|
||||||
/* Find the tail of the list. */
|
/* 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; tail = &((*tail) -> next))
|
||||||
;
|
;
|
||||||
*tail = a;
|
*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
|
three seperate buffers if needed. This allows us to cons up a set
|
||||||
of vendor options using the same routine. */
|
of vendor options using the same routine. */
|
||||||
|
|
||||||
int cons_options (inpacket, outpacket, mms, options,
|
int cons_options (inpacket, outpacket,
|
||||||
agent_options, overload, terminate, bootpp, prl)
|
mms, options, overload, terminate, bootpp, prl)
|
||||||
struct packet *inpacket;
|
struct packet *inpacket;
|
||||||
struct dhcp_packet *outpacket;
|
struct dhcp_packet *outpacket;
|
||||||
int mms;
|
int mms;
|
||||||
struct option_state *options;
|
struct option_state *options;
|
||||||
struct agent_options *agent_options;
|
|
||||||
int overload; /* Overload flags that may be set. */
|
int overload; /* Overload flags that may be set. */
|
||||||
int terminate;
|
int terminate;
|
||||||
int bootpp;
|
int bootpp;
|
||||||
@@ -253,7 +255,7 @@ int cons_options (inpacket, outpacket, mms, options,
|
|||||||
int i;
|
int i;
|
||||||
struct option_cache *op;
|
struct option_cache *op;
|
||||||
struct data_string ds;
|
struct data_string ds;
|
||||||
pair pp;
|
pair pp, *hash;
|
||||||
|
|
||||||
memset (&ds, 0, sizeof ds);
|
memset (&ds, 0, sizeof ds);
|
||||||
|
|
||||||
@@ -262,10 +264,10 @@ int cons_options (inpacket, outpacket, mms, options,
|
|||||||
one in the packet. */
|
one in the packet. */
|
||||||
|
|
||||||
if (!mms && inpacket &&
|
if (!mms && inpacket &&
|
||||||
(op = lookup_option (inpacket -> options.dhcp_hash,
|
(op = lookup_option (&dhcp_universe, inpacket -> options,
|
||||||
DHO_DHCP_MAX_MESSAGE_SIZE))) {
|
DHO_DHCP_MAX_MESSAGE_SIZE))) {
|
||||||
evaluate_option_cache (&ds, inpacket,
|
evaluate_option_cache (&ds, inpacket,
|
||||||
&inpacket -> options, op);
|
inpacket -> options, op);
|
||||||
if (ds.len >= sizeof (u_int16_t))
|
if (ds.len >= sizeof (u_int16_t))
|
||||||
mms = getUShort (ds.data);
|
mms = getUShort (ds.data);
|
||||||
data_string_forget (&ds, "cons_options");
|
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,
|
/* Now just tack on the list of all the options we have,
|
||||||
and any duplicates will be eliminated. */
|
and any duplicates will be eliminated. */
|
||||||
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
for (i = 0; i < OPTION_HASH_SIZE; i++) {
|
||||||
for (pp = options -> dhcp_hash [i];
|
hash = options -> universes [dhcp_universe.index];
|
||||||
pp; pp = pp -> cdr) {
|
for (pp = hash [i]; pp; pp = pp -> cdr) {
|
||||||
op = (struct option_cache *)(pp -> car);
|
op = (struct option_cache *)(pp -> car);
|
||||||
if (priority_len < PRIORITY_COUNT)
|
if (priority_len < PRIORITY_COUNT)
|
||||||
priority_list [priority_len++] =
|
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 tack any agent options onto the end of the packet after
|
||||||
we've put it together. */
|
we've put it together. */
|
||||||
if (agent_options) {
|
if (options -> universe_count > agent_universe.index &&
|
||||||
|
options -> universes [agent_universe.index]) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
struct agent_options *a;
|
struct agent_options *a;
|
||||||
struct option_tag *o;
|
struct option_tag *o;
|
||||||
|
|
||||||
/* Cycle through the options, appending them to the
|
/* Cycle through the options, appending them to the
|
||||||
buffer. */
|
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 <=
|
if (agentix + a -> length + 3 + DHCP_FIXED_LEN <=
|
||||||
dhcp_max_agent_option_packet_length) {
|
dhcp_max_agent_option_packet_length) {
|
||||||
outpacket -> options [agentix++]
|
outpacket -> options [agentix++]
|
||||||
@@ -491,7 +496,7 @@ int store_options (buffer, buflen, options, priority_list, priority_len,
|
|||||||
int length;
|
int length;
|
||||||
|
|
||||||
/* If no data is available for this option, skip it. */
|
/* 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,7 +600,7 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
|
|||||||
/* Figure out the size of the data. */
|
/* Figure out the size of the data. */
|
||||||
for (i = 0; dhcp_options [code].format [i]; i++) {
|
for (i = 0; dhcp_options [code].format [i]; i++) {
|
||||||
if (!numhunk) {
|
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].name,
|
||||||
&(dhcp_options [code].format [i]));
|
&(dhcp_options [code].format [i]));
|
||||||
break;
|
break;
|
||||||
@@ -718,7 +723,8 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
|
|||||||
strcpy (op, *dp++ ? "true" : "false");
|
strcpy (op, *dp++ ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_error ("Unexpected format code %c", fmtbuf [j]);
|
log_error ("Unexpected format code %c",
|
||||||
|
fmtbuf [j]);
|
||||||
}
|
}
|
||||||
op += strlen (op);
|
op += strlen (op);
|
||||||
if (j + 1 < numelem && comma != ':')
|
if (j + 1 < numelem && comma != ':')
|
||||||
@@ -753,20 +759,21 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
|
|||||||
tp.haddr = hfrom;
|
tp.haddr = hfrom;
|
||||||
|
|
||||||
if (packet -> hlen > sizeof packet -> chaddr) {
|
if (packet -> hlen > sizeof packet -> chaddr) {
|
||||||
log_info ("Discarding packet with bogus hardware address length.");
|
log_info ("Discarding packet with bogus hlen.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!parse_options (&tp)) {
|
if (!parse_options (&tp)) {
|
||||||
option_state_dereference (&tp.options);
|
if (tp.options)
|
||||||
|
option_state_dereference (&tp.options, "do_packet");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tp.options_valid &&
|
if (tp.options_valid &&
|
||||||
(op = lookup_option (tp.options.dhcp_hash,
|
(op = lookup_option (&dhcp_universe, tp.options,
|
||||||
DHO_DHCP_MESSAGE_TYPE))) {
|
DHO_DHCP_MESSAGE_TYPE))) {
|
||||||
struct data_string dp;
|
struct data_string dp;
|
||||||
memset (&dp, 0, sizeof 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)
|
if (dp.len > 0)
|
||||||
tp.packet_type = dp.data [0];
|
tp.packet_type = dp.data [0];
|
||||||
else
|
else
|
||||||
@@ -779,46 +786,57 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
|
|||||||
else
|
else
|
||||||
bootp (&tp);
|
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 data_string *result;
|
||||||
|
struct universe *universe;
|
||||||
struct option_state *options;
|
struct option_state *options;
|
||||||
int code;
|
int code;
|
||||||
{
|
{
|
||||||
struct option_cache *oc;
|
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;
|
return 0;
|
||||||
if (!evaluate_option_cache (result, (struct packet *)0, options, oc))
|
if (!evaluate_option_cache (result, (struct packet *)0, options, oc))
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int agent_suboption_lookup (result, options, code)
|
int agent_option_get (result, universe, options, code)
|
||||||
struct data_string *result;
|
struct data_string *result;
|
||||||
|
struct universe *universe;
|
||||||
struct option_state *options;
|
struct option_state *options;
|
||||||
int code;
|
int code;
|
||||||
{
|
{
|
||||||
struct agent_options *ao;
|
struct agent_options *ao;
|
||||||
struct option_tag *t;
|
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. */
|
/* 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) {
|
if (ao) {
|
||||||
for (t = ao -> first; t; t = t -> next) {
|
for (t = ao -> first; t; t = t -> next) {
|
||||||
if (t -> data [0] == code) {
|
if (t -> data [0] == code) {
|
||||||
result -> len = t -> data [1];
|
result -> len = t -> data [1];
|
||||||
if (!buffer_allocate (&result -> buffer,
|
if (!(buffer_allocate
|
||||||
result -> len + 1,
|
(&result -> buffer, result -> len + 1,
|
||||||
"agent_suboption_lookup"
|
"agent_suboption_get"))) {
|
||||||
)) {
|
|
||||||
result -> len = 0;
|
result -> len = 0;
|
||||||
buffer_dereference
|
buffer_dereference
|
||||||
(&result -> buffer,
|
(&result -> buffer,
|
||||||
"agent_suboption_lookup");
|
"agent_suboption_get");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
result -> data = &result -> buffer -> data [0];
|
result -> data = &result -> buffer -> data [0];
|
||||||
@@ -833,34 +851,9 @@ int agent_suboption_lookup (result, options, code)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int server_option_lookup (result, options, code)
|
void hashed_option_set (universe, options, option, op)
|
||||||
struct data_string *result;
|
struct universe *universe;
|
||||||
struct option_state *options;
|
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;
|
struct option_cache *option;
|
||||||
enum statement_op op;
|
enum statement_op op;
|
||||||
{
|
{
|
||||||
@@ -876,22 +869,24 @@ static void do_option_set (hash, option, op)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case default_option_statement:
|
case default_option_statement:
|
||||||
oc = lookup_option (hash, option -> option -> code);
|
oc = lookup_option (universe, options,
|
||||||
|
option -> option -> code);
|
||||||
if (oc)
|
if (oc)
|
||||||
break;
|
break;
|
||||||
save_option (hash, option);
|
save_option (universe, options, option);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case supersede_option_statement:
|
case supersede_option_statement:
|
||||||
/* Install the option, replacing any existing version. */
|
/* Install the option, replacing any existing version. */
|
||||||
save_option (hash, option);
|
save_option (universe, options, option);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case append_option_statement:
|
case append_option_statement:
|
||||||
case prepend_option_statement:
|
case prepend_option_statement:
|
||||||
oc = lookup_option (hash, option -> option -> code);
|
oc = lookup_option (universe, options,
|
||||||
|
option -> option -> code);
|
||||||
if (!oc) {
|
if (!oc) {
|
||||||
save_option (hash, option);
|
save_option (universe, options, option);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* If it's not an expression, make it into one. */
|
/* 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;
|
noc -> option = oc -> option;
|
||||||
save_option (hash, noc);
|
save_option (universe, options, noc);
|
||||||
option_cache_dereference (&noc, "do_option_set");
|
option_cache_dereference (&noc, "do_option_set");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct option_cache *lookup_option (hash, code)
|
struct option_cache *lookup_option (universe, options, code)
|
||||||
pair *hash;
|
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 code;
|
||||||
{
|
{
|
||||||
int hashix;
|
int hashix;
|
||||||
pair bptr;
|
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;
|
hashix = ((code & 31) + ((code >> 5) & 31)) % 17;
|
||||||
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
|
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
|
||||||
@@ -950,49 +967,101 @@ struct option_cache *lookup_option (hash, code)
|
|||||||
return (struct option_cache *)0;
|
return (struct option_cache *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_option (hash, oc)
|
void save_option (universe, options, oc)
|
||||||
pair *hash;
|
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;
|
struct option_cache *oc;
|
||||||
{
|
{
|
||||||
int hashix;
|
int hashix;
|
||||||
pair bptr;
|
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) +
|
hashix = ((oc -> option -> code & 31) +
|
||||||
((oc -> option -> code >> 5) & 31)) % 17;
|
((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 there's no hash table, make one. */
|
||||||
if (bptr) {
|
if (!hash) {
|
||||||
option_cache_dereference ((struct option_cache **)&bptr -> car,
|
hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash,
|
||||||
"save_option");
|
"save_hashed_options");
|
||||||
option_cache_reference ((struct option_cache **)&bptr -> car,
|
if (!hash) {
|
||||||
oc, "save_option");
|
log_error ("no memory to store %s.%s",
|
||||||
} else {
|
universe -> name, oc -> option -> name);
|
||||||
/* Otherwise, just put the new one at the head of the list. */
|
return;
|
||||||
bptr = new_pair ("save_option");
|
}
|
||||||
if (!bptr) {
|
memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
|
||||||
log_error ("No memory for option_cache reference.");
|
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;
|
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)
|
void delete_option (universe, options, code)
|
||||||
pair *hash;
|
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 code;
|
||||||
{
|
{
|
||||||
int hashix;
|
int hashix;
|
||||||
pair bptr, prev = (pair)0;
|
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. */
|
/* Try to find an existing option matching the new one. */
|
||||||
hashix = ((code & 31) +
|
hashix = ((code & 31) +
|
||||||
@@ -1023,7 +1092,8 @@ int option_cache_dereference (ptr, name)
|
|||||||
char *name;
|
char *name;
|
||||||
{
|
{
|
||||||
if (!ptr || !*ptr) {
|
if (!ptr || !*ptr) {
|
||||||
log_error ("Null pointer in option_cache_dereference: %s", name);
|
log_error ("Null pointer in option_cache_dereference: %s",
|
||||||
|
name);
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,3 +1111,150 @@ int option_cache_dereference (ptr, name)
|
|||||||
return 1;
|
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;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user