#ifndef lint
static char copyright[] =
-"$Id: dhclient.c,v 1.39 1997/06/03 01:40:58 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.40 1997/09/16 18:09:41 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
char *path_dhclient_db = _PATH_DHCLIENT_DB;
char *path_dhclient_pid = _PATH_DHCLIENT_PID;
+int interfaces_requested = 0;
+
int log_perror = 1;
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
strcpy (tmp -> name, argv [i]);
tmp -> next = interfaces;
tmp -> flags = INTERFACE_REQUESTED;
+ interfaces_requested = 1;
interfaces = tmp;
}
}
are relevant should be running, so now we once again call
discover_interfaces(), and this time ask it to actually set
up the interfaces. */
- discover_interfaces (DISCOVER_RUNNING);
+ discover_interfaces (interfaces_requested
+ ? DISCOVER_REQUESTED
+ : DISCOVER_RUNNING);
/* Make up a seed for the random number generator from current
time plus the sum of the last four bytes of each
/* Set up the bootp packet handler... */
bootp_packet_handler = do_packet;
+ /* Start listening on the systat socket... */
+ systat_startup (status_message);
+
/* Start dispatching packets and timeouts... */
dispatch ();
ip -> client -> first_sending = cur_time;
ip -> client -> interval = ip -> client -> config -> initial_interval;
- /* Add an immediate timeout to cause the first DHCPDISCOVER packet
- to go out. */
+ /* Zap the medium list... */
+ ip -> client -> medium = (struct string_list *)0;
+
+ /* Send out the first DHCPREQUEST packet. */
send_request (ip);
}
void bind_lease (ip)
struct interface_info *ip;
{
- /* Write out the new lease. */
- write_client_lease (ip, ip -> client -> new);
-
/* Remember the medium. */
ip -> client -> new -> medium = ip -> client -> medium;
+ /* Write out the new lease. */
+ write_client_lease (ip, ip -> client -> new);
+
/* Run the client script with the new parameters. */
script_init (ip, (ip -> client -> state == S_REQUESTING
? "BOUND"
note ("%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 [i].len) {
lease -> options [i].data =
(unsigned char *)
- malloc (packet -> options [i].len);
+ malloc (packet -> options [i].len + 1);
if (!lease -> options [i].data) {
warn ("dhcpoffer: no memory for option %d\n",
i);
packet -> options [i].len);
lease -> options [i].len =
packet -> options [i].len;
+ lease -> options [i].data
+ [lease -> options [i].len] = 0;
}
}
}
if ((ip -> client -> state == S_REBOOTING ||
ip -> client -> state == S_REQUESTING) &&
interval > ip -> client -> config -> reboot_timeout) {
+ cancel:
ip -> client -> state = S_INIT;
cancel_timeout (send_request, ip);
state_init (ip);
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 the medium we chose won't fly, go to INIT state. */
+ if (script_go (ip))
+ goto cancel;
+
+ /* Record the medium. */
+ ip -> client -> medium = ip -> client -> active -> medium;
+ }
+
/* If the lease has expired, relinquish the address and go back
to the INIT state. */
if (ip -> client -> state != S_REQUESTING &&
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet,
- options, 0, 0);
+ options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet,
- options, 0, 0);
+ options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet,
- options, 0, 0);
+ options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
/* Set up the option buffer... */
ip -> client -> packet_length =
cons_options ((struct packet *)0, &ip -> client -> packet,
- options, 0, 0);
+ options, 0, 0, 0);
if (ip -> client -> packet_length < BOOTP_MIN_LEN)
ip -> client -> packet_length = BOOTP_MIN_LEN;
char *reason;
struct string_list *medium;
{
- strcpy (scriptName, "/tmp/dcsXXXXXX");
- mktemp (scriptName);
+ int fd;
+#ifndef HAVE_MKSTEMP
- scriptFile = fopen (scriptName, "w");
+ do {
+#endif
+ strcpy (scriptName, "/tmp/dcsXXXXXX");
+#ifdef HAVE_MKSTEMP
+ fd = mkstemp (scriptName);
+#else
+ mktemp (scriptName);
+ fd = creat (scriptName, 0600);
+ } while (fd < 0);
+#endif
+
+ scriptFile = fdopen (fd, "w");
if (!scriptFile)
error ("can't write script file: %m");
fprintf (scriptFile, "#!/bin/sh\n\n");
int pid;
/* Don't become a daemon if the user requested otherwise. */
- if (no_daemon)
+ if (no_daemon) {
+ write_client_pid_file ();
return;
+ }
/* Only do it once. */
if (state)
exit (0);
/* Become session leader and get pid... */
pid = setsid ();
+
+ write_client_pid_file ();
+}
+
+void write_client_pid_file ()
+{
+ FILE *pf;
+ int pfdesc;
+
+ pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+
+ if (pfdesc < 0) {
+ warn ("Can't create %s: %m", path_dhclient_pid);
+ return;
+ }
+
+ pf = fdopen (pfdesc, "w");
+ if (!pf)
+ warn ("Can't fdopen %s: %m", path_dhclient_pid);
+ else {
+ fprintf (pf, "%d\n", getpid ());
+ fclose (pf);
+ }
+}
+
+void status_message (header, data)
+ struct systat_header *header;
+ void *data;
+{
+ switch (header -> type) {
+ case NETWORK_LOCATION_CHANGED:
+ client_location_changed ();
+ break;
+
+ default:
+ break;
+ }
}
+void client_location_changed ()
+{
+ struct interface_info *ip;
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ switch (ip -> client -> state) {
+ case S_SELECTING:
+ cancel_timeout (send_discover, ip);
+ break;
+
+ case S_BOUND:
+ cancel_timeout (state_bound, ip);
+ break;
+
+ case S_REBOOTING:
+ case S_REQUESTING:
+ case S_RENEWING:
+ cancel_timeout (send_request, ip);
+ break;
+
+ case S_INIT:
+ case S_REBINDING:
+ break;
+ }
+ ip -> client -> state = S_INIT;
+ state_reboot (ip);
+ }
+}