Annotation of embedaddon/dhcp/server/mdb6.c, revision 1.1.1.1

1.1       misho       1: /*
1.1.1.1 ! misho       2:  * Copyright (C) 2010-2012 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       3:  * Copyright (C) 2007-2008 by Internet Systems Consortium, Inc. ("ISC")
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                     10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     15:  * PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
1.1.1.1 ! misho      18: /*!
        !            19:  * \todo assert()
        !            20:  * \todo simplify functions, as pool is now in iaaddr
        !            21:  */
        !            22: 
        !            23: /*! \file server/mdb6.c
        !            24:  *
        !            25:  * \page ipv6structures IPv6 Structures Overview
        !            26:  *
        !            27:  * A brief description of the IPv6 structures as reverse engineered.
        !            28:  *
        !            29:  * There are three major data strucutes involved in the database:
        !            30:  *
        !            31:  * - ipv6_pool - this contains information about a pool of addresses or prefixes
        !            32:  *             that the server is using.  This includes a hash table that
        !            33:  *             tracks the active items and a pair of heap tables one for
        !            34:  *             active items and one for non-active items.  The heap tables
        !            35:  *             are used to determine the next items to be modified due to
        !            36:  *             timing events (expire mostly).
        !            37:  * - ia_xx   - this contains information about a single IA from a request
        !            38:  *             normally it will contain one pointer to a lease for the client
        !            39:  *             but it may contain more in some circumstances.  There are 3
        !            40:  *             hash tables to aid in accessing these one each for NA, TA and PD.
        !            41:  * - iasubopt- the v6 lease structure.  These are created dynamically when
        !            42:  *             a client asks for something and will eventually be destroyed
        !            43:  *             if the client doesn't re-ask for that item.  A lease has space
        !            44:  *             for backpointers to the IA and to the pool to which it belongs.
        !            45:  *             The pool backpointer is always filled, the IA pointer may not be.
        !            46:  *
        !            47:  * In normal use we then have something like this:
        !            48:  *
        !            49:  * \verbatim
        !            50:  * ia hash tables
        !            51:  *  ia_na_active                           +----------------+
        !            52:  *  ia_ta_active          +------------+   | pool           |
        !            53:  *  ia_pd_active          | iasubopt   |<--|  active hash   |
        !            54:  * +-----------------+    | aka lease  |<--|  active heap   |
        !            55:  * | ia_xx           |    |  pool ptr  |-->|                |
        !            56:  * |  iasubopt array |<---|  iaptr     |<--|  inactive heap |
        !            57:  * |   lease ptr     |--->|            |   |                |
        !            58:  * +-----------------+    +------------+   +----------------+
        !            59:  * \endverbatim
        !            60:  *
        !            61:  * For the pool either the inactive heap will have a pointer
        !            62:  * or both the active heap and the active hash will have pointers.
        !            63:  *
        !            64:  * I think there are several major items to notice.   The first is
        !            65:  * that as a lease moves around it will be added to and removed
        !            66:  * from the address hash table in the pool and between the active
        !            67:  * and inactive hash tables.  The hash table and the active heap
        !            68:  * are used when the lease is either active or abandoned.  The
        !            69:  * inactive heap is used for all other states.  In particular a
        !            70:  * lease that has expired or been released will be cleaned
        !            71:  * (DDNS removal etc) and then moved to the inactive heap.  After
        !            72:  * some time period (currently 1 hour) it will be freed.
        !            73:  *
        !            74:  * The second is that when a client requests specific addresses,
        !            75:  * either because it previously owned them or if the server supplied
        !            76:  * them as part of a solicit, the server will try to lookup the ia_xx
        !            77:  * associated with the client and find the addresses there.  If it
        !            78:  * does find appropriate leases it moves them from the old IA to
        !            79:  * a new IA and eventually replaces the old IA with the new IA
        !            80:  * in the IA hash tables.
        !            81:  *
        !            82:  */
