From 02a015fb469a4b167ecc329d4ab1bc719c34a90f Mon Sep 17 00:00:00 2001 From: Ted Lemon Date: Thu, 5 Nov 1998 18:43:23 +0000 Subject: [PATCH] Fix up all the option handling code to use evaluation instead of fixed data. --- client/clparse.c | 171 ++++++----- client/dhclient.c | 731 ++++++++++++++++++++++---------------------- common/parse.c | 754 +++++++++++++++++++++++++++++----------------- 3 files changed, 923 insertions(+), 733 deletions(-) diff --git a/client/clparse.c b/client/clparse.c index 5b7003720..28f448210 100644 --- a/client/clparse.c +++ b/client/clparse.c @@ -42,7 +42,7 @@ #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" @@ -52,6 +52,17 @@ static TIME parsed_time; 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 :== | client-declaration @@ -84,32 +95,8 @@ int read_client_conf () 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 { @@ -144,12 +131,6 @@ int read_client_conf () 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; } @@ -215,19 +196,17 @@ void parse_client_statement (cfile, ip, 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)) @@ -271,14 +250,11 @@ void parse_client_statement (cfile, ip, config) 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: @@ -390,13 +366,14 @@ int parse_X (cfile, buf, max) /* 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 { @@ -404,7 +381,7 @@ int parse_option_list (cfile, list) 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)) @@ -413,22 +390,42 @@ int parse_option_list (cfile, list) 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 :== @@ -589,7 +586,7 @@ void parse_client_lease_statement (cfile, is_static) /* 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; } @@ -616,7 +613,7 @@ void parse_client_lease_statement (cfile, is_static) pl -> next = lp -> next; else ip -> client -> leases = lp -> next; - free_client_lease (lp); + destroy_client_lease (lp); break; } } @@ -642,13 +639,13 @@ void parse_client_lease_statement (cfile, is_static) 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; @@ -680,6 +677,7 @@ void parse_client_lease_declaration (cfile, lease, ipp) char *val; char *t, *n; struct interface_info *ip; + struct option_cache *oc; switch (next_token (&val, cfile)) { case BOOTP: @@ -727,7 +725,14 @@ void parse_client_lease_declaration (cfile, lease, ipp) 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: @@ -742,9 +747,9 @@ void parse_client_lease_declaration (cfile, lease, ipp) } } -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; @@ -757,10 +762,11 @@ struct option *parse_option_decl (cfile, options) 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 { @@ -784,14 +790,14 @@ struct option *parse_option_decl (cfile, options) 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; @@ -800,7 +806,7 @@ struct option *parse_option_decl (cfile, options) 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; @@ -809,7 +815,7 @@ struct option *parse_option_decl (cfile, options) parse_warn ("option data buffer %s", "overflow"); skip_to_semi (cfile); - return (struct option *)0; + return 0; } memcpy (&hunkbuf [hunkix], dp, len); hunkix += len; @@ -823,7 +829,7 @@ struct option *parse_option_decl (cfile, options) 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; @@ -857,7 +863,7 @@ struct option *parse_option_decl (cfile, options) bad_flag: if (token != SEMI) skip_to_semi (cfile); - return (struct option *)0; + return 0; } if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) @@ -877,7 +883,7 @@ struct option *parse_option_decl (cfile, options) warn ("Bad format %c in parse_option_param.", *fmt); skip_to_semi (cfile); - return (struct option *)0; + return 0; } } token = next_token (&val, cfile); @@ -886,16 +892,25 @@ struct option *parse_option_decl (cfile, options) 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) diff --git a/client/dhclient.c b/client/dhclient.c index 785c9148e..0a9893cc7 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -56,7 +56,7 @@ #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" @@ -259,6 +259,25 @@ void cleanup () { } +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 @@ -389,7 +408,7 @@ void state_selecting (ipp) picked -> next = (struct client_lease *)0; } else { freeit: - free_client_lease (lp); + destroy_client_lease (lp); } } ip -> client -> offered_leases = (struct client_lease *)0; @@ -403,7 +422,7 @@ void state_selecting (ipp) } /* 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 @@ -430,7 +449,7 @@ void state_selecting (ipp) 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); @@ -444,6 +463,8 @@ void dhcpack (packet) { 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 @@ -479,26 +500,63 @@ void dhcpack (packet) 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 + @@ -537,7 +595,7 @@ void bind_lease (ip) /* 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; @@ -562,6 +620,9 @@ void state_bound (ipp) void *ipp; { struct interface_info *ip = ipp; + int i; + struct option_cache *oc; + struct data_string ds; ASSERT_STATE(state, S_BOUND); @@ -569,12 +630,17 @@ void state_bound (ipp) 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; @@ -671,9 +737,9 @@ void dhcpoffer (packet) 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); @@ -696,11 +762,15 @@ void dhcpoffer (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; + } } } @@ -723,7 +793,7 @@ void dhcpoffer (packet) /* 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. */ @@ -797,8 +867,10 @@ struct client_lease *packet_to_lease (packet) { 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"); @@ -808,45 +880,38 @@ struct client_lease *packet_to_lease (packet) 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, @@ -856,18 +921,16 @@ struct client_lease *packet_to_lease (packet) } /* 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, @@ -909,7 +972,7 @@ void dhcpnak (packet) return; } - free_client_lease (ip -> client -> active); + destroy_client_lease (ip -> client -> active); ip -> client -> active = (struct client_lease *)0; /* Stop sending DHCPREQUEST packets... */ @@ -1317,74 +1380,124 @@ void send_release (ipp) 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; @@ -1420,78 +1533,30 @@ void make_request (ip, lease) { 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; @@ -1535,62 +1600,22 @@ void make_decline (ip, lease) { 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; @@ -1626,37 +1651,22 @@ void make_release (ip, lease) { 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; @@ -1685,20 +1695,17 @@ void make_release (ip, lease) #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; @@ -1744,6 +1751,8 @@ void write_client_lease (ip, lease, rewrite) int i; struct tm *t; static int leases_written; + struct option_cache *oc; + struct data_string ds; if (!rewrite) { if (leases_written++ > 20) { @@ -1778,14 +1787,21 @@ void write_client_lease (ip, lease, rewrite) 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"); + } } } @@ -1863,8 +1879,8 @@ void script_write_params (ip, prefix, 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)); @@ -1877,33 +1893,45 @@ void script_write_params (ip, prefix, lease) 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"); + } } } } @@ -1919,84 +1947,33 @@ void script_write_params (ip, prefix, lease) 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", diff --git a/common/parse.c b/common/parse.c index ece7e7002..251eb0095 100644 --- a/common/parse.c +++ b/common/parse.c @@ -42,7 +42,7 @@ #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" @@ -65,7 +65,7 @@ static char copyright[] = void skip_to_semi (cfile) FILE *cfile; { - int token; + enum dhcp_token token; char *val; int brace_count = 0; @@ -97,7 +97,7 @@ void skip_to_semi (cfile) int parse_semi (cfile) FILE *cfile; { - int token; + enum dhcp_token token; char *val; token = next_token (&val, cfile); @@ -115,7 +115,7 @@ char *parse_string (cfile) FILE *cfile; { char *val; - int token; + enum dhcp_token token; char *s; token = next_token (&val, cfile); @@ -144,7 +144,7 @@ char *parse_host_name (cfile) FILE *cfile; { char *val; - int token; + enum dhcp_token token; int len = 0; char *s; char *t; @@ -198,29 +198,36 @@ char *parse_host_name (cfile) 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); @@ -228,10 +235,10 @@ struct expression *parse_ip_addr_or_hostname (cfile, uniform) val, token); if (token != SEMI) skip_to_semi (cfile); - return (struct expression *)0; + return 0; } - return rv; + return 1; } /* @@ -243,7 +250,7 @@ int parse_ip_addr (cfile, addr) struct iaddr *addr; { char *val; - int token; + enum dhcp_token token; addr -> len = 4; if (parse_numeric_aggregate (cfile, addr -> iabuf, @@ -262,7 +269,7 @@ void parse_hardware_param (cfile, hardware) struct hardware *hardware; { char *val; - int token; + enum dhcp_token token; int hlen; unsigned char *t; @@ -316,7 +323,7 @@ void parse_lease_time (cfile, timep) TIME *timep; { char *val; - int token; + enum dhcp_token token; token = next_token (&val, cfile); if (token != NUMBER) { @@ -348,7 +355,7 @@ unsigned char *parse_numeric_aggregate (cfile, buf, int size; { char *val; - int token; + enum dhcp_token token; unsigned char *bufp = buf, *s, *t; int count = 0; pair c = (pair)0; @@ -547,7 +554,7 @@ TIME parse_date (cfile) 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 }; @@ -709,7 +716,7 @@ struct option *parse_option_name (cfile) FILE *cfile; { char *val; - int token; + enum dhcp_token token; char *vendor; struct universe *universe; struct option *option; @@ -783,18 +790,18 @@ struct option *parse_option_name (cfile) * 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); @@ -805,7 +812,7 @@ unsigned char *parse_cshl (cfile, plen) next = sl -> next; dfree (sl, "parse_cshl"); } - return (unsigned char *)0; + return 0; } if (ilen == sizeof ibuf) { next = (struct option_tag *) @@ -828,10 +835,13 @@ unsigned char *parse_cshl (cfile, plen) 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); @@ -841,8 +851,7 @@ unsigned char *parse_cshl (cfile, plen) } memcpy (rvp, ibuf, ilen); - *plen = ilen + tlen; - return rv; + return 1; } /* @@ -868,7 +877,7 @@ struct executable_statement *parse_executable_statements (cfile, lose) next = &head; while ((*next = parse_executable_statement (cfile, lose))) next = &((*next) -> next); - if (!lose) + if (!*lose) return head; return (struct executable_statement *)0; } @@ -877,7 +886,7 @@ struct executable_statement *parse_executable_statement (cfile, lose) FILE *cfile; int *lose; { - int token; + enum dhcp_token token; char *val; struct executable_statement *stmt, base; struct class *cta; @@ -989,19 +998,22 @@ struct executable_statement *parse_if_statement (cfile, lose) 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."); @@ -1066,18 +1078,95 @@ struct executable_statement *parse_if_statement (cfile, lose) * 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); @@ -1090,7 +1179,7 @@ struct expression *parse_boolean_expression (cfile, lose) 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)) @@ -1098,150 +1187,102 @@ struct expression *parse_boolean_expression (cfile, lose) 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); @@ -1249,201 +1290,331 @@ struct expression *parse_data_expression (cfile, lose) 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 SEMI | identifier SEMI @@ -1459,32 +1630,21 @@ struct executable_statement *parse_option_statement (cfile, lookups, 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., @@ -1495,8 +1655,16 @@ struct executable_statement *parse_option_statement (cfile, lookups, 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); @@ -1508,6 +1676,19 @@ struct executable_statement *parse_option_statement (cfile, lookups, } } 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) { @@ -1517,12 +1698,16 @@ struct executable_statement *parse_option_statement (cfile, lookups, } 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; @@ -1530,8 +1715,8 @@ struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups) 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; @@ -1541,21 +1726,20 @@ struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups) 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; @@ -1565,24 +1749,23 @@ struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups) 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... */ @@ -1593,27 +1776,33 @@ struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups) 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)) { @@ -1621,7 +1810,7 @@ struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups) bad_flag: if (token != SEMI) skip_to_semi (cfile); - return (struct expression *)0; + return 0; } if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) @@ -1633,12 +1822,21 @@ struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups) 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; } -- 2.47.3