struct sockaddr_in6 DHCPv6DestAddr;
-/* Option definition structures that are used by the software - declared
+/*
+ * Option definition structures that are used by the software - declared
* here once and assigned at startup to save lookups.
*/
struct option *clientid_option = NULL;
static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
const char *file, int line);
-static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia,
+static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia,
const char *file, int line);
static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr,
const char *file, int line);
static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr,
struct packet *packet,
struct option_state *options);
-static isc_result_t dhc6_parse_prefs(struct dhc6_addr **ppref,
- struct packet *packet,
- struct option_state *options);
-static struct dhc6_ia *find_ia_na(struct dhc6_ia *head, const char *id);
+static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppref,
+ struct packet *packet,
+ struct option_state *options);
+static struct dhc6_ia *find_ia(struct dhc6_ia *head,
+ u_int16_t type, const char *id);
static struct dhc6_addr *find_addr(struct dhc6_addr *head,
struct iaddr *address);
+static struct dhc6_addr *find_pref(struct dhc6_addr *head,
+ struct iaddr *prefix, u_int8_t plen);
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);
struct data_string *packet,
struct dhc6_lease *lease,
u_int8_t message);
+static isc_result_t dhc6_add_ia_ta(struct client_state *client,
+ struct data_string *packet,
+ struct dhc6_lease *lease,
+ u_int8_t message);
+static isc_result_t dhc6_add_ia_pd(struct client_state *client,
+ struct data_string *packet,
+ struct dhc6_lease *lease,
+ u_int8_t message);
static isc_boolean_t stopping_finished(void);
static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst);
void do_select6(void *input);
static void make_client6_options(struct client_state *client,
struct option_state **op,
struct dhc6_lease *lease, u_int8_t message);
-static void script_write_params6(struct client_state *client,
+static void script_write_params6(struct client_state *client,
const char *prefix,
struct option_state *options);
+static isc_boolean_t active_prefix(struct client_state *client);
extern int stateless;
-/* The "best" default DUID, since we cannot predict any information
+/*
+ * 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. For real stateless "LL" is better.
(ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
log_fatal("Impossible hardware address length at %s:%d.", MDL);
- /* 2 bytes for the 'duid type' field.
+ /*
+ * 2 bytes for the 'duid type' field.
* 2 bytes for the 'htype' field.
* (not stateless) 4 bytes for the 'current time'.
* enough bytes for the hardware address (note that hw_address has
}
}
-/* Assign DHCPv6 port numbers as a client.
+/*
+ * Assign DHCPv6 port numbers as a client.
*/
void
dhcpv6_client_assignments(void)
#endif
}
-/* Instead of implementing RFC3315 RAND (section 14) as a float "between"
+/*
+ * Instead of implementing RFC3315 RAND (section 14) as a float "between"
* -0.1 and 0.1 non-inclusive, we implement it as an integer.
*
* The result is expected to follow this table:
TIME range;
TIME split;
- /* A zero or less timeout is a bad thing...we don't want to
+ /*
+ * A zero or less timeout is a bad thing...we don't want to
* DHCP-flood anyone.
*/
if (base <= 0)
log_fatal("Impossible condition at %s:%d.", MDL);
- /* The first thing we do is count how many random integers we want
+ /*
+ * The first thing we do is count how many random integers we want
* in either direction (best thought of as the maximum negative
* integer, as we will subtract this potentially from a random 0).
*/
if (split == 0)
return 0;
- /* Then we count the total number of integers in this set. This
+ /*
+ * Then we count the total number of integers in this set. This
* is twice the number of integers in positive and negative
* directions, plus zero (-1, 0, 1 is 3, -2..2 adds 2 to 5, so forth).
*/
elapsed.tv_usec -= 1000000;
}
- /* RT for each subsequent message transmission is based on the previous
- * value of RT:
- *
- * RT = 2*RTprev + RAND*RTprev
- */
- client->RT += client->RT + dhc6_rand(client->RT);
-
- /* MRT specifies an upper bound on the value of RT (disregarding the
- * randomization added by the use of RAND). If MRT has a value of 0,
- * there is no upper limit on the value of RT. Otherwise:
- *
- * if (RT > MRT)
- * RT = MRT + RAND*MRT
- */
- if ((client->MRT != 0) && (client->RT > client->MRT))
- client->RT = client->MRT + dhc6_rand(client->MRT);
-
- /* Further, if there's an MRD, we should wake up upon reaching
+ /*
+ * RT for each subsequent message transmission is based on the previous
+ * value of RT:
+ *
+ * RT = 2*RTprev + RAND*RTprev
+ */
+ client->RT += client->RT + dhc6_rand(client->RT);
+
+ /*
+ * MRT specifies an upper bound on the value of RT (disregarding the
+ * randomization added by the use of RAND). If MRT has a value of 0,
+ * there is no upper limit on the value of RT. Otherwise:
+ *
+ * if (RT > MRT)
+ * RT = MRT + RAND*MRT
+ */
+ if ((client->MRT != 0) && (client->RT > client->MRT))
+ client->RT = client->MRT + dhc6_rand(client->MRT);
+
+ /*
+ * Further, if there's an MRD, we should wake up upon reaching
* the MRD rather than at some point after it.
*/
if (client->MRD == 0) {
return rval;
}
-/* Create a complete copy of a DHCPv6 lease structure.
+/*
+ * Create a complete copy of a DHCPv6 lease structure.
*/
static struct dhc6_lease *
dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line)
return copy;
}
-/* Duplicate an IA structure.
+/*
+ * Duplicate an IA structure.
*/
static struct dhc6_ia *
dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line)
return copy;
}
-/* Duplicate an IAADDR or IAPREFIX structure.
+/*
+ * Duplicate an IAADDR or IAPREFIX structure.
*/
static struct dhc6_addr *
dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line)
return copy;
}
-/* Form a DHCPv6 lease structure based upon packet contents. Creates and
+/*
+ * Form a DHCPv6 lease structure based upon packet contents. Creates and
* populates IA's and any IAADDR/IAPREFIX's they contain.
* Parsed options are deleted in order to not save them in the lease file.
*/
}
delete_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
- /* Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR
+ /*
+ * Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR
* options.
*/
if (dhc6_parse_ia_na(&lease->bindings, packet,
dhc6_lease_destroy(&lease, MDL);
return NULL;
}
- /* Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR
+ /*
+ * Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR
* options.
*/
if (dhc6_parse_ia_ta(&lease->bindings, packet,
dhc6_lease_destroy(&lease, MDL);
return NULL;
}
- /* Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX
+ /*
+ * Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX
* options.
*/
if (dhc6_parse_ia_pd(&lease->bindings, packet,
return NULL;
}
- /* This is last because in the future we may want to make a different
+ /*
+ * This is last because in the future we may want to make a different
* key based upon additional information from the packet (we may need
* to allow multiple leases in one client state per server, but we're
* not sure based on what additional keys now).
log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
- /* RFC3315 section 22.4, discard IA_NA's that
+ /*
+ * RFC3315 section 22.4, discard IA_NA's that
* have t1 greater than t2, and both not zero.
* Since RFC3315 defines this behaviour, it is not
* an error - just normal operation.
if (!option_state_allocate(&ia->options,
MDL)) {
log_error("Out of memory allocating "
- "IA option state.");
+ "IA_NA option state.");
dfree(ia, MDL);
data_string_forget(&ds, MDL);
return ISC_R_NOMEMORY;
}
}
+ while (*pia != NULL)
+ pia = &(*pia)->next;
*pia = ia;
pia = &ia->next;
} else {
if (!option_state_allocate(&ia->options,
MDL)) {
log_error("Out of memory allocating "
- "IA option state.");
+ "IA_TA option state.");
dfree(ia, MDL);
data_string_forget(&ds, MDL);
return ISC_R_NOMEMORY;
}
}
+ while (*pia != NULL)
+ pia = &(*pia)->next;
*pia = ia;
pia = &ia->next;
} else {
log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
- /* RFC3315 section 22.4, discard IA_PD's that
+ /*
+ * RFC3633 section 9, discard IA_PD's that
* have t1 greater than t2, and both not zero.
- * Since RFC3315 defines this behaviour, it is not
+ * Since RFC3633 defines this behaviour, it is not
* an error - just normal operation.
*/
if ((ia->renew > 0) && (ia->rebind > 0) &&
if (!option_state_allocate(&ia->options,
MDL)) {
log_error("Out of memory allocating "
- "IA option state.");
+ "IA_PD option state.");
dfree(ia, MDL);
data_string_forget(&ds, MDL);
return ISC_R_NOMEMORY;
data_string_forget(&ds, MDL);
if (ia->options != NULL) {
- result = dhc6_parse_prefs(&ia->addrs, packet,
- ia->options);
+ result = dhc6_parse_prefixes(&ia->addrs,
+ packet,
+ ia->options);
if (result != ISC_R_SUCCESS) {
option_state_dereference(&ia->options,
MDL);
}
}
+ while (*pia != NULL)
+ pia = &(*pia)->next;
*pia = ia;
pia = &ia->next;
} else {
log_debug("RCV: | | | X-- Max lifetime %u.",
addr->max_life);
- /* RFC 3315 section 22.6 says we must discard
+ /*
+ * RFC 3315 section 22.6 says we must discard
* addresses whose pref is later than valid.
*/
if ((addr->preferred_life > addr->max_life)) {
continue;
}
- /* Fortunately this is the last recursion in the
+ /*
+ * Fortunately this is the last recursion in the
* protocol.
*/
if (ds.len > 24) {
}
static isc_result_t
-dhc6_parse_prefs(struct dhc6_addr **ppref, struct packet *packet,
- struct option_state *options)
+dhc6_parse_prefixes(struct dhc6_addr **ppfx, struct packet *packet,
+ struct option_state *options)
{
struct data_string ds;
struct option_cache *oc;
- struct dhc6_addr *pref;
+ struct dhc6_addr *pfx;
memset(&ds, 0, sizeof(ds));
oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX);
for ( ; oc != NULL ; oc = oc->next) {
- pref = dmalloc(sizeof(*pref), MDL);
- if (pref == NULL) {
+ pfx = dmalloc(sizeof(*pfx), MDL);
+ if (pfx == NULL) {
log_error("Out of memory allocating "
"prefix structure.");
return ISC_R_NOMEMORY;
oc, MDL) &&
(ds.len >= 25)) {
- pref->preferred_life = getULong(ds.data);
- pref->max_life = getULong(ds.data + 4);
- pref->plen = getUChar(ds.data + 8);
- pref->address.len = 16;
- memcpy(pref->address.iabuf, ds.data + 9, 16);
- pref->starts = cur_time;
+ pfx->preferred_life = getULong(ds.data);
+ pfx->max_life = getULong(ds.data + 4);
+ pfx->plen = getUChar(ds.data + 8);
+ pfx->address.len = 16;
+ memcpy(pfx->address.iabuf, ds.data + 9, 16);
+ pfx->starts = cur_time;
log_debug("RCV: | | X-- IAPREFIX %s/%d",
- piaddr(pref->address), (int)pref->plen);
+ piaddr(pfx->address), (int)pfx->plen);
log_debug("RCV: | | | X-- Preferred lifetime %u.",
- pref->preferred_life);
+ pfx->preferred_life);
log_debug("RCV: | | | X-- Max lifetime %u.",
- pref->max_life);
+ pfx->max_life);
/* Sanity check over the prefix length */
- if ((pref->plen < 4) || (pref->plen > 128)) {
+ if ((pfx->plen < 4) || (pfx->plen > 128)) {
log_debug("RCV: | | | !-- INVALID prefix "
"length, IAPREFIX discarded. "
"Check your server configuration.");
- dfree(pref, MDL);
+ dfree(pfx, MDL);
data_string_forget(&ds, MDL);
continue;
}
- /* RFC 3315 section 22.6 says we must discard
+ /*
+ * RFC 3633 section 10 says we must discard
* prefixes whose pref is later than valid.
*/
- if ((pref->preferred_life > pref->max_life)) {
+ if ((pfx->preferred_life > pfx->max_life)) {
log_debug("RCV: | | | !-- INVALID lifetimes, "
"IAPREFIX discarded. Check your "
"server configuration.");
- dfree(pref, MDL);
+ dfree(pfx, MDL);
data_string_forget(&ds, MDL);
continue;
}
- /* Fortunately this is the last recursion in the
+ /*
+ * Fortunately this is the last recursion in the
* protocol.
*/
if (ds.len > 25) {
- if (!option_state_allocate(&pref->options,
+ if (!option_state_allocate(&pfx->options,
MDL)) {
log_error("Out of memory allocating "
"IAPREFIX option state.");
- dfree(pref, MDL);
+ dfree(pfx, MDL);
data_string_forget(&ds, MDL);
return ISC_R_NOMEMORY;
}
- if (!parse_option_buffer(pref->options,
+ if (!parse_option_buffer(pfx->options,
ds.data + 25,
ds.len - 25,
&dhcpv6_universe)) {
log_error("Corrupt IAPREFIX options.");
- option_state_dereference(&pref->options,
+ option_state_dereference(&pfx->options,
MDL);
- dfree(pref, MDL);
+ dfree(pfx, MDL);
data_string_forget(&ds, MDL);
return ISC_R_BADPARSE;
}
}
- if (pref->options != NULL)
+ if (pfx->options != NULL)
log_debug("RCV: | | | X-- "
"[Options]");
data_string_forget(&ds, MDL);
- *ppref = pref;
- ppref = &pref->next;
+ *ppfx = pfx;
+ ppfx = &pfx->next;
} else {
log_error("Invalid IAPREFIX option cache.");
- dfree(pref, MDL);
+ dfree(pfx, MDL);
if (ds.len != 0)
data_string_forget(&ds, MDL);
return ISC_R_UNEXPECTED;
dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line)
{
struct dhc6_ia *ia, *nia;
- struct dhc6_lease *lease;
+ struct dhc6_lease *lease;
if (src == NULL || *src == NULL) {
- log_error("Attempt to destroy null lease.");
+ log_error("Attempt to destroy null lease.");
return;
- }
+ }
lease = *src;
if (lease->server_id.len != 0)
option_state_dereference(&lease->options, file, line);
dfree(lease, file, line);
- *src = NULL;
+ *src = NULL;
}
/*
dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line)
{
struct dhc6_addr *addr, *naddr;
- struct dhc6_ia *ia;
+ struct dhc6_ia *ia;
if (src == NULL || *src == NULL) {
- log_error("Attempt to destroy null IA.");
+ log_error("Attempt to destroy null IA.");
return;
- }
+ }
ia = *src;
for (addr = ia->addrs ; addr != NULL ; addr = naddr) {
option_state_dereference(&ia->options, file, line);
dfree(ia, file, line);
- *src = NULL;
+ *src = NULL;
}
-/* For a given lease, insert it into the tail of the lease list. Upon
+/*
+ * For a given lease, insert it into the tail of the lease list. Upon
* finding a duplicate by server id, remove it and take over its position.
*/
static void
return;
}
-/* Not really clear what to do here yet.
+/*
+ * Not really clear what to do here yet.
*/
static int
dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
}
}
- /* If this lease contains a requested option, improve its
- * score.
- */
+ /* If this lease contains a requested option, improve its score. */
req = client->config->requested_options;
if (req != NULL) {
for (i = 0 ; req[i] != NULL ; i++) {
return lease->score;
}
-/* start_init6() kicks off the process, transmitting a packet and
+/*
+ * start_init6() kicks off the process, transmitting a packet and
* scheduling a retransmission event.
*/
void
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.
*/
client->v6_handler = init_handler;
- /* RFC3315 section 17.1.2 says we MUST start the first packet
+ /*
+ * RFC3315 section 17.1.2 says we MUST start the first packet
* between 0 and SOL_MAX_DELAY seconds. The good news is
* SOL_MAX_DELAY is 1.
*/
go_daemon();
}
-/* start_info_request6() kicks off the process, transmitting an info
+/*
+ * start_info_request6() kicks off the process, transmitting an info
* request packet and scheduling a retransmission event.
*/
void
client->v6_handler = info_request_handler;
- /* RFC3315 section 18.1.5 says we MUST start the first packet
+ /*
+ * 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.
*/
go_daemon();
}
-/* start_confirm6() kicks off an "init-reboot" version of the process, at
+/*
+ * 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.
*/
struct timeval tv;
/* If there is no active lease, there is nothing to check. */
- if ((client->active_lease == NULL) || client->active_lease->released) {
+ if ((client->active_lease == NULL) ||
+ !active_prefix(client) ||
+ client->active_lease->released) {
start_init6(client);
return;
}
client->v6_handler = reply_handler;
- /* RFC3315 section 18.1.2 says we MUST start the first packet
+ /*
+ * RFC3315 section 18.1.2 says we MUST start the first packet
* between 0 and CNF_MAX_DELAY seconds. The good news is
* CNF_MAX_DELAY is 1.
*/
tv.tv_sec += 1;
tv.tv_usec -= 1000000;
}
- add_timeout(&tv, do_confirm6, client, NULL, NULL);
+ if (wanted_ia_pd != 0) {
+ client->state = S_REBINDING;
+ client->refresh_type = DHCPV6_REBIND;
+ add_timeout(&tv, do_refresh6, client, NULL, NULL);
+ } else
+ add_timeout(&tv, do_confirm6, client, NULL, NULL);
}
-/* do_init6() marshals and transmits a solicit.
+/*
+ * do_init6() marshals and transmits a solicit.
*/
void
do_init6(void *input)
struct data_string addr;
struct timeval elapsed, tv;
u_int32_t t1, t2;
- int idx, len, send_ret;
+ int i, idx, len, send_ret;
client = input;
- /* In RFC3315 section 17.1.2, the retransmission timer is
+ /*
+ * In RFC3315 section 17.1.2, the retransmission timer is
* used as the selecting timer.
*/
if (client->advertised_leases != NULL) {
make_client6_options(client, &client->sent_options, NULL,
DHCPV6_SOLICIT);
- /* Fetch any configured 'sent' options (includes DUID) in wire format.
+ /*
+ * 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);
- /* Use a specific handler with rapid-commit.
- */
+ /* Use a specific handler with rapid-commit. */
if (lookup_option(&dhcpv6_universe, client->sent_options,
D6O_RAPID_COMMIT) != NULL) {
client->v6_handler = rapid_commit_handler;
}
- /* Append an IA_NA. */
- /* XXX: maybe the IA_NA('s) should be put into the sent_options
- * cache. They'd have to be pulled down as they also contain
- * different option caches in the same universe...
- */
- memset(&ia, 0, sizeof(ia));
- if (!buffer_allocate(&ia.buffer, 12, MDL)) {
- log_error("Unable to allocate memory for IA_NA.");
- data_string_forget(&ds, MDL);
- return;
- }
- ia.data = ia.buffer->data;
- ia.len = 12;
+ /* Append IA_NA. */
+ for (i = 0; i < wanted_ia_na; i++) {
+ /*
+ * XXX: maybe the IA_NA('s) should be put into the sent_options
+ * cache. They'd have to be pulled down as they also contain
+ * different option caches in the same universe...
+ */
+ memset(&ia, 0, sizeof(ia));
+ if (!buffer_allocate(&ia.buffer, 12, MDL)) {
+ log_error("Unable to allocate memory for IA_NA.");
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ ia.data = ia.buffer->data;
+ ia.len = 12;
- /* A simple IAID is the last 4 bytes of the hardware address. */
- if (client->interface->hw_address.hlen > 4) {
- idx = client->interface->hw_address.hlen - 4;
- len = 4;
- } else {
- idx = 0;
- len = client->interface->hw_address.hlen;
- }
- memcpy(ia.buffer->data, client->interface->hw_address.hbuf + idx, len);
-
- t1 = client->config->requested_lease / 2;
- t2 = t1 + (t1 / 2);
- putULong(ia.buffer->data + 4, t1);
- putULong(ia.buffer->data + 8, t2);
-
- log_debug("XMT: X-- IA_NA %s", print_hex_1(4, ia.buffer->data, 55));
- log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
- log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
-
- if ((client->active_lease != NULL) &&
- ((old_ia = find_ia_na(client->active_lease->bindings,
- (char *)ia.buffer->data)) != NULL)) {
- /* For each address in the old IA, request a binding. */
- memset(&addr, 0, sizeof(addr));
- for (old_addr = old_ia->addrs ; old_addr != NULL ;
- old_addr = old_addr->next) {
- if (old_addr->address.len != 16) {
- log_error("Invalid IPv6 address length %d. "
- "Ignoring. (%s:%d)",
- old_addr->address.len, MDL);
- continue;
- }
+ /*
+ * A simple IAID is the last 4 bytes
+ * of the hardware address.
+ */
+ if (client->interface->hw_address.hlen > 4) {
+ idx = client->interface->hw_address.hlen - 4;
+ len = 4;
+ } else {
+ idx = 0;
+ len = client->interface->hw_address.hlen;
+ }
+ memcpy(ia.buffer->data,
+ client->interface->hw_address.hbuf + idx,
+ len);
+ if (i)
+ ia.buffer->data[3] += i;
+
+ t1 = client->config->requested_lease / 2;
+ t2 = t1 + (t1 / 2);
+ putULong(ia.buffer->data + 4, t1);
+ putULong(ia.buffer->data + 8, t2);
+
+ log_debug("XMT: X-- IA_NA %s",
+ print_hex_1(4, ia.buffer->data, 55));
+ log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
+ log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
+
+ if ((client->active_lease != NULL) &&
+ ((old_ia = find_ia(client->active_lease->bindings,
+ D6O_IA_NA,
+ (char *)ia.buffer->data)) != NULL)) {
+ /*
+ * For each address in the old IA_NA,
+ * request a binding.
+ */
+ memset(&addr, 0, sizeof(addr));
+ for (old_addr = old_ia->addrs ; old_addr != NULL ;
+ old_addr = old_addr->next) {
+ if (old_addr->address.len != 16) {
+ log_error("Invalid IPv6 address "
+ "length %d. "
+ "Ignoring. (%s:%d)",
+ old_addr->address.len,
+ MDL);
+ continue;
+ }
- if (!buffer_allocate(&addr.buffer, 24, MDL)) {
- log_error("Unable to allocate memory for "
- "IAADDR.");
- data_string_forget(&ia, MDL);
- data_string_forget(&ds, MDL);
- return;
+ if (!buffer_allocate(&addr.buffer, 24, MDL)) {
+ log_error("Unable to allocate memory "
+ "for IAADDR.");
+ data_string_forget(&ia, MDL);
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ addr.data = addr.buffer->data;
+ addr.len = 24;
+
+ memcpy(addr.buffer->data,
+ old_addr->address.iabuf,
+ 16);
+
+ t1 = client->config->requested_lease;
+ t2 = t1 + (t1 / 2);
+ putULong(addr.buffer->data + 16, t1);
+ putULong(addr.buffer->data + 20, t2);
+
+ log_debug("XMT: | X-- Request address %s.",
+ piaddr(old_addr->address));
+ log_debug("XMT: | | X-- Request "
+ "preferred in +%u",
+ (unsigned)t1);
+ log_debug("XMT: | | X-- Request valid "
+ "in +%u",
+ (unsigned)t2);
+
+ append_option(&ia, &dhcpv6_universe,
+ iaaddr_option,
+ &addr);
+
+ data_string_forget(&addr, MDL);
}
- addr.data = addr.buffer->data;
- addr.len = 24;
-
- memcpy(addr.buffer->data, old_addr->address.iabuf, 16);
+ }
- t1 = client->config->requested_lease;
- t2 = t1 + (t1 / 2);
- putULong(addr.buffer->data + 16, t1);
- putULong(addr.buffer->data + 20, t2);
+ append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
+ data_string_forget(&ia, MDL);
+ }
- log_debug("XMT: | X-- Request address %s.",
- piaddr(old_addr->address));
- log_debug("XMT: | | X-- Request preferred in +%u",
- (unsigned)t1);
- log_debug("XMT: | | X-- Request valid in +%u",
- (unsigned)t2);
+ /* Append IA_TA. */
+ for (i = 0; i < wanted_ia_ta; i++) {
+ /*
+ * XXX: maybe the IA_TA('s) should be put into the sent_options
+ * cache. They'd have to be pulled down as they also contain
+ * different option caches in the same universe...
+ */
+ memset(&ia, 0, sizeof(ia));
+ if (!buffer_allocate(&ia.buffer, 4, MDL)) {
+ log_error("Unable to allocate memory for IA_TA.");
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ ia.data = ia.buffer->data;
+ ia.len = 4;
- append_option(&ia, &dhcpv6_universe, iaaddr_option,
- &addr);
+ /*
+ * A simple IAID is the last 4 bytes
+ * of the hardware address.
+ */
+ if (client->interface->hw_address.hlen > 4) {
+ idx = client->interface->hw_address.hlen - 4;
+ len = 4;
+ } else {
+ idx = 0;
+ len = client->interface->hw_address.hlen;
+ }
+ memcpy(ia.buffer->data,
+ client->interface->hw_address.hbuf + idx,
+ len);
+ if (i)
+ ia.buffer->data[3] += i;
+
+ log_debug("XMT: X-- IA_TA %s",
+ print_hex_1(4, ia.buffer->data, 55));
+
+ if ((client->active_lease != NULL) &&
+ ((old_ia = find_ia(client->active_lease->bindings,
+ D6O_IA_TA,
+ (char *)ia.buffer->data)) != NULL)) {
+ /*
+ * For each address in the old IA_TA,
+ * request a binding.
+ */
+ memset(&addr, 0, sizeof(addr));
+ for (old_addr = old_ia->addrs ; old_addr != NULL ;
+ old_addr = old_addr->next) {
+ if (old_addr->address.len != 16) {
+ log_error("Invalid IPv6 address "
+ "length %d. "
+ "Ignoring. (%s:%d)",
+ old_addr->address.len,
+ MDL);
+ continue;
+ }
- data_string_forget(&addr, MDL);
+ if (!buffer_allocate(&addr.buffer, 24, MDL)) {
+ log_error("Unable to allocate memory "
+ "for IAADDR.");
+ data_string_forget(&ia, MDL);
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ addr.data = addr.buffer->data;
+ addr.len = 24;
+
+ memcpy(addr.buffer->data,
+ old_addr->address.iabuf,
+ 16);
+
+ t1 = client->config->requested_lease;
+ t2 = t1 + (t1 / 2);
+ putULong(addr.buffer->data + 16, t1);
+ putULong(addr.buffer->data + 20, t2);
+
+ log_debug("XMT: | X-- Request address %s.",
+ piaddr(old_addr->address));
+ log_debug("XMT: | | X-- Request "
+ "preferred in +%u",
+ (unsigned)t1);
+ log_debug("XMT: | | X-- Request valid "
+ "in +%u",
+ (unsigned)t2);
+
+ append_option(&ia, &dhcpv6_universe,
+ iaaddr_option,
+ &addr);
+
+ data_string_forget(&addr, MDL);
+ }
}
+
+ append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia);
+ data_string_forget(&ia, MDL);
}
- append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
- data_string_forget(&ia, MDL);
+ /* Append IA_PD. */
+ for (i = 0; i < wanted_ia_pd; i++) {
+ /*
+ * XXX: maybe the IA_PD('s) should be put into the sent_options
+ * cache. They'd have to be pulled down as they also contain
+ * different option caches in the same universe...
+ */
+ memset(&ia, 0, sizeof(ia));
+ if (!buffer_allocate(&ia.buffer, 12, MDL)) {
+ log_error("Unable to allocate memory for IA_PD.");
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ ia.data = ia.buffer->data;
+ ia.len = 12;
+
+ /*
+ * A simple IAID is the last 4 bytes
+ * of the hardware address.
+ */
+ if (client->interface->hw_address.hlen > 4) {
+ idx = client->interface->hw_address.hlen - 4;
+ len = 4;
+ } else {
+ idx = 0;
+ len = client->interface->hw_address.hlen;
+ }
+ memcpy(ia.buffer->data,
+ client->interface->hw_address.hbuf + idx,
+ len);
+ if (i)
+ ia.buffer->data[3] += i;
+
+ t1 = client->config->requested_lease / 2;
+ t2 = t1 + (t1 / 2);
+ putULong(ia.buffer->data + 4, t1);
+ putULong(ia.buffer->data + 8, t2);
+
+ log_debug("XMT: X-- IA_PD %s",
+ print_hex_1(4, ia.buffer->data, 55));
+ log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
+ log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
+
+ if ((client->active_lease != NULL) &&
+ ((old_ia = find_ia(client->active_lease->bindings,
+ D6O_IA_PD,
+ (char *)ia.buffer->data)) != NULL)) {
+ /*
+ * For each prefix in the old IA_PD,
+ * request a binding.
+ */
+ memset(&addr, 0, sizeof(addr));
+ for (old_addr = old_ia->addrs ; old_addr != NULL ;
+ old_addr = old_addr->next) {
+ if (old_addr->address.len != 16) {
+ log_error("Invalid IPv6 prefix, "
+ "Ignoring. (%s:%d)",
+ MDL);
+ continue;
+ }
+
+ if (!buffer_allocate(&addr.buffer, 25, MDL)) {
+ log_error("Unable to allocate memory "
+ "for IAPREFIX.");
+ data_string_forget(&ia, MDL);
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ addr.data = addr.buffer->data;
+ addr.len = 25;
+
+ t1 = client->config->requested_lease;
+ t2 = t1 + (t1 / 2);
+ putULong(addr.buffer->data, t1);
+ putULong(addr.buffer->data + 4, t2);
+
+ putUChar(addr.buffer->data + 8,
+ old_addr->plen);
+ memcpy(addr.buffer->data + 9,
+ old_addr->address.iabuf,
+ 16);
+
+ log_debug("XMT: | X-- Request prefix %s/%u.",
+ piaddr(old_addr->address),
+ (unsigned) old_addr->plen);
+ log_debug("XMT: | | X-- Request "
+ "preferred in +%u",
+ (unsigned)t1);
+ log_debug("XMT: | | X-- Request valid "
+ "in +%u",
+ (unsigned)t2);
+
+ append_option(&ia, &dhcpv6_universe,
+ iaprefix_option,
+ &addr);
+
+ data_string_forget(&addr, MDL);
+ }
+ }
+
+ append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia);
+ data_string_forget(&ia, MDL);
+ }
/* Transmit and wait. */
&dhcpv6_universe);
/* Append IA's. */
- if (dhc6_add_ia_na(client, &ds, client->active_lease,
+ if (wanted_ia_na &&
+ dhc6_add_ia_na(client, &ds, client->active_lease,
+ DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ if (wanted_ia_ta &&
+ dhc6_add_ia_ta(client, &ds, client->active_lease,
DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
return;
void
start_release6(struct client_state *client)
{
- /* Cancel any pending transmissions */
+ /* Cancel any pending transmissions */
cancel_timeout(do_confirm6, client);
cancel_timeout(do_select6, client);
cancel_timeout(do_refresh6, client);
cancel_timeout(do_release6, client);
- client->state = S_STOPPED;
+ client->state = S_STOPPED;
- /*
- * It is written: "The client MUST NOT use any of the addresses it
- * is releasing as the source address in the Release message or in
- * any subsequently transmitted message." So unconfigure now.
- */
- unconfigure6(client, "RELEASE6");
+ /*
+ * It is written: "The client MUST NOT use any of the addresses it
+ * is releasing as the source address in the Release message or in
+ * any subsequently transmitted message." So unconfigure now.
+ */
+ unconfigure6(client, "RELEASE6");
/* Note this in the lease file. */
if (client->active_lease == NULL)
client = input;
- if (client->active_lease == NULL)
+ if ((client->active_lease == NULL) || !active_prefix(client))
return;
if ((client->MRC != 0) && (client->txcount > client->MRC)) {
client->sent_options, &global_scope,
&dhcpv6_universe);
- /* Append IA's. */
- if (dhc6_add_ia_na(client, &ds, client->active_lease,
+ /* Append IA's (but don't release temporary addresses). */
+ if (wanted_ia_na &&
+ dhc6_add_ia_na(client, &ds, client->active_lease,
+ DHCPV6_RELEASE) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ goto release_done;
+ }
+ if (wanted_ia_pd &&
+ dhc6_add_ia_pd(client, &ds, client->active_lease,
DHCPV6_RELEASE) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
goto release_done;
msg = "UseMulticast";
break;
+ case STATUS_NoPrefixAvail:
+ msg = "NoPrefixAvail";
+ break;
+
default:
msg = "UNKNOWN";
break;
if (len > 0)
log_info("%s status code %s: %s", scope, msg,
- print_hex_1(len,
- (const unsigned char *)additional, 50));
+ print_hex_1(len,
+ (const unsigned char *)additional, 50));
else
log_info("%s status code %s.", scope, msg);
}
for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
switch (ia->ia_type) {
case D6O_IA_NA:
- default:
scope = "IA_NA";
break;
case D6O_IA_TA:
case D6O_IA_PD:
scope = "IA_PD";
break;
+ default:
+ log_error("dhc6_check_advertise: no type.");
+ return ISC_R_FAILURE;
}
rval = dhc6_check_status(rval, ia->options, scope, &code);
* servers.
*/
case STATUS_NoAddrsAvail:
+ case STATUS_NoPrefixAvail:
if (client->state == S_REBOOTING)
return ISC_FALSE;
* server."
*/
case STATUS_NoAddrsAvail:
+ case STATUS_NoPrefixAvail:
/* Head back to init, keeping any active bindings (!). */
start_init6(client);
break;
/* Should not happen */
case STATUS_NoAddrsAvail:
+ case STATUS_NoPrefixAvail:
break;
/* Give up on it */
for (ia = new->bindings ; ia != NULL ; ia = ia->next) {
switch (ia->ia_type) {
case D6O_IA_NA:
- default:
scope = "IA_NA";
break;
case D6O_IA_TA:
case D6O_IA_PD:
scope = "IA_PD";
break;
+ default:
+ log_error("dhc6_check_reply: no type.");
+ return ISC_R_INVALIDARG;
}
rval = dhc6_check_status(rval, ia->options,
scope, &code);
&dhcpv6_universe);
/* Now append any IA's, and within them any IAADDR/IAPREFIXs. */
- if (dhc6_add_ia_na(client, &ds, lease,
+ if (wanted_ia_na &&
+ dhc6_add_ia_na(client, &ds, lease,
+ DHCPV6_REQUEST) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ if (wanted_ia_ta &&
+ dhc6_add_ia_ta(client, &ds, lease,
+ DHCPV6_REQUEST) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ if (wanted_ia_pd &&
+ dhc6_add_ia_pd(client, &ds, lease,
DHCPV6_REQUEST) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
return;
memset(&iads, 0, sizeof(iads));
memset(&addrds, 0, sizeof(addrds));
for (ia = lease->bindings;
- ia != NULL && rval == ISC_R_SUCCESS;
- ia = ia->next) {
+ ia != NULL && rval == ISC_R_SUCCESS;
+ ia = ia->next) {
if (ia->ia_type != D6O_IA_NA)
continue;
iads.data = iads.buffer->data;
iads.len = 12;
- switch (message) {
- case DHCPV6_REQUEST:
- case DHCPV6_RENEW:
- case DHCPV6_REBIND:
-
- t1 = client->config->requested_lease / 2;
- t2 = t1 + (t1 / 2);
+ switch (message) {
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+
+ t1 = client->config->requested_lease / 2;
+ t2 = t1 + (t1 / 2);
#if MAX_TIME > 0xffffffff
- if (t1 > 0xffffffff)
- t1 = 0xffffffff;
- if (t2 > 0xffffffff)
- t2 = 0xffffffff;
+ if (t1 > 0xffffffff)
+ t1 = 0xffffffff;
+ if (t2 > 0xffffffff)
+ t2 = 0xffffffff;
#endif
- putULong(iads.buffer->data + 4, t1);
- putULong(iads.buffer->data + 8, t2);
-
- log_debug("XMT: X-- IA_NA %s",
- print_hex_1(4, iads.data, 59));
- log_debug("XMT: | X-- Requested renew +%u",
- (unsigned) t1);
- log_debug("XMT: | X-- Requested rebind +%u",
- (unsigned) t2);
- break;
-
- case DHCPV6_CONFIRM:
- case DHCPV6_RELEASE:
- case DHCPV6_DECLINE:
- /* Set t1 and t2 to zero; server will ignore them */
- memset(iads.buffer->data + 4, 0, 8);
- log_debug("XMT: X-- IA_NA %s",
- print_hex_1(4, iads.buffer->data, 55));
-
- break;
-
- default:
- log_fatal("Impossible condition at %s:%d.", MDL);
- }
+ putULong(iads.buffer->data + 4, t1);
+ putULong(iads.buffer->data + 8, t2);
+
+ log_debug("XMT: X-- IA_NA %s",
+ print_hex_1(4, iads.data, 59));
+ log_debug("XMT: | X-- Requested renew +%u",
+ (unsigned) t1);
+ log_debug("XMT: | X-- Requested rebind +%u",
+ (unsigned) t2);
+ break;
+
+ case DHCPV6_CONFIRM:
+ case DHCPV6_RELEASE:
+ case DHCPV6_DECLINE:
+ /* Set t1 and t2 to zero; server will ignore them */
+ memset(iads.buffer->data + 4, 0, 8);
+ log_debug("XMT: X-- IA_NA %s",
+ print_hex_1(4, iads.buffer->data, 55));
+
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
/*
/* Copy the address into the packet buffer. */
memcpy(addrds.buffer->data, addr->address.iabuf, 16);
- /* Copy in additional information as appropriate */
- switch (message) {
- case DHCPV6_REQUEST:
- case DHCPV6_RENEW:
- case DHCPV6_REBIND:
- t1 = client->config->requested_lease;
- t2 = t1 + 300;
- putULong(addrds.buffer->data + 16, t1);
- putULong(addrds.buffer->data + 20, t2);
-
- log_debug("XMT: | | X-- IAADDR %s",
- piaddr(addr->address));
- log_debug("XMT: | | | X-- Preferred "
- "lifetime +%u", (unsigned)t1);
- log_debug("XMT: | | | X-- Max lifetime +%u",
- (unsigned)t2);
-
- break;
-
- case DHCPV6_CONFIRM:
- /*
- * Set preferred and max life to zero,
- * per 17.1.3.
- */
- memset(addrds.buffer->data + 16, 0, 8);
- log_debug("XMT: | X-- Confirm Address %s",
- piaddr(addr->address));
- break;
-
- case DHCPV6_RELEASE:
- /* Preferred and max life are irrelevant */
- memset(addrds.buffer->data + 16, 0, 8);
- log_debug("XMT: | X-- Release Address %s",
- piaddr(addr->address));
- break;
-
- case DHCPV6_DECLINE:
- /* Preferred and max life are irrelevant */
- memset(addrds.buffer->data + 16, 0, 8);
- log_debug("XMT: | X-- Decline Address %s",
- piaddr(addr->address));
- break;
-
- default:
- log_fatal("Impossible condition at %s:%d.",
- MDL);
- }
+ /* Copy in additional information as appropriate */
+ switch (message) {
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease;
+ t2 = t1 + 300;
+ putULong(addrds.buffer->data + 16, t1);
+ putULong(addrds.buffer->data + 20, t2);
+
+ log_debug("XMT: | | X-- IAADDR %s",
+ piaddr(addr->address));
+ log_debug("XMT: | | | X-- Preferred "
+ "lifetime +%u", (unsigned)t1);
+ log_debug("XMT: | | | X-- Max lifetime +%u",
+ (unsigned)t2);
+
+ break;
+
+ case DHCPV6_CONFIRM:
+ /*
+ * Set preferred and max life to zero,
+ * per 17.1.3.
+ */
+ memset(addrds.buffer->data + 16, 0, 8);
+ log_debug("XMT: | X-- Confirm Address %s",
+ piaddr(addr->address));
+ break;
+
+ case DHCPV6_RELEASE:
+ /* Preferred and max life are irrelevant */
+ memset(addrds.buffer->data + 16, 0, 8);
+ log_debug("XMT: | X-- Release Address %s",
+ piaddr(addr->address));
+ break;
+
+ case DHCPV6_DECLINE:
+ /* Preferred and max life are irrelevant */
+ memset(addrds.buffer->data + 16, 0, 8);
+ log_debug("XMT: | X-- Decline Address %s",
+ piaddr(addr->address));
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.",
+ MDL);
+ }
append_option(&iads, &dhcpv6_universe, iaaddr_option,
- &addrds);
+ &addrds);
data_string_forget(&addrds, MDL);
}
/*
- * It doesn't make sense to make a request without an
+ * It doesn't make sense to make a request without an
* address.
*/
if (ia->addrs == NULL) {
data_string_forget(&iads, MDL);
}
- return rval;
+ return rval;
+}
+
+/* For each IA_TA in the lease, for each address in the IA_TA,
+ * append that information onto the packet-so-far.
+ */
+static isc_result_t
+dhc6_add_ia_ta(struct client_state *client, struct data_string *packet,
+ struct dhc6_lease *lease, u_int8_t message)
+{
+ struct data_string iads;
+ struct data_string addrds;
+ struct dhc6_addr *addr;
+ struct dhc6_ia *ia;
+ isc_result_t rval = ISC_R_SUCCESS;
+ TIME t1, t2;
+
+ memset(&iads, 0, sizeof(iads));
+ memset(&addrds, 0, sizeof(addrds));
+ for (ia = lease->bindings;
+ ia != NULL && rval == ISC_R_SUCCESS;
+ ia = ia->next) {
+ if (ia->ia_type != D6O_IA_TA)
+ continue;
+
+ if (!buffer_allocate(&iads.buffer, 4, MDL)) {
+ log_error("Unable to allocate memory for IA_TA.");
+ rval = ISC_R_NOMEMORY;
+ break;
+ }
+
+ /* Copy the IAID into the packet buffer. */
+ memcpy(iads.buffer->data, ia->iaid, 4);
+ iads.data = iads.buffer->data;
+ iads.len = 4;
+
+ log_debug("XMT: X-- IA_TA %s",
+ print_hex_1(4, iads.buffer->data, 55));
+
+ for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
+ /*
+ * Do not confirm expired addresses, do not request
+ * expired addresses (but we keep them around for
+ * solicit).
+ */
+ if (addr->flags & DHC6_ADDR_EXPIRED)
+ continue;
+
+ if (addr->address.len != 16) {
+ log_error("Illegal IPv6 address length (%d), "
+ "ignoring. (%s:%d)",
+ addr->address.len, MDL);
+ continue;
+ }
+
+ if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
+ log_error("Unable to allocate memory for "
+ "IAADDR.");
+ rval = ISC_R_NOMEMORY;
+ break;
+ }
+
+ addrds.data = addrds.buffer->data;
+ addrds.len = 24;
+
+ /* Copy the address into the packet buffer. */
+ memcpy(addrds.buffer->data, addr->address.iabuf, 16);
+
+ /* Copy in additional information as appropriate */
+ switch (message) {
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease;
+ t2 = t1 + 300;
+ putULong(addrds.buffer->data + 16, t1);
+ putULong(addrds.buffer->data + 20, t2);
+
+ log_debug("XMT: | | X-- IAADDR %s",
+ piaddr(addr->address));
+ log_debug("XMT: | | | X-- Preferred "
+ "lifetime +%u", (unsigned)t1);
+ log_debug("XMT: | | | X-- Max lifetime +%u",
+ (unsigned)t2);
+
+ break;
+
+ case DHCPV6_CONFIRM:
+ /*
+ * Set preferred and max life to zero,
+ * per 17.1.3.
+ */
+ memset(addrds.buffer->data + 16, 0, 8);
+ log_debug("XMT: | X-- Confirm Address %s",
+ piaddr(addr->address));
+ break;
+
+ case DHCPV6_RELEASE:
+ /* Preferred and max life are irrelevant */
+ memset(addrds.buffer->data + 16, 0, 8);
+ log_debug("XMT: | X-- Release Address %s",
+ piaddr(addr->address));
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.",
+ MDL);
+ }
+
+ append_option(&iads, &dhcpv6_universe, iaaddr_option,
+ &addrds);
+ data_string_forget(&addrds, MDL);
+ }
+
+ /*
+ * It doesn't make sense to make a request without an
+ * address.
+ */
+ if (ia->addrs == NULL) {
+ log_debug("!!!: V IA_TA has no IAADDRs - removed.");
+ rval = ISC_R_FAILURE;
+ } else if (rval == ISC_R_SUCCESS) {
+ log_debug("XMT: V IA_TA appended.");
+ append_option(packet, &dhcpv6_universe, ia_ta_option,
+ &iads);
+ }
+
+ data_string_forget(&iads, MDL);
+ }
+
+ return rval;
+}
+
+/* For each IA_PD in the lease, for each prefix in the IA_PD,
+ * append that information onto the packet-so-far.
+ */
+static isc_result_t
+dhc6_add_ia_pd(struct client_state *client, struct data_string *packet,
+ struct dhc6_lease *lease, u_int8_t message)
+{
+ struct data_string iads;
+ struct data_string prefds;
+ struct dhc6_addr *pref;
+ struct dhc6_ia *ia;
+ isc_result_t rval = ISC_R_SUCCESS;
+ TIME t1, t2;
+
+ memset(&iads, 0, sizeof(iads));
+ memset(&prefds, 0, sizeof(prefds));
+ for (ia = lease->bindings;
+ ia != NULL && rval == ISC_R_SUCCESS;
+ ia = ia->next) {
+ if (ia->ia_type != D6O_IA_PD)
+ continue;
+
+ if (!buffer_allocate(&iads.buffer, 12, MDL)) {
+ log_error("Unable to allocate memory for IA_PD.");
+ rval = ISC_R_NOMEMORY;
+ break;
+ }
+
+ /* Copy the IAID into the packet buffer. */
+ memcpy(iads.buffer->data, ia->iaid, 4);
+ iads.data = iads.buffer->data;
+ iads.len = 12;
+
+ switch (message) {
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+
+ t1 = client->config->requested_lease / 2;
+ t2 = t1 + (t1 / 2);
+#if MAX_TIME > 0xffffffff
+ if (t1 > 0xffffffff)
+ t1 = 0xffffffff;
+ if (t2 > 0xffffffff)
+ t2 = 0xffffffff;
+#endif
+ putULong(iads.buffer->data + 4, t1);
+ putULong(iads.buffer->data + 8, t2);
+
+ log_debug("XMT: X-- IA_PD %s",
+ print_hex_1(4, iads.data, 59));
+ log_debug("XMT: | X-- Requested renew +%u",
+ (unsigned) t1);
+ log_debug("XMT: | X-- Requested rebind +%u",
+ (unsigned) t2);
+ break;
+
+ case DHCPV6_RELEASE:
+ /* Set t1 and t2 to zero; server will ignore them */
+ memset(iads.buffer->data + 4, 0, 8);
+ log_debug("XMT: X-- IA_PD %s",
+ print_hex_1(4, iads.buffer->data, 55));
+
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
+
+ for (pref = ia->addrs ; pref != NULL ; pref = pref->next) {
+ /*
+ * Do not confirm expired prefixes, do not request
+ * expired prefixes (but we keep them around for
+ * solicit).
+ */
+ if (pref->flags & DHC6_ADDR_EXPIRED)
+ continue;
+
+ if (pref->address.len != 16) {
+ log_error("Illegal IPv6 prefix "
+ "ignoring. (%s:%d)",
+ MDL);
+ continue;
+ }
+
+ if (pref->plen == 0) {
+ log_info("Null IPv6 prefix, "
+ "ignoring. (%s:%d)",
+ MDL);
+ }
+
+ if (!buffer_allocate(&prefds.buffer, 25, MDL)) {
+ log_error("Unable to allocate memory for "
+ "IAPREFIX.");
+ rval = ISC_R_NOMEMORY;
+ break;
+ }
+
+ prefds.data = prefds.buffer->data;
+ prefds.len = 25;
+
+ /* Copy the prefix into the packet buffer. */
+ putUChar(prefds.buffer->data + 8, pref->plen);
+ memcpy(prefds.buffer->data + 9,
+ pref->address.iabuf,
+ 16);
+
+ /* Copy in additional information as appropriate */
+ switch (message) {
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease;
+ t2 = t1 + 300;
+ putULong(prefds.buffer->data, t1);
+ putULong(prefds.buffer->data + 4, t2);
+
+ log_debug("XMT: | | X-- IAPREFIX %s/%u",
+ piaddr(pref->address),
+ (unsigned) pref->plen);
+ log_debug("XMT: | | | X-- Preferred "
+ "lifetime +%u", (unsigned)t1);
+ log_debug("XMT: | | | X-- Max lifetime +%u",
+ (unsigned)t2);
+
+ break;
+
+ case DHCPV6_RELEASE:
+ /* Preferred and max life are irrelevant */
+ memset(prefds.buffer->data, 0, 8);
+ log_debug("XMT: | X-- Release Prefix %s/%u",
+ piaddr(pref->address),
+ (unsigned) pref->plen);
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.",
+ MDL);
+ }
+
+ append_option(&iads, &dhcpv6_universe,
+ iaprefix_option, &prefds);
+ data_string_forget(&prefds, MDL);
+ }
+
+ /*
+ * It doesn't make sense to make a request without an
+ * address.
+ */
+ if (ia->addrs == NULL) {
+ log_debug("!!!: V IA_PD has no IAPREFIXs - removed.");
+ rval = ISC_R_FAILURE;
+ } else if (rval == ISC_R_SUCCESS) {
+ log_debug("XMT: V IA_PD appended.");
+ append_option(packet, &dhcpv6_universe,
+ ia_pd_option, &iads);
+ }
+
+ data_string_forget(&iads, MDL);
+ }
+
+ return rval;
}
/* stopping_finished() checks if there is a remaining work to do.
cancel_timeout(do_refresh6, client);
cancel_timeout(do_release6, client);
- /* If this is in response to a Release/Decline, clean up and return. */
+ /* If this is in response to a Release/Decline, clean up and return. */
if (client->state == S_STOPPED) {
if (client->active_lease == NULL)
return;
- dhc6_lease_destroy(&client->active_lease, MDL);
- client->active_lease = NULL;
+ dhc6_lease_destroy(&client->active_lease, MDL);
+ client->active_lease = NULL;
/* We should never wait for nothing!? */
if (stopping_finished())
exit(0);
return;
- }
+ }
/* Action was taken, so now that we've torn down our scheduled
* retransmissions, return.
/* addr fields. */
if (addr != NULL) {
- /* Current practice is that all subnets are /64's, but
- * some suspect this may not be permanent.
- */
- client_envadd(client, prefix, "ip6_prefixlen", "%d", 64);
- client_envadd(client, prefix, "ip6_address", "%s",
- piaddr(addr->address));
+ if ((ia != NULL) && (ia->ia_type == D6O_IA_PD)) {
+ client_envadd(client, prefix,
+ "ip6_prefix", "%s/%u",
+ piaddr(addr->address),
+ (unsigned) addr->plen);
+ } else {
+ /* Current practice is that all subnets are /64's, but
+ * some suspect this may not be permanent.
+ */
+ client_envadd(client, prefix, "ip6_prefixlen",
+ "%d", 64);
+ client_envadd(client, prefix, "ip6_address",
+ "%s", piaddr(addr->address));
+ }
+ if ((ia != NULL) && (ia->ia_type == D6O_IA_TA)) {
+ client_envadd(client, prefix,
+ "ip6_type", "temporary");
+ }
client_envadd(client, prefix, "life_starts", "%d",
(int)(addr->starts));
client_envadd(client, prefix, "preferred_life", "%d",
for(ia = lease->bindings ; ia != NULL ; ia = ia->next) {
TIME this_ia_lo_expire, this_ia_hi_expire, use_expire;
- if (ia->ia_type != D6O_IA_NA)
- continue;
-
this_ia_lo_expire = MAX_TIME;
this_ia_hi_expire = 0;
else
use_expire /= 2;
- if (ia->renew == 0) {
- tmp = ia->starts + use_expire;
- } else if(ia->renew == 0xffffffff)
- tmp = MAX_TIME;
- else
- tmp = ia->starts + ia->renew;
+ /* Don't renew/rebind temporary addresses. */
+ if (ia->ia_type != D6O_IA_TA) {
+
+ if (ia->renew == 0) {
+ tmp = ia->starts + use_expire;
+ } else if (ia->renew == 0xffffffff)
+ tmp = MAX_TIME;
+ else
+ tmp = ia->starts + ia->renew;
- if (tmp < renew)
- renew = tmp;
+ if (tmp < renew)
+ renew = tmp;
- if (ia->rebind == 0) {
- /* Set rebind to 3/4 expiration interval. */
- tmp = ia->starts + use_expire + (use_expire / 2);
- } else if (ia->renew == 0xffffffff)
- tmp = MAX_TIME;
- else
- tmp = ia->starts + ia->rebind;
+ if (ia->rebind == 0) {
+ /* Set rebind to 3/4 expiration interval. */
+ tmp = ia->starts;
+ tmp += use_expire + (use_expire / 2);
+ } else if (ia->renew == 0xffffffff)
+ tmp = MAX_TIME;
+ else
+ tmp = ia->starts + ia->rebind;
- if (tmp < rebind)
- rebind = tmp;
+ if (tmp < rebind)
+ rebind = tmp;
+ }
/*
* Return expiration ranges to EPOCH relative for event
}
}
-/* In a given IA chain, find the IA with the same 'iaid'. */
+/* In a given IA chain, find the IA with the same type and 'iaid'. */
static struct dhc6_ia *
-find_ia_na(struct dhc6_ia *head, const char *id)
+find_ia(struct dhc6_ia *head, u_int16_t type, const char *id)
{
struct dhc6_ia *ia;
for (ia = head ; ia != NULL ; ia = ia->next) {
- if (ia->ia_type != D6O_IA_NA)
+ if (ia->ia_type != type)
continue;
if (memcmp(ia->iaid, id, 4) == 0)
return ia;
return NULL;
}
+/* In a given prefix chain, find a matching prefix. */
+static struct dhc6_addr *
+find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen)
+{
+ struct dhc6_addr *pref;
+
+ for (pref = head ; pref != NULL ; pref = pref->next) {
+ if ((pref->address.len == prefix->len) &&
+ (pref->plen == plen) &&
+ (memcmp(pref->address.iabuf, prefix->iabuf,
+ prefix->len) == 0))
+ return pref;
+ }
+
+ return NULL;
+}
+
/* Merge the bindings from the source lease into the destination lease
* structure, where they are missing. We have to copy the stateful
* objects rather than move them over, because later code needs to be
return;
for (sia = src->bindings ; sia != NULL ; sia = sia->next) {
- if (sia->ia_type != D6O_IA_NA)
- continue;
- dia = find_ia_na(dst->bindings, (char *)sia->iaid);
+ dia = find_ia(dst->bindings, sia->ia_type, (char *)sia->iaid);
if (dia == NULL) {
tia = dhc6_dup_ia(sia, MDL);
} else {
for (saddr = sia->addrs ; saddr != NULL ;
saddr = saddr->next) {
- daddr = find_addr(dia->addrs,
- &saddr->address);
+ if (sia->ia_type != D6O_IA_PD)
+ daddr = find_addr(dia->addrs,
+ &saddr->address);
+ else
+ daddr = find_pref(dia->addrs,
+ &saddr->address,
+ saddr->plen);
if (daddr == NULL) {
taddr = dhc6_dup_addr(saddr, MDL);
oldia = NULL;
for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
- if (ia->ia_type != D6O_IA_NA)
- continue;
-
if (old != NULL)
- oldia = find_ia_na(old->bindings, (char *)ia->iaid);
+ oldia = find_ia(old->bindings,
+ ia->ia_type,
+ (char *)ia->iaid);
else
oldia = NULL;
for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
- if (oldia != NULL)
- oldaddr = find_addr(oldia->addrs,
- &addr->address);
- else
+ if (oldia != NULL) {
+ if (ia->ia_type != D6O_IA_PD)
+ oldaddr = find_addr(oldia->addrs,
+ &addr->address);
+ else
+ oldaddr = find_pref(oldia->addrs,
+ &addr->address,
+ addr->plen);
+ } else
oldaddr = NULL;
- if (oldaddr == NULL)
+ if ((oldaddr == NULL) && (ia->ia_type == D6O_IA_NA))
dhclient_schedule_updates(client,
&addr->address,
dns_update_offset++);
int send_ret;
client = (struct client_state *)input;
+ memset(&ds, 0, sizeof(ds));
lease = client->active_lease;
if (lease == NULL) {
*/
oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST);
if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
- lease->options, NULL, &global_scope,
+ lease->options, NULL, &global_scope,
oc, MDL)) {
if (ds.len < 16) {
log_error("Invalid unicast option length %d.", ds.len);
client->sent_options, &global_scope,
&dhcpv6_universe);
- /* Append IA's */
- if (dhc6_add_ia_na(client, &ds, lease,
+ /* Append IA's */
+ if (wanted_ia_na &&
+ dhc6_add_ia_na(client, &ds, lease,
+ client->refresh_type) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
+ }
+ if (wanted_ia_pd &&
+ dhc6_add_ia_pd(client, &ds, lease,
client->refresh_type) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
return;
return;
for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
- if (ia->ia_type != D6O_IA_NA)
- continue;
for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
if (addr->flags & DHC6_ADDR_DEPREFFED)
continue;
ia, addr);
script_go(client);
- log_info("PRC: Address %s depreferred.",
- print_hex_1(addr->address.len,
- addr->address.iabuf,
- 50));
-
-
addr->flags |= DHC6_ADDR_DEPREFFED;
+ if (ia->ia_type != D6O_IA_PD)
+ log_info("PRC: Address %s depreferred.",
+ piaddr(addr->address));
+ else
+ log_info("PRC: Prefix %s/%u depreferred.",
+ piaddr(addr->address),
+ (unsigned) addr->plen);
+
/* Remove DDNS bindings at depref time. */
- if (client->config->do_forward_update)
+ if ((ia->ia_type == D6O_IA_NA) &&
+ client->config->do_forward_update)
client_dns_update(client, 0, 0,
&addr->address);
}
return;
for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
- if (ia->ia_type != D6O_IA_NA)
- continue;
for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
if (addr->flags & DHC6_ADDR_EXPIRED)
continue;
addr->flags |= DHC6_ADDR_EXPIRED;
- log_info("PRC: Address %s expired.",
- print_hex_1(addr->address.len,
- addr->address.iabuf,
- 50));
+ if (ia->ia_type != D6O_IA_PD)
+ log_info("PRC: Address %s expired.",
+ piaddr(addr->address));
+ else
+ log_info("PRC: Prefix %s/%u expired.",
+ piaddr(addr->address),
+ (unsigned) addr->plen);
/* We remove DNS records at depref time, but
* it is possible that we might get here
* without depreffing.
*/
- if (client->config->do_forward_update &&
+ if ((ia->ia_type == D6O_IA_NA) &&
+ client->config->do_forward_update &&
!(addr->flags & DHC6_ADDR_DEPREFFED))
client_dns_update(client, 0, 0,
&addr->address);
return;
for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) {
- if (ia->ia_type != D6O_IA_NA)
+ if (ia->ia_type == D6O_IA_TA)
continue;
for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
script_init(client, reason, NULL);
- dhc6_marshall_values("old_", client,
+ dhc6_marshall_values("old_", client,
client->active_lease, ia, addr);
script_go(client);
-
- if (client->config->do_forward_update)
+
+ if ((ia->ia_type == D6O_IA_NA) &&
+ client->config->do_forward_update)
client_dns_update(client, 0, 0, &addr->address);
}
}
option_cache_dereference(&oc, MDL);
}
- /* Bring in any configured options to send. */
+ /* Bring in any configured options to send. */
if (client->config->on_transmission)
execute_statements_in_scope(NULL, NULL, NULL, client,
lease ? lease->options : NULL,
}
}
+/*
+ * Check if there is something not fully defined in the active lease.
+ */
+static isc_boolean_t
+active_prefix(struct client_state *client)
+{
+ struct dhc6_lease *lease;
+ struct dhc6_ia *ia;
+ struct dhc6_addr *pref;
+ char zeros[16];
+
+ lease = client->active_lease;
+ if (lease == NULL)
+ return ISC_FALSE;
+ memset(zeros, 0, 16);
+ for (ia = lease->bindings; ia != NULL; ia = ia->next) {
+ if (ia->ia_type != D6O_IA_PD)
+ continue;
+ for (pref = ia->addrs; pref != NULL; pref = pref->next) {
+ if (pref->plen == 0)
+ return ISC_FALSE;
+ if (pref->address.len != 16)
+ return ISC_FALSE;
+ if (memcmp(pref->address.iabuf, zeros, 16) == 0)
+ return ISC_FALSE;
+ }
+ }
+ return ISC_TRUE;
+}
#endif /* DHCPv6 */
const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
const char *path_dhclient_db = NULL;
const char *path_dhclient_pid = NULL;
-static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT;
+static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
char *path_dhclient_script = path_dhclient_script_array;
int dhcp_max_agent_option_packet_length = 0;
static char message [] = "Internet Systems Consortium DHCP Client";
static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/";
-u_int16_t local_port=0;
-u_int16_t remote_port=0;
-int no_daemon=0;
-struct string_list *client_env=NULL;
-int client_env_count=0;
-int onetry=0;
-int quiet=1;
-int nowait=0;
-int stateless=0;
+u_int16_t local_port = 0;
+u_int16_t remote_port = 0;
+int no_daemon = 0;
+struct string_list *client_env = NULL;
+int client_env_count = 0;
+int onetry = 0;
+int quiet = 1;
+int nowait = 0;
+int stateless = 0;
+int wanted_ia_na = -1; /* the absolute value is the real one. */
+int wanted_ia_ta = 0;
+int wanted_ia_pd = 0;
char *mockup_relay = NULL;
void run_stateless(int exit_mode);
-static void usage PROTO ((void));
+static void usage(void);
static isc_result_t write_duid(struct data_string *duid);
struct interface_info *ip;
struct client_state *client;
unsigned seed;
- char *server = (char *)0;
+ char *server = NULL;
isc_result_t status;
int exit_mode = 0;
int release_mode = 0;
else if (fd != -1)
close(fd);
- openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
+ openlog("dhclient", LOG_NDELAY, LOG_DAEMON);
-#if !(defined (DEBUG) || defined (__CYGWIN32__))
- setlogmask (LOG_UPTO (LOG_INFO));
+#if !(defined(DEBUG) || defined(__CYGWIN32__))
+ setlogmask(LOG_UPTO(LOG_INFO));
#endif
/* Set up the OMAPI. */
- status = omapi_init ();
+ status = omapi_init();
if (status != ISC_R_SUCCESS)
- log_fatal ("Can't initialize OMAPI: %s",
- isc_result_totext (status));
+ 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_common_objects_setup();
dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
local_family_set = 1;
local_family = AF_INET6;
#endif /* DHCPv6 */
- } else if (!strcmp (argv [i], "-x")) { /* eXit, no release */
+ } else if (!strcmp(argv[i], "-x")) { /* eXit, no release */
release_mode = 0;
no_daemon = 0;
exit_mode = 1;
- } else if (!strcmp (argv [i], "-p")) {
+ } else if (!strcmp(argv[i], "-p")) {
if (++i == argc)
- usage ();
- local_port = htons (atoi (argv [i]));
- log_debug ("binding to user-specified port %d",
- ntohs (local_port));
- } else if (!strcmp (argv [i], "-d")) {
+ usage();
+ local_port = htons(atoi(argv[i]));
+ log_debug("binding to user-specified port %d",
+ ntohs(local_port));
+ } else if (!strcmp(argv[i], "-d")) {
no_daemon = 1;
quiet = 0;
- } else if (!strcmp (argv [i], "-pf")) {
+ } else if (!strcmp(argv[i], "-pf")) {
if (++i == argc)
- usage ();
- path_dhclient_pid = argv [i];
+ usage();
+ path_dhclient_pid = argv[i];
no_dhclient_pid = 1;
- } else if (!strcmp (argv [i], "-cf")) {
+ } else if (!strcmp(argv[i], "-cf")) {
if (++i == argc)
- usage ();
- path_dhclient_conf = argv [i];
+ usage();
+ path_dhclient_conf = argv[i];
no_dhclient_conf = 1;
- } else if (!strcmp (argv [i], "-lf")) {
+ } else if (!strcmp(argv[i], "-lf")) {
if (++i == argc)
- usage ();
- path_dhclient_db = argv [i];
+ usage();
+ path_dhclient_db = argv[i];
no_dhclient_db = 1;
- } else if (!strcmp (argv [i], "-sf")) {
+ } else if (!strcmp(argv[i], "-sf")) {
if (++i == argc)
- usage ();
- path_dhclient_script = argv [i];
+ usage();
+ path_dhclient_script = argv[i];
no_dhclient_script = 1;
- } else if (!strcmp (argv [i], "-1")) {
+ } else if (!strcmp(argv[i], "-1")) {
onetry = 1;
- } else if (!strcmp (argv [i], "-q")) {
+ } else if (!strcmp(argv[i], "-q")) {
quiet = 1;
- } else if (!strcmp (argv [i], "-s")) {
+ } else if (!strcmp(argv[i], "-s")) {
if (++i == argc)
- usage ();
- server = argv [i];
- } else if (!strcmp (argv [i], "-g")) {
+ usage();
+ server = argv[i];
+ } else if (!strcmp(argv[i], "-g")) {
if (++i == argc)
- usage ();
- mockup_relay = argv [i];
- } else if (!strcmp (argv [i], "-nw")) {
+ usage();
+ mockup_relay = argv[i];
+ } else if (!strcmp(argv[i], "-nw")) {
nowait = 1;
- } else if (!strcmp (argv [i], "-n")) {
+ } else if (!strcmp(argv[i], "-n")) {
/* do not start up any interfaces */
interfaces_requested = -1;
- } else if (!strcmp (argv [i], "-w")) {
+ } else if (!strcmp(argv[i], "-w")) {
/* do not exit if there are no broadcast interfaces. */
persist = 1;
- } else if (!strcmp (argv [i], "-e")) {
+ } else if (!strcmp(argv[i], "-e")) {
struct string_list *tmp;
if (++i == argc)
- usage ();
- tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL);
+ 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;
+ log_fatal("No memory for %s", argv[i]);
+ strcpy(tmp->string, argv[i]);
+ tmp->next = client_env;
client_env = tmp;
client_env_count++;
+#ifdef DHCPv6
} else if (!strcmp(argv[i], "-S")) {
if (local_family_set && (local_family == AF_INET)) {
- usage ();
+ usage();
}
local_family_set = 1;
local_family = AF_INET6;
+ wanted_ia_na = 0;
stateless = 1;
+ } else if (!strcmp(argv[i], "-N")) {
+ if (local_family_set && (local_family == AF_INET)) {
+ usage();
+ }
+ local_family_set = 1;
+ local_family = AF_INET6;
+ if (wanted_ia_na < 0) {
+ wanted_ia_na = 0;
+ }
+ wanted_ia_na++;
+ } else if (!strcmp(argv[i], "-T")) {
+ if (local_family_set && (local_family == AF_INET)) {
+ usage();
+ }
+ local_family_set = 1;
+ local_family = AF_INET6;
+ if (wanted_ia_na < 0) {
+ wanted_ia_na = 0;
+ }
+ wanted_ia_ta++;
+ } else if (!strcmp(argv[i], "-P")) {
+ if (local_family_set && (local_family == AF_INET)) {
+ usage();
+ }
+ local_family_set = 1;
+ local_family = AF_INET6;
+ if (wanted_ia_na < 0) {
+ wanted_ia_na = 0;
+ }
+ wanted_ia_pd++;
+#endif /* DHCPv6 */
} 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 (!strcmp(argv[i], "--version")) {
+ log_info("isc-dhclient-%s", PACKAGE_VERSION);
+ exit(0);
+ } else if (argv[i][0] == '-') {
+ usage();
} else if (interfaces_requested < 0) {
- usage ();
+ usage();
} else {
- struct interface_info *tmp = (struct interface_info *)0;
- status = interface_allocate (&tmp, MDL);
+ struct interface_info *tmp = NULL;
+
+ status = interface_allocate(&tmp, MDL);
if (status != ISC_R_SUCCESS)
- log_fatal ("Can't record interface %s:%s",
- argv [i], isc_result_totext (status));
+ 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)",
- argv [i], (long)strlen(argv[i]));
+ argv[i], (long)strlen(argv[i]));
strcpy(tmp->name, argv[i]);
if (interfaces) {
- interface_reference (&tmp -> next,
- interfaces, MDL);
- interface_dereference (&interfaces, MDL);
+ interface_reference(&tmp->next,
+ interfaces, MDL);
+ interface_dereference(&interfaces, MDL);
}
- interface_reference (&interfaces, tmp, MDL);
- tmp -> flags = INTERFACE_REQUESTED;
+ interface_reference(&interfaces, tmp, MDL);
+ tmp->flags = INTERFACE_REQUESTED;
interfaces_requested++;
}
}
- if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
+ if (wanted_ia_na < 0) {
+ wanted_ia_na = 1;
+ }
+
+ /* Support only one (requested) interface for Prefix Delegation. */
+ if (wanted_ia_pd && (interfaces_requested != 1)) {
+ usage();
+ }
+
+ if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) {
path_dhclient_conf = s;
}
- if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) {
+ if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) {
path_dhclient_db = s;
}
- if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) {
+ if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) {
path_dhclient_pid = s;
}
- if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) {
+ if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) {
path_dhclient_script = s;
}
char *path = dmalloc(PATH_MAX, MDL);
if (path == NULL)
log_fatal("No memory for filename\n");
- path_dhclient_db = realpath(path_dhclient_db, path);
+ path_dhclient_db = realpath(path_dhclient_db, path);
if (path_dhclient_db == NULL)
log_fatal("%s: %s", path, strerror(errno));
}
char *path = dmalloc(PATH_MAX, MDL);
if (path == NULL)
log_fatal("No memory for filename\n");
- path_dhclient_script = realpath(path_dhclient_script, path);
+ path_dhclient_script = realpath(path_dhclient_script, path);
if (path_dhclient_script == NULL)
log_fatal("%s: %s", path, strerror(errno));
}
}
if (!quiet) {
- log_info ("%s %s", message, PACKAGE_VERSION);
- log_info (copyright);
- log_info (arr);
- log_info (url);
- log_info ("%s", "");
+ log_info("%s %s", message, PACKAGE_VERSION);
+ log_info(copyright);
+ log_info(arr);
+ log_info(url);
+ log_info("%s", "");
} else {
log_perror = 0;
quiet_interface_discovery = 1;
/* If we're given a relay agent address to insert, for testing
purposes, figure out what it is. */
if (mockup_relay) {
- if (!inet_aton (mockup_relay, &giaddr)) {
+ if (!inet_aton(mockup_relay, &giaddr)) {
struct hostent *he;
- he = gethostbyname (mockup_relay);
+ he = gethostbyname(mockup_relay);
if (he) {
- memcpy (&giaddr, he -> h_addr_list [0],
- sizeof giaddr);
+ memcpy(&giaddr, he->h_addr_list[0],
+ sizeof giaddr);
} else {
- log_fatal ("%s: no such host", mockup_relay);
+ log_fatal("%s: no such host", mockup_relay);
}
}
}
sockaddr_broadcast.sin_family = AF_INET;
sockaddr_broadcast.sin_port = remote_port;
if (server) {
- if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) {
+ if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) {
struct hostent *he;
- he = gethostbyname (server);
+ he = gethostbyname(server);
if (he) {
- memcpy (&sockaddr_broadcast.sin_addr,
- he -> h_addr_list [0],
- sizeof sockaddr_broadcast.sin_addr);
+ memcpy(&sockaddr_broadcast.sin_addr,
+ he->h_addr_list[0],
+ sizeof sockaddr_broadcast.sin_addr);
} else
sockaddr_broadcast.sin_addr.s_addr =
INADDR_BROADCAST;
/* Stateless special case. */
if (stateless) {
- if (release_mode || (interfaces_requested != 1)) {
- usage ();
+ if (release_mode || (wanted_ia_na > 0) ||
+ wanted_ia_ta || wanted_ia_pd ||
+ (interfaces_requested != 1)) {
+ usage();
}
- run_stateless (exit_mode);
+ run_stateless(exit_mode);
return 0;
}
/* Discover all the network interfaces. */
- discover_interfaces (DISCOVER_UNCONFIGURED);
+ discover_interfaces(DISCOVER_UNCONFIGURED);
/* Parse the dhclient.conf file. */
- read_client_conf ();
+ read_client_conf();
/* Parse the lease database. */
- read_client_leases ();
+ read_client_leases();
/* Rewrite the lease database... */
- rewrite_client_leases ();
+ rewrite_client_leases();
/* XXX */
/* config_counter(&snd_counter, &rcv_counter); */
- /* If no broadcast interfaces were discovered, call the script
- and tell it so. */
+ /*
+ * If no broadcast interfaces were discovered, call the script
+ * and tell it so.
+ */
if (!interfaces) {
- /* 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 client_state *)0);
-
- /* If we haven't been asked to persist, waiting for new
- interfaces, then just exit. */
+ /*
+ * Call dhclient-script with the NBI flag,
+ * in case somebody cares.
+ */
+ script_init(NULL, "NBI", NULL);
+ script_go(NULL);
+
+ /*
+ * 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);
+ log_info("No broadcast interfaces found - exiting.");
+ exit(0);
}
} else if (!release_mode && !exit_mode) {
/* Call the script with the list of interfaces. */
- for (ip = interfaces; ip; ip = ip -> next) {
- /* If interfaces were specified, don't configure
- interfaces that weren't specified! */
+ for (ip = interfaces; ip; ip = ip->next) {
+ /*
+ * If interfaces were specified, don't configure
+ * interfaces that weren't specified!
+ */
if ((interfaces_requested > 0) &&
- ((ip -> flags & (INTERFACE_REQUESTED |
- INTERFACE_AUTOMATIC)) !=
+ ((ip->flags & (INTERFACE_REQUESTED |
+ INTERFACE_AUTOMATIC)) !=
INTERFACE_REQUESTED))
continue;
"alias_",
ip->client->alias);
}
- script_go (ip->client);
+ script_go(ip->client);
}
}
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 != 0
- ? DISCOVER_REQUESTED
- : DISCOVER_RUNNING);
+ discover_interfaces(interfaces_requested != 0
+ ? 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
Not much entropy, but we're booting, so we're not likely to
find anything better. */
seed = 0;
- for (ip = interfaces; ip; ip = ip -> next) {
+ for (ip = interfaces; ip; ip = ip->next) {
int junk;
- memcpy (&junk,
- &ip -> hw_address.hbuf [ip -> hw_address.hlen -
- sizeof seed], sizeof seed);
+ memcpy(&junk,
+ &ip->hw_address.hbuf[ip->hw_address.hlen -
+ sizeof seed], sizeof seed);
seed += junk;
}
- srandom (seed + cur_time);
+ srandom(seed + cur_time);
/* Start a configuration state machine for each interface. */
#ifdef DHCPv6
/* 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);
+ listener = NULL;
+ 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);
+ 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));
+ log_fatal("Can't start OMAPI protocol: %s",
+ isc_result_totext (result));
}
/* Set up the bootp packet handler... */
dhcpv6_packet_handler = do_packet6;
#endif /* DHCPv6 */
-#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
- defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+#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;
/* If we're not supposed to wait before getting the address,
don't. */
if (nowait)
- go_daemon ();
+ go_daemon();
/* If we're not going to daemonize, write the pid file
now. */
if (no_daemon || nowait)
- write_client_pid_file ();
+ write_client_pid_file();
/* Start dispatching packets and timeouts... */
- dispatch ();
+ dispatch();
/*NOTREACHED*/
return 0;
}
-static void usage ()
+static void usage()
{
- log_info ("%s %s", message, PACKAGE_VERSION);
- log_info (copyright);
- log_info (arr);
- log_info (url);
+ log_info("%s %s", message, PACKAGE_VERSION);
+ log_info(copyright);
+ log_info(arr);
+ log_info(url);
- log_error ("Usage: dhclient %s %s",
+ log_error("Usage: dhclient %s %s",
#ifdef DHCPv6
- "[-4|-6] [-S1dvrx] [-nw] [-p <port>]",
+ "[-4|-6] [-SNTP1dvrx] [-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",
- "[-pf pid-file] [-e VAR=val]");
- log_fatal (" [-sf script-file] [interface]");
+ "[-s server]");
+ log_error(" [-cf config-file] [-lf lease-file]%s",
+ "[-pf pid-file] [-e VAR=val]");
+ log_fatal(" [-sf script-file] [interface]");
}
void run_stateless(int exit_mode)
{
+#ifdef DHCPv6
struct client_state *client;
omapi_object_t *listener;
isc_result_t result;
/* Start up a listener for the object management API protocol. */
if (top_level_config.omapi_port != -1) {
- listener = (omapi_object_t *)0;
+ listener = NULL;
result = omapi_generic_new(&listener, MDL);
if (result != ISC_R_SUCCESS)
log_fatal("Can't allocate new generic object: %s\n",
/* 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)
+#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;
dispatch();
/*NOTREACHED*/
+#endif /* DHCPv6 */
return;
}
/* We are in the rebooting state. */
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. */
+ /*
+ * 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.
+ */
client -> xid = random ();
- /* Make a DHCPREQUEST packet, and set appropriate per-interface
- flags. */
+ /*
+ * Make a DHCPREQUEST packet, and set
+ * appropriate per-interface flags.
+ */
make_request (client, client -> active);
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;
+ client -> medium = NULL;
/* Send out the first DHCPREQUEST packet. */
send_request (client);
send_discover (client);
}
-/* state_selecting is called when one or more DHCPOFFER packets have been
- received and a configurable period of time has passed. */
+/*
+ * state_selecting is called when one or more DHCPOFFER packets have been
+ * received and a configurable period of time has passed.
+ */
void state_selecting (cpp)
void *cpp;
ASSERT_STATE(state, S_SELECTING);
- /* Cancel state_selecting and send_discover timeouts, since either
- one could have got us here. */
+ /*
+ * Cancel state_selecting and send_discover timeouts, since either
+ * one could have got us here.
+ */
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;
+ /*
+ * 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 = NULL;
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. */
+ /*
+ * Check to see if we got an ARPREPLY for the address
+ * in this particular lease.
+ */
if (!picked) {
picked = lp;
- picked -> next = (struct client_lease *)0;
+ picked -> next = NULL;
} else {
destroy_client_lease (lp);
}
}
- client -> offered_leases = (struct client_lease *)0;
+ client -> offered_leases = NULL;
- /* If we just tossed all the leases we were offered, go back
- to square one. */
+ /*
+ * If we just tossed all the leases we were offered, go back
+ * to square one.
+ */
if (!picked) {
client -> state = S_INIT;
state_init (client);