File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / server / mdb.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:30:18 2012 UTC (12 years, 5 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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