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