Diff for /embedaddon/dhcp/server/mdb6.c between versions 1.1 and 1.1.1.1

version 1.1, 2012/02/21 22:30:18 version 1.1.1.1, 2012/10/09 09:06:55
Line 1 Line 1
 /*  /*
 * Copyright (C) 2010-2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2010-2012 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2007-2008 by Internet Systems Consortium, Inc. ("ISC")   * Copyright (C) 2007-2008 by Internet Systems Consortium, Inc. ("ISC")
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
Line 15 Line 15
  * PERFORMANCE OF THIS SOFTWARE.   * PERFORMANCE OF THIS SOFTWARE.
  */   */
   
/* TODO: assert() *//*!
/* TODO: simplify functions, as pool is now in iaaddr */ * \todo assert()
  * \todo simplify functions, as pool is now in iaaddr
  */
   
   /*! \file server/mdb6.c
    *
    * \page ipv6structures IPv6 Structures Overview
    *
    * A brief description of the IPv6 structures as reverse engineered.
    *
    * There are three major data strucutes involved in the database:
    *
    * - ipv6_pool - this contains information about a pool of addresses or prefixes
    *             that the server is using.  This includes a hash table that
    *             tracks the active items and a pair of heap tables one for
    *             active items and one for non-active items.  The heap tables
    *             are used to determine the next items to be modified due to
    *             timing events (expire mostly).
    * - ia_xx   - this contains information about a single IA from a request
    *             normally it will contain one pointer to a lease for the client
    *             but it may contain more in some circumstances.  There are 3
    *             hash tables to aid in accessing these one each for NA, TA and PD.
    * - iasubopt- the v6 lease structure.  These are created dynamically when
    *             a client asks for something and will eventually be destroyed
    *             if the client doesn't re-ask for that item.  A lease has space
    *             for backpointers to the IA and to the pool to which it belongs.
    *             The pool backpointer is always filled, the IA pointer may not be.
    *
    * In normal use we then have something like this:
    *
    * \verbatim
    * ia hash tables
    *  ia_na_active                           +----------------+
    *  ia_ta_active          +------------+   | pool           |
    *  ia_pd_active          | iasubopt   |<--|  active hash   |
    * +-----------------+    | aka lease  |<--|  active heap   |
    * | ia_xx           |    |  pool ptr  |-->|                |
    * |  iasubopt array |<---|  iaptr     |<--|  inactive heap |
    * |   lease ptr     |--->|            |   |                |
    * +-----------------+    +------------+   +----------------+
    * \endverbatim
    *
    * For the pool either the inactive heap will have a pointer
    * or both the active heap and the active hash will have pointers.
    *
    * I think there are several major items to notice.   The first is
    * that as a lease moves around it will be added to and removed
    * from the address hash table in the pool and between the active
    * and inactive hash tables.  The hash table and the active heap
    * are used when the lease is either active or abandoned.  The
    * inactive heap is used for all other states.  In particular a
    * lease that has expired or been released will be cleaned
    * (DDNS removal etc) and then moved to the inactive heap.  After
    * some time period (currently 1 hour) it will be freed.
    *
    * The second is that when a client requests specific addresses,
    * either because it previously owned them or if the server supplied
    * them as part of a solicit, the server will try to lookup the ia_xx
    * associated with the client and find the addresses there.  If it
    * does find appropriate leases it moves them from the old IA to
    * a new IA and eventually replaces the old IA with the new IA
    * in the IA hash tables.
    *
    */
 #include "config.h"  #include "config.h"
   
 #include <sys/types.h>  #include <sys/types.h>