1.1       misho      83: #include "config.h"
                     84: 
                     85: #include <sys/types.h>
                     86: #include <time.h>
                     87: #include <netinet/in.h>
                     88: 
                     89: #include "isc-dhcp/result.h"
                     90: 
                     91: #include <stdarg.h>
                     92: #include "dhcpd.h"
                     93: #include "omapip/omapip.h"
                     94: #include "omapip/hash.h"
                     95: #include "dst/md5.h"
                     96: 
                     97: HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t,
                     98:               ia_reference, ia_dereference, do_string_hash)
                     99: 
                    100: ia_hash_t *ia_na_active;
                    101: ia_hash_t *ia_ta_active;
                    102: ia_hash_t *ia_pd_active;
                    103: 
                    104: HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t,
                    105:               iasubopt_reference, iasubopt_dereference, do_string_hash)
                    106: 
                    107: struct ipv6_pool **pools;
                    108: int num_pools;
                    109: 
                    110: /*
                    111:  * Create a new IAADDR/PREFIX structure.
                    112:  *
                    113:  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
                    114:  *   initialized to NULL
                    115:  */
                    116: isc_result_t
                    117: iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) {
                    118:        struct iasubopt *tmp;
                    119: 
                    120:        if (iasubopt == NULL) {
                    121:                log_error("%s(%d): NULL pointer reference", file, line);
                    122:                return ISC_R_INVALIDARG;
                    123:        }
                    124:        if (*iasubopt != NULL) {
                    125:                log_error("%s(%d): non-NULL pointer", file, line);
                    126:                return ISC_R_INVALIDARG;
                    127:        }
                    128: 
                    129:        tmp = dmalloc(sizeof(*tmp), file, line);
                    130:        if (tmp == NULL) {
                    131:                return ISC_R_NOMEMORY;
                    132:        }
                    133: 
                    134:        tmp->refcnt = 1;
                    135:        tmp->state = FTS_FREE;
                    136:        tmp->heap_index = -1;
                    137:        tmp->plen = 255;
                    138: 
                    139:        *iasubopt = tmp;
                    140:        return ISC_R_SUCCESS;
                    141: }
                    142: 
                    143: /*
                    144:  * Reference an IAADDR/PREFIX structure.
                    145:  *
                    146:  * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
                    147:  *   initialized to NULL
                    148:  */
                    149: isc_result_t
                    150: iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src,
                    151:                 const char *file, int line) {
                    152:        if (iasubopt == NULL) {
                    153:                log_error("%s(%d): NULL pointer reference", file, line);
                    154:                return ISC_R_INVALIDARG;
                    155:        }
                    156:        if (*iasubopt != NULL) {
                    157:                log_error("%s(%d): non-NULL pointer", file, line);
                    158:                return ISC_R_INVALIDARG;
                    159:        }
                    160:        if (src == NULL) {
                    161:                log_error("%s(%d): NULL pointer reference", file, line);
                    162:                return ISC_R_INVALIDARG;
                    163:        }
                    164:        *iasubopt = src;
                    165:        src->refcnt++;
                    166:        return ISC_R_SUCCESS;
                    167: }
                    168: 
                    169: 
                    170: /*
                    171:  * Dereference an IAADDR/PREFIX structure.
                    172:  *
                    173:  * If it is the last reference, then the memory for the 
                    174:  * structure is freed.
                    175:  */
                    176: isc_result_t
                    177: iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) {
                    178:        struct iasubopt *tmp;
                    179: 
                    180:        if ((iasubopt == NULL) || (*iasubopt == NULL)) {
                    181:                log_error("%s(%d): NULL pointer", file, line);
                    182:                return ISC_R_INVALIDARG;
                    183:        }
                    184: 
                    185:        tmp = *iasubopt;
                    186:        *iasubopt = NULL;
                    187: 
                    188:        tmp->refcnt--;
                    189:        if (tmp->refcnt < 0) {
                    190:                log_error("%s(%d): negative refcnt", file, line);
                    191:                tmp->refcnt = 0;
                    192:        }
                    193:        if (tmp->refcnt == 0) {
                    194:                if (tmp->ia != NULL) {
                    195:                        ia_dereference(&(tmp->ia), file, line);
                    196:                }
                    197:                if (tmp->ipv6_pool != NULL) {
                    198:                        ipv6_pool_dereference(&(tmp->ipv6_pool), file, line);
                    199:                }
                    200:                if (tmp->scope != NULL) {
                    201:                        binding_scope_dereference(&tmp->scope, file, line);
                    202:                }
                    203:                dfree(tmp, file, line);
                    204:        }
                    205: 
                    206:        return ISC_R_SUCCESS;
                    207: }
                    208: 
                    209: /* 
                    210:  * Make the key that we use for IA.
                    211:  */
                    212: isc_result_t
                    213: ia_make_key(struct data_string *key, u_int32_t iaid,
                    214:            const char *duid, unsigned int duid_len,
                    215:            const char *file, int line) {
                    216: 
                    217:        memset(key, 0, sizeof(*key));
                    218:        key->len = duid_len + sizeof(iaid);
                    219:        if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
                    220:                return ISC_R_NOMEMORY;
                    221:        }
                    222:        key->data = key->buffer->data;
                    223:        memcpy((char *)key->data, &iaid, sizeof(iaid));
                    224:        memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
                    225: 
                    226:        return ISC_R_SUCCESS;
                    227: }
                    228: 
                    229: /*
                    230:  * Create a new IA structure.
                    231:  *
                    232:  * - ia must be a pointer to a (struct ia_xx *) pointer previously
                    233:  *   initialized to NULL
                    234:  * - iaid and duid are values from the client
                    235:  *
                    236:  * XXXsk: we don't concern ourself with the byte order of the IAID, 
                    237:  *        which might be a problem if we transfer this structure 
                    238:  *        between machines of different byte order
                    239:  */
                    240: isc_result_t
                    241: ia_allocate(struct ia_xx **ia, u_int32_t iaid, 
                    242:            const char *duid, unsigned int duid_len,
                    243:            const char *file, int line) {
                    244:        struct ia_xx *tmp;
                    245: 
                    246:        if (ia == NULL) {
                    247:                log_error("%s(%d): NULL pointer reference", file, line);
                    248:                return ISC_R_INVALIDARG;
                    249:        }
                    250:        if (*ia != NULL) {
                    251:                log_error("%s(%d): non-NULL pointer", file, line);
                    252:                return ISC_R_INVALIDARG;
                    253:        }
                    254: 
                    255:        tmp = dmalloc(sizeof(*tmp), file, line);
                    256:        if (tmp == NULL) {
                    257:                return ISC_R_NOMEMORY;
                    258:        }
                    259: 
                    260:        if (ia_make_key(&tmp->iaid_duid, iaid, 
                    261:                        duid, duid_len, file, line) != ISC_R_SUCCESS) {
                    262:                dfree(tmp, file, line);
                    263:                return ISC_R_NOMEMORY;
                    264:        }
                    265: 
                    266:        tmp->refcnt = 1;
                    267: 
                    268:        *ia = tmp;
                    269:        return ISC_R_SUCCESS;
                    270: }
                    271: 
                    272: /*
                    273:  * Reference an IA structure.
                    274:  *
                    275:  * - ia must be a pointer to a (struct ia_xx *) pointer previously
                    276:  *   initialized to NULL
                    277:  */
                    278: isc_result_t
                    279: ia_reference(struct ia_xx **ia, struct ia_xx *src,
                    280:             const char *file, int line) {
                    281:        if (ia == NULL) {
                    282:                log_error("%s(%d): NULL pointer reference", file, line);
                    283:                return ISC_R_INVALIDARG;
                    284:        }
                    285:        if (*ia != NULL) {
                    286:                log_error("%s(%d): non-NULL pointer", file, line);
                    287:                return ISC_R_INVALIDARG;
                    288:        }
                    289:        if (src == NULL) {
                    290:                log_error("%s(%d): NULL pointer reference", file, line);
                    291:                return ISC_R_INVALIDARG;
                    292:        }
                    293:        *ia = src;
                    294:        src->refcnt++;
                    295:        return ISC_R_SUCCESS;
                    296: }
                    297: 
                    298: /*
                    299:  * Dereference an IA structure.
                    300:  *
                    301:  * If it is the last reference, then the memory for the 
                    302:  * structure is freed.
                    303:  */
                    304: isc_result_t
                    305: ia_dereference(struct ia_xx **ia, const char *file, int line) {
                    306:        struct ia_xx *tmp;
                    307:        int i;
                    308: 
                    309:        if ((ia == NULL) || (*ia == NULL)) {
                    310:                log_error("%s(%d): NULL pointer", file, line);
                    311:                return ISC_R_INVALIDARG;
                    312:        }
                    313: 
                    314:        tmp = *ia;
                    315:        *ia = NULL;
                    316: 
                    317:        tmp->refcnt--;
                    318:        if (tmp->refcnt < 0) {
                    319:                log_error("%s(%d): negative refcnt", file, line);
                    320:                tmp->refcnt = 0;
                    321:        }
                    322:        if (tmp->refcnt == 0) {
                    323:                if (tmp->iasubopt != NULL) {
                    324:                        for (i=0; i<tmp->num_iasubopt; i++) {
                    325:                                iasubopt_dereference(&(tmp->iasubopt[i]), 
                    326:                                                     file, line);
                    327:                        }
                    328:                        dfree(tmp->iasubopt, file, line);
                    329:                }
                    330:                data_string_forget(&(tmp->iaid_duid), file, line);
                    331:                dfree(tmp, file, line);
                    332:        }
                    333:        return ISC_R_SUCCESS;
                    334: }
                    335: 
                    336: 
                    337: /*
                    338:  * Add an IAADDR/PREFIX entry to an IA structure.
                    339:  */
                    340: isc_result_t
                    341: ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, 
                    342:                const char *file, int line) {
                    343:        int max;
                    344:        struct iasubopt **new;
                    345: 
                    346:        /* 
                    347:         * Grow our array if we need to.
                    348:         * 
                    349:         * Note: we pick 4 as the increment, as that seems a reasonable
                    350:         *       guess as to how many addresses/prefixes we might expect
                    351:         *       on an interface.
                    352:         */
                    353:        if (ia->max_iasubopt <= ia->num_iasubopt) {
                    354:                max = ia->max_iasubopt + 4;
                    355:                new = dmalloc(max * sizeof(struct iasubopt *), file, line);
                    356:                if (new == NULL) {
                    357:                        return ISC_R_NOMEMORY;
                    358:                }
                    359:                memcpy(new, ia->iasubopt, 
                    360:                       ia->num_iasubopt * sizeof(struct iasubopt *));
                    361:                ia->iasubopt = new;
                    362:                ia->max_iasubopt = max;
                    363:        }
                    364: 
                    365:        iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt, 
                    366:                           file, line);
                    367:        ia->num_iasubopt++;
                    368: 
                    369:        return ISC_R_SUCCESS;
                    370: }
                    371: 
                    372: /*
                    373:  * Remove an IAADDR/PREFIX entry to an IA structure.
                    374:  *
                    375:  * Note: if a suboption appears more than once, then only ONE will be removed.
                    376:  */
                    377: void
                    378: ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
                    379:                   const char *file, int line) {
                    380:        int i, j;
1.1.1.1 ! misho     381:         if (ia == NULL || iasubopt == NULL)
        !           382:             return;
1.1       misho     383: 
                    384:        for (i=0; i<ia->num_iasubopt; i++) {
                    385:                if (ia->iasubopt[i] == iasubopt) {
                    386:                        /* remove this sub option */
                    387:                        iasubopt_dereference(&(ia->iasubopt[i]), file, line);
                    388:                        /* move remaining suboption pointers down one */
                    389:                        for (j=i+1; j < ia->num_iasubopt; j++) {
                    390:                                ia->iasubopt[j-1] = ia->iasubopt[j];
                    391:                        }
                    392:                        /* decrease our total count */
                    393:                        /* remove the back-reference in the suboption itself */
                    394:                        ia_dereference(&iasubopt->ia, file, line);
                    395:                        ia->num_iasubopt--;
                    396:                        return;
                    397:                }
                    398:        }
                    399:        log_error("%s(%d): IAADDR/PREFIX not in IA", file, line);
                    400: }
                    401: 
                    402: /*
                    403:  * Remove all addresses/prefixes from an IA.
                    404:  */
                    405: void
                    406: ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) {
                    407:        int i;
                    408: 
                    409:        for (i=0; i<ia->num_iasubopt; i++) {
                    410:                ia_dereference(&(ia->iasubopt[i]->ia), file, line);
                    411:                iasubopt_dereference(&(ia->iasubopt[i]), file, line);
                    412:        }
                    413:        ia->num_iasubopt = 0;
                    414: }
                    415: 
                    416: /*
                    417:  * Compare two IA.
                    418:  */
                    419: isc_boolean_t
                    420: ia_equal(const struct ia_xx *a, const struct ia_xx *b) 
                    421: {
                    422:        isc_boolean_t found;
                    423:        int i, j;
                    424: 
                    425:        /*
                    426:         * Handle cases where one or both of the inputs is NULL.
                    427:         */
                    428:        if (a == NULL) {
                    429:                if (b == NULL) {
                    430:                        return ISC_TRUE;
                    431:                } else {
                    432:                        return ISC_FALSE;
                    433:                }
                    434:        }       
                    435: 
                    436:        /*
                    437:         * Check the type is the same.
                    438:         */
                    439:        if (a->ia_type != b->ia_type) {
                    440:                return ISC_FALSE;
                    441:        }
                    442: 
                    443:        /*
                    444:         * Check the DUID is the same.
                    445:         */
                    446:        if (a->iaid_duid.len != b->iaid_duid.len) {
                    447:                return ISC_FALSE;
                    448:        }
                    449:        if (memcmp(a->iaid_duid.data, 
                    450:                   b->iaid_duid.data, a->iaid_duid.len) != 0) {
                    451:                return ISC_FALSE;
                    452:        }
                    453: 
                    454:        /*
                    455:         * Make sure we have the same number of addresses/prefixes in each.
                    456:         */
                    457:        if (a->num_iasubopt != b->num_iasubopt) {
                    458:                return ISC_FALSE;
                    459:        }
                    460: 
                    461:        /*
                    462:         * Check that each address/prefix is present in both.
                    463:         */
                    464:        for (i=0; i<a->num_iasubopt; i++) {
                    465:                found = ISC_FALSE;
                    466:                for (j=0; j<a->num_iasubopt; j++) {
                    467:                        if (a->iasubopt[i]->plen != b->iasubopt[i]->plen)
                    468:                                continue;
                    469:                        if (memcmp(&(a->iasubopt[i]->addr),
                    470:                                   &(b->iasubopt[j]->addr), 
                    471:                                   sizeof(struct in6_addr)) == 0) {
                    472:                                found = ISC_TRUE;
                    473:                                break;
                    474:                        }
                    475:                }
                    476:                if (!found) {
                    477:                        return ISC_FALSE;
                    478:                }
                    479:        }
                    480: 
                    481:        /*
                    482:         * These are the same in every way we care about.
                    483:         */
                    484:        return ISC_TRUE;
                    485: }
                    486: 
                    487: /*
                    488:  * Helper function for lease heaps.
                    489:  * Makes the top of the heap the oldest lease.
                    490:  */
                    491: static isc_boolean_t 
                    492: lease_older(void *a, void *b) {
                    493:        struct iasubopt *la = (struct iasubopt *)a;
                    494:        struct iasubopt *lb = (struct iasubopt *)b;
                    495: 
                    496:        if (la->hard_lifetime_end_time == lb->hard_lifetime_end_time) {
                    497:                return difftime(la->soft_lifetime_end_time,
                    498:                                lb->soft_lifetime_end_time) < 0;
                    499:        } else {
                    500:                return difftime(la->hard_lifetime_end_time, 
                    501:                                lb->hard_lifetime_end_time) < 0;
                    502:        }
                    503: }
                    504: 
                    505: /*
                    506:  * Helper function for lease address/prefix heaps.
                    507:  * Callback when an address's position in the heap changes.
                    508:  */
                    509: static void
                    510: lease_index_changed(void *iasubopt, unsigned int new_heap_index) {
                    511:        ((struct iasubopt *)iasubopt)-> heap_index = new_heap_index;
                    512: }
                    513: 
                    514: 
                    515: /*
                    516:  * Create a new IPv6 lease pool structure.
                    517:  *
                    518:  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
                    519:  *   initialized to NULL
                    520:  */
                    521: isc_result_t
                    522: ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
                    523:                   const struct in6_addr *start_addr, int bits, 
                    524:                   int units, const char *file, int line) {
                    525:        struct ipv6_pool *tmp;
                    526: 
                    527:        if (pool == NULL) {
                    528:                log_error("%s(%d): NULL pointer reference", file, line);
                    529:                return ISC_R_INVALIDARG;
                    530:        }
                    531:        if (*pool != NULL) {
                    532:                log_error("%s(%d): non-NULL pointer", file, line);
                    533:                return ISC_R_INVALIDARG;
                    534:        }
                    535: 
                    536:        tmp = dmalloc(sizeof(*tmp), file, line);
                    537:        if (tmp == NULL) {
                    538:                return ISC_R_NOMEMORY;
                    539:        }
                    540: 
                    541:        tmp->refcnt = 1;
                    542:        tmp->pool_type = type;
                    543:        tmp->start_addr = *start_addr;
                    544:        tmp->bits = bits;
                    545:        tmp->units = units;
                    546:        if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) {
                    547:                dfree(tmp, file, line);
                    548:                return ISC_R_NOMEMORY;
                    549:        }
                    550:        if (isc_heap_create(lease_older, lease_index_changed,
                    551:                            0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) {
                    552:                iasubopt_free_hash_table(&(tmp->leases), file, line);
                    553:                dfree(tmp, file, line);
                    554:                return ISC_R_NOMEMORY;
                    555:        }
                    556:        if (isc_heap_create(lease_older, lease_index_changed,
                    557:                            0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) {
                    558:                isc_heap_destroy(&(tmp->active_timeouts));
                    559:                iasubopt_free_hash_table(&(tmp->leases), file, line);
                    560:                dfree(tmp, file, line);
                    561:                return ISC_R_NOMEMORY;
                    562:        }
                    563: 
                    564:        *pool = tmp;
                    565:        return ISC_R_SUCCESS;
                    566: }
                    567: 
                    568: /*
                    569:  * Reference an IPv6 pool structure.
                    570:  *
                    571:  * - pool must be a pointer to a (struct pool *) pointer previously
                    572:  *   initialized to NULL
                    573:  */
                    574: isc_result_t
                    575: ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
                    576:                    const char *file, int line) {
                    577:        if (pool == NULL) {
                    578:                log_error("%s(%d): NULL pointer reference", file, line);
                    579:                return ISC_R_INVALIDARG;
                    580:        }
                    581:        if (*pool != NULL) {
                    582:                log_error("%s(%d): non-NULL pointer", file, line);
                    583:                return ISC_R_INVALIDARG;
                    584:        }
                    585:        if (src == NULL) {
                    586:                log_error("%s(%d): NULL pointer reference", file, line);
                    587:                return ISC_R_INVALIDARG;
                    588:        }
                    589:        *pool = src;
                    590:        src->refcnt++;
                    591:        return ISC_R_SUCCESS;
                    592: }
                    593: 
                    594: /* 
                    595:  * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
                    596:  * to prevent the lease from being garbage collected out from under the
                    597:  * pool.
                    598:  *
                    599:  * The references are made from the hash and from the heap. The following
                    600:  * helper functions dereference these when a pool is destroyed.
                    601:  */
                    602: 
                    603: /*
                    604:  * Helper function for pool cleanup.
                    605:  * Dereference each of the hash entries in a pool.
                    606:  */
                    607: static isc_result_t 
                    608: dereference_hash_entry(const void *name, unsigned len, void *value) {
                    609:        struct iasubopt *iasubopt = (struct iasubopt *)value;
                    610: 
                    611:        iasubopt_dereference(&iasubopt, MDL);
                    612:        return ISC_R_SUCCESS;
                    613: }
                    614: 
                    615: /*
                    616:  * Helper function for pool cleanup.
                    617:  * Dereference each of the heap entries in a pool.
                    618:  */
                    619: static void
                    620: dereference_heap_entry(void *value, void *dummy) {
                    621:        struct iasubopt *iasubopt = (struct iasubopt *)value;
                    622: 
                    623:        iasubopt_dereference(&iasubopt, MDL);
                    624: }
                    625: 
                    626: 
                    627: /*
                    628:  * Dereference an IPv6 pool structure.
                    629:  *
                    630:  * If it is the last reference, then the memory for the 
                    631:  * structure is freed.
                    632:  */
                    633: isc_result_t
                    634: ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
                    635:        struct ipv6_pool *tmp;
                    636: 
                    637:        if ((pool == NULL) || (*pool == NULL)) {
                    638:                log_error("%s(%d): NULL pointer", file, line);
                    639:                return ISC_R_INVALIDARG;
                    640:        }
                    641: 
                    642:        tmp = *pool;
                    643:        *pool = NULL;
                    644: 
                    645:        tmp->refcnt--;
                    646:        if (tmp->refcnt < 0) {
                    647:                log_error("%s(%d): negative refcnt", file, line);
                    648:                tmp->refcnt = 0;
                    649:        }
                    650:        if (tmp->refcnt == 0) {
                    651:                iasubopt_hash_foreach(tmp->leases, dereference_hash_entry);
                    652:                iasubopt_free_hash_table(&(tmp->leases), file, line);
                    653:                isc_heap_foreach(tmp->active_timeouts, 
                    654:                                 dereference_heap_entry, NULL);
                    655:                isc_heap_destroy(&(tmp->active_timeouts));
                    656:                isc_heap_foreach(tmp->inactive_timeouts, 
                    657:                                 dereference_heap_entry, NULL);
                    658:                isc_heap_destroy(&(tmp->inactive_timeouts));
                    659:                dfree(tmp, file, line);
                    660:        }
                    661: 
                    662:        return ISC_R_SUCCESS;
                    663: }
                    664: 
                    665: /* 
                    666:  * Create an address by hashing the input, and using that for
                    667:  * the non-network part.
                    668:  */
                    669: static void
                    670: build_address6(struct in6_addr *addr, 
                    671:               const struct in6_addr *net_start_addr, int net_bits, 
                    672:               const struct data_string *input) {
                    673:        MD5_CTX ctx;
                    674:        int net_bytes;
                    675:        int i;
                    676:        char *str;
                    677:        const char *net_str;
                    678: 
                    679:        /* 
                    680:         * Use MD5 to get a nice 128 bit hash of the input.
                    681:         * Yes, we know MD5 isn't cryptographically sound. 
                    682:         * No, we don't care.
                    683:         */
                    684:        MD5_Init(&ctx);
                    685:        MD5_Update(&ctx, input->data, input->len);
                    686:        MD5_Final((unsigned char *)addr, &ctx);
                    687: 
                    688:        /*
                    689:         * Copy the [0..128] network bits over.
                    690:         */
                    691:        str = (char *)addr;
                    692:        net_str = (const char *)net_start_addr;
                    693:        net_bytes = net_bits / 8;
                    694:        for (i = 0; i < net_bytes; i++) {
                    695:                str[i] = net_str[i];
                    696:        }
                    697:        switch (net_bits % 8) {
                    698:                case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
                    699:                case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
                    700:                case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
                    701:                case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
                    702:                case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
                    703:                case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
                    704:                case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
                    705:        }
                    706:        /* set the 'u' bit to zero for /64s. */
                    707:        if (net_bits == 64)
                    708:                str[8] &= ~0x02;
                    709: }
                    710: 
                    711: /* 
                    712:  * Create a temporary address by a variant of RFC 4941 algo.
                    713:  * Note: this should not be used for prefixes shorter than 64 bits.
                    714:  */
                    715: static void
                    716: build_temporary6(struct in6_addr *addr, 
                    717:                 const struct in6_addr *net_start_addr, int net_bits,
                    718:                 const struct data_string *input) {
                    719:        static u_int8_t history[8];
                    720:        static u_int32_t counter = 0;
                    721:        MD5_CTX ctx;
                    722:        unsigned char md[16];
                    723:        extern int dst_s_random(u_int8_t *, unsigned);
                    724: 
                    725:        /*
                    726:         * First time/time to reseed.
                    727:         * Please use a good pseudo-random generator here!
                    728:         */
                    729:        if (counter == 0) {
                    730:                if (dst_s_random(history, 8) != 8)
                    731:                        log_fatal("Random failed.");
                    732:        }
                    733: 
                    734:        /* 
                    735:         * Use MD5 as recommended by RFC 4941.
                    736:         */
                    737:        MD5_Init(&ctx);
                    738:        MD5_Update(&ctx, history, 8UL);
                    739:        MD5_Update(&ctx, input->data, input->len);
                    740:        MD5_Final(md, &ctx);
                    741: 
                    742:        /*
                    743:         * Build the address.
                    744:         */
                    745:        if (net_bits == 64) {
                    746:                memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8);
                    747:                memcpy(&addr->s6_addr[8], md, 8);
                    748:                addr->s6_addr[8] &= ~0x02;
                    749:        } else {
                    750:                int net_bytes;
                    751:                int i;
                    752:                char *str;
                    753:                const char *net_str;
                    754: 
                    755:                /*
                    756:                 * Copy the [0..128] network bits over.
                    757:                 */
                    758:                str = (char *)addr;
                    759:                net_str = (const char *)net_start_addr;
                    760:                net_bytes = net_bits / 8;
                    761:                for (i = 0; i < net_bytes; i++) {
                    762:                        str[i] = net_str[i];
                    763:                }
                    764:                memcpy(str + net_bytes, md, 16 - net_bytes);
                    765:                switch (net_bits % 8) {
                    766:                case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
                    767:                case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
                    768:                case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
                    769:                case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
                    770:                case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
                    771:                case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
                    772:                case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
                    773:                }
                    774:        }
                    775: 
                    776: 
                    777:        /*
                    778:         * Save history for the next call.
                    779:         */
                    780:        memcpy(history, md + 8, 8);
                    781:        counter++;
                    782: }
                    783: 
                    784: /* Reserved Subnet Router Anycast ::0:0:0:0. */
                    785: static struct in6_addr rtany;
                    786: /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
                    787: static struct in6_addr resany;
                    788: 
                    789: /*
                    790:  * Create a lease for the given address and client duid.
                    791:  *
                    792:  * - pool must be a pointer to a (struct pool *) pointer previously
                    793:  *   initialized to NULL
                    794:  *
                    795:  * Right now we simply hash the DUID, and if we get a collision, we hash 
                    796:  * again until we find a free address. We try this a fixed number of times,
                    797:  * to avoid getting stuck in a loop (this is important on small pools
                    798:  * where we can run out of space).
                    799:  *
                    800:  * We return the number of attempts that it took to find an available
                    801:  * lease. This tells callers when a pool is are filling up, as
                    802:  * well as an indication of how full the pool is; statistically the 
                    803:  * more full a pool is the more attempts must be made before finding
                    804:  * a free lease. Realistically this will only happen in very full
                    805:  * pools.
                    806:  *
                    807:  * We probably want different algorithms depending on the network size, in
                    808:  * the long term.
                    809:  */
                    810: isc_result_t
                    811: create_lease6(struct ipv6_pool *pool, struct iasubopt **addr, 
                    812:              unsigned int *attempts,
                    813:              const struct data_string *uid, time_t soft_lifetime_end_time) {
                    814:        struct data_string ds;
                    815:        struct in6_addr tmp;
                    816:        struct iasubopt *test_iaaddr;
                    817:        struct data_string new_ds;
                    818:        struct iasubopt *iaaddr;
                    819:        isc_result_t result;
                    820:        isc_boolean_t reserved_iid;
                    821:        static isc_boolean_t init_resiid = ISC_FALSE;
                    822: 
                    823:        /*
                    824:         * Fill the reserved IIDs.
                    825:         */
                    826:        if (!init_resiid) {
                    827:                memset(&rtany, 0, 16);
                    828:                memset(&resany, 0, 8);
                    829:                resany.s6_addr[8] = 0xfd;
                    830:                memset(&resany.s6_addr[9], 0xff, 6);
                    831:                init_resiid = ISC_TRUE;
                    832:        }
                    833: 
                    834:        /* 
                    835:         * Use the UID as our initial seed for the hash
                    836:         */
                    837:        memset(&ds, 0, sizeof(ds));
                    838:        data_string_copy(&ds, (struct data_string *)uid, MDL);
                    839: 
                    840:        *attempts = 0;
                    841:        for (;;) {
                    842:                /*
                    843:                 * Give up at some point.
                    844:                 */
                    845:                if (++(*attempts) > 100) {
                    846:                        data_string_forget(&ds, MDL);
                    847:                        return ISC_R_NORESOURCES;
                    848:                }
                    849: 
                    850:                /* 
                    851:                 * Build a resource.
                    852:                 */
                    853:                switch (pool->pool_type) {
                    854:                case D6O_IA_NA:
                    855:                        /* address */
                    856:                        build_address6(&tmp, &pool->start_addr,
                    857:                                       pool->bits, &ds);
                    858:                        break;
                    859:                case D6O_IA_TA:
                    860:                        /* temporary address */
                    861:                        build_temporary6(&tmp, &pool->start_addr,
                    862:                                         pool->bits, &ds);
                    863:                        break;
                    864:                case D6O_IA_PD:
                    865:                        /* prefix */
                    866:                        log_error("create_lease6: prefix pool.");
                    867:                        return ISC_R_INVALIDARG;
                    868:                default:
                    869:                        log_error("create_lease6: untyped pool.");
                    870:                        return ISC_R_INVALIDARG;
                    871:                }
                    872: 
                    873:                /*
1.1.1.1 ! misho     874:                 * Avoid reserved interface IDs. (cf. RFC 5453)
1.1       misho     875:                 */
                    876:                reserved_iid = ISC_FALSE;
1.1.1.1 ! misho     877:                if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
1.1       misho     878:                        reserved_iid = ISC_TRUE;
                    879:                }
                    880:                if (!reserved_iid &&
1.1.1.1 ! misho     881:                    (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1.1       misho     882:                    ((tmp.s6_addr[15] & 0x80) == 0x80)) {
                    883:                        reserved_iid = ISC_TRUE;
                    884:                }
                    885: 
                    886:                /*
                    887:                 * If this address is not in use, we're happy with it
                    888:                 */
                    889:                test_iaaddr = NULL;
                    890:                if (!reserved_iid &&
                    891:                    (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
                    892:                                          &tmp, sizeof(tmp), MDL) == 0)) {
                    893:                        break;
                    894:                }
                    895:                if (test_iaaddr != NULL)
                    896:                        iasubopt_dereference(&test_iaaddr, MDL);
                    897: 
                    898:                /* 
                    899:                 * Otherwise, we create a new input, adding the address
                    900:                 */
                    901:                memset(&new_ds, 0, sizeof(new_ds));
                    902:                new_ds.len = ds.len + sizeof(tmp);
                    903:                if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
                    904:                        data_string_forget(&ds, MDL);
                    905:                        return ISC_R_NOMEMORY;
                    906:                }
                    907:                new_ds.data = new_ds.buffer->data;
                    908:                memcpy(new_ds.buffer->data, ds.data, ds.len);
                    909:                memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
                    910:                data_string_forget(&ds, MDL);
                    911:                data_string_copy(&ds, &new_ds, MDL);
                    912:                data_string_forget(&new_ds, MDL);
                    913:        }
                    914: 
                    915:        data_string_forget(&ds, MDL);
                    916: 
                    917:        /* 
                    918:         * We're happy with the address, create an IAADDR
                    919:         * to hold it.
                    920:         */
                    921:        iaaddr = NULL;
                    922:        result = iasubopt_allocate(&iaaddr, MDL);
                    923:        if (result != ISC_R_SUCCESS) {
                    924:                return result;
                    925:        }
                    926:        iaaddr->plen = 0;
                    927:        memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
                    928: 
                    929:        /*
                    930:         * Add the lease to the pool (note state is free, not active?!).
                    931:         */
                    932:        result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
                    933:        if (result == ISC_R_SUCCESS) {
                    934:                iasubopt_reference(addr, iaaddr, MDL);
                    935:        }
                    936:        iasubopt_dereference(&iaaddr, MDL);
                    937:        return result;
                    938: }
                    939: 
