2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-29 13:28:14 +00:00

- A bug was fixed where the DHCPv6 server puts the NoAddrsAvail status

code in the IA_NA was fixed.  The status code now appears in the root
  level.  [ISC-Bugs #17316b]
This commit is contained in:
David Hankins 2007-12-06 00:08:44 +00:00
parent b9137d42af
commit 9f1d5a2f4c
2 changed files with 178 additions and 57 deletions

View File

@ -98,6 +98,10 @@ suggested fixes to <dhcp-users@isc.org>.
response to a SOLICIT but would not return the address in response response to a SOLICIT but would not return the address in response
to a REQUEST. to a REQUEST.
- A bug was fixed where the DHCPv6 server puts the NoAddrsAvail status
code in the IA_NA was fixed. The status code now appears in the root
level.
Changes since 4.0.0b2 Changes since 4.0.0b2
- Clarified error message when lease limit exceeded - Clarified error message when lease limit exceeded

View File

@ -50,6 +50,7 @@ struct reply_state {
/* IA level persistent state */ /* IA level persistent state */
unsigned ia_count; unsigned ia_count;
unsigned client_addresses; unsigned client_addresses;
isc_boolean_t ia_addrs_included;
isc_boolean_t static_lease; isc_boolean_t static_lease;
struct ia_na *ia_na; struct ia_na *ia_na;
struct ia_na *old_ia; struct ia_na *old_ia;
@ -1031,6 +1032,7 @@ lease_to_client(struct data_string *reply_ret,
static struct reply_state reply; static struct reply_state reply;
struct option_cache *oc; struct option_cache *oc;
struct data_string packet_oro; struct data_string packet_oro;
isc_boolean_t no_addrs_avail;
/* Locate the client. */ /* Locate the client. */
if (shared_network_from_packet6(&reply.shared, if (shared_network_from_packet6(&reply.shared,
@ -1082,10 +1084,30 @@ lease_to_client(struct data_string *reply_ret,
/* Process the client supplied IA_NA's onto the reply buffer. */ /* Process the client supplied IA_NA's onto the reply buffer. */
reply.ia_count = 0; reply.ia_count = 0;
oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA); oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
no_addrs_avail = ISC_FALSE;
for (; oc != NULL ; oc = oc->next) { for (; oc != NULL ; oc = oc->next) {
if (reply_process_ia(&reply, oc) != ISC_R_SUCCESS) { isc_result_t status;
/* Start counting addresses offered. */
reply.client_addresses = 0;
reply.ia_addrs_included = ISC_FALSE;
status = reply_process_ia(&reply, oc);
/*
* We continue to try other IA's whether we can address
* this one or not. Any other result is an immediate fail.
*/
if ((status != ISC_R_SUCCESS) &&
(status != ISC_R_NORESOURCES))
goto exit; goto exit;
}
/*
* If any address can be given to any IA, then do not set the
* NoAddrsAvail status code.
*/
if (reply.client_addresses == 0)
no_addrs_avail = ISC_TRUE;
} }
/* /*
@ -1094,16 +1116,94 @@ lease_to_client(struct data_string *reply_ret,
*/ */
if ((reply.ia_count == 0) && if ((reply.ia_count == 0) &&
(packet->dhcpv6_msg_type != DHCPV6_INFORMATION_REQUEST)) (packet->dhcpv6_msg_type != DHCPV6_INFORMATION_REQUEST))
goto exit; goto exit;
/* /*
* Having stored the client's IA_NA's, store any options that will * RFC3315 section 17.2.2 (Solicit):
* fit in the remaining space. *
* If the server will not assign any addresses to any IAs in a
* subsequent Request from the client, the server MUST send an
* Advertise message to the client that includes only a Status
* Code option with code NoAddrsAvail and a status message for
* the user, a Server Identifier option with the server's DUID,
* and a Client Identifier option with the client's DUID.
*
* Section 18.2.1 (Request):
*
* If the server cannot assign any addresses to an IA in the
* message from the client, the server MUST include the IA in
* the Reply message with no addresses in the IA and a Status
* Code option in the IA containing status code NoAddrsAvail.
*
* Section 18.2.3 (Renew):
*
* The server may choose to change the list of addresses and
* the lifetimes of addresses in IAs that are returned to the
* client.
*
* Section 18.2.4 (Rebind):
*
* Absolutely nothing.
*
* INTERPRETATION;
*
* Solicit and Request are fairly explicit; we send NoAddrsAvail.
* We handle SOLICIT here and REQUEST in the reply_process_ia()
* function (because SOLICIT only counts if we never get around to
* it).
*
* Renew and Rebind are totally undefined. If we send a reply with
* empty IA's, however, the client will stop renewing or rebinding,
* and this is a problem if they could have gotten addressed from
* another server. So we ignore client packets...they will eventually
* time out in the worst case.
*/ */
reply.cursor += store_options6((char *)reply.buf.data + reply.cursor, if (no_addrs_avail &&
sizeof(reply.buf) - reply.cursor, (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
reply.opt_state, reply.packet, {
required_opts_solicit, &packet_oro); /* Set the NoAddrsAvail status code. */
if (!set_status_code(STATUS_NoAddrsAvail,
"No addresses available for this "
"interface.", reply.opt_state)) {
log_error("lease_to_client: Unable to set "
"NoAddrsAvail status code.");
goto exit;
}
/* Rewind the cursor to the start. */
reply.cursor = REPLY_OPTIONS_INDEX;
/*
* Produce a reply that includes;
*
* Status code.
* Server DUID.
* Client DUID.
*/
reply.cursor += store_options6((char *)reply.buf.data +
reply.cursor,
sizeof(reply.buf) -
reply.cursor,
reply.opt_state, reply.packet,
required_opts,
NULL);
} else if (no_addrs_avail &&
(reply.packet->dhcpv6_msg_type != DHCPV6_REQUEST))
{
goto exit;
} else {
/*
* Having stored the client's IA_NA's, store any options that
* will fit in the remaining space.
*/
reply.cursor += store_options6((char *)reply.buf.data +
reply.cursor,
sizeof(reply.buf) -
reply.cursor,
reply.opt_state, reply.packet,
required_opts_solicit,
&packet_oro);
}
/* Return our reply to the caller. */ /* Return our reply to the caller. */
reply_ret->len = reply.cursor; reply_ret->len = reply.cursor;
@ -1250,7 +1350,6 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) {
oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR); oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
reply->valid = reply->prefer = 0xffffffff; reply->valid = reply->prefer = 0xffffffff;
reply->client_valid = reply->client_prefer = 0; reply->client_valid = reply->client_prefer = 0;
reply->client_addresses = 0;
for (; oc != NULL ; oc = oc->next) { for (; oc != NULL ; oc = oc->next) {
status = reply_process_addr(reply, oc); status = reply_process_addr(reply, oc);
@ -1276,60 +1375,76 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) {
if ((status != ISC_R_CANCELED) && (reply->client_addresses == 0)) { if ((status != ISC_R_CANCELED) && (reply->client_addresses == 0)) {
status = find_client_address(reply); status = find_client_address(reply);
/* if (status == ISC_R_NORESOURCES) {
* RFC3315 section 17.2.2 (Solicit): switch (reply->packet->dhcpv6_msg_type) {
* case DHCPV6_SOLICIT:
* If the server will not assign any addresses to any IAs in a /*
* subsequent Request from the client, the server MUST send an * Solicit is handled by the caller, because
* Advertise message to the client that includes only a Status * it has to be the sum of all the IA's.
* Code option with code NoAddrsAvail and a status message for */
* the user, a Server Identifier option with the server's DUID, goto cleanup;
* and a Client Identifier option with the client's DUID.
* case DHCPV6_REQUEST:
* Section 18.2.1 (Request): /* Section 18.2.1 (Request):
* *
* If the server cannot assign any addresses to an IA in the * If the server cannot assign any addresses to
* message from the client, the server MUST include the IA in * an IA in the message from the client, the
* the Reply message with no addresses in the IA and a Status * server MUST include the IA in the Reply
* Code option in the IA containing status code NoAddrsAvail. * message with no addresses in the IA and a
* * Status Code option in the IA containing
* Section 18.2.3 (Renew): * status code NoAddrsAvail.
* */
* The server may choose to change the list of addresses and
* the lifetimes of addresses in IAs that are returned to the
* client.
*
* Section 18.2.4 (Rebind):
*
* Absolutely nothing. Interpretation: Only address the
* client if its old binding can be found.
*/
if ((status == ISC_R_NORESOURCES) &&
(reply->packet->dhcpv6_msg_type != DHCPV6_REBIND)) {
/* If this is not a Renew, clear all IAADDRs. */
if (reply->packet->dhcpv6_msg_type != DHCPV6_RENEW) {
option_state_dereference(&reply->reply_ia, MDL); option_state_dereference(&reply->reply_ia, MDL);
if (!option_state_allocate(&reply->reply_ia, if (!option_state_allocate(&reply->reply_ia,
MDL)) { MDL))
log_error("reply_process_ia: No memory " {
"for option state wipe."); log_error("reply_process_ia: No "
"memory for option state "
"wipe.");
status = ISC_R_NOMEMORY; status = ISC_R_NOMEMORY;
goto cleanup; goto cleanup;
} }
}
/* Set the status code. */ if (!set_status_code(STATUS_NoAddrsAvail,
if (!set_status_code(STATUS_NoAddrsAvail, "No addresses available "
"No addresses available " "for this interface.",
"for this interface.", reply->reply_ia)) {
reply->reply_ia)) { log_error("reply_process_ia: Unable "
log_error("reply_process_ia: Unable to set " "to set NoAddrsAvail status "
"NoAddrsAvail status code."); "code.");
status = ISC_R_FAILURE; status = ISC_R_FAILURE;
goto cleanup; goto cleanup;
} }
status = ISC_R_SUCCESS; status = ISC_R_SUCCESS;
break;
default:
/*
* RFC 3315 does not tell us to emit a status
* code in this condition, or anything else.
*
* If we included non-allocated addresses
* (zeroed lifetimes) in an IA, then the client
* will deconfigure them.
*
* So we want to include the IA even if we
* can't give it a new address if it includes
* zeroed lifetime addresses.
*
* We don't want to include the IA if we
* provide zero addresses including zeroed
* lifetimes...if we did, the client would
* reset its renew/rebind behaviour. If we do
* not, the client may get a success off
* another server.
*/
if (reply->ia_addrs_included)
status = ISC_R_SUCCESS;
else
goto cleanup;
break;
}
} }
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
@ -2091,6 +2206,8 @@ reply_process_send_addr(struct reply_state *reply, struct iaddr *addr) {
goto cleanup; goto cleanup;
} }
reply->ia_addrs_included = ISC_TRUE;
cleanup: cleanup:
if (data.data != NULL) if (data.data != NULL)
data_string_forget(&data, MDL); data_string_forget(&data, MDL);