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