1.1.1.1 ! misho     940: 
        !           941: /*!
        !           942:  *
        !           943:  * \brief Cleans up leases when reading from a lease file
        !           944:  *
        !           945:  * This function is only expected to be run when reading leases in from a file.
        !           946:  * It checks to see if a lease already exists for the new leases's address.
        !           947:  * We don't add expired leases to the structures when reading a lease file
        !           948:  * which limits what can happen.  We have two variables the owners of the leases
        !           949:  * being the same or different and the new lease being active or non-active:
        !           950:  * Owners active
        !           951:  * same   no     remove old lease and its connections
        !           952:  * same   yes    nothing to do, other code will update the structures.
        !           953:  * diff   no     nothing to do
        !           954:  * diff   yes    this combination shouldn't happen, we should only have a
        !           955:  *               single active lease per address at a time and that lease
        !           956:  *               should move to non-active before any other lease can
        !           957:  *               become active for that address.
        !           958:  *               Currently we delete the previous lease and pass an error
        !           959:  *               to the caller who should log an error.
        !           960:  *
        !           961:  * When we remove a lease we remove it from the hash table and active heap
        !           962:  * (remember only active leases are in the structures at this time) for the
        !           963:  * pool, and from the IA's array.  If, after we've removed the pointer from
        !           964:  * IA's array to the lease, the IA has no more pointers we remove it from
        !           965:  * the appropriate hash table as well.
        !           966:  *
        !           967:  * \param[in] ia_table = the hash table for the IA
        !           968:  * \param[in] pool     = the pool to update
        !           969:  * \param[in] lease    = the new lease we want to add
        !           970:  * \param[in] ia       = the new ia we are building
        !           971:  *
        !           972:  * \return
        !           973:  * ISC_R_SUCCESS = the incoming lease and any previous lease were in
        !           974:  *                 an expected state - one of the first 3 options above.
        !           975:  *                 If necessary the old lease was removed.
        !           976:  * ISC_R_FAILURE = there is already an active lease for the address in
        !           977:  *                 the incoming lease.  This shouldn't happen if it does
        !           978:  *                 flag an error for the caller to log.
        !           979:  */
        !           980: 
        !           981: isc_result_t
        !           982: cleanup_lease6(ia_hash_t *ia_table,
        !           983:               struct ipv6_pool *pool,
        !           984:               struct iasubopt *lease,
        !           985:               struct ia_xx *ia) {
        !           986: 
        !           987:        struct iasubopt *test_iasubopt, *tmp_iasubopt;
        !           988:        struct ia_xx *old_ia;
        !           989:        isc_result_t status = ISC_R_SUCCESS;
        !           990: 
        !           991:        test_iasubopt = NULL;
        !           992:        old_ia = NULL;
        !           993: 
        !           994:        /*
        !           995:         * Look up the address - if we don't find a lease
        !           996:         * we don't need to do anything.
        !           997:         */
        !           998:        if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
        !           999:                                 &lease->addr, sizeof(lease->addr),
        !          1000:                                 MDL) == 0) {
        !          1001:                return (ISC_R_SUCCESS);
        !          1002:        }
        !          1003: 
        !          1004:        if (test_iasubopt->ia == NULL) {
        !          1005:                /* no old ia, no work to do */
        !          1006:                iasubopt_dereference(&test_iasubopt, MDL);
        !          1007:                return (status);
        !          1008:        }
        !          1009: 
        !          1010:        ia_reference(&old_ia, test_iasubopt->ia, MDL);
        !          1011: 
        !          1012:        if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
        !          1013:            (memcmp((unsigned char *)ia->iaid_duid.data,
        !          1014:                    (unsigned char *)old_ia->iaid_duid.data,
        !          1015:                    ia->iaid_duid.len) == 0)) {
        !          1016:                /* same IA */
        !          1017:                if ((lease->state == FTS_ACTIVE) ||
        !          1018:                    (lease->state == FTS_ABANDONED)) {
        !          1019:                        /* still active, no need to delete */
        !          1020:                        goto cleanup;
        !          1021:                }
        !          1022:        } else {
        !          1023:                /* different IA */
        !          1024:                if ((lease->state != FTS_ACTIVE) &&
        !          1025:                    (lease->state != FTS_ABANDONED)) {
        !          1026:                        /* new lease isn't active, no work */
        !          1027:                        goto cleanup;
        !          1028:                }
        !          1029: 
        !          1030:                /*
        !          1031:                 * We appear to have two active leases, this shouldn't happen.
        !          1032:                 * Before a second lease can be set to active the first lease
        !          1033:                 * should be set to inactive (released, expired etc). For now
        !          1034:                 * delete the previous lease and indicate a failure to the
        !          1035:                 * caller so it can generate a warning.
        !          1036:                 * In the future we may try and determine which is the better
        !          1037:                 * lease to keep.
        !          1038:                 */
        !          1039: 
        !          1040:                status = ISC_R_FAILURE;
        !          1041:        }
        !          1042: 
        !          1043:        /*
        !          1044:         * Remove the old lease from the active heap and from the hash table
        !          1045:         * then remove the lease from the IA and clean up the IA if necessary.
        !          1046:         */
        !          1047:        isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index);
        !          1048:        pool->num_active--;
        !          1049: 
        !          1050:        iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
        !          1051:                             sizeof(test_iasubopt->addr), MDL);
        !          1052:        ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
        !          1053:        if (old_ia->num_iasubopt <= 0) {
        !          1054:                ia_hash_delete(ia_table,
        !          1055:                               (unsigned char *)old_ia->iaid_duid.data,
        !          1056:                               old_ia->iaid_duid.len, MDL);
        !          1057:        }
        !          1058: 
        !          1059:        /*
        !          1060:         * We derefenrece the subopt here as we've just removed it from
        !          1061:         * the hash table in the pool.  We need to make a copy as we
        !          1062:         * need to derefernece it again later.
        !          1063:         */
        !          1064:        tmp_iasubopt = test_iasubopt;
        !          1065:        iasubopt_dereference(&tmp_iasubopt, MDL);
        !          1066: 
        !          1067:       cleanup:
        !          1068:        ia_dereference(&old_ia, MDL);
        !          1069: 
        !          1070:        /*
        !          1071:         * Clean up the reference, this is in addition to the deference
        !          1072:         * above after removing the entry from the hash table
        !          1073:         */
        !          1074:        iasubopt_dereference(&test_iasubopt, MDL);
        !          1075: 
        !          1076:        return (status);
        !          1077: }
        !          1078: 
