summaryrefslogtreecommitdiffstats
path: root/contrib/isc-dhcp/client/dhclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/isc-dhcp/client/dhclient.c')
-rw-r--r--contrib/isc-dhcp/client/dhclient.c3061
1 files changed, 1955 insertions, 1106 deletions
diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c
index 129f99a..f1c0ddd 100644
--- a/contrib/isc-dhcp/client/dhclient.c
+++ b/contrib/isc-dhcp/client/dhclient.c
@@ -3,8 +3,8 @@
DHCP Client. */
/*
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
+ * Copyright (c) 1995-2001 Internet Software Consortium.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -15,7 +15,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
+ * 3. Neither the name of Internet Software Consortium nor the names
* of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -33,30 +33,15 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- *
- * This client was substantially modified and enhanced by Elliot Poger
- * for use on Linux while he was working on the MosquitoNet project at
- * Stanford.
- *
- * The current version owes much to Elliot's Linux enhancements, but
- * was substantially reorganized and partially rewritten by Ted Lemon
- * so as to use the same networking framework that the Internet Software
- * Consortium DHCP server uses. Much system-specific configuration code
- * was moved into a shell script so that as support for more operating
- * systems is added, it will not be necessary to port and maintain
- * system-specific configuration code to these operating systems - instead,
- * the shell script can invoke the native tools to accomplish the same
- * purpose.
+ * This code is based on the original client state machine that was
+ * written by Elliot Poger. The code has been extensively hacked on
+ * by Ted Lemon since then, so any mistakes you find are probably his
+ * fault and not Elliot's.
*/
#ifndef lint
static char ocopyright[] =
-"$Id: dhclient.c,v 1.44.2.47 2000/09/06 20:59:09 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.129.2.7 2001/08/08 14:46:14 mellon Exp $ Copyright (c) 1995-2001 Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -65,39 +50,44 @@ static char ocopyright[] =
TIME cur_time;
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
-struct tree_cache *global_options [256];
-char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
-char *path_dhclient_db = _PATH_DHCLIENT_DB;
-char *path_dhclient_pid = _PATH_DHCLIENT_PID;
+const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
+const char *path_dhclient_db = _PATH_DHCLIENT_DB;
+const char *path_dhclient_pid = _PATH_DHCLIENT_PID;
+static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT;
+char *path_dhclient_script = path_dhclient_script_array;
-int interfaces_requested = 0;
+int dhcp_max_agent_option_packet_length = 0;
-int log_perror = 1;
+int interfaces_requested = 0;
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
struct in_addr inaddr_any;
struct sockaddr_in sockaddr_broadcast;
+struct in_addr giaddr;
/* ASSERT_STATE() does nothing now; it used to be
assert (state_is == state_shouldbe). */
#define ASSERT_STATE(state_is, state_shouldbe) {}
+static char copyright[] = "Copyright 1995-2001 Internet Software Consortium.";
+static char arr [] = "All rights reserved.";
+static char message [] = "Internet Software Consortium DHCP Client";
+static char url [] = "For info, please visit http://www.isc.org/products/DHCP";
+
u_int16_t local_port;
u_int16_t remote_port;
-int log_priority;
int no_daemon;
-int save_scripts;
+struct string_list *client_env;
+int client_env_count;
+int onetry;
+int quiet;
+int nowait;
-static char copyright[] =
-"Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.";
-static char arr [] = "All rights reserved.";
-static char message [] = "Internet Software Consortium DHCP Client";
-static char contrib [] = "Please contribute if you find this software useful.";
-static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html";
+static void usage PROTO ((void));
-static void usage PROTO ((char *));
+void do_release(struct client_state *);
int main (argc, argv, envp)
int argc;
@@ -106,105 +96,242 @@ int main (argc, argv, envp)
int i;
struct servent *ent;
struct interface_info *ip;
- int seed;
- int quiet = 0;
+ struct client_state *client;
+ unsigned seed;
+ char *server = (char *)0;
+ char *relay = (char *)0;
+ isc_result_t status;
+ int release_mode = 0;
+ omapi_object_t *listener;
+ isc_result_t result;
+ int persist = 0;
+ int omapi_port;
+ int no_dhclient_conf = 0;
+ int no_dhclient_db = 0;
+ int no_dhclient_pid = 0;
+ int no_dhclient_script = 0;
char *s;
- s = strrchr (argv [0], '/');
- if (!s)
- s = argv [0];
- else
- s++;
+ /* Make sure we have stdin, stdout and stderr. */
+ i = open ("/dev/null", O_RDWR);
+ if (i == 0)
+ i = open ("/dev/null", O_RDWR);
+ if (i == 1) {
+ i = open ("/dev/null", O_RDWR);
+ log_perror = 0; /* No sense logging to /dev/null. */
+ } else if (i != -1)
+ close (i);
- /* Initially, log errors to stderr as well as to syslogd. */
#ifdef SYSLOG_4_2
- openlog (s, LOG_NDELAY);
- log_priority = DHCPD_LOG_FACILITY;
+ openlog ("dhclient", LOG_NDELAY);
+ log_priority = LOG_DAEMON;
#else
- openlog (s, LOG_NDELAY, DHCPD_LOG_FACILITY);
+ openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
#endif
#if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
setlogmask (LOG_UPTO (LOG_INFO));
#endif
+ /* Set up the OMAPI. */
+ status = omapi_init ();
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't initialize OMAPI: %s",
+ isc_result_totext (status));
+
+ /* Set up the OMAPI wrappers for various server database internal
+ objects. */
+ dhcp_common_objects_setup ();
+
+ dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
+ dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
+ dhcp_interface_startup_hook = dhclient_interface_startup_hook;
+
for (i = 1; i < argc; i++) {
- if (!strcmp (argv [i], "-p")) {
+ if (!strcmp (argv [i], "-r")) {
+ release_mode = 1;
+ no_daemon = 1;
+ } else if (!strcmp (argv [i], "-p")) {
if (++i == argc)
- usage (s);
+ usage ();
local_port = htons (atoi (argv [i]));
- debug ("binding to user-specified port %d",
+ log_debug ("binding to user-specified port %d",
ntohs (local_port));
} else if (!strcmp (argv [i], "-d")) {
no_daemon = 1;
- } else if (!strcmp (argv [i], "-D")) {
- save_scripts = 1;
- } else if (!strcmp (argv [i], "-cf")) {
+ } else if (!strcmp (argv [i], "-pf")) {
+ if (++i == argc)
+ usage ();
+ path_dhclient_pid = argv [i];
+ no_dhclient_pid = 1;
+ } else if (!strcmp (argv [i], "-cf")) {
+ if (++i == argc)
+ usage ();
+ path_dhclient_conf = argv [i];
+ no_dhclient_conf = 1;
+ } else if (!strcmp (argv [i], "-lf")) {
+ if (++i == argc)
+ usage ();
+ path_dhclient_db = argv [i];
+ no_dhclient_db = 1;
+ } else if (!strcmp (argv [i], "-sf")) {
if (++i == argc)
- usage (s);
- path_dhclient_conf = argv [i];
- } else if (!strcmp (argv [i], "-pf")) {
- if (++i == argc)
- usage (s);
- path_dhclient_pid = argv [i];
- } else if (!strcmp (argv [i], "-lf")) {
- if (++i == argc)
- usage (s);
- path_dhclient_db = argv [i];
+ usage ();
+ path_dhclient_script = argv [i];
+ no_dhclient_script = 1;
+ } else if (!strcmp (argv [i], "-1")) {
+ onetry = 1;
} else if (!strcmp (argv [i], "-q")) {
quiet = 1;
quiet_interface_discovery = 1;
+ } else if (!strcmp (argv [i], "-s")) {
+ if (++i == argc)
+ usage ();
+ server = argv [i];
+ } else if (!strcmp (argv [i], "-g")) {
+ if (++i == argc)
+ usage ();
+ relay = argv [i];
+ } else if (!strcmp (argv [i], "-n")) {
+ /* do not start up any interfaces */
+ interfaces_requested = 1;
+ } else if (!strcmp (argv [i], "-w")) {
+ /* do not exit if there are no broadcast interfaces. */
+ persist = 1;
} else if (argv [i][0] == '-') {
- usage (s);
+ usage ();
+ } else if (!strcmp (argv [i], "-e")) {
+ struct string_list *tmp;
+ if (++i == argc)
+ usage ();
+ tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL);
+ if (!tmp)
+ log_fatal ("No memory for %s", argv [i]);
+ strcpy (tmp -> string, argv [i]);
+ tmp -> next = client_env;
+ client_env = tmp;
+ client_env_count++;
+ } else if (!strcmp (argv [i], "--version")) {
+ log_info ("isc-dhclient-%s", DHCP_VERSION);
+ exit (0);
+ } else if (!strcmp (argv [i], "-nw")) {
+ nowait = 1;
} else {
- struct interface_info *tmp =
- ((struct interface_info *)
- dmalloc (sizeof *tmp, "specified_interface"));
- if (!tmp)
- error ("Insufficient memory to %s %s",
- "record interface", argv [i]);
- memset (tmp, 0, sizeof *tmp);
+ struct interface_info *tmp = (struct interface_info *)0;
+ status = interface_allocate (&tmp, MDL);
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't record interface %s:%s",
+ argv [i], isc_result_totext (status));
+ if (strlen (argv [i]) > sizeof tmp -> name)
+ log_fatal ("%s: interface name too long (max %ld)",
+ argv [i], (long)strlen (argv [i]));
strcpy (tmp -> name, argv [i]);
- tmp -> next = interfaces;
+ if (interfaces) {
+ interface_reference (&tmp -> next,
+ interfaces, MDL);
+ interface_dereference (&interfaces, MDL);
+ }
+ interface_reference (&interfaces, tmp, MDL);
tmp -> flags = INTERFACE_REQUESTED;
interfaces_requested = 1;
- interfaces = tmp;
}
}
+ if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
+ path_dhclient_conf = s;
+ }
+ if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) {
+ path_dhclient_db = s;
+ }
+ if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) {
+ path_dhclient_pid = s;
+ }
+ if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) {
+ path_dhclient_script = s;
+ }
+
+ /* first kill of any currently running client */
+ if (release_mode) {
+ /* XXX inelegant hack to prove concept */
+ char command[1024];
+
+#if !defined (NO_SNPRINTF)
+ snprintf (command, 1024, "kill `cat %s`", path_dhclient_pid);
+#else
+ sprintf (command, "kill `cat %s`", path_dhclient_pid);
+#endif
+ system (command);
+ }
+
if (!quiet) {
- note ("%s %s", message, DHCP_VERSION);
- note (copyright);
- note (arr);
- note ("");
- note (contrib);
- note (url);
- note ("");
+ log_info ("%s %s", message, DHCP_VERSION);
+ log_info (copyright);
+ log_info (arr);
+ log_info (url);
+ log_info ("%s", "");
} else
log_perror = 0;
+ /* If we're given a relay agent address to insert, for testing
+ purposes, figure out what it is. */
+ if (relay) {
+ if (!inet_aton (relay, &giaddr)) {
+ struct hostent *he;
+ he = gethostbyname (relay);
+ if (he) {
+ memcpy (&giaddr, he -> h_addr_list [0],
+ sizeof giaddr);
+ } else {
+ log_fatal ("%s: no such host", relay);
+ }
+ }
+ }
+
/* Default to the DHCP/BOOTP port. */
if (!local_port) {
- ent = getservbyname ("dhcpc", "udp");
- if (!ent)
- local_port = htons (68);
- else
- local_port = ent -> s_port;
+ if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
+ local_port = htons (67);
+ } else {
+ ent = getservbyname ("dhcpc", "udp");
+ if (!ent)
+ local_port = htons (68);
+ else
+ local_port = ent -> s_port;
#ifndef __CYGWIN32__
- endservent ();
+ endservent ();
#endif
+ }
}
- remote_port = htons (ntohs (local_port) - 1); /* XXX */
+
+ /* If we're faking a relay agent, and we're not using loopback,
+ use the server port, not the client port. */
+ if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
+ local_port = htons (ntohs (local_port) - 1);
+ remote_port = local_port;
+ } else
+ remote_port = htons (ntohs (local_port) - 1); /* XXX */
/* Get the current time... */
GET_TIME (&cur_time);
sockaddr_broadcast.sin_family = AF_INET;
sockaddr_broadcast.sin_port = remote_port;
- sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
-#ifdef HAVE_SA_LEN
- sockaddr_broadcast.sin_len = sizeof sockaddr_broadcast;
-#endif
+ if (server) {
+ if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) {
+ struct hostent *he;
+ he = gethostbyname (server);
+ if (he) {
+ memcpy (&sockaddr_broadcast.sin_addr,
+ he -> h_addr_list [0],
+ sizeof sockaddr_broadcast.sin_addr);
+ } else
+ sockaddr_broadcast.sin_addr.s_addr =
+ INADDR_BROADCAST;
+ }
+ } else {
+ sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
+ }
+
inaddr_any.s_addr = INADDR_ANY;
/* Discover all the network interfaces. */
@@ -219,17 +346,26 @@ int main (argc, argv, envp)
/* Rewrite the lease database... */
rewrite_client_leases ();
+ /* XXX */
+/* config_counter(&snd_counter, &rcv_counter); */
+
/* If no broadcast interfaces were discovered, call the script
and tell it so. */
if (!interfaces) {
- script_init ((struct interface_info *)0, "NBI",
+ /* Call dhclient-script with the NBI flag, in case somebody
+ cares. */
+ script_init ((struct client_state *)0, "NBI",
(struct string_list *)0);
- script_go ((struct interface_info *)0);
-
- note ("No broadcast interfaces found - exiting.");
- /* Nothing more to do. */
- exit (0);
- } else {
+ script_go ((struct client_state *)0);
+
+ /* If we haven't been asked to persist, waiting for new
+ interfaces, then just exit. */
+ if (!persist) {
+ /* Nothing more to do. */
+ log_info ("No broadcast interfaces found - exiting.");
+ exit (0);
+ }
+ } else if (!release_mode) {
/* Call the script with the list of interfaces. */
for (ip = interfaces; ip; ip = ip -> next) {
/* If interfaces were specified, don't configure
@@ -239,11 +375,12 @@ int main (argc, argv, envp)
INTERFACE_AUTOMATIC)) !=
INTERFACE_REQUESTED))
continue;
- script_init (ip, "PREINIT", (struct string_list *)0);
+ script_init (ip -> client,
+ "PREINIT", (struct string_list *)0);
if (ip -> client -> alias)
- script_write_params (ip, "alias_",
+ script_write_params (ip -> client, "alias_",
ip -> client -> alias);
- script_go (ip);
+ script_go (ip -> client);
}
}
@@ -260,25 +397,71 @@ int main (argc, argv, envp)
interface's hardware address interpreted as an integer.
Not much entropy, but we're booting, so we're not likely to
find anything better. */
- seed = 0; /* Unfortunately, what's on the stack isn't random. :') */
+ seed = 0;
for (ip = interfaces; ip; ip = ip -> next) {
int junk;
memcpy (&junk,
- &ip -> hw_address.haddr [ip -> hw_address.hlen -
- sizeof seed], sizeof seed);
+ &ip -> hw_address.hbuf [ip -> hw_address.hlen -
+ sizeof seed], sizeof seed);
seed += junk;
}
srandom (seed + cur_time);
/* Start a configuration state machine for each interface. */
for (ip = interfaces; ip; ip = ip -> next) {
- ip -> client -> state = S_INIT;
- state_reboot (ip);
+ ip -> flags |= INTERFACE_RUNNING;
+ for (client = ip -> client; client; client = client -> next) {
+ if (release_mode)
+ do_release (client);
+ else {
+ client -> state = S_INIT;
+ /* Set up a timeout to start the initialization
+ process. */
+ add_timeout (cur_time + random () % 5,
+ state_reboot, client, 0, 0);
+ }
+ }
+ }
+
+ if (release_mode)
+ return 0;
+
+ /* Start up a listener for the object management API protocol. */
+ if (top_level_config.omapi_port != -1) {
+ listener = (omapi_object_t *)0;
+ result = omapi_generic_new (&listener, MDL);
+ if (result != ISC_R_SUCCESS)
+ log_fatal ("Can't allocate new generic object: %s\n",
+ isc_result_totext (result));
+ result = omapi_protocol_listen (listener,
+ (unsigned)
+ top_level_config.omapi_port,
+ 1);
+ if (result != ISC_R_SUCCESS)
+ log_fatal ("Can't start OMAPI protocol: %s",
+ isc_result_totext (result));
}
/* Set up the bootp packet handler... */
bootp_packet_handler = do_packet;
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ dmalloc_cutoff_generation = dmalloc_generation;
+ dmalloc_longterm = dmalloc_outstanding;
+ dmalloc_outstanding = 0;
+#endif
+
+ /* If we're not supposed to wait before getting the address,
+ don't. */
+ if (nowait)
+ go_daemon ();
+
+ /* If we're not going to daemonize, write the pid file
+ now. */
+ if (no_daemon || nowait)
+ write_client_pid_file ();
+
/* Start dispatching packets and timeouts... */
dispatch ();
@@ -286,23 +469,51 @@ int main (argc, argv, envp)
return 0;
}
-static void usage (appname)
- char *appname;
+static void usage ()
+{
+ log_info ("%s %s", message, DHCP_VERSION);
+ log_info (copyright);
+ log_info (arr);
+ log_info (url);
+
+ log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s",
+ "[-s server]");
+ log_error (" [-cf config-file] [-lf lease-file]%s",
+ "[-pf pid-file] [-e VAR=val]");
+ log_fatal (" [-sf script-file] [interface]");
+}
+
+isc_result_t find_class (struct class **c,
+ const char *s, const char *file, int line)
{
- note (message);
- note (copyright);
- note (arr);
- note ("");
- note (contrib);
- note (url);
- note ("");
-
- warn ("Usage: %s [-c] [-p <port>] [-lf lease-file]", appname);
- error (" [-pf pidfile] [interface]");
+ return 0;
}
-void cleanup ()
+int check_collection (packet, lease, collection)
+ struct packet *packet;
+ struct lease *lease;
+ struct collection *collection;
{
+ return 0;
+}
+
+void classify (packet, class)
+ struct packet *packet;
+ struct class *class;
+{
+}
+
+int unbill_class (lease, class)
+ struct lease *lease;
+ struct class *class;
+{
+ return 0;
+}
+
+int find_subnet (struct subnet **sp,
+ struct iaddr addr, const char *file, int line)
+{
+ return 0;
}
/* Individual States:
@@ -334,152 +545,141 @@ void cleanup ()
* can no longer legitimately use the lease.
*/
-void state_reboot (ipp)
- void *ipp;
+void state_reboot (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
/* If we don't remember an active lease, go straight to INIT. */
- if (!ip -> client -> active ||
- ip -> client -> active -> is_bootp) {
- state_init (ip);
+ if (!client -> active ||
+ client -> active -> is_bootp ||
+ client -> active -> expiry <= cur_time) {
+ state_init (client);
return;
}
/* We are in the rebooting state. */
- ip -> client -> state = S_REBOOTING;
+ client -> state = S_REBOOTING;
/* make_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */
- ip -> client -> xid = random ();
+ client -> xid = random ();
/* Make a DHCPREQUEST packet, and set appropriate per-interface
flags. */
- make_request (ip, ip -> client -> active);
- ip -> client -> destination = iaddr_broadcast;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
+ make_request (client, client -> active);
+ client -> destination = iaddr_broadcast;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
/* Zap the medium list... */
- ip -> client -> medium = (struct string_list *)0;
+ client -> medium = (struct string_list *)0;
/* Send out the first DHCPREQUEST packet. */
- send_request (ip);
+ send_request (client);
}
/* Called when a lease has completely expired and we've been unable to
renew it. */
-void state_init (ipp)
- void *ipp;
+void state_init (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
ASSERT_STATE(state, S_INIT);
/* Make a DHCPDISCOVER packet, and set appropriate per-interface
flags. */
- make_discover (ip, ip -> client -> active);
- ip -> client -> xid = ip -> client -> packet.xid;
- ip -> client -> destination = iaddr_broadcast;
- ip -> client -> state = S_SELECTING;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
+ make_discover (client, client -> active);
+ client -> xid = client -> packet.xid;
+ client -> destination = iaddr_broadcast;
+ client -> state = S_SELECTING;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
/* Add an immediate timeout to cause the first DHCPDISCOVER packet
to go out. */
- send_discover (ip);
+ send_discover (client);
}
/* state_selecting is called when one or more DHCPOFFER packets have been
received and a configurable period of time has passed. */
-void state_selecting (ipp)
- void *ipp;
+void state_selecting (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
-
+ struct client_state *client = cpp;
struct client_lease *lp, *next, *picked;
+
ASSERT_STATE(state, S_SELECTING);
/* Cancel state_selecting and send_discover timeouts, since either
one could have got us here. */
- cancel_timeout (state_selecting, ip);
- cancel_timeout (send_discover, ip);
+ cancel_timeout (state_selecting, client);
+ cancel_timeout (send_discover, client);
/* We have received one or more DHCPOFFER packets. Currently,
the only criterion by which we judge leases is whether or
not we get a response when we arp for them. */
picked = (struct client_lease *)0;
- for (lp = ip -> client -> offered_leases; lp; lp = next) {
+ for (lp = client -> offered_leases; lp; lp = next) {
next = lp -> next;
/* Check to see if we got an ARPREPLY for the address
in this particular lease. */
if (!picked) {
- script_init (ip, "ARPCHECK", lp -> medium);
- script_write_params (ip, "check_", lp);
-
- /* If the ARPCHECK code detects another
- machine using the offered address, it exits
- nonzero. We need to send a DHCPDECLINE and
- toss the lease. */
- if (script_go (ip)) {
- make_decline (ip, lp);
- send_decline (ip);
- goto freeit;
- }
picked = lp;
picked -> next = (struct client_lease *)0;
} else {
freeit:
- free_client_lease (lp);
+ destroy_client_lease (lp);
}
}
- ip -> client -> offered_leases = (struct client_lease *)0;
+ client -> offered_leases = (struct client_lease *)0;
/* If we just tossed all the leases we were offered, go back
to square one. */
if (!picked) {
- ip -> client -> state = S_INIT;
- state_init (ip);
+ client -> state = S_INIT;
+ state_init (client);
return;
}
/* If it was a BOOTREPLY, we can just take the address right now. */
- if (!picked -> options [DHO_DHCP_MESSAGE_TYPE].len) {
- ip -> client -> new = picked;
+ if (picked -> is_bootp) {
+ client -> new = picked;
/* Make up some lease expiry times
XXX these should be configurable. */
- ip -> client -> new -> expiry = cur_time + 12000;
- ip -> client -> new -> renewal += cur_time + 8000;
- ip -> client -> new -> rebind += cur_time + 10000;
+ client -> new -> expiry = cur_time + 12000;
+ client -> new -> renewal += cur_time + 8000;
+ client -> new -> rebind += cur_time + 10000;
- ip -> client -> state = S_REQUESTING;
+ client -> state = S_REQUESTING;
/* Bind to the address we received. */
- bind_lease (ip);
+ bind_lease (client);
return;
}
/* Go to the REQUESTING state. */
- ip -> client -> destination = iaddr_broadcast;
- ip -> client -> state = S_REQUESTING;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
+ client -> destination = iaddr_broadcast;
+ client -> state = S_REQUESTING;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
/* Make a DHCPREQUEST packet from the lease we picked. */
- make_request (ip, picked);
- ip -> client -> xid = ip -> client -> packet.xid;
+ make_request (client, picked);
+ client -> xid = 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);
+ send_request (client);
}
/* state_requesting is called when we receive a DHCPACK message after
@@ -489,128 +689,200 @@ void dhcpack (packet)
struct packet *packet;
{
struct interface_info *ip = packet -> interface;
+ struct client_state *client;
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
has an unrecognizable transaction id, then just drop it. */
- if (packet -> interface -> client -> xid != packet -> raw -> xid ||
- (packet -> interface -> hw_address.hlen !=
+ for (client = ip -> client; client; client = client -> next) {
+ if (client -> xid == packet -> raw -> xid)
+ break;
+ }
+ if (!client ||
+ (packet -> interface -> hw_address.hlen - 1 !=
packet -> raw -> hlen) ||
- (memcmp (packet -> interface -> hw_address.haddr,
+ (memcmp (&packet -> interface -> hw_address.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
- debug ("DHCPACK in wrong transaction.");
+ log_debug ("DHCPACK in wrong transaction.");
#endif
return;
}
- if (ip -> client -> state != S_REBOOTING &&
- ip -> client -> state != S_REQUESTING &&
- ip -> client -> state != S_RENEWING &&
- ip -> client -> state != S_REBINDING) {
+ if (client -> state != S_REBOOTING &&
+ client -> state != S_REQUESTING &&
+ client -> state != S_RENEWING &&
+ client -> state != S_REBINDING) {
#if defined (DEBUG)
- debug ("DHCPACK in wrong state.");
+ log_debug ("DHCPACK in wrong state.");
#endif
return;
}
- note ("DHCPACK from %s", piaddr (packet -> client_addr));
+ log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
- lease = packet_to_lease (packet);
+ lease = packet_to_lease (packet, client);
if (!lease) {
- note ("packet_to_lease failed.");
+ log_info ("packet_to_lease failed.");
return;
}
- ip -> client -> new = lease;
+ client -> new = lease;
/* Stop resending DHCPREQUEST. */
- cancel_timeout (send_request, ip);
+ cancel_timeout (send_request, client);
/* Figure out the lease time. */
- ip -> client -> new -> expiry =
- getULong (ip -> client ->
- new -> options [DHO_DHCP_LEASE_TIME].data);
+ oc = lookup_option (&dhcp_universe, client -> new -> options,
+ DHO_DHCP_LEASE_TIME);
+ memset (&ds, 0, sizeof ds);
+ if (oc &&
+ evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+ packet -> options, client -> new -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3)
+ client -> new -> expiry = getULong (ds.data);
+ else
+ client -> new -> expiry = 0;
+ data_string_forget (&ds, MDL);
+ } else
+ client -> new -> expiry = 0;
+
+ if (!client -> new -> expiry) {
+ log_error ("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 (client);
+ return;
+ }
+
/* A number that looks negative here is really just very large,
because the lease expiry offset is unsigned. */
- if (ip -> client -> new -> expiry < 0)
- ip -> client -> new -> expiry = TIME_MAX;
-
- /* 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
- ip -> client -> new -> renewal =
- ip -> client -> new -> expiry / 2;
+ if (client -> new -> expiry < 0)
+ client -> new -> expiry = TIME_MAX;
+ /* Take the server-provided renewal time if there is one. */
+ oc = lookup_option (&dhcp_universe, client -> new -> options,
+ DHO_DHCP_RENEWAL_TIME);
+ if (oc &&
+ evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+ packet -> options, client -> new -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3)
+ client -> new -> renewal = getULong (ds.data);
+ else
+ client -> new -> renewal = 0;
+ data_string_forget (&ds, MDL);
+ } else
+ client -> new -> renewal = 0;
+
+ /* If it wasn't specified by the server, calculate it. */
+ if (!client -> new -> renewal)
+ client -> new -> renewal =
+ client -> new -> expiry / 2;
+
+ /* Now introduce some randomness to the renewal time: */
+ client -> new -> renewal = (((client -> new -> renewal + 3) * 3 / 4) +
+ (random () % /* XXX NUMS */
+ ((client -> new -> renewal + 3) / 4)));
/* 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
- ip -> client -> new -> rebind =
- ip -> client -> new -> renewal +
- ip -> client -> new -> renewal / 2 +
- ip -> client -> new -> renewal / 4;
+ oc = lookup_option (&dhcp_universe, client -> new -> options,
+ DHO_DHCP_REBINDING_TIME);
+ if (oc &&
+ evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+ packet -> options, client -> new -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3)
+ client -> new -> rebind = getULong (ds.data);
+ else
+ client -> new -> rebind = 0;
+ data_string_forget (&ds, MDL);
+ } else
+ client -> new -> rebind = 0;
+
+ if (!client -> new -> rebind)
+ client -> new -> rebind =
+ (client -> new -> expiry * 7) / 8; /* XXX NUMS */
+
+ /* Make sure our randomness didn't run the renewal time past the
+ rebind time. */
+ if (client -> new -> renewal > client -> new -> rebind)
+ client -> new -> renewal = (client -> new -> rebind * 3) / 4;
- ip -> client -> new -> expiry += cur_time;
+ client -> new -> expiry += cur_time;
/* Lease lengths can never be negative. */
- if (ip -> client -> new -> expiry < cur_time)
- ip -> client -> new -> expiry = TIME_MAX;
- ip -> client -> new -> renewal += cur_time;
- if (ip -> client -> new -> renewal < cur_time)
- ip -> client -> new -> renewal = TIME_MAX;
- ip -> client -> new -> rebind += cur_time;
- if (ip -> client -> new -> rebind < cur_time)
- ip -> client -> new -> rebind = TIME_MAX;
-
- bind_lease (ip);
+ if (client -> new -> expiry < cur_time)
+ client -> new -> expiry = TIME_MAX;
+ client -> new -> renewal += cur_time;
+ if (client -> new -> renewal < cur_time)
+ client -> new -> renewal = TIME_MAX;
+ client -> new -> rebind += cur_time;
+ if (client -> new -> rebind < cur_time)
+ client -> new -> rebind = TIME_MAX;
+
+ bind_lease (client);
}
-void bind_lease (ip)
- struct interface_info *ip;
+void bind_lease (client)
+ struct client_state *client;
{
- /* Remember the medium. */
- ip -> client -> new -> medium = ip -> client -> medium;
+ struct interface_info *ip = client -> interface;
- /* Write out the new lease. */
- write_client_lease (ip, ip -> client -> new, 0);
+ /* Remember the medium. */
+ client -> new -> medium = client -> medium;
/* Run the client script with the new parameters. */
- script_init (ip, (ip -> client -> state == S_REQUESTING
+ script_init (client, (client -> state == S_REQUESTING
? "BOUND"
- : (ip -> client -> state == S_RENEWING
+ : (client -> state == S_RENEWING
? "RENEW"
- : (ip -> client -> state == S_REBOOTING
+ : (client -> state == S_REBOOTING
? "REBOOT" : "REBIND"))),
- ip -> client -> new -> medium);
- if (ip -> client -> active && ip -> client -> state != S_REBOOTING)
- script_write_params (ip, "old_", ip -> client -> active);
- script_write_params (ip, "new_", ip -> client -> new);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_", ip -> client -> alias);
- script_go (ip);
+ client -> new -> medium);
+ if (client -> active && client -> state != S_REBOOTING)
+ script_write_params (client, "old_", client -> active);
+ script_write_params (client, "new_", client -> new);
+ if (client -> alias)
+ script_write_params (client, "alias_", client -> alias);
+
+ /* If the BOUND/RENEW code detects another machine using the
+ offered address, it exits nonzero. We need to send a
+ DHCPDECLINE and toss the lease. */
+ if (script_go (client)) {
+ make_decline (client, client -> new);
+ send_decline (client);
+ destroy_client_lease (client -> new);
+ client -> new = (struct client_lease *)0;
+ state_init (client);
+ return;
+ }
+
+ /* Write out the new lease. */
+ write_client_lease (client, client -> new, 0, 0);
/* Replace the old active lease with the new one. */
- if (ip -> client -> active)
- free_client_lease (ip -> client -> active);
- ip -> client -> active = ip -> client -> new;
- ip -> client -> new = (struct client_lease *)0;
+ if (client -> active)
+ destroy_client_lease (client -> active);
+ client -> active = client -> new;
+ client -> new = (struct client_lease *)0;
/* Set up a timeout to start the renewal process. */
- add_timeout (ip -> client -> active -> renewal,
- state_bound, ip);
+ add_timeout (client -> active -> renewal,
+ state_bound, client, 0, 0);
- note ("bound to %s -- renewal in %d seconds.",
- piaddr (ip -> client -> active -> address),
- ip -> client -> active -> renewal - cur_time);
- ip -> client -> state = S_BOUND;
+ log_info ("bound to %s -- renewal in %ld seconds.",
+ piaddr (client -> active -> address),
+ (long)(client -> active -> renewal - cur_time));
+ client -> state = S_BOUND;
reinitialize_interfaces ();
go_daemon ();
+ client_dns_update (client, 1);
}
/* state_bound is called when we've successfully bound to a particular
@@ -618,32 +890,68 @@ void bind_lease (ip)
expected to unicast a DHCPREQUEST to the server that gave us our
original lease. */
-void state_bound (ipp)
- void *ipp;
+void state_bound (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
+ int i;
+ struct option_cache *oc;
+ struct data_string ds;
ASSERT_STATE(state, S_BOUND);
/* T1 has expired. */
- 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;
+ make_request (client, client -> active);
+ client -> xid = client -> packet.xid;
+
+ memset (&ds, 0, sizeof ds);
+ oc = lookup_option (&dhcp_universe, client -> active -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ if (oc &&
+ evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
+ client, (struct option_state *)0,
+ client -> active -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3) {
+ memcpy (client -> destination.iabuf, ds.data, 4);
+ client -> destination.len = 4;
+ } else
+ client -> destination = iaddr_broadcast;
} else
- ip -> client -> destination = iaddr_broadcast;
+ client -> destination = iaddr_broadcast;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
- ip -> client -> state = S_RENEWING;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
+ client -> state = S_RENEWING;
/* Send the first packet immediately. */
- send_request (ip);
+ send_request (client);
+}
+
+/* state_stop is called when we've been told to shut down. We unconfigure
+ the interfaces, and then stop operating until told otherwise. */
+
+void state_stop (cpp)
+ void *cpp;
+{
+ struct client_state *client = cpp;
+ int i;
+
+ /* Cancel all timeouts. */
+ cancel_timeout (state_selecting, client);
+ cancel_timeout (send_discover, client);
+ cancel_timeout (send_request, client);
+ cancel_timeout (state_bound, client);
+
+ /* If we have an address, unconfigure it. */
+ if (client -> active) {
+ script_init (client, "STOP", client -> active -> medium);
+ script_write_params (client, "old_", client -> active);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_go (client);
+ }
}
int commit_leases ()
@@ -657,7 +965,14 @@ int write_lease (lease)
return 0;
}
-void db_startup ()
+int write_host (host)
+ struct host_decl *host;
+{
+ return 0;
+}
+
+void db_startup (testp)
+ int testp;
{
}
@@ -674,7 +989,7 @@ void bootp (packet)
for (ap = packet -> interface -> client -> config -> reject_list;
ap; ap = ap -> next) {
if (addr_eq (packet -> client_addr, ap -> addr)) {
- note ("BOOTREPLY from %s rejected.",
+ log_info ("BOOTREPLY from %s rejected.",
piaddr (ap -> addr));
return;
}
@@ -689,7 +1004,7 @@ void dhcp (packet)
{
struct iaddrlist *ap;
void (*handler) PROTO ((struct packet *));
- char *type;
+ const char *type;
switch (packet -> packet_type) {
case DHCPOFFER:
@@ -716,7 +1031,7 @@ void dhcp (packet)
for (ap = packet -> interface -> client -> config -> reject_list;
ap; ap = ap -> next) {
if (addr_eq (packet -> client_addr, ap -> addr)) {
- note ("%s from %s rejected.",
+ log_info ("%s from %s rejected.",
type, piaddr (ap -> addr));
return;
}
@@ -728,186 +1043,196 @@ void dhcpoffer (packet)
struct packet *packet;
{
struct interface_info *ip = packet -> interface;
+ struct client_state *client;
struct client_lease *lease, *lp;
int i;
- int arp_timeout_needed, stop_selecting;
- char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len
- ? "DHCPOFFER" : "BOOTREPLY");
+ int stop_selecting;
+ const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
+ struct iaddrlist *ap;
+ struct option_cache *oc;
+ char obuf [1024];
#ifdef DEBUG_PACKET
dump_packet (packet);
#endif
+ /* Find a client state that matches the xid... */
+ for (client = ip -> client; client; client = client -> next)
+ if (client -> xid == packet -> raw -> xid)
+ break;
+
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
- if (ip -> client -> state != S_SELECTING ||
- packet -> interface -> client -> xid != packet -> raw -> xid ||
- (packet -> interface -> hw_address.hlen !=
+ if (!client ||
+ client -> state != S_SELECTING ||
+ (packet -> interface -> hw_address.hlen - 1 !=
packet -> raw -> hlen) ||
- (memcmp (packet -> interface -> hw_address.haddr,
+ (memcmp (&packet -> interface -> hw_address.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
- debug ("%s in wrong transaction.", name);
+ log_debug ("%s in wrong transaction.", name);
#endif
return;
}
- note ("%s from %s", name, piaddr (packet -> client_addr));
+ sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
/* 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 (client -> config -> required_options) {
+ for (i = 0; client -> config -> required_options [i]; i++) {
+ if (!lookup_option
+ (&dhcp_universe, packet -> options,
+ client -> config -> required_options [i])) {
+ log_info ("%s: no %s option.",
+ obuf, (dhcp_universe.options
+ [client -> config -> required_options [i]]
+ -> name));
+ return;
+ }
}
}
/* If we've already seen this lease, don't record it again. */
- for (lease = ip -> client -> offered_leases;
- lease; lease = lease -> next) {
+ for (lease = client -> offered_leases; lease; lease = lease -> next) {
if (lease -> address.len == sizeof packet -> raw -> yiaddr &&
!memcmp (lease -> address.iabuf,
&packet -> raw -> yiaddr, lease -> address.len)) {
- debug ("%s already seen.", name);
+ log_debug ("%s: already seen.", obuf);
return;
}
}
- lease = packet_to_lease (packet);
+ lease = packet_to_lease (packet, client);
if (!lease) {
- note ("packet_to_lease failed.");
+ log_info ("%s: packet_to_lease failed.", obuf);
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. */
- lease -> medium = ip -> client -> medium;
-
- /* Send out an ARP Request for the offered IP address. */
- script_init (ip, "ARPSEND", lease -> medium);
- script_write_params (ip, "check_", lease);
- /* If the script can't send an ARP request without waiting,
- we'll be waiting when we do the ARPCHECK, so don't wait now. */
- if (script_go (ip))
- arp_timeout_needed = 0;
- else
- arp_timeout_needed = 2;
+ lease -> medium = client -> medium;
/* Figure out when we're supposed to stop selecting. */
- stop_selecting = (ip -> client -> first_sending +
- ip -> client -> config -> select_interval);
+ stop_selecting = (client -> first_sending +
+ client -> config -> select_interval);
/* If this is the lease we asked for, put it at the head of the
list, and don't mess with the arp request timeout. */
- if (lease -> address.len == ip -> client -> requested_address.len &&
+ if (lease -> address.len == client -> requested_address.len &&
!memcmp (lease -> address.iabuf,
- ip -> client -> requested_address.iabuf,
- ip -> client -> requested_address.len)) {
- lease -> next = ip -> client -> offered_leases;
- ip -> client -> offered_leases = lease;
+ client -> requested_address.iabuf,
+ client -> requested_address.len)) {
+ lease -> next = client -> offered_leases;
+ client -> offered_leases = lease;
} else {
- /* If we already have an offer, and arping for this
- offer would take us past the selection timeout,
- then don't extend the timeout - just hope for the
- best. */
- if (ip -> client -> offered_leases &&
- (cur_time + arp_timeout_needed) > stop_selecting)
- arp_timeout_needed = 0;
-
/* Put the lease at the end of the list. */
lease -> next = (struct client_lease *)0;
- if (!ip -> client -> offered_leases)
- ip -> client -> offered_leases = lease;
+ if (!client -> offered_leases)
+ client -> offered_leases = lease;
else {
- for (lp = ip -> client -> offered_leases; lp -> next;
+ for (lp = client -> offered_leases; lp -> next;
lp = lp -> next)
;
lp -> next = lease;
}
}
- /* If we're supposed to stop selecting before we've had time
- to wait for the ARPREPLY, add some delay to wait for
- the ARPREPLY. */
- if (stop_selecting - cur_time < arp_timeout_needed)
- stop_selecting = cur_time + arp_timeout_needed;
-
/* If the selecting interval has expired, go immediately to
state_selecting(). Otherwise, time out into
state_selecting at the select interval. */
if (stop_selecting <= 0)
- state_selecting (ip);
+ state_selecting (client);
else {
- add_timeout (stop_selecting, state_selecting, ip);
- cancel_timeout (send_discover, ip);
+ add_timeout (stop_selecting, state_selecting, client, 0, 0);
+ cancel_timeout (send_discover, client);
}
+ log_info ("%s", obuf);
}
/* Allocate a client_lease structure and initialize it from the parameters
in the specified packet. */
-struct client_lease *packet_to_lease (packet)
+struct client_lease *packet_to_lease (packet, client)
struct packet *packet;
+ struct client_state *client;
{
struct client_lease *lease;
- int i;
+ unsigned 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 (MDL);
if (!lease) {
- warn ("dhcpoffer: no memory to record lease.\n");
+ log_error ("packet_to_lease: no memory to record lease.\n");
return (struct client_lease *)0;
}
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;
- }
- }
- }
+ option_state_reference (&lease -> options, packet -> options, MDL);
lease -> address.len = sizeof (packet -> raw -> yiaddr);
memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
lease -> address.len);
+ if (client -> config -> vendor_space_name) {
+ i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
+
+ /* See if there was a vendor encapsulation option. */
+ oc = lookup_option (&dhcp_universe, lease -> options, i);
+ memset (&data, 0, sizeof data);
+ if (oc &&
+ client -> config -> vendor_space_name &&
+ evaluate_option_cache (&data, packet,
+ (struct lease *)0, client,
+ packet -> options, lease -> options,
+ &global_scope, oc, MDL)) {
+ if (data.len) {
+ parse_encapsulated_suboptions
+ (packet -> options, &dhcp_options [i],
+ data.data, data.len, &dhcp_universe,
+ client -> config -> vendor_space_name
+ );
+ }
+ data_string_forget (&data, MDL);
+ }
+ } else
+ i = 0;
+
+ /* Figure out the overload flag. */
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_OPTION_OVERLOAD);
+ if (oc &&
+ evaluate_option_cache (&data, packet, (struct lease *)0, client,
+ packet -> options, lease -> options,
+ &global_scope, oc, MDL)) {
+ if (data.len > 0)
+ i = data.data [0];
+ else
+ i = 0;
+ data_string_forget (&data, MDL);
+ } 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]) {
- int len;
+ if (!(i & 2) && packet -> raw -> sname [0]) {
+ unsigned 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, MDL);
if (!lease -> server_name) {
- warn ("dhcpoffer: no memory for filename.\n");
- free_client_lease (lease);
+ log_error ("dhcpoffer: no memory for filename.\n");
+ destroy_client_lease (lease);
return (struct client_lease *)0;
} else {
memcpy (lease -> server_name,
@@ -917,18 +1242,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]) {
- int len;
+ if (!(i & 1) && packet -> raw -> file [0]) {
+ unsigned 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, MDL);
if (!lease -> filename) {
- warn ("dhcpoffer: no memory for filename.\n");
- free_client_lease (lease);
+ log_error ("dhcpoffer: no memory for filename.\n");
+ destroy_client_lease (lease);
return (struct client_lease *)0;
} else {
memcpy (lease -> filename,
@@ -936,6 +1259,15 @@ struct client_lease *packet_to_lease (packet)
lease -> filename [len] = 0;
}
}
+
+ execute_statements_in_scope ((struct binding_value **)0,
+ (struct packet *)packet,
+ (struct lease *)0, client,
+ lease -> options, lease -> options,
+ &global_scope,
+ client -> config -> on_receipt,
+ (struct group *)0);
+
return lease;
}
@@ -943,95 +1275,103 @@ void dhcpnak (packet)
struct packet *packet;
{
struct interface_info *ip = packet -> interface;
+ struct client_state *client;
+
+ /* Find a client state that matches the xid... */
+ for (client = ip -> client; client; client = client -> next)
+ if (client -> xid == packet -> raw -> xid)
+ break;
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
- if (packet -> interface -> client -> xid != packet -> raw -> xid ||
- (packet -> interface -> hw_address.hlen !=
+ if (!client ||
+ (packet -> interface -> hw_address.hlen - 1 !=
packet -> raw -> hlen) ||
- (memcmp (packet -> interface -> hw_address.haddr,
+ (memcmp (&packet -> interface -> hw_address.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
- debug ("DHCPNAK in wrong transaction.");
+ log_debug ("DHCPNAK in wrong transaction.");
#endif
return;
}
- if (ip -> client -> state != S_REBOOTING &&
- ip -> client -> state != S_REQUESTING &&
- ip -> client -> state != S_RENEWING &&
- ip -> client -> state != S_REBINDING) {
+ if (client -> state != S_REBOOTING &&
+ client -> state != S_REQUESTING &&
+ client -> state != S_RENEWING &&
+ client -> state != S_REBINDING) {
#if defined (DEBUG)
- debug ("DHCPNAK in wrong state.");
+ log_debug ("DHCPNAK in wrong state.");
#endif
return;
}
- note ("DHCPNAK from %s", piaddr (packet -> client_addr));
+ log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
- if (!ip -> client -> active) {
- note ("DHCPNAK with no active lease.\n");
+ if (!client -> active) {
+#if defined (DEBUG)
+ log_info ("DHCPNAK with no active lease.\n");
+#endif
return;
}
- free_client_lease (ip -> client -> active);
- ip -> client -> active = (struct client_lease *)0;
+ destroy_client_lease (client -> active);
+ client -> active = (struct client_lease *)0;
/* Stop sending DHCPREQUEST packets... */
- cancel_timeout (send_request, ip);
+ cancel_timeout (send_request, client);
- ip -> client -> state = S_INIT;
- state_init (ip);
+ client -> state = S_INIT;
+ state_init (client);
}
/* Send out a DHCPDISCOVER packet, and set a timeout to send out another
one after the right interval has expired. If we don't get an offer by
the time we reach the panic interval, call the panic function. */
-void send_discover (ipp)
- void *ipp;
+void send_discover (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
int interval;
int increase = 1;
/* Figure out how long it's been since we started transmitting. */
- interval = cur_time - ip -> client -> first_sending;
+ interval = cur_time - client -> first_sending;
/* If we're past the panic timeout, call the script and tell it
we haven't found anything for this interface yet. */
- if (interval > ip -> client -> config -> timeout) {
- state_panic (ip);
+ if (interval > client -> config -> timeout) {
+ state_panic (client);
return;
}
/* If we're selecting media, try the whole list before doing
the exponential backoff, but if we've already received an
offer, stop looping, because we obviously have it right. */
- if (!ip -> client -> offered_leases &&
- ip -> client -> config -> media) {
+ if (!client -> offered_leases &&
+ client -> config -> media) {
int fail = 0;
again:
- if (ip -> client -> medium) {
- ip -> client -> medium =
- ip -> client -> medium -> next;
+ if (client -> medium) {
+ client -> medium = client -> medium -> next;
increase = 0;
}
- if (!ip -> client -> medium) {
+ if (!client -> medium) {
if (fail)
- error ("No valid media types for %s!",
- ip -> name);
- ip -> client -> medium =
- ip -> client -> config -> media;
+ log_fatal ("No valid media types for %s!",
+ client -> interface -> name);
+ client -> medium =
+ client -> config -> media;
increase = 1;
}
- note ("Trying medium \"%s\" %d",
- ip -> client -> medium -> string, increase);
- script_init (ip, "MEDIUM", ip -> client -> medium);
- if (script_go (ip)) {
+ log_info ("Trying medium \"%s\" %d",
+ client -> medium -> string, increase);
+ script_init (client, "MEDIUM", client -> medium);
+ if (script_go (client)) {
+ fail = 1;
goto again;
}
}
@@ -1042,54 +1382,52 @@ void send_discover (ipp)
zero and two times itself. On average, this means that it
will double with every transmission. */
if (increase) {
- if (!ip -> client -> interval)
- ip -> client -> interval =
- ip -> client -> config -> initial_interval;
- else {
- ip -> client -> interval +=
- ((random () >> 2) %
- (2 * ip -> client -> interval));
- }
+ if (!client -> interval)
+ client -> interval =
+ client -> config -> initial_interval;
+ else
+ client -> interval += ((random () >> 2) %
+ (2 * client -> interval));
/* Don't backoff past cutoff. */
- if (ip -> client -> interval >
- ip -> client -> config -> backoff_cutoff)
- ip -> client -> interval =
- ((ip -> client -> config -> backoff_cutoff / 2)
+ if (client -> interval >
+ client -> config -> backoff_cutoff)
+ client -> interval =
+ ((client -> config -> backoff_cutoff / 2)
+ ((random () >> 2) %
- ip -> client -> config -> backoff_cutoff));
- } else if (!ip -> client -> interval)
- ip -> client -> interval =
- ip -> client -> config -> initial_interval;
+ client -> config -> backoff_cutoff));
+ } else if (!client -> interval)
+ client -> interval = client -> config -> initial_interval;
/* If the backoff would take us to the panic timeout, just use that
as the interval. */
- if (cur_time + ip -> client -> interval >
- ip -> client -> first_sending + ip -> client -> config -> timeout)
- ip -> client -> interval =
- (ip -> client -> first_sending +
- ip -> client -> config -> timeout) - cur_time + 1;
+ if (cur_time + client -> interval >
+ client -> first_sending + client -> config -> timeout)
+ client -> interval =
+ (client -> first_sending +
+ client -> config -> timeout) - cur_time + 1;
/* Record the number of seconds since we started sending. */
if (interval < 65536)
- ip -> client -> packet.secs = htons (interval);
+ client -> packet.secs = htons (interval);
else
- ip -> client -> packet.secs = htons (65535);
- ip -> client -> secs = ip -> client -> packet.secs;
+ client -> packet.secs = htons (65535);
+ client -> secs = client -> packet.secs;
- note ("DHCPDISCOVER on %s to %s port %d interval %ld",
- ip -> name,
+ log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
+ client -> name ? client -> name : client -> interface -> name,
inet_ntoa (sockaddr_broadcast.sin_addr),
- ntohs (sockaddr_broadcast.sin_port), ip -> client -> interval);
+ ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
/* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
- add_timeout (cur_time + ip -> client -> interval, send_discover, ip);
+ add_timeout (cur_time + client -> interval,
+ send_discover, client, 0, 0);
}
/* state_panic gets called if we haven't received any offers in a preset
@@ -1097,106 +1435,113 @@ void send_discover (ipp)
haven't yet expired, and failing that, we call the client script and
hope it can do something. */
-void state_panic (ipp)
- void *ipp;
+void state_panic (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
-
- struct client_lease *loop = ip -> client -> active;
+ struct client_state *client = cpp;
+ struct client_lease *loop;
struct client_lease *lp;
- note ("No DHCPOFFERS received.");
+ loop = lp = client -> active;
+
+ log_info ("No DHCPOFFERS received.");
/* We may not have an active lease, but we may have some
predefined leases that we can try. */
- if (!ip -> client -> active && ip -> client -> leases)
+ if (!client -> active && client -> leases)
goto activate_next;
/* Run through the list of leases and see if one can be used. */
- while (ip -> client -> active) {
- if (ip -> client -> active -> expiry > cur_time) {
- note ("Trying recorded lease %s",
- piaddr (ip -> client -> active -> address));
+ while (client -> active) {
+ if (client -> active -> expiry > cur_time) {
+ log_info ("Trying recorded lease %s",
+ piaddr (client -> active -> address));
/* Run the client script with the existing
parameters. */
- script_init (ip, "TIMEOUT",
- ip -> client -> active -> medium);
- script_write_params (ip, "new_",
- ip -> client -> active);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_",
- ip -> client -> alias);
+ script_init (client, "TIMEOUT",
+ client -> active -> medium);
+ script_write_params (client, "new_", client -> active);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
/* If the old lease is still good and doesn't
yet need renewal, go into BOUND state and
timeout at the renewal time. */
- if (!script_go (ip)) {
- if (cur_time <
- ip -> client -> active -> renewal) {
- ip -> client -> state = S_BOUND;
- note ("bound: renewal in %d seconds.",
- ip -> client -> active -> renewal
- - cur_time);
- add_timeout ((ip -> client ->
- active -> renewal),
- state_bound, ip);
- } else {
- ip -> client -> state = S_BOUND;
- note ("bound: immediate renewal.");
- state_bound (ip);
- }
- reinitialize_interfaces ();
- go_daemon ();
- return;
+ if (!script_go (client)) {
+ if (cur_time < client -> active -> renewal) {
+ client -> state = S_BOUND;
+ log_info ("bound: renewal in %ld %s.",
+ (long)(client -> active -> renewal -
+ cur_time), "seconds");
+ add_timeout (client -> active -> renewal,
+ state_bound, client, 0, 0);
+ } else {
+ client -> state = S_BOUND;
+ log_info ("bound: immediate renewal.");
+ state_bound (client);
+ }
+ reinitialize_interfaces ();
+ go_daemon ();
+ return;
}
}
/* If there are no other leases, give up. */
- if (!ip -> client -> leases) {
- ip -> client -> leases = ip -> client -> active;
- ip -> client -> active = (struct client_lease *)0;
+ if (!client -> leases) {
+ client -> leases = client -> active;
+ client -> active = (struct client_lease *)0;
break;
}
activate_next:
/* Otherwise, put the active lease at the end of the
lease list, and try another lease.. */
- for (lp = ip -> client -> leases; lp -> next; lp = lp -> next)
+ for (lp = client -> leases; lp -> next; lp = lp -> next)
;
- lp -> next = ip -> client -> active;
+ lp -> next = client -> active;
if (lp -> next) {
lp -> next -> next = (struct client_lease *)0;
}
- ip -> client -> active = ip -> client -> leases;
- ip -> client -> leases = ip -> client -> leases -> next;
+ client -> active = client -> leases;
+ client -> leases = client -> leases -> next;
/* If we already tried this lease, we've exhausted the
set of leases, so we might as well give up for
now. */
- if (ip -> client -> active == loop)
+ if (client -> active == loop)
break;
else if (!loop)
- loop = ip -> client -> active;
+ loop = client -> active;
}
/* No leases were available, or what was available didn't work, so
tell the shell script that we failed to allocate an address,
and try again later. */
- note ("No working leases in persistent database - sleeping.\n");
- script_init (ip, "FAIL", (struct string_list *)0);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_", ip -> client -> alias);
- script_go (ip);
- ip -> client -> state = S_INIT;
- add_timeout (cur_time + ip -> client -> config -> retry_interval,
- state_init, ip);
+ if (onetry) {
+ if (!quiet)
+ log_info ("Unable to obtain a lease on first try.%s",
+ " Exiting.");
+ exit (2);
+ }
+
+ log_info ("No working leases in persistent database - sleeping.");
+ script_init (client, "FAIL", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_", client -> alias);
+ script_go (client);
+ client -> state = S_INIT;
+ add_timeout (cur_time +
+ ((client -> config -> retry_interval + 1) / 2 +
+ (random () % client -> config -> retry_interval)),
+ state_init, client, 0, 0);
go_daemon ();
}
-void send_request (ipp)
- void *ipp;
+void send_request (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
int interval;
@@ -1204,7 +1549,7 @@ void send_request (ipp)
struct in_addr from;
/* Figure out how long it's been since we started transmitting. */
- interval = cur_time - ip -> client -> first_sending;
+ interval = cur_time - client -> first_sending;
/* If we're in the INIT-REBOOT or REQUESTING state and we're
past the reboot timeout, go to INIT and see if we can
@@ -1216,91 +1561,87 @@ void send_request (ipp)
us a new address, but we could also have successfully
reused our old address. In the former case, we're hosed
anyway. This is not a win-prone situation. */
- if ((ip -> client -> state == S_REBOOTING ||
- ip -> client -> state == S_REQUESTING) &&
- interval > ip -> client -> config -> reboot_timeout) {
+ if ((client -> state == S_REBOOTING ||
+ client -> state == S_REQUESTING) &&
+ interval > client -> config -> reboot_timeout) {
cancel:
- ip -> client -> state = S_INIT;
- cancel_timeout (send_request, ip);
- state_init (ip);
+ client -> state = S_INIT;
+ cancel_timeout (send_request, client);
+ state_init (client);
return;
}
/* If we're in the reboot state, make sure the media is set up
correctly. */
- if (ip -> client -> state == S_REBOOTING &&
- !ip -> client -> medium &&
- ip -> client -> active -> medium ) {
- script_init (ip, "MEDIUM", ip -> client -> active -> medium);
+ if (client -> state == S_REBOOTING &&
+ !client -> medium &&
+ client -> active -> medium ) {
+ script_init (client, "MEDIUM", client -> active -> medium);
/* If the medium we chose won't fly, go to INIT state. */
- if (script_go (ip))
+ if (script_go (client))
goto cancel;
/* Record the medium. */
- ip -> client -> medium = ip -> client -> active -> medium;
+ client -> medium = client -> active -> medium;
}
/* If the lease has expired, relinquish the address and go back
to the INIT state. */
- if (ip -> client -> state != S_REQUESTING &&
- cur_time > ip -> client -> active -> expiry) {
+ if (client -> state != S_REQUESTING &&
+ cur_time > client -> active -> expiry) {
/* Run the client script with the new parameters. */
- script_init (ip, "EXPIRE", (struct string_list *)0);
- script_write_params (ip, "old_", ip -> client -> active);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_",
- ip -> client -> alias);
- script_go (ip);
+ script_init (client, "EXPIRE", (struct string_list *)0);
+ script_write_params (client, "old_", client -> active);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_go (client);
/* Now do a preinit on the interface so that we can
discover a new address. */
- script_init (ip, "PREINIT", (struct string_list *)0);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_",
- ip -> client -> alias);
- script_go (ip);
-
- ip -> client -> state = S_INIT;
- state_init (ip);
+ script_init (client, "PREINIT", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_go (client);
+
+ client -> state = S_INIT;
+ state_init (client);
return;
}
/* Do the exponential backoff... */
- if (!ip -> client -> interval)
- ip -> client -> interval =
- ip -> client -> config -> initial_interval;
+ if (!client -> interval)
+ client -> interval = client -> config -> initial_interval;
else {
- ip -> client -> interval +=
- ((random () >> 2) %
- (2 * ip -> client -> interval));
+ client -> interval += ((random () >> 2) %
+ (2 * client -> interval));
}
/* Don't backoff past cutoff. */
- if (ip -> client -> interval >
- ip -> client -> config -> backoff_cutoff)
- ip -> client -> interval =
- ((ip -> client -> config -> backoff_cutoff / 2)
- + ((random () >> 2)
- % ip -> client -> interval));
+ if (client -> interval >
+ client -> config -> backoff_cutoff)
+ client -> interval =
+ ((client -> config -> backoff_cutoff / 2)
+ + ((random () >> 2) % client -> interval));
/* If the backoff would take us to the expiry time, just set the
timeout to the expiry time. */
- if (ip -> client -> state != S_REQUESTING &&
- cur_time + ip -> client -> interval >
- ip -> client -> active -> expiry)
- ip -> client -> interval =
- ip -> client -> active -> expiry - cur_time + 1;
+ if (client -> state != S_REQUESTING &&
+ cur_time + client -> interval > client -> active -> expiry)
+ client -> interval =
+ client -> active -> expiry - cur_time + 1;
/* If the lease T2 time has elapsed, or if we're not yet bound,
broadcast the DHCPREQUEST rather than unicasting. */
- if (ip -> client -> state == S_REQUESTING ||
- ip -> client -> state == S_REBOOTING ||
- cur_time > ip -> client -> active -> rebind)
- destination.sin_addr.s_addr = INADDR_BROADCAST;
+ if (client -> state == S_REQUESTING ||
+ client -> state == S_REBOOTING ||
+ cur_time > client -> active -> rebind)
+ destination.sin_addr = sockaddr_broadcast.sin_addr;
else
memcpy (&destination.sin_addr.s_addr,
- ip -> client -> destination.iabuf,
+ client -> destination.iabuf,
sizeof destination.sin_addr.s_addr);
destination.sin_port = remote_port;
destination.sin_family = AF_INET;
@@ -1308,23 +1649,25 @@ void send_request (ipp)
destination.sin_len = sizeof destination;
#endif
- if (ip -> client -> state != S_REQUESTING)
- memcpy (&from, ip -> client -> active -> address.iabuf,
+ if (client -> state == S_RENEWING ||
+ client -> state == S_REBINDING)
+ memcpy (&from, client -> active -> address.iabuf,
sizeof from);
else
from.s_addr = INADDR_ANY;
/* Record the number of seconds since we started sending. */
- if (ip -> client -> state == S_REQUESTING)
- ip -> client -> packet.secs = ip -> client -> secs;
+ if (client -> state == S_REQUESTING)
+ client -> packet.secs = client -> secs;
else {
if (interval < 65536)
- ip -> client -> packet.secs = htons (interval);
+ client -> packet.secs = htons (interval);
else
- ip -> client -> packet.secs = htons (65535);
+ client -> packet.secs = htons (65535);
}
- note ("DHCPREQUEST on %s to %s port %d", ip -> name,
+ log_info ("DHCPREQUEST on %s to %s port %d",
+ client -> name ? client -> name : client -> interface -> name,
inet_ntoa (destination.sin_addr),
ntohs (destination.sin_port));
@@ -1332,451 +1675,429 @@ void send_request (ipp)
fallback_interface)
result = send_packet (fallback_interface,
(struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ &client -> packet,
+ client -> packet_length,
from, &destination,
(struct hardware *)0);
else
/* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
from, &destination,
(struct hardware *)0);
- add_timeout (cur_time + ip -> client -> interval,
- send_request, ip);
+ add_timeout (cur_time + client -> interval,
+ send_request, client, 0, 0);
}
-void send_decline (ipp)
- void *ipp;
+void send_decline (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
- note ("DHCPDECLINE on %s to %s port %d", ip -> name,
+ log_info ("DHCPDECLINE on %s to %s port %d",
+ client -> name ? client -> name : client -> interface -> name,
inet_ntoa (sockaddr_broadcast.sin_addr),
ntohs (sockaddr_broadcast.sin_port));
/* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
}
-void send_release (ipp)
- void *ipp;
+void send_release (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
+ struct sockaddr_in destination;
+ struct in_addr from;
- note ("DHCPRELEASE on %s to %s port %d", ip -> name,
- inet_ntoa (sockaddr_broadcast.sin_addr),
- ntohs (sockaddr_broadcast.sin_port));
+ memcpy (&from, client -> active -> address.iabuf,
+ sizeof from);
+ memcpy (&destination.sin_addr.s_addr,
+ client -> destination.iabuf,
+ sizeof destination.sin_addr.s_addr);
+ destination.sin_port = remote_port;
+ destination.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+ destination.sin_len = sizeof destination;
+#endif
- /* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
- inaddr_any, &sockaddr_broadcast,
- (struct hardware *)0);
+ /* Set the lease to end now, so that we don't accidentally
+ reuse it if we restart before the old expiry time. */
+ client -> active -> expiry =
+ client -> active -> renewal =
+ client -> active -> rebind = cur_time;
+ if (!write_client_lease (client, client -> active, 1, 1)) {
+ log_error ("Can't release lease: lease write failed.");
+ return;
+ }
+
+ log_info ("DHCPRELEASE on %s to %s port %d",
+ client -> name ? client -> name : client -> interface -> name,
+ inet_ntoa (destination.sin_addr),
+ ntohs (destination.sin_port));
+
+ if (fallback_interface)
+ result = send_packet (fallback_interface,
+ (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
+ from, &destination,
+ (struct hardware *)0);
+ else
+ /* Send out a packet. */
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
+ from, &destination,
+ (struct hardware *)0);
}
-void make_discover (ip, lease)
- struct interface_info *ip;
+void make_client_options (client, lease, type, sid, rip, prl, op)
+ struct client_state *client;
struct client_lease *lease;
+ u_int8_t *type;
+ struct option_cache *sid;
+ struct iaddr *rip;
+ u_int32_t *prl;
+ struct option_state **op;
{
- 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;
+ unsigned i;
+ struct option_cache *oc;
+ struct buffer *bp = (struct buffer *)0;
+
+ /* If there are any leftover options, get rid of them. */
+ if (*op)
+ option_state_dereference (op, MDL);
+
+ /* Allocate space for options. */
+ option_state_allocate (op, MDL);
+
+ /* Send the server identifier if provided. */
+ if (sid)
+ save_option (&dhcp_universe, *op, sid);
+
+ oc = (struct option_cache *)0;
+
+ /* Send the requested address if provided. */
+ if (rip) {
+ client -> requested_address = *rip;
+ if (!(make_const_option_cache
+ (&oc, (struct buffer **)0, rip -> iabuf, rip -> len,
+ &dhcp_options [DHO_DHCP_REQUESTED_ADDRESS], MDL)))
+ log_error ("can't make requested address cache.");
+ else {
+ save_option (&dhcp_universe, *op, oc);
+ option_cache_dereference (&oc, MDL);
+ }
} 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;
+ client -> requested_address.len = 0;
+ }
+
+ if (!(make_const_option_cache
+ (&oc, (struct buffer **)0,
+ type, 1, &dhcp_options [DHO_DHCP_MESSAGE_TYPE], MDL)))
+ log_error ("can't make message type.");
+ else {
+ save_option (&dhcp_universe, *op, oc);
+ option_cache_dereference (&oc, MDL);
+ }
+
+ if (prl) {
+ /* Figure out how many parameters were requested. */
+ for (i = 0; prl [i]; i++)
+ ;
+ if (!buffer_allocate (&bp, i, MDL))
+ log_error ("can't make parameter list buffer.");
+ 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],
+ MDL)))
+ log_error ("can't make option cache");
+ else {
+ save_option (&dhcp_universe, *op, oc);
+ option_cache_dereference (&oc, MDL);
+ }
}
}
+ /* Run statements that need to be run on transmission. */
+ if (client -> config -> on_transmission)
+ execute_statements_in_scope
+ ((struct binding_value **)0,
+ (struct packet *)0, (struct lease *)0, client,
+ (lease ? lease -> options : (struct option_state *)0),
+ *op, &global_scope,
+ client -> config -> on_transmission,
+ (struct group *)0);
+}
+
+void make_discover (client, lease)
+ struct client_state *client;
+ struct client_lease *lease;
+{
+ unsigned char discover = DHCPDISCOVER;
+ int i;
+ struct option_state *options = (struct option_state *)0;
+
+ memset (&client -> packet, 0, sizeof (client -> packet));
+
+ make_client_options (client,
+ lease, &discover, (struct option_cache *)0,
+ lease ? &lease -> address : (struct iaddr *)0,
+ client -> config -> requested_options,
+ &options);
+
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = random ();
- ip -> client -> packet.secs = 0; /* filled in by send_discover. */
-
- if (can_receive_unicast_unconfigured (ip))
- ip -> client -> packet.flags = 0;
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = random ();
+ client -> packet.secs = 0; /* filled in by send_discover. */
+
+ if (can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
else
- ip -> client -> packet.flags = htons (BOOTP_BROADCAST);
-
- memset (&(ip -> client -> packet.ciaddr),
- 0, sizeof ip -> client -> packet.ciaddr);
- memset (&(ip -> client -> packet.yiaddr),
- 0, sizeof ip -> client -> packet.yiaddr);
- memset (&(ip -> client -> packet.siaddr),
- 0, sizeof ip -> client -> packet.siaddr);
- memset (&(ip -> client -> packet.giaddr),
- 0, sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ client -> packet.flags = htons (BOOTP_BROADCAST);
+
+ memset (&(client -> packet.ciaddr),
+ 0, sizeof client -> packet.ciaddr);
+ memset (&(client -> packet.yiaddr),
+ 0, sizeof client -> packet.yiaddr);
+ memset (&(client -> packet.siaddr),
+ 0, sizeof client -> packet.siaddr);
+ client -> packet.giaddr = giaddr;
+ if (client -> interface -> hw_address.hlen > 0)
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ (unsigned)(client -> interface -> hw_address.hlen - 1));
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet,
- sendpkt->packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void make_request (ip, lease)
- struct interface_info *ip;
+void make_request (client, lease)
+ struct client_state *client;
struct client_lease *lease;
{
unsigned char request = DHCPREQUEST;
- int i;
+ int i, j;
+ unsigned char *tmp, *digest;
+ unsigned char *old_digest_loc;
+ 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;
- }
-
- /* 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;
- }
- }
+ memset (&client -> packet, 0, sizeof (client -> packet));
+
+ if (client -> state == S_REQUESTING)
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ else
+ oc = (struct option_cache *)0;
+
+ make_client_options (client, lease, &request, oc,
+ ((client -> state == S_REQUESTING ||
+ client -> state == S_REBOOTING)
+ ? &lease -> address
+ : (struct iaddr *)0),
+ client -> config -> requested_options,
+ &client -> sent_options);
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = ip -> client -> xid;
- ip -> client -> packet.secs = 0; /* Filled in by send_request. */
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, client -> sent_options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = client -> xid;
+ client -> packet.secs = 0; /* Filled in by send_request. */
/* If we own the address we're requesting, put it in ciaddr;
otherwise set ciaddr to zero. */
- if (ip -> client -> state == S_BOUND ||
- ip -> client -> state == S_RENEWING ||
- ip -> client -> state == S_REBINDING) {
- memcpy (&ip -> client -> packet.ciaddr,
+ if (client -> state == S_BOUND ||
+ client -> state == S_RENEWING ||
+ client -> state == S_REBINDING) {
+ memcpy (&client -> packet.ciaddr,
lease -> address.iabuf, lease -> address.len);
- ip -> client -> packet.flags = 0;
+ client -> packet.flags = 0;
} else {
- memset (&ip -> client -> packet.ciaddr, 0,
- sizeof ip -> client -> packet.ciaddr);
- if (can_receive_unicast_unconfigured (ip))
- ip -> client -> packet.flags = 0;
+ memset (&client -> packet.ciaddr, 0,
+ sizeof client -> packet.ciaddr);
+ if (can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
else
- ip -> client -> packet.flags = htons (BOOTP_BROADCAST);
+ client -> packet.flags = htons (BOOTP_BROADCAST);
}
- memset (&ip -> client -> packet.yiaddr, 0,
- sizeof ip -> client -> packet.yiaddr);
- memset (&ip -> client -> packet.siaddr, 0,
- sizeof ip -> client -> packet.siaddr);
- memset (&ip -> client -> packet.giaddr, 0,
- sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ memset (&client -> packet.yiaddr, 0,
+ sizeof client -> packet.yiaddr);
+ memset (&client -> packet.siaddr, 0,
+ sizeof client -> packet.siaddr);
+ if (client -> state != S_BOUND &&
+ client -> state != S_RENEWING)
+ client -> packet.giaddr = giaddr;
+ else
+ memset (&client -> packet.giaddr, 0,
+ sizeof client -> packet.giaddr);
+ if (client -> interface -> hw_address.hlen > 0)
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ (unsigned)(client -> interface -> hw_address.hlen - 1));
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void make_decline (ip, lease)
- struct interface_info *ip;
+void make_decline (client, lease)
+ struct client_state *client;
struct client_lease *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;
-
- 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;
- }
+ struct option_state *options = (struct option_state *)0;
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ make_client_options (client, lease, &decline, oc,
+ &lease -> address, (u_int32_t *)0, &options);
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = ip -> client -> xid;
- ip -> client -> packet.secs = 0; /* Filled in by send_request. */
- ip -> client -> packet.flags = 0;
+ memset (&client -> packet, 0, sizeof (client -> packet));
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+ option_state_dereference (&options, MDL);
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = client -> xid;
+ client -> packet.secs = 0; /* Filled in by send_request. */
+ if (can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
+ else
+ client -> packet.flags = htons (BOOTP_BROADCAST);
/* ciaddr must always be zero. */
- memset (&ip -> client -> packet.ciaddr, 0,
- sizeof ip -> client -> packet.ciaddr);
- memset (&ip -> client -> packet.yiaddr, 0,
- sizeof ip -> client -> packet.yiaddr);
- memset (&ip -> client -> packet.siaddr, 0,
- sizeof ip -> client -> packet.siaddr);
- memset (&ip -> client -> packet.giaddr, 0,
- sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ memset (&client -> packet.ciaddr, 0,
+ sizeof client -> packet.ciaddr);
+ memset (&client -> packet.yiaddr, 0,
+ sizeof client -> packet.yiaddr);
+ memset (&client -> packet.siaddr, 0,
+ sizeof client -> packet.siaddr);
+ client -> packet.giaddr = giaddr;
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ client -> interface -> hw_address.hlen);
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void make_release (ip, lease)
- struct interface_info *ip;
+void make_release (client, lease)
+ struct client_state *client;
struct client_lease *lease;
{
unsigned char request = DHCPRELEASE;
int i;
+ struct option_cache *oc;
+
+ struct option_state *options = (struct option_state *)0;
- struct tree_cache *options [256];
- struct tree_cache message_type_tree;
- struct tree_cache server_id_tree;
-
- 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;
+ memset (&client -> packet, 0, sizeof (client -> packet));
+
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ make_client_options (client, lease, &request, oc,
+ (struct iaddr *)0, (u_int32_t *)0,
+ &options);
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = random ();
- ip -> client -> packet.secs = 0;
- ip -> client -> packet.flags = 0;
-
- memset (&ip -> client -> packet.ciaddr, 0,
- sizeof ip -> client -> packet.ciaddr);
- memset (&ip -> client -> packet.yiaddr, 0,
- sizeof ip -> client -> packet.yiaddr);
- memset (&ip -> client -> packet.siaddr, 0,
- sizeof ip -> client -> packet.siaddr);
- memset (&ip -> client -> packet.giaddr, 0,
- sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+ option_state_dereference (&options, MDL);
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = random ();
+ client -> packet.secs = 0;
+ client -> packet.flags = 0;
+ memcpy (&client -> packet.ciaddr,
+ lease -> address.iabuf, lease -> address.len);
+ memset (&client -> packet.yiaddr, 0,
+ sizeof client -> packet.yiaddr);
+ memset (&client -> packet.siaddr, 0,
+ sizeof client -> packet.siaddr);
+ client -> packet.giaddr = giaddr;
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ client -> interface -> hw_address.hlen);
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet,
- ip -> client -> packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#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, MDL);
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, MDL);
+ option_state_dereference (&lease -> options, MDL);
+ free_client_lease (lease, MDL);
}
FILE *leaseFile;
@@ -1784,44 +2105,92 @@ FILE *leaseFile;
void rewrite_client_leases ()
{
struct interface_info *ip;
+ struct client_state *client;
struct client_lease *lp;
if (leaseFile)
fclose (leaseFile);
leaseFile = fopen (path_dhclient_db, "w");
- if (!leaseFile)
- error ("can't create %s: %m", path_dhclient_db);
+ if (!leaseFile) {
+ log_error ("can't create %s: %m", path_dhclient_db);
+ return;
+ }
/* Write out all the leases attached to configured interfaces that
we know about. */
for (ip = interfaces; ip; ip = ip -> next) {
- for (lp = ip -> client -> leases; lp; lp = lp -> next) {
- write_client_lease (ip, lp, 1);
+ for (client = ip -> client; client; client = client -> next) {
+ for (lp = client -> leases; lp; lp = lp -> next) {
+ write_client_lease (client, lp, 1, 0);
+ }
+ if (client -> active)
+ write_client_lease (client,
+ client -> active, 1, 0);
}
- if (ip -> client -> active)
- write_client_lease (ip, ip -> client -> active, 1);
}
/* Write out any leases that are attached to interfaces that aren't
currently configured. */
for (ip = dummy_interfaces; ip; ip = ip -> next) {
- for (lp = ip -> client -> leases; lp; lp = lp -> next) {
- write_client_lease (ip, lp, 1);
+ for (client = ip -> client; client; client = client -> next) {
+ for (lp = client -> leases; lp; lp = lp -> next) {
+ write_client_lease (client, lp, 1, 0);
+ }
+ if (client -> active)
+ write_client_lease (client,
+ client -> active, 1, 0);
}
- if (ip -> client -> active)
- write_client_lease (ip, ip -> client -> active, 1);
}
fflush (leaseFile);
}
-void write_client_lease (ip, lease, rewrite)
- struct interface_info *ip;
+void write_lease_option (struct option_cache *oc,
+ struct packet *packet, struct lease *lease,
+ struct client_state *client_state,
+ struct option_state *in_options,
+ struct option_state *cfg_options,
+ struct binding_scope **scope,
+ struct universe *u, void *stuff)
+{
+ const char *name, *dot;
+ struct data_string ds;
+ int status;
+ struct client_state *client;
+
+ memset (&ds, 0, sizeof ds);
+
+ if (u != &dhcp_universe) {
+ name = u -> name;
+ dot = ".";
+ } else {
+ name = "";
+ dot = "";
+ }
+ if (evaluate_option_cache (&ds, packet, lease, client_state,
+ in_options, cfg_options, scope, oc, MDL)) {
+ fprintf (leaseFile,
+ " option %s%s%s %s;\n",
+ name, dot, oc -> option -> name,
+ pretty_print_option (oc -> option,
+ ds.data, ds.len, 1, 1));
+ data_string_forget (&ds, MDL);
+ }
+}
+
+int write_client_lease (client, lease, rewrite, makesure)
+ struct client_state *client;
struct client_lease *lease;
int rewrite;
+ int makesure;
{
int i;
struct tm *t;
static int leases_written;
+ struct option_cache *oc;
+ struct data_string ds;
+ pair *hash;
+ int errors = 0;
+ char *s;
if (!rewrite) {
if (leases_written++ > 20) {
@@ -1833,38 +2202,94 @@ void write_client_lease (ip, lease, rewrite)
/* If the lease came from the config file, we don't need to stash
a copy in the lease database. */
if (lease -> is_static)
- return;
+ return 1;
if (!leaseFile) { /* XXX */
leaseFile = fopen (path_dhclient_db, "w");
- if (!leaseFile)
- error ("can't create %s: %m", path_dhclient_db);
+ if (!leaseFile) {
+ log_error ("can't create %s: %m", path_dhclient_db);
+ return 0;
+ }
}
+ errno = 0;
fprintf (leaseFile, "lease {\n");
- if (lease -> is_bootp)
+ if (lease -> is_bootp) {
fprintf (leaseFile, " bootp;\n");
- fprintf (leaseFile, " interface \"%s\";\n", ip -> name);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ }
+ fprintf (leaseFile, " interface \"%s\";\n",
+ client -> interface -> name);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ if (client -> name) {
+ fprintf (leaseFile, " name \"%s\";\n", client -> name);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ }
fprintf (leaseFile, " fixed-address %s;\n",
piaddr (lease -> address));
- if (lease -> filename)
- fprintf (leaseFile, " filename \"%s\";\n",
- lease -> filename);
- if (lease -> server_name)
- fprintf (leaseFile, " server-name \"%s\";\n",
- lease -> server_name);
- 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));
- }
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ if (lease -> filename) {
+ s = quotify_string (lease -> filename, MDL);
+ if (s) {
+ fprintf (leaseFile, " filename \"%s\";\n", s);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ dfree (s, MDL);
+ } else
+ errors++;
+
+ }
+ if (lease -> server_name) {
+ s = quotify_string (lease -> filename, MDL);
+ if (s) {
+ fprintf (leaseFile, " server-name \"%s\";\n", s);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ dfree (s, MDL);
+ } else
+ ++errors;
+ }
+ if (lease -> medium) {
+ s = quotify_string (lease -> medium -> string, MDL);
+ if (s) {
+ fprintf (leaseFile, " medium \"%s\";\n", s);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ dfree (s, MDL);
+ } else
+ errors++;
+ }
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
+
+ memset (&ds, 0, sizeof ds);
+
+ for (i = 0; i < lease -> options -> universe_count; i++) {
+ option_space_foreach ((struct packet *)0, (struct lease *)0,
+ client, (struct option_state *)0,
+ lease -> options, &global_scope,
+ universes [i],
+ client, write_lease_option);
}
/* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
@@ -1876,20 +2301,47 @@ void write_client_lease (ip, lease, rewrite)
t -> tm_wday, t -> tm_year + 1900,
t -> tm_mon + 1, t -> tm_mday,
t -> tm_hour, t -> tm_min, t -> tm_sec);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
t = gmtime (&lease -> rebind);
fprintf (leaseFile,
" rebind %d %d/%d/%d %02d:%02d:%02d;\n",
t -> tm_wday, t -> tm_year + 1900,
t -> tm_mon + 1, t -> tm_mday,
t -> tm_hour, t -> tm_min, t -> tm_sec);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
t = gmtime (&lease -> expiry);
fprintf (leaseFile,
" expire %d %d/%d/%d %02d:%02d:%02d;\n",
t -> tm_wday, t -> tm_year + 1900,
t -> tm_mon + 1, t -> tm_mday,
t -> tm_hour, t -> tm_min, t -> tm_sec);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
fprintf (leaseFile, "}\n");
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
fflush (leaseFile);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
+ if (!errors && makesure) {
+ if (fsync (fileno (leaseFile)) < 0) {
+ log_info ("write_client_lease: %m");
+ return 0;
+ }
+ }
+ return errors ? 0 : 1;
}
/* Variables holding name of script and file pointer for writing to
@@ -1898,41 +2350,88 @@ void write_client_lease (ip, lease, rewrite)
char scriptName [256];
FILE *scriptFile;
-void script_init (ip, reason, medium)
- struct interface_info *ip;
- char *reason;
+void script_init (client, reason, medium)
+ struct client_state *client;
+ const char *reason;
struct string_list *medium;
{
struct string_list *sl, *next;
- if (ip) {
- for (sl = ip -> client -> env; sl; sl = next) {
+ if (client) {
+ for (sl = client -> env; sl; sl = next) {
next = sl -> next;
- dfree (sl, "script_init");
+ dfree (sl, MDL);
}
- ip -> client -> env = (struct string_list *)0;
- ip -> client -> envc = 0;
+ client -> env = (struct string_list *)0;
+ client -> envc = 0;
- client_envadd (ip -> client, "", "interface", "%s",
- ip -> name);
+ if (client -> interface) {
+ client_envadd (client, "", "interface", "%s",
+ client -> interface -> name);
+ }
+ if (client -> name)
+ client_envadd (client,
+ "", "client", "%s", client -> name);
if (medium)
- client_envadd (ip -> client,
+ client_envadd (client,
"", "medium", "%s", medium -> string);
- client_envadd (ip -> client, "", "reason", "%s", reason);
+ client_envadd (client, "", "reason", "%s", reason);
+ client_envadd (client, "", "pid", "%ld", (long int)getpid ());
}
}
-void script_write_params (ip, prefix, lease)
- struct interface_info *ip;
- char *prefix;
+struct envadd_state {
+ struct client_state *client;
+ const char *prefix;
+};
+
+void client_option_envadd (struct option_cache *oc,
+ struct packet *packet, struct lease *lease,
+ struct client_state *client_state,
+ struct option_state *in_options,
+ struct option_state *cfg_options,
+ struct binding_scope **scope,
+ struct universe *u, void *stuff)
+{
+ struct envadd_state *es = stuff;
+ struct data_string data;
+ memset (&data, 0, sizeof data);
+
+ if (evaluate_option_cache (&data, packet, lease, client_state,
+ in_options, cfg_options, scope, oc, MDL)) {
+ if (data.len) {
+ char name [256];
+ if (dhcp_option_ev_name (name, sizeof name,
+ oc -> option)) {
+ client_envadd (es -> client, es -> prefix,
+ name, "%s",
+ (pretty_print_option
+ (oc -> option,
+ data.data, data.len,
+ 0, 0)));
+ data_string_forget (&data, MDL);
+ }
+ }
+ }
+}
+
+void script_write_params (client, prefix, lease)
+ struct client_state *client;
+ const char *prefix;
struct client_lease *lease;
{
int i;
- u_int8_t dbuf [1500];
- int len;
+ struct data_string data;
+ struct option_cache *oc;
+ pair *hash;
+ char *s, *t;
+ struct envadd_state es;
- client_envadd (ip -> client,
+ es.client = client;
+ es.prefix = prefix;
+
+ client_envadd (client,
prefix, "ip_address", "%s", piaddr (lease -> address));
/* For the benefit of Linux (and operating systems which may
@@ -1942,125 +2441,66 @@ 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) {
- client_envadd (ip -> client, prefix, "network_number",
- "%s", piaddr (subnet));
-
- if (!lease -> options [DHO_BROADCAST_ADDRESS].len) {
+ memset (&data, 0, sizeof data);
+ oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
+ if (oc && evaluate_option_cache (&data, (struct packet *)0,
+ (struct lease *)0, client,
+ (struct option_state *)0,
+ lease -> options,
+ &global_scope, oc, MDL)) {
+ if (data.len > 3) {
+ struct iaddr netmask, subnet, broadcast;
+
+ memcpy (netmask.iabuf, data.data, data.len);
+ netmask.len = data.len;
+ data_string_forget (&data, MDL);
+
+ subnet = subnet_number (lease -> address, netmask);
+ if (subnet.len) {
+ client_envadd (client, prefix, "network_number",
+ "%s", piaddr (subnet));
+
+ oc = lookup_option (&dhcp_universe,
+ lease -> options,
+ DHO_BROADCAST_ADDRESS);
+ if (!oc ||
+ !(evaluate_option_cache
+ (&data, (struct packet *)0,
+ (struct lease *)0, client,
+ (struct option_state *)0,
+ lease -> options,
+ &global_scope, oc, MDL))) {
broadcast = broadcast_addr (subnet, netmask);
if (broadcast.len) {
- client_envadd (ip -> client,
+ client_envadd (client,
prefix, "broadcast_address",
"%s", piaddr (broadcast));
}
+ }
}
}
+ data_string_forget (&data, MDL);
}
if (lease -> filename)
- client_envadd (ip -> client,
+ client_envadd (client,
prefix, "filename", "%s", lease -> filename);
if (lease -> server_name)
- client_envadd (ip -> client, prefix, "server_name",
+ client_envadd (client, prefix, "server_name",
"%s", lease -> server_name);
- 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",
- "append option",
- dhcp_options [i].name);
- goto supersede;
- }
- dp = dbuf;
- memcpy (dp,
- lease -> options [i].data,
- lease -> options [i].len);
- memcpy (dp + lease -> options [i].len,
- ip -> client ->
- config -> defaults [i].data,
- ip -> client ->
- config -> defaults [i].len);
- }
- } 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 name [256];
- if (dhcp_option_ev_name (name, sizeof name,
- &dhcp_options [i])) {
- client_envadd (ip -> client, prefix, name, "%s",
- (pretty_print_option (i, dp,
- len, 0, 0)));
- }
- }
+
+ for (i = 0; i < lease -> options -> universe_count; i++) {
+ option_space_foreach ((struct packet *)0, (struct lease *)0,
+ client, (struct option_state *)0,
+ lease -> options, &global_scope,
+ universes [i],
+ &es, client_option_envadd);
}
- client_envadd (ip -> client,
- prefix, "expiry", "%d", (int)(lease -> expiry));
+ client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
}
-int script_go (ip)
- struct interface_info *ip;
+int script_go (client)
+ struct client_state *client;
{
int rval;
char *scriptName;
@@ -2073,59 +2513,68 @@ int script_go (ip)
struct string_list *sp, *next;
int pid, wpid, wstatus;
- if (ip) {
- scriptName = ip -> client -> config -> script_name;
- envp = dmalloc ((ip -> client -> envc + 2) * sizeof (char *),
- "script_go");
- if (!envp) {
- error ("No memory for client script environment.");
- return 0;
- }
- i = 0;
- for (sp = ip -> client -> env; sp; sp = sp -> next) {
+ if (client)
+ scriptName = client -> config -> script_name;
+ else
+ scriptName = top_level_config.script_name;
+
+ envp = dmalloc (((client ? client -> envc : 2) +
+ client_env_count + 2) * sizeof (char *), MDL);
+ if (!envp) {
+ log_error ("No memory for client script environment.");
+ return 0;
+ }
+ i = 0;
+ /* Copy out the environment specified on the command line,
+ if any. */
+ for (sp = client_env; sp; sp = sp -> next) {
+ envp [i++] = sp -> string;
+ }
+ /* Copy out the environment specified by dhclient. */
+ if (client) {
+ for (sp = client -> env; sp; sp = sp -> next) {
envp [i++] = sp -> string;
}
- envp [i++] = client_path;
- envp [i] = (char *)0;
} else {
- scriptName = top_level_config.script_name;
- epp [0] = reason;
- epp [1] = client_path;
- epp [2] = (char *)0;
- envp = epp;
+ envp [i++] = reason;
}
+ /* Set $PATH. */
+ envp [i++] = client_path;
+ envp [i] = (char *)0;
argv [0] = scriptName;
argv [1] = (char *)0;
pid = fork ();
if (pid < 0) {
- error ("fork: %m");
+ log_error ("fork: %m");
wstatus = 0;
} else if (pid) {
do {
wpid = wait (&wstatus);
} while (wpid != pid && wpid > 0);
if (wpid < 0) {
- error ("wait: %m");
+ log_error ("wait: %m");
wstatus = 0;
}
} else {
execve (scriptName, argv, envp);
- error ("execve (%s, ...): %m", scriptName);
+ log_error ("execve (%s, ...): %m", scriptName);
exit (0);
}
- if (ip) {
- for (sp = ip -> client -> env; sp; sp = next) {
+ if (client) {
+ for (sp = client -> env; sp; sp = next) {
next = sp -> next;
- dfree (sp, "script_go");
+ dfree (sp, MDL);
}
- ip -> client -> env = (struct string_list *)0;
- ip -> client -> envc = 0;
- dfree (envp, "script_go");
+ client -> env = (struct string_list *)0;
+ client -> envc = 0;
}
- return wstatus & 0xff;
+ dfree (envp, MDL);
+ GET_TIME (&cur_time);
+ return (WIFEXITED (wstatus) ?
+ WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
}
void client_envadd (struct client_state *client,
@@ -2142,7 +2591,7 @@ void client_envadd (struct client_state *client,
va_end (list);
val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
- len + sizeof *val, "client_envadd");
+ len + sizeof *val, MDL);
if (!val)
return;
s = val -> string;
@@ -2166,25 +2615,46 @@ int dhcp_option_ev_name (buf, buflen, option)
size_t buflen;
struct option *option;
{
- int i;
+ int i, j;
+ const char *s;
- for (i = 0; option -> name [i]; i++) {
- if (i + 1 == buflen)
- return 0;
- if (option -> name [i] == '-')
- buf [i] = '_';
- else
- buf [i] = option -> name [i];
+ j = 0;
+ if (option -> universe != &dhcp_universe) {
+ s = option -> universe -> name;
+ i = 0;
+ } else {
+ s = option -> name;
+ i = 1;
}
- buf [i] = 0;
+ do {
+ while (*s) {
+ if (j + 1 == buflen)
+ return 0;
+ if (*s == '-')
+ buf [j++] = '_';
+ else
+ buf [j++] = *s;
+ ++s;
+ }
+ if (!i) {
+ s = option -> name;
+ if (j + 1 == buflen)
+ return 0;
+ buf [j++] = '_';
+ }
+ ++i;
+ } while (i != 2);
+
+ buf [j] = 0;
return 1;
}
-
+
void go_daemon ()
{
static int state = 0;
int pid;
+ int i;
/* Don't become a daemon if the user requested otherwise. */
if (no_daemon) {
@@ -2202,7 +2672,7 @@ void go_daemon ()
/* Become a daemon... */
if ((pid = fork ()) < 0)
- error ("Can't fork daemon: %m");
+ log_fatal ("Can't fork daemon: %m");
else if (pid)
exit (0);
/* Become session leader and get pid... */
@@ -2213,6 +2683,16 @@ void go_daemon ()
close(1);
close(2);
+ /* Reopen them on /dev/null. */
+ i = open ("/dev/null", O_RDWR);
+ if (i == 0)
+ i = open ("/dev/null", O_RDWR);
+ if (i == 1) {
+ i = open ("/dev/null", O_RDWR);
+ log_perror = 0; /* No sense logging to /dev/null. */
+ } else if (i != -1)
+ close (i);
+
write_client_pid_file ();
}
@@ -2224,15 +2704,384 @@ void write_client_pid_file ()
pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (pfdesc < 0) {
- warn ("Can't create %s: %m", path_dhclient_pid);
+ log_error ("Can't create %s: %m", path_dhclient_pid);
return;
}
pf = fdopen (pfdesc, "w");
if (!pf)
- warn ("Can't fdopen %s: %m", path_dhclient_pid);
+ log_error ("Can't fdopen %s: %m", path_dhclient_pid);
else {
fprintf (pf, "%ld\n", (long)getpid ());
fclose (pf);
}
}
+
+void client_location_changed ()
+{
+ struct interface_info *ip;
+ struct client_state *client;
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ for (client = ip -> client; client; client = client -> next) {
+ switch (client -> state) {
+ case S_SELECTING:
+ cancel_timeout (send_discover, client);
+ break;
+
+ case S_BOUND:
+ cancel_timeout (state_bound, client);
+ break;
+
+ case S_REBOOTING:
+ case S_REQUESTING:
+ case S_RENEWING:
+ cancel_timeout (send_request, client);
+ break;
+
+ case S_INIT:
+ case S_REBINDING:
+ case S_STOPPED:
+ break;
+ }
+ client -> state = S_INIT;
+ state_reboot (client);
+ }
+ }
+}
+
+void do_release(client)
+ struct client_state *client;
+{
+ struct data_string ds;
+ struct option_cache *oc;
+
+ /* Pick a random xid. */
+ client -> xid = random ();
+
+ /* is there even a lease to release? */
+ if (client -> active) {
+ /* Make a DHCPRELEASE packet, and set appropriate per-interface
+ flags. */
+ make_release (client, client -> active);
+
+ memset (&ds, 0, sizeof ds);
+ oc = lookup_option (&dhcp_universe,
+ client -> active -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ if (oc &&
+ evaluate_option_cache (&ds, (struct packet *)0,
+ (struct lease *)0, client,
+ (struct option_state *)0,
+ client -> active -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3) {
+ memcpy (client -> destination.iabuf,
+ ds.data, 4);
+ client -> destination.len = 4;
+ } else
+ client -> destination = iaddr_broadcast;
+ } else
+ client -> destination = iaddr_broadcast;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
+
+ /* Zap the medium list... */
+ client -> medium = (struct string_list *)0;
+
+ /* Send out the first and only DHCPRELEASE packet. */
+ send_release (client);
+
+ /* Do the client script RELEASE operation. */
+ script_init (client,
+ "RELEASE", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_write_params (client, "old_", client -> active);
+ script_go (client);
+ }
+
+ /* Cancel any timeouts. */
+ cancel_timeout (state_bound, client);
+ cancel_timeout (send_discover, client);
+ cancel_timeout (state_init, client);
+ cancel_timeout (send_request, client);
+ cancel_timeout (state_reboot, client);
+ client -> state = S_STOPPED;
+}
+
+int dhclient_interface_shutdown_hook (struct interface_info *interface)
+{
+ do_release (interface -> client);
+
+ return 1;
+}
+
+int dhclient_interface_discovery_hook (struct interface_info *tmp)
+{
+ struct interface_info *last, *ip;
+ /* See if we can find the client from dummy_interfaces */
+ last = 0;
+ for (ip = dummy_interfaces; ip; ip = ip -> next) {
+ if (!strcmp (ip -> name, tmp -> name)) {
+ /* Remove from dummy_interfaces */
+ if (last) {
+ ip = (struct interface_info *)0;
+ interface_reference (&ip, last -> next, MDL);
+ interface_dereference (&last -> next, MDL);
+ if (ip -> next) {
+ interface_reference (&last -> next,
+ ip -> next, MDL);
+ interface_dereference (&ip -> next,
+ MDL);
+ }
+ } else {
+ ip = (struct interface_info *)0;
+ interface_reference (&ip,
+ dummy_interfaces, MDL);
+ interface_dereference (&dummy_interfaces, MDL);
+ if (ip -> next) {
+ interface_reference (&dummy_interfaces,
+ ip -> next, MDL);
+ interface_dereference (&ip -> next,
+ MDL);
+ }
+ }
+ /* Copy "client" to tmp */
+ if (ip -> client) {
+ tmp -> client = ip -> client;
+ tmp -> client -> interface = tmp;
+ }
+ interface_dereference (&ip, MDL);
+ break;
+ }
+ last = ip;
+ }
+ return 1;
+}
+
+isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
+{
+ struct interface_info *ip;
+ struct client_state *client;
+
+ /* This code needs some rethinking. It doesn't test against
+ a signal name, and it just kind of bulls into doing something
+ that may or may not be appropriate. */
+
+ if (interfaces) {
+ interface_reference (&interface -> next, interfaces, MDL);
+ interface_dereference (&interfaces, MDL);
+ }
+ interface_reference (&interfaces, interface, MDL);
+
+ discover_interfaces (DISCOVER_UNCONFIGURED);
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ /* If interfaces were specified, don't configure
+ interfaces that weren't specified! */
+ if (ip -> flags & INTERFACE_RUNNING ||
+ (ip -> flags & (INTERFACE_REQUESTED |
+ INTERFACE_AUTOMATIC)) !=
+ INTERFACE_REQUESTED)
+ continue;
+ script_init (ip -> client,
+ "PREINIT", (struct string_list *)0);
+ if (ip -> client -> alias)
+ script_write_params (ip -> client, "alias_",
+ ip -> client -> alias);
+ script_go (ip -> client);
+ }
+
+ discover_interfaces (interfaces_requested
+ ? DISCOVER_REQUESTED
+ : DISCOVER_RUNNING);
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ if (ip -> flags & INTERFACE_RUNNING)
+ continue;
+ ip -> flags |= INTERFACE_RUNNING;
+ for (client = ip -> client; client; client = client -> next) {
+ client -> state = S_INIT;
+ /* Set up a timeout to start the initialization
+ process. */
+ add_timeout (cur_time + random () % 5,
+ state_reboot, client, 0, 0);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* The client should never receive a relay agent information option,
+ so if it does, log it and discard it. */
+
+int parse_agent_information_option (packet, len, data)
+ struct packet *packet;
+ int len;
+ u_int8_t *data;
+{
+ return 1;
+}
+
+/* The client never sends relay agent information options. */
+
+unsigned cons_agent_information_options (cfg_options, outpacket,
+ agentix, length)
+ struct option_state *cfg_options;
+ struct dhcp_packet *outpacket;
+ unsigned agentix;
+ unsigned length;
+{
+ return length;
+}
+
+static void shutdown_exit (void *foo)
+{
+ exit (0);
+}
+
+isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
+ control_object_state_t newstate)
+{
+ struct interface_info *ip;
+ struct client_state *client;
+
+ /* Do the right thing for each interface. */
+ for (ip = interfaces; ip; ip = ip -> next) {
+ for (client = ip -> client; client; client = client -> next) {
+ switch (newstate) {
+ case server_startup:
+ return ISC_R_SUCCESS;
+
+ case server_running:
+ return ISC_R_SUCCESS;
+
+ case server_shutdown:
+ if (client -> active &&
+ client -> active -> expiry > cur_time) {
+ client_dns_update (client, 0);
+ do_release (client);
+ }
+ break;
+
+ case server_hibernate:
+ state_stop (client);
+ break;
+
+ case server_awaken:
+ state_reboot (client);
+ break;
+ }
+ }
+ }
+ if (newstate == server_shutdown)
+ add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0);
+ return ISC_R_SUCCESS;
+}
+
+/* See if we should do a DNS update, and if so, do it. */
+
+void client_dns_update (struct client_state *client, int addp)
+{
+ struct data_string ddns_fqdn, ddns_fwd_name,
+ ddns_dhcid, client_identifier;
+ struct option_cache *oc;
+ int ignorep;
+ int result;
+ isc_result_t rcode;
+
+ /* If we didn't send an FQDN option, we certainly aren't going to
+ be doing an update. */
+ if (!client -> sent_options)
+ return;
+
+ /* If we don't have a lease, we can't do an update. */
+ if (!client -> active)
+ return;
+
+ /* If we set the no client update flag, don't do the update. */
+ if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
+ FQDN_NO_CLIENT_UPDATE)) &&
+ evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL))
+ return;
+
+ /* If we set the "server, please update" flag, or didn't set it
+ to false, don't do the update. */
+ if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
+ FQDN_SERVER_UPDATE)) ||
+ evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL))
+ return;
+
+ /* If no FQDN option was supplied, don't do the update. */
+ memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
+ if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
+ FQDN_FQDN)) ||
+ !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL))
+ return;
+
+ /* Make a dhcid string out of either the client identifier,
+ if we are sending one, or the interface's MAC address,
+ otherwise. */
+ memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
+
+ memset (&client_identifier, 0, sizeof client_identifier);
+ if ((oc = lookup_option (&dhcp_universe, client -> sent_options,
+ DHO_DHCP_CLIENT_IDENTIFIER)) &&
+ evaluate_option_cache (&client_identifier, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL)) {
+ result = get_dhcid (&ddns_dhcid,
+ DHO_DHCP_CLIENT_IDENTIFIER,
+ client_identifier.data,
+ client_identifier.len);
+ data_string_forget (&client_identifier, MDL);
+ } else
+ result = get_dhcid (&ddns_dhcid, 0,
+ client -> interface -> hw_address.hbuf,
+ client -> interface -> hw_address.hlen);
+ if (!result) {
+ data_string_forget (&ddns_fwd_name, MDL);
+ return;
+ }
+
+ /* Start the resolver, if necessary. */
+ if (!resolver_inited) {
+ minires_ninit (&resolver_state);
+ resolver_inited = 1;
+ resolver_state.retrans = 1;
+ resolver_state.retry = 1;
+ }
+
+ /*
+ * Perform updates.
+ */
+ if (ddns_fwd_name.len && ddns_dhcid.len) {
+ if (addp)
+ rcode = ddns_update_a (&ddns_fwd_name,
+ client -> active -> address,
+ &ddns_dhcid, DEFAULT_DDNS_TTL,
+ 1);
+ else
+ rcode = ddns_remove_a (&ddns_fwd_name,
+ client -> active -> address,
+ &ddns_dhcid);
+ }
+
+ data_string_forget (&ddns_fwd_name, MDL);
+ data_string_forget (&ddns_dhcid, MDL);
+}
OpenPOWER on IntegriCloud