[PATCH RFC v2 1/3] dhclient: IPv6: factor common code in dhc6.c
H. Peter Anvin
hpa at zytor.com
Wed Dec 2 19:21:15 UTC 2015
Factor a number of common code idioms into functions, rather than
replicating the code in several places.
Signed-off-by: H. Peter Anvin <hpa at zytor.com>
---
client/dhc6.c | 1054 +++++++++++++++++++++------------------------------------
1 file changed, 394 insertions(+), 660 deletions(-)
diff --git a/client/dhc6.c b/client/dhc6.c
index 37ce739460ff..8f77fafd7281 100644
--- a/client/dhc6.c
+++ b/client/dhc6.c
@@ -74,22 +74,39 @@ static struct dhc6_addr *find_pref(struct dhc6_addr *head,
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);
+static void dhc6_new_iaid(unsigned char iaid[4],
+ const struct client_state *client, int i);
void do_init6(void *input);
void do_info_request6(void *input);
void do_confirm6(void *input);
void reply_handler(struct packet *packet, struct client_state *client);
-static isc_result_t dhc6_add_ia_na(struct client_state *client,
- 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_na_ta(struct client_state *client,
+ struct data_string *packet,
+ struct option *option,
+ struct dhc6_lease *lease,
+ u_int8_t message);
+static isc_result_t dhc6_make_ia_na_ta(const struct client_state *client,
+ struct data_string *packet,
+ struct option *option,
+ const struct dhc6_addr *addr,
+ const unsigned char iaid[4],
+ u_int8_t message);
+static isc_result_t dhc6_make_iaaddr(struct data_string *iads,
+ const struct dhc6_addr *old_addr,
+ TIME t1, TIME t2);
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_result_t dhc6_make_ia_pd(const struct client_state *client,
+ struct data_string *packet,
+ const struct dhc6_addr *pref,
+ const unsigned char iaid[4],
+ u_int8_t message);
+static isc_result_t dhc6_make_iaprefix(struct data_string *ia,
+ const struct dhc6_addr *old_addr,
+ TIME t1, TIME t2);
+static void putTimes(unsigned char *, TIME t1, TIME t2);
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);
@@ -1496,6 +1513,26 @@ check_timing6 (struct client_state *client, u_int8_t msg_type,
return(CHK_TIM_SUCCESS);
}
+static void
+dhc6_new_iaid(unsigned char iaid[4], const struct client_state *client, int i)
+{
+ int idx, len;
+
+ /*
+ * 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;
+ }
+ memset(iaid, 0, 4);
+ memcpy(iaid, client->interface->hw_address.hbuf + idx, len);
+ iaid[3] += i;
+}
+
/*
* do_init6() marshals and transmits a solicit.
*/
@@ -1506,11 +1543,9 @@ do_init6(void *input)
struct dhc6_ia *old_ia;
struct dhc6_addr *old_addr;
struct data_string ds;
- struct data_string ia;
- struct data_string addr;
struct timeval tv;
- u_int32_t t1, t2;
- int i, idx, len, send_ret;
+ unsigned char iaid[4];
+ int i, send_ret;
client = input;
@@ -1559,100 +1594,20 @@ do_init6(void *input)
* 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);
- 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);
+ dhc6_new_iaid(iaid, client, i);
+ old_addr = NULL;
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;
- }
+ D6O_IA_NA, (char *)iaid)) != NULL))
+ old_addr = old_ia->addrs;
- 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);
- }
+ if (dhc6_make_ia_na_ta(client, &ds, ia_na_option,
+ old_addr, iaid,
+ DHCPV6_SOLICIT) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
}
-
- append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
- data_string_forget(&ia, MDL);
}
/* Append IA_TA. */
@@ -1662,93 +1617,20 @@ do_init6(void *input)
* 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;
-
- /*
- * 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));
+ dhc6_new_iaid(iaid, client, i);
+ old_addr = NULL;
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;
- }
+ D6O_IA_TA, (char *)iaid)) != NULL))
+ old_addr = old_ia->addrs;
- 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);
- }
+ if (dhc6_make_ia_na_ta(client, &ds, ia_ta_option,
+ old_addr, iaid,
+ DHCPV6_SOLICIT) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
}
-
- append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia);
- data_string_forget(&ia, MDL);
}
/* Append IA_PD. */
@@ -1758,101 +1640,20 @@ do_init6(void *input)
* 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);
+ dhc6_new_iaid(iaid, client, i);
+ old_addr = NULL;
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;
- }
+ D6O_IA_PD, (char *)iaid)) != NULL))
+ old_addr = old_ia->addrs;
- 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);
- }
+ if (dhc6_make_ia_pd(client, &ds, old_addr, iaid,
+ DHCPV6_SOLICIT) != ISC_R_SUCCESS) {
+ data_string_forget(&ds, MDL);
+ return;
}
-
- append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia);
- data_string_forget(&ia, MDL);
}
/* Transmit and wait. */
@@ -1987,13 +1788,13 @@ do_confirm6(void *input)
/* Append IA's. */
if (wanted_ia_na &&
- dhc6_add_ia_na(client, &ds, client->active_lease,
- DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
+ dhc6_add_ia_na_ta(client, &ds, ia_na_option, 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,
+ dhc6_add_ia_na_ta(client, &ds, ia_ta_option, client->active_lease,
DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
return;
@@ -2100,8 +1901,9 @@ do_release6(void *input)
/* 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) {
+ dhc6_add_ia_na_ta(client, &ds, ia_na_option,
+ client->active_lease,
+ DHCPV6_RELEASE) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
goto release_done;
}
@@ -3195,14 +2997,14 @@ do_select6(void *input)
/* Now append any IA's, and within them any IAADDR/IAPREFIXs. */
if (wanted_ia_na &&
- dhc6_add_ia_na(client, &ds, lease,
- DHCPV6_REQUEST) != ISC_R_SUCCESS) {
+ dhc6_add_ia_na_ta(client, &ds, ia_na_option, 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) {
+ dhc6_add_ia_na_ta(client, &ds, ia_ta_option, lease,
+ DHCPV6_REQUEST) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
return;
}
@@ -3238,78 +3040,124 @@ do_select6(void *input)
dhc6_retrans_advance(client);
}
-/* For each IA_NA in the lease, for each address in the IA_NA,
+/* For each IA_NA/IA_TA in the lease, for each address in the IA_NA/IA_TA,
* append that information onto the packet-so-far.
*/
static isc_result_t
-dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
- struct dhc6_lease *lease, u_int8_t message)
+dhc6_add_ia_na_ta(struct client_state *client, struct data_string *packet,
+ struct option *option,
+ 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_NA)
+ for (ia = lease->bindings; ia != NULL; ia = ia->next) {
+ if (ia->ia_type != option->code)
continue;
- if (!buffer_allocate(&iads.buffer, 12, MDL)) {
- log_error("Unable to allocate memory for IA_NA.");
- rval = ISC_R_NOMEMORY;
+ rval = dhc6_make_ia_na_ta(client, packet, option,
+ ia->addrs, ia->iaid, message);
+ if (rval != ISC_R_SUCCESS)
break;
- }
+ }
- /* Copy the IAID into the packet buffer. */
- memcpy(iads.buffer->data, ia->iaid, 4);
- iads.data = iads.buffer->data;
- iads.len = 12;
+ return rval;
+}
- switch (message) {
- case DHCPV6_REQUEST:
- case DHCPV6_RENEW:
- case DHCPV6_REBIND:
+/* Build an IA_NA or IA_TA option to add to a packet */
+static isc_result_t
+dhc6_make_ia_na_ta(const struct client_state *client,
+ struct data_string *packet,
+ struct option *option,
+ const struct dhc6_addr *addr,
+ const unsigned char iaid[4],
+ u_int8_t message)
+{
+ TIME t1, t2;
+ struct data_string iads;
+ int addr_count;
+ isc_result_t rval = ISC_R_SUCCESS;
+ const char *name;
- 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_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;
+ switch (option->code) {
+ case D6O_IA_NA:
+ name = "IA_NA";
+ break;
+ case D6O_IA_TA:
+ name = "IA_TA";
+ break;
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
+
+ memset(&iads, 0, sizeof(iads));
+ if (!buffer_allocate(&iads.buffer, 12, MDL)) {
+ log_error("Unable to allocate memory for %s.", name);
+ return ISC_R_NOMEMORY;
+ }
+
+ /* Copy the IAID into the packet buffer. */
+ memcpy(&iads.buffer->data, iaid, 4);
+ iads.data = iads.buffer->data;
+ iads.len = 12;
+
+ /* Times for the IA_NA/IA_TA options */
+ switch (message) {
+ case DHCPV6_SOLICIT:
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease / 2;
+ t2 = t1 + (t1 / 2);
+ 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));
+ case DHCPV6_CONFIRM:
+ case DHCPV6_RELEASE:
+ case DHCPV6_DECLINE:
+ /* Set t1 and t2 to zero; server will ignore them */
+ t1 = t2 = 0;
+ break;
- break;
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
+ putTimes(iads.buffer->data + 4, t1, t2);
- default:
- log_fatal("Impossible condition at %s:%d.", MDL);
- }
+ log_debug("XMT: X-- %s %s", option->name,
+ print_hex_1(4, iads.buffer->data, 55));
+ if (t1 || t2) {
+ log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
+ log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
+ }
- for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
+ /* Times for the IAADDR options */
+ switch (message) {
+ case DHCPV6_SOLICIT:
+ t1 = client->config->requested_lease;
+ t2 = t1 + (t1 / 2);
+ break;
+
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease;
+ t2 = t1 + 300;
+ break;
+
+ case DHCPV6_CONFIRM:
+ case DHCPV6_RELEASE:
+ case DHCPV6_DECLINE:
+ /* Set t1 and t2 to zero; server will ignore them */
+ t1 = t2 = 0;
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
+
+ addr_count = 0;
+ for (; addr; addr = addr->next) {
+ if (message != DHCPV6_SOLICIT) {
/*
* Do not confirm expired addresses, do not request
* expired addresses (but we keep them around for
@@ -3317,299 +3165,178 @@ dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
*/
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 (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;
- }
+ rval = dhc6_make_iaaddr(&iads, addr, t1, t2);
+ if (rval != ISC_R_SUCCESS)
+ goto fail;
- 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);
+ addr_count++;
+ }
- break;
+ if (message != DHCPV6_SOLICIT && !addr_count) {
+ log_debug("!!!: V %s has no IAADDRs - removed.", name);
+ rval = ISC_R_FAILURE;
+ goto fail;
+ }
- 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;
+ append_option(packet, &dhcpv6_universe, option, &iads);
- 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;
+fail:
+ data_string_forget(&iads, MDL);
+ return rval;
+}
- 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;
+/* Build an IAPREFIX suboption to add to an IA_NA or IA_TA option
+ */
+static isc_result_t
+dhc6_make_iaaddr(struct data_string *iads,
+ const struct dhc6_addr *old_addr,
+ TIME t1, TIME t2)
+{
+ struct data_string addr;
- default:
- log_fatal("Impossible condition at %s:%d.",
- MDL);
- }
+ memset(&addr, 0, sizeof addr);
+ if (!buffer_allocate(&addr.buffer, 24, MDL)) {
+ log_error("Unable to allocate memory "
+ "for IAADDR.");
+ return ISC_R_NOMEMORY;
+ }
- append_option(&iads, &dhcpv6_universe, iaaddr_option,
- &addrds);
- data_string_forget(&addrds, MDL);
- }
+ addr.data = addr.buffer->data;
+ addr.len = 24;
- /*
- * It doesn't make sense to make a request without an
- * address.
- */
- if (ia->addrs == NULL) {
- log_debug("!!!: V IA_NA has no IAADDRs - removed.");
- rval = ISC_R_FAILURE;
- } else if (rval == ISC_R_SUCCESS) {
- log_debug("XMT: V IA_NA appended.");
- append_option(packet, &dhcpv6_universe, ia_na_option,
- &iads);
- }
+ memcpy(addr.buffer->data,
+ old_addr->address.iabuf,
+ 16);
- data_string_forget(&iads, MDL);
+ putTimes(addr.buffer->data + 16, t1, t2);
+
+ log_debug("XMT: | X-- %s address %s.",
+ t1 ? "Request" : "Release",
+ piaddr(old_addr->address));
+ if (t1 || t2) {
+ log_debug("XMT: | | X-- Request preferred in +%u",
+ (unsigned)t1);
+ log_debug("XMT: | | X-- Request valid in +%u",
+ (unsigned)t2);
}
- return rval;
+ append_option(iads, &dhcpv6_universe, iaaddr_option, &addr);
+ data_string_forget(&addr, MDL);
+
+ return ISC_R_SUCCESS;
}
-/* For each IA_TA in the lease, for each address in the IA_TA,
+/* 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_ta(struct client_state *client, struct data_string *packet,
+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 addrds;
- struct dhc6_addr *addr;
- struct dhc6_ia *ia;
+ const 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)
+ for (ia = lease->bindings; ia != NULL; ia = ia->next) {
+ if (ia->ia_type != D6O_IA_PD)
continue;
- if (!buffer_allocate(&iads.buffer, 4, MDL)) {
- log_error("Unable to allocate memory for IA_TA.");
- rval = ISC_R_NOMEMORY;
+ rval = dhc6_make_ia_pd(client, packet,
+ ia->addrs, ia->iaid, message);
+ if (rval != ISC_R_SUCCESS)
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.
+/* Build an IA_PD option to add to a packet
*/
static isc_result_t
-dhc6_add_ia_pd(struct client_state *client, struct data_string *packet,
- struct dhc6_lease *lease, u_int8_t message)
+dhc6_make_ia_pd(const struct client_state *client,
+ struct data_string *packet,
+ const struct dhc6_addr *pref,
+ const unsigned char iaid[4],
+ u_int8_t message)
{
+ TIME t1, t2;
struct data_string iads;
- struct data_string prefds;
- struct dhc6_addr *pref;
- struct dhc6_ia *ia;
+ int pfx_count;
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;
+ memset(&iads, 0, sizeof iads);
+ if (!buffer_allocate(&iads.buffer, 12, MDL)) {
+ log_error("Unable to allocate memory for IA_PD.");
+ return ISC_R_NOMEMORY;
+ }
- 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, iaid, 4);
+ iads.data = iads.buffer->data;
+ iads.len = 12;
- /* Copy the IAID into the packet buffer. */
- memcpy(iads.buffer->data, ia->iaid, 4);
- iads.data = iads.buffer->data;
- iads.len = 12;
+ /* Times for the IA_PD option */
+ switch (message) {
+ case DHCPV6_SOLICIT:
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease / 2;
+ t2 = t1 + (t1 / 2);
+ break;
- switch (message) {
- case DHCPV6_REQUEST:
- case DHCPV6_RENEW:
- case DHCPV6_REBIND:
+ case DHCPV6_RELEASE:
+ /* Set t1 and t2 to zero; server will ignore them */
+ t1 = t2 = 0;
+ break;
- 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;
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
- 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));
+ putTimes(iads.buffer->data + 4, t1, t2);
- break;
+ log_debug("XMT: X-- IA_PD %s", print_hex_1(4, iads.data, 55));
+ if (t1 || t2) {
+ log_debug("XMT: | X-- Requested renew +%u", (unsigned) t1);
+ log_debug("XMT: | X-- Requested rebind +%u", (unsigned) t2);
+ }
- default:
- log_fatal("Impossible condition at %s:%d.", MDL);
- }
+ /* Times for the IAPREFIX options */
+ switch (message) {
+ case DHCPV6_SOLICIT:
+ t1 = client->config->requested_lease;
+ t2 = t1 + (t1 / 2);
+ break;
+
+ case DHCPV6_REQUEST:
+ case DHCPV6_RENEW:
+ case DHCPV6_REBIND:
+ t1 = client->config->requested_lease;
+ t2 = t1 + 300;
+ break;
+
+ case DHCPV6_RELEASE:
+ /* Preferred and max life are irrelevant */
+ t1 = t2 = 0;
+ break;
+
+ default:
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ }
- for (pref = ia->addrs ; pref != NULL ; pref = pref->next) {
+ pfx_count = 0;
+
+ for (; pref; pref = pref->next) {
+ if (message != DHCPV6_SOLICIT) {
/*
* Do not confirm expired prefixes, do not request
* expired prefixes (but we keep them around for
@@ -3617,93 +3344,100 @@ dhc6_add_ia_pd(struct client_state *client, struct data_string *packet,
*/
if (pref->flags & DHC6_ADDR_EXPIRED)
continue;
+ }
- if (pref->address.len != 16) {
- log_error("Illegal IPv6 prefix "
- "ignoring. (%s:%d)",
- MDL);
- 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 (pref->plen == 0) {
+ log_info("Null IPv6 prefix, ignoring. (%s:%d)",
+ MDL);
+ continue;
+ }
- if (!buffer_allocate(&prefds.buffer, 25, MDL)) {
- log_error("Unable to allocate memory for "
- "IAPREFIX.");
- rval = ISC_R_NOMEMORY;
- break;
- }
+ rval = dhc6_make_iaprefix(&iads, pref, t1, t2);
+ if (rval != ISC_R_SUCCESS)
+ goto fail;
- 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);
+ pfx_count++;
+ }
- break;
+ /*
+ * It doesn't make sense to make a request without any
+ * address, except in a solicitation.
+ */
+ if (message != DHCPV6_SOLICIT && !pfx_count) {
+ log_debug("!!!: V IA_PD has no IAPREFIXs - removed.");
+ rval = ISC_R_FAILURE;
+ goto fail;
+ }
- 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;
+ log_debug("XMT: V IA_PD appended.");
+ append_option(packet, &dhcpv6_universe, ia_pd_option, &iads);
- default:
- log_fatal("Impossible condition at %s:%d.",
- MDL);
- }
+fail:
+ data_string_forget(&iads, MDL);
+ return rval;
+}
- append_option(&iads, &dhcpv6_universe,
- iaprefix_option, &prefds);
- data_string_forget(&prefds, MDL);
- }
+/* Build an IAPREFIX suboption to add to an IA_PD option
+ */
+static isc_result_t
+dhc6_make_iaprefix(struct data_string *iads,
+ const struct dhc6_addr *old_addr,
+ TIME t1, TIME t2)
+{
+ struct data_string addr;
- /*
- * 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);
- }
+ memset(&addr, 0, sizeof addr);
+ if (!buffer_allocate(&addr.buffer, 25, MDL)) {
+ log_error("Unable to allocate memory for IAPREFIX.");
+ return ISC_R_NOMEMORY;
+ }
+
+ addr.data = addr.buffer->data;
+ addr.len = 25;
+
+ putTimes(addr.buffer->data, t1, t2);
- data_string_forget(&iads, MDL);
+ putUChar(addr.buffer->data + 8, old_addr->plen);
+ memcpy(addr.buffer->data + 9, old_addr->address.iabuf, 16);
+
+ log_debug("XMT: | X-- %s prefix %s/%u.",
+ t1 ? "Request" : "Release",
+ piaddr(old_addr->address), (unsigned) old_addr->plen);
+ if (t1 || t2) {
+ log_debug("XMT: | | X-- Request preferred in +%u",
+ (unsigned)t1);
+ log_debug("XMT: | | X-- Request valid in +%u",
+ (unsigned)t2);
}
- return rval;
+ append_option(iads, &dhcpv6_universe, iaprefix_option, &addr);
+
+ data_string_forget(&addr, MDL);
+ return ISC_R_SUCCESS;
}
+/* Write a pair of times, with capping.
+ */
+static void
+putTimes(unsigned char *buf, TIME t1, TIME t2)
+{
+#if MAX_TIME > 0xffffffff
+ if (t1 > 0xffffffff)
+ t1 = 0xffffffff;
+ if (t2 > 0xffffffff)
+ t2 = 0xffffffff;
+#endif
+ putULong(buf, t1);
+ putULong(buf + 4, t2);
+}
+
+
/* stopping_finished() checks if there is a remaining work to do.
*/
static isc_boolean_t
@@ -4517,8 +4251,8 @@ do_refresh6(void *input)
/* Append IA's */
if (wanted_ia_na &&
- dhc6_add_ia_na(client, &ds, lease,
- client->refresh_type) != ISC_R_SUCCESS) {
+ dhc6_add_ia_na_ta(client, &ds, ia_na_option, lease,
+ client->refresh_type) != ISC_R_SUCCESS) {
data_string_forget(&ds, MDL);
return;
}
--
2.4.3
More information about the dhcp-workers
mailing list