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

1.1       misho       1: /* mdb.c
                      2: 
                      3:    Server-specific in-memory database support. */
                      4: 
                      5: /*
1.1.1.1 ! misho       6:  * Copyright (c) 2011-2012 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       7:  * Copyright (c) 2004-2009 by Internet Systems Consortium, Inc. ("ISC")
                      8:  * Copyright (c) 1996-2003 by Internet Software Consortium
                      9:  *
                     10:  * Permission to use, copy, modify, and distribute this software for any
                     11:  * purpose with or without fee is hereby granted, provided that the above
                     12:  * copyright notice and this permission notice appear in all copies.
                     13:  *
                     14:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
                     15:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     16:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
                     17:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     18:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     19:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
                     20:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     21:  *
                     22:  *   Internet Systems Consortium, Inc.
                     23:  *   950 Charter Street
                     24:  *   Redwood City, CA 94063
                     25:  *   <info@isc.org>
                     26:  *   https://www.isc.org/
                     27:  *
                     28:  * This software has been written for Internet Systems Consortium
                     29:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
                     30:  * To learn more about Internet Systems Consortium, see
                     31:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
                     32:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
                     33:  * ``http://www.nominum.com''.
                     34:  */
                     35: 
                     36: #include "dhcpd.h"
                     37: #include "omapip/hash.h"
                     38: 
                     39: struct subnet *subnets;
                     40: struct shared_network *shared_networks;
                     41: host_hash_t *host_hw_addr_hash;
                     42: host_hash_t *host_uid_hash;
                     43: host_hash_t *host_name_hash;
                     44: lease_id_hash_t *lease_uid_hash;
                     45: lease_ip_hash_t *lease_ip_addr_hash;
                     46: lease_id_hash_t *lease_hw_addr_hash;
                     47: 
                     48: /*
                     49:  * We allow users to specify any option as a host identifier.
                     50:  *
                     51:  * Any host is uniquely identified by the combination of 
                     52:  * option type & option data.
                     53:  *
                     54:  * We expect people will only use a few types of options as host 
                     55:  * identifier. Because of this, we store a list with an entry for
                     56:  * each option type. Each of these has a hash table, which contains 
                     57:  * hash of the option data.
                     58:  */
                     59: typedef struct host_id_info {
                     60:        struct option *option;
                     61:        host_hash_t *values_hash;
                     62:        struct host_id_info *next;
                     63: } host_id_info_t;
                     64: 
                     65: static host_id_info_t *host_id_info = NULL;
                     66: 
                     67: int numclasseswritten;
                     68: 
                     69: omapi_object_type_t *dhcp_type_host;
                     70: 
                     71: isc_result_t enter_class(cd, dynamicp, commit)
                     72:        struct class *cd;
                     73:        int dynamicp;
                     74:        int commit;
                     75: {
                     76:        if (!collections -> classes) {
                     77:                /* A subclass with no parent is invalid. */
                     78:                if (cd->name == NULL)
                     79:                        return ISC_R_INVALIDARG;
                     80: 
                     81:                class_reference (&collections -> classes, cd, MDL);
                     82:        } else if (cd->name != NULL) {  /* regular class */
                     83:                struct class *c = 0;
                     84: 
                     85:                if (find_class(&c, cd->name, MDL) != ISC_R_NOTFOUND) {
                     86:                        class_dereference(&c, MDL);
                     87:                        return ISC_R_EXISTS;
                     88:                }
                     89:                
                     90:                /* Find the tail. */
                     91:                for (c = collections -> classes;
                     92:                     c -> nic; c = c -> nic)
                     93:                        /* nothing */ ;
                     94:                class_reference (&c -> nic, cd, MDL);
                     95:        }
                     96: 
                     97:        if (dynamicp && commit) {
                     98:                const char *name = cd->name;
                     99: 
                    100:                if (name == NULL) {
                    101:                        name = cd->superclass->name;
                    102:                }
                    103: 
                    104:                write_named_billing_class ((const unsigned char *)name, 0, cd);
                    105:                if (!commit_leases ())
                    106:                        return ISC_R_IOERROR;
                    107:        }
                    108: 
                    109:        return ISC_R_SUCCESS;
                    110: }
                    111: 
                    112: 
                    113: /* Variable to check if we're starting the server.  The server will init as
                    114:  * starting - but just to be safe start out as false to avoid triggering new
                    115:  * special-case code
                    116:  * XXX: There is actually a server_startup state...which is never entered...
                    117:  */
                    118: #define SS_NOSYNC      1
                    119: #define SS_QFOLLOW     2
                    120: static int server_starting = 0;
                    121: 
                    122: static int find_uid_statement (struct executable_statement *esp,
                    123:                               void *vp, int condp)
                    124: {
                    125:        struct executable_statement **evp = vp;
                    126: 
                    127:        if (esp -> op == supersede_option_statement &&
                    128:            esp -> data.option &&
                    129:            (esp -> data.option -> option -> universe ==
                    130:             &dhcp_universe) &&
                    131:            (esp -> data.option -> option -> code ==
                    132:             DHO_DHCP_CLIENT_IDENTIFIER)) {
                    133:                if (condp) {
                    134:                        log_error ("dhcp client identifier may not be %s",
                    135:                                   "specified conditionally.");
                    136:                } else if (!(*evp)) {
                    137:                        executable_statement_reference (evp, esp, MDL);
                    138:                        return 1;
                    139:                } else {
                    140:                        log_error ("only one dhcp client identifier may be %s",
                    141:                                   "specified");
                    142:                }
                    143:        }
                    144:        return 0;
                    145: }
                    146: 
                    147: 
                    148: static host_id_info_t *
                    149: find_host_id_info(unsigned int option_code) {
                    150:        host_id_info_t *p;
                    151: 
                    152:        for (p=host_id_info; p != NULL; p = p->next) {
                    153:                if (p->option->code == option_code) {
                    154:                        break;
                    155:                }
                    156:        }
                    157:        return p;
                    158: }
                    159: 
                    160: /* Debugging code */
                    161: #if 0
                    162: isc_result_t
                    163: print_host(const void *name, unsigned len, void *value) {
                    164:        struct host_decl *h;
                    165:        printf("--------------\n");
                    166:        printf("name:'%s'\n", print_hex_1(len, name, 60));
                    167:        printf("len:%d\n", len);
                    168:        h = (struct host_decl *)value;
                    169:        printf("host @%p is '%s'\n", h, h->name);
                    170:        return ISC_R_SUCCESS;
                    171: }
                    172: 
                    173: void
                    174: hash_print_hosts(struct hash_table *h) {
                    175:        hash_foreach(h, print_host);
                    176:        printf("--------------\n");
                    177: }
                    178: #endif /* 0 */
                    179: 
                    180: void
                    181: change_host_uid(struct host_decl *host, const char *uid, int len) {
                    182:        /* XXX: should consolidate this type of code throughout */
                    183:        if (host_uid_hash == NULL) {
                    184:                if (!host_new_hash(&host_uid_hash, HOST_HASH_SIZE, MDL)) {
                    185:                        log_fatal("Can't allocate host/uid hash");
                    186:                }
                    187:        }
                    188: 
                    189:        /* 
                    190:         * Remove the old entry, if one exists.
                    191:         */
                    192:        if (host->client_identifier.data != NULL) {
                    193:                host_hash_delete(host_uid_hash,
                    194:                                 host->client_identifier.data,
                    195:                                 host->client_identifier.len,
                    196:                                 MDL);
                    197:                data_string_forget(&host->client_identifier, MDL);
                    198:        }
                    199: 
                    200:        /* 
                    201:         * Set our new value.
                    202:         */
                    203:        memset(&host->client_identifier, 0, sizeof(host->client_identifier));
                    204:        host->client_identifier.len = len;
                    205:        if (!buffer_allocate(&host->client_identifier.buffer, len, MDL)) {
                    206:                log_fatal("Can't allocate uid buffer");
                    207:        }
                    208:        host->client_identifier.data = host->client_identifier.buffer->data;
                    209:        memcpy((char *)host->client_identifier.data, uid, len);
                    210: 
                    211:        /*
                    212:         * And add to hash.
                    213:         */
                    214:        host_hash_add(host_uid_hash, host->client_identifier.data, 
                    215:                      host->client_identifier.len, host, MDL);
                    216: }
                    217: 
                    218: isc_result_t enter_host (hd, dynamicp, commit)
                    219:        struct host_decl *hd;
                    220:        int dynamicp;
                    221:        int commit;
                    222: {
                    223:        struct host_decl *hp = (struct host_decl *)0;
                    224:        struct host_decl *np = (struct host_decl *)0;
                    225:        struct executable_statement *esp;
                    226:        host_id_info_t *h_id_info;
                    227: 
                    228:        if (!host_name_hash) {
                    229:                if (!host_new_hash(&host_name_hash, HOST_HASH_SIZE, MDL))
                    230:                        log_fatal ("Can't allocate host name hash");
                    231:                host_hash_add (host_name_hash,
                    232:                               (unsigned char *)hd -> name,
                    233:                               strlen (hd -> name), hd, MDL);
                    234:        } else {
                    235:                host_hash_lookup (&hp, host_name_hash,
                    236:                                  (unsigned char *)hd -> name,
                    237:                                  strlen (hd -> name), MDL);
                    238: 
                    239:                /* If it's deleted, we can supersede it. */
                    240:                if (hp && (hp -> flags & HOST_DECL_DELETED)) {
                    241:                        host_hash_delete (host_name_hash,
                    242:                                          (unsigned char *)hd -> name,
                    243:                                          strlen (hd -> name), MDL);
                    244:                        /* If the old entry wasn't dynamic, then we
                    245:                           always have to keep the deletion. */
                    246:                        if (hp -> flags & HOST_DECL_STATIC) {
                    247:                                hd -> flags |= HOST_DECL_STATIC;
                    248:                        }
                    249:                        host_dereference (&hp, MDL);
                    250:                }
                    251: 
                    252:                /* If we are updating an existing host declaration, we
                    253:                   can just delete it and add it again. */
                    254:                if (hp && hp == hd) {
                    255:                        host_dereference (&hp, MDL);
                    256:                        delete_host (hd, 0);
                    257:                        if (!write_host (hd))
                    258:                                return ISC_R_IOERROR;
                    259:                        hd -> flags &= ~HOST_DECL_DELETED;
                    260:                }
                    261: 
                    262:                /* If there isn't already a host decl matching this
                    263:                   address, add it to the hash table. */
                    264:                if (!hp) {
                    265:                        host_hash_add (host_name_hash,
                    266:                                       (unsigned char *)hd -> name,
                    267:                                       strlen (hd -> name), hd, MDL);
                    268:                } else {
                    269:                        /* XXX actually, we have to delete the old one
                    270:                           XXX carefully and replace it.   Not done yet. */
                    271:                        host_dereference (&hp, MDL);
                    272:                        return ISC_R_EXISTS;
                    273:                }
                    274:        }
                    275: 
                    276:        if (hd -> n_ipaddr)
                    277:                host_dereference (&hd -> n_ipaddr, MDL);
                    278: 
                    279:        if (!hd -> type)
                    280:                hd -> type = dhcp_type_host;
                    281: 
                    282:        if (hd -> interface.hlen) {
                    283:                if (!host_hw_addr_hash) {
                    284:                        if (!host_new_hash(&host_hw_addr_hash,
                    285:                                           HOST_HASH_SIZE, MDL))
                    286:                                log_fatal ("Can't allocate host/hw hash");
                    287:                } else {
                    288:                        /* If there isn't already a host decl matching this
                    289:                           address, add it to the hash table. */
                    290:                        host_hash_lookup (&hp, host_hw_addr_hash,
                    291:                                          hd -> interface.hbuf,
                    292:                                          hd -> interface.hlen, MDL);
                    293:                }
                    294:                if (!hp)
                    295:                        host_hash_add (host_hw_addr_hash, hd -> interface.hbuf,
                    296:                                       hd -> interface.hlen, hd, MDL);
                    297:                else {
                    298:                        /* If there was already a host declaration for
                    299:                           this hardware address, add this one to the
                    300:                           end of the list. */
                    301:                        for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr)
                    302:                                ;
                    303:                        host_reference (&np -> n_ipaddr, hd, MDL);
                    304:                        host_dereference (&hp, MDL);
                    305:                }
                    306:        }
                    307: 
                    308:        /* See if there's a statement that sets the client identifier.
                    309:           This is a kludge - the client identifier really shouldn't be
                    310:           set with an executable statement. */
                    311:        esp = (struct executable_statement *)0;
                    312:        if (executable_statement_foreach (hd -> group -> statements,
                    313:                                          find_uid_statement, &esp, 0)) {
                    314:                evaluate_option_cache (&hd -> client_identifier,
                    315:                                       (struct packet *)0,
                    316:                                       (struct lease *)0,
                    317:                                       (struct client_state *)0,
                    318:                                       (struct option_state *)0,
                    319:                                       (struct option_state *)0, &global_scope,
                    320:                                       esp -> data.option, MDL);
                    321:        }
                    322: 
                    323:        /* If we got a client identifier, hash this entry by
                    324:           client identifier. */
                    325:        if (hd -> client_identifier.len) {
                    326:                /* If there's no uid hash, make one; otherwise, see if
                    327:                   there's already an entry in the hash for this host. */
                    328:                if (!host_uid_hash) {
                    329:                        if (!host_new_hash(&host_uid_hash,
                    330:                                           HOST_HASH_SIZE, MDL))
                    331:                                log_fatal ("Can't allocate host/uid hash");
                    332: 
                    333:                        host_hash_add (host_uid_hash,
                    334:                                       hd -> client_identifier.data,
                    335:                                       hd -> client_identifier.len,
                    336:                                       hd, MDL);
                    337:                } else {
                    338:                        /* If there's already a host declaration for this
                    339:                           client identifier, add this one to the end of the
                    340:                           list.  Otherwise, add it to the hash table. */
                    341:                        if (host_hash_lookup (&hp, host_uid_hash,
                    342:                                              hd -> client_identifier.data,
                    343:                                              hd -> client_identifier.len,
                    344:                                              MDL)) {
                    345:                                /* Don't link it in twice... */
                    346:                                if (!np) {
                    347:                                        for (np = hp; np -> n_ipaddr;
                    348:                                             np = np -> n_ipaddr) {
                    349:                                                if (hd == np)
                    350:                                                    break;
                    351:                                        }
                    352:                                        if (hd != np)
                    353:                                            host_reference (&np -> n_ipaddr,
                    354:                                                            hd, MDL);
                    355:                                }
                    356:                                host_dereference (&hp, MDL);
                    357:                        } else {
                    358:                                host_hash_add (host_uid_hash,
                    359:                                               hd -> client_identifier.data,
                    360:                                               hd -> client_identifier.len,
                    361:                                               hd, MDL);
                    362:                        }
                    363:                }
                    364:        }
                    365: 
                    366: 
                    367:        /*
                    368:         * If we use an option as our host identifier, record it here.
                    369:         */
                    370:        if (hd->host_id_option != NULL) {
                    371:                /*
                    372:                 * Look for the host identifier information for this option,
                    373:                 * and create a new entry if there is none.
                    374:                 */
                    375:                h_id_info = find_host_id_info(hd->host_id_option->code);
                    376:                if (h_id_info == NULL) {
                    377:                        h_id_info = dmalloc(sizeof(*h_id_info), MDL);
                    378:                        if (h_id_info == NULL) {
                    379:                                log_fatal("No memory for host-identifier "
                    380:                                          "option information.");
                    381:                        }
                    382:                        option_reference(&h_id_info->option, 
                    383:                                         hd->host_id_option, MDL);
                    384:                        if (!host_new_hash(&h_id_info->values_hash, 
                    385:                                           HOST_HASH_SIZE, MDL)) {
                    386:                                log_fatal("No memory for host-identifier "
                    387:                                          "option hash.");
                    388:                        }
                    389:                        h_id_info->next = host_id_info;
                    390:                        host_id_info = h_id_info;
                    391:                }
                    392: 
                    393:                if (host_hash_lookup(&hp, h_id_info->values_hash, 
                    394:                                     hd->host_id.data, hd->host_id.len, MDL)) {
                    395:                        /* 
                    396:                         * If this option is already present, then add 
                    397:                         * this host to the list in n_ipaddr, unless
                    398:                         * we have already done so previously.
                    399:                         *
                    400:                         * XXXSK: This seems scary to me, but I don't
                    401:                         *        fully understand how these are used. 
                    402:                         *        Shouldn't there be multiple lists, or 
                    403:                         *        maybe we should just forbid duplicates?
                    404:                         */
                    405:                        if (np == NULL) {
                    406:                                np = hp;
                    407:                                while (np->n_ipaddr != NULL) {
                    408:                                        np = np->n_ipaddr;
                    409:                                }
                    410:                                if (hd != np) {
                    411:                                        host_reference(&np->n_ipaddr, hd, MDL);
                    412:                                }
                    413:                        }
                    414:                        host_dereference(&hp, MDL);
                    415:                } else {
                    416:                        host_hash_add(h_id_info->values_hash, 
                    417:                                      hd->host_id.data,
                    418:                                      hd->host_id.len,
                    419:                                      hd, MDL);
                    420:                }
                    421:        }
                    422: 
                    423:        if (dynamicp && commit) {
                    424:                if (!write_host (hd))
                    425:                        return ISC_R_IOERROR;
                    426:                if (!commit_leases ())
                    427:                        return ISC_R_IOERROR;
                    428:        }
                    429: 
                    430:        return ISC_R_SUCCESS;
                    431: }
                    432: 
                    433: 
                    434: isc_result_t delete_class (cp, commit)
                    435:        struct class *cp;
                    436:        int commit;
                    437: {
                    438:        cp->flags |= CLASS_DECL_DELETED;
                    439: 
                    440:        /* do the write first as we won't be leaving it in any data
                    441:           structures, unlike the host objects */
                    442:        
                    443:        if (commit) {
                    444:                write_named_billing_class ((unsigned char *)cp->name, 0, cp);
                    445:                if (!commit_leases ())
                    446:                        return ISC_R_IOERROR;
                    447:        }
                    448:        
                    449:        unlink_class(&cp);              /* remove from collections */
                    450: 
                    451:        class_dereference(&cp, MDL);
                    452: 
                    453:        return ISC_R_SUCCESS;
                    454: }
                    455: 
                    456: 
                    457: isc_result_t delete_host (hd, commit)
                    458:        struct host_decl *hd;
                    459:        int commit;
                    460: {
                    461:        struct host_decl *hp = (struct host_decl *)0;
                    462:        struct host_decl *np = (struct host_decl *)0;
                    463:        struct host_decl *foo;
                    464:        int hw_head = 0, uid_head = 1;
                    465: 
                    466:        /* Don't need to do it twice. */
                    467:        if (hd -> flags & HOST_DECL_DELETED)
                    468:                return ISC_R_SUCCESS;
                    469: 
                    470:        /* But we do need to do it once!   :') */
                    471:        hd -> flags |= HOST_DECL_DELETED;
                    472: 
                    473:        if (hd -> interface.hlen) {
                    474:            if (host_hw_addr_hash) {
                    475:                if (host_hash_lookup (&hp, host_hw_addr_hash,
                    476:                                      hd -> interface.hbuf,
                    477:                                      hd -> interface.hlen, MDL)) {
                    478:                    if (hp == hd) {
                    479:                        host_hash_delete (host_hw_addr_hash,
                    480:                                          hd -> interface.hbuf,
                    481:                                          hd -> interface.hlen, MDL);
                    482:                        hw_head = 1;
                    483:                    } else {
                    484:                        np = (struct host_decl *)0;
                    485:                        foo = (struct host_decl *)0;
                    486:                        host_reference (&foo, hp, MDL);
                    487:                        while (foo) {
                    488:                            if (foo == hd)
                    489:                                    break;
                    490:                            if (np)
                    491:                                    host_dereference (&np, MDL);
                    492:                            host_reference (&np, foo, MDL);
                    493:                            host_dereference (&foo, MDL);
                    494:                            if (np -> n_ipaddr)
                    495:                                    host_reference (&foo, np -> n_ipaddr, MDL);
                    496:                        }
                    497: 
                    498:                        if (foo) {
                    499:                            host_dereference (&np -> n_ipaddr, MDL);
                    500:                            if (hd -> n_ipaddr)
                    501:                                host_reference (&np -> n_ipaddr,
                    502:                                                hd -> n_ipaddr, MDL);
                    503:                            host_dereference (&foo, MDL);
                    504:                        }
                    505:                        if (np)
                    506:                                host_dereference (&np, MDL);
                    507:                    }
                    508:                    host_dereference (&hp, MDL);
                    509:                }
                    510:            }
                    511:        }
                    512: 
                    513:        /* If we got a client identifier, hash this entry by
                    514:           client identifier. */
                    515:        if (hd -> client_identifier.len) {
                    516:            if (host_uid_hash) {
                    517:                if (host_hash_lookup (&hp, host_uid_hash,
                    518:                                      hd -> client_identifier.data,
                    519:                                      hd -> client_identifier.len, MDL)) {
                    520:                    if (hp == hd) {
                    521:                        host_hash_delete (host_uid_hash,
                    522:                                          hd -> client_identifier.data,
                    523:                                          hd -> client_identifier.len, MDL);
                    524:                        uid_head = 1;
                    525:                    } else {
                    526:                        np = (struct host_decl *)0;
                    527:                        foo = (struct host_decl *)0;
                    528:                        host_reference (&foo, hp, MDL);
                    529:                        while (foo) {
                    530:                            if (foo == hd)
                    531:                                    break;
                    532:                            if (np)
                    533:                                host_dereference (&np, MDL);
                    534:                            host_reference (&np, foo, MDL);
                    535:                            host_dereference (&foo, MDL);
                    536:                            if (np -> n_ipaddr)
                    537:                                    host_reference (&foo, np -> n_ipaddr, MDL);
                    538:                        }
                    539: 
                    540:                        if (foo) {
                    541:                            host_dereference (&np -> n_ipaddr, MDL);
                    542:                            if (hd -> n_ipaddr)
                    543:                                host_reference (&np -> n_ipaddr,
                    544:                                                hd -> n_ipaddr, MDL);
                    545:                            host_dereference (&foo, MDL);
                    546:                        }
                    547:                        if (np)
                    548:                                host_dereference (&np, MDL);
                    549:                    }
                    550:                    host_dereference (&hp, MDL);
                    551:                }
                    552:            }
                    553:        }
                    554: 
                    555:        if (hd->host_id_option != NULL) {
                    556:                option_dereference(&hd->host_id_option, MDL);
                    557:                data_string_forget(&hd->host_id, MDL);
                    558:        }
                    559: 
                    560:        if (hd -> n_ipaddr) {
                    561:                if (uid_head && hd -> n_ipaddr -> client_identifier.len) {
                    562:                        host_hash_add
                    563:                                (host_uid_hash,
                    564:                                 hd -> n_ipaddr -> client_identifier.data,
                    565:                                 hd -> n_ipaddr -> client_identifier.len,
                    566:                                 hd -> n_ipaddr, MDL);
                    567:                }
                    568:                if (hw_head && hd -> n_ipaddr -> interface.hlen) {
                    569:                        host_hash_add (host_hw_addr_hash,
                    570:                                       hd -> n_ipaddr -> interface.hbuf,
                    571:                                       hd -> n_ipaddr -> interface.hlen,
                    572:                                       hd -> n_ipaddr, MDL);
                    573:                }
                    574:                host_dereference (&hd -> n_ipaddr, MDL);
                    575:        }
                    576: 
                    577:        if (host_name_hash) {
                    578:                if (host_hash_lookup (&hp, host_name_hash,
                    579:                                      (unsigned char *)hd -> name,
                    580:                                      strlen (hd -> name), MDL)) {
                    581:                        if (hp == hd && !(hp -> flags & HOST_DECL_STATIC)) {
                    582:                                host_hash_delete (host_name_hash,
                    583:                                                  (unsigned char *)hd -> name,
                    584:                                                  strlen (hd -> name), MDL);
                    585:                        }
                    586:                        host_dereference (&hp, MDL);
                    587:                }
                    588:        }
                    589: 
                    590:        if (commit) {
                    591:                if (!write_host (hd))
                    592:                        return ISC_R_IOERROR;
                    593:                if (!commit_leases ())
                    594:                        return ISC_R_IOERROR;
                    595:        }
                    596:        return ISC_R_SUCCESS;
                    597: }
                    598: 
                    599: int find_hosts_by_haddr (struct host_decl **hp, int htype,
                    600:                         const unsigned char *haddr, unsigned hlen,
                    601:                         const char *file, int line)
                    602: {
                    603:        struct hardware h;
                    604: 
                    605:        h.hlen = hlen + 1;
                    606:        h.hbuf [0] = htype;
                    607:        memcpy (&h.hbuf [1], haddr, hlen);
                    608: 
                    609:        return host_hash_lookup (hp, host_hw_addr_hash,
                    610:                                 h.hbuf, h.hlen, file, line);
                    611: }
                    612: 
                    613: int find_hosts_by_uid (struct host_decl **hp,
                    614:                       const unsigned char *data, unsigned len,
                    615:                       const char *file, int line)
                    616: {
                    617:        return host_hash_lookup (hp, host_uid_hash, data, len, file, line);
                    618: }
                    619: 
                    620: int
                    621: find_hosts_by_option(struct host_decl **hp, 
                    622:                     struct packet *packet,
                    623:                     struct option_state *opt_state,
                    624:                     const char *file, int line) {
                    625:        host_id_info_t *p;
                    626:        struct option_cache *oc;
                    627:        struct data_string data;
                    628:        int found;
                    629:        
                    630:        for (p = host_id_info; p != NULL; p = p->next) {
                    631:                oc = lookup_option(p->option->universe, 
                    632:                                   opt_state, p->option->code);
                    633:                if (oc != NULL) {
                    634:                        memset(&data, 0, sizeof(data));
                    635:                        if (!evaluate_option_cache(&data, packet, NULL, NULL,
                    636:                                                   opt_state, NULL,
                    637:                                                   &global_scope, oc, 
                    638:                                                   MDL)) {
                    639:                                log_error("Error evaluating option cache");
                    640:                                return 0;
                    641:                        }
                    642:                        
                    643:                        found = host_hash_lookup(hp, p->values_hash, 
                    644:                                                 data.data, data.len,
                    645:                                                 file, line);
                    646: 
                    647:                        data_string_forget(&data, MDL);
                    648: 
                    649:                        if (found) {
                    650:                                return 1;
                    651:                        }
                    652:                }
                    653:        }
                    654:        return 0;
                    655: }
                    656: 
                    657: /* More than one host_decl can be returned by find_hosts_by_haddr or
                    658:    find_hosts_by_uid, and each host_decl can have multiple addresses.
                    659:    Loop through the list of hosts, and then for each host, through the
                    660:    list of addresses, looking for an address that's in the same shared
                    661:    network as the one specified.    Store the matching address through
                    662:    the addr pointer, update the host pointer to point at the host_decl
                    663:    that matched, and return the subnet that matched. */
                    664: 
                    665: int find_host_for_network (struct subnet **sp, struct host_decl **host,
                    666:                           struct iaddr *addr, struct shared_network *share)
                    667: {
                    668:        int i;
                    669:        struct iaddr ip_address;
                    670:        struct host_decl *hp;
                    671:        struct data_string fixed_addr;
                    672: 
                    673:        memset (&fixed_addr, 0, sizeof fixed_addr);
                    674: 
                    675:        for (hp = *host; hp; hp = hp -> n_ipaddr) {
                    676:                if (!hp -> fixed_addr)
                    677:                        continue;
                    678:                if (!evaluate_option_cache (&fixed_addr, (struct packet *)0,
                    679:                                            (struct lease *)0,
                    680:                                            (struct client_state *)0,
                    681:                                            (struct option_state *)0,
                    682:                                            (struct option_state *)0,
                    683:                                            &global_scope,
                    684:                                            hp -> fixed_addr, MDL))
                    685:                        continue;
                    686:                for (i = 0; i < fixed_addr.len; i += 4) {
                    687:                        ip_address.len = 4;
                    688:                        memcpy (ip_address.iabuf,
                    689:                                fixed_addr.data + i, 4);
                    690:                        if (find_grouped_subnet (sp, share, ip_address, MDL)) {
                    691:                                struct host_decl *tmp = (struct host_decl *)0;
                    692:                                *addr = ip_address;
                    693:                                /* This is probably not necessary, but
                    694:                                   just in case *host is the only reference
                    695:                                   to that host declaration, make a temporary
                    696:                                   reference so that dereferencing it doesn't
                    697:                                   dereference hp out from under us. */
                    698:                                host_reference (&tmp, *host, MDL);
                    699:                                host_dereference (host, MDL);
                    700:                                host_reference (host, hp, MDL);
                    701:                                host_dereference (&tmp, MDL);
                    702:                                data_string_forget (&fixed_addr, MDL);
                    703:                                return 1;
                    704:                        }
                    705:                }
                    706:                data_string_forget (&fixed_addr, MDL);
                    707:        }
                    708:        return 0;
                    709: }
                    710: 
                    711: void new_address_range (cfile, low, high, subnet, pool, lpchain)
                    712:        struct parse *cfile;
                    713:        struct iaddr low, high;
                    714:        struct subnet *subnet;
                    715:        struct pool *pool;
                    716:        struct lease **lpchain;
                    717: {
                    718: #if defined(COMPACT_LEASES)
                    719:        struct lease *address_range;
                    720: #endif
                    721:        unsigned min, max, i;
                    722:        char lowbuf [16], highbuf [16], netbuf [16];
                    723:        struct shared_network *share = subnet -> shared_network;
                    724:        struct lease *lt = (struct lease *)0;
                    725: #if !defined(COMPACT_LEASES)
                    726:        isc_result_t status;
                    727: #endif
                    728: 
                    729:        /* All subnets should have attached shared network structures. */
                    730:        if (!share) {
                    731:                strcpy (netbuf, piaddr (subnet -> net));
                    732:                log_fatal ("No shared network for network %s (%s)",
                    733:                       netbuf, piaddr (subnet -> netmask));
                    734:        }
                    735: 
                    736:        /* Initialize the hash table if it hasn't been done yet. */
                    737:        if (!lease_uid_hash) {
                    738:                if (!lease_id_new_hash(&lease_uid_hash, LEASE_HASH_SIZE, MDL))
                    739:                        log_fatal ("Can't allocate lease/uid hash");
                    740:        }
                    741:        if (!lease_ip_addr_hash) {
                    742:                if (!lease_ip_new_hash(&lease_ip_addr_hash, LEASE_HASH_SIZE,
                    743:                                       MDL))
                    744:                        log_fatal ("Can't allocate lease/ip hash");
                    745:        }
                    746:        if (!lease_hw_addr_hash) {
                    747:                if (!lease_id_new_hash(&lease_hw_addr_hash, LEASE_HASH_SIZE,
                    748:                                       MDL))
                    749:                        log_fatal ("Can't allocate lease/hw hash");
                    750:        }
                    751: 
                    752:        /* Make sure that high and low addresses are in this subnet. */
                    753:        if (!addr_eq(subnet->net, subnet_number(low, subnet->netmask))) {
                    754:                strcpy(lowbuf, piaddr(low));
                    755:                strcpy(netbuf, piaddr(subnet->net));
                    756:                log_fatal("bad range, address %s not in subnet %s netmask %s",
                    757:                          lowbuf, netbuf, piaddr(subnet->netmask));
                    758:        }
                    759: 
                    760:        if (!addr_eq(subnet->net, subnet_number(high, subnet->netmask))) {
                    761:                strcpy(highbuf, piaddr(high));
                    762:                strcpy(netbuf, piaddr(subnet->net));
                    763:                log_fatal("bad range, address %s not in subnet %s netmask %s",
                    764:                          highbuf, netbuf, piaddr(subnet->netmask));
                    765:        }
                    766: 
                    767:        /* Get the high and low host addresses... */
                    768:        max = host_addr (high, subnet -> netmask);
                    769:        min = host_addr (low, subnet -> netmask);
                    770: 
                    771:        /* Allow range to be specified high-to-low as well as low-to-high. */
                    772:        if (min > max) {
                    773:                max = min;
                    774:                min = host_addr (high, subnet -> netmask);
                    775:        }
                    776: 
                    777:        /* Get a lease structure for each address in the range. */
                    778: #if defined (COMPACT_LEASES)
                    779:        address_range = new_leases (max - min + 1, MDL);
                    780:        if (!address_range) {
                    781:                strcpy (lowbuf, piaddr (low));
                    782:                strcpy (highbuf, piaddr (high));
                    783:                log_fatal ("No memory for address range %s-%s.",
                    784:                           lowbuf, highbuf);
                    785:        }
                    786: #endif
                    787: 
                    788:        /* Fill out the lease structures with some minimal information. */
                    789:        for (i = 0; i < max - min + 1; i++) {
                    790:                struct lease *lp = (struct lease *)0;
                    791: #if defined (COMPACT_LEASES)
                    792:                omapi_object_initialize ((omapi_object_t *)&address_range [i],
                    793:                                         dhcp_type_lease,
                    794:                                         0, sizeof (struct lease), MDL);
                    795:                lease_reference (&lp, &address_range [i], MDL);
                    796: #else
                    797:                status = lease_allocate (&lp, MDL);
                    798:                if (status != ISC_R_SUCCESS)
                    799:                        log_fatal ("No memory for lease %s: %s",
                    800:                                   piaddr (ip_addr (subnet -> net,
                    801:                                                    subnet -> netmask,
                    802:                                                    i + min)),
                    803:                                   isc_result_totext (status));
                    804: #endif
                    805:                lp -> ip_addr = ip_addr (subnet -> net,
                    806:                                         subnet -> netmask, i + min);
                    807:                lp -> starts = MIN_TIME;
                    808:                lp -> ends = MIN_TIME;
                    809:                subnet_reference (&lp -> subnet, subnet, MDL);
                    810:                pool_reference (&lp -> pool, pool, MDL);
                    811:                lp -> binding_state = FTS_FREE;
                    812:                lp -> next_binding_state = FTS_FREE;
                    813:                lp -> flags = 0;
                    814: 
                    815:                /* Remember the lease in the IP address hash. */
                    816:                if (find_lease_by_ip_addr (&lt, lp -> ip_addr, MDL)) {
                    817:                        if (lt -> pool) {
                    818:                                parse_warn (cfile,
                    819:                                            "lease %s is declared twice!",
                    820:                                            piaddr (lp -> ip_addr));
                    821:                        } else
                    822:                                pool_reference (&lt -> pool, pool, MDL);
                    823:                        lease_dereference (&lt, MDL);
                    824:                } else
                    825:                        lease_ip_hash_add(lease_ip_addr_hash,
                    826:                                          lp->ip_addr.iabuf, lp->ip_addr.len,
                    827:                                          lp, MDL);
                    828:                /* Put the lease on the chain for the caller. */
                    829:                if (lpchain) {
                    830:                        if (*lpchain) {
                    831:                                lease_reference (&lp -> next, *lpchain, MDL);
                    832:                                lease_dereference (lpchain, MDL);
                    833:                        }
                    834:                        lease_reference (lpchain, lp, MDL);
                    835:                }
                    836:                lease_dereference (&lp, MDL);
                    837:        }
                    838: }
                    839: 
                    840: int find_subnet (struct subnet **sp,
                    841:                 struct iaddr addr, const char *file, int line)
                    842: {
                    843:        struct subnet *rv;
                    844: 
                    845:        for (rv = subnets; rv; rv = rv -> next_subnet) {
                    846:                if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
                    847:                        if (subnet_reference (sp, rv,
                    848:                                              file, line) != ISC_R_SUCCESS)
                    849:                                return 0;
                    850:                        return 1;
                    851:                }
                    852:        }
                    853:        return 0;
                    854: }
                    855: 
                    856: int find_grouped_subnet (struct subnet **sp,
                    857:                         struct shared_network *share, struct iaddr addr,
                    858:                         const char *file, int line)
                    859: {
                    860:        struct subnet *rv;
                    861: 
                    862:        for (rv = share -> subnets; rv; rv = rv -> next_sibling) {
                    863:                if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
                    864:                        if (subnet_reference (sp, rv,
                    865:                                              file, line) != ISC_R_SUCCESS)
                    866:                                return 0;
                    867:                        return 1;
                    868:                }
                    869:        }
                    870:        return 0;
                    871: }
                    872: 
                    873: /* XXX: could speed up if everyone had a prefix length */
                    874: int 
                    875: subnet_inner_than(const struct subnet *subnet, 
                    876:                  const struct subnet *scan,
                    877:                  int warnp) {
                    878:        if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) ||
                    879:            addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) {
                    880:                char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")];
                    881:                int i, j;
                    882:                for (i = 0; i < 128; i++)
                    883:                        if (subnet->netmask.iabuf[3 - (i >> 3)]
                    884:                            & (1 << (i & 7)))
                    885:                                break;
                    886:                for (j = 0; j < 128; j++)
                    887:                        if (scan->netmask.iabuf[3 - (j >> 3)] &
                    888:                            (1 << (j & 7)))
                    889:                                break;
                    890:                if (warnp) {
                    891:                        strcpy(n1buf, piaddr(subnet->net));
                    892:                        log_error("Warning: subnet %s/%d overlaps subnet %s/%d",
                    893:                              n1buf, 32 - i,
                    894:                              piaddr(scan->net), 32 - j);
                    895:                }
                    896:                if (i < j)
                    897:                        return 1;
                    898:        }
                    899:        return 0;
                    900: }
                    901: 
                    902: /* Enter a new subnet into the subnet list. */
                    903: void enter_subnet (subnet)
                    904:        struct subnet *subnet;
                    905: {
                    906:        struct subnet *scan = (struct subnet *)0;
                    907:        struct subnet *next = (struct subnet *)0;
                    908:        struct subnet *prev = (struct subnet *)0;
                    909: 
                    910:        /* Check for duplicates... */
                    911:        if (subnets)
                    912:            subnet_reference (&next, subnets, MDL);
                    913:        while (next) {
                    914:            subnet_reference (&scan, next, MDL);
                    915:            subnet_dereference (&next, MDL);
                    916: 
                    917:            /* When we find a conflict, make sure that the
                    918:               subnet with the narrowest subnet mask comes
                    919:               first. */
                    920:            if (subnet_inner_than (subnet, scan, 1)) {
                    921:                if (prev) {
                    922:                    if (prev -> next_subnet)
                    923:                        subnet_dereference (&prev -> next_subnet, MDL);
                    924:                    subnet_reference (&prev -> next_subnet, subnet, MDL);
                    925:                    subnet_dereference (&prev, MDL);
                    926:                } else {
                    927:                    subnet_dereference (&subnets, MDL);
                    928:                    subnet_reference (&subnets, subnet, MDL);
                    929:                }
                    930:                subnet_reference (&subnet -> next_subnet, scan, MDL);
                    931:                subnet_dereference (&scan, MDL);
                    932:                return;
                    933:            }
                    934:            subnet_reference (&prev, scan, MDL);
                    935:            subnet_dereference (&scan, MDL);
                    936:        }
                    937:        if (prev)
                    938:                subnet_dereference (&prev, MDL);
                    939: 
                    940:        /* XXX use the BSD radix tree code instead of a linked list. */
                    941:        if (subnets) {
                    942:                subnet_reference (&subnet -> next_subnet, subnets, MDL);
                    943:                subnet_dereference (&subnets, MDL);
                    944:        }
                    945:        subnet_reference (&subnets, subnet, MDL);
                    946: }
                    947:        
                    948: /* Enter a new shared network into the shared network list. */
                    949: 
                    950: void enter_shared_network (share)
                    951:        struct shared_network *share;
                    952: {
                    953:        if (shared_networks) {
                    954:                shared_network_reference (&share -> next,
                    955:                                          shared_networks, MDL);
                    956:                shared_network_dereference (&shared_networks, MDL);
                    957:        }
                    958:        shared_network_reference (&shared_networks, share, MDL);
                    959: }
                    960:        
                    961: void new_shared_network_interface (cfile, share, name)
                    962:        struct parse *cfile;
                    963:        struct shared_network *share;
                    964:        const char *name;
                    965: {
                    966:        struct interface_info *ip;
                    967:        isc_result_t status;
                    968: 
                    969:        if (share -> interface) {
                    970:                parse_warn (cfile, 
                    971:                            "A subnet or shared network can't be connected %s",
                    972:                            "to two interfaces.");
                    973:                return;
                    974:        }
                    975:        
                    976:        for (ip = interfaces; ip; ip = ip -> next)
                    977:                if (!strcmp (ip -> name, name))
                    978:                        break;
                    979:        if (!ip) {
                    980:                status = interface_allocate (&ip, MDL);
                    981:                if (status != ISC_R_SUCCESS)
                    982:                        log_fatal ("new_shared_network_interface %s: %s",
                    983:                                   name, isc_result_totext (status));
                    984:                if (strlen (name) > sizeof ip -> name) {
                    985:                        memcpy (ip -> name, name, (sizeof ip -> name) - 1);
                    986:                        ip -> name [(sizeof ip -> name) - 1] = 0;
                    987:                } else
                    988:                        strcpy (ip -> name, name);
                    989:                if (interfaces) {
                    990:                        interface_reference (&ip -> next, interfaces, MDL);
                    991:                        interface_dereference (&interfaces, MDL);
                    992:                }
                    993:                interface_reference (&interfaces, ip, MDL);
                    994:                ip -> flags = INTERFACE_REQUESTED;
                    995:                /* XXX this is a reference loop. */
                    996:                shared_network_reference (&ip -> shared_network, share, MDL);
                    997:                interface_reference (&share -> interface, ip, MDL);
                    998:        }
                    999: }
                   1000: 
                   1001: /* Enter a lease into the system.   This is called by the parser each
                   1002:    time it reads in a new lease.   If the subnet for that lease has
                   1003:    already been read in (usually the case), just update that lease;
                   1004:    otherwise, allocate temporary storage for the lease and keep it around
                   1005:    until we're done reading in the config file. */
                   1006: 
                   1007: void enter_lease (lease)
                   1008:        struct lease *lease;
                   1009: {
                   1010:        struct lease *comp = (struct lease *)0;
                   1011: 
                   1012:        if (find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) {
                   1013:                if (!comp -> pool) {
                   1014:                        log_error ("undeclared lease found in database: %s",
                   1015:                                   piaddr (lease -> ip_addr));
                   1016:                } else
                   1017:                        pool_reference (&lease -> pool, comp -> pool, MDL);
                   1018: 
                   1019:                if (comp -> subnet)
                   1020:                        subnet_reference (&lease -> subnet,
                   1021:                                          comp -> subnet, MDL);
                   1022:                lease_ip_hash_delete(lease_ip_addr_hash,
                   1023:                                     lease->ip_addr.iabuf, lease->ip_addr.len,
                   1024:                                     MDL);
                   1025:                lease_dereference (&comp, MDL);
                   1026:        }
                   1027: 
                   1028:        /* The only way a lease can get here without a subnet is if it's in
                   1029:           the lease file, but not in the dhcpd.conf file.  In this case, we
                   1030:           *should* keep it around until it's expired, but never reallocate it
                   1031:           or renew it.  Currently, to maintain consistency, we are not doing
                   1032:           this.
                   1033:           XXX fix this so that the lease is kept around until it expires.
                   1034:           XXX this will be important in IPv6 with addresses that become
                   1035:           XXX non-renewable as a result of a renumbering event. */
                   1036: 
                   1037:        if (!lease -> subnet) {
                   1038:                log_error ("lease %s: no subnet.", piaddr (lease -> ip_addr));
                   1039:                return;
                   1040:        }
                   1041:        lease_ip_hash_add(lease_ip_addr_hash, lease->ip_addr.iabuf,
                   1042:                          lease->ip_addr.len, lease, MDL);
                   1043: }
                   1044: 
                   1045: /* Replace the data in an existing lease with the data in a new lease;
                   1046:    adjust hash tables to suit, and insertion sort the lease into the
                   1047:    list of leases by expiry time so that we can always find the oldest
                   1048:    lease. */
                   1049: 
                   1050: int supersede_lease (comp, lease, commit, propogate, pimmediate)
                   1051:        struct lease *comp, *lease;
                   1052:        int commit;
                   1053:        int propogate;
                   1054:        int pimmediate;
                   1055: {
                   1056:        struct lease *lp, **lq, *prev;
                   1057:        struct timeval tv;
                   1058: #if defined (FAILOVER_PROTOCOL)
                   1059:        int do_pool_check = 0;
                   1060: 
                   1061:        /* We must commit leases before sending updates regarding them
                   1062:           to failover peers.  It is, therefore, an error to set pimmediate
                   1063:           and not commit. */
                   1064:        if (pimmediate && !commit)
                   1065:                return 0;
                   1066: #endif
                   1067: 
                   1068:        /* If there is no sample lease, just do the move. */
                   1069:        if (!lease)
                   1070:                goto just_move_it;
                   1071: 
                   1072:        /* Static leases are not currently kept in the database... */
                   1073:        if (lease -> flags & STATIC_LEASE)
                   1074:                return 1;
                   1075: 
                   1076:        /* If the existing lease hasn't expired and has a different
                   1077:           unique identifier or, if it doesn't have a unique
                   1078:           identifier, a different hardware address, then the two
                   1079:           leases are in conflict.  If the existing lease has a uid
                   1080:           and the new one doesn't, but they both have the same
                   1081:           hardware address, and dynamic bootp is allowed on this
                   1082:           lease, then we allow that, in case a dynamic BOOTP lease is
                   1083:           requested *after* a DHCP lease has been assigned. */
                   1084: 
                   1085:        if (lease -> binding_state != FTS_ABANDONED &&
                   1086:            lease -> next_binding_state != FTS_ABANDONED &&
                   1087:            comp -> binding_state == FTS_ACTIVE &&
                   1088:            (((comp -> uid && lease -> uid) &&
                   1089:              (comp -> uid_len != lease -> uid_len ||
                   1090:               memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
                   1091:             (!comp -> uid &&
                   1092:              ((comp -> hardware_addr.hlen !=
                   1093:                lease -> hardware_addr.hlen) ||
                   1094:               memcmp (comp -> hardware_addr.hbuf,
                   1095:                       lease -> hardware_addr.hbuf,
                   1096:                       comp -> hardware_addr.hlen))))) {
                   1097:                log_error ("Lease conflict at %s",
                   1098:                      piaddr (comp -> ip_addr));
                   1099:        }
                   1100: 
                   1101:        /* If there's a Unique ID, dissociate it from the hash
                   1102:           table and free it if necessary. */
                   1103:        if (comp->uid) {
                   1104:                uid_hash_delete(comp);
                   1105:                if (comp->uid != comp->uid_buf) {
                   1106:                        dfree(comp->uid, MDL);
                   1107:                        comp->uid_max = 0;
                   1108:                        comp->uid_len = 0;
                   1109:                }
                   1110:                comp -> uid = (unsigned char *)0;
                   1111:        }
                   1112: 
                   1113:        /* If there's a hardware address, remove the lease from its
                   1114:         * old position in the hash bucket's ordered list.
                   1115:         */
                   1116:        if (comp->hardware_addr.hlen)
                   1117:                hw_hash_delete(comp);
                   1118: 
                   1119:        /* If the lease has been billed to a class, remove the billing. */
                   1120:        if (comp -> billing_class != lease -> billing_class) {
                   1121:                if (comp -> billing_class)
                   1122:                        unbill_class (comp, comp -> billing_class);
                   1123:                if (lease -> billing_class)
                   1124:                        bill_class (comp, lease -> billing_class);
                   1125:        }
                   1126: 
                   1127:        /* Copy the data files, but not the linkages. */
                   1128:        comp -> starts = lease -> starts;
                   1129:        if (lease -> uid) {
                   1130:                if (lease -> uid_len <= sizeof (lease -> uid_buf)) {
                   1131:                        memcpy (comp -> uid_buf,
                   1132:                                lease -> uid, lease -> uid_len);
                   1133:                        comp -> uid = &comp -> uid_buf [0];
                   1134:                        comp -> uid_max = sizeof comp -> uid_buf;
                   1135:                        comp -> uid_len = lease -> uid_len;
                   1136:                } else if (lease -> uid != &lease -> uid_buf [0]) {
                   1137:                        comp -> uid = lease -> uid;
                   1138:                        comp -> uid_max = lease -> uid_max;
                   1139:                        lease -> uid = (unsigned char *)0;
                   1140:                        lease -> uid_max = 0;
                   1141:                        comp -> uid_len = lease -> uid_len;
                   1142:                        lease -> uid_len = 0;
                   1143:                } else {
                   1144:                        log_fatal ("corrupt lease uid."); /* XXX */
                   1145:                }
                   1146:        } else {
                   1147:                comp -> uid = (unsigned char *)0;
                   1148:                comp -> uid_len = comp -> uid_max = 0;
                   1149:        }
                   1150:        if (comp -> host)
                   1151:                host_dereference (&comp -> host, MDL);
                   1152:        host_reference (&comp -> host, lease -> host, MDL);
                   1153:        comp -> hardware_addr = lease -> hardware_addr;
                   1154:        comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) |
                   1155:                         (comp -> flags & ~EPHEMERAL_FLAGS));
                   1156:        if (comp -> scope)
                   1157:                binding_scope_dereference (&comp -> scope, MDL);
                   1158:        if (lease -> scope) {
                   1159:                binding_scope_reference (&comp -> scope, lease -> scope, MDL);
                   1160:                binding_scope_dereference (&lease -> scope, MDL);
                   1161:        }
                   1162: 
                   1163:        if (comp -> agent_options)
                   1164:                option_chain_head_dereference (&comp -> agent_options, MDL);
                   1165:        if (lease -> agent_options) {
                   1166:                /* Only retain the agent options if the lease is still
                   1167:                   affirmatively associated with a client. */
                   1168:                if (lease -> next_binding_state == FTS_ACTIVE ||
                   1169:                    lease -> next_binding_state == FTS_EXPIRED)
                   1170:                        option_chain_head_reference (&comp -> agent_options,
                   1171:                                                     lease -> agent_options,
                   1172:                                                     MDL);
                   1173:                option_chain_head_dereference (&lease -> agent_options, MDL);
                   1174:        }
                   1175: 
                   1176:        /* Record the hostname information in the lease. */
                   1177:        if (comp -> client_hostname)
                   1178:                dfree (comp -> client_hostname, MDL);
                   1179:        comp -> client_hostname = lease -> client_hostname;
                   1180:        lease -> client_hostname = (char *)0;
                   1181: 
                   1182:        if (lease -> on_expiry) {
                   1183:                if (comp -> on_expiry)
                   1184:                        executable_statement_dereference (&comp -> on_expiry,
                   1185:                                                          MDL);
                   1186:                executable_statement_reference (&comp -> on_expiry,
                   1187:                                                lease -> on_expiry,
                   1188:                                                MDL);
                   1189:        }
                   1190:        if (lease -> on_commit) {
                   1191:                if (comp -> on_commit)
                   1192:                        executable_statement_dereference (&comp -> on_commit,
                   1193:                                                          MDL);
                   1194:                executable_statement_reference (&comp -> on_commit,
                   1195:                                                lease -> on_commit,
                   1196:                                                MDL);
                   1197:        }
                   1198:        if (lease -> on_release) {
                   1199:                if (comp -> on_release)
                   1200:                        executable_statement_dereference (&comp -> on_release,
                   1201:                                                          MDL);
                   1202:                executable_statement_reference (&comp -> on_release,
                   1203:                                                lease -> on_release, MDL);
                   1204:        }
                   1205: 
                   1206:        /* Record the lease in the uid hash if necessary. */
                   1207:        if (comp->uid)
                   1208:                uid_hash_add(comp);
                   1209: 
                   1210:        /* Record it in the hardware address hash if necessary. */
                   1211:        if (comp->hardware_addr.hlen)
                   1212:                hw_hash_add(comp);
                   1213: 
                   1214:        comp->cltt = lease->cltt;
                   1215: #if defined (FAILOVER_PROTOCOL)
                   1216:        comp->tstp = lease->tstp;
                   1217:        comp->tsfp = lease->tsfp;
                   1218:        comp->atsfp = lease->atsfp;
                   1219: #endif /* FAILOVER_PROTOCOL */
                   1220:        comp->ends = lease->ends;
                   1221:        comp->next_binding_state = lease->next_binding_state;
                   1222: 
                   1223:       just_move_it:
                   1224: #if defined (FAILOVER_PROTOCOL)
                   1225:        /* Atsfp should be cleared upon any state change that implies
                   1226:         * propagation whether supersede_lease was given a copy lease
                   1227:         * structure or not (often from the pool_timer()).
                   1228:         */
                   1229:        if (propogate)
                   1230:                comp->atsfp = 0;
                   1231: #endif /* FAILOVER_PROTOCOL */
                   1232: 
                   1233:        if (!comp -> pool) {
                   1234:                log_error ("Supersede_lease: lease %s with no pool.",
                   1235:                           piaddr (comp -> ip_addr));
                   1236:                return 0;
                   1237:        }
                   1238: 
                   1239:        /* Figure out which queue it's on. */
                   1240:        switch (comp -> binding_state) {
                   1241:              case FTS_FREE:
                   1242:                if (comp->flags & RESERVED_LEASE)
                   1243:                        lq = &comp->pool->reserved;
                   1244:                else {
                   1245:                        lq = &comp->pool->free;
                   1246:                        comp->pool->free_leases--;
                   1247:                }
                   1248: 
                   1249: #if defined(FAILOVER_PROTOCOL)
                   1250:                do_pool_check = 1;
                   1251: #endif
                   1252:                break;
                   1253: 
                   1254:              case FTS_ACTIVE:
                   1255:                lq = &comp -> pool -> active;
                   1256:                break;
                   1257: 
                   1258:              case FTS_EXPIRED:
                   1259:              case FTS_RELEASED:
                   1260:              case FTS_RESET:
                   1261:                lq = &comp -> pool -> expired;
                   1262:                break;
                   1263: 
                   1264:              case FTS_ABANDONED:
                   1265:                lq = &comp -> pool -> abandoned;
                   1266:                break;
                   1267: 
                   1268:              case FTS_BACKUP:
                   1269:                if (comp->flags & RESERVED_LEASE)
                   1270:                        lq = &comp->pool->reserved;
                   1271:                else {
                   1272:                        lq = &comp->pool->backup;
                   1273:                        comp->pool->backup_leases--;
                   1274:                }
                   1275: 
                   1276: #if defined(FAILOVER_PROTOCOL)
                   1277:                do_pool_check = 1;
                   1278: #endif
                   1279:                break;
                   1280: 
                   1281:              default:
                   1282:                log_error ("Lease with bogus binding state: %d",
                   1283:                           comp -> binding_state);
                   1284: #if defined (BINDING_STATE_DEBUG)
                   1285:                abort ();
                   1286: #endif
                   1287:                return 0;
                   1288:        }
                   1289: 
                   1290:        /* Remove the lease from its current place in its current
                   1291:           timer sequence. */
                   1292:        /* XXX this is horrid. */
                   1293:        prev = (struct lease *)0;
                   1294:        for (lp = *lq; lp; lp = lp -> next) {
                   1295:                if (lp == comp)
                   1296:                        break;
                   1297:                prev = lp;
                   1298:        }
                   1299: 
                   1300:        if (!lp) {
                   1301:                log_fatal("Lease with binding state %s not on its queue.",
                   1302:                          (comp->binding_state < 1 ||
                   1303:                           comp->binding_state > FTS_LAST)
                   1304:                          ? "unknown"
                   1305:                          : binding_state_names[comp->binding_state - 1]);
                   1306:        }
                   1307: 
                   1308:        if (prev) {
                   1309:                lease_dereference (&prev -> next, MDL);
                   1310:                if (comp -> next) {
                   1311:                        lease_reference (&prev -> next, comp -> next, MDL);
                   1312:                        lease_dereference (&comp -> next, MDL);
                   1313:                }
                   1314:        } else {
                   1315:                lease_dereference (lq, MDL);
                   1316:                if (comp -> next) {
                   1317:                        lease_reference (lq, comp -> next, MDL);
                   1318:                        lease_dereference (&comp -> next, MDL);
                   1319:                }
                   1320:        }
                   1321: 
                   1322:        /* Make the state transition. */
                   1323:        if (commit || !pimmediate)
                   1324:                make_binding_state_transition (comp);
                   1325: 
                   1326:        /* Put the lease back on the appropriate queue.    If the lease
                   1327:           is corrupt (as detected by lease_enqueue), don't go any farther. */
                   1328:        if (!lease_enqueue (comp))
                   1329:                return 0;
                   1330: 
                   1331:        /* If this is the next lease that will timeout on the pool,
                   1332:           zap the old timeout and set the timeout on this pool to the
                   1333:           time that the lease's next event will happen.
                   1334:                   
                   1335:           We do not actually set the timeout unless commit is true -
                   1336:           we don't want to thrash the timer queue when reading the
                   1337:           lease database.  Instead, the database code calls the
                   1338:           expiry event on each pool after reading in the lease file,
                   1339:           and the expiry code sets the timer if there's anything left
                   1340:           to expire after it's run any outstanding expiry events on
                   1341:           the pool. */
                   1342:        if ((commit || !pimmediate) &&
                   1343:            comp -> sort_time != MIN_TIME &&
                   1344:            comp -> sort_time > cur_time &&
                   1345:            (comp -> sort_time < comp -> pool -> next_event_time ||
                   1346:             comp -> pool -> next_event_time == MIN_TIME)) {
                   1347:                comp -> pool -> next_event_time = comp -> sort_time;
                   1348:                tv . tv_sec = comp -> pool -> next_event_time;
                   1349:                tv . tv_usec = 0;
                   1350:                add_timeout (&tv,
                   1351:                             pool_timer, comp -> pool,
                   1352:                             (tvref_t)pool_reference,
                   1353:                             (tvunref_t)pool_dereference);
                   1354:        }
                   1355: 
                   1356:        if (commit) {
                   1357:                if (!write_lease (comp))
                   1358:                        return 0;
                   1359:                if ((server_starting & SS_NOSYNC) == 0) {
                   1360:                        if (!commit_leases ())
                   1361:                                return 0;
                   1362:                }
                   1363:        }
                   1364: 
                   1365: #if defined (FAILOVER_PROTOCOL)
                   1366:        if (propogate) {
                   1367:                comp -> desired_binding_state = comp -> binding_state;
                   1368:                if (!dhcp_failover_queue_update (comp, pimmediate))
                   1369:                        return 0;
                   1370:        }
                   1371:        if (do_pool_check && comp->pool->failover_peer)
                   1372:                dhcp_failover_pool_check(comp->pool);
                   1373: #endif
                   1374: 
                   1375:        /* If the current binding state has already expired, do an
                   1376:           expiry event right now. */
                   1377:        /* XXX At some point we should optimize this so that we don't
                   1378:           XXX write the lease twice, but this is a safe way to fix the
                   1379:           XXX problem for 3.0 (I hope!). */
                   1380:        if ((commit || !pimmediate) &&
                   1381:            comp -> sort_time < cur_time &&
                   1382:            comp -> next_binding_state != comp -> binding_state)
                   1383:                pool_timer (comp -> pool);
                   1384: 
                   1385:        return 1;
                   1386: }
                   1387: 
                   1388: void make_binding_state_transition (struct lease *lease)
                   1389: {
                   1390: #if defined (FAILOVER_PROTOCOL)
                   1391:        dhcp_failover_state_t *peer;
                   1392: 
                   1393:        if (lease && lease -> pool && lease -> pool -> failover_peer)
                   1394:                peer = lease -> pool -> failover_peer;
                   1395:        else
                   1396:                peer = (dhcp_failover_state_t *)0;
                   1397: #endif
                   1398: 
                   1399:        /* If the lease was active and is now no longer active, but isn't
                   1400:           released, then it just expired, so do the expiry event. */
                   1401:        if (lease -> next_binding_state != lease -> binding_state &&
                   1402:            ((
                   1403: #if defined (FAILOVER_PROTOCOL)
                   1404:                    peer &&
                   1405:                    (lease -> binding_state == FTS_EXPIRED ||
                   1406:                     (peer -> i_am == secondary &&
                   1407:                      lease -> binding_state == FTS_ACTIVE)) &&
                   1408:                    (lease -> next_binding_state == FTS_FREE ||
                   1409:                     lease -> next_binding_state == FTS_BACKUP)) ||
                   1410:             (!peer &&
                   1411: #endif
                   1412:              lease -> binding_state == FTS_ACTIVE &&
                   1413:              lease -> next_binding_state != FTS_RELEASED))) {
                   1414: #if defined (NSUPDATE)
                   1415:                ddns_removals(lease, NULL);
                   1416: #endif
                   1417:                if (lease -> on_expiry) {
                   1418:                        execute_statements ((struct binding_value **)0,
                   1419:                                            (struct packet *)0, lease,
                   1420:                                            (struct client_state *)0,
                   1421:                                            (struct option_state *)0,
                   1422:                                            (struct option_state *)0, /* XXX */
                   1423:                                            &lease -> scope,
                   1424:                                            lease -> on_expiry);
                   1425:                        if (lease -> on_expiry)
                   1426:                                executable_statement_dereference
                   1427:                                        (&lease -> on_expiry, MDL);
                   1428:                }
                   1429:                
                   1430:                /* No sense releasing a lease after it's expired. */
                   1431:                if (lease -> on_release)
                   1432:                        executable_statement_dereference (&lease -> on_release,
                   1433:                                                          MDL);
                   1434:                /* Get rid of client-specific bindings that are only
                   1435:                   correct when the lease is active. */
                   1436:                if (lease -> billing_class)
                   1437:                        unbill_class (lease, lease -> billing_class);
                   1438:                if (lease -> agent_options)
                   1439:                        option_chain_head_dereference (&lease -> agent_options,
                   1440:                                                       MDL);
                   1441:                if (lease -> client_hostname) {
                   1442:                        dfree (lease -> client_hostname, MDL);
                   1443:                        lease -> client_hostname = (char *)0;
                   1444:                }
                   1445:                if (lease -> host)
                   1446:                        host_dereference (&lease -> host, MDL);
                   1447: 
                   1448:                /* Send the expiry time to the peer. */
                   1449:                lease -> tstp = lease -> ends;
                   1450:        }
                   1451: 
                   1452:        /* If the lease was active and is now released, do the release
                   1453:           event. */
                   1454:        if (lease -> next_binding_state != lease -> binding_state &&
                   1455:            ((
                   1456: #if defined (FAILOVER_PROTOCOL)
                   1457:                    peer &&
                   1458:                    lease -> binding_state == FTS_RELEASED &&
                   1459:                    (lease -> next_binding_state == FTS_FREE ||
                   1460:                     lease -> next_binding_state == FTS_BACKUP)) ||
                   1461:             (!peer &&
                   1462: #endif
                   1463:              lease -> binding_state == FTS_ACTIVE &&
                   1464:              lease -> next_binding_state == FTS_RELEASED))) {
                   1465: #if defined (NSUPDATE)
                   1466:                /*
                   1467:                 * Note: ddns_removals() is also iterated when the lease
                   1468:                 * enters state 'released' in 'release_lease()'.  The below
                   1469:                 * is caught when a peer receives a BNDUPD from a failover
                   1470:                 * peer; it may not have received the client's release (it
                   1471:                 * may have been offline).
                   1472:                 *
                   1473:                 * We could remove the call from release_lease() because
                   1474:                 * it will also catch here on the originating server after the
                   1475:                 * peer acknowledges the state change.  However, there could
                   1476:                 * be many hours inbetween, and in this case we /know/ the
                   1477:                 * client is no longer using the lease when we receive the
                   1478:                 * release message.  This is not true of expiry, where the
                   1479:                 * peer may have extended the lease.
                   1480:                 */
                   1481:                ddns_removals(lease, NULL);
                   1482: #endif
                   1483:                if (lease -> on_release) {
                   1484:                        execute_statements ((struct binding_value **)0,
                   1485:                                            (struct packet *)0, lease,
                   1486:                                            (struct client_state *)0,
                   1487:                                            (struct option_state *)0,
                   1488:                                            (struct option_state *)0, /* XXX */
                   1489:                                            &lease -> scope,
                   1490:                                            lease -> on_release);
                   1491:                        executable_statement_dereference (&lease -> on_release,
                   1492:                                                          MDL);
                   1493:                }
                   1494:                
                   1495:                /* A released lease can't expire. */
                   1496:                if (lease -> on_expiry)
                   1497:                        executable_statement_dereference (&lease -> on_expiry,
                   1498:                                                          MDL);
                   1499: 
                   1500:                /* Get rid of client-specific bindings that are only
                   1501:                   correct when the lease is active. */
                   1502:                if (lease -> billing_class)
                   1503:                        unbill_class (lease, lease -> billing_class);
                   1504:                if (lease -> agent_options)
                   1505:                        option_chain_head_dereference (&lease -> agent_options,
                   1506:                                                       MDL);
                   1507:                if (lease -> client_hostname) {
                   1508:                        dfree (lease -> client_hostname, MDL);
                   1509:                        lease -> client_hostname = (char *)0;
                   1510:                }
                   1511:                if (lease -> host)
                   1512:                        host_dereference (&lease -> host, MDL);
                   1513: 
                   1514:                /* Send the release time (should be == cur_time) to the
                   1515:                   peer. */
                   1516:                lease -> tstp = lease -> ends;
                   1517:        }
                   1518: 
                   1519: #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
                   1520:        log_debug ("lease %s moves from %s to %s",
                   1521:                   piaddr (lease -> ip_addr),
                   1522:                   binding_state_print (lease -> binding_state),
                   1523:                   binding_state_print (lease -> next_binding_state));
                   1524: #endif
                   1525: 
                   1526:        lease -> binding_state = lease -> next_binding_state;
                   1527:        switch (lease -> binding_state) {
                   1528:              case FTS_ACTIVE:
                   1529: #if defined (FAILOVER_PROTOCOL)
                   1530:                if (lease -> pool && lease -> pool -> failover_peer)
                   1531:                        lease -> next_binding_state = FTS_EXPIRED;
                   1532:                else
                   1533: #endif
                   1534:                        lease -> next_binding_state = FTS_FREE;
                   1535:                break;
                   1536: 
                   1537:              case FTS_EXPIRED:
                   1538:              case FTS_RELEASED:
                   1539:              case FTS_ABANDONED:
                   1540:              case FTS_RESET:
                   1541:                lease -> next_binding_state = FTS_FREE;
                   1542: #if defined(FAILOVER_PROTOCOL)
                   1543:                /* If we are not in partner_down, leases don't go from
                   1544:                   EXPIRED to FREE on a timeout - only on an update.
                   1545:                   If we're in partner_down, they expire at mclt past
                   1546:                   the time we entered partner_down. */
                   1547:                if (lease -> pool -> failover_peer &&
                   1548:                    lease -> pool -> failover_peer -> me.state == partner_down)
                   1549:                        lease -> tsfp =
                   1550:                            (lease -> pool -> failover_peer -> me.stos +
                   1551:                             lease -> pool -> failover_peer -> mclt);
                   1552: #endif /* FAILOVER_PROTOCOL */
                   1553:                break;
                   1554: 
                   1555:              case FTS_FREE:
                   1556:              case FTS_BACKUP:
                   1557:                lease -> next_binding_state = lease -> binding_state;
                   1558:                break;
                   1559:        }
                   1560: #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
                   1561:        log_debug ("lease %s: next binding state %s",
                   1562:                   piaddr (lease -> ip_addr),
                   1563:                   binding_state_print (lease -> next_binding_state));
                   1564: #endif
                   1565: 
                   1566: }
                   1567: 
                   1568: /* Copy the contents of one lease into another, correctly maintaining
                   1569:    reference counts. */
                   1570: int lease_copy (struct lease **lp,
                   1571:                struct lease *lease, const char *file, int line)
                   1572: {
                   1573:        struct lease *lt = (struct lease *)0;
                   1574:        isc_result_t status;
                   1575: 
                   1576:        status = lease_allocate (&lt, MDL);
                   1577:        if (status != ISC_R_SUCCESS)
                   1578:                return 0;
                   1579: 
                   1580:        lt -> ip_addr = lease -> ip_addr;
                   1581:        lt -> starts = lease -> starts;
                   1582:        lt -> ends = lease -> ends;
                   1583:        lt -> uid_len = lease -> uid_len;
                   1584:        lt -> uid_max = lease -> uid_max;
                   1585:        if (lease -> uid == lease -> uid_buf) {
                   1586:                lt -> uid = lt -> uid_buf;
                   1587:                memcpy (lt -> uid_buf, lease -> uid_buf, sizeof lt -> uid_buf);
                   1588:        } else if (!lease -> uid_max) {
                   1589:                lt -> uid = (unsigned char *)0;
                   1590:        } else {
                   1591:                lt -> uid = dmalloc (lt -> uid_max, MDL);
                   1592:                if (!lt -> uid) {
                   1593:                        lease_dereference (&lt, MDL);
                   1594:                        return 0;
                   1595:                }
                   1596:                memcpy (lt -> uid, lease -> uid, lease -> uid_max);
                   1597:        }
                   1598:        if (lease -> client_hostname) {
                   1599:                lt -> client_hostname =
                   1600:                        dmalloc (strlen (lease -> client_hostname) + 1, MDL);
                   1601:                if (!lt -> client_hostname) {
                   1602:                        lease_dereference (&lt, MDL);
                   1603:                        return 0;
                   1604:                }
                   1605:                strcpy (lt -> client_hostname, lease -> client_hostname);
                   1606:        }
                   1607:        if (lease -> scope)
                   1608:                binding_scope_reference (&lt -> scope, lease -> scope, MDL);
                   1609:        if (lease -> agent_options)
                   1610:                option_chain_head_reference (&lt -> agent_options,
                   1611:                                             lease -> agent_options, MDL);
                   1612:        host_reference (&lt -> host, lease -> host, file, line);
                   1613:        subnet_reference (&lt -> subnet, lease -> subnet, file, line);
                   1614:        pool_reference (&lt -> pool, lease -> pool, file, line);
                   1615:        class_reference (&lt -> billing_class,
                   1616:                         lease -> billing_class, file, line);
                   1617:        lt -> hardware_addr = lease -> hardware_addr;
                   1618:        if (lease -> on_expiry)
                   1619:                executable_statement_reference (&lt -> on_expiry,
                   1620:                                                lease -> on_expiry,
                   1621:                                                file, line);
                   1622:        if (lease -> on_commit)
                   1623:                executable_statement_reference (&lt -> on_commit,
                   1624:                                                lease -> on_commit,
                   1625:                                                file, line);
                   1626:        if (lease -> on_release)
                   1627:                executable_statement_reference (&lt -> on_release,
                   1628:                                                lease -> on_release,
                   1629:                                                file, line);
                   1630:        lt->flags = lease->flags;
                   1631:        lt->tstp = lease->tstp;
                   1632:        lt->tsfp = lease->tsfp;
                   1633:        lt->atsfp = lease->atsfp;
                   1634:        lt->cltt = lease -> cltt;
                   1635:        lt->binding_state = lease->binding_state;
                   1636:        lt->next_binding_state = lease->next_binding_state;
                   1637:        status = lease_reference(lp, lt, file, line);
                   1638:        lease_dereference(&lt, MDL);
                   1639:        return status == ISC_R_SUCCESS;
                   1640: }
                   1641: 
                   1642: /* Release the specified lease and re-hash it as appropriate. */
                   1643: void release_lease (lease, packet)
                   1644:        struct lease *lease;
                   1645:        struct packet *packet;
                   1646: {
                   1647:        /* If there are statements to execute when the lease is
                   1648:           released, execute them. */
                   1649: #if defined (NSUPDATE)
                   1650:        ddns_removals(lease, NULL);
                   1651: #endif
                   1652:        if (lease -> on_release) {
                   1653:                execute_statements ((struct binding_value **)0,
                   1654:                                    packet, lease, (struct client_state *)0,
                   1655:                                    packet -> options,
                   1656:                                    (struct option_state *)0, /* XXX */
                   1657:                                    &lease -> scope, lease -> on_release);
                   1658:                if (lease -> on_release)
                   1659:                        executable_statement_dereference (&lease -> on_release,
                   1660:                                                          MDL);
                   1661:        }
                   1662: 
                   1663:        /* We do either the on_release or the on_expiry events, but
                   1664:           not both (it's possible that they could be the same,
                   1665:           in any case). */
                   1666:        if (lease -> on_expiry)
                   1667:                executable_statement_dereference (&lease -> on_expiry, MDL);
                   1668: 
                   1669:        if (lease -> binding_state != FTS_FREE &&
                   1670:            lease -> binding_state != FTS_BACKUP &&
                   1671:            lease -> binding_state != FTS_RELEASED &&
                   1672:            lease -> binding_state != FTS_EXPIRED &&
                   1673:            lease -> binding_state != FTS_RESET) {
                   1674:                if (lease -> on_commit)
                   1675:                        executable_statement_dereference (&lease -> on_commit,
                   1676:                                                          MDL);
                   1677: 
                   1678:                /* Blow away any bindings. */
                   1679:                if (lease -> scope)
                   1680:                        binding_scope_dereference (&lease -> scope, MDL);
                   1681: 
                   1682:                /* Set sort times to the present. */
                   1683:                lease -> ends = cur_time;
                   1684:                /* Lower layers of muckery set tstp to ->ends.  But we send
                   1685:                 * protocol messages before this.  So it is best to set
                   1686:                 * tstp now anyway.
                   1687:                 */
                   1688:                lease->tstp = cur_time;
                   1689: #if defined (FAILOVER_PROTOCOL)
                   1690:                if (lease -> pool && lease -> pool -> failover_peer) {
                   1691:                        lease -> next_binding_state = FTS_RELEASED;
                   1692:                } else {
                   1693:                        lease -> next_binding_state = FTS_FREE;
                   1694:                }
                   1695: #else
                   1696:                lease -> next_binding_state = FTS_FREE;
                   1697: #endif
                   1698:                supersede_lease (lease, (struct lease *)0, 1, 1, 1);
                   1699:        }
                   1700: }
                   1701: 
                   1702: /* Abandon the specified lease (set its timeout to infinity and its
                   1703:    particulars to zero, and re-hash it as appropriate. */
                   1704: 
                   1705: void abandon_lease (lease, message)
                   1706:        struct lease *lease;
                   1707:        const char *message;
                   1708: {
                   1709:        struct lease *lt = (struct lease *)0;
                   1710: #if defined (NSUPDATE)
                   1711:        ddns_removals(lease, NULL);
                   1712: #endif
                   1713: 
                   1714:        if (!lease_copy (&lt, lease, MDL))
                   1715:                return;
                   1716: 
                   1717:        if (lt->scope)
                   1718:                binding_scope_dereference(&lt->scope, MDL);
                   1719: 
                   1720:        lt -> ends = cur_time; /* XXX */
                   1721:        lt -> next_binding_state = FTS_ABANDONED;
                   1722: 
                   1723:        log_error ("Abandoning IP address %s: %s",
                   1724:              piaddr (lease -> ip_addr), message);
                   1725:        lt -> hardware_addr.hlen = 0;
                   1726:        if (lt -> uid && lt -> uid != lt -> uid_buf)
                   1727:                dfree (lt -> uid, MDL);
                   1728:        lt -> uid = (unsigned char *)0;
                   1729:        lt -> uid_len = 0;
                   1730:        lt -> uid_max = 0;
                   1731:        supersede_lease (lease, lt, 1, 1, 1);
                   1732:        lease_dereference (&lt, MDL);
                   1733: }
                   1734: 
                   1735: /* Abandon the specified lease (set its timeout to infinity and its
                   1736:    particulars to zero, and re-hash it as appropriate. */
                   1737: 
                   1738: void dissociate_lease (lease)
                   1739:        struct lease *lease;
                   1740: {
                   1741:        struct lease *lt = (struct lease *)0;
                   1742: #if defined (NSUPDATE)
                   1743:        ddns_removals(lease, NULL);
                   1744: #endif
                   1745: 
                   1746:        if (!lease_copy (&lt, lease, MDL))
                   1747:                return;
                   1748: 
                   1749: #if defined (FAILOVER_PROTOCOL)
                   1750:        if (lease -> pool && lease -> pool -> failover_peer) {
                   1751:                lt -> next_binding_state = FTS_RESET;
                   1752:        } else {
                   1753:                lt -> next_binding_state = FTS_FREE;
                   1754:        }
                   1755: #else
                   1756:        lt -> next_binding_state = FTS_FREE;
                   1757: #endif
                   1758:        lt -> ends = cur_time; /* XXX */
                   1759:        lt -> hardware_addr.hlen = 0;
                   1760:        if (lt -> uid && lt -> uid != lt -> uid_buf)
                   1761:                dfree (lt -> uid, MDL);
                   1762:        lt -> uid = (unsigned char *)0;
                   1763:        lt -> uid_len = 0;
                   1764:        lt -> uid_max = 0;
                   1765:        supersede_lease (lease, lt, 1, 1, 1);
                   1766:        lease_dereference (&lt, MDL);
                   1767: }
                   1768: 
                   1769: /* Timer called when a lease in a particular pool expires. */
                   1770: void pool_timer (vpool)
                   1771:        void *vpool;
                   1772: {
                   1773:        struct pool *pool;
                   1774:        struct lease *next = (struct lease *)0;
                   1775:        struct lease *lease = (struct lease *)0;
                   1776: #define FREE_LEASES 0
                   1777: #define ACTIVE_LEASES 1
                   1778: #define EXPIRED_LEASES 2
                   1779: #define ABANDONED_LEASES 3
                   1780: #define BACKUP_LEASES 4
                   1781: #define RESERVED_LEASES 5
                   1782:        struct lease **lptr[RESERVED_LEASES+1];
                   1783:        TIME next_expiry = MAX_TIME;
                   1784:        int i;
                   1785:        struct timeval tv;
                   1786: 
                   1787:        pool = (struct pool *)vpool;
                   1788: 
                   1789:        lptr [FREE_LEASES] = &pool -> free;
                   1790:        lptr [ACTIVE_LEASES] = &pool -> active;
                   1791:        lptr [EXPIRED_LEASES] = &pool -> expired;
                   1792:        lptr [ABANDONED_LEASES] = &pool -> abandoned;
                   1793:        lptr [BACKUP_LEASES] = &pool -> backup;
                   1794:        lptr[RESERVED_LEASES] = &pool->reserved;
                   1795: 
                   1796:        for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
                   1797:                /* If there's nothing on the queue, skip it. */
                   1798:                if (!*(lptr [i]))
                   1799:                        continue;
                   1800: 
                   1801: #if defined (FAILOVER_PROTOCOL)
                   1802:                if (pool -> failover_peer &&
                   1803:                    pool -> failover_peer -> me.state != partner_down) {
                   1804:                        /* The secondary can't remove a lease from the
                   1805:                           active state except in partner_down. */
                   1806:                        if (i == ACTIVE_LEASES &&
                   1807:                            pool -> failover_peer -> i_am == secondary)
                   1808:                                continue;
                   1809:                        /* Leases in an expired state don't move to
                   1810:                           free because of a timeout unless we're in
                   1811:                           partner_down. */
                   1812:                        if (i == EXPIRED_LEASES)
                   1813:                                continue;
                   1814:                }
                   1815: #endif         
                   1816:                lease_reference (&lease, *(lptr [i]), MDL);
                   1817: 
                   1818:                while (lease) {
                   1819:                        /* Remember the next lease in the list. */
                   1820:                        if (next)
                   1821:                                lease_dereference (&next, MDL);
                   1822:                        if (lease -> next)
                   1823:                                lease_reference (&next, lease -> next, MDL);
                   1824: 
                   1825:                        /* If we've run out of things to expire on this list,
                   1826:                           stop. */
                   1827:                        if (lease -> sort_time > cur_time) {
                   1828:                                if (lease -> sort_time < next_expiry)
                   1829:                                        next_expiry = lease -> sort_time;
                   1830:                                break;
                   1831:                        }
                   1832: 
                   1833:                        /* If there is a pending state change, and
                   1834:                           this lease has gotten to the time when the
                   1835:                           state change should happen, just call
                   1836:                           supersede_lease on it to make the change
                   1837:                           happen. */
                   1838:                        if (lease -> next_binding_state !=
                   1839:                            lease -> binding_state)
                   1840:                                supersede_lease (lease,
                   1841:                                                 (struct lease *)0, 1, 1, 1);
                   1842: 
                   1843:                        lease_dereference (&lease, MDL);
                   1844:                        if (next)
                   1845:                                lease_reference (&lease, next, MDL);
                   1846:                }
                   1847:                if (next)
                   1848:                        lease_dereference (&next, MDL);
                   1849:                if (lease)
                   1850:                        lease_dereference (&lease, MDL);
                   1851:        }
                   1852:        if (next_expiry != MAX_TIME) {
                   1853:                pool -> next_event_time = next_expiry;
                   1854:                tv . tv_sec = pool -> next_event_time;
                   1855:                tv . tv_usec = 0;
                   1856:                add_timeout (&tv, pool_timer, pool,
                   1857:                             (tvref_t)pool_reference,
                   1858:                             (tvunref_t)pool_dereference);
                   1859:        } else
                   1860:                pool -> next_event_time = MIN_TIME;
                   1861: 
                   1862: }
                   1863: 
                   1864: /* Locate the lease associated with a given IP address... */
                   1865: 
                   1866: int find_lease_by_ip_addr (struct lease **lp, struct iaddr addr,
                   1867:                           const char *file, int line)
                   1868: {
                   1869:        return lease_ip_hash_lookup(lp, lease_ip_addr_hash, addr.iabuf,
                   1870:                                    addr.len, file, line);
                   1871: }
                   1872: 
                   1873: int find_lease_by_uid (struct lease **lp, const unsigned char *uid,
                   1874:                       unsigned len, const char *file, int line)
                   1875: {
                   1876:        if (len == 0)
                   1877:                return 0;
                   1878:        return lease_id_hash_lookup (lp, lease_uid_hash, uid, len, file, line);
                   1879: }
                   1880: 
                   1881: int find_lease_by_hw_addr (struct lease **lp,
                   1882:                           const unsigned char *hwaddr, unsigned hwlen,
                   1883:                           const char *file, int line)
                   1884: {
                   1885:        if (hwlen == 0)
1.1.1.1 ! misho    1886:                return (0);
        !          1887: 
        !          1888:        /*
        !          1889:         * If it's an infiniband address don't bother
        !          1890:         * as we don't have a useful address to hash.
        !          1891:         */
        !          1892:        if ((hwlen == 1) && (hwaddr[0] == HTYPE_INFINIBAND))
        !          1893:                return (0);
        !          1894: 
        !          1895:        return (lease_id_hash_lookup(lp, lease_hw_addr_hash, hwaddr, hwlen,
        !          1896:                                     file, line));
1.1       misho    1897: }
                   1898: 
                   1899: /* If the lease is preferred over the candidate, return truth.  The
                   1900:  * 'cand' and 'lease' names are retained to read more clearly against
                   1901:  * the 'uid_hash_add' and 'hw_hash_add' functions (this is common logic
                   1902:  * to those two functions).
                   1903:  *
                   1904:  * 1) ACTIVE leases are preferred.  The active lease with
                   1905:  *    the longest lifetime is preferred over shortest.
                   1906:  * 2) "transitional states" are next, this time with the
                   1907:  *    most recent CLTT.
                   1908:  * 3) free/backup/etc states are next, again with CLTT.  In truth we
                   1909:  *    should never see reset leases for this.
                   1910:  * 4) Abandoned leases are always dead last.
                   1911:  */
                   1912: static isc_boolean_t
                   1913: client_lease_preferred(struct lease *cand, struct lease *lease)
                   1914: {
                   1915:        if (cand->binding_state == FTS_ACTIVE) {
                   1916:                if (lease->binding_state == FTS_ACTIVE &&
                   1917:                    lease->ends >= cand->ends)
                   1918:                        return ISC_TRUE;
                   1919:        } else if (cand->binding_state == FTS_EXPIRED ||
                   1920:                   cand->binding_state == FTS_RELEASED) {
                   1921:                if (lease->binding_state == FTS_ACTIVE)
                   1922:                        return ISC_TRUE;
                   1923: 
                   1924:                if ((lease->binding_state == FTS_EXPIRED ||
                   1925:                     lease->binding_state == FTS_RELEASED) &&
                   1926:                    lease->cltt >= cand->cltt)
                   1927:                        return ISC_TRUE;
                   1928:        } else if (cand->binding_state != FTS_ABANDONED) {
                   1929:                if (lease->binding_state == FTS_ACTIVE ||
                   1930:                    lease->binding_state == FTS_EXPIRED ||
                   1931:                    lease->binding_state == FTS_RELEASED)
                   1932:                        return ISC_TRUE;
                   1933: 
                   1934:                if (lease->binding_state != FTS_ABANDONED &&
                   1935:                    lease->cltt >= cand->cltt)
                   1936:                        return ISC_TRUE;
                   1937:        } else /* (cand->binding_state == FTS_ABANDONED) */ {
                   1938:                if (lease->binding_state != FTS_ABANDONED ||
                   1939:                    lease->cltt >= cand->cltt)
                   1940:                        return ISC_TRUE;
                   1941:        }
                   1942: 
                   1943:        return ISC_FALSE;
                   1944: }
                   1945: 
                   1946: /* Add the specified lease to the uid hash. */
                   1947: void
                   1948: uid_hash_add(struct lease *lease)
                   1949: {
                   1950:        struct lease *head = NULL;
                   1951:        struct lease *cand = NULL;
                   1952:        struct lease *prev = NULL;
                   1953:        struct lease *next = NULL;
                   1954: 
                   1955:        /* If it's not in the hash, just add it. */
                   1956:        if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL))
                   1957:                lease_id_hash_add(lease_uid_hash, lease->uid, lease->uid_len,
                   1958:                                  lease, MDL);
                   1959:        else {
                   1960:                /* Otherwise, insert it into the list in order of its
                   1961:                 * preference for "resuming allocation to the client."
                   1962:                 *
                   1963:                 * Because we don't have control of the hash bucket index
                   1964:                 * directly, we have to remove and re-insert the client
                   1965:                 * id into the hash if we're inserting onto the head.
                   1966:                 */
                   1967:                lease_reference(&cand, head, MDL);
                   1968:                while (cand != NULL) {
                   1969:                        if (client_lease_preferred(cand, lease))
                   1970:                                break;
                   1971: 
                   1972:                        if (prev != NULL)
                   1973:                                lease_dereference(&prev, MDL);
                   1974:                        lease_reference(&prev, cand, MDL);
                   1975: 
                   1976:                        if (cand->n_uid != NULL)
                   1977:                                lease_reference(&next, cand->n_uid, MDL);
                   1978: 
                   1979:                        lease_dereference(&cand, MDL);
                   1980: 
                   1981:                        if (next != NULL) {
                   1982:                                lease_reference(&cand, next, MDL);
                   1983:                                lease_dereference(&next, MDL);
                   1984:                        }
                   1985:                }
                   1986: 
                   1987:                /* If we want to insert 'before cand', and prev is NULL,
                   1988:                 * then it was the head of the list.  Assume that position.
                   1989:                 */
                   1990:                if (prev == NULL) {
                   1991:                        lease_reference(&lease->n_uid, head, MDL);
                   1992:                        lease_id_hash_delete(lease_uid_hash, lease->uid,
                   1993:                                             lease->uid_len, MDL);
                   1994:                        lease_id_hash_add(lease_uid_hash, lease->uid,
                   1995:                                          lease->uid_len, lease, MDL);
                   1996:                } else /* (prev != NULL) */ {
                   1997:                        if(prev->n_uid != NULL) {
                   1998:                                lease_reference(&lease->n_uid, prev->n_uid,
                   1999:                                                MDL);
                   2000:                                lease_dereference(&prev->n_uid, MDL);
                   2001:                        }
                   2002:                        lease_reference(&prev->n_uid, lease, MDL);
                   2003: 
                   2004:                        lease_dereference(&prev, MDL);
                   2005:                }
                   2006: 
                   2007:                if (cand != NULL)
                   2008:                        lease_dereference(&cand, MDL);
                   2009:                lease_dereference(&head, MDL);
                   2010:        }
                   2011: }
                   2012: 
                   2013: /* Delete the specified lease from the uid hash. */
                   2014: 
                   2015: void uid_hash_delete (lease)
                   2016:        struct lease *lease;
                   2017: {
                   2018:        struct lease *head = (struct lease *)0;
                   2019:        struct lease *scan;
                   2020: 
                   2021:        /* If it's not in the hash, we have no work to do. */
                   2022:        if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL)) {
                   2023:                if (lease -> n_uid)
                   2024:                        lease_dereference (&lease -> n_uid, MDL);
                   2025:                return;
                   2026:        }
                   2027: 
                   2028:        /* If the lease we're freeing is at the head of the list,
                   2029:           remove the hash table entry and add a new one with the
                   2030:           next lease on the list (if there is one). */
                   2031:        if (head == lease) {
                   2032:                lease_id_hash_delete(lease_uid_hash, lease->uid,
                   2033:                                     lease->uid_len, MDL);
                   2034:                if (lease -> n_uid) {
                   2035:                        lease_id_hash_add(lease_uid_hash, lease->n_uid->uid,
                   2036:                                          lease->n_uid->uid_len, lease->n_uid,
                   2037:                                          MDL);
                   2038:                        lease_dereference (&lease -> n_uid, MDL);
                   2039:                }
                   2040:        } else {
                   2041:                /* Otherwise, look for the lease in the list of leases
                   2042:                   attached to the hash table entry, and remove it if
                   2043:                   we find it. */
                   2044:                for (scan = head; scan -> n_uid; scan = scan -> n_uid) {
                   2045:                        if (scan -> n_uid == lease) {
                   2046:                                lease_dereference (&scan -> n_uid, MDL);
                   2047:                                if (lease -> n_uid) {
                   2048:                                        lease_reference (&scan -> n_uid,
                   2049:                                                         lease -> n_uid, MDL);
                   2050:                                        lease_dereference (&lease -> n_uid,
                   2051:                                                           MDL);
                   2052:                                }
                   2053:                                break;
                   2054:                        }
                   2055:                }
                   2056:        }
                   2057:        lease_dereference (&head, MDL);
                   2058: }
                   2059: 
                   2060: /* Add the specified lease to the hardware address hash. */
