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