]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Insure we let people Request addresses that we suggested in Advertise.
authorShane Kerr <shane@isc.org>
Thu, 6 Dec 2007 00:07:12 +0000 (00:07 +0000)
committerShane Kerr <shane@isc.org>
Thu, 6 Dec 2007 00:07:12 +0000 (00:07 +0000)
See RT ticket #17302 for more.

RELNOTES
includes/dhcpd.h
includes/tree.h
server/dhcpv6.c
server/mdb6.c

index dd71a851c3a1f03bf01b64e258a89b631827bcdd..40a3897fafe3d34c54f784706001b3c2d66ec923 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -94,6 +94,10 @@ suggested fixes to <dhcp-users@isc.org>.
   to put dhcpd.leases and dhclient.leases in /usr/local/var/db, which no
   one ever has.
 
+- Regression fix for bug where server advertised a IPv6 address in 
+  response to a SOLICIT but would not return the address in response 
+  to a REQUEST.
+
                        Changes since 4.0.0b2
 
 - Clarified error message when lease limit exceeded
index 3d380653228ec831a111161aaf0c16b61ec806d6..a426d9ecb8677dfa85b1710538c5f6cd70d79dff 100644 (file)
@@ -3184,6 +3184,7 @@ isc_result_t ia_na_add_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr,
                              const char *file, int line);
 void ia_na_remove_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr,
                         const char *file, int line);
+isc_boolean_t ia_na_equal(const struct ia_na *a, const struct ia_na *b);
 
 isc_result_t ipv6_pool_allocate(struct ipv6_pool **pool,
                                const struct in6_addr *start_addr, int bits, 
index 8171ce1bbfbd4ee0a67b4ed41021cc1d34a37a3e..ef8f3bafe1503a643c84d35ab13234a247cbe37a 100644 (file)
@@ -75,6 +75,8 @@ struct buffer {
    XXX ephemeral by default and be made a persistent reference explicitly. */
 /* XXX on the other hand, it seems to work pretty nicely, so maybe the
    XXX above comment is meshuggenah. */
+/* XXX I think the above comment tries to say this: 
+   XXX    http://tinyurl.com/2tjqre */
 
 /* A string of data bytes, possibly accompanied by a larger buffer. */
 struct data_string {
index ac59b284863402dab5d02c48f73c79ec05ae317e..69c3f6d11af1bc4464d19315252ae693b11ae208 100644 (file)
@@ -1130,7 +1130,7 @@ lease_to_client(struct data_string *reply_ret,
        reply.cursor = 0;
 }
 
-/* Process a client-supplied IA_NA.  This may append options ot the tail of
+/* Process a client-supplied IA_NA.  This may append options to the tail of
  * the reply packet being built in the reply_state structure.
  */
 static isc_result_t
@@ -1141,12 +1141,16 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) {
        struct option_state *packet_ia;
        struct option_cache *oc;
        struct data_string ia_data, data;
+       isc_boolean_t lease_in_database;
 
        /* Initialize values that will get cleaned up on return. */
        packet_ia = NULL;
        memset(&ia_data, 0, sizeof(ia_data));
        memset(&data, 0, sizeof(data));
-       /* Note that find_client_address() may set reply->lease. */
+       lease_in_database = ISC_FALSE;
+       /* 
+        * Note that find_client_address() may set reply->lease. 
+        */
 
        /* Make sure there is at least room for the header. */
        if ((reply->cursor + IA_NA_OFFSET + 4) > sizeof(reply->buf)) {
@@ -1395,7 +1399,7 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) {
         * pool timers for each (if any).
         */
        if ((status != ISC_R_CANCELED) && !reply->static_lease &&
-           (reply->packet->dhcpv6_msg_type != DHCPV6_SOLICIT) &&
+           (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
            (reply->ia_na->num_iaaddr != 0)) {
                struct iaaddr *tmp;
                struct data_string *ia_id;
@@ -1443,6 +1447,23 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) {
                               ia_id->len, reply->ia_na, MDL);
 
                write_ia_na(reply->ia_na);
+
+               /* 
+                * Note that we wrote the lease into the database,
+                * so that we know not to release it when we're done
+                * with this function.
+                */
+               lease_in_database = ISC_TRUE;
+
+       /*
+        * If this is a soft binding, we will check to see if we are 
+        * suggesting the existing database entry to the client.
+        */
+       } else if ((status != ISC_R_CANCELED) && !reply->static_lease &&
+           (reply->old_ia != NULL)) {
+               if (ia_na_equal(reply->old_ia, reply->ia_na)) {
+                       lease_in_database = ISC_TRUE;
+               }
        }
 
       cleanup:
@@ -1458,8 +1479,12 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) {
                ia_na_dereference(&reply->ia_na, MDL);
        if (reply->old_ia != NULL)
                ia_na_dereference(&reply->old_ia, MDL);
-       if (reply->lease != NULL)
+       if (reply->lease != NULL) {
+               if (!lease_in_database) {
+                       release_lease6(reply->lease->ipv6_pool, reply->lease);
+               }
                iaaddr_dereference(&reply->lease, MDL);
+       }
        if (reply->fixed.data != NULL)
                data_string_forget(&reply->fixed, MDL);
 
index 398e6c6751595a15d9644c209879e289015d7697..5e48a29e687c6eb771017864eb4d2bd927c93d34 100644 (file)
@@ -343,6 +343,68 @@ ia_na_remove_all_iaaddr(struct ia_na *ia_na, const char *file, int line) {
        ia_na->num_iaaddr = 0;
 }
 
+/*
+ * Compare two IA_NA.
+ */
+isc_boolean_t
+ia_na_equal(const struct ia_na *a, const struct ia_na *b) 
+{
+       isc_boolean_t found;
+       int i, j;
+
+       /*
+        * Handle cases where one or both of the inputs is NULL.
+        */
+       if (a == NULL) {
+               if (b == NULL) {
+                       return ISC_TRUE;
+               } else {
+                       return ISC_FALSE;
+               }
+       }       
+
+       /*
+        * Check the DUID is the same.
+        */
+       if (a->iaid_duid.len != b->iaid_duid.len) {
+               return ISC_FALSE;
+       }
+       if (memcmp(a->iaid_duid.data, 
+                  b->iaid_duid.data, a->iaid_duid.len) != 0) {
+               return ISC_FALSE;
+       }
+
+       /*
+        * Make sure we have the same number of addresses in each.
+        */
+       if (a->num_iaaddr != b->num_iaaddr) {
+               return ISC_FALSE;
+       }
+
+       /*
+        * Check that each address is present in both.
+        */
+       for (i=0; i<a->num_iaaddr; i++) {
+               found = ISC_FALSE;
+               for (j=0; j<a->num_iaaddr; j++) {
+                       if (memcmp(&(a->iaaddr[i]->addr),
+                                  &(b->iaaddr[j]->addr), 
+                                  sizeof(struct in6_addr) == 0)) {
+                               found = ISC_TRUE;
+                               break;
+                       }
+               }
+               if (!found) {
+                       return ISC_FALSE;
+               }
+       }
+
+       /*
+        * These are the same in every way we care about.
+        */
+       return ISC_TRUE;
+}
+
 /*
  * Helper function for lease heaps.
  * Makes the top of the heap the oldest lease.