Line 316  void Line 378  void
 ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,  ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
                    const char *file, int line) {                     const char *file, int line) {
         int i, j;          int i, j;
           if (ia == NULL || iasubopt == NULL)
               return;
   
         for (i=0; i<ia->num_iasubopt; i++) {          for (i=0; i<ia->num_iasubopt; i++) {
                 if (ia->iasubopt[i] == iasubopt) {                  if (ia->iasubopt[i] == iasubopt) {
Line 807  create_lease6(struct ipv6_pool *pool, struct iasubopt  Line 871  create_lease6(struct ipv6_pool *pool, struct iasubopt 
                 }                  }
   
                 /*                  /*
                 * Avoid reserved interface IDs.                 * Avoid reserved interface IDs. (cf. RFC 5453)
                 * (cf. draft-krishnan-ipv6-reserved-iids-02.txt) 
                  */                   */
                 reserved_iid = ISC_FALSE;                  reserved_iid = ISC_FALSE;
                if (memcmp(&tmp.s6_addr[8], &rtany, 8) == 0) {                if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
                         reserved_iid = ISC_TRUE;                          reserved_iid = ISC_TRUE;
                 }                  }
                 if (!reserved_iid &&                  if (!reserved_iid &&
                    (memcmp(&tmp.s6_addr[8], &resany, 7) == 0) &&                    (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
                     ((tmp.s6_addr[15] & 0x80) == 0x80)) {                      ((tmp.s6_addr[15] & 0x80) == 0x80)) {
                         reserved_iid = ISC_TRUE;                          reserved_iid = ISC_TRUE;
                 }                  }
Line 874  create_lease6(struct ipv6_pool *pool, struct iasubopt  Line 937  create_lease6(struct ipv6_pool *pool, struct iasubopt 
         return result;          return result;
 }  }
   
   
   /*!
    *
    * \brief Cleans up leases when reading from a lease file
    *
    * This function is only expected to be run when reading leases in from a file.
    * It checks to see if a lease already exists for the new leases's address.
    * We don't add expired leases to the structures when reading a lease file
    * which limits what can happen.  We have two variables the owners of the leases
    * being the same or different and the new lease being active or non-active:
    * Owners active
    * same   no     remove old lease and its connections
    * same   yes    nothing to do, other code will update the structures.
    * diff   no     nothing to do
    * diff   yes    this combination shouldn't happen, we should only have a
    *               single active lease per address at a time and that lease
    *               should move to non-active before any other lease can
    *               become active for that address.
    *               Currently we delete the previous lease and pass an error
    *               to the caller who should log an error.
    *
    * When we remove a lease we remove it from the hash table and active heap
    * (remember only active leases are in the structures at this time) for the
    * pool, and from the IA's array.  If, after we've removed the pointer from
    * IA's array to the lease, the IA has no more pointers we remove it from
    * the appropriate hash table as well.
    *
    * \param[in] ia_table = the hash table for the IA
    * \param[in] pool     = the pool to update
    * \param[in] lease    = the new lease we want to add
    * \param[in] ia       = the new ia we are building
    *
    * \return
    * ISC_R_SUCCESS = the incoming lease and any previous lease were in
    *                 an expected state - one of the first 3 options above.
    *                 If necessary the old lease was removed.
    * ISC_R_FAILURE = there is already an active lease for the address in
    *                 the incoming lease.  This shouldn't happen if it does
    *                 flag an error for the caller to log.
    */
   
   isc_result_t
   cleanup_lease6(ia_hash_t *ia_table,
                  struct ipv6_pool *pool,
                  struct iasubopt *lease,
                  struct ia_xx *ia) {
   
           struct iasubopt *test_iasubopt, *tmp_iasubopt;
           struct ia_xx *old_ia;
           isc_result_t status = ISC_R_SUCCESS;
   
           test_iasubopt = NULL;
           old_ia = NULL;
   
           /*
            * Look up the address - if we don't find a lease
            * we don't need to do anything.
            */
           if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
                                    &lease->addr, sizeof(lease->addr),
                                    MDL) == 0) {
                   return (ISC_R_SUCCESS);
           }
   
           if (test_iasubopt->ia == NULL) {
                   /* no old ia, no work to do */
                   iasubopt_dereference(&test_iasubopt, MDL);
                   return (status);
           }
   
           ia_reference(&old_ia, test_iasubopt->ia, MDL);
   
           if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
               (memcmp((unsigned char *)ia->iaid_duid.data,
                       (unsigned char *)old_ia->iaid_duid.data,
                       ia->iaid_duid.len) == 0)) {
                   /* same IA */
                   if ((lease->state == FTS_ACTIVE) ||
                       (lease->state == FTS_ABANDONED)) {
                           /* still active, no need to delete */
                           goto cleanup;
                   }
           } else {
                   /* different IA */
                   if ((lease->state != FTS_ACTIVE) &&
                       (lease->state != FTS_ABANDONED)) {
                           /* new lease isn't active, no work */
                           goto cleanup;
                   }
   
                   /*
                    * We appear to have two active leases, this shouldn't happen.
                    * Before a second lease can be set to active the first lease
                    * should be set to inactive (released, expired etc). For now
                    * delete the previous lease and indicate a failure to the
                    * caller so it can generate a warning.
                    * In the future we may try and determine which is the better
                    * lease to keep.
                    */
   
                   status = ISC_R_FAILURE;
           }
   
           /*
            * Remove the old lease from the active heap and from the hash table
            * then remove the lease from the IA and clean up the IA if necessary.
            */
           isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index);
           pool->num_active--;
   
           iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
                                sizeof(test_iasubopt->addr), MDL);
           ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
           if (old_ia->num_iasubopt <= 0) {
                   ia_hash_delete(ia_table,
                                  (unsigned char *)old_ia->iaid_duid.data,
                                  old_ia->iaid_duid.len, MDL);
           }
   
           /*
            * We derefenrece the subopt here as we've just removed it from
            * the hash table in the pool.  We need to make a copy as we
            * need to derefernece it again later.
            */
           tmp_iasubopt = test_iasubopt;
           iasubopt_dereference(&tmp_iasubopt, MDL);
   
         cleanup:
           ia_dereference(&old_ia, MDL);
   
           /*
            * Clean up the reference, this is in addition to the deference
            * above after removing the entry from the hash table
            */
           iasubopt_dereference(&test_iasubopt, MDL);
   
           return (status);
   }
   
 /*  /*
  * Put a lease in the pool directly. This is intended to be used when   * Put a lease in the pool directly. This is intended to be used when
  * loading leases from the file.   * loading leases from the file.
Line 984  lease6_exists(const struct ipv6_pool *pool, const stru Line 1186  lease6_exists(const struct ipv6_pool *pool, const stru
         }          }
 }  }
   
   /*!
    *
    * \brief Check if address is available to a lease
    *
    * Determine if the address in the lease is available to that
    * lease.  Either the address isn't in use or it is in use
    * but by that lease.
    *
    * \param[in] lease = lease to check
    *
    * \return
    * ISC_TRUE  = The lease is allowed to use that address
    * ISC_FALSE = The lease isn't allowed to use that address
    */
   isc_boolean_t
   lease6_usable(struct iasubopt *lease) {
           struct iasubopt *test_iaaddr;
           isc_boolean_t status = ISC_TRUE;
   
           test_iaaddr = NULL;
           if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
                                    (void *)&lease->addr,
                                    sizeof(lease->addr), MDL)) {
                   if (test_iaaddr != lease) {
                           status = ISC_FALSE;
                   }
                   iasubopt_dereference(&test_iaaddr, MDL);
           }
   
           return (status);
   }
   
 /*  /*
  * Put the lease on our active pool.   * Put the lease on our active pool.
  */   */
