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

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

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