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