struct option *iaaddr_option = NULL;
struct option *iaprefix_option = NULL;
struct option *oro_option = NULL;
+struct option *irt_option = NULL;
static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
const char *file, int line);
static struct dhc6_addr *find_addr(struct dhc6_addr *head,
struct iaddr *address);
void init_handler(struct packet *packet, struct client_state *client);
+void info_request_handler(struct packet *packet, struct client_state *client);
void rapid_commit_handler(struct packet *packet, struct client_state *client);
void do_init6(void *input);
+void do_info_request6(void *input);
void do_confirm6(void *input);
void reply_handler(struct packet *packet, struct client_state *client);
static isc_result_t dhc6_add_ia_na(struct client_state *client,
void do_refresh6(void *input);
static void do_release6(void *input);
static void start_bound(struct client_state *client);
+static void start_informed(struct client_state *client);
+void informed_handler(struct packet *packet, struct client_state *client);
void bound_handler(struct packet *packet, struct client_state *client);
void start_renew6(void *input);
void start_rebind6(void *input);
const char *prefix,
struct option_state *options);
+extern int stateless;
+
/* The "best" default DUID, since we cannot predict any information
* about the system (such as whether or not the hardware addresses are
* integrated into the motherboard or similar), is the "LLT", link local
- * plus time, DUID.
+ * plus time, DUID. For real stateless "LL" is better.
*
* Once generated, this duid is stored into the state database, and
* retained across restarts.
/* 2 bytes for the 'duid type' field.
* 2 bytes for the 'htype' field.
- * 4 bytes for the 'current time'.
+ * (not stateless) 4 bytes for the 'current time'.
* enough bytes for the hardware address (note that hw_address has
* the 'htype' on byte zero).
*/
- len = 8 + (ip->hw_address.hlen - 1);
+ len = 4 + (ip->hw_address.hlen - 1);
+ if (!stateless)
+ len += 4;
if (!buffer_allocate(&duid->buffer, len, MDL))
log_fatal("no memory for default DUID!");
duid->data = duid->buffer->data;
duid->len = len;
/* Basic Link Local Address type of DUID. */
- putUShort(duid->buffer->data, DUID_LLT);
- putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
- putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
- memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
- ip->hw_address.hlen - 1);
+ if (!stateless) {
+ putUShort(duid->buffer->data, DUID_LLT);
+ putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
+ putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
+ memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
+ ip->hw_address.hlen - 1);
+ } else {
+ putUShort(duid->buffer->data, DUID_LL);
+ putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
+ memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
+ ip->hw_address.hlen - 1);
+ }
}
/* Assign DHCPv6 port numbers as a client.
&code, 0, MDL))
log_fatal("Unable to find the ORO option definition.");
+ code = D6O_INFORMATION_REFRESH_TIME;
+ if (!option_code_hash_lookup(&irt_option, dhcpv6_universe.code_hash,
+ &code, 0, MDL))
+ log_fatal("Unable to find the IRT option definition.");
+
#ifndef __CYGWIN32__ /* XXX */
endservent();
#endif
client->MRD = 0;
dhc6_retrans_init(client);
- /* RFC3315 section 17.1.2 goes out of its way:
- *
+
+ /*
+ * RFC3315 section 17.1.2 goes out of its way:
* Also, the first RT MUST be selected to be strictly greater than IRT
* by choosing RAND to be strictly greater than 0.
*/
go_daemon();
}
-/* start_init6() kicks off an "init-reboot" version of the process, at
+/* start_info_request6() kicks off the process, transmitting an info
+ * request packet and scheduling a retransmission event.
+ */
+void
+start_info_request6(struct client_state *client)
+{
+ struct timeval tv;
+
+ log_debug("PRC: Requesting information (INIT).");
+ client->state = S_INIT;
+
+ /* Initialize timers, RFC3315 section 18.1.5. */
+ client->IRT = INF_TIMEOUT * 100;
+ client->MRT = INF_MAX_RT * 100;
+ client->MRC = 0;
+ client->MRD = 0;
+
+ dhc6_retrans_init(client);
+
+ client->v6_handler = info_request_handler;
+
+ /* RFC3315 section 18.1.5 says we MUST start the first packet
+ * between 0 and INF_MAX_DELAY seconds. The good news is
+ * INF_MAX_DELAY is 1.
+ */
+ tv.tv_sec = cur_tv.tv_sec;
+ tv.tv_usec = cur_tv.tv_usec;
+ tv.tv_usec += (random() % (INF_MAX_DELAY * 100)) * 10000;
+ if (tv.tv_usec >= 1000000) {
+ tv.tv_sec += 1;
+ tv.tv_usec -= 1000000;
+ }
+ add_timeout(&tv, do_info_request6, client, NULL, NULL);
+
+ if (nowait)
+ go_daemon();
+}
+
+/* start_confirm6() kicks off an "init-reboot" version of the process, at
* startup to find out if old bindings are 'fair' and at runtime whenever
* a link cycles state we'll eventually want to do this.
*/
dhc6_retrans_advance(client);
}
+/* do_info_request6() marshals and transmits an information-request. */
+void
+do_info_request6(void *input)
+{
+ struct client_state *client;
+ struct data_string ds;
+ struct timeval elapsed, tv;
+ int send_ret;
+
+ client = input;
+
+ if ((client->MRC != 0) && (client->txcount > client->MRC)) {
+ log_info("Max retransmission count exceeded.");
+ return;
+ }
+
+ /*
+ * Start_time starts at the first transmission.
+ */
+ if (client->txcount == 0) {
+ client->start_time.tv_sec = cur_tv.tv_sec;
+ client->start_time.tv_usec = cur_tv.tv_usec;
+ }
+
+ /* elapsed = cur - start */
+ elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
+ elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
+ if (elapsed.tv_usec < 0) {
+ elapsed.tv_sec -= 1;
+ elapsed.tv_usec += 1000000;
+ }
+ if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
+ log_info("Max retransmission duration exceeded.");
+ return;
+ }
+
+ memset(&ds, 0, sizeof(ds));
+ if (!buffer_allocate(&ds.buffer, 4, MDL)) {
+ log_error("Unable to allocate memory for INFO-REQUEST.");
+ return;
+ }
+ ds.data = ds.buffer->data;
+ ds.len = 4;
+
+ ds.buffer->data[0] = DHCPV6_INFORMATION_REQUEST;
+ memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
+
+ /* Form an elapsed option. */
+ /* Maximum value is 65535 1/100s coded as 0xffff. */
+ if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
+ ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
+ client->elapsed = 0xffff;
+ } else {
+ client->elapsed = elapsed.tv_sec * 100;
+ client->elapsed += elapsed.tv_usec / 10000;
+ }
+
+ if (client->elapsed == 0)
+ log_debug("XMT: Forming Info-Request, 0 ms elapsed.");
+ else
+ log_debug("XMT: Forming Info-Request, %u0 ms elapsed.",
+ (unsigned)client->elapsed);
+
+ client->elapsed = htons(client->elapsed);
+
+ make_client6_options(client, &client->sent_options, NULL,
+ DHCPV6_INFORMATION_REQUEST);
+
+ /* Fetch any configured 'sent' options (includes DUID) in wire format.
+ */
+ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
+ NULL, client->sent_options, &global_scope,
+ &dhcpv6_universe);
+
+ /* Transmit and wait. */
+
+ log_info("XMT: Info-Request on %s, interval %ld0ms.",
+ client->name ? client->name : client->interface->name,
+ (long int)client->RT);
+
+ send_ret = send_packet6(client->interface,
+ ds.data, ds.len, &DHCPv6DestAddr);
+ if (send_ret != ds.len) {
+ log_error("dhc6: send_packet6() sent %d of %d bytes",
+ send_ret, ds.len);
+ }
+
+ data_string_forget(&ds, MDL);
+
+ /* Wait RT */
+ tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
+ tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
+ if (tv.tv_usec >= 1000000) {
+ tv.tv_sec += 1;
+ tv.tv_usec -= 1000000;
+ }
+ add_timeout(&tv, do_info_request6, client, NULL, NULL);
+
+ dhc6_retrans_advance(client);
+}
+
/* do_confirm6() creates a Confirm packet and transmits it. This function
* is called on every timeout to (re)transmit.
*/
log_debug("RCV: Advertisement recorded.");
}
+/* info_request_handler() accepts a Reply to an Info-request.
+ */
+void
+info_request_handler(struct packet *packet, struct client_state *client)
+{
+ isc_result_t check_status;
+ unsigned code;
+
+ if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
+ return;
+
+ /* RFC3315 section 15.10 validation (same as 15.3 since we
+ * always include a client id).
+ */
+ if (!valid_reply(packet, client)) {
+ log_error("Invalid Reply - rejecting.");
+ return;
+ }
+
+ check_status = dhc6_check_status(ISC_R_SUCCESS, packet->options,
+ "message", &code);
+ if (check_status != ISC_R_SUCCESS) {
+ /* If no action was taken, but there is an error, then
+ * we wait for a retransmission.
+ */
+ if (check_status != ISC_R_CANCELED)
+ return;
+ }
+
+ /* We're done retransmitting at this point. */
+ cancel_timeout(do_info_request6, client);
+
+ /* Action was taken, so now that we've torn down our scheduled
+ * retransmissions, return.
+ */
+ if (check_status == ISC_R_CANCELED)
+ return;
+
+ /* Cleanup if a previous attempt to go bound failed. */
+ if (client->old_lease != NULL) {
+ dhc6_lease_destroy(&client->old_lease, MDL);
+ client->old_lease = NULL;
+ }
+
+ /* Cache options in the active_lease. */
+ if (client->active_lease != NULL)
+ client->old_lease = client->active_lease;
+ client->active_lease = dmalloc(sizeof(struct dhc6_lease), MDL);
+ if (client->active_lease == NULL)
+ log_fatal("Out of memory for v6 lease structure.");
+ option_state_reference(&client->active_lease->options,
+ packet->options, MDL);
+
+ start_informed(client);
+}
+
/* Specific version of init_handler() for rapid-commit.
*/
void
* to inform it about the new values, and then lay in wait for the next
* event.
*/
-void
+static void
start_bound(struct client_state *client)
{
struct dhc6_ia *ia, *oldia;
* Run client script to unconfigure interface.
* Called with reason STOP6 when dhclient -x is run, or with reason
* RELEASE6 when server has replied to a Release message.
+ * Stateless is a special case.
*/
void
unconfigure6(struct client_state *client, const char *reason)
struct dhc6_ia *ia;
struct dhc6_addr *addr;
+ if (stateless) {
+ script_init(client, reason, NULL);
+ if (client->active_lease != NULL)
+ script_write_params6(client, "old_",
+ client->active_lease->options);
+ script_go(client);
+ return;
+ }
+
if (client->active_lease == NULL)
return;
}
}
+void
+refresh_info_request6(void *input)
+{
+ struct client_state *client;
+
+ client = (struct client_state *)input;
+ start_info_request6(client);
+}
+
+/* Timeout for Information-Request (using the IRT option).
+ */
+static void
+dhc6_check_irt(struct client_state *client)
+{
+ struct option **req;
+ struct option_cache *oc;
+ TIME expire = MAX_TIME;
+ struct timeval tv;
+ int i;
+ isc_boolean_t found = ISC_FALSE;
+
+ cancel_timeout(refresh_info_request6, client);
+
+ req = client->config->requested_options;
+ for (i = 0; req[i] != NULL; i++) {
+ if (req[i] == irt_option) {
+ found = ISC_TRUE;
+ break;
+ }
+ }
+ /* Simply return gives a endless loop waiting for nothing. */
+ if (!found)
+ exit(0);
+
+ oc = lookup_option(&dhcpv6_universe, client->active_lease->options,
+ D6O_INFORMATION_REFRESH_TIME);
+ if (oc != NULL) {
+ struct data_string irt;
+
+ memset(&irt, 0, sizeof(irt));
+ if (!evaluate_option_cache(&irt, NULL, NULL, client,
+ client->active_lease->options,
+ NULL, &global_scope, oc, MDL) ||
+ (irt.len < 4)) {
+ log_error("Can't evaluate IRT.");
+ } else {
+ expire = getULong(irt.data);
+ if (expire < IRT_MINIMUM)
+ expire = IRT_MINIMUM;
+ if (expire == 0xffffffff)
+ expire = MAX_TIME;
+ }
+ data_string_forget(&irt, MDL);
+ } else
+ expire = IRT_DEFAULT;
+
+ if (expire != MAX_TIME) {
+ log_debug("PRC: Refresh event scheduled in %u seconds.",
+ (unsigned) expire);
+ tv.tv_sec = cur_time + expire;
+ tv.tv_usec = 0;
+ add_timeout(&tv, refresh_info_request6, client, NULL, NULL);
+ }
+}
+
+/* We got a Reply. Give dhclient-script a tickle to inform it about
+ * the new values, and then lay in wait for the next event.
+ */
+static void
+start_informed(struct client_state *client)
+{
+ client->v6_handler = informed_handler;
+
+ log_debug("PRC: Done.");
+
+ client->state = S_BOUND;
+
+ script_init(client, "RENEW6", NULL);
+ if (client->old_lease != NULL)
+ script_write_params6(client, "old_",
+ client->old_lease->options);
+ script_write_params6(client, "new_", client->active_lease->options);
+ script_go(client);
+
+ go_daemon();
+
+ if (client->old_lease != NULL) {
+ dhc6_lease_destroy(&client->old_lease, MDL);
+ client->old_lease = NULL;
+ }
+
+ /* Schedule events. */
+ dhc6_check_irt(client);
+}
+
+/* While informed, ignore packets.
+ */
+void
+informed_handler(struct packet *packet, struct client_state *client)
+{
+ log_debug("RCV: Input packets are ignored once bound.");
+}
+
/* make_client6_options() fetches option caches relevant to the client's
* scope and places them into the sent_options cache. This cache is later
* used to populate DHCPv6 output packets with options.
int onetry=0;
int quiet=1;
int nowait=0;
+int stateless=0;
char *mockup_relay = NULL;
+void run_stateless(int exit_mode);
+
static void usage PROTO ((void));
static isc_result_t write_duid(struct data_string *duid);
-int
+int
main(int argc, char **argv) {
int fd;
int i;
unsigned seed;
char *server = (char *)0;
isc_result_t status;
- int exit_mode = 0;
- int release_mode = 0;
+ int exit_mode = 0;
+ int release_mode = 0;
struct timeval tv;
omapi_object_t *listener;
isc_result_t result;
/* Initialize client globals. */
memset(&default_duid, 0, sizeof(default_duid));
- /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
- 2 (stderr) are open. To do this, we assume that when we
- open a file the lowest available file descriptor is used. */
- fd = open("/dev/null", O_RDWR);
- if (fd == 0)
- fd = open("/dev/null", O_RDWR);
- if (fd == 1)
- fd = open("/dev/null", O_RDWR);
- if (fd == 2)
- log_perror = 0; /* No sense logging to /dev/null. */
- else if (fd != -1)
- close(fd);
+ /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
+ 2 (stderr) are open. To do this, we assume that when we
+ open a file the lowest available file descriptor is used. */
+ fd = open("/dev/null", O_RDWR);
+ if (fd == 0)
+ fd = open("/dev/null", O_RDWR);
+ if (fd == 1)
+ fd = open("/dev/null", O_RDWR);
+ if (fd == 2)
+ log_perror = 0; /* No sense logging to /dev/null. */
+ else if (fd != -1)
+ close(fd);
openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
#if !(defined (DEBUG) || defined (__CYGWIN32__))
setlogmask (LOG_UPTO (LOG_INFO));
-#endif
+#endif
/* Set up the OMAPI. */
status = omapi_init ();
dhcp_interface_startup_hook = dhclient_interface_startup_hook;
for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-r")) {
+ if (!strcmp(argv[i], "-r")) {
release_mode = 1;
no_daemon = 1;
#ifdef DHCPv6
local_family_set = 1;
local_family = AF_INET6;
#endif /* DHCPv6 */
- } else if (!strcmp (argv [i], "-x")) { /* eXit, no release */
- release_mode = 0;
- no_daemon = 0;
- exit_mode = 1;
+ } else if (!strcmp (argv [i], "-x")) { /* eXit, no release */
+ release_mode = 0;
+ no_daemon = 0;
+ exit_mode = 1;
} else if (!strcmp (argv [i], "-p")) {
if (++i == argc)
usage ();
} else if (!strcmp (argv [i], "-d")) {
no_daemon = 1;
quiet = 0;
- } else if (!strcmp (argv [i], "-pf")) {
- if (++i == argc)
- usage ();
- path_dhclient_pid = argv [i];
+ } 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];
+ } 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];
+ } 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 ();
- path_dhclient_script = argv [i];
+ path_dhclient_script = argv [i];
no_dhclient_script = 1;
} else if (!strcmp (argv [i], "-1")) {
onetry = 1;
nowait = 1;
} else if (!strcmp (argv [i], "-n")) {
/* do not start up any interfaces */
- interfaces_requested = 1;
+ interfaces_requested = -1;
} else if (!strcmp (argv [i], "-w")) {
/* do not exit if there are no broadcast interfaces. */
persist = 1;
tmp -> next = client_env;
client_env = tmp;
client_env_count++;
+ } else if (!strcmp(argv[i], "-S")) {
+ if (local_family_set && (local_family == AF_INET)) {
+ usage ();
+ }
+ local_family_set = 1;
+ local_family = AF_INET6;
+ stateless = 1;
} else if (!strcmp(argv[i], "-v")) {
quiet = 0;
} else if (!strcmp (argv [i], "--version")) {
log_info ("isc-dhclient-%s", PACKAGE_VERSION);
exit (0);
- } else if (argv [i][0] == '-') {
- usage ();
+ } else if (argv [i][0] == '-') {
+ usage ();
+ } else if (interfaces_requested < 0) {
+ usage ();
} else {
- struct interface_info *tmp = (struct interface_info *)0;
+ 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",
+ 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 (is %ld)",
interface_dereference (&interfaces, MDL);
}
interface_reference (&interfaces, tmp, MDL);
- tmp -> flags = INTERFACE_REQUESTED;
- interfaces_requested = 1;
- }
+ tmp -> flags = INTERFACE_REQUESTED;
+ interfaces_requested++;
+ }
}
if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
if (path_dhclient_db == NULL)
log_fatal("%s: %s", path, strerror(errno));
}
-
+
if (path_dhclient_script[0] != '/') {
char *path = dmalloc(PATH_MAX, MDL);
if (path == NULL)
if (path_dhclient_script == NULL)
log_fatal("%s: %s", path, strerror(errno));
}
-
+
/* first kill off any currently running client */
if (release_mode || exit_mode) {
FILE *pidfd;
inaddr_any.s_addr = INADDR_ANY;
+ /* Stateless special case. */
+ if (stateless) {
+ if (release_mode || (interfaces_requested != 1)) {
+ usage ();
+ }
+ run_stateless (exit_mode);
+ return 0;
+ }
+
/* Discover all the network interfaces. */
discover_interfaces (DISCOVER_UNCONFIGURED);
for (ip = interfaces; ip; ip = ip -> next) {
/* If interfaces were specified, don't configure
interfaces that weren't specified! */
- if (interfaces_requested &&
+ if ((interfaces_requested > 0) &&
((ip -> flags & (INTERFACE_REQUESTED |
INTERFACE_AUTOMATIC)) !=
INTERFACE_REQUESTED))
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 (interfaces_requested
+ discover_interfaces (interfaces_requested != 0
? DISCOVER_REQUESTED
: DISCOVER_RUNNING);
for (ip = interfaces ; ip != NULL ; ip = ip->next) {
for (client = ip->client ; client != NULL ;
client = client->next) {
- if (release_mode) {
- start_release6(client);
- continue;
- } else if (exit_mode) {
- unconfigure6(client, "STOP6");
- continue;
- }
+ if (release_mode) {
+ start_release6(client);
+ continue;
+ } else if (exit_mode) {
+ unconfigure6(client, "STOP6");
+ continue;
+ }
/* If we have a previous binding, Confirm
* that we can (or can't) still use it.
start_init6(client);
}
}
- } else
+ } else
#endif /* DHCPv6 */
{
for (ip = interfaces ; ip ; ip = ip->next) {
ip->flags |= INTERFACE_RUNNING;
for (client = ip->client ; client ;
client = client->next) {
- if (exit_mode)
- state_stop(client);
- else if (release_mode)
+ if (exit_mode)
+ state_stop(client);
+ else if (release_mode)
do_release(client);
else {
client->state = S_INIT;
log_error ("Usage: dhclient %s %s",
#ifdef DHCPv6
- "[-4|-6] [-1dvrx] [-nw] [-p <port>]",
+ "[-4|-6] [-S1dvrx] [-nw] [-p <port>]",
#else /* DHCPv6 */
- "[-1dvrx] [-nw] [-p <port>]",
+ "[-1dvrx] [-nw] [-p <port>]",
#endif /* DHCPv6 */
"[-s server]");
log_error (" [-cf config-file] [-lf lease-file]%s",
log_fatal (" [-sf script-file] [interface]");
}
+void run_stateless(int exit_mode)
+{
+ struct client_state *client;
+ omapi_object_t *listener;
+ isc_result_t result;
+
+ /* Discover the network interface. */
+ discover_interfaces(DISCOVER_REQUESTED);
+
+ if (!interfaces)
+ usage();
+
+ /* Parse the dhclient.conf file. */
+ read_client_conf();
+
+ /* Parse the lease database. */
+ read_client_leases();
+
+ /* Establish a default DUID. */
+ if (default_duid.len == 0) {
+ if (default_duid.buffer != NULL)
+ data_string_forget(&default_duid, MDL);
+
+ form_duid(&default_duid, MDL);
+ }
+
+ /* Start a configuration state machine. */
+ for (client = interfaces->client ;
+ client != NULL ;
+ client = client->next) {
+ if (exit_mode) {
+ unconfigure6(client, "STOP6");
+ continue;
+ }
+ start_info_request6(client);
+ }
+ if (exit_mode)
+ return;
+
+ /* 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 packet handler... */
+ dhcpv6_packet_handler = do_packet6;
+
+#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();
+
+ /*NOTREACHED*/
+ return;
+}
+
isc_result_t find_class (struct class **c,
const char *s, const char *file, int line)
{
}
/* Individual States:
- *
+ *
* Each routine is called from the dhclient_state_machine() in one of
* these conditions:
* -> entering INIT state
/* Add an immediate timeout to send the first DHCPREQUEST packet. */
send_request (client);
-}
+}
/* state_requesting is called when we receive a DHCPACK message after
having sent out one or more DHCPREQUEST packets. */
struct client_lease *lease;
struct option_cache *oc;
struct data_string ds;
-
+
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
for (client = ip -> client; client; client = client -> next) {
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 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. */
if (client->config->do_forward_update)
dhclient_schedule_updates(client, &client->active->address,
1);
-}
+}
/* state_bound is called when we've successfully bound to a particular
lease, but the renewal time on that lease has expired. We are
/* Send the first packet immediately. */
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. */
script_write_params(client, "alias_", client->alias);
script_go(client);
}
-}
+}
int commit_leases ()
{
return;
}
}
-
+
dhcpoffer (packet);
}
}
#ifdef DHCPv6
-void
+void
dhcpv6(struct packet *packet) {
struct iaddrmatchlist *ap;
struct client_state *client;
/* Screen out nonsensical messages. */
switch(packet->dhcpv6_msg_type) {
case DHCPV6_ADVERTISE:
- case DHCPV6_REPLY:
case DHCPV6_RECONFIGURE:
+ if (stateless)
+ return;
+ /* Falls through */
+ case DHCPV6_REPLY:
log_info("RCV: %s message on %s from %s.",
dhcpv6_type_names[packet->dhcpv6_msg_type],
packet->interface->name, piaddr(packet->client_addr));
const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
char obuf [1024];
struct timeval tv;
-
+
#ifdef DEBUG_PACKET
dump_packet (packet);
-#endif
+#endif
/* Find a client state that matches the xid... */
for (client = ip -> client; client; client = client -> next)
(struct group *)0);
return lease;
-}
+}
void dhcpnak (packet)
struct packet *packet;
if (client -> medium) {
client -> medium = client -> medium -> next;
increase = 0;
- }
+ }
if (!client -> medium) {
if (fail)
log_fatal ("No valid media types for %s!",
client -> config -> media;
increase = 1;
}
-
+
log_info ("Trying medium \"%s\" %d",
client -> medium -> string, increase);
script_init (client, "MEDIUM", client -> medium);
+ (random() % 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 + client -> interval >
client -> interval += ((random () >> 2) %
(2 * client -> interval));
}
-
+
/* Don't backoff past cutoff. */
if (client -> interval >
client -> config -> backoff_cutoff)
(struct lease *)0, client,
/* maximum packet size */1500,
(struct option_state *)0,
- client -> sent_options,
+ client -> sent_options,
/* scope */ &global_scope,
/* overload */ 0,
/* terminate */0,
for (i = 0; i < options->universe_count; i++) {
option_space_foreach(NULL, NULL, client, NULL, options,
- &global_scope, universes[i],
+ &global_scope, universes[i],
(char *)preamble, write_lease_option);
}
}
}
client -> env = (struct string_list *)0;
client -> envc = 0;
-
+
if (client -> interface) {
client_envadd (client, "", "interface", "%s",
client -> interface -> name);
if (option -> universe != &dhcp_universe) {
s = option -> universe -> name;
i = 0;
- } else {
+ } else {
s = option -> name;
i = 1;
}
pid = setsid ();
/* Close standard I/O descriptors. */
- close(0);
- close(1);
- close(2);
+ close(0);
+ close(1);
+ close(2);
/* Reopen them on /dev/null. */
open("/dev/null", O_RDWR);
write_client_pid_file ();
- chdir("/");
+ chdir("/");
}
void write_client_pid_file ()
}
}
-void do_release(client)
+void do_release(client)
struct client_state *client;
{
struct data_string ds;
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);
ip -> client -> alias);
script_go (ip -> client);
}
-
- discover_interfaces (interfaces_requested
+
+ discover_interfaces (interfaces_requested != 0
? DISCOVER_REQUESTED
: DISCOVER_RUNNING);
(struct option_state *)0,
&global_scope, oc, MDL))
return ISC_R_SUCCESS;
-
+
/* 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,
(struct option_state *)0,
&global_scope, oc, MDL))
return ISC_R_SUCCESS;
-
+
/* 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,
+ !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
(struct lease *)0, client,
client -> sent_options,
(struct option_state *)0,
&ddns_dhcid);
} else
rcode = ISC_R_FAILURE;
-
+
data_string_forget (&ddns_fwd_name, MDL);
data_string_forget (&ddns_dhcid, MDL);
return rcode;