]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
- A bug was fixed where the DHCPv6 server puts the NoAddrsAvail status
authorDavid Hankins <dhankins@isc.org>
Thu, 6 Dec 2007 00:08:44 +0000 (00:08 +0000)
committerDavid Hankins <dhankins@isc.org>
Thu, 6 Dec 2007 00:08:44 +0000 (00:08 +0000)
  code in the IA_NA was fixed.  The status code now appears in the root
  level.  [ISC-Bugs #17316b]

RELNOTES
server/dhcpv6.c

index 40a3897fafe3d34c54f784706001b3c2d66ec923..bdce411ff470dfa67d39ec7b1498e2e79daae7c6 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -98,6 +98,10 @@ suggested fixes to <dhcp-users@isc.org>.
   response to a SOLICIT but would not return the address in response 
   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
 
 - Clarified error message when lease limit exceeded
index 69c3f6d11af1bc4464d19315252ae693b11ae208..f0b6df082708020e55c9bc61739ca8e10fdb603c 100644 (file)
@@ -50,6 +50,7 @@ struct reply_state {
        /* IA level persistent state */
        unsigned ia_count;
        unsigned client_addresses;
+       isc_boolean_t ia_addrs_included;
        isc_boolean_t static_lease;
        struct ia_na *ia_na;
        struct ia_na *old_ia;
@@ -1031,6 +1032,7 @@ lease_to_client(struct data_string *reply_ret,
        static struct reply_state reply;
        struct option_cache *oc;
        struct data_string packet_oro;
+       isc_boolean_t no_addrs_avail;
 
        /* Locate the client.  */
        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. */
        reply.ia_count = 0;
        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
+       no_addrs_avail = ISC_FALSE;
        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;
-               }
+
+               /*
+                * 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) &&
            (packet->dhcpv6_msg_type != DHCPV6_INFORMATION_REQUEST))
-               goto exit;
+               goto exit;
 
        /*
-        * 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);
+        * RFC3315 section 17.2.2 (Solicit):
+        *
+        * 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.
+        */
+       if (no_addrs_avail &&
+           (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+       {
+               /* 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. */
        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);
        reply->valid = reply->prefer = 0xffffffff;
        reply->client_valid = reply->client_prefer = 0;
-       reply->client_addresses = 0;
        for (; oc != NULL ; oc = oc->next) {
                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)) {
                status = find_client_address(reply);
 
-               /*
-                * RFC3315 section 17.2.2 (Solicit):
-                *
-                * 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:  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) {
+               if (status == ISC_R_NORESOURCES) {
+                       switch (reply->packet->dhcpv6_msg_type) {
+                             case DHCPV6_SOLICIT:
+                               /*
+                                * Solicit is handled by the caller, because
+                                * it has to be the sum of all the IA's.
+                                */
+                               goto cleanup;
+
+                             case DHCPV6_REQUEST:
+                               /* 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.
+                                */
                                option_state_dereference(&reply->reply_ia, MDL);
                                if (!option_state_allocate(&reply->reply_ia,
-                                                         MDL)) {
-                                       log_error("reply_process_ia: No memory "
-                                                 "for option state wipe.");
+                                                          MDL))
+                               {
+                                       log_error("reply_process_ia: No "
+                                                 "memory for option state "
+                                                 "wipe.");
                                        status = ISC_R_NOMEMORY;
                                        goto cleanup;
                                }
-                       }
 
-                       /* Set the status code. */
-                       if (!set_status_code(STATUS_NoAddrsAvail,
-                                            "No addresses available "
-                                            "for this interface.",
-                                            reply->reply_ia)) {
-                               log_error("reply_process_ia: Unable to set "
-                                         "NoAddrsAvail status code.");
-                               status = ISC_R_FAILURE;
-                               goto cleanup;
-                       }
+                               if (!set_status_code(STATUS_NoAddrsAvail,
+                                                    "No addresses available "
+                                                    "for this interface.",
+                                                     reply->reply_ia)) {
+                                       log_error("reply_process_ia: Unable "
+                                                 "to set NoAddrsAvail status "
+                                                 "code.");
+                                       status = ISC_R_FAILURE;
+                                       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)
@@ -2091,6 +2206,8 @@ reply_process_send_addr(struct reply_state *reply, struct iaddr *addr) {
                goto cleanup;
        }
 
+       reply->ia_addrs_included = ISC_TRUE;
+
       cleanup:
        if (data.data != NULL)
                data_string_forget(&data, MDL);