1.1       misho    1079: /*
                   1080:  * Put a lease in the pool directly. This is intended to be used when
                   1081:  * loading leases from the file.
                   1082:  */
                   1083: isc_result_t
                   1084: add_lease6(struct ipv6_pool *pool, struct iasubopt *lease,
                   1085:           time_t valid_lifetime_end_time) {
                   1086:        isc_result_t insert_result;
                   1087:        struct iasubopt *test_iasubopt;
                   1088:        struct iasubopt *tmp_iasubopt;
                   1089: 
                   1090:        /* If a state was not assigned by the caller, assume active. */
                   1091:        if (lease->state == 0)
                   1092:                lease->state = FTS_ACTIVE;
                   1093: 
                   1094:        ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
                   1095: 
                   1096:        /*
                   1097:         * If this IAADDR/PREFIX is already in our structures, remove the 
                   1098:         * old one.
                   1099:         */
                   1100:        test_iasubopt = NULL;
                   1101:        if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
                   1102:                                 &lease->addr, sizeof(lease->addr), MDL)) {
                   1103:                /* XXX: we should probably ask the lease what heap it is on
                   1104:                 * (as a consistency check).
                   1105:                 * XXX: we should probably have one function to "put this lease
                   1106:                 * on its heap" rather than doing these if's everywhere.  If
                   1107:                 * you add more states to this list, don't.
                   1108:                 */
                   1109:                if ((test_iasubopt->state == FTS_ACTIVE) ||
                   1110:                    (test_iasubopt->state == FTS_ABANDONED)) {
                   1111:                        isc_heap_delete(pool->active_timeouts,
                   1112:                                        test_iasubopt->heap_index);
                   1113:                        pool->num_active--;
                   1114:                } else {
                   1115:                        isc_heap_delete(pool->inactive_timeouts,
                   1116:                                        test_iasubopt->heap_index);
                   1117:                        pool->num_inactive--;
                   1118:                }
                   1119: 
                   1120:                iasubopt_hash_delete(pool->leases, &test_iasubopt->addr, 
                   1121:                                     sizeof(test_iasubopt->addr), MDL);
                   1122: 
                   1123:                /*
                   1124:                 * We're going to do a bit of evil trickery here.
                   1125:                 *
                   1126:                 * We need to dereference the entry once to remove our
                   1127:                 * current reference (in test_iasubopt), and then one
                   1128:                 * more time to remove the reference left when the
                   1129:                 * address was added to the pool before.
                   1130:                 */
                   1131:                tmp_iasubopt = test_iasubopt;
                   1132:                iasubopt_dereference(&test_iasubopt, MDL);
                   1133:                iasubopt_dereference(&tmp_iasubopt, MDL);
                   1134:        }
                   1135: 
                   1136:        /* 
                   1137:         * Add IAADDR/PREFIX to our structures.
                   1138:         */
                   1139:        tmp_iasubopt = NULL;
                   1140:        iasubopt_reference(&tmp_iasubopt, lease, MDL);
                   1141:        if ((tmp_iasubopt->state == FTS_ACTIVE) ||
                   1142:            (tmp_iasubopt->state == FTS_ABANDONED)) {
                   1143:                tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
                   1144:                iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr, 
                   1145:                                  sizeof(tmp_iasubopt->addr), lease, MDL);
                   1146:                insert_result = isc_heap_insert(pool->active_timeouts,
                   1147:                                                tmp_iasubopt);
                   1148:                if (insert_result == ISC_R_SUCCESS)
                   1149:                        pool->num_active++;
                   1150:        } else {
                   1151:                tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
                   1152:                insert_result = isc_heap_insert(pool->inactive_timeouts,
                   1153:                                                tmp_iasubopt);
                   1154:                if (insert_result == ISC_R_SUCCESS)
                   1155:                        pool->num_inactive++;
                   1156:        }
                   1157:        if (insert_result != ISC_R_SUCCESS) {
                   1158:                iasubopt_hash_delete(pool->leases, &lease->addr, 
                   1159:                                     sizeof(lease->addr), MDL);
                   1160:                iasubopt_dereference(&tmp_iasubopt, MDL);
                   1161:                return insert_result;
                   1162:        }
                   1163: 
                   1164:        /* 
                   1165:         * Note: we intentionally leave tmp_iasubopt referenced; there
                   1166:         * is a reference in the heap/hash, after all.
                   1167:         */
                   1168: 
                   1169:        return ISC_R_SUCCESS;
                   1170: }
                   1171: 
                   1172: /*
                   1173:  * Determine if an address is present in a pool or not.
                   1174:  */
                   1175: isc_boolean_t
                   1176: lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
                   1177:        struct iasubopt *test_iaaddr;
                   1178: 
                   1179:        test_iaaddr = NULL;
                   1180:        if (iasubopt_hash_lookup(&test_iaaddr, pool->leases, 
                   1181:                                 (void *)addr, sizeof(*addr), MDL)) {
                   1182:                iasubopt_dereference(&test_iaaddr, MDL);
                   1183:                return ISC_TRUE;
                   1184:        } else {
                   1185:                return ISC_FALSE;
                   1186:        }
                   1187: }
                   1188: 
