summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2008-05-23 13:56:07 +0000
committerFrancis Dupont <fdupont@isc.org>2008-05-23 13:56:07 +0000
commit420d8b3f0cecfc774ce9c46747ed5a2fb1ff8b5c (patch)
tree2a5159203b72007751b52eba9bffabedea38d901 /client
parent3dbe22465b8d37681dc59e18c0c0d3807e09069d (diff)
downloadisc-dhcp-420d8b3f0cecfc774ce9c46747ed5a2fb1ff8b5c.tar.gz
merge 17500
Diffstat (limited to 'client')
-rw-r--r--client/dhc6.c1396
-rw-r--r--client/dhclient.845
-rw-r--r--client/dhclient.c423
-rwxr-xr-xclient/scripts/bsdos6
-rwxr-xr-xclient/scripts/freebsd14
-rwxr-xr-xclient/scripts/linux12
-rwxr-xr-xclient/scripts/netbsd6
-rw-r--r--client/scripts/openbsd6
8 files changed, 1367 insertions, 541 deletions
diff --git a/client/dhc6.c b/client/dhc6.c
index 00f30e61..b8dbdd28 100644
--- a/client/dhc6.c
+++ b/client/dhc6.c
@@ -28,7 +28,8 @@
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;
@@ -43,7 +44,7 @@ struct option *irt_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);
@@ -60,12 +61,15 @@ static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia,
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);
@@ -77,6 +81,14 @@ static isc_result_t dhc6_add_ia_na(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);
@@ -93,13 +105,15 @@ void do_expire(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.
@@ -128,7 +142,8 @@ form_duid(struct data_string *duid, const char *file, int line)
(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
@@ -157,7 +172,8 @@ form_duid(struct data_string *duid, const char *file, int line)
}
}
-/* Assign DHCPv6 port numbers as a client.
+/*
+ * Assign DHCPv6 port numbers as a client.
*/
void
dhcpv6_client_assignments(void)
@@ -243,7 +259,8 @@ 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:
@@ -268,13 +285,15 @@ dhc6_rand(TIME base)
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).
*/
@@ -284,7 +303,8 @@ dhc6_rand(TIME base)
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).
*/
@@ -349,24 +369,27 @@ dhc6_retrans_advance(struct client_state *client)
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) {
@@ -439,7 +462,8 @@ valid_reply(struct packet *packet, struct client_state *client)
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)
@@ -476,7 +500,8 @@ 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)
@@ -512,7 +537,8 @@ 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)
@@ -539,7 +565,8 @@ 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.
*/
@@ -582,7 +609,8 @@ dhc6_leaseify(struct packet *packet)
}
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,
@@ -591,7 +619,8 @@ dhc6_leaseify(struct packet *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,
@@ -600,7 +629,8 @@ dhc6_leaseify(struct packet *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,
@@ -610,7 +640,8 @@ dhc6_leaseify(struct packet *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).
@@ -669,7 +700,8 @@ dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
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.
@@ -693,7 +725,7 @@ dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
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;
@@ -724,6 +756,8 @@ dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
}
}
+ while (*pia != NULL)
+ pia = &(*pia)->next;
*pia = ia;
pia = &ia->next;
} else {
@@ -776,7 +810,7 @@ dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet,
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;
@@ -807,6 +841,8 @@ dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet,
}
}
+ while (*pia != NULL)
+ pia = &(*pia)->next;
*pia = ia;
pia = &ia->next;
} else {
@@ -857,9 +893,10 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
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) &&
@@ -877,7 +914,7 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
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;
@@ -898,8 +935,9 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
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);
@@ -908,6 +946,8 @@ dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
}
}
+ while (*pia != NULL)
+ pia = &(*pia)->next;
*pia = ia;
pia = &ia->next;
} else {
@@ -959,7 +999,8 @@ dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
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)) {
@@ -971,7 +1012,8 @@ dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
continue;
}
- /* Fortunately this is the last recursion in the
+ /*
+ * Fortunately this is the last recursion in the
* protocol.
*/
if (ds.len > 24) {
@@ -1019,19 +1061,19 @@ dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
}
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;
@@ -1040,78 +1082,80 @@ dhc6_parse_prefs(struct dhc6_addr **ppref, struct packet *packet,
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;
@@ -1127,12 +1171,12 @@ void
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)
@@ -1148,7 +1192,7 @@ dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line)
option_state_dereference(&lease->options, file, line);
dfree(lease, file, line);
- *src = NULL;
+ *src = NULL;
}
/*
@@ -1159,12 +1203,12 @@ static void
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) {
@@ -1180,10 +1224,11 @@ dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line)
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
@@ -1205,7 +1250,8 @@ insert_lease(struct dhc6_lease **head, struct dhc6_lease *new)
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)
@@ -1233,9 +1279,7 @@ 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++) {
@@ -1256,7 +1300,8 @@ dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
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
@@ -1276,7 +1321,7 @@ start_init6(struct client_state *client)
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.
*/
@@ -1289,7 +1334,8 @@ start_init6(struct client_state *client)
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.
*/
@@ -1306,7 +1352,8 @@ start_init6(struct client_state *client)
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
@@ -1327,7 +1374,8 @@ start_info_request6(struct client_state *client)
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.
*/
@@ -1344,7 +1392,8 @@ start_info_request6(struct client_state *client)
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.
*/
@@ -1354,7 +1403,9 @@ start_confirm6(struct client_state *client)
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;
}
@@ -1372,7 +1423,8 @@ start_confirm6(struct client_state *client)
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.
*/
@@ -1383,10 +1435,16 @@ start_confirm6(struct client_state *client)
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)
@@ -1399,11 +1457,12 @@ 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) {
@@ -1468,99 +1527,321 @@ do_init6(void *input)
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. */
@@ -1786,7 +2067,14 @@ do_confirm6(void *input)
&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;
@@ -1825,19 +2113,19 @@ do_confirm6(void *input)
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)
@@ -1869,7 +2157,7 @@ do_release6(void *input)
client = input;
- if (client->active_lease == NULL)
+ if ((client->active_lease == NULL) || !active_prefix(client))
return;
if ((client->MRC != 0) && (client->txcount > client->MRC)) {
@@ -1908,8 +2196,15 @@ do_release6(void *input)
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;
@@ -1980,6 +2275,10 @@ status_log(int code, const char *scope, const char *additional, int len)
msg = "UseMulticast";
break;
+ case STATUS_NoPrefixAvail:
+ msg = "NoPrefixAvail";
+ break;
+
default:
msg = "UNKNOWN";
break;
@@ -1987,8 +2286,8 @@ status_log(int code, const char *scope, const char *additional, int len)
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);
}
@@ -2089,7 +2388,6 @@ dhc6_check_advertise(struct dhc6_lease *lease)
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:
@@ -2098,6 +2396,9 @@ dhc6_check_advertise(struct dhc6_lease *lease)
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);
@@ -2197,6 +2498,7 @@ dhc6_select_action(struct client_state *client, isc_result_t *rvalp,
* servers.
*/
case STATUS_NoAddrsAvail:
+ case STATUS_NoPrefixAvail:
if (client->state == S_REBOOTING)
return ISC_FALSE;
@@ -2345,6 +2647,7 @@ dhc6_reply_action(struct client_state *client, isc_result_t *rvalp,
* server."
*/
case STATUS_NoAddrsAvail:
+ case STATUS_NoPrefixAvail:
/* Head back to init, keeping any active bindings (!). */
start_init6(client);
break;
@@ -2407,6 +2710,7 @@ dhc6_stop_action(struct client_state *client, isc_result_t *rvalp,
/* Should not happen */
case STATUS_NoAddrsAvail:
+ case STATUS_NoPrefixAvail:
break;
/* Give up on it */
@@ -2483,7 +2787,6 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
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:
@@ -2492,6 +2795,9 @@ dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
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);
@@ -3032,7 +3338,20 @@ do_select6(void *input)
&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;
@@ -3080,8 +3399,8 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
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;
@@ -3096,43 +3415,43 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
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) {
/*
@@ -3163,61 +3482,61 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
/* 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) {
@@ -3232,7 +3551,301 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
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.
@@ -3299,18 +3912,18 @@ reply_handler(struct packet *packet, struct client_state *client)
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.
@@ -3392,12 +4005,24 @@ dhc6_marshall_values(const char *prefix, struct client_state *client,
/* 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",
@@ -3444,9 +4069,6 @@ dhc6_check_times(struct client_state *client)
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;
@@ -3496,26 +4118,31 @@ dhc6_check_times(struct client_state *client)
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
@@ -3616,14 +4243,14 @@ dhc6_check_times(struct client_state *client)
}
}
-/* 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;
@@ -3648,6 +4275,23 @@ find_addr(struct dhc6_addr *head, struct iaddr *address)
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
@@ -3664,9 +4308,7 @@ dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
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);
@@ -3683,8 +4325,13 @@ dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
} 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);
@@ -3765,22 +4412,26 @@ start_bound(struct client_state *client)
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++);
@@ -3896,6 +4547,7 @@ do_refresh6(void *input)
int send_ret;
client = (struct client_state *)input;
+ memset(&ds, 0, sizeof(ds));
lease = client->active_lease;
if (lease == NULL) {
@@ -3942,7 +4594,7 @@ do_refresh6(void *input)
*/
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);
@@ -3999,8 +4651,15 @@ do_refresh6(void *input)
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;
@@ -4086,8 +4745,6 @@ do_depref(void *input)
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;
@@ -4098,16 +4755,19 @@ do_depref(void *input)
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);
}
@@ -4136,8 +4796,6 @@ do_expire(void *input)
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;
@@ -4150,16 +4808,20 @@ do_expire(void *input)
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);
@@ -4212,16 +4874,17 @@ unconfigure6(struct client_state *client, const char *reason)
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);
}
}
@@ -4367,7 +5030,7 @@ make_client6_options(struct client_state *client, struct option_state **op,
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,
@@ -4535,4 +5198,33 @@ script_write_params6(struct client_state *client, const char *prefix,
}
}
+/*
+ * 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 */
diff --git a/client/dhclient.8 b/client/dhclient.8
index fe68f6f4..21f7ed27 100644
--- a/client/dhclient.8
+++ b/client/dhclient.8
@@ -1,4 +1,4 @@
-.\" $Id: dhclient.8,v 1.27 2008/01/24 02:43:04 each Exp $
+.\" $Id: dhclient.8,v 1.28 2008/05/23 13:56:07 fdupont Exp $
.\"
.\" Copyright (c) 2004,2007-2008 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1996-2003 by Internet Software Consortium
@@ -35,6 +35,27 @@ dhclient - Dynamic Host Configuration Protocol Client
.B -6
]
[
+.B -S
+]
+[
+.B -N
+[
+.B -N...
+]
+]
+[
+.B -T
+[
+.B -T...
+]
+]
+[
+.B -P
+[
+.B -P...
+]
+]
+[
.B -p
.I port
]
@@ -53,8 +74,7 @@ dhclient - Dynamic Host Configuration Protocol Client
]
[
.B -r
-]
-[
+|
.B -x
]
[
@@ -123,7 +143,23 @@ DHCPv4 protocol to obtain an IPv4 address and configuration parameters.
.PP
If given the -6 command line argument, dhclient will use the DHCPv6
protocol to obtain whatever IPv6 addresses are available along with
-configuration parameters. Information-request is not yet supported.
+configuration parameters. But with
+.B -S
+it uses Information-request to get only (i.e., without address)
+stateless configuration parameters.
+.PP
+The default DHCPv6 behavior is modified too with
+.B -T
+which asks for IPv6 temporary addresses, one set per
+.B -T
+flag.
+.B -P
+enables the IPv6 prefix delegation.
+As temporary addresses or prefix delegation disables the normal
+address query,
+.B -N
+restores it. Note it is not recommended to mix queries of different types
+together, or even to share the lease file between them.
.PP
If given the --version command line argument, dhclient will print its
version number and exit.
@@ -198,6 +234,7 @@ the server transmit these messages to some other address. This can
be specified with the
.B -s
flag, followed by the IP address or domain name of the destination.
+This feature is not supported by DHCPv6.
.PP
For testing purposes, the giaddr field of all packets that the client
sends can be set using the
diff --git a/client/dhclient.c b/client/dhclient.c
index d4bc2c90..5674a341 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -44,7 +44,7 @@ TIME max_lease_time = 86400; /* 24 hours... */
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;
@@ -67,20 +67,23 @@ static char arr [] = "All rights reserved.";
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);
@@ -91,7 +94,7 @@ main(int argc, char **argv) {
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;
@@ -124,21 +127,21 @@ main(int argc, char **argv) {
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;
@@ -162,117 +165,160 @@ main(int argc, char **argv) {
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;
}
@@ -297,7 +343,7 @@ main(int argc, char **argv) {
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));
}
@@ -306,7 +352,7 @@ main(int argc, char **argv) {
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));
}
@@ -332,11 +378,11 @@ main(int argc, char **argv) {
}
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;
@@ -345,14 +391,14 @@ main(int argc, char **argv) {
/* 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);
}
}
}
@@ -363,13 +409,13 @@ main(int argc, char **argv) {
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;
@@ -382,52 +428,61 @@ main(int argc, char **argv) {
/* 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;
@@ -440,7 +495,7 @@ main(int argc, char **argv) {
"alias_",
ip->client->alias);
}
- script_go (ip->client);
+ script_go(ip->client);
}
}
@@ -448,9 +503,9 @@ main(int argc, char **argv) {
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
@@ -458,14 +513,14 @@ main(int argc, char **argv) {
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
@@ -543,18 +598,18 @@ main(int argc, char **argv) {
/* 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... */
@@ -563,8 +618,8 @@ main(int argc, char **argv) {
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;
@@ -573,41 +628,42 @@ main(int argc, char **argv) {
/* 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;
@@ -647,7 +703,7 @@ void run_stateless(int exit_mode)
/* 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",
@@ -664,8 +720,8 @@ void run_stateless(int exit_mode)
/* 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;
@@ -685,6 +741,7 @@ void run_stateless(int exit_mode)
dispatch();
/*NOTREACHED*/
+#endif /* DHCPv6 */
return;
}
@@ -766,20 +823,24 @@ void state_reboot (cpp)
/* 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);
@@ -809,8 +870,10 @@ void state_init (cpp)
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;
@@ -821,31 +884,39 @@ void state_selecting (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);
diff --git a/client/scripts/bsdos b/client/scripts/bsdos
index 12077f0c..7f858502 100755
--- a/client/scripts/bsdos
+++ b/client/scripts/bsdos
@@ -242,6 +242,12 @@ if [ ${reason} = PREINIT6 ] ; then
exit_with_hooks 0
fi
+if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then
+ echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}
+
+ exit_with_hooks 0
+fi
+
if [ ${reason} = BOUND6 ] ; then
if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
exit_with_hooks 2;
diff --git a/client/scripts/freebsd b/client/scripts/freebsd
index 67ff002e..ea8f5bb5 100755
--- a/client/scripts/freebsd
+++ b/client/scripts/freebsd
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# $Id: freebsd,v 1.21 2008/01/16 23:02:10 dhankins Exp $
+# $Id: freebsd,v 1.22 2008/05/23 13:56:07 fdupont Exp $
#
# $FreeBSD$
@@ -306,6 +306,12 @@ if [ ${reason} = PREINIT6 ] ; then
exit_with_hooks 0
fi
+if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then
+ echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}
+
+ exit_with_hooks 0
+fi
+
if [ ${reason} = BOUND6 ] ; then
if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
exit_with_hooks 2;
@@ -332,13 +338,11 @@ if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then
fi
if [ ${reason} = DEPREF6 ] ; then
- if [ x${new_ip6_prefixlen} = x ] ; then
+ if [ x${new_ip6_address} = x ] ; then
exit_with_hooks 2;
fi
- # XXX:
- # There doesn't appear to be a way to update an addr to indicate
- # preference.
+ ifconfig ${interface} inet6 ${new_ip6_address} deprecated
exit_with_hooks 0
fi
diff --git a/client/scripts/linux b/client/scripts/linux
index a0fcab55..49f0977d 100755
--- a/client/scripts/linux
+++ b/client/scripts/linux
@@ -243,6 +243,12 @@ if [ ${reason} = PREINIT6 ] ; then
exit_with_hooks 0
fi
+if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then
+ echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}
+
+ exit_with_hooks 0
+fi
+
if [ ${reason} = BOUND6 ] ; then
if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
exit_with_hooks 2;
@@ -274,10 +280,8 @@ if [ ${reason} = DEPREF6 ] ; then
exit_with_hooks 2;
fi
- # There doesn't appear to be a way to update an addr to indicate
- # preference.
-# ${ip} -f inet6 addr ??? ${new_ip6_address}/${new_ip6_prefixlen} \
-# dev ${interface} scope global deprecated?
+ ${ip} -f inet6 addr change ${new_ip6_address}/${new_ip6_prefixlen} \
+ dev ${interface} scope global preferred_lft 0
exit_with_hooks 0
fi
diff --git a/client/scripts/netbsd b/client/scripts/netbsd
index a5394796..7a26d28d 100755
--- a/client/scripts/netbsd
+++ b/client/scripts/netbsd
@@ -242,6 +242,12 @@ if [ ${reason} = PREINIT6 ] ; then
exit_with_hooks 0
fi
+if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then
+ echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}
+
+ exit_with_hooks 0
+fi
+
if [ ${reason} = BOUND6 ] ; then
if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
exit_with_hooks 2;
diff --git a/client/scripts/openbsd b/client/scripts/openbsd
index 1b8d7b02..182c7d6c 100644
--- a/client/scripts/openbsd
+++ b/client/scripts/openbsd
@@ -242,6 +242,12 @@ if [ ${reason} = PREINIT6 ] ; then
exit_with_hooks 0
fi
+if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then
+ echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}
+
+ exit_with_hooks 0
+fi
+
if [ ${reason} = BOUND6 ] ; then
if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then
exit_with_hooks 2;