#ifndef lint
static char copyright[] =
-"$Id: clparse.c,v 1.17 1998/10/22 04:52:23 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
+"$Id: clparse.c,v 1.18 1998/11/05 18:38:43 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
struct client_config top_level_config;
+u_int32_t default_requested_options [] = {
+ DHO_SUBNET_MASK,
+ DHO_BROADCAST_ADDRESS,
+ DHO_TIME_OFFSET,
+ DHO_ROUTERS,
+ DHO_DOMAIN_NAME,
+ DHO_DOMAIN_NAME_SERVERS,
+ DHO_HOST_NAME,
+ 0
+};
+
/* client-conf-file :== client-declarations EOF
client-declarations :== <nil>
| client-declaration
top_level_config.initial_interval = 10;
top_level_config.bootp_policy = ACCEPT;
top_level_config.script_name = "/etc/dhclient-script";
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_SUBNET_MASK;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_BROADCAST_ADDRESS;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_TIME_OFFSET;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_ROUTERS;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_DOMAIN_NAME;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_DOMAIN_NAME_SERVERS;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_HOST_NAME;
- top_level_config.requested_lease_time = 7200;
- top_level_config.send_options.dhcp_options [DHO_DHCP_LEASE_TIME].data
- = (unsigned char *)&top_level_config.requested_lease_time;
- top_level_config.send_options.dhcp_options [DHO_DHCP_LEASE_TIME].len
- = sizeof top_level_config.requested_lease_time;
+ top_level_config.requested_options = default_requested_options;
+ top_level_config.requested_lease = 7200;
if ((cfile = fopen (path_dhclient_conf, "r")) != NULL) {
do {
error ("no memory for client config.");
memcpy (config, &top_level_config,
sizeof top_level_config);
- i = DHO_DHCP_LEASE_TIME;
- config -> send_options.dhcp_options [i].data =
- (unsigned char *)&config -> requested_lease_time;
- top_level_config.send_options.dhcp_options [DHO_DHCP_LEASE_TIME].len
- = sizeof top_level_config.requested_lease_time;
-
}
ip -> client -> config = config;
}
char *val;
struct option *option;
struct executable_statement *stmt, **p;
- enum statement op op;
+ enum statement_op op;
switch (next_token (&val, cfile)) {
case SEND:
- p = &config -> on_tranmission;
+ p = &config -> on_transmission;
op = send_option_statement;
do_option:
token = next_token (&val, cfile);
option = parse_option_name (cfile);
- if (!option) {
- *lose = 1;
- return (struct executable_statement *)0;
- }
+ if (!option)
+ return;
stmt = parse_option_statement (cfile, 1, option,
send_option_statement);
for (; *p; p = &((*p) -> next))
return;
case REQUEST:
- config -> requested_option_count =
- parse_option_list (cfile, config -> requested_options);
+ parse_option_list (cfile, &config -> requested_options);
return;
case REQUIRE:
- memset (config -> required_options, 0,
- sizeof config -> required_options);
- parse_option_list (cfile, config -> required_options);
+ parse_option_list (cfile, &config -> required_options);
return;
case TIMEOUT:
/* option-list :== option_name |
option_list COMMA option_name */
-int parse_option_list (cfile, list)
+void parse_option_list (cfile, list)
FILE *cfile;
- u_int8_t *list;
+ u_int32_t **list;
{
int ix, i;
int token;
char *val;
+ pair p = (pair)0, q, r;
ix = 0;
do {
if (!is_identifier (token)) {
parse_warn ("expected option name.");
skip_to_semi (cfile);
- return 0;
+ return;
}
for (i = 0; i < 256; i++) {
if (!strcasecmp (dhcp_options [i].name, val))
if (i == 256) {
parse_warn ("%s: expected option name.");
skip_to_semi (cfile);
- return 0;
- }
- list [ix++] = i;
- if (ix == 256) {
- parse_warn ("%s: too many options.", val);
- skip_to_semi (cfile);
- return 0;
+ return;
}
+ r = new_pair ("parse_option_list");
+ if (!r)
+ error ("can't allocate pair for option code.");
+ r -> car = (caddr_t)i;
+ r -> cdr = (pair)0;
+ if (p)
+ q -> cdr = r;
+ else
+ p = r;
+ q = r;
+ ++ix;
token = next_token (&val, cfile);
} while (token == COMMA);
if (token != SEMI) {
parse_warn ("expecting semicolon.");
skip_to_semi (cfile);
- return 0;
+ return;
+ }
+ if (*list)
+ dfree (*list, "parse_option_list");
+ *list = dmalloc (ix * sizeof **list, "parse_option_list");
+ if (!*list)
+ warn ("no memory for option list.");
+ else {
+ ix = 0;
+ for (q = p; q; q = q -> cdr)
+ (*list) [ix++] = (u_int32_t)q -> car;
+ (*list) [ix] = 0;
+ }
+ while (p) {
+ q = p -> cdr;
+ free_pair (p, "parse_option_list");
+ p = q;
}
- return ix;
}
/* interface-declaration :==
/* If the lease declaration didn't include an interface
declaration that we recognized, it's of no use to us. */
if (!ip) {
- free_client_lease (lease);
+ destroy_client_lease (lease);
return;
}
pl -> next = lp -> next;
else
ip -> client -> leases = lp -> next;
- free_client_lease (lp);
+ destroy_client_lease (lp);
break;
}
}
still valid but no longer active. */
if (ip -> client -> active) {
if (ip -> client -> active -> expiry < cur_time)
- free_client_lease (ip -> client -> active);
+ destroy_client_lease (ip -> client -> active);
else if (ip -> client -> active -> address.len ==
lease -> address.len &&
!memcmp (ip -> client -> active -> address.iabuf,
lease -> address.iabuf,
lease -> address.len))
- free_client_lease (ip -> client -> active);
+ destroy_client_lease (ip -> client -> active);
else {
ip -> client -> active -> next =
ip -> client -> leases;
char *val;
char *t, *n;
struct interface_info *ip;
+ struct option_cache *oc;
switch (next_token (&val, cfile)) {
case BOOTP:
return;
case OPTION:
- parse_option_decl (cfile, lease -> options);
+ oc = (struct option_cache *)0;
+ if (parse_option_decl (&oc, cfile)) {
+ /* XXX save_option here ought to account for the
+ XXX correct option universe, but it doesn't. */
+ save_option (lease -> options.dhcp_hash, oc);
+ option_cache_dereference
+ (&oc, "parse_client_lease_declaration");
+ }
return;
default:
}
}
-struct option *parse_option_decl (cfile, options)
+int parse_option_decl (oc, cfile)
+ struct option_cache **oc;
FILE *cfile;
- struct option_data *options;
{
char *val;
int token;
u_int8_t *dp;
int len;
int nul_term = 0;
+ struct buffer *bp;
option = parse_option_name (cfile);
if (!option)
- return;
+ return 0;
/* Parse the option data... */
do {
if (token != STRING) {
parse_warn ("expecting string.");
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
len = strlen (val);
if (hunkix + len + 1 > sizeof hunkbuf) {
parse_warn ("option data buffer %s",
"overflow");
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
memcpy (&hunkbuf [hunkix], val, len + 1);
nul_term = 1;
case 'I': /* IP address. */
if (!parse_ip_addr (cfile, &ip_addr))
- return (struct option *)0;
+ return 0;
len = ip_addr.len;
dp = ip_addr.iabuf;
parse_warn ("option data buffer %s",
"overflow");
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
memcpy (&hunkbuf [hunkix], dp, len);
hunkix += len;
parse_warn ("expecting number.");
if (token != SEMI)
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
convert_num (buf, val, 0, 32);
len = 4;
bad_flag:
if (token != SEMI)
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
if (!strcasecmp (val, "true")
|| !strcasecmp (val, "on"))
warn ("Bad format %c in parse_option_param.",
*fmt);
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
}
token = next_token (&val, cfile);
if (token != SEMI) {
parse_warn ("semicolon expected.");
skip_to_semi (cfile);
- return (struct option *)0;
+ return 0;
}
- options [option -> code].data =
- (unsigned char *)malloc (hunkix + nul_term);
- if (!options [option -> code].data)
+ bp = (struct buffer *)0;
+ if (!buffer_allocate (&bp, hunkix + nul_term, "parse_option_decl"))
+ error ("no memory to store option declaration.");
+ if (!bp -> data)
error ("out of memory allocating option data.");
- memcpy (options [option -> code].data, hunkbuf, hunkix + nul_term);
- options [option -> code].len = hunkix;
- return option;
+ memcpy (bp -> data, hunkbuf, hunkix + nul_term);
+
+ if (!option_cache_allocate (oc, "parse_option_decl"))
+ error ("out of memory allocating option cache.");
+
+ (*oc) -> data.buffer = bp;
+ (*oc) -> data.data = &bp -> data [0];
+ (*oc) -> data.terminated = nul_term;
+ (*oc) -> data.len = hunkix;
+ (*oc) -> option = option;
+ return 1;
}
void parse_string_list (cfile, lp, multiple)
#ifndef lint
static char copyright[] =
-"$Id: dhclient.c,v 1.49 1998/04/09 04:26:24 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.50 1998/11/05 18:39:04 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
{
}
+struct class *find_class (s)
+ char *s;
+{
+ return (struct class *)0;
+}
+
+int check_collection (packet, collection)
+ struct packet *packet;
+ struct collection *collection;
+{
+ return 0;
+}
+
+void classify (packet, class)
+ struct packet *packet;
+ struct class *class;
+{
+}
+
/* Individual States:
*
* Each routine is called from the dhclient_state_machine() in one of
picked -> next = (struct client_lease *)0;
} else {
freeit:
- free_client_lease (lp);
+ destroy_client_lease (lp);
}
}
ip -> client -> offered_leases = (struct client_lease *)0;
}
/* If it was a BOOTREPLY, we can just take the address right now. */
- if (!picked -> options [DHO_DHCP_MESSAGE_TYPE].len) {
+ if (!picked -> is_bootp) {
ip -> client -> new = picked;
/* Make up some lease expiry times
ip -> client -> xid = ip -> client -> packet.xid;
/* Toss the lease we picked - we'll get it back in a DHCPACK. */
- free_client_lease (picked);
+ destroy_client_lease (picked);
/* Add an immediate timeout to send the first DHCPREQUEST packet. */
send_request (ip);
{
struct interface_info *ip = packet -> interface;
struct client_lease *lease;
+ struct option_cache *oc;
+ struct data_string ds;
int i;
/* If we're not receptive to an offer right now, or if the offer
cancel_timeout (send_request, ip);
/* Figure out the lease time. */
- ip -> client -> new -> expiry =
- getULong (ip -> client ->
- new -> options [DHO_DHCP_LEASE_TIME].data);
+ oc = lookup_option (ip -> client -> new -> options.dhcp_hash,
+ DHO_DHCP_LEASE_TIME);
+ memset (&ds, 0, sizeof ds);
+ if (oc &&
+ evaluate_option_cache (&ds, packet,
+ &ip -> client -> new -> options, oc)) {
+ if (ds.len > 3)
+ ip -> client -> new -> expiry = getULong (ds.data);
+ else
+ ip -> client -> new -> expiry = 0;
+ data_string_forget (&ds, "dhcpack");
+ } else
+ ip -> client -> new -> expiry = 0;
+
+ if (!ip -> client -> new -> expiry) {
+ warn ("no expiry time on offered lease.");
+ /* XXX this is going to be bad - if this _does_
+ XXX happen, we should probably dynamically
+ XXX disqualify the DHCP server that gave us the
+ XXX bad packet from future selections and
+ XXX then go back into the init state. */
+ state_init (ip);
+ return;
+ }
- /* Take the server-provided renewal time if there is one;
- otherwise figure it out according to the spec. */
- if (ip -> client -> new -> options [DHO_DHCP_RENEWAL_TIME].len)
- ip -> client -> new -> renewal =
- getULong (ip -> client ->
- new -> options [DHO_DHCP_RENEWAL_TIME].data);
- else
+ /* Take the server-provided renewal time if there is one. */
+ oc = lookup_option (ip -> client -> new -> options.dhcp_hash,
+ DHO_DHCP_RENEWAL_TIME);
+ if (oc &&
+ evaluate_option_cache (&ds, packet,
+ &ip -> client -> new -> options, oc)) {
+ if (ds.len > 3)
+ ip -> client -> new -> renewal = getULong (ds.data);
+ else
+ ip -> client -> new -> renewal = 0;
+ } else
+ ip -> client -> new -> renewal = 0;
+
+ /* If it wasn't specified by the server, calculate it. */
+ if (!ip -> client -> new -> renewal)
ip -> client -> new -> renewal =
ip -> client -> new -> expiry / 2;
/* Same deal with the rebind time. */
- if (ip -> client -> new -> options [DHO_DHCP_REBINDING_TIME].len)
- ip -> client -> new -> rebind =
- getULong (ip -> client -> new ->
- options [DHO_DHCP_REBINDING_TIME].data);
- else
+ oc = lookup_option (ip -> client -> new -> options.dhcp_hash,
+ DHO_DHCP_REBINDING_TIME);
+ if (oc &&
+ evaluate_option_cache (&ds, packet,
+ &ip -> client -> new -> options, oc)) {
+ if (ds.len > 3)
+ ip -> client -> new -> rebind = getULong (ds.data);
+ else
+ ip -> client -> new -> rebind = 0;
+ } else
+ ip -> client -> new -> rebind = 0;
+
+ if (!ip -> client -> new -> rebind)
ip -> client -> new -> rebind =
ip -> client -> new -> renewal +
ip -> client -> new -> renewal / 2 +
/* Replace the old active lease with the new one. */
if (ip -> client -> active)
- free_client_lease (ip -> client -> active);
+ destroy_client_lease (ip -> client -> active);
ip -> client -> active = ip -> client -> new;
ip -> client -> new = (struct client_lease *)0;
void *ipp;
{
struct interface_info *ip = ipp;
+ int i;
+ struct option_cache *oc;
+ struct data_string ds;
ASSERT_STATE(state, S_BOUND);
make_request (ip, ip -> client -> active);
ip -> client -> xid = ip -> client -> packet.xid;
- if (ip -> client -> active ->
- options [DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
- memcpy (ip -> client -> destination.iabuf,
- ip -> client -> active ->
- options [DHO_DHCP_SERVER_IDENTIFIER].data, 4);
- ip -> client -> destination.len = 4;
+ memset (&ds, 0, sizeof ds);
+ oc = lookup_option (ip -> client -> active -> options.dhcp_hash,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ if (oc &&
+ evaluate_option_cache (&ds, (struct packet *)0,
+ &ip -> client -> active -> options, oc)) {
+ if (ds.len > 3) {
+ memcpy (ip -> client -> destination.iabuf, ds.data, 4);
+ ip -> client -> destination.len = 4;
+ } else
+ ip -> client -> destination = iaddr_broadcast;
} else
ip -> client -> destination = iaddr_broadcast;
struct client_lease *lease, *lp;
int i;
int arp_timeout_needed, stop_selecting;
- char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len
- ? "DHCPOFFER" : "BOOTREPLY");
+ char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
struct iaddrlist *ap;
+ struct option_cache *oc;
#ifdef DEBUG_PACKET
dump_packet (packet);
/* If this lease doesn't supply the minimum required parameters,
blow it off. */
- for (i = 0; ip -> client -> config -> required_options [i]; i++) {
- if (!packet -> options [ip -> client -> config ->
- required_options [i]].len) {
- note ("%s isn't satisfactory.", name);
- return;
+ if (ip -> client -> config -> required_options) {
+ for (i = 0;
+ ip -> client -> config -> required_options [i]; i++) {
+ if (!lookup_option
+ (packet -> options.dhcp_hash,
+ ip -> client -> config -> required_options [i])) {
+ note ("%s isn't satisfactory.", name);
+ return;
+ }
}
}
/* If this lease was acquired through a BOOTREPLY, record that
fact. */
- if (!packet -> options [DHO_DHCP_MESSAGE_TYPE].len)
+ if (!packet -> options_valid || !packet -> packet_type)
lease -> is_bootp = 1;
/* Record the medium under which this lease was offered. */
{
struct client_lease *lease;
int i;
+ struct option_cache *oc;
+ struct data_string data;
- lease = (struct client_lease *)malloc (sizeof (struct client_lease));
+ lease = (struct client_lease *)new_client_lease ("packet_to_lease");
if (!lease) {
warn ("dhcpoffer: no memory to record lease.\n");
memset (lease, 0, sizeof *lease);
/* Copy the lease options. */
- for (i = 0; i < 256; i++) {
- if (packet -> options [i].len) {
- lease -> options [i].data =
- (unsigned char *)
- malloc (packet -> options [i].len + 1);
- if (!lease -> options [i].data) {
- warn ("dhcpoffer: no memory for option %d\n",
- i);
- free_client_lease (lease);
- return (struct client_lease *)0;
- } else {
- memcpy (lease -> options [i].data,
- packet -> options [i].data,
- packet -> options [i].len);
- lease -> options [i].len =
- packet -> options [i].len;
- lease -> options [i].data
- [lease -> options [i].len] = 0;
- }
- }
- }
+ lease -> options = packet -> options;
+ memset (&packet -> options, 0, sizeof packet -> options);
lease -> address.len = sizeof (packet -> raw -> yiaddr);
memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
lease -> address.len);
+ /* Figure out the overload flag. */
+ oc = lookup_option (lease -> options.dhcp_hash,
+ DHO_DHCP_OPTION_OVERLOAD);
+ memset (&data, 0, sizeof data);
+ if (oc &&
+ evaluate_option_cache (&data, packet, &lease -> options, oc)) {
+ if (data.len > 0)
+ i = data.data [0];
+ else
+ i = 0;
+ data_string_forget (&data, "packet_to_lease");
+ } else
+ i = 0;
+
/* If the server name was filled out, copy it. */
- if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len ||
- !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)) &&
- packet -> raw -> sname [0]) {
+ if (!(i & 2) && packet -> raw -> sname [0]) {
int len;
/* Don't count on the NUL terminator. */
for (len = 0; len < 64; len++)
if (!packet -> raw -> sname [len])
break;
- lease -> server_name = malloc (len + 1);
+ lease -> server_name = dmalloc (len + 1, "packet_to_lease");
if (!lease -> server_name) {
warn ("dhcpoffer: no memory for filename.\n");
- free_client_lease (lease);
+ destroy_client_lease (lease);
return (struct client_lease *)0;
} else {
memcpy (lease -> server_name,
}
/* Ditto for the filename. */
- if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len ||
- !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)) &&
- packet -> raw -> file [0]) {
+ if ((i & 1) && packet -> raw -> file [0]) {
int len;
/* Don't count on the NUL terminator. */
for (len = 0; len < 64; len++)
if (!packet -> raw -> file [len])
break;
- lease -> filename = malloc (len + 1);
+ lease -> filename = dmalloc (len + 1, "packet_to_lease");
if (!lease -> filename) {
warn ("dhcpoffer: no memory for filename.\n");
- free_client_lease (lease);
+ destroy_client_lease (lease);
return (struct client_lease *)0;
} else {
memcpy (lease -> filename,
return;
}
- free_client_lease (ip -> client -> active);
+ destroy_client_lease (ip -> client -> active);
ip -> client -> active = (struct client_lease *)0;
/* Stop sending DHCPREQUEST packets... */
warn ("send_packet: %m");
}
-void make_discover (ip, lease)
+void make_client_options (ip, lease, type, sid, rip, prl, statements,
+ options)
struct interface_info *ip;
struct client_lease *lease;
+ u_int8_t *type;
+ struct option_cache *sid;
+ struct iaddr *rip;
+ u_int32_t *prl;
+ struct executable_statement *statements;
+ struct option_state *options;
{
- struct dhcp_packet *raw;
- unsigned char discover = DHCPDISCOVER;
int i;
-
- struct tree_cache *options [256];
- struct tree_cache option_elements [256];
-
- memset (option_elements, 0, sizeof option_elements);
- memset (options, 0, sizeof options);
- memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &option_elements [i];
- options [i] -> value = &discover;
- options [i] -> len = sizeof discover;
- options [i] -> buf_size = sizeof discover;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Request the options we want */
- i = DHO_DHCP_PARAMETER_REQUEST_LIST;
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config -> requested_options;
- options [i] -> len = ip -> client -> config -> requested_option_count;
- options [i] -> buf_size =
- ip -> client -> config -> requested_option_count;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* If we had an address, try to get it again. */
- if (lease) {
- ip -> client -> requested_address = lease -> address;
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options [i] = &option_elements [i];
- options [i] -> value = lease -> address.iabuf;
- options [i] -> len = lease -> address.len;
- options [i] -> buf_size = lease -> address.len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
+ struct option_cache *oc;
+ struct buffer *bp = (struct buffer *)0;
+
+ memset (options, 0, sizeof *options);
+
+ /* Send the server identifier if provided. */
+ if (sid)
+ save_option (options -> dhcp_hash, sid);
+
+ /* Send the requested address if provided. */
+ if (rip) {
+ ip -> client -> requested_address = *rip;
+ if (!(make_const_option_cache
+ (&oc, (struct buffer **)0,
+ rip -> iabuf, rip -> len,
+ &dhcp_options [DHO_DHCP_REQUESTED_ADDRESS],
+ "make_client_options")))
+ warn ("can't make requested address option cache.");
+ else {
+ save_option (options -> dhcp_hash, oc);
+ option_cache_dereference (&oc, "make_client_options");
+ }
} else {
ip -> client -> requested_address.len = 0;
}
- /* Send any options requested in the config file. */
- for (i = 0; i < 256; i++) {
- if (!options [i] &&
- ip -> client -> config -> send_options [i].data) {
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config ->
- send_options [i].data;
- options [i] -> len = ip -> client -> config ->
- send_options [i].len;
- options [i] -> buf_size = ip -> client -> config ->
- send_options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
+ if (!(make_const_option_cache
+ (&oc, (struct buffer **)0,
+ type, 1, &dhcp_options [DHO_DHCP_MESSAGE_TYPE],
+ "make_client_options")))
+ warn ("can't make message type.");
+ else {
+ save_option (options -> dhcp_hash, oc);
+ option_cache_dereference (&oc, "make_client_options");
+ }
+
+ if (prl) {
+ /* Figure out how many parameters were requested. */
+ for (i = 0; prl [i]; i++)
+ ;
+ if (!buffer_allocate (&bp, i, "make_client_options"))
+ warn ("can't make buffer for parameter request list.");
+ else {
+ for (i = 0; prl [i]; i++)
+ bp -> data [i] = prl [i];
+ if (!(make_const_option_cache
+ (&oc, &bp, (u_int8_t *)0, i,
+ &dhcp_options [DHO_DHCP_PARAMETER_REQUEST_LIST],
+ "make_client_options")))
+ warn ("can't make option cache");
+ else {
+ save_option (options -> dhcp_hash, oc);
+ option_cache_dereference
+ (&oc, "make_client_options");
+ }
}
}
+ if (!(oc = lookup_option (options -> dhcp_hash,
+ DHO_DHCP_LEASE_TIME))) {
+ if (!buffer_allocate (&bp, sizeof (u_int32_t),
+ "make_client_options"))
+ warn ("can't make buffer for requested lease time.");
+ else {
+ putULong (bp -> data,
+ ip -> client -> config -> requested_lease);
+ if (!(make_const_option_cache
+ (&oc, &bp, (u_int8_t *)0, sizeof (u_int32_t),
+ &dhcp_options [DHO_DHCP_LEASE_TIME],
+ "make_client_options")))
+ warn ("can't make option cache");
+ else {
+ save_option (options -> dhcp_hash, oc);
+ option_cache_dereference
+ (&oc, "make_client_options");
+ }
+ }
+ }
+
+ /* Run statements that need to be run on transmission. */
+ if (statements)
+ execute_statements ((struct packet *)0,
+ &lease -> options, options, statements);
+}
+
+void make_discover (ip, lease)
+ struct interface_info *ip;
+ struct client_lease *lease;
+{
+ struct dhcp_packet *raw;
+ unsigned char discover = DHCPDISCOVER;
+ int i;
+ struct option_state options;
+
+ memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
+
+ make_client_options (ip, lease, &discover, (struct option_cache *)0,
+ lease ? &lease -> address : (struct iaddr *)0,
+ ip -> client -> config -> requested_options,
+ ip -> client -> config -> on_transmission,
+ &options);
+
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, (struct agent_options *)0, 0, 0, 0);
+ &options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
{
unsigned char request = DHCPREQUEST;
int i;
+ struct option_state options;
+ struct option_cache *oc;
- struct tree_cache *options [256];
- struct tree_cache option_elements [256];
-
- memset (options, 0, sizeof options);
memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
- /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &option_elements [i];
- options [i] -> value = &request;
- options [i] -> len = sizeof request;
- options [i] -> buf_size = sizeof request;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Request the options we want */
- i = DHO_DHCP_PARAMETER_REQUEST_LIST;
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config -> requested_options;
- options [i] -> len = ip -> client -> config -> requested_option_count;
- options [i] -> buf_size =
- ip -> client -> config -> requested_option_count;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* If we are requesting an address that hasn't yet been assigned
- to us, use the DHCP Requested Address option. */
- if (ip -> client -> state == S_REQUESTING) {
- /* Send back the server identifier... */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options [i] = &option_elements [i];
- options [i] -> value = lease -> options [i].data;
- options [i] -> len = lease -> options [i].len;
- options [i] -> buf_size = lease -> options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- }
- if (ip -> client -> state == S_REQUESTING ||
- ip -> client -> state == S_REBOOTING) {
- ip -> client -> requested_address = lease -> address;
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options [i] = &option_elements [i];
- options [i] -> value = lease -> address.iabuf;
- options [i] -> len = lease -> address.len;
- options [i] -> buf_size = lease -> address.len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- } else {
- ip -> client -> requested_address.len = 0;
- }
+ if (ip -> client -> state == S_REQUESTING)
+ oc = lookup_option (lease -> options.dhcp_hash,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ else
+ oc = (struct option_cache *)0;
- /* Send any options requested in the config file. */
- for (i = 0; i < 256; i++) {
- if (!options [i] &&
- ip -> client -> config -> send_options [i].data) {
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config ->
- send_options [i].data;
- options [i] -> len = ip -> client -> config ->
- send_options [i].len;
- options [i] -> buf_size = ip -> client -> config ->
- send_options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- }
- }
+ make_client_options (ip, lease, &request, oc,
+ ((ip -> client -> state == S_REQUESTING ||
+ ip -> client -> state == S_REBOOTING)
+ ? &lease -> address
+ : (struct iaddr *)0),
+ ip -> client -> config -> requested_options,
+ ip -> client -> config -> on_transmission,
+ &options);
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, (struct agent_options *)0, 0, 0, 0);
+ &options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
{
unsigned char decline = DHCPDECLINE;
int i;
+ struct option_cache *oc;
- struct tree_cache *options [256];
- struct tree_cache message_type_tree;
- struct tree_cache requested_address_tree;
- struct tree_cache server_id_tree;
- struct tree_cache client_id_tree;
+ struct option_state options;
- memset (options, 0, sizeof options);
memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
- /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &message_type_tree;
- options [i] -> value = &decline;
- options [i] -> len = sizeof decline;
- options [i] -> buf_size = sizeof decline;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send back the server identifier... */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options [i] = &server_id_tree;
- options [i] -> value = lease -> options [i].data;
- options [i] -> len = lease -> options [i].len;
- options [i] -> buf_size = lease -> options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send back the address we're declining. */
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options [i] = &requested_address_tree;
- options [i] -> value = lease -> address.iabuf;
- options [i] -> len = lease -> address.len;
- options [i] -> buf_size = lease -> address.len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send the uid if the user supplied one. */
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- if (ip -> client -> config -> send_options [i].len) {
- options [i] = &client_id_tree;
- options [i] -> value = ip -> client -> config ->
- send_options [i].data;
- options [i] -> len = ip -> client -> config ->
- send_options [i].len;
- options [i] -> buf_size = ip -> client -> config ->
- send_options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- }
-
+ oc = lookup_option (lease -> options.dhcp_hash,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ make_client_options (ip, lease, &decline, oc,
+ &lease -> address, (u_int32_t *)0,
+ (struct executable_statement *)0, &options);
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, (struct agent_options *)0, 0, 0, 0);
+ &options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
{
unsigned char request = DHCPRELEASE;
int i;
+ struct option_cache *oc;
- struct tree_cache *options [256];
- struct tree_cache message_type_tree;
- struct tree_cache requested_address_tree;
- struct tree_cache server_id_tree;
+ struct option_state options;
- memset (options, 0, sizeof options);
memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
- /* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &message_type_tree;
- options [i] -> value = &request;
- options [i] -> len = sizeof request;
- options [i] -> buf_size = sizeof request;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send back the server identifier... */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options [i] = &server_id_tree;
- options [i] -> value = lease -> options [i].data;
- options [i] -> len = lease -> options [i].len;
- options [i] -> buf_size = lease -> options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
+ oc = lookup_option (lease -> options.dhcp_hash,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ make_client_options (ip, lease, &request, oc,
+ &lease -> address, (u_int32_t *)0,
+ (struct executable_statement *)0, &options);
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, (struct agent_options *)0, 0, 0, 0);
+ &options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
#endif
}
-void free_client_lease (lease)
+void destroy_client_lease (lease)
struct client_lease *lease;
{
int i;
if (lease -> server_name)
- free (lease -> server_name);
+ dfree (lease -> server_name, "destroy_client_lease");
if (lease -> filename)
- free (lease -> filename);
- for (i = 0; i < 256; i++) {
- if (lease -> options [i].len)
- free (lease -> options [i].data);
- }
- free (lease);
+ dfree (lease -> filename, "destroy_client_lease");
+ option_state_dereference (&lease -> options);
+ free_client_lease (lease, "destroy_client_lease");
}
FILE *leaseFile;
int i;
struct tm *t;
static int leases_written;
+ struct option_cache *oc;
+ struct data_string ds;
if (!rewrite) {
if (leases_written++ > 20) {
if (lease -> medium)
fprintf (leaseFile, " medium \"%s\";\n",
lease -> medium -> string);
- for (i = 0; i < 256; i++) {
- if (lease -> options [i].len) {
- fprintf (leaseFile,
- " option %s %s;\n",
- dhcp_options [i].name,
- pretty_print_option
- (i, lease -> options [i].data,
- lease -> options [i].len, 1, 1));
+ for (i = 0; i < OPTION_HASH_SIZE; i++) {
+ pair p;
+ for (p = lease -> options.dhcp_hash [i]; p; p = p -> cdr) {
+ memset (&ds, 0, sizeof ds);
+ if (evaluate_option_cache (&ds, (struct packet *)0,
+ &lease -> options, oc)) {
+ fprintf (leaseFile,
+ " option %s %s;\n",
+ dhcp_options [i].name,
+ pretty_print_option
+ (i, ds.data, ds.len,
+ 1, 1));
+ data_string_forget (&ds,
+ "write_client_lease");
+ }
}
}
struct client_lease *lease;
{
int i;
- u_int8_t dbuf [1500];
- int len;
+ struct data_string data;
+ struct option_cache *oc;
fprintf (scriptFile, "%sip_address=\"%s\"\n",
prefix, piaddr (lease -> address));
broadcast address, not the host address all zeroes
broadcast address). */
- if (lease -> options [DHO_SUBNET_MASK].len &&
- (lease -> options [DHO_SUBNET_MASK].len <
- sizeof lease -> address.iabuf)) {
- struct iaddr netmask, subnet, broadcast;
-
- memcpy (netmask.iabuf,
- lease -> options [DHO_SUBNET_MASK].data,
- lease -> options [DHO_SUBNET_MASK].len);
- netmask.len = lease -> options [DHO_SUBNET_MASK].len;
-
- subnet = subnet_number (lease -> address, netmask);
- if (subnet.len) {
- fprintf (scriptFile, "%snetwork_number=\"%s\";\n",
- prefix, piaddr (subnet));
- fprintf (scriptFile, "export %snetwork_number\n",
- prefix);
-
- if (!lease -> options [DHO_BROADCAST_ADDRESS].len) {
- broadcast = broadcast_addr (subnet, netmask);
- if (broadcast.len) {
- fprintf (scriptFile,
- "%s%s=\"%s\";\n", prefix,
- "broadcast_address",
- piaddr (broadcast));
- fprintf (scriptFile,
- "export %s%s\n", prefix,
- "broadcast_address");
+ memset (&data, 0, sizeof data);
+ oc = lookup_option (lease -> options.dhcp_hash, DHO_SUBNET_MASK);
+ if (oc && evaluate_option_cache (&data, (struct packet *)0,
+ &lease -> options, oc)) {
+ if (data.len > 3) {
+ struct iaddr netmask, subnet, broadcast;
+
+ memcpy (netmask.iabuf, data.data, data.len);
+ netmask.len = data.len;
+ data_string_forget (&data, "script_write_params");
+
+ subnet = subnet_number (lease -> address, netmask);
+ if (subnet.len) {
+ fprintf (scriptFile,
+ "%snetwork_number=\"%s\";\n",
+ prefix, piaddr (subnet));
+ fprintf (scriptFile,
+ "export %snetwork_number\n", prefix);
+
+ oc = lookup_option (lease -> options.dhcp_hash,
+ DHO_BROADCAST_ADDRESS);
+ if (!oc ||
+ !evaluate_option_cache (&data,
+ (struct packet *)0,
+ &lease -> options,
+ oc)) {
+ broadcast = broadcast_addr (subnet,
+ netmask);
+ if (broadcast.len) {
+ fprintf (scriptFile,
+ "%s%s=\"%s\";\n",
+ prefix,
+ "broadcast_address",
+ piaddr (broadcast));
+ fprintf (scriptFile,
+ "export %s%s\n",
+ prefix,
+ "broadcast_address");
+ }
}
}
}
prefix, lease -> server_name);
fprintf (scriptFile, "export %sserver_name\n", prefix);
}
- for (i = 0; i < 256; i++) {
- u_int8_t *dp;
-
- if (ip -> client -> config -> defaults [i].len) {
- if (lease -> options [i].len) {
- switch (ip -> client ->
- config -> default_actions [i]) {
- case ACTION_DEFAULT:
- dp = lease -> options [i].data;
- len = lease -> options [i].len;
- break;
- case ACTION_SUPERSEDE:
- supersede:
- dp = ip -> client ->
- config -> defaults [i].data;
- len = ip -> client ->
- config -> defaults [i].len;
- break;
- case ACTION_PREPEND:
- len = (ip -> client ->
- config -> defaults [i].len +
- lease -> options [i].len);
- if (len > sizeof dbuf) {
- warn ("no space to %s %s",
- "prepend option",
- dhcp_options [i].name);
- goto supersede;
- }
- dp = dbuf;
- memcpy (dp,
- ip -> client ->
- config -> defaults [i].data,
- ip -> client ->
- config -> defaults [i].len);
- memcpy (dp + ip -> client ->
- config -> defaults [i].len,
- lease -> options [i].data,
- lease -> options [i].len);
- break;
- case ACTION_APPEND:
- len = (ip -> client ->
- config -> defaults [i].len +
- lease -> options [i].len);
- if (len > sizeof dbuf) {
- warn ("no space to %s %s",
- "prepend option",
- dhcp_options [i].name);
- goto supersede;
- }
- dp = dbuf;
- memcpy (dp,
- ip -> client ->
- config -> defaults [i].data,
- ip -> client ->
- config -> defaults [i].len);
- memcpy (dp + ip -> client ->
- config -> defaults [i].len,
- lease -> options [i].data,
- lease -> options [i].len);
+
+ execute_statements ((struct packet *)0, &lease -> options,
+ &lease -> options,
+ ip -> client -> config -> on_transmission);
+
+ for (i = 0; i < OPTION_HASH_SIZE; i++) {
+ pair hp;
+
+ for (hp = lease -> options.dhcp_hash [i]; hp; hp = hp -> cdr) {
+ oc = (struct option_cache *)hp -> car;
+
+ if (evaluate_option_cache (&data, (struct packet *)0,
+ &lease -> options, oc)) {
+
+ if (data.len) {
+ char *s = (dhcp_option_ev_name
+ (oc -> option));
+
+ fprintf (scriptFile,
+ "%s%s=\"%s\"\n", prefix, s,
+ (pretty_print_option
+ (i, data.data, data.len,
+ 0, 0)));
+ fprintf (scriptFile,
+ "export %s%s\n", prefix, s);
}
- } else {
- dp = ip -> client ->
- config -> defaults [i].data;
- len = ip -> client ->
- config -> defaults [i].len;
}
- } else if (lease -> options [i].len) {
- len = lease -> options [i].len;
- dp = lease -> options [i].data;
- } else {
- len = 0;
- }
- if (len) {
- char *s = dhcp_option_ev_name (&dhcp_options [i]);
-
- fprintf (scriptFile, "%s%s=\"%s\"\n", prefix, s,
- pretty_print_option (i, dp, len, 0, 0));
- fprintf (scriptFile, "export %s%s\n", prefix, s);
}
}
fprintf (scriptFile, "%sexpiry=\"%d\"\n",
#ifndef lint
static char copyright[] =
-"$Id: parse.c,v 1.7 1998/06/25 03:07:51 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: parse.c,v 1.8 1998/11/05 18:43:23 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
void skip_to_semi (cfile)
FILE *cfile;
{
- int token;
+ enum dhcp_token token;
char *val;
int brace_count = 0;
int parse_semi (cfile)
FILE *cfile;
{
- int token;
+ enum dhcp_token token;
char *val;
token = next_token (&val, cfile);
FILE *cfile;
{
char *val;
- int token;
+ enum dhcp_token token;
char *s;
token = next_token (&val, cfile);
FILE *cfile;
{
char *val;
- int token;
+ enum dhcp_token token;
int len = 0;
char *s;
char *t;
an expr_substring node to limit hostnames that evaluate to more
than one IP address. */
-struct expression *parse_ip_addr_or_hostname (cfile, uniform)
+int parse_ip_addr_or_hostname (expr, cfile, uniform)
+ struct expression **expr;
FILE *cfile;
int uniform;
{
char *val;
- int token;
+ enum dhcp_token token;
unsigned char addr [4];
int len = sizeof addr;
char *name;
- struct expression *rv;
+ struct expression *x = (struct expression *)0;
token = peek_token (&val, cfile);
if (is_identifier (token)) {
name = parse_host_name (cfile);
if (!name)
- return (struct expression *)0;
- rv = make_host_lookup (name);
- if (!uniform)
- rv = make_limit (rv, 4);
+ return 0;
+ if (!make_host_lookup (expr, name))
+ return 0;
+ if (!uniform) {
+ if (!make_limit (&x, *expr, 4))
+ return 0;
+ expression_dereference (expr,
+ "parse_ip_addr_or_hostname");
+ *expr = x;
+ }
} else if (token == NUMBER) {
if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
- return (struct expression *)0;
- rv = make_const_data (addr, len, 0, 0);
+ return 0;
+ return make_const_data (expr, addr, len, 0, 1);
} else {
if (token != RBRACE && token != LBRACE)
token = next_token (&val, cfile);
val, token);
if (token != SEMI)
skip_to_semi (cfile);
- return (struct expression *)0;
+ return 0;
}
- return rv;
+ return 1;
}
/*
struct iaddr *addr;
{
char *val;
- int token;
+ enum dhcp_token token;
addr -> len = 4;
if (parse_numeric_aggregate (cfile, addr -> iabuf,
struct hardware *hardware;
{
char *val;
- int token;
+ enum dhcp_token token;
int hlen;
unsigned char *t;
TIME *timep;
{
char *val;
- int token;
+ enum dhcp_token token;
token = next_token (&val, cfile);
if (token != NUMBER) {
int size;
{
char *val;
- int token;
+ enum dhcp_token token;
unsigned char *bufp = buf, *s, *t;
int count = 0;
pair c = (pair)0;
struct tm tm;
int guess;
char *val;
- int token;
+ enum dhcp_token token;
static int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
FILE *cfile;
{
char *val;
- int token;
+ enum dhcp_token token;
char *vendor;
struct universe *universe;
struct option *option;
* NUMBER COLON colon-seperated-hex-list
*/
-unsigned char *parse_cshl (cfile, plen)
+int parse_cshl (data, cfile)
+ struct data_string *data;
FILE *cfile;
- int *plen;
{
char ibuf [128];
int ilen = 0;
int tlen = 0;
struct option_tag *sl = (struct option_tag *)0;
struct option_tag *next, **last = &sl;
- int token;
+ enum dhcp_token token;
char *val;
- unsigned char *rv, *rvp;
+ unsigned char *rvp;
do {
token = next_token (&val, cfile);
next = sl -> next;
dfree (sl, "parse_cshl");
}
- return (unsigned char *)0;
+ return 0;
}
if (ilen == sizeof ibuf) {
next = (struct option_tag *)
token = next_token (&val, cfile);
} while (1);
- rv = dmalloc (tlen + ilen, "parse_cshl");
- if (!rv)
+ if (!buffer_allocate (&data -> buffer, tlen + ilen, "parse_cshl"))
error ("no memory to store octet data.");
- rvp = rv;
+ data -> data = &data -> buffer -> data [0];
+ data -> len = tlen + ilen;
+ data -> terminated = 0;
+
+ rvp = &data -> data [0];
while (sl) {
next = sl -> next;
memcpy (rvp, sl -> data, sizeof ibuf);
}
memcpy (rvp, ibuf, ilen);
- *plen = ilen + tlen;
- return rv;
+ return 1;
}
/*
next = &head;
while ((*next = parse_executable_statement (cfile, lose)))
next = &((*next) -> next);
- if (!lose)
+ if (!*lose)
return head;
return (struct executable_statement *)0;
}
FILE *cfile;
int *lose;
{
- int token;
+ enum dhcp_token token;
char *val;
struct executable_statement *stmt, base;
struct class *cta;
FILE *cfile;
int *lose;
{
- int token;
+ enum dhcp_token token;
char *val;
struct executable_statement *stmt;
struct expression *if_condition;
struct executable_statement *true, *false;
token = next_token (&val, cfile);
- if_condition = parse_boolean_expression (cfile, lose);
- if (!if_condition) {
+ if_condition = (struct expression *)0;
+ if (!parse_boolean_expression (&if_condition, cfile, lose)) {
if (!*lose)
parse_warn ("boolean expression expected.");
return (struct executable_statement *)0;
}
+#if defined (DEBUG_EXPRESSION_PARSE)
+ print_expression ("if condition", if_condition);
+#endif
token = next_token (&val, cfile);
if (token != LBRACE) {
parse_warn ("left brace expected.");
* data-expression EQUAL data-expression |
* boolean-expression AND boolean-expression |
* boolean-expression OR boolean-expression
+ * EXISTS OPTION-NAME
*/
+int parse_boolean_expression (expr, cfile, lose)
+ struct expression **expr;
+ FILE *cfile;
+ int *lose;
+{
+ /* Parse an expression... */
+ if (!parse_expression (expr, cfile, lose, context_boolean,
+ (struct expression **)0, expr_none))
+ return 0;
+
+ if (!is_boolean_expression (*expr)) {
+ parse_warn ("Expecting a boolean expression.");
+ *lose = 1;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * data_expression :== SUBSTRING LPAREN data-expression COMMA
+ * numeric-expression COMMA
+ * numeric-expression RPAREN |
+ * SUFFIX LPAREN data_expression COMMA
+ * numeric-expression |
+ * OPTION option_name |
+ * HARDWARE |
+ * PACKET LPAREN numeric-expression COMMA
+ * numeric-expression RPAREN |
+ * STRING |
+ * colon_seperated_hex_list
+ */
+
+int parse_data_expression (expr, cfile, lose)
+ struct expression **expr;
+ FILE *cfile;
+ int *lose;
+{
+ /* Parse an expression... */
+ if (!parse_expression (expr, cfile, lose, context_data,
+ (struct expression **)0, expr_none))
+ return 0;
+
+ if (!is_data_expression (*expr)) {
+ parse_warn ("Expecting a data expression.");
+ *lose = 1;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * numeric-expression :== EXTRACT_INT LPAREN data-expression
+ * COMMA number RPAREN |
+ * NUMBER
+ */
+
+int parse_numeric_expression (expr, cfile, lose)
+ struct expression **expr;
+ FILE *cfile;
+ int *lose;
+{
+ /* Parse an expression... */
+ if (!parse_expression (expr, cfile, lose, context_numeric,
+ (struct expression **)0, expr_none))
+ return 0;
+
+ if (!is_numeric_expression (*expr)) {
+ parse_warn ("Expecting a numeric expression.");
+ *lose = 1;
+ return 0;
+ }
+ return 1;
+}
+
+/* Parse a subexpression that does not contain a binary operator. */
-struct expression *parse_boolean_expression (cfile, lose)
+int parse_non_binary (expr, cfile, lose, context)
+ struct expression **expr;
FILE *cfile;
int *lose;
+ enum expression_context context;
{
- int token;
+ enum dhcp_token token;
char *val;
struct collection *col;
- struct expression buf, *rv;
- struct expression *left, *right;
+ struct option *option;
token = peek_token (&val, cfile);
parse_warn ("string expected.");
skip_to_semi (cfile);
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
for (col = collections; col; col = col -> next)
if (!strcmp (col -> name, val))
if (!col) {
parse_warn ("unknown collection.");
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
- buf.op = expr_check;
- buf.data.check = col;
- goto have_expr;
+ if (!expression_allocate (expr, "parse_expression: CHECK"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_check;
+ (*expr) -> data.check = col;
+ break;
case NOT:
token = next_token (&val, cfile);
- buf.op = expr_not;
- buf.data.not = parse_boolean_expression (cfile, lose);
- if (!buf.data.not) {
+ if (!expression_allocate (expr, "parse_expression: NOT"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_not;
+ if (!parse_non_binary (&(*expr) -> data.not,
+ cfile, lose, context)) {
if (!*lose) {
- parse_warn ("match expression expected");
+ parse_warn ("expression expected");
skip_to_semi (cfile);
}
*lose = 1;
- return (struct expression *)0;
+ expression_dereference (expr, "parse_expression: NOT");
+ return 0;
}
- goto have_expr;
- }
-
- /* If we're going to find an expression at this point, it must
- involve a binary operator seperating two subexpressions. */
- left = parse_data_expression (cfile, lose);
- if (!left)
- return left;
- token = peek_token (&val, cfile);
- switch (token) {
- case EQUAL:
- buf.op = expr_equal;
- break;
- case AND:
- buf.op = expr_and;
break;
- case OR:
- buf.op = expr_or;
- break;
- default:
- parse_warn ("Expecting a boolean expression.");
- skip_to_semi (cfile);
- *lose = 1;
- return (struct expression *)0;
- }
- token = next_token (&val, cfile);
- /* Now find the RHS of the expression. */
- right = parse_data_expression (cfile, lose);
- if (!right) {
- if (!*lose) {
- if (buf.op == expr_equal)
- parse_warn ("Expecting a data expression.");
- else
- parse_warn ("Expecting a boolean expression.");
- skip_to_semi (cfile);
+ case EXISTS:
+ token = next_token (&val, cfile);
+ if (!expression_allocate (expr, "parse_expression: EXISTS"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_exists;
+ (*expr) -> data.option = parse_option_name (cfile);
+ if (!(*expr) -> data.option) {
+ *lose = 1;
+ expression_dereference (expr,
+ "parse_expression: EXISTS");
+ return 0;
}
- return right;
- }
-
- /* Store the LHS and RHS. */
- buf.data.equal [0] = left;
- buf.data.equal [1] = right;
-
- have_expr:
- rv = new_expression ("parse_boolean_expression");
- if (!rv)
- error ("No memory for boolean expression.");
- *rv = buf;
- return rv;
-}
-
-/*
- * data_expression :== SUBSTRING LPAREN data-expression COMMA
- * numeric-expression COMMA
- * numeric-expression RPAREN |
- * SUFFIX LPAREN data_expression COMMA
- * numeric-expression |
- * OPTION option_name |
- * HARDWARE |
- * PACKET LPAREN numeric-expression COMMA
- * numeric-expression RPAREN |
- * STRING |
- * colon_seperated_hex_list
- */
-
-struct expression *parse_data_expression (cfile, lose)
- FILE *cfile;
- int *lose;
-{
- int token;
- char *val;
- struct collection *col;
- struct expression buf, *rv;
- struct expression *left, *right;
- struct option *option;
-
- token = peek_token (&val, cfile);
+ break;
- switch (token) {
case SUBSTRING:
token = next_token (&val, cfile);
- buf.op = expr_substring;
+ if (!expression_allocate (expr, "parse_expression: SUBSTRING"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_substring;
token = next_token (&val, cfile);
if (token != LPAREN) {
nolparen:
+ expression_dereference (expr,
+ "parse_expression: nolparen");
parse_warn ("left parenthesis expected.");
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
- rv = parse_data_expression (cfile, lose);
- if (!rv) {
+ if (!parse_data_expression (&(*expr) -> data.substring.expr,
+ cfile, lose)) {
nodata:
+ expression_dereference (expr,
+ "parse_expression: nodata");
parse_warn ("expecting data expression.");
skip_to_semi (cfile);
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
token = next_token (&val, cfile);
if (token != COMMA) {
nocomma:
+ expression_dereference (expr,
+ "parse_expression: nocomma1");
parse_warn ("comma expected.");
*lose = 1;
- return (struct expression *)0;
+
+ return 0;
}
- left = parse_numeric_expression (cfile, lose);
- if (!left) {
+ if (!parse_numeric_expression
+ (&(*expr) -> data.substring.offset,cfile, lose)) {
nonum:
if (!*lose) {
parse_warn ("expecting numeric expression.");
skip_to_semi (cfile);
*lose = 1;
}
- return (struct expression *)0;
+ expression_dereference (expr,
+ "parse_expression: nonum");
+ return 0;
}
token = next_token (&val, cfile);
if (token != COMMA)
goto nocomma;
- right = parse_numeric_expression (cfile, lose);
- if (!right)
+ if (!parse_numeric_expression
+ (&(*expr) -> data.substring.len, cfile, lose))
goto nonum;
token = next_token (&val, cfile);
norparen:
parse_warn ("right parenthesis expected.");
*lose = 1;
- return (struct expression *)0;
+ expression_dereference (expr,
+ "parse_expression: norparen");
+ return 0;
}
- return make_substring (rv, left, right);
+ break;
case SUFFIX:
token = next_token (&val, cfile);
- buf.op = expr_suffix;
+ if (!expression_allocate (expr, "parse_expression: SUFFIX"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_suffix;
token = next_token (&val, cfile);
if (token != LPAREN)
goto nolparen;
- buf.data.suffix.expr = parse_data_expression (cfile, lose);
- if (!buf.data.suffix.expr)
+ if (!parse_data_expression (&(*expr) -> data.suffix.expr,
+ cfile, lose))
goto nodata;
token = next_token (&val, cfile);
if (token != COMMA)
goto nocomma;
- buf.data.suffix.len = parse_numeric_expression (cfile, lose);
- if (!buf.data.suffix.len)
+ if (!parse_data_expression (&(*expr) -> data.suffix.len,
+ cfile, lose))
goto nonum;
token = next_token (&val, cfile);
if (token != RPAREN)
goto norparen;
- goto have_expr;
+ break;
case OPTION:
token = next_token (&val, cfile);
- buf.op = expr_option;
- buf.data.option = parse_option_name (cfile);
- if (!buf.data.option) {
+ if (!expression_allocate (expr, "parse_expression: OPTION"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_option;
+ (*expr) -> data.option = parse_option_name (cfile);
+ if (!(*expr) -> data.option) {
*lose = 1;
- return (struct expression *)0;
+ expression_dereference (expr,
+ "parse_expression: OPTION");
+ return 0;
}
- goto have_expr;
+ break;
case HARDWARE:
token = next_token (&val, cfile);
- buf.op = expr_hardware;
- goto have_expr;
+ if (!expression_allocate (expr, "parse_expression: HARDWARE"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_hardware;
+ break;
case PACKET:
token = next_token (&val, cfile);
- buf.op = expr_packet;
+ if (!expression_allocate (expr, "parse_expression: PACKET"))
+ error ("can't allocate expression");
+ (*expr) -> op = expr_packet;
token = next_token (&val, cfile);
if (token != LPAREN)
goto nolparen;
- buf.data.packet.offset =
- parse_numeric_expression (cfile, lose);
- if (!buf.data.packet.offset)
+ if (!parse_numeric_expression (&(*expr) -> data.packet.offset,
+ cfile, lose))
goto nonum;
token = next_token (&val, cfile);
if (token != COMMA)
goto nocomma;
- buf.data.packet.len =
- parse_numeric_expression (cfile, lose);
- if (!buf.data.substring.len)
+ if (!parse_numeric_expression (&(*expr) -> data.packet.len,
+ cfile, lose))
goto nonum;
token = next_token (&val, cfile);
if (token != RPAREN)
goto norparen;
- goto have_expr;
+ break;
case STRING:
token = next_token (&val, cfile);
- return make_const_data (val, strlen (val), 1, 1);
-
- case NUMBER:
- case NUMBER_OR_NAME:
- buf.op = expr_const_data;
- memset (&buf.data, 0, sizeof buf.data);
- buf.data.const_data.data =
- parse_cshl (cfile, &buf.data.const_data.len);
- goto have_expr;
-
- default:
- return (struct expression *)0;
- }
-
- have_expr:
- rv = (struct expression *)dmalloc (sizeof (struct expression),
- "parse_boolean_expression");
- if (!rv)
- error ("No memory for boolean expression.");
- *rv = buf;
- return rv;
-}
-
-/*
- * numeric-expression :== EXTRACT_INT LPAREN data-expression
- * COMMA number RPAREN |
- * NUMBER
- */
-
-struct expression *parse_numeric_expression (cfile, lose)
- FILE *cfile;
- int *lose;
-{
- int token;
- char *val;
- struct collection *col;
- struct expression buf, *rv;
- struct expression *left, *right;
- struct option *option;
-
- token = peek_token (&val, cfile);
+ if (!make_const_data (expr, val, strlen (val), 1, 1))
+ error ("can't make constant string expression.");
+ break;
- switch (token) {
case EXTRACT_INT:
token = next_token (&val, cfile);
-
token = next_token (&val, cfile);
if (token != LPAREN) {
parse_warn ("left parenthesis expected.");
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
- buf.data.extract_int.expr =
- parse_data_expression (cfile, lose);
- if (!buf.data.extract_int.expr) {
+ if (!expression_allocate (expr,
+ "parse_expression: EXTRACT_INT"))
+ error ("can't allocate expression");
+
+ if (!parse_data_expression (&(*expr) -> data.extract_int,
+ cfile, lose)) {
parse_warn ("expecting data expression.");
skip_to_semi (cfile);
*lose = 1;
- return (struct expression *)0;
+ expression_dereference
+ (expr, "parse_expression: EXTRACT_INT");
+ return 0;
}
token = next_token (&val, cfile);
if (token != COMMA) {
parse_warn ("comma expected.");
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
token = next_token (&val, cfile);
if (token != NUMBER) {
parse_warn ("number expected.");
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
- buf.data.extract_int.width = (struct expression *)0;
switch (atoi (val)) {
case 8:
- buf.op = expr_extract_int8;
+ (*expr) -> op = expr_extract_int8;
break;
case 16:
- buf.op = expr_extract_int16;
+ (*expr) -> op = expr_extract_int16;
break;
case 32:
- buf.op = expr_extract_int32;
+ (*expr) -> op = expr_extract_int32;
break;
default:
parse_warn ("unsupported integer size %d", atoi (val));
*lose = 1;
skip_to_semi (cfile);
- return (struct expression *)0;
+ expression_dereference
+ (expr, "parse_expression: EXTRACT_INT");
+ return 0;
}
token = next_token (&val, cfile);
if (token != RPAREN) {
parse_warn ("right parenthesis expected.");
*lose = 1;
- return (struct expression *)0;
+ return 0;
}
- goto have_expr;
+ break;
case NUMBER:
- buf.op = expr_const_int;
- buf.data.const_int = atoi (val);
- goto have_expr;
+ if (!expression_allocate (expr,
+ "parse_expression: NUMBER"))
+ error ("can't allocate expression");
+
+ /* If we're in a numeric context, this should just be a
+ number, by itself. */
+ if (context == context_numeric) {
+ next_token (&val, cfile); /* Eat the number. */
+ (*expr) -> op = expr_const_int;
+ (*expr) -> data.const_int = atoi (val);
+ break;
+ }
+ case NUMBER_OR_NAME:
+ (*expr) -> op = expr_const_data;
+ if (!parse_cshl (&(*expr) -> data.const_data, cfile)) {
+ expression_dereference (expr,
+ "parse_expression: cshl");
+ return 0;
+ }
+ break;
+
+ /* Not a valid start to an expression... */
default:
- return (struct expression *)0;
+ return 0;
}
-
- have_expr:
- rv = (struct expression *)dmalloc (sizeof (struct expression),
- "parse_boolean_expression");
- if (!rv)
- error ("No memory for boolean expression.");
- *rv = buf;
- return rv;
+ return 1;
}
+/* Parse an expression. */
+
+int parse_expression (expr, cfile, lose, context, plhs, binop)
+ struct expression **expr;
+ FILE *cfile;
+ int *lose;
+ enum expression_context context;
+ struct expression **plhs;
+ enum expr_op binop;
+{
+ enum dhcp_token token;
+ char *val;
+ struct expression *rhs = (struct expression *)0, *tmp;
+ struct expression *lhs;
+ enum expr_op next_op;
+
+ /* Consume the left hand side we were passed. */
+ if (plhs) {
+ lhs = *plhs;
+ *plhs = (struct expression *)0;
+ } else
+ lhs = (struct expression *)0;
+
+ new_rhs:
+ if (!parse_non_binary (&rhs, cfile, lose, context)) {
+ /* If we already have a left-hand side, then it's not
+ okay for there not to be a right-hand side here, so
+ we need to flag it as an error. */
+ if (lhs) {
+ if (!*lose) {
+ parse_warn ("expecting right-hand side.");
+ *lose = 1;
+ skip_to_semi (cfile);
+ }
+ expression_dereference (&lhs, "parse_expression");
+ }
+ return 0;
+ }
+
+ /* At this point, rhs contains either an entire subexpression,
+ or at least a left-hand-side. If we do not see a binary token
+ as the next token, we're done with the expression. */
+
+ token = peek_token (&val, cfile);
+ switch (token) {
+ case EQUAL:
+ next_op = expr_equal;
+ break;
+
+ case AND:
+ next_op = expr_and;
+ break;
+
+ case OR:
+ next_op = expr_or;
+ break;
+
+ default:
+ next_op = expr_none;
+ }
+
+ /* If we have no lhs yet, we just parsed it. */
+ if (!lhs) {
+ /* If there was no operator following what we just parsed,
+ then we're done - return it. */
+ if (next_op == expr_none) {
+ *expr = rhs;
+ return 1;
+ }
+ lhs = rhs;
+ rhs = (struct expression *)0;
+ binop = next_op;
+ next_token (&val, cfile); /* Consume the operator. */
+ goto new_rhs;
+ }
+
+ /* Now, if we didn't find a binary operator, we're done parsing
+ this subexpression, so combine it with the preceding binary
+ operator and return the result. */
+ if (next_op == expr_none) {
+ if (!expression_allocate (expr,
+ "parse_expression: COMBINE"))
+ error ("Can't allocate expression!");
+
+ (*expr) -> op = binop;
+ /* All the binary operators' data union members
+ are the same, so we'll cheat and use the member
+ for the equals operator. */
+ (*expr) -> data.equal [0] = lhs;
+ (*expr) -> data.equal [1] = rhs;
+ return 1;
+ }
+
+ /* Eat the operator token - we now know it was a binary operator... */
+ token = next_token (&val, cfile);
+
+ /* If the binary operator we saw previously has a lower precedence
+ than the next operator, then the rhs we just parsed for that
+ operator is actually the lhs of the operator with the higher
+ precedence - to get the real rhs, we need to recurse on the
+ new operator. */
+ if (binop != expr_none &&
+ op_precedence (binop, next_op) < 0) {
+ tmp = rhs;
+ rhs = (struct expression *)0;
+ if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
+ &tmp, next_op)) {
+ if (!*lose) {
+ parse_warn ("expecting a subexpression");
+ *lose = 1;
+ }
+ return 0;
+ }
+ next_op = expr_none;
+ }
+
+ /* Now combine the LHS and the RHS using binop. */
+ tmp = (struct expression *)0;
+ if (!expression_allocate (&tmp, "parse_expression: COMBINE2"))
+ error ("No memory for equal precedence combination.");
+
+ /* Store the LHS and RHS. */
+ tmp -> data.equal [0] = lhs;
+ tmp -> data.equal [1] = rhs;
+ tmp -> op = binop;
+
+ lhs = tmp;
+ tmp = (struct expression *)0;
+ rhs = (struct expression *)0;
+
+ /* Recursions don't return until we have parsed the end of the
+ expression, so if we recursed earlier, we can now return what
+ we got. */
+ if (next_op == expr_none) {
+ *expr = lhs;
+ return 1;
+ }
+
+ binop = next_op;
+ goto new_rhs;
+}
+
/* option-statement :== identifier DOT identifier <syntax> SEMI
| identifier <syntax> SEMI
enum statement_op op;
{
char *val;
- int token;
+ enum dhcp_token token;
char *fmt;
struct expression *expr = (struct expression *)0;
+ struct expression *tmp;
int lose;
struct executable_statement *stmt;
+ int ftt = 1;
token = peek_token (&val, cfile);
if (token == SEMI) {
/* Eat the semicolon... */
token = next_token (&val, cfile);
- expr = make_const_data (0, 0, 0, 0);
goto done;
}
- /* See if there's a data expression, and if so, use it rather than
- the standard format. */
- expr = ((struct expression *)parse_data_expression (cfile, &lose));
-
- /* Found a data expression, but it was bogus? */
- if (lose)
- return (struct executable_statement *)0;
-
- /* We found one. */
- if (expr)
- goto done;
-
/* Parse the option data... */
do {
/* Set a flag if this is an array of a simple type (i.e.,
for (fmt = option -> format; *fmt; fmt++) {
if (*fmt == 'A')
break;
- expr = parse_option_token (cfile, fmt,
- expr, uniform, lookups);
+ tmp = expr;
+ if (!parse_option_token (&expr, cfile, fmt,
+ tmp, uniform, lookups)) {
+ expression_dereference
+ (&tmp, "parse_option_statement");
+ return (struct executable_statement *)0;
+ }
+ if (tmp)
+ expression_dereference
+ (&tmp, "parse_option_statement");
}
if (*fmt == 'A') {
token = peek_token (&val, cfile);
}
} while (*fmt == 'A');
+#if 0
+ goto done;
+
+ try_expr:
+ /* See if there's a data expression, and if so, use it rather than
+ the standard format. */
+ expr = parse_data_expression (cfile, &lose);
+
+ /* Found a data expression, but it was bogus? */
+ if (lose)
+ return (struct executable_statement *)0;
+
+#endif /* 0 */
done:
token = next_token (&val, cfile);
if (token != SEMI) {
}
stmt = ((struct executable_statement *)
dmalloc (sizeof *stmt, "parse_option_statement"));
+ memset (stmt, 0, sizeof *stmt);
stmt -> op = op;
- stmt -> data.option = option_cache (expr, option);
+ if (expr && !option_cache (&stmt -> data.option,
+ (struct data_string *)0, expr, option))
+ error ("no memory for option cache in parse_option_statement");
return stmt;
}
-struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups)
+int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
+ struct expression **rv;
FILE *cfile;
char *fmt;
struct expression *expr;
int lookups;
{
char *val;
- int token;
- struct expression *t;
+ enum dhcp_token token;
+ struct expression *t = (struct expression *)0;
unsigned char buf [4];
int len;
unsigned char *ob;
case 'X':
token = peek_token (&val, cfile);
if (token == NUMBER_OR_NAME || token == NUMBER) {
- ob = parse_cshl (cfile, &len);
- return make_concat (expr,
- make_const_data (ob, len, 0, 0));
+ if (!expression_allocate (&t, "parse_option_token"))
+ return 0;
+ if (!parse_cshl (&t -> data.const_data, cfile))
+ return 0;
} else if (token == STRING) {
token = next_token (&val, cfile);
- return make_concat (expr,
- make_const_data ((unsigned char *)
- val,
- strlen (val),
- 1, 1));
+ if (!make_const_data (&t, (unsigned char *) val,
+ strlen (val), 1, 1))
+ error ("No memory for concatenation");
} else {
parse_warn ("expecting string %s.",
"or hexadecimal data");
skip_to_semi (cfile);
- return (struct expression *)0;
+ return 0;
}
break;
parse_warn ("expecting string.");
if (token != SEMI)
skip_to_semi (cfile);
- return (struct expression *)0;
+ return 0;
}
- return make_concat (expr,
- make_const_data ((unsigned char *)
- val, strlen (val), 1, 1));
+ if (!make_const_data (&t, (unsigned char *)val,
+ strlen (val), 1, 1))
+ error ("No memory for concatenation");
break;
case 'I': /* IP address or hostname. */
- if (lookups)
- t = parse_ip_addr_or_hostname (cfile, uniform);
- else {
+ if (lookups) {
+ if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
+ return 0;
+ } else {
if (!parse_ip_addr (cfile, &addr))
- return (struct expression *)0;
- t = make_const_data (addr.iabuf, addr.len, 0, 1);
+ return 0;
+ if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1))
+ return 0;
}
- if (!t)
- return (struct expression *)0;
- return make_concat (expr, t);
break;
case 'L': /* Unsigned 32-bit integer... */
parse_warn ("expecting number.");
if (token != SEMI)
skip_to_semi (cfile);
- return (struct expression *)0;
+ return 0;
}
convert_num (buf, val, 0, 32);
- return make_concat (expr, make_const_data (buf, 4, 0, 1));
+ if (!make_const_data (&t, buf, 4, 0, 1))
+ return 0;
break;
+
case 's': /* Signed 16-bit integer. */
case 'S': /* Unsigned 16-bit integer. */
token = next_token (&val, cfile);
if (token != NUMBER)
goto need_number;
convert_num (buf, val, 0, 16);
- return make_concat (expr, make_const_data (buf, 2, 0, 1));
+ if (!make_const_data (&t, buf, 2, 0, 1))
+ return 0;
break;
+
case 'b': /* Signed 8-bit integer. */
case 'B': /* Unsigned 8-bit integer. */
token = next_token (&val, cfile);
if (token != NUMBER)
goto need_number;
convert_num (buf, val, 0, 8);
- return make_concat (expr, make_const_data (buf, 1, 0, 1));
+ if (!make_const_data (&t, buf, 1, 0, 1))
+ return 0;
break;
+
case 'f': /* Boolean flag. */
token = next_token (&val, cfile);
if (!is_identifier (token)) {
bad_flag:
if (token != SEMI)
skip_to_semi (cfile);
- return (struct expression *)0;
+ return 0;
}
if (!strcasecmp (val, "true")
|| !strcasecmp (val, "on"))
parse_warn ("expecting boolean.");
goto bad_flag;
}
- return make_concat (expr, make_const_data (buf, 1, 0, 1));
+ if (!make_const_data (&t, buf, 1, 0, 1))
+ return 0;
break;
+
default:
warn ("Bad format %c in parse_option_param.",
*fmt);
skip_to_semi (cfile);
- return (struct expression *)0;
+ return 0;
}
+ if (expr) {
+ if (!make_concat (rv, expr, t))
+ return 0;
+ expression_dereference (&t, "parse_option_token");
+ } else
+ *rv = t;
+ return 1;
}