1.1.1.1 ! misho    1189: /*!
        !          1190:  *
        !          1191:  * \brief Check if address is available to a lease
        !          1192:  *
        !          1193:  * Determine if the address in the lease is available to that
        !          1194:  * lease.  Either the address isn't in use or it is in use
        !          1195:  * but by that lease.
        !          1196:  *
        !          1197:  * \param[in] lease = lease to check
        !          1198:  *
        !          1199:  * \return
        !          1200:  * ISC_TRUE  = The lease is allowed to use that address
        !          1201:  * ISC_FALSE = The lease isn't allowed to use that address
        !          1202:  */
        !          1203: isc_boolean_t
        !          1204: lease6_usable(struct iasubopt *lease) {
        !          1205:        struct iasubopt *test_iaaddr;
        !          1206:        isc_boolean_t status = ISC_TRUE;
        !          1207: 
        !          1208:        test_iaaddr = NULL;
        !          1209:        if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
        !          1210:                                 (void *)&lease->addr,
        !          1211:                                 sizeof(lease->addr), MDL)) {
        !          1212:                if (test_iaaddr != lease) {
        !          1213:                        status = ISC_FALSE;
        !          1214:                }
        !          1215:                iasubopt_dereference(&test_iaaddr, MDL);
        !          1216:        }
        !          1217: 
        !          1218:        return (status);
        !          1219: }
        !          1220: 
1.1       misho    1221: /*
                   1222:  * Put the lease on our active pool.
                   1223:  */
                   1224: static isc_result_t
                   1225: move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
                   1226:        isc_result_t insert_result;
                   1227:        int old_heap_index;
                   1228: 
                   1229:        old_heap_index = lease->heap_index;
                   1230:        insert_result = isc_heap_insert(pool->active_timeouts, lease);
                   1231:        if (insert_result == ISC_R_SUCCESS) {
                   1232:                        iasubopt_hash_add(pool->leases, &lease->addr, 
                   1233:                                  sizeof(lease->addr), lease, MDL);
                   1234:                isc_heap_delete(pool->inactive_timeouts, old_heap_index);
                   1235:                pool->num_active++;
                   1236:                pool->num_inactive--;
                   1237:                lease->state = FTS_ACTIVE;
                   1238:        }
                   1239:        return insert_result;
                   1240: }
                   1241: 
1.1.1.1 ! misho    1242: /*!
        !          1243:  * \brief Renew a lease in the pool.
        !          1244:  *
        !          1245:  * The hard_lifetime_end_time of the lease should be set to
        !          1246:  * the current expiration time.
        !          1247:  * The soft_lifetime_end_time of the lease should be set to
        !          1248:  * the desired expiration time.
        !          1249:  *
        !          1250:  * This routine will compare the two and call the correct
        !          1251:  * heap routine to move the lease.  If the lease is active
        !          1252:  * and the new expiration time is greater (the normal case)
        !          1253:  * then we call isc_heap_decreased() as a larger time is a
        !          1254:  * lower priority.  If the new expiration time is less then
        !          1255:  * we call isc_heap_increased().
        !          1256:  *
        !          1257:  * If the lease is abandoned then it will be on the active list
        !          1258:  * and we will always call isc_heap_increased() as the previous
        !          1259:  * expiration would have been all 1s (as close as we can get
        !          1260:  * to infinite).
1.1       misho    1261:  *
1.1.1.1 ! misho    1262:  * If the lease is moving to active we call that routine
        !          1263:  * which will move it from the inactive list to the active list.
1.1       misho    1264:  *
1.1.1.1 ! misho    1265:  * \param pool a pool the lease belongs to
        !          1266:  * \param lease the lease to be renewed
        !          1267:  *
        !          1268:  * \return result of the renew operation (ISC_R_SUCCESS if successful,
        !          1269:            ISC_R_NOMEMORY when run out of memory)
1.1       misho    1270:  */
                   1271: isc_result_t
                   1272: renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1.1.1.1 ! misho    1273:        time_t old_end_time = lease->hard_lifetime_end_time;
        !          1274:        lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
        !          1275:        lease->soft_lifetime_end_time = 0;
        !          1276: 
