server/mdb.c

Go to the documentation of this file.
00001 /* mdb.c
00002 
00003    Server-specific in-memory database support. */
00004 
00005 /*
00006  * Copyright (c) 2011-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004-2009 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1996-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00030 #include "dhcpd.h"
00031 #include "omapip/hash.h"
00032 
00033 struct subnet *subnets;
00034 struct shared_network *shared_networks;
00035 host_hash_t *host_hw_addr_hash;
00036 host_hash_t *host_uid_hash;
00037 host_hash_t *host_name_hash;
00038 lease_id_hash_t *lease_uid_hash;
00039 lease_ip_hash_t *lease_ip_addr_hash;
00040 lease_id_hash_t *lease_hw_addr_hash;
00041 
00042 /*
00043  * We allow users to specify any option as a host identifier.
00044  *
00045  * Any host is uniquely identified by the combination of 
00046  * option type & option data.
00047  *
00048  * We expect people will only use a few types of options as host 
00049  * identifier. Because of this, we store a list with an entry for
00050  * each option type. Each of these has a hash table, which contains 
00051  * hash of the option data.
00052  *
00053  * For v6 we also include a relay count - this specifies which
00054  * relay to check for the requested option.  As each different
00055  * value of relays creates a new instance admins should use the
00056  * same value across each option for all host-identifers.
00057  * A value of 0 indicates that we aren't doing relay options
00058  * and should simply look in the current option list.
00059  */
00060 typedef struct host_id_info {
00061         struct option *option;
00062         host_hash_t *values_hash;
00063         int relays;
00064         struct host_id_info *next;
00065 } host_id_info_t;
00066 
00067 static host_id_info_t *host_id_info = NULL;
00068 
00069 int numclasseswritten;
00070 
00071 omapi_object_type_t *dhcp_type_host;
00072 
00073 isc_result_t enter_class(cd, dynamicp, commit)
00074         struct class *cd;
00075         int dynamicp;
00076         int commit;
00077 {
00078         if (!collections -> classes) {
00079                 /* A subclass with no parent is invalid. */
00080                 if (cd->name == NULL)
00081                         return DHCP_R_INVALIDARG;
00082 
00083                 class_reference (&collections -> classes, cd, MDL);
00084         } else if (cd->name != NULL) {  /* regular class */
00085                 struct class *c = 0;
00086 
00087                 if (find_class(&c, cd->name, MDL) != ISC_R_NOTFOUND) {
00088                         class_dereference(&c, MDL);
00089                         return ISC_R_EXISTS;
00090                 }
00091                 
00092                 /* Find the tail. */
00093                 for (c = collections -> classes;
00094                      c -> nic; c = c -> nic)
00095                         /* nothing */ ;
00096                 class_reference (&c -> nic, cd, MDL);
00097         }
00098 
00099         if (dynamicp && commit) {
00100                 const char *name = cd->name;
00101 
00102                 if (name == NULL) {
00103                         name = cd->superclass->name;
00104                 }
00105 
00106                 write_named_billing_class ((const unsigned char *)name, 0, cd);
00107                 if (!commit_leases ())
00108                         return ISC_R_IOERROR;
00109         }
00110 
00111         return ISC_R_SUCCESS;
00112 }
00113 
00114 
00115 /* Variable to check if we're starting the server.  The server will init as
00116  * starting - but just to be safe start out as false to avoid triggering new
00117  * special-case code
00118  * XXX: There is actually a server_startup state...which is never entered...
00119  */
00120 #define SS_NOSYNC       1
00121 #define SS_QFOLLOW      2
00122 static int server_starting = 0;
00123 
00124 static int find_uid_statement (struct executable_statement *esp,
00125                                void *vp, int condp)
00126 {
00127         struct executable_statement **evp = vp;
00128 
00129         if (esp -> op == supersede_option_statement &&
00130             esp -> data.option &&
00131             (esp -> data.option -> option -> universe ==
00132              &dhcp_universe) &&
00133             (esp -> data.option -> option -> code ==
00134              DHO_DHCP_CLIENT_IDENTIFIER)) {
00135                 if (condp) {
00136                         log_error ("dhcp client identifier may not be %s",
00137                                    "specified conditionally.");
00138                 } else if (!(*evp)) {
00139                         executable_statement_reference (evp, esp, MDL);
00140                         return 1;
00141                 } else {
00142                         log_error ("only one dhcp client identifier may be %s",
00143                                    "specified");
00144                 }
00145         }
00146         return 0;
00147 }
00148 
00149 
00150 static host_id_info_t *
00151 find_host_id_info(unsigned int option_code, int relays) {
00152         host_id_info_t *p;
00153 
00154         for (p = host_id_info; p != NULL; p = p->next) {
00155                 if ((p->option->code == option_code) &&
00156                     (p->relays == relays)) {
00157                         break;
00158                 }
00159         }
00160         return p;
00161 }
00162 
00163 /* Debugging code */
00164 #if 0
00165 isc_result_t
00166 print_host(const void *name, unsigned len, void *value) {
00167         struct host_decl *h;
00168         printf("--------------\n");
00169         printf("name:'%s'\n", print_hex_1(len, name, 60));
00170         printf("len:%d\n", len);
00171         h = (struct host_decl *)value;
00172         printf("host @%p is '%s'\n", h, h->name);
00173         return ISC_R_SUCCESS;
00174 }
00175 
00176 void
00177 hash_print_hosts(struct hash_table *h) {
00178         hash_foreach(h, print_host);
00179         printf("--------------\n");
00180 }
00181 #endif /* 0 */
00182 
00183 void
00184 change_host_uid(struct host_decl *host, const char *uid, int len) {
00185         /* XXX: should consolidate this type of code throughout */
00186         if (host_uid_hash == NULL) {
00187                 if (!host_new_hash(&host_uid_hash, HOST_HASH_SIZE, MDL)) {
00188                         log_fatal("Can't allocate host/uid hash");
00189                 }
00190         }
00191 
00192         /* 
00193          * Remove the old entry, if one exists.
00194          */
00195         if (host->client_identifier.data != NULL) {
00196                 host_hash_delete(host_uid_hash,
00197                                  host->client_identifier.data,
00198                                  host->client_identifier.len,
00199                                  MDL);
00200                 data_string_forget(&host->client_identifier, MDL);
00201         }
00202 
00203         /* 
00204          * Set our new value.
00205          */
00206         memset(&host->client_identifier, 0, sizeof(host->client_identifier));
00207         host->client_identifier.len = len;
00208         if (!buffer_allocate(&host->client_identifier.buffer, len, MDL)) {
00209                 log_fatal("Can't allocate uid buffer");
00210         }
00211         host->client_identifier.data = host->client_identifier.buffer->data;
00212         memcpy((char *)host->client_identifier.data, uid, len);
00213 
00214         /*
00215          * And add to hash.
00216          */
00217         host_hash_add(host_uid_hash, host->client_identifier.data, 
00218                       host->client_identifier.len, host, MDL);
00219 }
00220 
00221 isc_result_t enter_host (hd, dynamicp, commit)
00222         struct host_decl *hd;
00223         int dynamicp;
00224         int commit;
00225 {
00226         struct host_decl *hp = (struct host_decl *)0;
00227         struct host_decl *np = (struct host_decl *)0;
00228         struct executable_statement *esp;
00229         host_id_info_t *h_id_info;
00230 
00231         if (!host_name_hash) {
00232                 if (!host_new_hash(&host_name_hash, HOST_HASH_SIZE, MDL))
00233                         log_fatal ("Can't allocate host name hash");
00234                 host_hash_add (host_name_hash,
00235                                (unsigned char *)hd -> name,
00236                                strlen (hd -> name), hd, MDL);
00237         } else {
00238                 host_hash_lookup (&hp, host_name_hash,
00239                                   (unsigned char *)hd -> name,
00240                                   strlen (hd -> name), MDL);
00241 
00242                 /* If it's deleted, we can supersede it. */
00243                 if (hp && (hp -> flags & HOST_DECL_DELETED)) {
00244                         host_hash_delete (host_name_hash,
00245                                           (unsigned char *)hd -> name,
00246                                           strlen (hd -> name), MDL);
00247                         /* If the old entry wasn't dynamic, then we
00248                            always have to keep the deletion. */
00249                         if (hp -> flags & HOST_DECL_STATIC) {
00250                                 hd -> flags |= HOST_DECL_STATIC;
00251                         }
00252                         host_dereference (&hp, MDL);
00253                 }
00254 
00255                 /* If we are updating an existing host declaration, we
00256                    can just delete it and add it again. */
00257                 if (hp && hp == hd) {
00258                         host_dereference (&hp, MDL);
00259                         delete_host (hd, 0);
00260                         if (!write_host (hd))
00261                                 return ISC_R_IOERROR;
00262                         hd -> flags &= ~HOST_DECL_DELETED;
00263                 }
00264 
00265                 /* If there isn't already a host decl matching this
00266                    address, add it to the hash table. */
00267                 if (!hp) {
00268                         host_hash_add (host_name_hash,
00269                                        (unsigned char *)hd -> name,
00270                                        strlen (hd -> name), hd, MDL);
00271                 } else {
00272                         /* XXX actually, we have to delete the old one
00273                            XXX carefully and replace it.   Not done yet. */
00274                         host_dereference (&hp, MDL);
00275                         return ISC_R_EXISTS;
00276                 }
00277         }
00278 
00279         if (hd -> n_ipaddr)
00280                 host_dereference (&hd -> n_ipaddr, MDL);
00281 
00282         if (!hd -> type)
00283                 hd -> type = dhcp_type_host;
00284 
00285         if (hd -> interface.hlen) {
00286                 if (!host_hw_addr_hash) {
00287                         if (!host_new_hash(&host_hw_addr_hash,
00288                                            HOST_HASH_SIZE, MDL))
00289                                 log_fatal ("Can't allocate host/hw hash");
00290                 } else {
00291                         /* If there isn't already a host decl matching this
00292                            address, add it to the hash table. */
00293                         host_hash_lookup (&hp, host_hw_addr_hash,
00294                                           hd -> interface.hbuf,
00295                                           hd -> interface.hlen, MDL);
00296                 }
00297                 if (!hp)
00298                         host_hash_add (host_hw_addr_hash, hd -> interface.hbuf,
00299                                        hd -> interface.hlen, hd, MDL);
00300                 else {
00301                         /* If there was already a host declaration for
00302                            this hardware address, add this one to the
00303                            end of the list. */
00304                         for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr)
00305                                 ;
00306                         host_reference (&np -> n_ipaddr, hd, MDL);
00307                         host_dereference (&hp, MDL);
00308                 }
00309         }
00310 
00311         /* See if there's a statement that sets the client identifier.
00312            This is a kludge - the client identifier really shouldn't be
00313            set with an executable statement. */
00314         esp = NULL;
00315         if (executable_statement_foreach (hd->group->statements,
00316                                           find_uid_statement, &esp, 0)) {
00317                 (void) evaluate_option_cache (&hd->client_identifier,
00318                                               NULL, NULL, NULL, NULL, NULL, 
00319                                               &global_scope,
00320                                               esp->data.option, MDL);
00321         }
00322 
00323         /* If we got a client identifier, hash this entry by
00324            client identifier. */
00325         if (hd -> client_identifier.len) {
00326                 /* If there's no uid hash, make one; otherwise, see if
00327                    there's already an entry in the hash for this host. */
00328                 if (!host_uid_hash) {
00329                         if (!host_new_hash(&host_uid_hash,
00330                                            HOST_HASH_SIZE, MDL))
00331                                 log_fatal ("Can't allocate host/uid hash");
00332 
00333                         host_hash_add (host_uid_hash,
00334                                        hd -> client_identifier.data,
00335                                        hd -> client_identifier.len,
00336                                        hd, MDL);
00337                 } else {
00338                         /* If there's already a host declaration for this
00339                            client identifier, add this one to the end of the
00340                            list.  Otherwise, add it to the hash table. */
00341                         if (host_hash_lookup (&hp, host_uid_hash,
00342                                               hd -> client_identifier.data,
00343                                               hd -> client_identifier.len,
00344                                               MDL)) {
00345                                 /* Don't link it in twice... */
00346                                 if (!np) {
00347                                         for (np = hp; np -> n_ipaddr;
00348                                              np = np -> n_ipaddr) {
00349                                                 if (hd == np)
00350                                                     break;
00351                                         }
00352                                         if (hd != np)
00353                                             host_reference (&np -> n_ipaddr,
00354                                                             hd, MDL);
00355                                 }
00356                                 host_dereference (&hp, MDL);
00357                         } else {
00358                                 host_hash_add (host_uid_hash,
00359                                                hd -> client_identifier.data,
00360                                                hd -> client_identifier.len,
00361                                                hd, MDL);
00362                         }
00363                 }
00364         }
00365 
00366 
00367         /*
00368          * If we use an option as our host identifier, record it here.
00369          */
00370         if (hd->host_id_option != NULL) {
00371                 /*
00372                  * Look for the host identifier information for this option,
00373                  * and create a new entry if there is none.
00374                  */
00375                 h_id_info = find_host_id_info(hd->host_id_option->code,
00376                                               hd->relays);
00377                 if (h_id_info == NULL) {
00378                         h_id_info = dmalloc(sizeof(*h_id_info), MDL);
00379                         if (h_id_info == NULL) {
00380                                 log_fatal("No memory for host-identifier "
00381                                           "option information.");
00382                         }
00383                         option_reference(&h_id_info->option, 
00384                                          hd->host_id_option, MDL);
00385                         if (!host_new_hash(&h_id_info->values_hash, 
00386                                            HOST_HASH_SIZE, MDL)) {
00387                                 log_fatal("No memory for host-identifier "
00388                                           "option hash.");
00389                         }
00390                         h_id_info->relays = hd->relays;
00391                         h_id_info->next = host_id_info;
00392                         host_id_info = h_id_info;
00393                 }
00394 
00395                 if (host_hash_lookup(&hp, h_id_info->values_hash, 
00396                                      hd->host_id.data, hd->host_id.len, MDL)) {
00397                         /* 
00398                          * If this option is already present, then add 
00399                          * this host to the list in n_ipaddr, unless
00400                          * we have already done so previously.
00401                          *
00402                          * XXXSK: This seems scary to me, but I don't
00403                          *        fully understand how these are used. 
00404                          *        Shouldn't there be multiple lists, or 
00405                          *        maybe we should just forbid duplicates?
00406                          */
00407                         if (np == NULL) {
00408                                 np = hp;
00409                                 while (np->n_ipaddr != NULL) {
00410                                         np = np->n_ipaddr;
00411                                 }
00412                                 if (hd != np) {
00413                                         host_reference(&np->n_ipaddr, hd, MDL);
00414                                 }
00415                         }
00416                         host_dereference(&hp, MDL);
00417                 } else {
00418                         host_hash_add(h_id_info->values_hash, 
00419                                       hd->host_id.data,
00420                                       hd->host_id.len,
00421                                       hd, MDL);
00422                 }
00423         }
00424 
00425         if (dynamicp && commit) {
00426                 if (!write_host (hd))
00427                         return ISC_R_IOERROR;
00428                 if (!commit_leases ())
00429                         return ISC_R_IOERROR;
00430         }
00431 
00432         return ISC_R_SUCCESS;
00433 }
00434 
00435 
00436 isc_result_t delete_class (cp, commit)
00437         struct class *cp;
00438         int commit;
00439 {
00440         cp->flags |= CLASS_DECL_DELETED;
00441 
00442         /* do the write first as we won't be leaving it in any data
00443            structures, unlike the host objects */
00444         
00445         if (commit) {
00446                 write_named_billing_class ((unsigned char *)cp->name, 0, cp);
00447                 if (!commit_leases ())
00448                         return ISC_R_IOERROR;
00449         }
00450         
00451         /*
00452          * If this is a subclass remove it from the class's hash table
00453          */
00454         if (cp->superclass) {
00455                 class_hash_delete(cp->superclass->hash, 
00456                                   (const char *)cp->hash_string.data,
00457                                   cp->hash_string.len,
00458                                   MDL);
00459         }
00460 
00461         /* remove from collections */
00462         unlink_class(&cp);
00463 
00464         return ISC_R_SUCCESS;
00465 }
00466 
00467 
00468 isc_result_t delete_host (hd, commit)
00469         struct host_decl *hd;
00470         int commit;
00471 {
00472         struct host_decl *hp = (struct host_decl *)0;
00473         struct host_decl *np = (struct host_decl *)0;
00474         struct host_decl *foo;
00475         int hw_head = 0, uid_head = 1;
00476 
00477         /* Don't need to do it twice. */
00478         if (hd -> flags & HOST_DECL_DELETED)
00479                 return ISC_R_SUCCESS;
00480 
00481         /* But we do need to do it once!   :') */
00482         hd -> flags |= HOST_DECL_DELETED;
00483 
00484         if (hd -> interface.hlen) {
00485             if (host_hw_addr_hash) {
00486                 if (host_hash_lookup (&hp, host_hw_addr_hash,
00487                                       hd -> interface.hbuf,
00488                                       hd -> interface.hlen, MDL)) {
00489                     if (hp == hd) {
00490                         host_hash_delete (host_hw_addr_hash,
00491                                           hd -> interface.hbuf,
00492                                           hd -> interface.hlen, MDL);
00493                         hw_head = 1;
00494                     } else {
00495                         np = (struct host_decl *)0;
00496                         foo = (struct host_decl *)0;
00497                         host_reference (&foo, hp, MDL);
00498                         while (foo) {
00499                             if (foo == hd)
00500                                     break;
00501                             if (np)
00502                                     host_dereference (&np, MDL);
00503                             host_reference (&np, foo, MDL);
00504                             host_dereference (&foo, MDL);
00505                             if (np -> n_ipaddr)
00506                                     host_reference (&foo, np -> n_ipaddr, MDL);
00507                         }
00508 
00509                         if (foo) {
00510                             host_dereference (&np -> n_ipaddr, MDL);
00511                             if (hd -> n_ipaddr)
00512                                 host_reference (&np -> n_ipaddr,
00513                                                 hd -> n_ipaddr, MDL);
00514                             host_dereference (&foo, MDL);
00515                         }
00516                         if (np)
00517                                 host_dereference (&np, MDL);
00518                     }
00519                     host_dereference (&hp, MDL);
00520                 }
00521             }
00522         }
00523 
00524         /* If we got a client identifier, hash this entry by
00525            client identifier. */
00526         if (hd -> client_identifier.len) {
00527             if (host_uid_hash) {
00528                 if (host_hash_lookup (&hp, host_uid_hash,
00529                                       hd -> client_identifier.data,
00530                                       hd -> client_identifier.len, MDL)) {
00531                     if (hp == hd) {
00532                         host_hash_delete (host_uid_hash,
00533                                           hd -> client_identifier.data,
00534                                           hd -> client_identifier.len, MDL);
00535                         uid_head = 1;
00536                     } else {
00537                         np = (struct host_decl *)0;
00538                         foo = (struct host_decl *)0;
00539                         host_reference (&foo, hp, MDL);
00540                         while (foo) {
00541                             if (foo == hd)
00542                                     break;
00543                             if (np)
00544                                 host_dereference (&np, MDL);
00545                             host_reference (&np, foo, MDL);
00546                             host_dereference (&foo, MDL);
00547                             if (np -> n_ipaddr)
00548                                     host_reference (&foo, np -> n_ipaddr, MDL);
00549                         }
00550 
00551                         if (foo) {
00552                             host_dereference (&np -> n_ipaddr, MDL);
00553                             if (hd -> n_ipaddr)
00554                                 host_reference (&np -> n_ipaddr,
00555                                                 hd -> n_ipaddr, MDL);
00556                             host_dereference (&foo, MDL);
00557                         }
00558                         if (np)
00559                                 host_dereference (&np, MDL);
00560                     }
00561                     host_dereference (&hp, MDL);
00562                 }
00563             }
00564         }
00565 
00566         if (hd->host_id_option != NULL) {
00567                 option_dereference(&hd->host_id_option, MDL);
00568                 data_string_forget(&hd->host_id, MDL);
00569         }
00570 
00571         if (hd -> n_ipaddr) {
00572                 if (uid_head && hd -> n_ipaddr -> client_identifier.len) {
00573                         host_hash_add
00574                                 (host_uid_hash,
00575                                  hd -> n_ipaddr -> client_identifier.data,
00576                                  hd -> n_ipaddr -> client_identifier.len,
00577                                  hd -> n_ipaddr, MDL);
00578                 }
00579                 if (hw_head && hd -> n_ipaddr -> interface.hlen) {
00580                         host_hash_add (host_hw_addr_hash,
00581                                        hd -> n_ipaddr -> interface.hbuf,
00582                                        hd -> n_ipaddr -> interface.hlen,
00583                                        hd -> n_ipaddr, MDL);
00584                 }
00585                 host_dereference (&hd -> n_ipaddr, MDL);
00586         }
00587 
00588         if (host_name_hash) {
00589                 if (host_hash_lookup (&hp, host_name_hash,
00590                                       (unsigned char *)hd -> name,
00591                                       strlen (hd -> name), MDL)) {
00592                         if (hp == hd && !(hp -> flags & HOST_DECL_STATIC)) {
00593                                 host_hash_delete (host_name_hash,
00594                                                   (unsigned char *)hd -> name,
00595                                                   strlen (hd -> name), MDL);
00596                         }
00597                         host_dereference (&hp, MDL);
00598                 }
00599         }
00600 
00601         if (commit) {
00602                 if (!write_host (hd))
00603                         return ISC_R_IOERROR;
00604                 if (!commit_leases ())
00605                         return ISC_R_IOERROR;
00606         }
00607         return ISC_R_SUCCESS;
00608 }
00609 
00610 int find_hosts_by_haddr (struct host_decl **hp, int htype,
00611                          const unsigned char *haddr, unsigned hlen,
00612                          const char *file, int line)
00613 {
00614         struct hardware h;
00615 #if defined(LDAP_CONFIGURATION)
00616         int ret;
00617 
00618         if ((ret = find_haddr_in_ldap (hp, htype, hlen, haddr, file, line)))
00619                 return ret;
00620 #endif
00621 
00622         h.hlen = hlen + 1;
00623         h.hbuf [0] = htype;
00624         memcpy (&h.hbuf [1], haddr, hlen);
00625 
00626         return host_hash_lookup (hp, host_hw_addr_hash,
00627                                  h.hbuf, h.hlen, file, line);
00628 }
00629 
00630 int find_hosts_by_uid (struct host_decl **hp,
00631                        const unsigned char *data, unsigned len,
00632                        const char *file, int line)
00633 {
00634         return host_hash_lookup (hp, host_uid_hash, data, len, file, line);
00635 }
00636 
00637 int
00638 find_hosts_by_option(struct host_decl **hp, 
00639                      struct packet *packet,
00640                      struct option_state *opt_state,
00641                      const char *file, int line) {
00642         host_id_info_t *p;
00643         struct option_cache *oc;
00644         struct data_string data;
00645         int found;
00646         struct packet *relay_packet;
00647         struct option_state *relay_state;
00648         
00649         for (p = host_id_info; p != NULL; p = p->next) {
00650                 relay_packet = packet;  
00651                 relay_state = opt_state;
00652 
00653                 /* If this option block is for a relay (relays != 0)
00654                  * and we are processing the main options and not
00655                  * options from the IA (packet->options == opt_state)
00656                  * try to find the proper relay
00657                  */
00658                 if ((p->relays != 0) && (packet->options == opt_state)) {
00659                         int i = p->relays;
00660                         while ((i != 0) &&
00661                                (relay_packet->dhcpv6_container_packet != NULL)) {
00662                                 relay_packet =
00663                                         relay_packet->dhcpv6_container_packet;
00664                                 i--;
00665                         }
00666                         /* We wanted a specific relay but were
00667                          * unable to find it */
00668                         if ((p->relays <= MAX_V6RELAY_HOPS) && (i != 0))
00669                                 continue;
00670 
00671                         relay_state = relay_packet->options;
00672                 }
00673 
00674                 oc = lookup_option(p->option->universe, 
00675                                    relay_state, p->option->code);
00676                 if (oc != NULL) {
00677                         memset(&data, 0, sizeof(data));
00678 
00679                         if (!evaluate_option_cache(&data, relay_packet, NULL,
00680                                                    NULL, relay_state, NULL,
00681                                                    &global_scope, oc, 
00682                                                    MDL)) {
00683                                 log_error("Error evaluating option cache");
00684                                 return 0;
00685                         }
00686                         
00687                         found = host_hash_lookup(hp, p->values_hash, 
00688                                                  data.data, data.len,
00689                                                  file, line);
00690 
00691                         data_string_forget(&data, MDL);
00692 
00693                         if (found) {
00694                                 return 1;
00695                         }
00696                 }
00697         }
00698         return 0;
00699 }
00700 
00701 /* More than one host_decl can be returned by find_hosts_by_haddr or
00702    find_hosts_by_uid, and each host_decl can have multiple addresses.
00703    Loop through the list of hosts, and then for each host, through the
00704    list of addresses, looking for an address that's in the same shared
00705    network as the one specified.    Store the matching address through
00706    the addr pointer, update the host pointer to point at the host_decl
00707    that matched, and return the subnet that matched. */
00708 
00709 int find_host_for_network (struct subnet **sp, struct host_decl **host,
00710                            struct iaddr *addr, struct shared_network *share)
00711 {
00712         int i;
00713         struct iaddr ip_address;
00714         struct host_decl *hp;
00715         struct data_string fixed_addr;
00716 
00717         memset (&fixed_addr, 0, sizeof fixed_addr);
00718 
00719         for (hp = *host; hp; hp = hp -> n_ipaddr) {
00720                 if (!hp -> fixed_addr)
00721                         continue;
00722                 if (!evaluate_option_cache (&fixed_addr, (struct packet *)0,
00723                                             (struct lease *)0,
00724                                             (struct client_state *)0,
00725                                             (struct option_state *)0,
00726                                             (struct option_state *)0,
00727                                             &global_scope,
00728                                             hp -> fixed_addr, MDL))
00729                         continue;
00730                 for (i = 0; i < fixed_addr.len; i += 4) {
00731                         ip_address.len = 4;
00732                         memcpy (ip_address.iabuf,
00733                                 fixed_addr.data + i, 4);
00734                         if (find_grouped_subnet (sp, share, ip_address, MDL)) {
00735                                 struct host_decl *tmp = (struct host_decl *)0;
00736                                 *addr = ip_address;
00737                                 /* This is probably not necessary, but
00738                                    just in case *host is the only reference
00739                                    to that host declaration, make a temporary
00740                                    reference so that dereferencing it doesn't
00741                                    dereference hp out from under us. */
00742                                 host_reference (&tmp, *host, MDL);
00743                                 host_dereference (host, MDL);
00744                                 host_reference (host, hp, MDL);
00745                                 host_dereference (&tmp, MDL);
00746                                 data_string_forget (&fixed_addr, MDL);
00747                                 return 1;
00748                         }
00749                 }
00750                 data_string_forget (&fixed_addr, MDL);
00751         }
00752         return 0;
00753 }
00754 
00755 void new_address_range (cfile, low, high, subnet, pool, lpchain)
00756         struct parse *cfile;
00757         struct iaddr low, high;
00758         struct subnet *subnet;
00759         struct pool *pool;
00760         struct lease **lpchain;
00761 {
00762 #if defined(COMPACT_LEASES)
00763         struct lease *address_range;
00764 #endif
00765         unsigned min, max, i;
00766         char lowbuf [16], highbuf [16], netbuf [16];
00767         struct shared_network *share = subnet -> shared_network;
00768         struct lease *lt = (struct lease *)0;
00769 #if !defined(COMPACT_LEASES)
00770         isc_result_t status;
00771 #endif
00772 
00773         /* All subnets should have attached shared network structures. */
00774         if (!share) {
00775                 strcpy (netbuf, piaddr (subnet -> net));
00776                 log_fatal ("No shared network for network %s (%s)",
00777                        netbuf, piaddr (subnet -> netmask));
00778         }
00779 
00780         /* Initialize the hash table if it hasn't been done yet. */
00781         if (!lease_uid_hash) {
00782                 if (!lease_id_new_hash(&lease_uid_hash, LEASE_HASH_SIZE, MDL))
00783                         log_fatal ("Can't allocate lease/uid hash");
00784         }
00785         if (!lease_ip_addr_hash) {
00786                 if (!lease_ip_new_hash(&lease_ip_addr_hash, LEASE_HASH_SIZE,
00787                                        MDL))
00788                         log_fatal ("Can't allocate lease/ip hash");
00789         }
00790         if (!lease_hw_addr_hash) {
00791                 if (!lease_id_new_hash(&lease_hw_addr_hash, LEASE_HASH_SIZE,
00792                                        MDL))
00793                         log_fatal ("Can't allocate lease/hw hash");
00794         }
00795 
00796         /* Make sure that high and low addresses are in this subnet. */
00797         if (!addr_eq(subnet->net, subnet_number(low, subnet->netmask))) {
00798                 strcpy(lowbuf, piaddr(low));
00799                 strcpy(netbuf, piaddr(subnet->net));
00800                 log_fatal("bad range, address %s not in subnet %s netmask %s",
00801                           lowbuf, netbuf, piaddr(subnet->netmask));
00802         }
00803 
00804         if (!addr_eq(subnet->net, subnet_number(high, subnet->netmask))) {
00805                 strcpy(highbuf, piaddr(high));
00806                 strcpy(netbuf, piaddr(subnet->net));
00807                 log_fatal("bad range, address %s not in subnet %s netmask %s",
00808                           highbuf, netbuf, piaddr(subnet->netmask));
00809         }
00810 
00811         /* Get the high and low host addresses... */
00812         max = host_addr (high, subnet -> netmask);
00813         min = host_addr (low, subnet -> netmask);
00814 
00815         /* Allow range to be specified high-to-low as well as low-to-high. */
00816         if (min > max) {
00817                 max = min;
00818                 min = host_addr (high, subnet -> netmask);
00819         }
00820 
00821         /* Get a lease structure for each address in the range. */
00822 #if defined (COMPACT_LEASES)
00823         address_range = new_leases (max - min + 1, MDL);
00824         if (!address_range) {
00825                 strcpy (lowbuf, piaddr (low));
00826                 strcpy (highbuf, piaddr (high));
00827                 log_fatal ("No memory for address range %s-%s.",
00828                            lowbuf, highbuf);
00829         }
00830 #endif
00831 
00832         /* Fill out the lease structures with some minimal information. */
00833         for (i = 0; i < max - min + 1; i++) {
00834                 struct lease *lp = (struct lease *)0;
00835 #if defined (COMPACT_LEASES)
00836                 omapi_object_initialize ((omapi_object_t *)&address_range [i],
00837                                          dhcp_type_lease,
00838                                          0, sizeof (struct lease), MDL);
00839                 lease_reference (&lp, &address_range [i], MDL);
00840 #else
00841                 status = lease_allocate (&lp, MDL);
00842                 if (status != ISC_R_SUCCESS)
00843                         log_fatal ("No memory for lease %s: %s",
00844                                    piaddr (ip_addr (subnet -> net,
00845                                                     subnet -> netmask,
00846                                                     i + min)),
00847                                    isc_result_totext (status));
00848 #endif
00849                 lp->ip_addr = ip_addr(subnet->net, subnet->netmask, i + min);
00850                 lp->starts = MIN_TIME;
00851                 lp->ends = MIN_TIME;
00852                 subnet_reference(&lp->subnet, subnet, MDL);
00853                 pool_reference(&lp->pool, pool, MDL);
00854                 lp->binding_state = FTS_FREE;
00855                 lp->next_binding_state = FTS_FREE;
00856                 lp->rewind_binding_state = FTS_FREE;
00857                 lp->flags = 0;
00858 
00859                 /* Remember the lease in the IP address hash. */
00860                 if (find_lease_by_ip_addr (&lt, lp -> ip_addr, MDL)) {
00861                         if (lt -> pool) {
00862                                 parse_warn (cfile,
00863                                             "lease %s is declared twice!",
00864                                             piaddr (lp -> ip_addr));
00865                         } else
00866                                 pool_reference (&lt -> pool, pool, MDL);
00867                         lease_dereference (&lt, MDL);
00868                 } else
00869                         lease_ip_hash_add(lease_ip_addr_hash,
00870                                           lp->ip_addr.iabuf, lp->ip_addr.len,
00871                                           lp, MDL);
00872                 /* Put the lease on the chain for the caller. */
00873                 if (lpchain) {
00874                         if (*lpchain) {
00875                                 lease_reference (&lp -> next, *lpchain, MDL);
00876                                 lease_dereference (lpchain, MDL);
00877                         }
00878                         lease_reference (lpchain, lp, MDL);
00879                 }
00880                 lease_dereference (&lp, MDL);
00881         }
00882 }
00883 
00884 int find_subnet (struct subnet **sp,
00885                  struct iaddr addr, const char *file, int line)
00886 {
00887         struct subnet *rv;
00888 
00889         for (rv = subnets; rv; rv = rv -> next_subnet) {
00890                 if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
00891                         if (subnet_reference (sp, rv,
00892                                               file, line) != ISC_R_SUCCESS)
00893                                 return 0;
00894                         return 1;
00895                 }
00896         }
00897         return 0;
00898 }
00899 
00900 int find_grouped_subnet (struct subnet **sp,
00901                          struct shared_network *share, struct iaddr addr,
00902                          const char *file, int line)
00903 {
00904         struct subnet *rv;
00905 
00906         for (rv = share -> subnets; rv; rv = rv -> next_sibling) {
00907                 if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
00908                         if (subnet_reference (sp, rv,
00909                                               file, line) != ISC_R_SUCCESS)
00910                                 return 0;
00911                         return 1;
00912                 }
00913         }
00914         return 0;
00915 }
00916 
00917 /* XXX: could speed up if everyone had a prefix length */
00918 int 
00919 subnet_inner_than(const struct subnet *subnet, 
00920                   const struct subnet *scan,
00921                   int warnp) {
00922         if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) ||
00923             addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) {
00924                 char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")];
00925                 int i, j;
00926                 for (i = 0; i < 128; i++)
00927                         if (subnet->netmask.iabuf[3 - (i >> 3)]
00928                             & (1 << (i & 7)))
00929                                 break;
00930                 for (j = 0; j < 128; j++)
00931                         if (scan->netmask.iabuf[3 - (j >> 3)] &
00932                             (1 << (j & 7)))
00933                                 break;
00934                 if (warnp) {
00935                         strcpy(n1buf, piaddr(subnet->net));
00936                         log_error("Warning: subnet %s/%d overlaps subnet %s/%d",
00937                               n1buf, 32 - i,
00938                               piaddr(scan->net), 32 - j);
00939                 }
00940                 if (i < j)
00941                         return 1;
00942         }
00943         return 0;
00944 }
00945 
00946 /* Enter a new subnet into the subnet list. */
00947 void enter_subnet (subnet)
00948         struct subnet *subnet;
00949 {
00950         struct subnet *scan = (struct subnet *)0;
00951         struct subnet *next = (struct subnet *)0;
00952         struct subnet *prev = (struct subnet *)0;
00953 
00954         /* Check for duplicates... */
00955         if (subnets)
00956             subnet_reference (&next, subnets, MDL);
00957         while (next) {
00958             subnet_reference (&scan, next, MDL);
00959             subnet_dereference (&next, MDL);
00960 
00961             /* When we find a conflict, make sure that the
00962                subnet with the narrowest subnet mask comes
00963                first. */
00964             if (subnet_inner_than (subnet, scan, 1)) {
00965                 if (prev) {
00966                     if (prev -> next_subnet)
00967                         subnet_dereference (&prev -> next_subnet, MDL);
00968                     subnet_reference (&prev -> next_subnet, subnet, MDL);
00969                     subnet_dereference (&prev, MDL);
00970                 } else {
00971                     subnet_dereference (&subnets, MDL);
00972                     subnet_reference (&subnets, subnet, MDL);
00973                 }
00974                 subnet_reference (&subnet -> next_subnet, scan, MDL);
00975                 subnet_dereference (&scan, MDL);
00976                 return;
00977             }
00978             subnet_reference (&prev, scan, MDL);
00979             subnet_dereference (&scan, MDL);
00980         }
00981         if (prev)
00982                 subnet_dereference (&prev, MDL);
00983 
00984         /* XXX use the BSD radix tree code instead of a linked list. */
00985         if (subnets) {
00986                 subnet_reference (&subnet -> next_subnet, subnets, MDL);
00987                 subnet_dereference (&subnets, MDL);
00988         }
00989         subnet_reference (&subnets, subnet, MDL);
00990 }
00991         
00992 /* Enter a new shared network into the shared network list. */
00993 
00994 void enter_shared_network (share)
00995         struct shared_network *share;
00996 {
00997         if (shared_networks) {
00998                 shared_network_reference (&share -> next,
00999                                           shared_networks, MDL);
01000                 shared_network_dereference (&shared_networks, MDL);
01001         }
01002         shared_network_reference (&shared_networks, share, MDL);
01003 }
01004         
01005 void new_shared_network_interface (cfile, share, name)
01006         struct parse *cfile;
01007         struct shared_network *share;
01008         const char *name;
01009 {
01010         struct interface_info *ip;
01011         isc_result_t status;
01012 
01013         if (share -> interface) {
01014                 parse_warn (cfile, 
01015                             "A subnet or shared network can't be connected %s",
01016                             "to two interfaces.");
01017                 return;
01018         }
01019         
01020         for (ip = interfaces; ip; ip = ip -> next)
01021                 if (!strcmp (ip -> name, name))
01022                         break;
01023         if (!ip) {
01024                 status = interface_allocate (&ip, MDL);
01025                 if (status != ISC_R_SUCCESS)
01026                         log_fatal ("new_shared_network_interface %s: %s",
01027                                    name, isc_result_totext (status));
01028                 if (strlen (name) > sizeof ip -> name) {
01029                         memcpy (ip -> name, name, (sizeof ip -> name) - 1);
01030                         ip -> name [(sizeof ip -> name) - 1] = 0;
01031                 } else
01032                         strcpy (ip -> name, name);
01033                 if (interfaces) {
01034                         interface_reference (&ip -> next, interfaces, MDL);
01035                         interface_dereference (&interfaces, MDL);
01036                 }
01037                 interface_reference (&interfaces, ip, MDL);
01038                 ip -> flags = INTERFACE_REQUESTED;
01039                 /* XXX this is a reference loop. */
01040                 shared_network_reference (&ip -> shared_network, share, MDL);
01041                 interface_reference (&share -> interface, ip, MDL);
01042         }
01043 }
01044 
01045 /* Enter a lease into the system.   This is called by the parser each
01046    time it reads in a new lease.   If the subnet for that lease has
01047    already been read in (usually the case), just update that lease;
01048    otherwise, allocate temporary storage for the lease and keep it around
01049    until we're done reading in the config file. */
01050 
01051 void enter_lease (lease)
01052         struct lease *lease;
01053 {
01054         struct lease *comp = (struct lease *)0;
01055 
01056         if (find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) {
01057                 if (!comp -> pool) {
01058                         log_error ("undeclared lease found in database: %s",
01059                                    piaddr (lease -> ip_addr));
01060                 } else
01061                         pool_reference (&lease -> pool, comp -> pool, MDL);
01062 
01063                 if (comp -> subnet)
01064                         subnet_reference (&lease -> subnet,
01065                                           comp -> subnet, MDL);
01066                 lease_ip_hash_delete(lease_ip_addr_hash,
01067                                      lease->ip_addr.iabuf, lease->ip_addr.len,
01068                                      MDL);
01069                 lease_dereference (&comp, MDL);
01070         }
01071 
01072         /* The only way a lease can get here without a subnet is if it's in
01073            the lease file, but not in the dhcpd.conf file.  In this case, we
01074            *should* keep it around until it's expired, but never reallocate it
01075            or renew it.  Currently, to maintain consistency, we are not doing
01076            this.
01077            XXX fix this so that the lease is kept around until it expires.
01078            XXX this will be important in IPv6 with addresses that become
01079            XXX non-renewable as a result of a renumbering event. */
01080 
01081         if (!lease -> subnet) {
01082                 log_error ("lease %s: no subnet.", piaddr (lease -> ip_addr));
01083                 return;
01084         }
01085         lease_ip_hash_add(lease_ip_addr_hash, lease->ip_addr.iabuf,
01086                           lease->ip_addr.len, lease, MDL);
01087 }
01088 
01089 /* Replace the data in an existing lease with the data in a new lease;
01090    adjust hash tables to suit, and insertion sort the lease into the
01091    list of leases by expiry time so that we can always find the oldest
01092    lease. */
01093 
01094 int supersede_lease (comp, lease, commit, propogate, pimmediate)
01095         struct lease *comp, *lease;
01096         int commit;
01097         int propogate;
01098         int pimmediate;
01099 {
01100         struct lease *lp, **lq, *prev;
01101         struct timeval tv;
01102 #if defined (FAILOVER_PROTOCOL)
01103         int do_pool_check = 0;
01104 
01105         /* We must commit leases before sending updates regarding them
01106            to failover peers.  It is, therefore, an error to set pimmediate
01107            and not commit. */
01108         if (pimmediate && !commit)
01109                 return 0;
01110 #endif
01111 
01112         /* If there is no sample lease, just do the move. */
01113         if (!lease)
01114                 goto just_move_it;
01115 
01116         /* Static leases are not currently kept in the database... */
01117         if (lease -> flags & STATIC_LEASE)
01118                 return 1;
01119 
01120         /* If the existing lease hasn't expired and has a different
01121            unique identifier or, if it doesn't have a unique
01122            identifier, a different hardware address, then the two
01123            leases are in conflict.  If the existing lease has a uid
01124            and the new one doesn't, but they both have the same
01125            hardware address, and dynamic bootp is allowed on this
01126            lease, then we allow that, in case a dynamic BOOTP lease is
01127            requested *after* a DHCP lease has been assigned. */
01128 
01129         if (lease -> binding_state != FTS_ABANDONED &&
01130             lease -> next_binding_state != FTS_ABANDONED &&
01131             comp -> binding_state == FTS_ACTIVE &&
01132             (((comp -> uid && lease -> uid) &&
01133               (comp -> uid_len != lease -> uid_len ||
01134                memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
01135              (!comp -> uid &&
01136               ((comp -> hardware_addr.hlen !=
01137                 lease -> hardware_addr.hlen) ||
01138                memcmp (comp -> hardware_addr.hbuf,
01139                        lease -> hardware_addr.hbuf,
01140                        comp -> hardware_addr.hlen))))) {
01141                 log_error ("Lease conflict at %s",
01142                       piaddr (comp -> ip_addr));
01143         }
01144 
01145         /* If there's a Unique ID, dissociate it from the hash
01146            table and free it if necessary. */
01147         if (comp->uid) {
01148                 uid_hash_delete(comp);
01149                 if (comp->uid != comp->uid_buf) {
01150                         dfree(comp->uid, MDL);
01151                         comp->uid_max = 0;
01152                         comp->uid_len = 0;
01153                 }
01154                 comp -> uid = (unsigned char *)0;
01155         }
01156 
01157         /* If there's a hardware address, remove the lease from its
01158          * old position in the hash bucket's ordered list.
01159          */
01160         if (comp->hardware_addr.hlen)
01161                 hw_hash_delete(comp);
01162 
01163         /* If the lease has been billed to a class, remove the billing. */
01164         if (comp -> billing_class != lease -> billing_class) {
01165                 if (comp -> billing_class)
01166                         unbill_class (comp, comp -> billing_class);
01167                 if (lease -> billing_class)
01168                         bill_class (comp, lease -> billing_class);
01169         }
01170 
01171         /* Copy the data files, but not the linkages. */
01172         comp -> starts = lease -> starts;
01173         if (lease -> uid) {
01174                 if (lease -> uid_len <= sizeof (lease -> uid_buf)) {
01175                         memcpy (comp -> uid_buf,
01176                                 lease -> uid, lease -> uid_len);
01177                         comp -> uid = &comp -> uid_buf [0];
01178                         comp -> uid_max = sizeof comp -> uid_buf;
01179                         comp -> uid_len = lease -> uid_len;
01180                 } else if (lease -> uid != &lease -> uid_buf [0]) {
01181                         comp -> uid = lease -> uid;
01182                         comp -> uid_max = lease -> uid_max;
01183                         lease -> uid = (unsigned char *)0;
01184                         lease -> uid_max = 0;
01185                         comp -> uid_len = lease -> uid_len;
01186                         lease -> uid_len = 0;
01187                 } else {
01188                         log_fatal ("corrupt lease uid."); /* XXX */
01189                 }
01190         } else {
01191                 comp -> uid = (unsigned char *)0;
01192                 comp -> uid_len = comp -> uid_max = 0;
01193         }
01194         if (comp -> host)
01195                 host_dereference (&comp -> host, MDL);
01196         host_reference (&comp -> host, lease -> host, MDL);
01197         comp -> hardware_addr = lease -> hardware_addr;
01198         comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) |
01199                          (comp -> flags & ~EPHEMERAL_FLAGS));
01200         if (comp -> scope)
01201                 binding_scope_dereference (&comp -> scope, MDL);
01202         if (lease -> scope) {
01203                 binding_scope_reference (&comp -> scope, lease -> scope, MDL);
01204                 binding_scope_dereference (&lease -> scope, MDL);
01205         }
01206 
01207         if (comp -> agent_options)
01208                 option_chain_head_dereference (&comp -> agent_options, MDL);
01209         if (lease -> agent_options) {
01210                 /* Only retain the agent options if the lease is still
01211                    affirmatively associated with a client. */
01212                 if (lease -> next_binding_state == FTS_ACTIVE ||
01213                     lease -> next_binding_state == FTS_EXPIRED)
01214                         option_chain_head_reference (&comp -> agent_options,
01215                                                      lease -> agent_options,
01216                                                      MDL);
01217                 option_chain_head_dereference (&lease -> agent_options, MDL);
01218         }
01219 
01220         /* Record the hostname information in the lease. */
01221         if (comp -> client_hostname)
01222                 dfree (comp -> client_hostname, MDL);
01223         comp -> client_hostname = lease -> client_hostname;
01224         lease -> client_hostname = (char *)0;
01225 
01226         if (lease->on_star.on_expiry) {
01227                 if (comp->on_star.on_expiry)
01228                         executable_statement_dereference
01229                                 (&comp->on_star.on_expiry, MDL);
01230                 executable_statement_reference (&comp->on_star.on_expiry,
01231                                                 lease->on_star.on_expiry,
01232                                                 MDL);
01233         }
01234         if (lease->on_star.on_commit) {
01235                 if (comp->on_star.on_commit)
01236                         executable_statement_dereference
01237                                 (&comp->on_star.on_commit, MDL);
01238                 executable_statement_reference (&comp->on_star.on_commit,
01239                                                 lease->on_star.on_commit,
01240                                                 MDL);
01241         }
01242         if (lease->on_star.on_release) {
01243                 if (comp->on_star.on_release)
01244                         executable_statement_dereference
01245                                 (&comp->on_star.on_release, MDL);
01246                 executable_statement_reference (&comp->on_star.on_release,
01247                                                 lease->on_star.on_release,
01248                                                 MDL);
01249         }
01250 
01251         /* Record the lease in the uid hash if necessary. */
01252         if (comp->uid)
01253                 uid_hash_add(comp);
01254 
01255         /* Record it in the hardware address hash if necessary. */
01256         if (comp->hardware_addr.hlen)
01257                 hw_hash_add(comp);
01258 
01259         comp->cltt = lease->cltt;
01260 #if defined (FAILOVER_PROTOCOL)
01261         comp->tstp = lease->tstp;
01262         comp->tsfp = lease->tsfp;
01263         comp->atsfp = lease->atsfp;
01264 #endif /* FAILOVER_PROTOCOL */
01265         comp->ends = lease->ends;
01266         comp->next_binding_state = lease->next_binding_state;
01267 
01268         /*
01269          * If we have a control block pointer copy it in.
01270          * We don't zero out an older ponter as it is still
01271          * in use.  We shouldn't need to overwrite an
01272          * old pointer with a new one as the old transaction
01273          * should have been cancelled before getting here.
01274          */
01275         if (lease->ddns_cb != NULL)
01276                 comp->ddns_cb = lease->ddns_cb;
01277 
01278       just_move_it:
01279 #if defined (FAILOVER_PROTOCOL)
01280         /*
01281          * Atsfp should be cleared upon any state change that implies
01282          * propagation whether supersede_lease was given a copy lease
01283          * structure or not (often from the pool_timer()).
01284          */
01285         if (propogate)
01286                 comp->atsfp = 0;
01287 #endif /* FAILOVER_PROTOCOL */
01288 
01289         if (!comp -> pool) {
01290                 log_error ("Supersede_lease: lease %s with no pool.",
01291                            piaddr (comp -> ip_addr));
01292                 return 0;
01293         }
01294 
01295         /* Figure out which queue it's on. */
01296         switch (comp -> binding_state) {
01297               case FTS_FREE:
01298                 if (comp->flags & RESERVED_LEASE)
01299                         lq = &comp->pool->reserved;
01300                 else {
01301                         lq = &comp->pool->free;
01302                         comp->pool->free_leases--;
01303                 }
01304 
01305 #if defined(FAILOVER_PROTOCOL)
01306                 do_pool_check = 1;
01307 #endif
01308                 break;
01309 
01310               case FTS_ACTIVE:
01311                 lq = &comp -> pool -> active;
01312                 break;
01313 
01314               case FTS_EXPIRED:
01315               case FTS_RELEASED:
01316               case FTS_RESET:
01317                 lq = &comp -> pool -> expired;
01318                 break;
01319 
01320               case FTS_ABANDONED:
01321                 lq = &comp -> pool -> abandoned;
01322                 break;
01323 
01324               case FTS_BACKUP:
01325                 if (comp->flags & RESERVED_LEASE)
01326                         lq = &comp->pool->reserved;
01327                 else {
01328                         lq = &comp->pool->backup;
01329                         comp->pool->backup_leases--;
01330                 }
01331 
01332 #if defined(FAILOVER_PROTOCOL)
01333                 do_pool_check = 1;
01334 #endif
01335                 break;
01336 
01337               default:
01338                 log_error ("Lease with bogus binding state: %d",
01339                            comp -> binding_state);
01340 #if defined (BINDING_STATE_DEBUG)
01341                 abort ();
01342 #endif
01343                 return 0;
01344         }
01345 
01346         /* Remove the lease from its current place in its current
01347            timer sequence. */
01348         /* XXX this is horrid. */
01349         prev = (struct lease *)0;
01350         for (lp = *lq; lp; lp = lp -> next) {
01351                 if (lp == comp)
01352                         break;
01353                 prev = lp;
01354         }
01355 
01356         if (!lp) {
01357                 log_fatal("Lease with binding state %s not on its queue.",
01358                           (comp->binding_state < 1 ||
01359                            comp->binding_state > FTS_LAST)
01360                           ? "unknown"
01361                           : binding_state_names[comp->binding_state - 1]);
01362         }
01363 
01364         if (prev) {
01365                 lease_dereference (&prev -> next, MDL);
01366                 if (comp -> next) {
01367                         lease_reference (&prev -> next, comp -> next, MDL);
01368                         lease_dereference (&comp -> next, MDL);
01369                 }
01370         } else {
01371                 lease_dereference (lq, MDL);
01372                 if (comp -> next) {
01373                         lease_reference (lq, comp -> next, MDL);
01374                         lease_dereference (&comp -> next, MDL);
01375                 }
01376         }
01377 
01378         /* Make the state transition. */
01379         if (commit || !pimmediate)
01380                 make_binding_state_transition (comp);
01381 
01382         /* Put the lease back on the appropriate queue.    If the lease
01383            is corrupt (as detected by lease_enqueue), don't go any farther. */
01384         if (!lease_enqueue (comp))
01385                 return 0;
01386 
01387         /* If this is the next lease that will timeout on the pool,
01388            zap the old timeout and set the timeout on this pool to the
01389            time that the lease's next event will happen.
01390                    
01391            We do not actually set the timeout unless commit is true -
01392            we don't want to thrash the timer queue when reading the
01393            lease database.  Instead, the database code calls the
01394            expiry event on each pool after reading in the lease file,
01395            and the expiry code sets the timer if there's anything left
01396            to expire after it's run any outstanding expiry events on
01397            the pool. */
01398         if ((commit || !pimmediate) &&
01399             comp -> sort_time != MIN_TIME &&
01400             comp -> sort_time > cur_time &&
01401             (comp -> sort_time < comp -> pool -> next_event_time ||
01402              comp -> pool -> next_event_time == MIN_TIME)) {
01403                 comp -> pool -> next_event_time = comp -> sort_time;
01404                 tv . tv_sec = comp -> pool -> next_event_time;
01405                 tv . tv_usec = 0;
01406                 add_timeout (&tv,
01407                              pool_timer, comp -> pool,
01408                              (tvref_t)pool_reference,
01409                              (tvunref_t)pool_dereference);
01410         }
01411 
01412         if (commit) {
01413 #if defined(FAILOVER_PROTOCOL)
01414                 /*
01415                  * If commit and propogate are set, then we can save a
01416                  * possible fsync later in BNDUPD socket transmission by
01417                  * stepping the rewind state forward to the new state, in
01418                  * case it has changed.  This is only worth doing if the
01419                  * failover connection is currently connected, as in this
01420                  * case it is likely we will be transmitting to the peer very
01421                  * shortly.
01422                  */
01423                 if (propogate && (comp->pool->failover_peer != NULL) &&
01424                     ((comp->pool->failover_peer->service_state ==
01425                                                             cooperating) ||
01426                      (comp->pool->failover_peer->service_state ==
01427                                                             not_responding)))
01428                         comp->rewind_binding_state = comp->binding_state;
01429 #endif
01430 
01431                 if (!write_lease (comp))
01432                         return 0;
01433                 if ((server_starting & SS_NOSYNC) == 0) {
01434                         if (!commit_leases ())
01435                                 return 0;
01436                 }
01437         }
01438 
01439 #if defined (FAILOVER_PROTOCOL)
01440         if (propogate) {
01441                 comp -> desired_binding_state = comp -> binding_state;
01442                 if (!dhcp_failover_queue_update (comp, pimmediate))
01443                         return 0;
01444         }
01445         if (do_pool_check && comp->pool->failover_peer)
01446                 dhcp_failover_pool_check(comp->pool);
01447 #endif
01448 
01449         /* If the current binding state has already expired, do an
01450            expiry event right now. */
01451         /* XXX At some point we should optimize this so that we don't
01452            XXX write the lease twice, but this is a safe way to fix the
01453            XXX problem for 3.0 (I hope!). */
01454         if ((commit || !pimmediate) &&
01455             comp -> sort_time < cur_time &&
01456             comp -> next_binding_state != comp -> binding_state)
01457                 pool_timer (comp -> pool);
01458 
01459         return 1;
01460 }
01461 
01462 void make_binding_state_transition (struct lease *lease)
01463 {
01464 
01465 #if defined (FAILOVER_PROTOCOL)
01466         dhcp_failover_state_t *peer;
01467 
01468         if (lease -> pool && lease -> pool -> failover_peer)
01469                 peer = lease -> pool -> failover_peer;
01470         else
01471                 peer = (dhcp_failover_state_t *)0;
01472 #endif
01473 
01474         /* If the lease was active and is now no longer active, but isn't
01475            released, then it just expired, so do the expiry event. */
01476         if (lease -> next_binding_state != lease -> binding_state &&
01477             ((
01478 #if defined (FAILOVER_PROTOCOL)
01479                     peer &&
01480                     (lease->binding_state == FTS_EXPIRED ||
01481                      lease->binding_state == FTS_ACTIVE) &&
01482                     (lease->next_binding_state == FTS_FREE ||
01483                      lease->next_binding_state == FTS_BACKUP)) ||
01484              (!peer &&
01485 #endif
01486               lease -> binding_state == FTS_ACTIVE &&
01487               lease -> next_binding_state != FTS_RELEASED))) {
01488 #if defined (NSUPDATE)
01489                 (void) ddns_removals(lease, NULL, NULL, ISC_TRUE);
01490 #endif
01491                 if (lease->on_star.on_expiry) {
01492                         execute_statements(NULL, NULL, lease,
01493                                            NULL, NULL, NULL,
01494                                            &lease->scope,
01495                                            lease->on_star.on_expiry,
01496                                            NULL);
01497                         if (lease->on_star.on_expiry)
01498                                 executable_statement_dereference
01499                                         (&lease->on_star.on_expiry, MDL);
01500                 }
01501                 
01502                 /* No sense releasing a lease after it's expired. */
01503                 if (lease->on_star.on_release)
01504                         executable_statement_dereference
01505                                 (&lease->on_star.on_release, MDL);
01506                 /* Get rid of client-specific bindings that are only
01507                    correct when the lease is active. */
01508                 if (lease -> billing_class)
01509                         unbill_class (lease, lease -> billing_class);
01510                 if (lease -> agent_options)
01511                         option_chain_head_dereference (&lease -> agent_options,
01512                                                        MDL);
01513                 if (lease -> client_hostname) {
01514                         dfree (lease -> client_hostname, MDL);
01515                         lease -> client_hostname = (char *)0;
01516                 }
01517                 if (lease -> host)
01518                         host_dereference (&lease -> host, MDL);
01519 
01520                 /* Send the expiry time to the peer. */
01521                 lease -> tstp = lease -> ends;
01522         }
01523 
01524         /* If the lease was active and is now released, do the release
01525            event. */
01526         if (lease -> next_binding_state != lease -> binding_state &&
01527             ((
01528 #if defined (FAILOVER_PROTOCOL)
01529                     peer &&
01530                     lease -> binding_state == FTS_RELEASED &&
01531                     (lease -> next_binding_state == FTS_FREE ||
01532                      lease -> next_binding_state == FTS_BACKUP)) ||
01533              (!peer &&
01534 #endif
01535               lease -> binding_state == FTS_ACTIVE &&
01536               lease -> next_binding_state == FTS_RELEASED))) {
01537 #if defined (NSUPDATE)
01538                 /*
01539                  * Note: ddns_removals() is also iterated when the lease
01540                  * enters state 'released' in 'release_lease()'.  The below
01541                  * is caught when a peer receives a BNDUPD from a failover
01542                  * peer; it may not have received the client's release (it
01543                  * may have been offline).
01544                  *
01545                  * We could remove the call from release_lease() because
01546                  * it will also catch here on the originating server after the
01547                  * peer acknowledges the state change.  However, there could
01548                  * be many hours inbetween, and in this case we /know/ the
01549                  * client is no longer using the lease when we receive the
01550                  * release message.  This is not true of expiry, where the
01551                  * peer may have extended the lease.
01552                  */
01553                 (void) ddns_removals(lease, NULL, NULL, ISC_TRUE);
01554 #endif
01555                 if (lease->on_star.on_release) {
01556                         execute_statements(NULL, NULL, lease,
01557                                            NULL, NULL, NULL,
01558                                            &lease->scope,
01559                                            lease->on_star.on_release,
01560                                            NULL);
01561                         executable_statement_dereference
01562                                 (&lease->on_star.on_release, MDL);
01563                 }
01564                 
01565                 /* A released lease can't expire. */
01566                 if (lease->on_star.on_expiry)
01567                         executable_statement_dereference
01568                                 (&lease->on_star.on_expiry, MDL);
01569 
01570                 /* Get rid of client-specific bindings that are only
01571                    correct when the lease is active. */
01572                 if (lease -> billing_class)
01573                         unbill_class (lease, lease -> billing_class);
01574                 if (lease -> agent_options)
01575                         option_chain_head_dereference (&lease -> agent_options,
01576                                                        MDL);
01577                 if (lease -> client_hostname) {
01578                         dfree (lease -> client_hostname, MDL);
01579                         lease -> client_hostname = (char *)0;
01580                 }
01581                 if (lease -> host)
01582                         host_dereference (&lease -> host, MDL);
01583 
01584                 /* Send the release time (should be == cur_time) to the
01585                    peer. */
01586                 lease -> tstp = lease -> ends;
01587         }
01588 
01589 #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
01590         log_debug ("lease %s moves from %s to %s",
01591                    piaddr (lease -> ip_addr),
01592                    binding_state_print (lease -> binding_state),
01593                    binding_state_print (lease -> next_binding_state));
01594 #endif
01595 
01596         lease -> binding_state = lease -> next_binding_state;
01597         switch (lease -> binding_state) {
01598               case FTS_ACTIVE:
01599 #if defined (FAILOVER_PROTOCOL)
01600                 if (lease -> pool && lease -> pool -> failover_peer)
01601                         lease -> next_binding_state = FTS_EXPIRED;
01602                 else
01603 #endif
01604                         lease -> next_binding_state = FTS_FREE;
01605                 break;
01606 
01607               case FTS_EXPIRED:
01608               case FTS_RELEASED:
01609               case FTS_ABANDONED:
01610               case FTS_RESET:
01611                 lease->next_binding_state = FTS_FREE;
01612 #if defined(FAILOVER_PROTOCOL)
01613                 /* If we are not in partner_down, leases don't go from
01614                    EXPIRED to FREE on a timeout - only on an update.
01615                    If we're in partner_down, they expire at mclt past
01616                    the time we entered partner_down. */
01617                 if ((lease->pool != NULL) &&
01618                     (lease->pool->failover_peer != NULL) &&
01619                     (lease->pool->failover_peer->me.state == partner_down))
01620                         lease->tsfp =
01621                             (lease->pool->failover_peer->me.stos +
01622                              lease->pool->failover_peer->mclt);
01623 #endif /* FAILOVER_PROTOCOL */
01624                 break;
01625 
01626               case FTS_FREE:
01627               case FTS_BACKUP:
01628                 lease -> next_binding_state = lease -> binding_state;
01629                 break;
01630         }
01631 #if defined (DEBUG_LEASE_STATE_TRANSITIONS)
01632         log_debug ("lease %s: next binding state %s",
01633                    piaddr (lease -> ip_addr),
01634                    binding_state_print (lease -> next_binding_state));
01635 #endif
01636 }
01637 
01638 /* Copy the contents of one lease into another, correctly maintaining
01639    reference counts. */
01640 int lease_copy (struct lease **lp,
01641                 struct lease *lease, const char *file, int line)
01642 {
01643         struct lease *lt = (struct lease *)0;
01644         isc_result_t status;
01645 
01646         status = lease_allocate (&lt, MDL);
01647         if (status != ISC_R_SUCCESS)
01648                 return 0;
01649 
01650         lt -> ip_addr = lease -> ip_addr;
01651         lt -> starts = lease -> starts;
01652         lt -> ends = lease -> ends;
01653         lt -> uid_len = lease -> uid_len;
01654         lt -> uid_max = lease -> uid_max;
01655         if (lease -> uid == lease -> uid_buf) {
01656                 lt -> uid = lt -> uid_buf;
01657                 memcpy (lt -> uid_buf, lease -> uid_buf, sizeof lt -> uid_buf);
01658         } else if (!lease -> uid_max) {
01659                 lt -> uid = (unsigned char *)0;
01660         } else {
01661                 lt -> uid = dmalloc (lt -> uid_max, MDL);
01662                 if (!lt -> uid) {
01663                         lease_dereference (&lt, MDL);
01664                         return 0;
01665                 }
01666                 memcpy (lt -> uid, lease -> uid, lease -> uid_max);
01667         }
01668         if (lease -> client_hostname) {
01669                 lt -> client_hostname =
01670                         dmalloc (strlen (lease -> client_hostname) + 1, MDL);
01671                 if (!lt -> client_hostname) {
01672                         lease_dereference (&lt, MDL);
01673                         return 0;
01674                 }
01675                 strcpy (lt -> client_hostname, lease -> client_hostname);
01676         }
01677         if (lease -> scope)
01678                 binding_scope_reference (&lt -> scope, lease -> scope, MDL);
01679         if (lease -> agent_options)
01680                 option_chain_head_reference (&lt -> agent_options,
01681                                              lease -> agent_options, MDL);
01682         host_reference (&lt -> host, lease -> host, file, line);
01683         subnet_reference (&lt -> subnet, lease -> subnet, file, line);
01684         pool_reference (&lt -> pool, lease -> pool, file, line);
01685         class_reference (&lt -> billing_class,
01686                          lease -> billing_class, file, line);
01687         lt -> hardware_addr = lease -> hardware_addr;
01688         if (lease->on_star.on_expiry)
01689                 executable_statement_reference (&lt->on_star.on_expiry,
01690                                                 lease->on_star.on_expiry,
01691                                                 file, line);
01692         if (lease->on_star.on_commit)
01693                 executable_statement_reference (&lt->on_star.on_commit,
01694                                                 lease->on_star.on_commit,
01695                                                 file, line);
01696         if (lease->on_star.on_release)
01697                 executable_statement_reference (&lt->on_star.on_release,
01698                                                 lease->on_star.on_release,
01699                                                 file, line);
01700         lt->flags = lease->flags;
01701         lt->tstp = lease->tstp;
01702         lt->tsfp = lease->tsfp;
01703         lt->atsfp = lease->atsfp;
01704         lt->cltt = lease -> cltt;
01705         lt->binding_state = lease->binding_state;
01706         lt->next_binding_state = lease->next_binding_state;
01707         lt->rewind_binding_state = lease->rewind_binding_state;
01708         status = lease_reference(lp, lt, file, line);
01709         lease_dereference(&lt, MDL);
01710         return status == ISC_R_SUCCESS;
01711 }
01712 
01713 /* Release the specified lease and re-hash it as appropriate. */
01714 void release_lease (lease, packet)
01715         struct lease *lease;
01716         struct packet *packet;
01717 {
01718         /* If there are statements to execute when the lease is
01719            released, execute them. */
01720 #if defined (NSUPDATE)
01721         (void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
01722 #endif
01723         if (lease->on_star.on_release) {
01724                 execute_statements (NULL, packet, lease,
01725                                     NULL, packet->options,
01726                                     NULL, &lease->scope,
01727                                     lease->on_star.on_release, NULL);
01728                 if (lease->on_star.on_release)
01729                         executable_statement_dereference
01730                                 (&lease->on_star.on_release, MDL);
01731         }
01732 
01733         /* We do either the on_release or the on_expiry events, but
01734            not both (it's possible that they could be the same,
01735            in any case). */
01736         if (lease->on_star.on_expiry)
01737                 executable_statement_dereference
01738                         (&lease->on_star.on_expiry, MDL);
01739 
01740         if (lease -> binding_state != FTS_FREE &&
01741             lease -> binding_state != FTS_BACKUP &&
01742             lease -> binding_state != FTS_RELEASED &&
01743             lease -> binding_state != FTS_EXPIRED &&
01744             lease -> binding_state != FTS_RESET) {
01745                 if (lease->on_star.on_commit)
01746                         executable_statement_dereference
01747                                 (&lease->on_star.on_commit, MDL);
01748 
01749                 /* Blow away any bindings. */
01750                 if (lease -> scope)
01751                         binding_scope_dereference (&lease -> scope, MDL);
01752 
01753                 /* Set sort times to the present. */
01754                 lease -> ends = cur_time;
01755                 /* Lower layers of muckery set tstp to ->ends.  But we send
01756                  * protocol messages before this.  So it is best to set
01757                  * tstp now anyway.
01758                  */
01759                 lease->tstp = cur_time;
01760 #if defined (FAILOVER_PROTOCOL)
01761                 if (lease -> pool && lease -> pool -> failover_peer) {
01762                         dhcp_failover_state_t *peer = NULL;
01763 
01764                         if (lease->pool != NULL)
01765                                 peer = lease->pool->failover_peer;
01766 
01767                         if ((peer->service_state == not_cooperating) &&
01768                             (((peer->i_am == primary) &&
01769                               (lease->rewind_binding_state == FTS_FREE)) ||
01770                              ((peer->i_am == secondary) &&
01771                               (lease->rewind_binding_state == FTS_BACKUP)))) {
01772                                 lease->next_binding_state =
01773                                                   lease->rewind_binding_state;
01774                         } else
01775                                 lease -> next_binding_state = FTS_RELEASED;
01776                 } else {
01777                         lease -> next_binding_state = FTS_FREE;
01778                 }
01779 #else
01780                 lease -> next_binding_state = FTS_FREE;
01781 #endif
01782                 supersede_lease (lease, (struct lease *)0, 1, 1, 1);
01783         }
01784 }
01785 
01786 /* Abandon the specified lease (set its timeout to infinity and its
01787    particulars to zero, and re-hash it as appropriate. */
01788 
01789 void abandon_lease (lease, message)
01790         struct lease *lease;
01791         const char *message;
01792 {
01793         struct lease *lt = (struct lease *)0;
01794 #if defined (NSUPDATE)
01795         (void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
01796 #endif
01797 
01798         if (!lease_copy (&lt, lease, MDL))
01799                 return;
01800 
01801         if (lt->scope)
01802                 binding_scope_dereference(&lt->scope, MDL);
01803 
01804         lt -> ends = cur_time; /* XXX */
01805         lt -> next_binding_state = FTS_ABANDONED;
01806 
01807         log_error ("Abandoning IP address %s: %s",
01808               piaddr (lease -> ip_addr), message);
01809         lt -> hardware_addr.hlen = 0;
01810         if (lt -> uid && lt -> uid != lt -> uid_buf)
01811                 dfree (lt -> uid, MDL);
01812         lt -> uid = (unsigned char *)0;
01813         lt -> uid_len = 0;
01814         lt -> uid_max = 0;
01815         supersede_lease (lease, lt, 1, 1, 1);
01816         lease_dereference (&lt, MDL);
01817 }
01818 
01819 #if 0
01820 /*
01821  * This doesn't appear to be in use for anything anymore.
01822  * I'm ifdeffing it now and if there are no complaints in
01823  * the future it will be removed.
01824  * SAR
01825  */
01826 
01827 /* Abandon the specified lease (set its timeout to infinity and its
01828    particulars to zero, and re-hash it as appropriate. */
01829 
01830 void dissociate_lease (lease)
01831         struct lease *lease;
01832 {
01833         struct lease *lt = (struct lease *)0;
01834 #if defined (NSUPDATE)
01835         (void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
01836 #endif
01837 
01838         if (!lease_copy (&lt, lease, MDL))
01839                 return;
01840 
01841 #if defined (FAILOVER_PROTOCOL)
01842         if (lease -> pool && lease -> pool -> failover_peer) {
01843                 lt -> next_binding_state = FTS_RESET;
01844         } else {
01845                 lt -> next_binding_state = FTS_FREE;
01846         }
01847 #else
01848         lt -> next_binding_state = FTS_FREE;
01849 #endif
01850         lt -> ends = cur_time; /* XXX */
01851         lt -> hardware_addr.hlen = 0;
01852         if (lt -> uid && lt -> uid != lt -> uid_buf)
01853                 dfree (lt -> uid, MDL);
01854         lt -> uid = (unsigned char *)0;
01855         lt -> uid_len = 0;
01856         lt -> uid_max = 0;
01857         supersede_lease (lease, lt, 1, 1, 1);
01858         lease_dereference (&lt, MDL);
01859 }
01860 #endif
01861 
01862 /* Timer called when a lease in a particular pool expires. */
01863 void pool_timer (vpool)
01864         void *vpool;
01865 {
01866         struct pool *pool;
01867         struct lease *next = (struct lease *)0;
01868         struct lease *lease = (struct lease *)0;
01869 #define FREE_LEASES 0
01870 #define ACTIVE_LEASES 1
01871 #define EXPIRED_LEASES 2
01872 #define ABANDONED_LEASES 3
01873 #define BACKUP_LEASES 4
01874 #define RESERVED_LEASES 5
01875         struct lease **lptr[RESERVED_LEASES+1];
01876         TIME next_expiry = MAX_TIME;
01877         int i;
01878         struct timeval tv;
01879 
01880         pool = (struct pool *)vpool;
01881 
01882         lptr [FREE_LEASES] = &pool -> free;
01883         lptr [ACTIVE_LEASES] = &pool -> active;
01884         lptr [EXPIRED_LEASES] = &pool -> expired;
01885         lptr [ABANDONED_LEASES] = &pool -> abandoned;
01886         lptr [BACKUP_LEASES] = &pool -> backup;
01887         lptr[RESERVED_LEASES] = &pool->reserved;
01888 
01889         for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
01890                 /* If there's nothing on the queue, skip it. */
01891                 if (!*(lptr [i]))
01892                         continue;
01893 
01894 #if defined (FAILOVER_PROTOCOL)
01895                 if (pool->failover_peer &&
01896                     pool->failover_peer->me.state != partner_down) {
01897                         /*
01898                          * Normally the secondary doesn't initiate expiration
01899                          * events (unless in partner-down), but rather relies
01900                          * on the primary to expire the lease.  However, when
01901                          * disconnected from its peer, the server is allowed to
01902                          * rewind a lease to the previous state that the peer
01903                          * would have recorded it.  This means there may be
01904                          * opportunities for active->free or active->backup
01905                          * expirations while out of contact.
01906                          *
01907                          * Q: Should we limit this expiration to
01908                          *    comms-interrupt rather than not-normal?
01909                          */
01910                         if ((i == ACTIVE_LEASES) &&
01911                             (pool->failover_peer->i_am == secondary) &&
01912                             (pool->failover_peer->me.state == normal))
01913                                 continue;
01914 
01915                         /* Leases in an expired state don't move to
01916                            free because of a timeout unless we're in
01917                            partner_down. */
01918                         if (i == EXPIRED_LEASES)
01919                                 continue;
01920                 }
01921 #endif          
01922                 lease_reference (&lease, *(lptr [i]), MDL);
01923 
01924                 while (lease) {
01925                         /* Remember the next lease in the list. */
01926                         if (next)
01927                                 lease_dereference (&next, MDL);
01928                         if (lease -> next)
01929                                 lease_reference (&next, lease -> next, MDL);
01930 
01931                         /* If we've run out of things to expire on this list,
01932                            stop. */
01933                         if (lease -> sort_time > cur_time) {
01934                                 if (lease -> sort_time < next_expiry)
01935                                         next_expiry = lease -> sort_time;
01936                                 break;
01937                         }
01938 
01939                         /* If there is a pending state change, and
01940                            this lease has gotten to the time when the
01941                            state change should happen, just call
01942                            supersede_lease on it to make the change
01943                            happen. */
01944                         if (lease->next_binding_state != lease->binding_state)
01945                         {
01946 #if defined(FAILOVER_PROTOCOL)
01947                                 dhcp_failover_state_t *peer = NULL;
01948 
01949                                 if (lease->pool != NULL)
01950                                         peer = lease->pool->failover_peer;
01951 
01952                                 /* Can we rewind the lease to a free state? */
01953                                 if (peer != NULL &&
01954                                     peer->service_state == not_cooperating &&
01955                                     lease->next_binding_state == FTS_EXPIRED &&
01956                                     ((peer->i_am == primary &&
01957                                       lease->rewind_binding_state == FTS_FREE)
01958                                         ||
01959                                      (peer->i_am == secondary &&
01960                                       lease->rewind_binding_state ==
01961                                                                 FTS_BACKUP)))
01962                                         lease->next_binding_state =
01963                                                    lease->rewind_binding_state;
01964 #endif
01965                                 supersede_lease(lease, NULL, 1, 1, 1);
01966                         }
01967 
01968                         lease_dereference (&lease, MDL);
01969                         if (next)
01970                                 lease_reference (&lease, next, MDL);
01971                 }
01972                 if (next)
01973                         lease_dereference (&next, MDL);
01974                 if (lease)
01975                         lease_dereference (&lease, MDL);
01976         }
01977         if (next_expiry != MAX_TIME) {
01978                 pool -> next_event_time = next_expiry;
01979                 tv . tv_sec = pool -> next_event_time;
01980                 tv . tv_usec = 0;
01981                 add_timeout (&tv, pool_timer, pool,
01982                              (tvref_t)pool_reference,
01983                              (tvunref_t)pool_dereference);
01984         } else
01985                 pool -> next_event_time = MIN_TIME;
01986 
01987 }
01988 
01989 /* Locate the lease associated with a given IP address... */
01990 
01991 int find_lease_by_ip_addr (struct lease **lp, struct iaddr addr,
01992                            const char *file, int line)
01993 {
01994         return lease_ip_hash_lookup(lp, lease_ip_addr_hash, addr.iabuf,
01995                                     addr.len, file, line);
01996 }
01997 
01998 int find_lease_by_uid (struct lease **lp, const unsigned char *uid,
01999                        unsigned len, const char *file, int line)
02000 {
02001         if (len == 0)
02002                 return 0;
02003         return lease_id_hash_lookup (lp, lease_uid_hash, uid, len, file, line);
02004 }
02005 
02006 int find_lease_by_hw_addr (struct lease **lp,
02007                            const unsigned char *hwaddr, unsigned hwlen,
02008                            const char *file, int line)
02009 {
02010         if (hwlen == 0)
02011                 return (0);
02012 
02013         /*
02014          * If it's an infiniband address don't bother
02015          * as we don't have a useful address to hash.
02016          */
02017         if ((hwlen == 1) && (hwaddr[0] == HTYPE_INFINIBAND))
02018                 return (0);
02019 
02020         return (lease_id_hash_lookup(lp, lease_hw_addr_hash, hwaddr, hwlen,
02021                                      file, line));
02022 }
02023 
02024 /* If the lease is preferred over the candidate, return truth.  The
02025  * 'cand' and 'lease' names are retained to read more clearly against
02026  * the 'uid_hash_add' and 'hw_hash_add' functions (this is common logic
02027  * to those two functions).
02028  *
02029  * 1) ACTIVE leases are preferred.  The active lease with
02030  *    the longest lifetime is preferred over shortest.
02031  * 2) "transitional states" are next, this time with the
02032  *    most recent CLTT.
02033  * 3) free/backup/etc states are next, again with CLTT.  In truth we
02034  *    should never see reset leases for this.
02035  * 4) Abandoned leases are always dead last.
02036  */
02037 static isc_boolean_t
02038 client_lease_preferred(struct lease *cand, struct lease *lease)
02039 {
02040         if (cand->binding_state == FTS_ACTIVE) {
02041                 if (lease->binding_state == FTS_ACTIVE &&
02042                     lease->ends >= cand->ends)
02043                         return ISC_TRUE;
02044         } else if (cand->binding_state == FTS_EXPIRED ||
02045                    cand->binding_state == FTS_RELEASED) {
02046                 if (lease->binding_state == FTS_ACTIVE)
02047                         return ISC_TRUE;
02048 
02049                 if ((lease->binding_state == FTS_EXPIRED ||
02050                      lease->binding_state == FTS_RELEASED) &&
02051                     lease->cltt >= cand->cltt)
02052                         return ISC_TRUE;
02053         } else if (cand->binding_state != FTS_ABANDONED) {
02054                 if (lease->binding_state == FTS_ACTIVE ||
02055                     lease->binding_state == FTS_EXPIRED ||
02056                     lease->binding_state == FTS_RELEASED)
02057                         return ISC_TRUE;
02058 
02059                 if (lease->binding_state != FTS_ABANDONED &&
02060                     lease->cltt >= cand->cltt)
02061                         return ISC_TRUE;
02062         } else /* (cand->binding_state == FTS_ABANDONED) */ {
02063                 if (lease->binding_state != FTS_ABANDONED ||
02064                     lease->cltt >= cand->cltt)
02065                         return ISC_TRUE;
02066         }
02067 
02068         return ISC_FALSE;
02069 }
02070 
02071 /* Add the specified lease to the uid hash. */
02072 void
02073 uid_hash_add(struct lease *lease)
02074 {
02075         struct lease *head = NULL;
02076         struct lease *cand = NULL;
02077         struct lease *prev = NULL;
02078         struct lease *next = NULL;
02079 
02080         /* If it's not in the hash, just add it. */
02081         if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL))
02082                 lease_id_hash_add(lease_uid_hash, lease->uid, lease->uid_len,
02083                                   lease, MDL);
02084         else {
02085                 /* Otherwise, insert it into the list in order of its
02086                  * preference for "resuming allocation to the client."
02087                  *
02088                  * Because we don't have control of the hash bucket index
02089                  * directly, we have to remove and re-insert the client
02090                  * id into the hash if we're inserting onto the head.
02091                  */
02092                 lease_reference(&cand, head, MDL);
02093                 while (cand != NULL) {
02094                         if (client_lease_preferred(cand, lease))
02095                                 break;
02096 
02097                         if (prev != NULL)
02098                                 lease_dereference(&prev, MDL);
02099                         lease_reference(&prev, cand, MDL);
02100 
02101                         if (cand->n_uid != NULL)
02102                                 lease_reference(&next, cand->n_uid, MDL);
02103 
02104                         lease_dereference(&cand, MDL);
02105 
02106                         if (next != NULL) {
02107                                 lease_reference(&cand, next, MDL);
02108                                 lease_dereference(&next, MDL);
02109                         }
02110                 }
02111 
02112                 /* If we want to insert 'before cand', and prev is NULL,
02113                  * then it was the head of the list.  Assume that position.
02114                  */
02115                 if (prev == NULL) {
02116                         lease_reference(&lease->n_uid, head, MDL);
02117                         lease_id_hash_delete(lease_uid_hash, lease->uid,
02118                                              lease->uid_len, MDL);
02119                         lease_id_hash_add(lease_uid_hash, lease->uid,
02120                                           lease->uid_len, lease, MDL);
02121                 } else /* (prev != NULL) */ {
02122                         if(prev->n_uid != NULL) {
02123                                 lease_reference(&lease->n_uid, prev->n_uid,
02124                                                 MDL);
02125                                 lease_dereference(&prev->n_uid, MDL);
02126                         }
02127                         lease_reference(&prev->n_uid, lease, MDL);
02128 
02129                         lease_dereference(&prev, MDL);
02130                 }
02131 
02132                 if (cand != NULL)
02133                         lease_dereference(&cand, MDL);
02134                 lease_dereference(&head, MDL);
02135         }
02136 }
02137 
02138 /* Delete the specified lease from the uid hash. */
02139 
02140 void uid_hash_delete (lease)
02141         struct lease *lease;
02142 {
02143         struct lease *head = (struct lease *)0;
02144         struct lease *scan;
02145 
02146         /* If it's not in the hash, we have no work to do. */
02147         if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL)) {
02148                 if (lease -> n_uid)
02149                         lease_dereference (&lease -> n_uid, MDL);
02150                 return;
02151         }
02152 
02153         /* If the lease we're freeing is at the head of the list,
02154            remove the hash table entry and add a new one with the
02155            next lease on the list (if there is one). */
02156         if (head == lease) {
02157                 lease_id_hash_delete(lease_uid_hash, lease->uid,
02158                                      lease->uid_len, MDL);
02159                 if (lease -> n_uid) {
02160                         lease_id_hash_add(lease_uid_hash, lease->n_uid->uid,
02161                                           lease->n_uid->uid_len, lease->n_uid,
02162                                           MDL);
02163                         lease_dereference (&lease -> n_uid, MDL);
02164                 }
02165         } else {
02166                 /* Otherwise, look for the lease in the list of leases
02167                    attached to the hash table entry, and remove it if
02168                    we find it. */
02169                 for (scan = head; scan -> n_uid; scan = scan -> n_uid) {
02170                         if (scan -> n_uid == lease) {
02171                                 lease_dereference (&scan -> n_uid, MDL);
02172                                 if (lease -> n_uid) {
02173                                         lease_reference (&scan -> n_uid,
02174                                                          lease -> n_uid, MDL);
02175                                         lease_dereference (&lease -> n_uid,
02176                                                            MDL);
02177                                 }
02178                                 break;
02179                         }
02180                 }
02181         }
02182         lease_dereference (&head, MDL);
02183 }
02184 
02185 /* Add the specified lease to the hardware address hash. */
02186 /* We don't add leases with infiniband addresses to the
02187  * hash as there isn't any address to hash on. */
02188 
02189 void
02190 hw_hash_add(struct lease *lease)
02191 {
02192         struct lease *head = NULL;
02193         struct lease *cand = NULL;
02194         struct lease *prev = NULL;
02195         struct lease *next = NULL;
02196 
02197         /*
02198          * If it's an infiniband address don't bother
02199          * as we don't have a useful address to hash.
02200          */
02201         if ((lease->hardware_addr.hlen == 1) &&
02202             (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
02203                 return;
02204            
02205         /* If it's not in the hash, just add it. */
02206         if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
02207                                     lease -> hardware_addr.hlen, MDL))
02208                 lease_id_hash_add(lease_hw_addr_hash,
02209                                   lease->hardware_addr.hbuf,
02210                                   lease->hardware_addr.hlen, lease, MDL);
02211         else {
02212                 /* Otherwise, insert it into the list in order of its
02213                  * preference for "resuming allocation to the client."
02214                  *
02215                  * Because we don't have control of the hash bucket index
02216                  * directly, we have to remove and re-insert the client
02217                  * id into the hash if we're inserting onto the head.
02218                  */
02219                 lease_reference(&cand, head, MDL);
02220                 while (cand != NULL) {
02221                         if (client_lease_preferred(cand, lease))
02222                                 break;
02223 
02224                         if (prev != NULL)
02225                                 lease_dereference(&prev, MDL);
02226                         lease_reference(&prev, cand, MDL);
02227 
02228                         if (cand->n_hw != NULL)
02229                                 lease_reference(&next, cand->n_hw, MDL);
02230 
02231                         lease_dereference(&cand, MDL);
02232 
02233                         if (next != NULL) {
02234                                 lease_reference(&cand, next, MDL);
02235                                 lease_dereference(&next, MDL);
02236                         }
02237                 }
02238 
02239                 /* If we want to insert 'before cand', and prev is NULL,
02240                  * then it was the head of the list.  Assume that position.
02241                  */
02242                 if (prev == NULL) {
02243                         lease_reference(&lease->n_hw, head, MDL);
02244                         lease_id_hash_delete(lease_hw_addr_hash,
02245                                              lease->hardware_addr.hbuf,
02246                                              lease->hardware_addr.hlen, MDL);
02247                         lease_id_hash_add(lease_hw_addr_hash,
02248                                           lease->hardware_addr.hbuf,
02249                                           lease->hardware_addr.hlen,
02250                                           lease, MDL);
02251                 } else /* (prev != NULL) */ {
02252                         if(prev->n_hw != NULL) {
02253                                 lease_reference(&lease->n_hw, prev->n_hw,
02254                                                 MDL);
02255                                 lease_dereference(&prev->n_hw, MDL);
02256                         }
02257                         lease_reference(&prev->n_hw, lease, MDL);
02258 
02259                         lease_dereference(&prev, MDL);
02260                 }
02261 
02262                 if (cand != NULL)
02263                         lease_dereference(&cand, MDL);
02264                 lease_dereference(&head, MDL);
02265         }
02266 }
02267 
02268 /* Delete the specified lease from the hardware address hash. */
02269 
02270 void hw_hash_delete (lease)
02271         struct lease *lease;
02272 {
02273         struct lease *head = (struct lease *)0;
02274         struct lease *next = (struct lease *)0;
02275 
02276         /*
02277          * If it's an infiniband address don't bother
02278          * as we don't have a useful address to hash.
02279          */
02280         if ((lease->hardware_addr.hlen == 1) &&
02281             (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
02282                 return;
02283 
02284         /* If it's not in the hash, we have no work to do. */
02285         if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
02286                                     lease -> hardware_addr.hlen, MDL)) {
02287                 if (lease -> n_hw)
02288                         lease_dereference (&lease -> n_hw, MDL);
02289                 return;
02290         }
02291 
02292         /* If the lease we're freeing is at the head of the list,
02293            remove the hash table entry and add a new one with the
02294            next lease on the list (if there is one). */
02295         if (head == lease) {
02296                 lease_id_hash_delete(lease_hw_addr_hash,
02297                                      lease->hardware_addr.hbuf,
02298                                      lease->hardware_addr.hlen, MDL);
02299                 if (lease->n_hw) {
02300                         lease_id_hash_add(lease_hw_addr_hash,
02301                                           lease->n_hw->hardware_addr.hbuf,
02302                                           lease->n_hw->hardware_addr.hlen,
02303                                           lease->n_hw, MDL);
02304                         lease_dereference(&lease->n_hw, MDL);
02305                 }
02306         } else {
02307                 /* Otherwise, look for the lease in the list of leases
02308                    attached to the hash table entry, and remove it if
02309                    we find it. */
02310                 while (head -> n_hw) {
02311                         if (head -> n_hw == lease) {
02312                                 lease_dereference (&head -> n_hw, MDL);
02313                                 if (lease -> n_hw) {
02314                                         lease_reference (&head -> n_hw,
02315                                                          lease -> n_hw, MDL);
02316                                         lease_dereference (&lease -> n_hw,
02317                                                            MDL);
02318                                 }
02319                                 break;
02320                         }
02321                         lease_reference (&next, head -> n_hw, MDL);
02322                         lease_dereference (&head, MDL);
02323                         lease_reference (&head, next, MDL);
02324                         lease_dereference (&next, MDL);
02325                 }
02326         }
02327         if (head)
02328                 lease_dereference (&head, MDL);
02329 }
02330 
02331 /* Write v4 leases to permanent storage. */
02332 int write_leases4(void) {
02333         struct lease *l;
02334         struct shared_network *s;
02335         struct pool *p;
02336         struct lease **lptr[RESERVED_LEASES+1];
02337         int num_written = 0, i;
02338 
02339         /* Write all the leases. */
02340         for (s = shared_networks; s; s = s->next) {
02341             for (p = s->pools; p; p = p->next) {
02342                 lptr[FREE_LEASES] = &p->free;
02343                 lptr[ACTIVE_LEASES] = &p->active;
02344                 lptr[EXPIRED_LEASES] = &p->expired;
02345                 lptr[ABANDONED_LEASES] = &p->abandoned;
02346                 lptr[BACKUP_LEASES] = &p->backup;
02347                 lptr[RESERVED_LEASES] = &p->reserved;
02348 
02349                 for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
02350                     for (l = *(lptr[i]); l; l = l->next) {
02351 #if !defined (DEBUG_DUMP_ALL_LEASES)
02352                         if (l->hardware_addr.hlen != 0 || l->uid_len != 0 ||
02353                             l->tsfp != 0 || l->binding_state != FTS_FREE)
02354 #endif
02355                         {
02356                             if (write_lease(l) == 0)
02357                                     return (0);
02358                             num_written++;
02359                         }
02360                     }
02361                 }
02362             }
02363         }
02364 
02365         log_info ("Wrote %d leases to leases file.", num_written);
02366         return (1);
02367 }
02368 
02369 /* Write all interesting leases to permanent storage. */
02370 
02371 int write_leases ()
02372 {
02373         struct host_decl *hp;
02374         struct group_object *gp;
02375         struct hash_bucket *hb;
02376         struct class *cp;
02377         struct collection *colp;
02378         int i;
02379         int num_written;
02380 
02381         /* write all the dynamically-created class declarations. */
02382         if (collections->classes) {
02383                 numclasseswritten = 0;
02384                 for (colp = collections ; colp ; colp = colp->next) {
02385                         for (cp = colp->classes ; cp ; cp = cp->nic) {
02386                                 write_named_billing_class(
02387                                                 (unsigned char *)cp->name,
02388                                                           0, cp);
02389                         }
02390                 }
02391 
02392                 /* XXXJAB this number doesn't include subclasses... */ 
02393                 log_info ("Wrote %d class decls to leases file.",
02394                           numclasseswritten);
02395         }
02396         
02397                         
02398         /* Write all the dynamically-created group declarations. */
02399         if (group_name_hash) {
02400             num_written = 0;
02401             for (i = 0; i < group_name_hash -> hash_count; i++) {
02402                 for (hb = group_name_hash -> buckets [i];
02403                      hb; hb = hb -> next) {
02404                         gp = (struct group_object *)hb -> value;
02405                         if ((gp -> flags & GROUP_OBJECT_DYNAMIC) ||
02406                             ((gp -> flags & GROUP_OBJECT_STATIC) &&
02407                              (gp -> flags & GROUP_OBJECT_DELETED))) {
02408                                 if (!write_group (gp))
02409                                         return 0;
02410                                 ++num_written;
02411                         }
02412                 }
02413             }
02414             log_info ("Wrote %d group decls to leases file.", num_written);
02415         }
02416 
02417         /* Write all the deleted host declarations. */
02418         if (host_name_hash) {
02419             num_written = 0;
02420             for (i = 0; i < host_name_hash -> hash_count; i++) {
02421                 for (hb = host_name_hash -> buckets [i];
02422                      hb; hb = hb -> next) {
02423                         hp = (struct host_decl *)hb -> value;
02424                         if (((hp -> flags & HOST_DECL_STATIC) &&
02425                              (hp -> flags & HOST_DECL_DELETED))) {
02426                                 if (!write_host (hp))
02427                                         return 0;
02428                                 ++num_written;
02429                         }
02430                 }
02431             }
02432             log_info ("Wrote %d deleted host decls to leases file.",
02433                       num_written);
02434         }
02435 
02436         /* Write all the new, dynamic host declarations. */
02437         if (host_name_hash) {
02438             num_written = 0;
02439             for (i = 0; i < host_name_hash -> hash_count; i++) {
02440                 for (hb = host_name_hash -> buckets [i];
02441                      hb; hb = hb -> next) {
02442                         hp = (struct host_decl *)hb -> value;
02443                         if ((hp -> flags & HOST_DECL_DYNAMIC)) {
02444                                 if (!write_host (hp))
02445                                         ++num_written;
02446                         }
02447                 }
02448             }
02449             log_info ("Wrote %d new dynamic host decls to leases file.",
02450                       num_written);
02451         }
02452 
02453 #if defined (FAILOVER_PROTOCOL)
02454         /* Write all the failover states. */
02455         if (!dhcp_failover_write_all_states ())
02456                 return 0;
02457 #endif
02458 
02459         switch (local_family) {
02460               case AF_INET:
02461                 if (write_leases4() == 0)
02462                         return (0);
02463                 break;
02464 #ifdef DHCPv6
02465               case AF_INET6:
02466                 if (write_leases6() == 0)
02467                         return (0);
02468                 break;
02469 #endif /* DHCPv6 */
02470         }
02471 
02472         if (commit_leases() == 0)
02473                 return (0);
02474         return (1);
02475 }
02476 
02477 /* In addition to placing this lease upon a lease queue depending on its
02478  * state, it also keeps track of the number of FREE and BACKUP leases in
02479  * existence, and sets the sort_time on the lease.
02480  *
02481  * Sort_time is used in pool_timer() to determine when the lease will
02482  * bubble to the top of the list and be supersede_lease()'d into its next
02483  * state (possibly, if all goes well).  Example, ACTIVE leases move to
02484  * EXPIRED state when the 'ends' value is reached, so that is its sort
02485  * time.  Most queues are sorted by 'ends', since it is generally best
02486  * practice to re-use the oldest lease, to reduce address collision
02487  * chances.
02488  */
02489 int lease_enqueue (struct lease *comp)
02490 {
02491         struct lease **lq, *prev, *lp;
02492         static struct lease **last_lq = NULL;
02493         static struct lease *last_insert_point = NULL;
02494 
02495         /* No queue to put it on? */
02496         if (!comp -> pool)
02497                 return 0;
02498 
02499         /* Figure out which queue it's going to. */
02500         switch (comp -> binding_state) {
02501               case FTS_FREE:
02502                 if (comp->flags & RESERVED_LEASE) {
02503                         lq = &comp->pool->reserved;
02504                 } else {
02505                         lq = &comp->pool->free;
02506                         comp->pool->free_leases++;
02507                 }
02508                 comp -> sort_time = comp -> ends;
02509                 break;
02510 
02511               case FTS_ACTIVE:
02512                 lq = &comp -> pool -> active;
02513                 comp -> sort_time = comp -> ends;
02514                 break;
02515 
02516               case FTS_EXPIRED:
02517               case FTS_RELEASED:
02518               case FTS_RESET:
02519                 lq = &comp -> pool -> expired;
02520 #if defined(FAILOVER_PROTOCOL)
02521                 /* In partner_down, tsfp is the time at which the lease
02522                  * may be reallocated (stos+mclt).  We can do that with
02523                  * lease_mine_to_reallocate() anywhere between tsfp and
02524                  * ends.  But we prefer to wait until ends before doing it
02525                  * automatically (choose the greater of the two).  Note
02526                  * that 'ends' is usually a historic timestamp in the
02527                  * case of expired leases, is really only in the future
02528                  * on released leases, and if we know a lease to be released
02529                  * the peer might still know it to be active...in which case
02530                  * it's possible the peer has renewed this lease, so avoid
02531                  * doing that.
02532                  */
02533                 if (comp->pool->failover_peer &&
02534                     comp->pool->failover_peer->me.state == partner_down)
02535                         comp->sort_time = (comp->tsfp > comp->ends) ?
02536                                           comp->tsfp : comp->ends;
02537                 else
02538 #endif
02539                         comp->sort_time = comp->ends;
02540 
02541                 break;
02542 
02543               case FTS_ABANDONED:
02544                 lq = &comp -> pool -> abandoned;
02545                 comp -> sort_time = comp -> ends;
02546                 break;
02547 
02548               case FTS_BACKUP:
02549                 if (comp->flags & RESERVED_LEASE) {
02550                         lq = &comp->pool->reserved;
02551                 } else {
02552                         lq = &comp->pool->backup;
02553                         comp->pool->backup_leases++;
02554                 }
02555                 comp -> sort_time = comp -> ends;
02556                 break;
02557 
02558               default:
02559                 log_error ("Lease with bogus binding state: %d",
02560                            comp -> binding_state);
02561 #if defined (BINDING_STATE_DEBUG)
02562                 abort ();
02563 #endif
02564                 return 0;
02565         }
02566 
02567         /* This only works during server startup: during runtime, the last
02568          * lease may be dequeued in between calls.  If the queue is the same
02569          * as was used previously, and the lease structure isn't (this is not
02570          * a re-queue), use that as a starting point for the insertion-sort.
02571          */
02572         if ((server_starting & SS_QFOLLOW) && (lq == last_lq) &&
02573             (comp != last_insert_point) && 
02574             (last_insert_point->sort_time <= comp->sort_time)) {
02575                 prev = last_insert_point;
02576                 lp = prev->next;
02577         } else {
02578                 prev = NULL;
02579                 lp = *lq;
02580         }
02581 
02582         /* Insertion sort the lease onto the appropriate queue. */
02583         for (; lp ; lp = lp->next) {
02584                 if (lp -> sort_time >= comp -> sort_time)
02585                         break;
02586                 prev = lp;
02587         }
02588 
02589         if (prev) {
02590                 if (prev -> next) {
02591                         lease_reference (&comp -> next, prev -> next, MDL);
02592                         lease_dereference (&prev -> next, MDL);
02593                 }
02594                 lease_reference (&prev -> next, comp, MDL);
02595         } else {
02596                 if (*lq) {
02597                         lease_reference (&comp -> next, *lq, MDL);
02598                         lease_dereference (lq, MDL);
02599                 }
02600                 lease_reference (lq, comp, MDL);
02601         }
02602         last_insert_point = comp;
02603         last_lq = lq;
02604         return 1;
02605 }
02606 
02607 /* For a given lease, sort it onto the right list in its pool and put it
02608    in each appropriate hash, understanding that it's already by definition
02609    in lease_ip_addr_hash. */
02610 
02611 isc_result_t
02612 lease_instantiate(const void *key, unsigned len, void *object)
02613 {
02614         struct lease *lease = object;
02615         struct class *class;
02616         /* XXX If the lease doesn't have a pool at this point, it's an
02617            XXX orphan, which we *should* keep around until it expires,
02618            XXX but which right now we just forget. */
02619         if (!lease -> pool) {
02620                 lease_ip_hash_delete(lease_ip_addr_hash, lease->ip_addr.iabuf,
02621                                      lease->ip_addr.len, MDL);
02622                 return ISC_R_SUCCESS;
02623         }
02624                 
02625         /* Put the lease on the right queue.  Failure to queue is probably
02626          * due to a bogus binding state.  In such a case, we claim success,
02627          * so that later leases in a hash_foreach are processed, but we
02628          * return early as we really don't want hw address hash entries or
02629          * other cruft to surround such a bogus entry.
02630          */
02631         if (!lease_enqueue(lease))
02632                 return ISC_R_SUCCESS;
02633 
02634         /* Record the lease in the uid hash if possible. */
02635         if (lease -> uid) {
02636                 uid_hash_add (lease);
02637         }
02638 
02639         /* Record it in the hardware address hash if possible. */
02640         if (lease -> hardware_addr.hlen) {
02641                 hw_hash_add (lease);
02642         }
02643 
02644         /* If the lease has a billing class, set up the billing. */
02645         if (lease -> billing_class) {
02646                 class = (struct class *)0;
02647                 class_reference (&class, lease -> billing_class, MDL);
02648                 class_dereference (&lease -> billing_class, MDL);
02649                 /* If the lease is available for allocation, the billing
02650                    is invalid, so we don't keep it. */
02651                 if (lease -> binding_state == FTS_ACTIVE ||
02652                     lease -> binding_state == FTS_EXPIRED ||
02653                     lease -> binding_state == FTS_RELEASED ||
02654                     lease -> binding_state == FTS_RESET)
02655                         bill_class (lease, class);
02656                 class_dereference (&class, MDL);
02657         }
02658         return ISC_R_SUCCESS;
02659 }
02660 
02661 /* Run expiry events on every pool.   This is called on startup so that
02662    any expiry events that occurred after the server stopped and before it
02663    was restarted can be run.   At the same time, if failover support is
02664    compiled in, we compute the balance of leases for the pool. */
02665 
02666 void expire_all_pools ()
02667 {
02668         struct shared_network *s;
02669         struct pool *p;
02670         int i;
02671         struct lease *l;
02672         struct lease **lptr[RESERVED_LEASES+1];
02673 
02674         /* Indicate that we are in the startup phase */
02675         server_starting = SS_NOSYNC | SS_QFOLLOW;
02676 
02677         /* First, go over the hash list and actually put all the leases
02678            on the appropriate lists. */
02679         lease_ip_hash_foreach(lease_ip_addr_hash, lease_instantiate);
02680 
02681         /* Loop through each pool in each shared network and call the
02682          * expiry routine on the pool.  It is no longer safe to follow
02683          * the queue insertion point, as expiration of a lease can move
02684          * it between queues (and this may be the lease that function
02685          * points at).
02686          */
02687         server_starting &= ~SS_QFOLLOW;
02688         for (s = shared_networks; s; s = s -> next) {
02689             for (p = s -> pools; p; p = p -> next) {
02690                 pool_timer (p);
02691 
02692                 p -> lease_count = 0;
02693                 p -> free_leases = 0;
02694                 p -> backup_leases = 0;
02695 
02696                 lptr [FREE_LEASES] = &p -> free;
02697                 lptr [ACTIVE_LEASES] = &p -> active;
02698                 lptr [EXPIRED_LEASES] = &p -> expired;
02699                 lptr [ABANDONED_LEASES] = &p -> abandoned;
02700                 lptr [BACKUP_LEASES] = &p -> backup;
02701                 lptr [RESERVED_LEASES] = &p->reserved;
02702 
02703                 for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
02704                     for (l = *(lptr [i]); l; l = l -> next) {
02705                         p -> lease_count++;
02706                         if (l -> ends <= cur_time) {
02707                                 if (l->binding_state == FTS_FREE) {
02708                                         if (i == FREE_LEASES)
02709                                                 p->free_leases++;
02710                                         else if (i != RESERVED_LEASES)
02711                                                 log_fatal("Impossible case "
02712                                                           "at %s:%d.", MDL);
02713                                 } else if (l->binding_state == FTS_BACKUP) {
02714                                         if (i == BACKUP_LEASES)
02715                                                 p->backup_leases++;
02716                                         else if (i != RESERVED_LEASES)
02717                                                 log_fatal("Impossible case "
02718                                                           "at %s:%d.", MDL);
02719                                 }
02720                         }
02721 #if defined (FAILOVER_PROTOCOL)
02722                         if (p -> failover_peer &&
02723                             l -> tstp > l -> atsfp &&
02724                             !(l -> flags & ON_UPDATE_QUEUE)) {
02725                                 l -> desired_binding_state = l -> binding_state;
02726                                 dhcp_failover_queue_update (l, 1);
02727                         }
02728 #endif
02729                     }
02730                 }
02731             }
02732         }
02733 
02734         /* turn off startup phase */
02735         server_starting = 0;
02736 }
02737 
02738 void dump_subnets ()
02739 {
02740         struct lease *l;
02741         struct shared_network *s;
02742         struct subnet *n;
02743         struct pool *p;
02744         struct lease **lptr[RESERVED_LEASES+1];
02745         int i;
02746 
02747         log_info ("Subnets:");
02748         for (n = subnets; n; n = n -> next_subnet) {
02749                 log_debug ("  Subnet %s", piaddr (n -> net));
02750                 log_debug ("     netmask %s",
02751                        piaddr (n -> netmask));
02752         }
02753         log_info ("Shared networks:");
02754         for (s = shared_networks; s; s = s -> next) {
02755             log_info ("  %s", s -> name);
02756             for (p = s -> pools; p; p = p -> next) {
02757                 lptr [FREE_LEASES] = &p -> free;
02758                 lptr [ACTIVE_LEASES] = &p -> active;
02759                 lptr [EXPIRED_LEASES] = &p -> expired;
02760                 lptr [ABANDONED_LEASES] = &p -> abandoned;
02761                 lptr [BACKUP_LEASES] = &p -> backup;
02762                 lptr [RESERVED_LEASES] = &p->reserved;
02763 
02764                 for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
02765                     for (l = *(lptr [i]); l; l = l -> next) {
02766                             print_lease (l);
02767                     }
02768                 }
02769             }
02770         }
02771 }
02772 
02773 HASH_FUNCTIONS(lease_ip, const unsigned char *, struct lease, lease_ip_hash_t,
02774                lease_reference, lease_dereference, do_ip4_hash)
02775 HASH_FUNCTIONS(lease_id, const unsigned char *, struct lease, lease_id_hash_t,
02776                lease_reference, lease_dereference, do_id_hash)
02777 HASH_FUNCTIONS (host, const unsigned char *, struct host_decl, host_hash_t,
02778                 host_reference, host_dereference, do_string_hash)
02779 HASH_FUNCTIONS (class, const char *, struct class, class_hash_t,
02780                 class_reference, class_dereference, do_string_hash)
02781 
02782 #if defined (DEBUG_MEMORY_LEAKAGE) && \
02783                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
02784 extern struct hash_table *dns_zone_hash;
02785 extern struct interface_info **interface_vector;
02786 extern int interface_count;
02787 dhcp_control_object_t *dhcp_control_object;
02788 extern struct hash_table *auth_key_hash;
02789 struct hash_table *universe_hash;
02790 struct universe **universes;
02791 int universe_count, universe_max;
02792 #if 0
02793 extern int end;
02794 #endif
02795 
02796 #if defined (COMPACT_LEASES)
02797 extern struct lease *lease_hunks;
02798 #endif
02799 
02800 void free_everything(void)
02801 {
02802         struct subnet *sc = (struct subnet *)0, *sn = (struct subnet *)0;
02803         struct shared_network *nc = (struct shared_network *)0,
02804                 *nn = (struct shared_network *)0;
02805         struct pool *pc = (struct pool *)0, *pn = (struct pool *)0;
02806         struct lease *lc = (struct lease *)0, *ln = (struct lease *)0;
02807         struct interface_info *ic = (struct interface_info *)0,
02808                 *in = (struct interface_info *)0;
02809         struct class *cc = (struct class *)0, *cn = (struct class *)0;
02810         struct collection *lp;
02811         int i;
02812 
02813         /* Get rid of all the hash tables. */
02814         if (host_hw_addr_hash)
02815                 host_free_hash_table (&host_hw_addr_hash, MDL);
02816         host_hw_addr_hash = 0;
02817         if (host_uid_hash)
02818                 host_free_hash_table (&host_uid_hash, MDL);
02819         host_uid_hash = 0;
02820         if (lease_uid_hash)
02821                 lease_id_free_hash_table (&lease_uid_hash, MDL);
02822         lease_uid_hash = 0;
02823         if (lease_ip_addr_hash)
02824                 lease_ip_free_hash_table (&lease_ip_addr_hash, MDL);
02825         lease_ip_addr_hash = 0;
02826         if (lease_hw_addr_hash)
02827                 lease_id_free_hash_table (&lease_hw_addr_hash, MDL);
02828         lease_hw_addr_hash = 0;
02829         if (host_name_hash)
02830                 host_free_hash_table (&host_name_hash, MDL);
02831         host_name_hash = 0;
02832         if (dns_zone_hash)
02833                 dns_zone_free_hash_table (&dns_zone_hash, MDL);
02834         dns_zone_hash = 0;
02835 
02836         while (host_id_info != NULL) {
02837                 host_id_info_t *tmp;
02838                 option_dereference(&host_id_info->option, MDL);
02839                 host_free_hash_table(&host_id_info->values_hash, MDL);
02840                 tmp = host_id_info->next;
02841                 dfree(host_id_info, MDL);
02842                 host_id_info = tmp;
02843         }
02844 #if 0
02845         if (auth_key_hash)
02846                 auth_key_free_hash_table (&auth_key_hash, MDL);
02847 #endif
02848         auth_key_hash = 0;
02849 
02850         omapi_object_dereference ((omapi_object_t **)&dhcp_control_object,
02851                                   MDL);
02852 
02853         for (lp = collections; lp; lp = lp -> next) {
02854             if (lp -> classes) {
02855                 class_reference (&cn, lp -> classes, MDL);
02856                 do {
02857                     if (cn) {
02858                         class_reference (&cc, cn, MDL);
02859                         class_dereference (&cn, MDL);
02860                     }
02861                     if (cc -> nic) {
02862                         class_reference (&cn, cc -> nic, MDL);
02863                         class_dereference (&cc -> nic, MDL);
02864                     }
02865                     group_dereference (&cc -> group, MDL);
02866                     if (cc -> hash) {
02867                             class_free_hash_table (&cc -> hash, MDL);
02868                             cc -> hash = (struct hash_table *)0;
02869                     }
02870                     class_dereference (&cc, MDL);
02871                 } while (cn);
02872                 class_dereference (&lp -> classes, MDL);
02873             }
02874         }
02875 
02876         if (interface_vector) {
02877             for (i = 0; i < interface_count; i++) {
02878                 if (interface_vector [i])
02879                     interface_dereference (&interface_vector [i], MDL);
02880             }
02881             dfree (interface_vector, MDL);
02882             interface_vector = 0;
02883         }
02884 
02885         if (interfaces) {
02886             interface_reference (&in, interfaces, MDL);
02887             do {
02888                 if (in) {
02889                     interface_reference (&ic, in, MDL);
02890                     interface_dereference (&in, MDL);
02891                 }
02892                 if (ic -> next) {
02893                     interface_reference (&in, ic -> next, MDL);
02894                     interface_dereference (&ic -> next, MDL);
02895                 }
02896                 omapi_unregister_io_object ((omapi_object_t *)ic);
02897                 if (ic -> shared_network) {
02898                     if (ic -> shared_network -> interface)
02899                         interface_dereference
02900                                 (&ic -> shared_network -> interface, MDL);
02901                     shared_network_dereference (&ic -> shared_network, MDL);
02902                 }
02903                 interface_dereference (&ic, MDL);
02904             } while (in);
02905             interface_dereference (&interfaces, MDL);
02906         }
02907 
02908         /* Subnets are complicated because of the extra links. */
02909         if (subnets) {
02910             subnet_reference (&sn, subnets, MDL);
02911             do {
02912                 if (sn) {
02913                     subnet_reference (&sc, sn, MDL);
02914                     subnet_dereference (&sn, MDL);
02915                 }
02916                 if (sc -> next_subnet) {
02917                     subnet_reference (&sn, sc -> next_subnet, MDL);
02918                     subnet_dereference (&sc -> next_subnet, MDL);
02919                 }
02920                 if (sc -> next_sibling)
02921                     subnet_dereference (&sc -> next_sibling, MDL);
02922                 if (sc -> shared_network)
02923                     shared_network_dereference (&sc -> shared_network, MDL);
02924                 group_dereference (&sc -> group, MDL);
02925                 if (sc -> interface)
02926                     interface_dereference (&sc -> interface, MDL);
02927                 subnet_dereference (&sc, MDL);
02928             } while (sn);
02929             subnet_dereference (&subnets, MDL);
02930         }
02931 
02932         /* So are shared networks. */
02933         /* XXX: this doesn't work presently, but i'm ok just filtering
02934          * it out of the noise (you get a bigger spike on the real leaks).
02935          * It would be good to fix this, but it is not a "real bug," so not
02936          * today.  This hack is incomplete, it doesn't trim out sub-values.
02937          */
02938         if (shared_networks) {
02939                 shared_network_dereference (&shared_networks, MDL);
02940         /* This is the old method (tries to free memory twice, broken) */
02941         } else if (0) {
02942             shared_network_reference (&nn, shared_networks, MDL);
02943             do {
02944                 if (nn) {
02945                     shared_network_reference (&nc, nn, MDL);
02946                     shared_network_dereference (&nn, MDL);
02947                 }
02948                 if (nc -> next) {
02949                     shared_network_reference (&nn, nc -> next, MDL);
02950                     shared_network_dereference (&nc -> next, MDL);
02951                 }
02952 
02953                 /* As are pools. */
02954                 if (nc -> pools) {
02955                     pool_reference (&pn, nc -> pools, MDL);
02956                     do {
02957                         struct lease **lptr[RESERVED_LEASES+1];
02958 
02959                         if (pn) {
02960                             pool_reference (&pc, pn, MDL);
02961                             pool_dereference (&pn, MDL);
02962                         }
02963                         if (pc -> next) {
02964                             pool_reference (&pn, pc -> next, MDL);
02965                             pool_dereference (&pc -> next, MDL);
02966                         }
02967 
02968                         lptr [FREE_LEASES] = &pc -> free;
02969                         lptr [ACTIVE_LEASES] = &pc -> active;
02970                         lptr [EXPIRED_LEASES] = &pc -> expired;
02971                         lptr [ABANDONED_LEASES] = &pc -> abandoned;
02972                         lptr [BACKUP_LEASES] = &pc -> backup;
02973                         lptr [RESERVED_LEASES] = &pc->reserved;
02974 
02975                         /* As (sigh) are leases. */
02976                         for (i = FREE_LEASES ; i <= RESERVED_LEASES ; i++) {
02977                             if (*lptr [i]) {
02978                                 lease_reference (&ln, *lptr [i], MDL);
02979                                 do {
02980                                     if (ln) {
02981                                         lease_reference (&lc, ln, MDL);
02982                                         lease_dereference (&ln, MDL);
02983                                     }
02984                                     if (lc -> next) {
02985                                         lease_reference (&ln, lc -> next, MDL);
02986                                         lease_dereference (&lc -> next, MDL);
02987                                     }
02988                                     if (lc -> billing_class)
02989                                        class_dereference (&lc -> billing_class,
02990                                                           MDL);
02991                                     if (lc -> state)
02992                                         free_lease_state (lc -> state, MDL);
02993                                     lc -> state = (struct lease_state *)0;
02994                                     if (lc -> n_hw)
02995                                         lease_dereference (&lc -> n_hw, MDL);
02996                                     if (lc -> n_uid)
02997                                         lease_dereference (&lc -> n_uid, MDL);
02998                                     lease_dereference (&lc, MDL);
02999                                 } while (ln);
03000                                 lease_dereference (lptr [i], MDL);
03001                             }
03002                         }
03003                         if (pc -> group)
03004                             group_dereference (&pc -> group, MDL);
03005                         if (pc -> shared_network)
03006                             shared_network_dereference (&pc -> shared_network,
03007                                                         MDL);
03008                         pool_dereference (&pc, MDL);
03009                     } while (pn);
03010                     pool_dereference (&nc -> pools, MDL);
03011                 }
03012                 /* Because of a circular reference, we need to nuke this
03013                    manually. */
03014                 group_dereference (&nc -> group, MDL);
03015                 shared_network_dereference (&nc, MDL);
03016             } while (nn);
03017             shared_network_dereference (&shared_networks, MDL);
03018         }
03019 
03020         cancel_all_timeouts ();
03021         relinquish_timeouts ();
03022         relinquish_ackqueue();
03023         trace_free_all ();
03024         group_dereference (&root_group, MDL);
03025         executable_statement_dereference (&default_classification_rules, MDL);
03026 
03027         shutdown_state = shutdown_drop_omapi_connections;
03028         omapi_io_state_foreach (dhcp_io_shutdown, 0);
03029         shutdown_state = shutdown_listeners;
03030         omapi_io_state_foreach (dhcp_io_shutdown, 0);
03031         shutdown_state = shutdown_dhcp;
03032         omapi_io_state_foreach (dhcp_io_shutdown, 0);
03033 
03034         omapi_object_dereference ((omapi_object_t **)&icmp_state, MDL);
03035 
03036         universe_free_hash_table (&universe_hash, MDL);
03037         for (i = 0; i < universe_count; i++) {
03038 #if 0
03039                 union {
03040                         const char *c;
03041                         char *s;
03042                 } foo;
03043 #endif
03044                 if (universes [i]) {
03045                         if (universes[i]->name_hash)
03046                             option_name_free_hash_table(
03047                                                 &universes[i]->name_hash,
03048                                                 MDL);
03049                         if (universes[i]->code_hash)
03050                             option_code_free_hash_table(
03051                                                 &universes[i]->code_hash,
03052                                                 MDL);
03053 #if 0
03054                         if (universes [i] -> name > (char *)&end) {
03055                                 foo.c = universes [i] -> name;
03056                                 dfree (foo.s, MDL);
03057                         }
03058                         if (universes [i] > (struct universe *)&end)
03059                                 dfree (universes [i], MDL);
03060 #endif
03061                 }
03062         }
03063         dfree (universes, MDL);
03064 
03065         relinquish_free_lease_states ();
03066         relinquish_free_pairs ();
03067         relinquish_free_expressions ();
03068         relinquish_free_binding_values ();
03069         relinquish_free_option_caches ();
03070         relinquish_free_packets ();
03071 #if defined(COMPACT_LEASES)
03072         relinquish_lease_hunks ();
03073 #endif
03074         relinquish_hash_bucket_hunks ();
03075         omapi_type_relinquish ();
03076 }
03077 #endif /* DEBUG_MEMORY_LEAKAGE_ON_EXIT */

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1