Line 1005  move_lease_to_active(struct ipv6_pool *pool, struct ia Line 1239  move_lease_to_active(struct ipv6_pool *pool, struct ia
         return insert_result;          return insert_result;
 }  }
   
/*/*!
 * Renew an lease in the pool. * \brief Renew a lease in the pool.
  *   *
 * To do this, first set the new hard_lifetime_end_time for the resource, * The hard_lifetime_end_time of the lease should be set to
 * and then invoke renew_lease6() on it. * the current expiration time.
  * The soft_lifetime_end_time of the lease should be set to
  * the desired expiration time.
  *   *
 * WARNING: lease times must only be extended, never reduced!!! * This routine will compare the two and call the correct
  * heap routine to move the lease.  If the lease is active
  * and the new expiration time is greater (the normal case)
  * then we call isc_heap_decreased() as a larger time is a
  * lower priority.  If the new expiration time is less then
  * we call isc_heap_increased().
  *
  * If the lease is abandoned then it will be on the active list
  * and we will always call isc_heap_increased() as the previous
  * expiration would have been all 1s (as close as we can get
  * to infinite).
  *
  * If the lease is moving to active we call that routine
  * which will move it from the inactive list to the active list.
  *
  * \param pool a pool the lease belongs to
  * \param lease the lease to be renewed
  *
  * \return result of the renew operation (ISC_R_SUCCESS if successful,
            ISC_R_NOMEMORY when run out of memory)
  */   */
 isc_result_t  isc_result_t
 renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {  renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
        /*        time_t old_end_time = lease->hard_lifetime_end_time;
         * If we're already active, then we can just move our expiration        lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
         * time down the heap.         lease->soft_lifetime_end_time = 0;
         *
         * If we're abandoned then we are already on the active list 
         * but we need to retag the lease and move our expiration 
         * from infinite to the current value 
         * 
         * Otherwise, we have to move from the inactive heap to the  
         * active heap. 
         */ 
         if (lease->state == FTS_ACTIVE) {          if (lease->state == FTS_ACTIVE) {
                isc_heap_decreased(pool->active_timeouts, lease->heap_index);                if (old_end_time <= lease->hard_lifetime_end_time) {
                         isc_heap_decreased(pool->active_timeouts,
                                            lease->heap_index);
                 } else {
                         isc_heap_increased(pool->active_timeouts,
                                            lease->heap_index);
                 }
                 return ISC_R_SUCCESS;                  return ISC_R_SUCCESS;
         } else if (lease->state == FTS_ABANDONED) {          } else if (lease->state == FTS_ABANDONED) {
                 char tmp_addr[INET6_ADDRSTRLEN];                  char tmp_addr[INET6_ADDRSTRLEN];
Line 1153  release_lease6(struct ipv6_pool *pool, struct iasubopt Line 1407  release_lease6(struct ipv6_pool *pool, struct iasubopt
  * Create a prefix by hashing the input, and using that for   * Create a prefix by hashing the input, and using that for
  * the part subject to allocation.   * the part subject to allocation.
  */   */
static voidvoid
 build_prefix6(struct in6_addr *pref,   build_prefix6(struct in6_addr *pref, 
               const struct in6_addr *net_start_pref,                const struct in6_addr *net_start_pref,
               int pool_bits, int pref_bits,                int pool_bits, int pref_bits,
Line 1488  lease_timeout_support(void *vpool) { Line 1742  lease_timeout_support(void *vpool) {
         }          }
   
         /*          /*
            * If appropriate commit and rotate the lease file
            * As commit_leases_timed() checks to see if we've done any writes
            * we don't bother tracking if this function called write _ia
            */
           (void) commit_leases_timed();
   
           /*
          * Do some cleanup of our expired leases.           * Do some cleanup of our expired leases.
          */           */
         cleanup_old_expired(pool);          cleanup_old_expired(pool);
Line 1686  change_leases(struct ia_xx *ia,  Line 1947  change_leases(struct ia_xx *ia, 
 /*  /*
  * Renew all leases in an IA from all pools.   * Renew all leases in an IA from all pools.
  *   *
 * The new hard_lifetime_end_time should be updated for the addresses/prefixes. * The new lifetime should be in the soft_lifetime_end_time
 * * and will be moved to hard_lifetime_end_time by renew_lease6.
 * WARNING: lease times must only be extended, never reduced!!! 
  */   */
 isc_result_t   isc_result_t 
 renew_leases(struct ia_xx *ia) {  renew_leases(struct ia_xx *ia) {
Line 1886  mark_interfaces_unavailable(void) { Line 2146  mark_interfaces_unavailable(void) {
         }          }
 }  }
   
/* unittest moved to server/tests/mdb6_unittest.c */
#ifdef UNIT_TEST 
#include <stdlib.h> 
 
int  
main(int argc, char *argv[]) { 
        struct iasubopt *iaaddr; 
        struct iasubopt *iaaddr_copy; 
        u_int32_t iaid; 
        struct ia_xx *ia_na; 
        struct ia_xx *ia_na_copy; 
        int i; 
        struct in6_addr addr; 
        struct ipv6_pool *pool; 
        struct ipv6_pool *pool_copy; 
        char addr_buf[INET6_ADDRSTRLEN]; 
        char *uid; 
        struct data_string ds; 
        struct iasubopt *expired_iaaddr; 
        unsigned int attempts; 
 
        /* 
         * Test 0: Basic iaaddr manipulation. 
         */ 
        iaaddr = NULL; 
        if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iaaddr->state != FTS_FREE) { 
                printf("ERROR: bad state %s:%d\n", MDL); 
                return 1; 
        } 
        if (iaaddr->heap_index != -1) { 
                printf("ERROR: bad heap_index %s:%d\n", MDL); 
                return 1; 
        } 
        iaaddr_copy = NULL; 
        if (iasubopt_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr_copy, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /*  
         * Test 1: Error iaaddr manipulation. 
         */ 
        /* bogus allocate arguments */ 
        if (iasubopt_allocate(NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        iaaddr = (struct iasubopt *)1; 
        if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* bogus reference arguments */ 
        iaaddr = NULL; 
        if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_reference(NULL, iaaddr, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        iaaddr_copy = (struct iasubopt *)1; 
        if (iasubopt_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        iaaddr_copy = NULL; 
        if (iasubopt_reference(&iaaddr_copy, NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* bogus dereference arguments */ 
        if (iasubopt_dereference(NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        iaaddr = NULL; 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* 
         * Test 2: Basic ia_na manipulation. 
         */ 
        iaid = 666; 
        ia_na = NULL; 
        if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (memcmp(ia_na->iaid_duid.data, &iaid, sizeof(iaid)) != 0) { 
                printf("ERROR: bad IAID_DUID %s:%d\n", MDL); 
                return 1; 
        } 
        if (memcmp(ia_na->iaid_duid.data+sizeof(iaid), "TestDUID", 8) != 0) { 
                printf("ERROR: bad IAID_DUID %s:%d\n", MDL); 
                return 1; 
        } 
        if (ia_na->num_iasubopt != 0) { 
                printf("ERROR: bad num_iasubopt %s:%d\n", MDL); 
                return 1; 
        } 
        ia_na_copy = NULL; 
        if (ia_reference(&ia_na_copy, ia_na, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        iaaddr = NULL; 
        if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); 
                return 1; 
        } 
        ia_remove_iasubopt(ia_na, iaaddr, MDL); 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ia_dereference(&ia_na_copy, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /*  
         * Test 3: lots of iaaddr in our ia_na 
         */ 
 
        /* lots of iaaddr that we delete */ 
        iaid = 666; 
        ia_na = NULL; 
        if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        for (i=0; i<100; i++) { 
                iaaddr = NULL; 
                if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                        return 1; 
                } 
        } 
        for (i=0; i<100; i++) { 
                iaaddr = ia_na->iasubopt[random() % ia_na->num_iasubopt]; 
                ia_remove_iasubopt(ia_na, iaaddr, MDL); 
        } 
        if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* lots of iaaddr, let dereference cleanup */ 
        iaid = 666; 
        ia_na = NULL; 
        if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        for (i=0; i<100; i++) { 
                iaaddr = NULL; 
                if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: iasubopt_reference() %s:%d\n", MDL); 
                        return 1; 
                } 
        } 
        if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* 
         * Test 4: Errors in ia_na. 
         */ 
        /* bogus allocate arguments */ 
        if (ia_allocate(NULL, 123, "", 0, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        ia_na = (struct ia_na *)1; 
        if (ia_allocate(&ia_na, 456, "", 0, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* bogus reference arguments */ 
        iaid = 666; 
        ia_na = NULL; 
        if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ia_reference(NULL, ia_na, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ia_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        ia_na_copy = (struct ia_na *)1; 
        if (ia_reference(&ia_na_copy, ia_na, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ia_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        ia_na_copy = NULL; 
        if (ia_reference(&ia_na_copy, NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ia_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* bogus dereference arguments */ 
        if (ia_dereference(NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* bogus remove */ 
        iaid = 666; 
        ia_na = NULL; 
        if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        ia_remove_iasubopt(ia_na, NULL, MDL); 
        if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* 
         * Test 5: Basic ipv6_pool manipulation. 
         */ 
 
        /* allocate, reference */ 
        inet_pton(AF_INET6, "1:2:3:4::", &addr); 
        pool = NULL; 
        if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 0) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->bits != 64) { 
                printf("ERROR: bad bits %s:%d\n", MDL); 
                return 1; 
        } 
        inet_ntop(AF_INET6, &pool->start_addr, addr_buf, sizeof(addr_buf)); 
        if (strcmp(inet_ntop(AF_INET6, &pool->start_addr, addr_buf,  
                             sizeof(addr_buf)), "1:2:3:4::") != 0) { 
                printf("ERROR: bad start_addr %s:%d\n", MDL); 
                return 1; 
        } 
        pool_copy = NULL; 
        if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* create_lease6, renew_lease6, expire_lease6 */ 
        uid = "client0"; 
        memset(&ds, 0, sizeof(ds)); 
        ds.len = strlen(uid); 
        if (!buffer_allocate(&ds.buffer, ds.len, MDL)) { 
                printf("Out of memory\n"); 
                return 1; 
        } 
        ds.data = ds.buffer->data; 
        memcpy((char *)ds.data, uid, ds.len); 
        if (create_lease6(pool, &iaaddr,  
                          &attempts, &ds, 1) != ISC_R_SUCCESS) { 
                printf("ERROR: create_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_inactive != 1) { 
                printf("ERROR: bad num_inactive %s:%d\n", MDL); 
                return 1; 
        } 
        if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: renew_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 1) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        expired_iaaddr = NULL; 
        if (expire_lease6(&expired_iaaddr, pool, 0) != ISC_R_SUCCESS) { 
                printf("ERROR: expire_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (expired_iaaddr != NULL) { 
                printf("ERROR: should not have expired a lease %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 1) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { 
                printf("ERROR: expire_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (expired_iaaddr == NULL) { 
                printf("ERROR: should have expired a lease %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 0) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* release_lease6, decline_lease6 */ 
        if (create_lease6(pool, &iaaddr, &attempts,  
                          &ds, 1) != ISC_R_SUCCESS) { 
                printf("ERROR: create_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: renew_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 1) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (release_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: decline_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 0) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (create_lease6(pool, &iaaddr, &attempts,  
                          &ds, 1) != ISC_R_SUCCESS) { 
                printf("ERROR: create_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: renew_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 1) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (decline_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: decline_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (pool->num_active != 1) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* dereference */ 
        if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* 
         * Test 6: Error ipv6_pool manipulation 
         */ 
        if (ipv6_pool_allocate(NULL, 0, &addr, 64, 128, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        pool = (struct ipv6_pool *)1; 
        if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_reference(NULL, pool, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        pool_copy = (struct ipv6_pool *)1; 
        if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        pool_copy = NULL; 
        if (ipv6_pool_reference(&pool_copy, NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(NULL, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_INVALIDARG) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* 
         * Test 7: order of expiration 
         */ 
        pool = NULL; 
        if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        for (i=10; i<100; i+=10) { 
                if (create_lease6(pool, &iaaddr, &attempts, 
                                  &ds, i) != ISC_R_SUCCESS) { 
                        printf("ERROR: create_lease6() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                        printf("ERROR: renew_lease6() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                        printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (pool->num_active != (i / 10)) { 
                        printf("ERROR: bad num_active %s:%d\n", MDL); 
                        return 1; 
                } 
        } 
        if (pool->num_active != 9) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        for (i=10; i<100; i+=10) { 
                if (expire_lease6(&expired_iaaddr,  
                                  pool, 1000) != ISC_R_SUCCESS) { 
                        printf("ERROR: expire_lease6() %s:%d\n", MDL); 
                        return 1; 
                } 
                if (expired_iaaddr == NULL) { 
                        printf("ERROR: should have expired a lease %s:%d\n",  
                               MDL); 
                        return 1; 
                } 
                if (pool->num_active != (9 - (i / 10))) { 
                        printf("ERROR: bad num_active %s:%d\n", MDL); 
                        return 1; 
                } 
                if (expired_iaaddr->hard_lifetime_end_time != i) { 
                        printf("ERROR: bad hard_lifetime_end_time %s:%d\n",  
                               MDL); 
                        return 1; 
                } 
                if (iasubopt_dereference(&expired_iaaddr, MDL) != 
                                ISC_R_SUCCESS) { 
                        printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                        return 1; 
                } 
        } 
        if (pool->num_active != 0) { 
                printf("ERROR: bad num_active %s:%d\n", MDL); 
                return 1; 
        } 
        expired_iaaddr = NULL; 
        if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { 
                printf("ERROR: expire_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
 
        /* 
         * Test 8: small pool 
         */ 
        pool = NULL; 
        addr.s6_addr[14] = 0x81; 
        if (ipv6_pool_allocate(&pool, 0, &addr, 127, 128, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (create_lease6(pool, &iaaddr, &attempts,  
                          &ds, 42) != ISC_R_SUCCESS) { 
                printf("ERROR: create_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: renew_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (create_lease6(pool, &iaaddr, &attempts,  
                          &ds, 11) != ISC_R_SUCCESS) { 
                printf("ERROR: create_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { 
                printf("ERROR: renew_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        if (create_lease6(pool, &iaaddr, &attempts,  
                          &ds, 11) != ISC_R_NORESOURCES) { 
                printf("ERROR: create_lease6() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        addr.s6_addr[14] = 0; 
 
        /*  
         * Test 9: functions across all pools 
         */ 
        pool = NULL; 
        if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); 
                return 1; 
        } 
        if (add_ipv6_pool(pool) != ISC_R_SUCCESS) { 
                printf("ERROR: add_ipv6_pool() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        pool = NULL; 
        if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { 
                printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        inet_pton(AF_INET6, "1:2:3:4:ffff:ffff:ffff:ffff", &addr); 
        pool = NULL; 
        if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { 
                printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); 
                return 1; 
        } 
        if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); 
                return 1; 
        } 
        inet_pton(AF_INET6, "1:2:3:5::", &addr); 
        pool = NULL; 
        if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { 
                printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); 
                return 1; 
        } 
        inet_pton(AF_INET6, "1:2:3:3:ffff:ffff:ffff:ffff", &addr); 
        pool = NULL; 
        if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { 
                printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); 
                return 1; 
        } 
 
/*      iaid = 666; 
        ia_na = NULL; 
        if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { 
                printf("ERROR: ia_allocate() %s:%d\n", MDL); 
                return 1; 
        }*/ 
 
        { 
                struct in6_addr r; 
                struct data_string ds; 
                u_char data[16]; 
                char buf[64]; 
                int i, j; 
 
                memset(&ds, 0, sizeof(ds)); 
                memset(data, 0xaa, sizeof(data)); 
                ds.len = 16; 
                ds.data = data; 
 
                inet_pton(AF_INET6, "3ffe:501:ffff:100::", &addr); 
                for (i = 32; i < 42; i++) 
                        for (j = i + 1; j < 49; j++) { 
                                memset(&r, 0, sizeof(r)); 
                                memset(buf, 0, 64); 
                                build_prefix6(&r, &addr, i, j, &ds); 
                                inet_ntop(AF_INET6, &r, buf, 64); 
                                printf("%d,%d-> %s/%d\n", i, j, buf, j); 
                        } 
        } 
         
        printf("SUCCESS: all tests passed (ignore any warning messages)\n"); 
        return 0; 
} 
#endif 

Removed from v.1.1  
changed lines
  Added in v.1.1.1.1


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>