1.1       misho    1277:        if (lease->state == FTS_ACTIVE) {
1.1.1.1 ! misho    1278:                if (old_end_time <= lease->hard_lifetime_end_time) {
        !          1279:                        isc_heap_decreased(pool->active_timeouts,
        !          1280:                                           lease->heap_index);
        !          1281:                } else {
        !          1282:                        isc_heap_increased(pool->active_timeouts,
        !          1283:                                           lease->heap_index);
        !          1284:                }
1.1       misho    1285:                return ISC_R_SUCCESS;
                   1286:        } else if (lease->state == FTS_ABANDONED) {
                   1287:                char tmp_addr[INET6_ADDRSTRLEN];
                   1288:                 lease->state = FTS_ACTIVE;
                   1289:                 isc_heap_increased(pool->active_timeouts, lease->heap_index);
                   1290:                log_info("Reclaiming previously abandoned address %s",
                   1291:                         inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
                   1292:                                   sizeof(tmp_addr)));
                   1293:                 return ISC_R_SUCCESS;
                   1294:        } else {
                   1295:                return move_lease_to_active(pool, lease);
                   1296:        }
                   1297: }
                   1298: 
                   1299: /*
                   1300:  * Put the lease on our inactive pool, with the specified state.
                   1301:  */
                   1302: static isc_result_t
                   1303: move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease, 
                   1304:                       binding_state_t state) {
                   1305:        isc_result_t insert_result;
                   1306:        int old_heap_index;
                   1307: 
                   1308:        old_heap_index = lease->heap_index;
                   1309:        insert_result = isc_heap_insert(pool->inactive_timeouts, lease);
                   1310:        if (insert_result == ISC_R_SUCCESS) {
                   1311:                /* Process events upon expiration. */
                   1312:                if (pool->pool_type != D6O_IA_PD) {
                   1313:                        ddns_removals(NULL, lease);
                   1314:                }
                   1315: 
                   1316:                /* Binding scopes are no longer valid after expiry or
                   1317:                 * release.
                   1318:                 */
                   1319:                if (lease->scope != NULL) {
                   1320:                        binding_scope_dereference(&lease->scope, MDL);
                   1321:                }
                   1322: 
                   1323:                iasubopt_hash_delete(pool->leases, 
                   1324:                                     &lease->addr, sizeof(lease->addr), MDL);
                   1325:                isc_heap_delete(pool->active_timeouts, old_heap_index);
                   1326:                lease->state = state;
                   1327:                pool->num_active--;
                   1328:                pool->num_inactive++;
                   1329:        }
                   1330:        return insert_result;
                   1331: }
                   1332: 
                   1333: /*
                   1334:  * Expire the oldest lease if it's lifetime_end_time is 
                   1335:  * older than the given time.
                   1336:  *
                   1337:  * - leasep must be a pointer to a (struct iasubopt *) pointer previously
                   1338:  *   initialized to NULL
                   1339:  *
                   1340:  * On return leasep has a reference to the removed entry. It is left
                   1341:  * pointing to NULL if the oldest lease has not expired.
                   1342:  */
                   1343: isc_result_t
                   1344: expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
                   1345:        struct iasubopt *tmp;
                   1346:        isc_result_t result;
                   1347: 
                   1348:        if (leasep == NULL) {
                   1349:                log_error("%s(%d): NULL pointer reference", MDL);
                   1350:                return ISC_R_INVALIDARG;
                   1351:        }
                   1352:        if (*leasep != NULL) {
                   1353:                log_error("%s(%d): non-NULL pointer", MDL);
                   1354:                return ISC_R_INVALIDARG;
                   1355:        }
                   1356: 
                   1357:        if (pool->num_active > 0) {
                   1358:                tmp = (struct iasubopt *)
                   1359:                                isc_heap_element(pool->active_timeouts, 1);
                   1360:                if (now > tmp->hard_lifetime_end_time) {
                   1361:                        result = move_lease_to_inactive(pool, tmp,
                   1362:                                                        FTS_EXPIRED);
                   1363:                        if (result == ISC_R_SUCCESS) {
                   1364:                                iasubopt_reference(leasep, tmp, MDL);
                   1365:                        }
                   1366:                        return result;
                   1367:                }
                   1368:        }
                   1369:        return ISC_R_SUCCESS;
                   1370: }
                   1371: 
                   1372: 
                   1373: /*
                   1374:  * For a declined lease, leave it on the "active" pool, but mark
                   1375:  * it as declined. Give it an infinite (well, really long) life.
                   1376:  */
                   1377: isc_result_t
                   1378: decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
                   1379:        isc_result_t result;
                   1380: 
                   1381:        if ((lease->state != FTS_ACTIVE) &&
                   1382:            (lease->state != FTS_ABANDONED)) {
                   1383:                result = move_lease_to_active(pool, lease);
                   1384:                if (result != ISC_R_SUCCESS) {
                   1385:                        return result;
                   1386:                }
                   1387:        }
                   1388:        lease->state = FTS_ABANDONED;
                   1389:        lease->hard_lifetime_end_time = MAX_TIME;
                   1390:        isc_heap_decreased(pool->active_timeouts, lease->heap_index);
                   1391:        return ISC_R_SUCCESS;
                   1392: }
                   1393: 
                   1394: /*
                   1395:  * Put the returned lease on our inactive pool.
                   1396:  */
                   1397: isc_result_t
                   1398: release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
                   1399:        if (lease->state == FTS_ACTIVE) {
                   1400:                return move_lease_to_inactive(pool, lease, FTS_RELEASED);
                   1401:        } else {
                   1402:                return ISC_R_SUCCESS;
                   1403:        }
                   1404: }
                   1405: 
                   1406: /* 
                   1407:  * Create a prefix by hashing the input, and using that for
                   1408:  * the part subject to allocation.
                   1409:  */
