File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / server / mdb.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:55 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

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

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