1.1.1.1 ! misho    2061: /* We don't add leases with infiniband addresses to the
        !          2062:  * hash as there isn't any address to hash on. */
1.1       misho    2063: 
                   2064: void
                   2065: hw_hash_add(struct lease *lease)
                   2066: {
                   2067:        struct lease *head = NULL;
                   2068:        struct lease *cand = NULL;
                   2069:        struct lease *prev = NULL;
                   2070:        struct lease *next = NULL;
                   2071: 
1.1.1.1 ! misho    2072:        /*
        !          2073:         * If it's an infiniband address don't bother
        !          2074:         * as we don't have a useful address to hash.
        !          2075:         */
        !          2076:        if ((lease->hardware_addr.hlen == 1) &&
        !          2077:            (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
        !          2078:                return;
        !          2079:           
1.1       misho    2080:        /* If it's not in the hash, just add it. */
                   2081:        if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
                   2082:                                    lease -> hardware_addr.hlen, MDL))
                   2083:                lease_id_hash_add(lease_hw_addr_hash,
                   2084:                                  lease->hardware_addr.hbuf,
                   2085:                                  lease->hardware_addr.hlen, lease, MDL);
                   2086:        else {
                   2087:                /* Otherwise, insert it into the list in order of its
                   2088:                 * preference for "resuming allocation to the client."
                   2089:                 *
                   2090:                 * Because we don't have control of the hash bucket index
                   2091:                 * directly, we have to remove and re-insert the client
                   2092:                 * id into the hash if we're inserting onto the head.
                   2093:                 */
                   2094:                lease_reference(&cand, head, MDL);
                   2095:                while (cand != NULL) {
                   2096:                        if (client_lease_preferred(cand, lease))
                   2097:                                break;
                   2098: 
                   2099:                        if (prev != NULL)
                   2100:                                lease_dereference(&prev, MDL);
                   2101:                        lease_reference(&prev, cand, MDL);
                   2102: 
                   2103:                        if (cand->n_hw != NULL)
                   2104:                                lease_reference(&next, cand->n_hw, MDL);
                   2105: 
                   2106:                        lease_dereference(&cand, MDL);
                   2107: 
                   2108:                        if (next != NULL) {
                   2109:                                lease_reference(&cand, next, MDL);
                   2110:                                lease_dereference(&next, MDL);
                   2111:                        }
                   2112:                }
                   2113: 
                   2114:                /* If we want to insert 'before cand', and prev is NULL,
                   2115:                 * then it was the head of the list.  Assume that position.
                   2116:                 */
                   2117:                if (prev == NULL) {
                   2118:                        lease_reference(&lease->n_hw, head, MDL);
                   2119:                        lease_id_hash_delete(lease_hw_addr_hash,
                   2120:                                             lease->hardware_addr.hbuf,
                   2121:                                             lease->hardware_addr.hlen, MDL);
                   2122:                        lease_id_hash_add(lease_hw_addr_hash,
                   2123:                                          lease->hardware_addr.hbuf,
                   2124:                                          lease->hardware_addr.hlen,
                   2125:                                          lease, MDL);
                   2126:                } else /* (prev != NULL) */ {
                   2127:                        if(prev->n_hw != NULL) {
                   2128:                                lease_reference(&lease->n_hw, prev->n_hw,
                   2129:                                                MDL);
                   2130:                                lease_dereference(&prev->n_hw, MDL);
                   2131:                        }
                   2132:                        lease_reference(&prev->n_hw, lease, MDL);
                   2133: 
                   2134:                        lease_dereference(&prev, MDL);
                   2135:                }
                   2136: 
                   2137:                if (cand != NULL)
                   2138:                        lease_dereference(&cand, MDL);
                   2139:                lease_dereference(&head, MDL);
                   2140:        }
                   2141: }
                   2142: 
                   2143: /* Delete the specified lease from the hardware address hash. */
                   2144: 
                   2145: void hw_hash_delete (lease)
                   2146:        struct lease *lease;
                   2147: {
                   2148:        struct lease *head = (struct lease *)0;
                   2149:        struct lease *next = (struct lease *)0;
                   2150: 
1.1.1.1 ! misho    2151:        /*
        !          2152:         * If it's an infiniband address don't bother
        !          2153:         * as we don't have a useful address to hash.
        !          2154:         */
        !          2155:        if ((lease->hardware_addr.hlen == 1) &&
        !          2156:            (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
        !          2157:                return;
        !          2158: 
1.1       misho    2159:        /* If it's not in the hash, we have no work to do. */
                   2160:        if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
                   2161:                                    lease -> hardware_addr.hlen, MDL)) {
                   2162:                if (lease -> n_hw)
                   2163:                        lease_dereference (&lease -> n_hw, MDL);
                   2164:                return;
                   2165:        }
                   2166: 
                   2167:        /* If the lease we're freeing is at the head of the list,
                   2168:           remove the hash table entry and add a new one with the
                   2169:           next lease on the list (if there is one). */
                   2170:        if (head == lease) {
                   2171:                lease_id_hash_delete(lease_hw_addr_hash,
                   2172:                                     lease->hardware_addr.hbuf,
                   2173:                                     lease->hardware_addr.hlen, MDL);
                   2174:                if (lease->n_hw) {
                   2175:                        lease_id_hash_add(lease_hw_addr_hash,
                   2176:                                          lease->n_hw->hardware_addr.hbuf,
                   2177:                                          lease->n_hw->hardware_addr.hlen,
                   2178:                                          lease->n_hw, MDL);
                   2179:                        lease_dereference(&lease->n_hw, MDL);
                   2180:                }
                   2181:        } else {
                   2182:                /* Otherwise, look for the lease in the list of leases
                   2183:                   attached to the hash table entry, and remove it if
                   2184:                   we find it. */
                   2185:                while (head -> n_hw) {
                   2186:                        if (head -> n_hw == lease) {
                   2187:                                lease_dereference (&head -> n_hw, MDL);
                   2188:                                if (lease -> n_hw) {
                   2189:                                        lease_reference (&head -> n_hw,
                   2190:                                                         lease -> n_hw, MDL);
                   2191:                                        lease_dereference (&lease -> n_hw,
                   2192:                                                           MDL);
                   2193:                                }
                   2194:                                break;
                   2195:                        }
                   2196:                        lease_reference (&next, head -> n_hw, MDL);
                   2197:                        lease_dereference (&head, MDL);
                   2198:                        lease_reference (&head, next, MDL);
                   2199:                        lease_dereference (&next, MDL);
                   2200:                }
                   2201:        }
                   2202:        if (head)
                   2203:                lease_dereference (&head, MDL);
                   2204: }
                   2205: 
                   2206: /* Write all interesting leases to permanent storage. */
                   2207: 
                   2208: int write_leases ()
                   2209: {
                   2210:        struct lease *l;
                   2211:        struct shared_network *s;
                   2212:        struct pool *p;
                   2213:        struct host_decl *hp;
                   2214:        struct group_object *gp;
                   2215:        struct hash_bucket *hb;
                   2216:        struct class *cp;
                   2217:        struct collection *colp;
                   2218:        int i;
                   2219:        int num_written;
                   2220:        struct lease **lptr[RESERVED_LEASES+1];
                   2221: 
                   2222:        /* write all the dynamically-created class declarations. */
                   2223:        if (collections->classes) {
                   2224:                numclasseswritten = 0;
                   2225:                for (colp = collections ; colp ; colp = colp->next) {
                   2226:                        for (cp = colp->classes ; cp ; cp = cp->nic) {
                   2227:                                write_named_billing_class(
                   2228:                                                (unsigned char *)cp->name,
                   2229:                                                          0, cp);
                   2230:                        }
                   2231:                }
                   2232: 
                   2233:                /* XXXJAB this number doesn't include subclasses... */ 
                   2234:                log_info ("Wrote %d class decls to leases file.",
                   2235:                          numclasseswritten);
                   2236:        }
                   2237:        
                   2238:                        
                   2239:        /* Write all the dynamically-created group declarations. */
                   2240:        if (group_name_hash) {
                   2241:            num_written = 0;
                   2242:            for (i = 0; i < group_name_hash -> hash_count; i++) {
                   2243:                for (hb = group_name_hash -> buckets [i];
                   2244:                     hb; hb = hb -> next) {
                   2245:                        gp = (struct group_object *)hb -> value;
                   2246:                        if ((gp -> flags & GROUP_OBJECT_DYNAMIC) ||
                   2247:                            ((gp -> flags & GROUP_OBJECT_STATIC) &&
                   2248:                             (gp -> flags & GROUP_OBJECT_DELETED))) {
                   2249:                                if (!write_group (gp))
                   2250:                                        return 0;
                   2251:                                ++num_written;
                   2252:                        }
                   2253:                }
                   2254:            }
                   2255:            log_info ("Wrote %d group decls to leases file.", num_written);
                   2256:        }
                   2257: 
                   2258:        /* Write all the deleted host declarations. */
                   2259:        if (host_name_hash) {
                   2260:            num_written = 0;
                   2261:            for (i = 0; i < host_name_hash -> hash_count; i++) {
                   2262:                for (hb = host_name_hash -> buckets [i];
                   2263:                     hb; hb = hb -> next) {
                   2264:                        hp = (struct host_decl *)hb -> value;
                   2265:                        if (((hp -> flags & HOST_DECL_STATIC) &&
                   2266:                             (hp -> flags & HOST_DECL_DELETED))) {
                   2267:                                if (!write_host (hp))
                   2268:                                        return 0;
                   2269:                                ++num_written;
                   2270:                        }
                   2271:                }
                   2272:            }
                   2273:            log_info ("Wrote %d deleted host decls to leases file.",
                   2274:                      num_written);
                   2275:        }
                   2276: 
                   2277:        /* Write all the new, dynamic host declarations. */
                   2278:        if (host_name_hash) {
                   2279:            num_written = 0;
                   2280:            for (i = 0; i < host_name_hash -> hash_count; i++) {
                   2281:                for (hb = host_name_hash -> buckets [i];
                   2282:                     hb; hb = hb -> next) {
                   2283:                        hp = (struct host_decl *)hb -> value;
                   2284:                        if ((hp -> flags & HOST_DECL_DYNAMIC)) {
                   2285:                                if (!write_host (hp))
                   2286:                                        ++num_written;
                   2287:                        }
                   2288:                }
                   2289:            }
                   2290:            log_info ("Wrote %d new dynamic host decls to leases file.",
                   2291:                      num_written);
                   2292:        }
                   2293: 
                   2294: #if defined (FAILOVER_PROTOCOL)
                   2295:        /* Write all the failover states. */
                   2296:        if (!dhcp_failover_write_all_states ())
                   2297:                return 0;
                   2298: #endif
                   2299: 
                   2300:        /* Write all the leases. */
                   2301:        num_written = 0;
                   2302:        for (s = shared_networks; s; s = s -> next) {
                   2303:            for (p = s -> pools; p; p = p -> next) {
                   2304:                lptr [FREE_LEASES] = &p -> free;
                   2305:                lptr [ACTIVE_LEASES] = &p -> active;
                   2306:                lptr [EXPIRED_LEASES] = &p -> expired;
                   2307:                lptr [ABANDONED_LEASES] = &p -> abandoned;
                   2308:                lptr [BACKUP_LEASES] = &p -> backup;
                   2309:                lptr [RESERVED_LEASES] = &p->reserved;
                   2310: 
                   2311:                for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
                   2312:                    for (l = *(lptr [i]); l; l = l -> next) {
                   2313: #if !defined (DEBUG_DUMP_ALL_LEASES)
                   2314:                        if (l -> hardware_addr.hlen ||
                   2315:                            l -> uid_len ||
                   2316:                            (l -> binding_state != FTS_FREE))
                   2317: #endif
                   2318:                        {
                   2319:                            if (!write_lease (l))
                   2320:                                    return 0;
                   2321:                            num_written++;
                   2322:                        }
                   2323:                    }
                   2324:                }
                   2325:            }
                   2326:        }
                   2327:        log_info ("Wrote %d leases to leases file.", num_written);
                   2328: #ifdef DHCPv6
                   2329:        if (!write_leases6()) {
                   2330:                return 0;
                   2331:        }
                   2332: #endif /* DHCPv6 */
                   2333:        if (!commit_leases ())
                   2334:                return 0;
                   2335:        return 1;
                   2336: }
                   2337: 
                   2338: /* In addition to placing this lease upon a lease queue depending on its
                   2339:  * state, it also keeps track of the number of FREE and BACKUP leases in
                   2340:  * existence, and sets the sort_time on the lease.
                   2341:  *
                   2342:  * Sort_time is used in pool_timer() to determine when the lease will
                   2343:  * bubble to the top of the list and be supersede_lease()'d into its next
                   2344:  * state (possibly, if all goes well).  Example, ACTIVE leases move to
                   2345:  * EXPIRED state when the 'ends' value is reached, so that is its sort
                   2346:  * time.  Most queues are sorted by 'ends', since it is generally best
                   2347:  * practice to re-use the oldest lease, to reduce address collision
                   2348:  * chances.
                   2349:  */
                   2350: int lease_enqueue (struct lease *comp)
                   2351: {
                   2352:        struct lease **lq, *prev, *lp;
                   2353:        static struct lease **last_lq = NULL;
                   2354:        static struct lease *last_insert_point = NULL;
                   2355: 
                   2356:        /* No queue to put it on? */
                   2357:        if (!comp -> pool)
                   2358:                return 0;
                   2359: 
                   2360:        /* Figure out which queue it's going to. */
                   2361:        switch (comp -> binding_state) {
                   2362:              case FTS_FREE:
                   2363:                if (comp->flags & RESERVED_LEASE) {
                   2364:                        lq = &comp->pool->reserved;
                   2365:                } else {
                   2366:                        lq = &comp->pool->free;
                   2367:                        comp->pool->free_leases++;
                   2368:                }
                   2369:                comp -> sort_time = comp -> ends;
                   2370:                break;
                   2371: 
                   2372:              case FTS_ACTIVE:
                   2373:                lq = &comp -> pool -> active;
                   2374:                comp -> sort_time = comp -> ends;
                   2375:                break;
                   2376: 
                   2377:              case FTS_EXPIRED:
                   2378:              case FTS_RELEASED:
                   2379:              case FTS_RESET:
                   2380:                lq = &comp -> pool -> expired;
                   2381: #if defined(FAILOVER_PROTOCOL)
                   2382:                /* In partner_down, tsfp is the time at which the lease
                   2383:                 * may be reallocated (stos+mclt).  We can do that with
                   2384:                 * lease_mine_to_reallocate() anywhere between tsfp and
                   2385:                 * ends.  But we prefer to wait until ends before doing it
                   2386:                 * automatically (choose the greater of the two).  Note
                   2387:                 * that 'ends' is usually a historic timestamp in the
                   2388:                 * case of expired leases, is really only in the future
                   2389:                 * on released leases, and if we know a lease to be released
                   2390:                 * the peer might still know it to be active...in which case
                   2391:                 * it's possible the peer has renewed this lease, so avoid
                   2392:                 * doing that.
                   2393:                 */
                   2394:                if (comp->pool->failover_peer &&
                   2395:                    comp->pool->failover_peer->me.state == partner_down)
                   2396:                        comp->sort_time = (comp->tsfp > comp->ends) ?
                   2397:                                          comp->tsfp : comp->ends;
                   2398:                else
                   2399: #endif
                   2400:                        comp->sort_time = comp->ends;
                   2401: 
                   2402:                break;
                   2403: 
                   2404:              case FTS_ABANDONED:
                   2405:                lq = &comp -> pool -> abandoned;
                   2406:                comp -> sort_time = comp -> ends;
                   2407:                break;
                   2408: 
                   2409:              case FTS_BACKUP:
                   2410:                if (comp->flags & RESERVED_LEASE) {
                   2411:                        lq = &comp->pool->reserved;
                   2412:                } else {
                   2413:                        lq = &comp->pool->backup;
                   2414:                        comp->pool->backup_leases++;
                   2415:                }
                   2416:                comp -> sort_time = comp -> ends;
                   2417:                break;
                   2418: 
                   2419:              default:
                   2420:                log_error ("Lease with bogus binding state: %d",
                   2421:                           comp -> binding_state);
                   2422: #if defined (BINDING_STATE_DEBUG)
                   2423:                abort ();
                   2424: #endif
                   2425:                return 0;
                   2426:        }
                   2427: 
                   2428:        /* This only works during server startup: during runtime, the last
                   2429:         * lease may be dequeued in between calls.  If the queue is the same
                   2430:         * as was used previously, and the lease structure isn't (this is not
                   2431:         * a re-queue), use that as a starting point for the insertion-sort.
                   2432:         */
                   2433:        if ((server_starting & SS_QFOLLOW) && (lq == last_lq) &&
                   2434:            (comp != last_insert_point) && 
                   2435:            (last_insert_point->sort_time <= comp->sort_time)) {
                   2436:                prev = last_insert_point;
                   2437:                lp = prev->next;
                   2438:        } else {
                   2439:                prev = NULL;
                   2440:                lp = *lq;
                   2441:        }
                   2442: 
                   2443:        /* Insertion sort the lease onto the appropriate queue. */
                   2444:        for (; lp ; lp = lp->next) {
                   2445:                if (lp -> sort_time >= comp -> sort_time)
                   2446:                        break;
                   2447:                prev = lp;
                   2448:        }
                   2449: 
                   2450:        if (prev) {
                   2451:                if (prev -> next) {
                   2452:                        lease_reference (&comp -> next, prev -> next, MDL);
                   2453:                        lease_dereference (&prev -> next, MDL);
                   2454:                }
                   2455:                lease_reference (&prev -> next, comp, MDL);
                   2456:        } else {
                   2457:                if (*lq) {
                   2458:                        lease_reference (&comp -> next, *lq, MDL);
                   2459:                        lease_dereference (lq, MDL);
                   2460:                }
                   2461:                lease_reference (lq, comp, MDL);
                   2462:        }
                   2463:        last_insert_point = comp;
                   2464:        last_lq = lq;
                   2465:        return 1;
                   2466: }
                   2467: 
                   2468: /* For a given lease, sort it onto the right list in its pool and put it
                   2469:    in each appropriate hash, understanding that it's already by definition
                   2470:    in lease_ip_addr_hash. */
                   2471: 
                   2472: isc_result_t
                   2473: lease_instantiate(const void *key, unsigned len, void *object)
                   2474: {
                   2475:        struct lease *lease = object;
                   2476:        struct class *class;
                   2477:        /* XXX If the lease doesn't have a pool at this point, it's an
                   2478:           XXX orphan, which we *should* keep around until it expires,
                   2479:           XXX but which right now we just forget. */
                   2480:        if (!lease -> pool) {
                   2481:                lease_ip_hash_delete(lease_ip_addr_hash, lease->ip_addr.iabuf,
                   2482:                                     lease->ip_addr.len, MDL);
                   2483:                return ISC_R_SUCCESS;
                   2484:        }
                   2485:                
                   2486:        /* Put the lease on the right queue.  Failure to queue is probably
                   2487:         * due to a bogus binding state.  In such a case, we claim success,
                   2488:         * so that later leases in a hash_foreach are processed, but we
                   2489:         * return early as we really don't want hw address hash entries or
                   2490:         * other cruft to surround such a bogus entry.
                   2491:         */
                   2492:        if (!lease_enqueue(lease))
                   2493:                return ISC_R_SUCCESS;
                   2494: 
                   2495:        /* Record the lease in the uid hash if possible. */
                   2496:        if (lease -> uid) {
                   2497:                uid_hash_add (lease);
                   2498:        }
                   2499: 
                   2500:        /* Record it in the hardware address hash if possible. */
                   2501:        if (lease -> hardware_addr.hlen) {
                   2502:                hw_hash_add (lease);
                   2503:        }
                   2504: 
                   2505:        /* If the lease has a billing class, set up the billing. */
                   2506:        if (lease -> billing_class) {
                   2507:                class = (struct class *)0;
                   2508:                class_reference (&class, lease -> billing_class, MDL);
                   2509:                class_dereference (&lease -> billing_class, MDL);
                   2510:                /* If the lease is available for allocation, the billing
                   2511:                   is invalid, so we don't keep it. */
                   2512:                if (lease -> binding_state == FTS_ACTIVE ||
                   2513:                    lease -> binding_state == FTS_EXPIRED ||
                   2514:                    lease -> binding_state == FTS_RELEASED ||
                   2515:                    lease -> binding_state == FTS_RESET)
                   2516:                        bill_class (lease, class);
                   2517:                class_dereference (&class, MDL);
                   2518:        }
                   2519:        return ISC_R_SUCCESS;
                   2520: }
                   2521: 
                   2522: /* Run expiry events on every pool.   This is called on startup so that
                   2523:    any expiry events that occurred after the server stopped and before it
                   2524:    was restarted can be run.   At the same time, if failover support is
                   2525:    compiled in, we compute the balance of leases for the pool. */
                   2526: 
                   2527: void expire_all_pools ()
                   2528: {
                   2529:        struct shared_network *s;
                   2530:        struct pool *p;
                   2531:        int i;
                   2532:        struct lease *l;
                   2533:        struct lease **lptr[RESERVED_LEASES+1];
                   2534: 
                   2535:        /* Indicate that we are in the startup phase */
                   2536:        server_starting = SS_NOSYNC | SS_QFOLLOW;
                   2537: 
                   2538:        /* First, go over the hash list and actually put all the leases
                   2539:           on the appropriate lists. */
                   2540:        lease_ip_hash_foreach(lease_ip_addr_hash, lease_instantiate);
                   2541: 
                   2542:        /* Loop through each pool in each shared network and call the
                   2543:         * expiry routine on the pool.  It is no longer safe to follow
                   2544:         * the queue insertion point, as expiration of a lease can move
                   2545:         * it between queues (and this may be the lease that function
                   2546:         * points at).
                   2547:         */
                   2548:        server_starting &= ~SS_QFOLLOW;
                   2549:        for (s = shared_networks; s; s = s -> next) {
                   2550:            for (p = s -> pools; p; p = p -> next) {
                   2551:                pool_timer (p);
                   2552: 
                   2553:                p -> lease_count = 0;
                   2554:                p -> free_leases = 0;
                   2555:                p -> backup_leases = 0;
                   2556: 
                   2557:                lptr [FREE_LEASES] = &p -> free;
                   2558:                lptr [ACTIVE_LEASES] = &p -> active;
                   2559:                lptr [EXPIRED_LEASES] = &p -> expired;
                   2560:                lptr [ABANDONED_LEASES] = &p -> abandoned;
                   2561:                lptr [BACKUP_LEASES] = &p -> backup;
                   2562:                lptr [RESERVED_LEASES] = &p->reserved;
                   2563: 
                   2564:                for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
                   2565:                    for (l = *(lptr [i]); l; l = l -> next) {
                   2566:                        p -> lease_count++;
                   2567:                        if (l -> ends <= cur_time) {
                   2568:                                if (l->binding_state == FTS_FREE) {
                   2569:                                        if (i == FREE_LEASES)
                   2570:                                                p->free_leases++;
                   2571:                                        else if (i != RESERVED_LEASES)
                   2572:                                                log_fatal("Impossible case "
                   2573:                                                          "at %s:%d.", MDL);
                   2574:                                } else if (l->binding_state == FTS_BACKUP) {
                   2575:                                        if (i == BACKUP_LEASES)
                   2576:                                                p->backup_leases++;
                   2577:                                        else if (i != RESERVED_LEASES)
                   2578:                                                log_fatal("Impossible case "
                   2579:                                                          "at %s:%d.", MDL);
                   2580:                                }
                   2581:                        }
                   2582: #if defined (FAILOVER_PROTOCOL)
                   2583:                        if (p -> failover_peer &&
                   2584:                            l -> tstp > l -> atsfp &&
                   2585:                            !(l -> flags & ON_UPDATE_QUEUE)) {
                   2586:                                l -> desired_binding_state = l -> binding_state;
                   2587:                                dhcp_failover_queue_update (l, 1);
                   2588:                        }
                   2589: #endif
                   2590:                    }
                   2591:                }
                   2592:            }
                   2593:        }
                   2594: 
                   2595:        /* turn off startup phase */
                   2596:        server_starting = 0;
                   2597: }
                   2598: 
                   2599: void dump_subnets ()
                   2600: {
                   2601:        struct lease *l;
                   2602:        struct shared_network *s;
                   2603:        struct subnet *n;
                   2604:        struct pool *p;
                   2605:        struct lease **lptr[RESERVED_LEASES+1];
                   2606:        int i;
                   2607: 
                   2608:        log_info ("Subnets:");
                   2609:        for (n = subnets; n; n = n -> next_subnet) {
                   2610:                log_debug ("  Subnet %s", piaddr (n -> net));
                   2611:                log_debug ("     netmask %s",
                   2612:                       piaddr (n -> netmask));
                   2613:        }
                   2614:        log_info ("Shared networks:");
                   2615:        for (s = shared_networks; s; s = s -> next) {
                   2616:            log_info ("  %s", s -> name);
                   2617:            for (p = s -> pools; p; p = p -> next) {
                   2618:                lptr [FREE_LEASES] = &p -> free;
                   2619:                lptr [ACTIVE_LEASES] = &p -> active;
                   2620:                lptr [EXPIRED_LEASES] = &p -> expired;
                   2621:                lptr [ABANDONED_LEASES] = &p -> abandoned;
                   2622:                lptr [BACKUP_LEASES] = &p -> backup;
                   2623:                lptr [RESERVED_LEASES] = &p->reserved;
                   2624: 
                   2625:                for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
                   2626:                    for (l = *(lptr [i]); l; l = l -> next) {
                   2627:                            print_lease (l);
                   2628:                    }
                   2629:                }
                   2630:            }
                   2631:        }
                   2632: }
                   2633: 
                   2634: HASH_FUNCTIONS(lease_ip, const unsigned char *, struct lease, lease_ip_hash_t,
                   2635:               lease_reference, lease_dereference, do_ip4_hash)
                   2636: HASH_FUNCTIONS(lease_id, const unsigned char *, struct lease, lease_id_hash_t,
                   2637:               lease_reference, lease_dereference, do_id_hash)
                   2638: HASH_FUNCTIONS (host, const unsigned char *, struct host_decl, host_hash_t,
                   2639:                host_reference, host_dereference, do_string_hash)
                   2640: HASH_FUNCTIONS (class, const char *, struct class, class_hash_t,
                   2641:                class_reference, class_dereference, do_string_hash)
                   2642: 
                   2643: #if defined (DEBUG_MEMORY_LEAKAGE) && \
                   2644:                defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
                   2645: extern struct hash_table *dns_zone_hash;
                   2646: extern struct interface_info **interface_vector;
                   2647: extern int interface_count;
                   2648: dhcp_control_object_t *dhcp_control_object;
                   2649: extern struct hash_table *auth_key_hash;
                   2650: struct hash_table *universe_hash;
                   2651: struct universe **universes;
                   2652: int universe_count, universe_max;
                   2653: #if 0
                   2654: extern int end;
                   2655: #endif
                   2656: 
                   2657: #if defined (COMPACT_LEASES)
                   2658: extern struct lease *lease_hunks;
                   2659: #endif
                   2660: 
                   2661: void free_everything(void)
                   2662: {
                   2663:        struct subnet *sc = (struct subnet *)0, *sn = (struct subnet *)0;
                   2664:        struct shared_network *nc = (struct shared_network *)0,
                   2665:                *nn = (struct shared_network *)0;
                   2666:        struct pool *pc = (struct pool *)0, *pn = (struct pool *)0;
                   2667:        struct lease *lc = (struct lease *)0, *ln = (struct lease *)0;
                   2668:        struct interface_info *ic = (struct interface_info *)0,
                   2669:                *in = (struct interface_info *)0;
                   2670:        struct class *cc = (struct class *)0, *cn = (struct class *)0;
                   2671:        struct collection *lp;
                   2672:        int i;
                   2673: 
                   2674:        /* Get rid of all the hash tables. */
                   2675:        if (host_hw_addr_hash)
                   2676:                host_free_hash_table (&host_hw_addr_hash, MDL);
                   2677:        host_hw_addr_hash = 0;
                   2678:        if (host_uid_hash)
                   2679:                host_free_hash_table (&host_uid_hash, MDL);
                   2680:        host_uid_hash = 0;
                   2681:        if (lease_uid_hash)
                   2682:                lease_id_free_hash_table (&lease_uid_hash, MDL);
                   2683:        lease_uid_hash = 0;
                   2684:        if (lease_ip_addr_hash)
                   2685:                lease_ip_free_hash_table (&lease_ip_addr_hash, MDL);
                   2686:        lease_ip_addr_hash = 0;
                   2687:        if (lease_hw_addr_hash)
                   2688:                lease_id_free_hash_table (&lease_hw_addr_hash, MDL);
                   2689:        lease_hw_addr_hash = 0;
                   2690:        if (host_name_hash)
                   2691:                host_free_hash_table (&host_name_hash, MDL);
                   2692:        host_name_hash = 0;
                   2693:        if (dns_zone_hash)
                   2694:                dns_zone_free_hash_table (&dns_zone_hash, MDL);
                   2695:        dns_zone_hash = 0;
                   2696: 
                   2697:        while (host_id_info != NULL) {
                   2698:                host_id_info_t *tmp;
                   2699:                option_dereference(&host_id_info->option, MDL);
                   2700:                host_free_hash_table(&host_id_info->values_hash, MDL);
                   2701:                tmp = host_id_info->next;
                   2702:                dfree(host_id_info, MDL);
                   2703:                host_id_info = tmp;
                   2704:        }
                   2705: #if 0
                   2706:        if (auth_key_hash)
                   2707:                auth_key_free_hash_table (&auth_key_hash, MDL);
                   2708: #endif
                   2709:        auth_key_hash = 0;
                   2710: 
                   2711:        omapi_object_dereference ((omapi_object_t **)&dhcp_control_object,
                   2712:                                  MDL);
                   2713: 
                   2714:        for (lp = collections; lp; lp = lp -> next) {
                   2715:            if (lp -> classes) {
                   2716:                class_reference (&cn, lp -> classes, MDL);
                   2717:                do {
                   2718:                    if (cn) {
                   2719:                        class_reference (&cc, cn, MDL);
                   2720:                        class_dereference (&cn, MDL);
                   2721:                    }
                   2722:                    if (cc -> nic) {
                   2723:                        class_reference (&cn, cc -> nic, MDL);
                   2724:                        class_dereference (&cc -> nic, MDL);
                   2725:                    }
                   2726:                    group_dereference (&cc -> group, MDL);
                   2727:                    if (cc -> hash) {
                   2728:                            class_free_hash_table (&cc -> hash, MDL);
                   2729:                            cc -> hash = (struct hash_table *)0;
                   2730:                    }
                   2731:                    class_dereference (&cc, MDL);
                   2732:                } while (cn);
                   2733:                class_dereference (&lp -> classes, MDL);
                   2734:            }
                   2735:        }
                   2736: 
                   2737:        if (interface_vector) {
                   2738:            for (i = 0; i < interface_count; i++) {
                   2739:                if (interface_vector [i])
                   2740:                    interface_dereference (&interface_vector [i], MDL);
                   2741:            }
                   2742:            dfree (interface_vector, MDL);
                   2743:            interface_vector = 0;
                   2744:        }
                   2745: 
                   2746:        if (interfaces) {
                   2747:            interface_reference (&in, interfaces, MDL);
                   2748:            do {
                   2749:                if (in) {
                   2750:                    interface_reference (&ic, in, MDL);
                   2751:                    interface_dereference (&in, MDL);
                   2752:                }
                   2753:                if (ic -> next) {
                   2754:                    interface_reference (&in, ic -> next, MDL);
                   2755:                    interface_dereference (&ic -> next, MDL);
                   2756:                }
                   2757:                omapi_unregister_io_object ((omapi_object_t *)ic);
                   2758:                if (ic -> shared_network) {
                   2759:                    if (ic -> shared_network -> interface)
                   2760:                        interface_dereference
                   2761:                                (&ic -> shared_network -> interface, MDL);
                   2762:                    shared_network_dereference (&ic -> shared_network, MDL);
                   2763:                }
                   2764:                interface_dereference (&ic, MDL);
                   2765:            } while (in);
                   2766:            interface_dereference (&interfaces, MDL);
                   2767:        }
                   2768: 
                   2769:        /* Subnets are complicated because of the extra links. */
                   2770:        if (subnets) {
                   2771:            subnet_reference (&sn, subnets, MDL);
                   2772:            do {
                   2773:                if (sn) {
                   2774:                    subnet_reference (&sc, sn, MDL);
                   2775:                    subnet_dereference (&sn, MDL);
                   2776:                }
                   2777:                if (sc -> next_subnet) {
                   2778:                    subnet_reference (&sn, sc -> next_subnet, MDL);
                   2779:                    subnet_dereference (&sc -> next_subnet, MDL);
                   2780:                }
                   2781:                if (sc -> next_sibling)
                   2782:                    subnet_dereference (&sc -> next_sibling, MDL);
                   2783:                if (sc -> shared_network)
                   2784:                    shared_network_dereference (&sc -> shared_network, MDL);
                   2785:                group_dereference (&sc -> group, MDL);
                   2786:                if (sc -> interface)
                   2787:                    interface_dereference (&sc -> interface, MDL);
                   2788:                subnet_dereference (&sc, MDL);
                   2789:            } while (sn);
                   2790:            subnet_dereference (&subnets, MDL);
                   2791:        }
                   2792: 
                   2793:        /* So are shared networks. */
                   2794:        /* XXX: this doesn't work presently, but i'm ok just filtering
                   2795:         * it out of the noise (you get a bigger spike on the real leaks).
                   2796:         * It would be good to fix this, but it is not a "real bug," so not
                   2797:         * today.  This hack is incomplete, it doesn't trim out sub-values.
                   2798:         */
                   2799:        if (shared_networks) {
                   2800:                shared_network_dereference (&shared_networks, MDL);
                   2801:        /* This is the old method (tries to free memory twice, broken) */
                   2802:        } else if (0) {
                   2803:            shared_network_reference (&nn, shared_networks, MDL);
                   2804:            do {
                   2805:                if (nn) {
                   2806:                    shared_network_reference (&nc, nn, MDL);
                   2807:                    shared_network_dereference (&nn, MDL);
                   2808:                }
                   2809:                if (nc -> next) {
                   2810:                    shared_network_reference (&nn, nc -> next, MDL);
                   2811:                    shared_network_dereference (&nc -> next, MDL);
                   2812:                }
                   2813: 
                   2814:                /* As are pools. */
                   2815:                if (nc -> pools) {
                   2816:                    pool_reference (&pn, nc -> pools, MDL);
                   2817:                    do {
                   2818:                        struct lease **lptr[RESERVED_LEASES+1];
                   2819: 
                   2820:                        if (pn) {
                   2821:                            pool_reference (&pc, pn, MDL);
                   2822:                            pool_dereference (&pn, MDL);
                   2823:                        }
                   2824:                        if (pc -> next) {
                   2825:                            pool_reference (&pn, pc -> next, MDL);
                   2826:                            pool_dereference (&pc -> next, MDL);
                   2827:                        }
                   2828: 
                   2829:                        lptr [FREE_LEASES] = &pc -> free;
                   2830:                        lptr [ACTIVE_LEASES] = &pc -> active;
                   2831:                        lptr [EXPIRED_LEASES] = &pc -> expired;
                   2832:                        lptr [ABANDONED_LEASES] = &pc -> abandoned;
                   2833:                        lptr [BACKUP_LEASES] = &pc -> backup;
                   2834:                        lptr [RESERVED_LEASES] = &pc->reserved;
                   2835: 
                   2836:                        /* As (sigh) are leases. */
                   2837:                        for (i = FREE_LEASES ; i <= RESERVED_LEASES ; i++) {
                   2838:                            if (*lptr [i]) {
                   2839:                                lease_reference (&ln, *lptr [i], MDL);
                   2840:                                do {
                   2841:                                    if (ln) {
                   2842:                                        lease_reference (&lc, ln, MDL);
                   2843:                                        lease_dereference (&ln, MDL);
                   2844:                                    }
                   2845:                                    if (lc -> next) {
                   2846:                                        lease_reference (&ln, lc -> next, MDL);
                   2847:                                        lease_dereference (&lc -> next, MDL);
                   2848:                                    }
                   2849:                                    if (lc -> billing_class)
                   2850:                                       class_dereference (&lc -> billing_class,
                   2851:                                                          MDL);
                   2852:                                    if (lc -> state)
                   2853:                                        free_lease_state (lc -> state, MDL);
                   2854:                                    lc -> state = (struct lease_state *)0;
                   2855:                                    if (lc -> n_hw)
                   2856:                                        lease_dereference (&lc -> n_hw, MDL);
                   2857:                                    if (lc -> n_uid)
                   2858:                                        lease_dereference (&lc -> n_uid, MDL);
                   2859:                                    lease_dereference (&lc, MDL);
                   2860:                                } while (ln);
                   2861:                                lease_dereference (lptr [i], MDL);
                   2862:                            }
                   2863:                        }
                   2864:                        if (pc -> group)
                   2865:                            group_dereference (&pc -> group, MDL);
                   2866:                        if (pc -> shared_network)
                   2867:                            shared_network_dereference (&pc -> shared_network,
                   2868:                                                        MDL);
                   2869:                        pool_dereference (&pc, MDL);
                   2870:                    } while (pn);
                   2871:                    pool_dereference (&nc -> pools, MDL);
                   2872:                }
                   2873:                /* Because of a circular reference, we need to nuke this
                   2874:                   manually. */
                   2875:                group_dereference (&nc -> group, MDL);
                   2876:                shared_network_dereference (&nc, MDL);
                   2877:            } while (nn);
                   2878:            shared_network_dereference (&shared_networks, MDL);
                   2879:        }
                   2880: 
                   2881:        cancel_all_timeouts ();
                   2882:        relinquish_timeouts ();
                   2883:        relinquish_ackqueue();
                   2884:        trace_free_all ();
                   2885:        group_dereference (&root_group, MDL);
                   2886:        executable_statement_dereference (&default_classification_rules, MDL);
                   2887: 
                   2888:        shutdown_state = shutdown_drop_omapi_connections;
                   2889:        omapi_io_state_foreach (dhcp_io_shutdown, 0);
                   2890:        shutdown_state = shutdown_listeners;
                   2891:        omapi_io_state_foreach (dhcp_io_shutdown, 0);
                   2892:        shutdown_state = shutdown_dhcp;
                   2893:        omapi_io_state_foreach (dhcp_io_shutdown, 0);
                   2894: 
                   2895:        omapi_object_dereference ((omapi_object_t **)&icmp_state, MDL);
                   2896: 
                   2897:        universe_free_hash_table (&universe_hash, MDL);
                   2898:        for (i = 0; i < universe_count; i++) {
                   2899: #if 0
                   2900:                union {
                   2901:                        const char *c;
                   2902:                        char *s;
                   2903:                } foo;
                   2904: #endif
                   2905:                if (universes [i]) {
                   2906:                        if (universes[i]->name_hash)
                   2907:                            option_name_free_hash_table(
                   2908:                                                &universes[i]->name_hash,
                   2909:                                                MDL);
                   2910:                        if (universes[i]->code_hash)
                   2911:                            option_code_free_hash_table(
                   2912:                                                &universes[i]->code_hash,
                   2913:                                                MDL);
                   2914: #if 0
                   2915:                        if (universes [i] -> name > (char *)&end) {
                   2916:                                foo.c = universes [i] -> name;
                   2917:                                dfree (foo.s, MDL);
                   2918:                        }
                   2919:                        if (universes [i] > (struct universe *)&end)
                   2920:                                dfree (universes [i], MDL);
                   2921: #endif
                   2922:                }
                   2923:        }
                   2924:        dfree (universes, MDL);
                   2925: 
                   2926:        relinquish_free_lease_states ();
                   2927:        relinquish_free_pairs ();
                   2928:        relinquish_free_expressions ();
                   2929:        relinquish_free_binding_values ();
                   2930:        relinquish_free_option_caches ();
                   2931:        relinquish_free_packets ();
                   2932: #if defined(COMPACT_LEASES)
                   2933:        relinquish_lease_hunks ();
                   2934: #endif
                   2935:        relinquish_hash_bucket_hunks ();
                   2936:        omapi_type_relinquish ();
                   2937: }
                   2938: #endif /* DEBUG_MEMORY_LEAKAGE_ON_EXIT */

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