1.1.1.1 ! misho    1410: void
1.1       misho    1411: build_prefix6(struct in6_addr *pref, 
                   1412:              const struct in6_addr *net_start_pref,
                   1413:              int pool_bits, int pref_bits,
                   1414:              const struct data_string *input) {
                   1415:        MD5_CTX ctx;
                   1416:        int net_bytes;
                   1417:        int i;
                   1418:        char *str;
                   1419:        const char *net_str;
                   1420: 
                   1421:        /* 
                   1422:         * Use MD5 to get a nice 128 bit hash of the input.
                   1423:         * Yes, we know MD5 isn't cryptographically sound. 
                   1424:         * No, we don't care.
                   1425:         */
                   1426:        MD5_Init(&ctx);
                   1427:        MD5_Update(&ctx, input->data, input->len);
                   1428:        MD5_Final((unsigned char *)pref, &ctx);
                   1429: 
                   1430:        /*
                   1431:         * Copy the network bits over.
                   1432:         */
                   1433:        str = (char *)pref;
                   1434:        net_str = (const char *)net_start_pref;
                   1435:        net_bytes = pool_bits / 8;
                   1436:        for (i = 0; i < net_bytes; i++) {
                   1437:                str[i] = net_str[i];
                   1438:        }
                   1439:        i = net_bytes;
                   1440:        switch (pool_bits % 8) {
                   1441:                case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
                   1442:                case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
                   1443:                case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
                   1444:                case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
                   1445:                case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
                   1446:                case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
                   1447:                case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
                   1448:        }
                   1449:        /*
                   1450:         * Zero the remaining bits.
                   1451:         */
                   1452:        net_bytes = pref_bits / 8;
                   1453:        for (i=net_bytes+1; i<16; i++) {
                   1454:                str[i] = 0;
                   1455:        }
                   1456:        i = net_bytes;
                   1457:        switch (pref_bits % 8) {
                   1458:                case 0: str[i] &= 0; break;
                   1459:                case 1: str[i] &= 0x80; break;
                   1460:                case 2: str[i] &= 0xC0; break;
                   1461:                case 3: str[i] &= 0xE0; break;
                   1462:                case 4: str[i] &= 0xF0; break;
                   1463:                case 5: str[i] &= 0xF8; break;
                   1464:                case 6: str[i] &= 0xFC; break;
                   1465:                case 7: str[i] &= 0xFE; break;
                   1466:        }
                   1467: }
                   1468: 
                   1469: /*
                   1470:  * Create a lease for the given prefix and client duid.
                   1471:  *
                   1472:  * - pool must be a pointer to a (struct pool *) pointer previously
                   1473:  *   initialized to NULL
                   1474:  *
                   1475:  * Right now we simply hash the DUID, and if we get a collision, we hash 
                   1476:  * again until we find a free prefix. We try this a fixed number of times,
                   1477:  * to avoid getting stuck in a loop (this is important on small pools
                   1478:  * where we can run out of space).
                   1479:  *
                   1480:  * We return the number of attempts that it took to find an available
                   1481:  * prefix. This tells callers when a pool is are filling up, as
                   1482:  * well as an indication of how full the pool is; statistically the 
                   1483:  * more full a pool is the more attempts must be made before finding
                   1484:  * a free prefix. Realistically this will only happen in very full
                   1485:  * pools.
                   1486:  *
                   1487:  * We probably want different algorithms depending on the network size, in
                   1488:  * the long term.
                   1489:  */
                   1490: isc_result_t
                   1491: create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref, 
                   1492:               unsigned int *attempts,
                   1493:               const struct data_string *uid,
                   1494:               time_t soft_lifetime_end_time) {
                   1495:        struct data_string ds;
                   1496:        struct in6_addr tmp;
                   1497:        struct iasubopt *test_iapref;
                   1498:        struct data_string new_ds;
                   1499:        struct iasubopt *iapref;
                   1500:        isc_result_t result;
                   1501: 
                   1502:        /* 
                   1503:         * Use the UID as our initial seed for the hash
                   1504:         */
                   1505:        memset(&ds, 0, sizeof(ds));
                   1506:        data_string_copy(&ds, (struct data_string *)uid, MDL);
                   1507: 
                   1508:        *attempts = 0;
                   1509:        for (;;) {
                   1510:                /*
                   1511:                 * Give up at some point.
                   1512:                 */
                   1513:                if (++(*attempts) > 10) {
                   1514:                        data_string_forget(&ds, MDL);
                   1515:                        return ISC_R_NORESOURCES;
                   1516:                }
                   1517: 
                   1518:                /* 
                   1519:                 * Build a prefix
                   1520:                 */
                   1521:                build_prefix6(&tmp, &pool->start_addr,
                   1522:                              pool->bits, pool->units, &ds);
                   1523: 
                   1524:                /*
                   1525:                 * If this prefix is not in use, we're happy with it
                   1526:                 */
                   1527:                test_iapref = NULL;
                   1528:                if (iasubopt_hash_lookup(&test_iapref, pool->leases,
                   1529:                                         &tmp, sizeof(tmp), MDL) == 0) {
                   1530:                        break;
                   1531:                }
                   1532:                iasubopt_dereference(&test_iapref, MDL);
                   1533: 
                   1534:                /* 
                   1535:                 * Otherwise, we create a new input, adding the prefix
                   1536:                 */
                   1537:                memset(&new_ds, 0, sizeof(new_ds));
                   1538:                new_ds.len = ds.len + sizeof(tmp);
                   1539:                if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
                   1540:                        data_string_forget(&ds, MDL);
                   1541:                        return ISC_R_NOMEMORY;
                   1542:                }
                   1543:                new_ds.data = new_ds.buffer->data;
                   1544:                memcpy(new_ds.buffer->data, ds.data, ds.len);
                   1545:                memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
                   1546:                data_string_forget(&ds, MDL);
                   1547:                data_string_copy(&ds, &new_ds, MDL);
                   1548:                data_string_forget(&new_ds, MDL);
                   1549:        }
                   1550: 
                   1551:        data_string_forget(&ds, MDL);
                   1552: 
                   1553:        /* 
                   1554:         * We're happy with the prefix, create an IAPREFIX
                   1555:         * to hold it.
                   1556:         */
                   1557:        iapref = NULL;
                   1558:        result = iasubopt_allocate(&iapref, MDL);
                   1559:        if (result != ISC_R_SUCCESS) {
                   1560:                return result;
                   1561:        }
                   1562:        iapref->plen = (u_int8_t)pool->units;
                   1563:        memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
                   1564: 
                   1565:        /*
                   1566:         * Add the prefix to the pool (note state is free, not active?!).
                   1567:         */
                   1568:        result = add_lease6(pool, iapref, soft_lifetime_end_time);
                   1569:        if (result == ISC_R_SUCCESS) {
                   1570:                iasubopt_reference(pref, iapref, MDL);
                   1571:        }
                   1572:        iasubopt_dereference(&iapref, MDL);
                   1573:        return result;
                   1574: }
                   1575: 
                   1576: /*
                   1577:  * Determine if a prefix is present in a pool or not.
                   1578:  */
                   1579: isc_boolean_t
                   1580: prefix6_exists(const struct ipv6_pool *pool,
                   1581:               const struct in6_addr *pref, u_int8_t plen) {
                   1582:        struct iasubopt *test_iapref;
                   1583: 
                   1584:        if ((int)plen != pool->units)
                   1585:                return ISC_FALSE;
                   1586: 
                   1587:        test_iapref = NULL;
                   1588:        if (iasubopt_hash_lookup(&test_iapref, pool->leases, 
                   1589:                                 (void *)pref, sizeof(*pref), MDL)) {
                   1590:                iasubopt_dereference(&test_iapref, MDL);
                   1591:                return ISC_TRUE;
                   1592:        } else {
                   1593:                return ISC_FALSE;
                   1594:        }
                   1595: }
                   1596: 
                   1597: /*
                   1598:  * Mark an IPv6 address/prefix as unavailable from a pool.
                   1599:  *
                   1600:  * This is used for host entries and the addresses of the server itself.
                   1601:  */
                   1602: isc_result_t
                   1603: mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
                   1604:        struct iasubopt *dummy_iasubopt;
                   1605:        isc_result_t result;
                   1606: 
                   1607:        dummy_iasubopt = NULL;
                   1608:        result = iasubopt_allocate(&dummy_iasubopt, MDL);
                   1609:        if (result == ISC_R_SUCCESS) {
                   1610:                dummy_iasubopt->addr = *addr;
                   1611:                iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
                   1612:                                  sizeof(*addr), dummy_iasubopt, MDL);
                   1613:        }
                   1614:        return result;
                   1615: }
                   1616: 
                   1617: /* 
                   1618:  * Add a pool.
                   1619:  */
                   1620: isc_result_t
                   1621: add_ipv6_pool(struct ipv6_pool *pool) {
                   1622:        struct ipv6_pool **new_pools;
                   1623: 
                   1624:        new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
                   1625:        if (new_pools == NULL) {
                   1626:                return ISC_R_NOMEMORY;
                   1627:        }
                   1628: 
                   1629:        if (num_pools > 0) {
                   1630:                memcpy(new_pools, pools, 
                   1631:                       sizeof(struct ipv6_pool *) * num_pools);
                   1632:                dfree(pools, MDL);
                   1633:        }
                   1634:        pools = new_pools;
                   1635: 
                   1636:        pools[num_pools] = NULL;
                   1637:        ipv6_pool_reference(&pools[num_pools], pool, MDL);
                   1638:        num_pools++;
                   1639:        return ISC_R_SUCCESS;
                   1640: }
                   1641: 
                   1642: static void
                   1643: cleanup_old_expired(struct ipv6_pool *pool) {
                   1644:        struct iasubopt *tmp;
                   1645:        struct ia_xx *ia;
                   1646:        struct ia_xx *ia_active;
                   1647:        unsigned char *tmpd;
                   1648:        time_t timeout;
                   1649:        
                   1650:        while (pool->num_inactive > 0) {
                   1651:                tmp = (struct iasubopt *)
                   1652:                                isc_heap_element(pool->inactive_timeouts, 1);
                   1653:                if (tmp->hard_lifetime_end_time != 0) {
                   1654:                        timeout = tmp->hard_lifetime_end_time;
                   1655:                        timeout += EXPIRED_IPV6_CLEANUP_TIME;
                   1656:                } else {
                   1657:                        timeout = tmp->soft_lifetime_end_time;
                   1658:                }
                   1659:                if (cur_time < timeout) {
                   1660:                        break;
                   1661:                }
                   1662: 
                   1663:                isc_heap_delete(pool->inactive_timeouts, tmp->heap_index);
                   1664:                pool->num_inactive--;
                   1665: 
                   1666:                if (tmp->ia != NULL) {
                   1667:                        /*
                   1668:                         * Check to see if this IA is in an active list,
                   1669:                         * but has no remaining resources. If so, remove it
                   1670:                         * from the active list.
                   1671:                         */
                   1672:                        ia = NULL;
                   1673:                        ia_reference(&ia, tmp->ia, MDL);
                   1674:                        ia_remove_iasubopt(ia, tmp, MDL);
                   1675:                        ia_active = NULL;
                   1676:                        tmpd = (unsigned char *)ia->iaid_duid.data;
                   1677:                        if ((ia->ia_type == D6O_IA_NA) &&
                   1678:                            (ia->num_iasubopt <= 0) &&
                   1679:                            (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
                   1680:                                            ia->iaid_duid.len, MDL) == 0) &&
                   1681:                            (ia_active == ia)) {
                   1682:                                ia_hash_delete(ia_na_active, tmpd, 
                   1683:                                               ia->iaid_duid.len, MDL);
                   1684:                        }
                   1685:                        if ((ia->ia_type == D6O_IA_TA) &&
                   1686:                            (ia->num_iasubopt <= 0) &&
                   1687:                            (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
                   1688:                                            ia->iaid_duid.len, MDL) == 0) &&
                   1689:                            (ia_active == ia)) {
                   1690:                                ia_hash_delete(ia_ta_active, tmpd, 
                   1691:                                               ia->iaid_duid.len, MDL);
                   1692:                        }
                   1693:                        if ((ia->ia_type == D6O_IA_PD) &&
                   1694:                            (ia->num_iasubopt <= 0) &&
                   1695:                            (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
                   1696:                                            ia->iaid_duid.len, MDL) == 0) &&
                   1697:                            (ia_active == ia)) {
                   1698:                                ia_hash_delete(ia_pd_active, tmpd, 
                   1699:                                               ia->iaid_duid.len, MDL);
                   1700:                        }
                   1701:                        ia_dereference(&ia, MDL);
                   1702:                }
                   1703:                iasubopt_dereference(&tmp, MDL);
                   1704:        }
                   1705: }
                   1706: 
                   1707: static void
                   1708: lease_timeout_support(void *vpool) {
                   1709:        struct ipv6_pool *pool;
                   1710:        struct iasubopt *lease;
                   1711:        
                   1712:        pool = (struct ipv6_pool *)vpool;
                   1713:        for (;;) {
                   1714:                /*
                   1715:                 * Get the next lease scheduled to expire.
                   1716:                 *
                   1717:                 * Note that if there are no leases in the pool, 
                   1718:                 * expire_lease6() will return ISC_R_SUCCESS with 
                   1719:                 * a NULL lease.
                   1720:                 */
                   1721:                lease = NULL;
                   1722:                if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
                   1723:                        break;
                   1724:                }
                   1725:                if (lease == NULL) {
                   1726:                        break;
                   1727:                }
                   1728: 
                   1729:                /* Look to see if there were ddns updates, and if
                   1730:                 * so, drop them.
                   1731:                 *
                   1732:                 * DH: Do we want to do this on a special 'depref'
                   1733:                 * timer rather than expiration timer?
                   1734:                 */
                   1735:                if (pool->pool_type != D6O_IA_PD) {
                   1736:                        ddns_removals(NULL, lease);
                   1737:                }
                   1738: 
                   1739:                write_ia(lease->ia);
                   1740: 
                   1741:                iasubopt_dereference(&lease, MDL);
                   1742:        }
                   1743: 
                   1744:        /*
1.1.1.1 ! misho    1745:         * If appropriate commit and rotate the lease file
        !          1746:         * As commit_leases_timed() checks to see if we've done any writes
        !          1747:         * we don't bother tracking if this function called write _ia
        !          1748:         */
        !          1749:        (void) commit_leases_timed();
        !          1750: 
        !          1751:        /*
1.1       misho    1752:         * Do some cleanup of our expired leases.
                   1753:         */
                   1754:        cleanup_old_expired(pool);
                   1755: 
                   1756:        /*
                   1757:         * Schedule next round of expirations.
                   1758:         */
                   1759:        schedule_lease_timeout(pool);
                   1760: }
                   1761: 
                   1762: /*
                   1763:  * For a given pool, add a timer that will remove the next
                   1764:  * lease to expire.
                   1765:  */
                   1766: void 
                   1767: schedule_lease_timeout(struct ipv6_pool *pool) {
                   1768:        struct iasubopt *tmp;
                   1769:        time_t timeout;
                   1770:        time_t next_timeout;
                   1771:        struct timeval tv;
                   1772: 
                   1773:        next_timeout = MAX_TIME;
                   1774: 
                   1775:        if (pool->num_active > 0) {
                   1776:                tmp = (struct iasubopt *)
                   1777:                                isc_heap_element(pool->active_timeouts, 1);
                   1778:                if (tmp->hard_lifetime_end_time < next_timeout) {
                   1779:                        next_timeout = tmp->hard_lifetime_end_time + 1;
                   1780:                }
                   1781:        }
                   1782: 
                   1783:        if (pool->num_inactive > 0) {
                   1784:                tmp = (struct iasubopt *)
                   1785:                                isc_heap_element(pool->inactive_timeouts, 1);
                   1786:                if (tmp->hard_lifetime_end_time != 0) {
                   1787:                        timeout = tmp->hard_lifetime_end_time;
                   1788:                        timeout += EXPIRED_IPV6_CLEANUP_TIME;
                   1789:                } else {
                   1790:                        timeout = tmp->soft_lifetime_end_time + 1;
                   1791:                }
                   1792:                if (timeout < next_timeout) {
                   1793:                        next_timeout = timeout;
                   1794:                }
                   1795:        }
                   1796: 
                   1797:        if (next_timeout < MAX_TIME) {
                   1798:                tv.tv_sec = next_timeout;
                   1799:                tv.tv_usec = 0;
                   1800:                add_timeout(&tv, lease_timeout_support, pool,
                   1801:                            (tvref_t)ipv6_pool_reference, 
                   1802:                            (tvunref_t)ipv6_pool_dereference);
                   1803:        }
                   1804: }
                   1805: 
                   1806: /*
                   1807:  * Schedule timeouts across all pools.
                   1808:  */
                   1809: void
                   1810: schedule_all_ipv6_lease_timeouts(void) {
                   1811:        int i;
                   1812: 
                   1813:        for (i=0; i<num_pools; i++) {
                   1814:                schedule_lease_timeout(pools[i]);
                   1815:        }
                   1816: }
                   1817: 
                   1818: /* 
                   1819:  * Given an address and the length of the network mask, return
                   1820:  * only the network portion.
                   1821:  *
                   1822:  * Examples:
                   1823:  *
                   1824:  *   "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
                   1825:  *   "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
                   1826:  */
                   1827: static void
                   1828: ipv6_network_portion(struct in6_addr *result, 
                   1829:                     const struct in6_addr *addr, int bits) {
                   1830:        unsigned char *addrp;
                   1831:        int mask_bits;
                   1832:        int bytes;
                   1833:        int extra_bits;
                   1834:        int i;
                   1835: 
                   1836:        static const unsigned char bitmasks[] = {
                   1837:                0x00, 0xFE, 0xFC, 0xF8, 
                   1838:                0xF0, 0xE0, 0xC0, 0x80, 
                   1839:        };
                   1840: 
                   1841:        /* 
                   1842:         *  Sanity check our bits. ;)
                   1843:         */
                   1844:        if ((bits < 0) || (bits > 128)) {
                   1845:                log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
                   1846:                          bits);
                   1847:        }
                   1848: 
                   1849:        /* 
                   1850:         * Copy our address portion.
                   1851:         */
                   1852:        *result = *addr;
                   1853:        addrp = ((unsigned char *)result) + 15;
                   1854: 
                   1855:        /* 
                   1856:         * Zero out masked portion.
                   1857:         */
                   1858:        mask_bits = 128 - bits;
                   1859:        bytes = mask_bits / 8;
                   1860:        extra_bits = mask_bits % 8;
                   1861: 
                   1862:        for (i=0; i<bytes; i++) {
                   1863:                *addrp = 0;
                   1864:                addrp--;
                   1865:        }
                   1866:        if (extra_bits) {
                   1867:                *addrp &= bitmasks[extra_bits];
                   1868:        }
                   1869: }
                   1870: 
                   1871: /*
                   1872:  * Determine if the given address/prefix is in the pool.
                   1873:  */
                   1874: isc_boolean_t
                   1875: ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
                   1876:        struct in6_addr tmp;
                   1877: 
                   1878:        ipv6_network_portion(&tmp, addr, pool->bits);
                   1879:        if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
                   1880:                return ISC_TRUE;
                   1881:        } else {
                   1882:                return ISC_FALSE;
                   1883:        }
                   1884: }
                   1885: 
                   1886: /*
                   1887:  * Find the pool that contains the given address.
                   1888:  *
                   1889:  * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
                   1890:  *   initialized to NULL
                   1891:  */
                   1892: isc_result_t
                   1893: find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
                   1894:               const struct in6_addr *addr) {
                   1895:        int i;
                   1896: 
                   1897:        if (pool == NULL) {
                   1898:                log_error("%s(%d): NULL pointer reference", MDL);
                   1899:                return ISC_R_INVALIDARG;
                   1900:        }
                   1901:        if (*pool != NULL) {
                   1902:                log_error("%s(%d): non-NULL pointer", MDL);
                   1903:                return ISC_R_INVALIDARG;
                   1904:        }
                   1905: 
                   1906:        for (i=0; i<num_pools; i++) {
                   1907:                if (pools[i]->pool_type != type)
                   1908:                        continue;
                   1909:                if (ipv6_in_pool(addr, pools[i])) { 
                   1910:                        ipv6_pool_reference(pool, pools[i], MDL);
                   1911:                        return ISC_R_SUCCESS;
                   1912:                }
                   1913:        }
                   1914:        return ISC_R_NOTFOUND;
                   1915: }
                   1916: 
                   1917: /*
                   1918:  * Helper function for the various functions that act across all
                   1919:  * pools.
                   1920:  */
                   1921: static isc_result_t 
                   1922: change_leases(struct ia_xx *ia, 
                   1923:              isc_result_t (*change_func)(struct ipv6_pool *,
                   1924:                                          struct iasubopt *)) {
                   1925:        isc_result_t retval;
                   1926:        isc_result_t renew_retval;
                   1927:        struct ipv6_pool *pool;
                   1928:        struct in6_addr *addr;
                   1929:        int i;
                   1930: 
                   1931:        retval = ISC_R_SUCCESS;
                   1932:        for (i=0; i<ia->num_iasubopt; i++) {
                   1933:                pool = NULL;
                   1934:                addr = &ia->iasubopt[i]->addr;
                   1935:                if (find_ipv6_pool(&pool, ia->ia_type,
                   1936:                                   addr) == ISC_R_SUCCESS) {
                   1937:                        renew_retval = change_func(pool, ia->iasubopt[i]);
                   1938:                        if (renew_retval != ISC_R_SUCCESS) {
                   1939:                                retval = renew_retval;
                   1940:                        }
                   1941:                }
                   1942:                /* XXXsk: should we warn if we don't find a pool? */
                   1943:        }
                   1944:        return retval;
                   1945: }
                   1946: 
                   1947: /*
                   1948:  * Renew all leases in an IA from all pools.
                   1949:  *
1.1.1.1 ! misho    1950:  * The new lifetime should be in the soft_lifetime_end_time
        !          1951:  * and will be moved to hard_lifetime_end_time by renew_lease6.
1.1       misho    1952:  */
                   1953: isc_result_t 
                   1954: renew_leases(struct ia_xx *ia) {
                   1955:        return change_leases(ia, renew_lease6);
                   1956: }
                   1957: 
                   1958: /*
                   1959:  * Release all leases in an IA from all pools.
                   1960:  */
                   1961: isc_result_t 
                   1962: release_leases(struct ia_xx *ia) {
                   1963:        return change_leases(ia, release_lease6);
                   1964: }
                   1965: 
                   1966: /*
                   1967:  * Decline all leases in an IA from all pools.
                   1968:  */
                   1969: isc_result_t 
                   1970: decline_leases(struct ia_xx *ia) {
                   1971:        return change_leases(ia, decline_lease6);
                   1972: }
                   1973: 
                   1974: #ifdef DHCPv6
                   1975: /*
                   1976:  * Helper function to output leases.
                   1977:  */
                   1978: static int write_error;
                   1979: 
                   1980: static isc_result_t 
                   1981: write_ia_leases(const void *name, unsigned len, void *value) {
                   1982:        struct ia_xx *ia = (struct ia_xx *)value;
                   1983:        
                   1984:        if (!write_error) { 
                   1985:                if (!write_ia(ia)) {
                   1986:                        write_error = 1;
                   1987:                }
                   1988:        }
                   1989:        return ISC_R_SUCCESS;
                   1990: }
                   1991: 
                   1992: /*
                   1993:  * Write all DHCPv6 information.
                   1994:  */
                   1995: int
                   1996: write_leases6(void) {
                   1997:        write_error = 0;
                   1998:        write_server_duid();
                   1999:        ia_hash_foreach(ia_na_active, write_ia_leases);
                   2000:        if (write_error) {
                   2001:                return 0;
                   2002:        }
                   2003:        ia_hash_foreach(ia_ta_active, write_ia_leases);
                   2004:        if (write_error) {
                   2005:                return 0;
                   2006:        }
                   2007:        ia_hash_foreach(ia_pd_active, write_ia_leases);
                   2008:        if (write_error) {
                   2009:                return 0;
                   2010:        }
                   2011:        return 1;
                   2012: }
                   2013: #endif /* DHCPv6 */
                   2014: 
                   2015: static isc_result_t
                   2016: mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
                   2017:        struct host_decl *h;
                   2018:        struct data_string fixed_addr;
                   2019:        struct in6_addr addr;
                   2020:        struct ipv6_pool *p;
                   2021: 
                   2022:        h = (struct host_decl *)value;
                   2023: 
                   2024:        /*
                   2025:         * If the host has no address, we don't need to mark anything.
                   2026:         */
                   2027:        if (h->fixed_addr == NULL) {
                   2028:                return ISC_R_SUCCESS;
                   2029:        }
                   2030: 
                   2031:        /* 
                   2032:         * Evaluate the fixed address.
                   2033:         */
                   2034:        memset(&fixed_addr, 0, sizeof(fixed_addr));
                   2035:        if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
                   2036:                                   &global_scope, h->fixed_addr, MDL)) {
                   2037:                log_error("mark_hosts_unavailable: "
                   2038:                          "error evaluating host address.");
                   2039:                return ISC_R_SUCCESS;
                   2040:        }
                   2041:        if (fixed_addr.len != 16) {
                   2042:                log_error("mark_hosts_unavailable: "
                   2043:                          "host address is not 128 bits.");
                   2044:                return ISC_R_SUCCESS;
                   2045:        }
                   2046:        memcpy(&addr, fixed_addr.data, 16);
                   2047:        data_string_forget(&fixed_addr, MDL);
                   2048: 
                   2049:        /*
                   2050:         * Find the pool holding this host, and mark the address.
                   2051:         * (I suppose it is arguably valid to have a host that does not
                   2052:         * sit in any pool.)
                   2053:         */
                   2054:        p = NULL;
                   2055:        if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
                   2056:                mark_lease_unavailable(p, &addr);
                   2057:                ipv6_pool_dereference(&p, MDL);
                   2058:        } 
                   2059:        if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
                   2060:                mark_lease_unavailable(p, &addr);
                   2061:                ipv6_pool_dereference(&p, MDL);
                   2062:        } 
                   2063: 
                   2064:        return ISC_R_SUCCESS;
                   2065: }
                   2066: 
                   2067: void
                   2068: mark_hosts_unavailable(void) {
                   2069:        hash_foreach(host_name_hash, mark_hosts_unavailable_support);
                   2070: }
                   2071: 
                   2072: static isc_result_t
                   2073: mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
                   2074:        struct host_decl *h;
                   2075:        struct iaddrcidrnetlist *l;
                   2076:        struct in6_addr pref;
                   2077:        struct ipv6_pool *p;
                   2078: 
                   2079:        h = (struct host_decl *)value;
                   2080: 
                   2081:        /*
                   2082:         * If the host has no prefix, we don't need to mark anything.
                   2083:         */
                   2084:        if (h->fixed_prefix == NULL) {
                   2085:                return ISC_R_SUCCESS;
                   2086:        }
                   2087: 
                   2088:        /* 
                   2089:         * Get the fixed prefixes.
                   2090:         */
                   2091:        for (l = h->fixed_prefix; l != NULL; l = l->next) {
                   2092:                if (l->cidrnet.lo_addr.len != 16) {
                   2093:                        continue;
                   2094:                }
                   2095:                memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
                   2096: 
                   2097:                /*
                   2098:                 * Find the pool holding this host, and mark the prefix.
                   2099:                 * (I suppose it is arguably valid to have a host that does not
                   2100:                 * sit in any pool.)
                   2101:                 */
                   2102:                p = NULL;
                   2103:                if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
                   2104:                        continue;
                   2105:                }
                   2106:                if (l->cidrnet.bits != p->units) {
                   2107:                        ipv6_pool_dereference(&p, MDL);
                   2108:                        continue;
                   2109:                }
                   2110:                mark_lease_unavailable(p, &pref);
                   2111:                ipv6_pool_dereference(&p, MDL);
                   2112:        } 
                   2113: 
                   2114:        return ISC_R_SUCCESS;
                   2115: }
                   2116: 
                   2117: void
                   2118: mark_phosts_unavailable(void) {
                   2119:        hash_foreach(host_name_hash, mark_phosts_unavailable_support);
                   2120: }
                   2121: 
                   2122: void 
                   2123: mark_interfaces_unavailable(void) {
                   2124:        struct interface_info *ip;
                   2125:        int i;
                   2126:        struct ipv6_pool *p;
                   2127: 
                   2128:        ip = interfaces;
                   2129:        while (ip != NULL) {
                   2130:                for (i=0; i<ip->v6address_count; i++) {
                   2131:                        p = NULL;
                   2132:                        if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i]) 
                   2133:                                                        == ISC_R_SUCCESS) {
                   2134:                                mark_lease_unavailable(p, 
                   2135:                                                       &ip->v6addresses[i]);
                   2136:                                ipv6_pool_dereference(&p, MDL);
                   2137:                        } 
                   2138:                        if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i]) 
                   2139:                                                        == ISC_R_SUCCESS) {
                   2140:                                mark_lease_unavailable(p, 
                   2141:                                                       &ip->v6addresses[i]);
                   2142:                                ipv6_pool_dereference(&p, MDL);
                   2143:                        } 
                   2144:                }
                   2145:                ip = ip->next;
                   2146:        }
                   2147: }
                   2148: 
1.1.1.1 ! misho    2149: /* unittest moved to server/tests/mdb6_unittest.c */

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