[DHCP]
[reactos.git] / reactos / base / services / dhcp / memory.c
1 /* memory.c
2
3 Memory-resident database... */
4
5 /*
6 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43 #ifndef lint
44 static char copyright[] =
45 "$Id: memory.c,v 1.35.2.4 1999/05/27 17:47:43 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
46 #endif /* not lint */
47
48 #include "rosdhcp.h"
49 #include "dhcpd.h"
50
51 struct subnet *subnets;
52 struct shared_network *shared_networks;
53 static struct hash_table *host_hw_addr_hash;
54 static struct hash_table *host_uid_hash;
55 static struct hash_table *lease_uid_hash;
56 static struct hash_table *lease_ip_addr_hash;
57 static struct hash_table *lease_hw_addr_hash;
58 struct lease *dangling_leases;
59
60 static struct hash_table *vendor_class_hash;
61 static struct hash_table *user_class_hash;
62
63 void enter_host (hd)
64 struct host_decl *hd;
65 {
66 struct host_decl *hp = (struct host_decl *)0;
67 struct host_decl *np = (struct host_decl *)0;
68
69 hd -> n_ipaddr = (struct host_decl *)0;
70
71 if (hd -> interface.hlen) {
72 if (!host_hw_addr_hash)
73 host_hw_addr_hash = new_hash ();
74 else
75 hp = (struct host_decl *)
76 hash_lookup (host_hw_addr_hash,
77 hd -> interface.haddr,
78 hd -> interface.hlen);
79
80 /* If there isn't already a host decl matching this
81 address, add it to the hash table. */
82 if (!hp)
83 add_hash (host_hw_addr_hash,
84 hd -> interface.haddr, hd -> interface.hlen,
85 (unsigned char *)hd);
86 }
87
88 /* If there was already a host declaration for this hardware
89 address, add this one to the end of the list. */
90
91 if (hp) {
92 for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr)
93 ;
94 np -> n_ipaddr = hd;
95 }
96
97
98 if (hd -> group -> options [DHO_DHCP_CLIENT_IDENTIFIER]) {
99 if (!tree_evaluate (hd -> group -> options
100 [DHO_DHCP_CLIENT_IDENTIFIER]))
101 return;
102
103 /* If there's no uid hash, make one; otherwise, see if
104 there's already an entry in the hash for this host. */
105 if (!host_uid_hash) {
106 host_uid_hash = new_hash ();
107 hp = (struct host_decl *)0;
108 } else
109 hp = (struct host_decl *) hash_lookup
110 (host_uid_hash,
111 hd -> group -> options
112 [DHO_DHCP_CLIENT_IDENTIFIER] -> value,
113 hd -> group -> options
114 [DHO_DHCP_CLIENT_IDENTIFIER] -> len);
115
116 /* If there's already a host declaration for this
117 client identifier, add this one to the end of the
118 list. Otherwise, add it to the hash table. */
119 if (hp) {
120 /* Don't link it in twice... */
121 if (!np) {
122 for (np = hp; np -> n_ipaddr;
123 np = np -> n_ipaddr)
124 ;
125 np -> n_ipaddr = hd;
126 }
127 } else {
128 add_hash (host_uid_hash,
129 hd -> group -> options
130 [DHO_DHCP_CLIENT_IDENTIFIER] -> value,
131 hd -> group -> options
132 [DHO_DHCP_CLIENT_IDENTIFIER] -> len,
133 (unsigned char *)hd);
134 }
135 }
136 }
137
138 struct host_decl *find_hosts_by_haddr (htype, haddr, hlen)
139 int htype;
140 unsigned char *haddr;
141 int hlen;
142 {
143 struct host_decl *foo;
144
145 foo = (struct host_decl *)hash_lookup (host_hw_addr_hash,
146 haddr, hlen);
147 return foo;
148 }
149
150 struct host_decl *find_hosts_by_uid (data, len)
151 unsigned char *data;
152 int len;
153 {
154 struct host_decl *foo;
155
156 foo = (struct host_decl *)hash_lookup (host_uid_hash, data, len);
157 return foo;
158 }
159
160 /* More than one host_decl can be returned by find_hosts_by_haddr or
161 find_hosts_by_uid, and each host_decl can have multiple addresses.
162 Loop through the list of hosts, and then for each host, through the
163 list of addresses, looking for an address that's in the same shared
164 network as the one specified. Store the matching address through
165 the addr pointer, update the host pointer to point at the host_decl
166 that matched, and return the subnet that matched. */
167
168 subnet *find_host_for_network (struct host_decl **host, iaddr *addr,
169 shared_network *share)
170 {
171 int i;
172 subnet *subnet;
173 iaddr ip_address;
174 struct host_decl *hp;
175
176 for (hp = *host; hp; hp = hp -> n_ipaddr) {
177 if (!hp -> fixed_addr || !tree_evaluate (hp -> fixed_addr))
178 continue;
179 for (i = 0; i < hp -> fixed_addr -> len; i += 4) {
180 ip_address.len = 4;
181 memcpy (ip_address.iabuf,
182 hp -> fixed_addr -> value + i, 4);
183 subnet = find_grouped_subnet (share, ip_address);
184 if (subnet) {
185 *addr = ip_address;
186 *host = hp;
187 return subnet;
188 }
189 }
190 }
191 return (struct _subnet *)0;
192 }
193
194 void new_address_range (iaddr low, iaddr high, subnet *subnet, int dynamic)
195 {
196 lease *address_range, *lp, *plp;
197 iaddr net;
198 int min, max, i;
199 char lowbuf [16], highbuf [16], netbuf [16];
200 shared_network *share = subnet -> shared_network;
201 struct hostent *h;
202 struct in_addr ia;
203
204 /* All subnets should have attached shared network structures. */
205 if (!share) {
206 strcpy (netbuf, piaddr (subnet -> net));
207 error ("No shared network for network %s (%s)",
208 netbuf, piaddr (subnet -> netmask));
209 }
210
211 /* Initialize the hash table if it hasn't been done yet. */
212 if (!lease_uid_hash)
213 lease_uid_hash = new_hash ();
214 if (!lease_ip_addr_hash)
215 lease_ip_addr_hash = new_hash ();
216 if (!lease_hw_addr_hash)
217 lease_hw_addr_hash = new_hash ();
218
219 /* Make sure that high and low addresses are in same subnet. */
220 net = subnet_number (low, subnet -> netmask);
221 if (!addr_eq (net, subnet_number (high, subnet -> netmask))) {
222 strcpy (lowbuf, piaddr (low));
223 strcpy (highbuf, piaddr (high));
224 strcpy (netbuf, piaddr (subnet -> netmask));
225 error ("Address range %s to %s, netmask %s spans %s!",
226 lowbuf, highbuf, netbuf, "multiple subnets");
227 }
228
229 /* Make sure that the addresses are on the correct subnet. */
230 if (!addr_eq (net, subnet -> net)) {
231 strcpy (lowbuf, piaddr (low));
232 strcpy (highbuf, piaddr (high));
233 strcpy (netbuf, piaddr (subnet -> netmask));
234 error ("Address range %s to %s not on net %s/%s!",
235 lowbuf, highbuf, piaddr (subnet -> net), netbuf);
236 }
237
238 /* Get the high and low host addresses... */
239 max = host_addr (high, subnet -> netmask);
240 min = host_addr (low, subnet -> netmask);
241
242 /* Allow range to be specified high-to-low as well as low-to-high. */
243 if (min > max) {
244 max = min;
245 min = host_addr (high, subnet -> netmask);
246 }
247
248 /* Get a lease structure for each address in the range. */
249 address_range = new_leases (max - min + 1, "new_address_range");
250 if (!address_range) {
251 strcpy (lowbuf, piaddr (low));
252 strcpy (highbuf, piaddr (high));
253 error ("No memory for address range %s-%s.", lowbuf, highbuf);
254 }
255 memset (address_range, 0, (sizeof *address_range) * (max - min + 1));
256
257 /* Fill in the last lease if it hasn't been already... */
258 if (!share -> last_lease) {
259 share -> last_lease = &address_range [0];
260 }
261
262 /* Fill out the lease structures with some minimal information. */
263 for (i = 0; i < max - min + 1; i++) {
264 address_range [i].ip_addr =
265 ip_addr (subnet -> net, subnet -> netmask, i + min);
266 address_range [i].starts =
267 address_range [i].timestamp = MIN_TIME;
268 address_range [i].ends = MIN_TIME;
269 address_range [i].subnet = subnet;
270 address_range [i].shared_network = share;
271 address_range [i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0;
272
273 memcpy (&ia, address_range [i].ip_addr.iabuf, 4);
274
275 if (subnet -> group -> get_lease_hostnames) {
276 h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET);
277 if (!h)
278 warn ("No hostname for %s", inet_ntoa (ia));
279 else {
280 address_range [i].hostname =
281 malloc (strlen (h -> h_name) + 1);
282 if (!address_range [i].hostname)
283 error ("no memory for hostname %s.",
284 h -> h_name);
285 strcpy (address_range [i].hostname,
286 h -> h_name);
287 }
288 }
289
290 /* Link this entry into the list. */
291 address_range [i].next = share -> leases;
292 address_range [i].prev = (struct lease *)0;
293 share -> leases = &address_range [i];
294 if (address_range [i].next)
295 address_range [i].next -> prev = share -> leases;
296 add_hash (lease_ip_addr_hash,
297 address_range [i].ip_addr.iabuf,
298 address_range [i].ip_addr.len,
299 (unsigned char *)&address_range [i]);
300 }
301
302 /* Find out if any dangling leases are in range... */
303 plp = (struct lease *)0;
304 for (lp = dangling_leases; lp; lp = lp -> next) {
305 iaddr lnet;
306 int lhost;
307
308 lnet = subnet_number (lp -> ip_addr, subnet -> netmask);
309 lhost = host_addr (lp -> ip_addr, subnet -> netmask);
310
311 /* If it's in range, fill in the real lease structure with
312 the dangling lease's values, and remove the lease from
313 the list of dangling leases. */
314 if (addr_eq (lnet, subnet -> net) &&
315 lhost >= i && lhost <= max) {
316 if (plp) {
317 plp -> next = lp -> next;
318 } else {
319 dangling_leases = lp -> next;
320 }
321 lp -> next = (struct lease *)0;
322 address_range [lhost - i].hostname = lp -> hostname;
323 address_range [lhost - i].client_hostname =
324 lp -> client_hostname;
325 supersede_lease (&address_range [lhost - i], lp, 0);
326 free_lease (lp, "new_address_range");
327 } else
328 plp = lp;
329 }
330 }
331
332 subnet *find_subnet (iaddr addr)
333 {
334 subnet *rv;
335
336 for (rv = subnets; rv; rv = rv -> next_subnet) {
337 if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
338 return rv;
339 }
340 return (subnet *)0;
341 }
342
343 subnet *find_grouped_subnet (shared_network *share, iaddr addr)
344 {
345 subnet *rv;
346
347 for (rv = share -> subnets; rv; rv = rv -> next_sibling) {
348 if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
349 return rv;
350 }
351 return (subnet *)0;
352 }
353
354 int subnet_inner_than (struct _subnet *subnet, struct _subnet *scan, int warnp)
355 {
356 if (addr_eq (subnet_number (subnet -> net, scan -> netmask),
357 scan -> net) ||
358 addr_eq (subnet_number (scan -> net, subnet -> netmask),
359 subnet -> net)) {
360 char n1buf [16];
361 int i, j;
362 for (i = 0; i < 32; i++)
363 if (subnet -> netmask.iabuf [3 - (i >> 3)]
364 & (1 << (i & 7)))
365 break;
366 for (j = 0; j < 32; j++)
367 if (scan -> netmask.iabuf [3 - (j >> 3)] &
368 (1 << (j & 7)))
369 break;
370 strcpy (n1buf, piaddr (subnet -> net));
371 if (warnp)
372 warn ("%ssubnet %s/%d conflicts with subnet %s/%d",
373 "Warning: ", n1buf, 32 - i,
374 piaddr (scan -> net), 32 - j);
375 if (i < j)
376 return 1;
377 }
378 return 0;
379 }
380
381 /* Enter a new subnet into the subnet list. */
382
383 void enter_subnet (struct _subnet *subnet)
384 {
385 struct _subnet *scan, *prev = (struct _subnet *)0;
386
387 /* Check for duplicates... */
388 for (scan = subnets; scan; scan = scan -> next_subnet) {
389 /* When we find a conflict, make sure that the
390 subnet with the narrowest subnet mask comes
391 first. */
392 if (subnet_inner_than (subnet, scan, 1)) {
393 if (prev) {
394 prev -> next_subnet = subnet;
395 } else
396 subnets = subnet;
397 subnet -> next_subnet = scan;
398 return;
399 }
400 prev = scan;
401 }
402
403 /* XXX use the BSD radix tree code instead of a linked list. */
404 subnet -> next_subnet = subnets;
405 subnets = subnet;
406 }
407
408 /* Enter a new shared network into the shared network list. */
409
410 void enter_shared_network (shared_network *share)
411 {
412 /* XXX Sort the nets into a balanced tree to make searching quicker. */
413 share -> next = shared_networks;
414 shared_networks = share;
415 }
416
417 /* Enter a lease into the system. This is called by the parser each
418 time it reads in a new lease. If the subnet for that lease has
419 already been read in (usually the case), just update that lease;
420 otherwise, allocate temporary storage for the lease and keep it around
421 until we're done reading in the config file. */
422
423 void enter_lease (struct _lease *lease)
424 {
425 struct _lease *comp = find_lease_by_ip_addr (lease -> ip_addr);
426
427 /* If we don't have a place for this lease yet, save it for
428 later. */
429 if (!comp) {
430 comp = new_lease ("enter_lease");
431 if (!comp) {
432 error ("No memory for lease %s\n",
433 piaddr (lease -> ip_addr));
434 }
435 *comp = *lease;
436 comp -> next = dangling_leases;
437 comp -> prev = (struct lease *)0;
438 dangling_leases = comp;
439 } else {
440 /* Record the hostname information in the lease. */
441 comp -> hostname = lease -> hostname;
442 comp -> client_hostname = lease -> client_hostname;
443 supersede_lease (comp, lease, 0);
444 }
445 }
446
447 /* Replace the data in an existing lease with the data in a new lease;
448 adjust hash tables to suit, and insertion sort the lease into the
449 list of leases by expiry time so that we can always find the oldest
450 lease. */
451
452 int supersede_lease (struct _lease *comp, struct _lease *lease, int commit)
453 {
454 int enter_uid = 0;
455 int enter_hwaddr = 0;
456 struct _lease *lp;
457
458 /* Static leases are not currently kept in the database... */
459 if (lease -> flags & STATIC_LEASE)
460 return 1;
461
462 /* If the existing lease hasn't expired and has a different
463 unique identifier or, if it doesn't have a unique
464 identifier, a different hardware address, then the two
465 leases are in conflict. If the existing lease has a uid
466 and the new one doesn't, but they both have the same
467 hardware address, and dynamic bootp is allowed on this
468 lease, then we allow that, in case a dynamic BOOTP lease is
469 requested *after* a DHCP lease has been assigned. */
470
471 if (!(lease -> flags & ABANDONED_LEASE) &&
472 comp -> ends > cur_time &&
473 (((comp -> uid && lease -> uid) &&
474 (comp -> uid_len != lease -> uid_len ||
475 memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
476 (!comp -> uid &&
477 ((comp -> hardware_addr.htype !=
478 lease -> hardware_addr.htype) ||
479 (comp -> hardware_addr.hlen !=
480 lease -> hardware_addr.hlen) ||
481 memcmp (comp -> hardware_addr.haddr,
482 lease -> hardware_addr.haddr,
483 comp -> hardware_addr.hlen))))) {
484 warn ("Lease conflict at %s",
485 piaddr (comp -> ip_addr));
486 return 0;
487 } else {
488 /* If there's a Unique ID, dissociate it from the hash
489 table and free it if necessary. */
490 if (comp -> uid) {
491 uid_hash_delete (comp);
492 enter_uid = 1;
493 if (comp -> uid != &comp -> uid_buf [0]) {
494 free (comp -> uid);
495 comp -> uid_max = 0;
496 comp -> uid_len = 0;
497 }
498 comp -> uid = (unsigned char *)0;
499 } else
500 enter_uid = 1;
501
502 if (comp -> hardware_addr.htype &&
503 ((comp -> hardware_addr.hlen !=
504 lease -> hardware_addr.hlen) ||
505 (comp -> hardware_addr.htype !=
506 lease -> hardware_addr.htype) ||
507 memcmp (comp -> hardware_addr.haddr,
508 lease -> hardware_addr.haddr,
509 comp -> hardware_addr.hlen))) {
510 hw_hash_delete (comp);
511 enter_hwaddr = 1;
512 } else if (!comp -> hardware_addr.htype)
513 enter_hwaddr = 1;
514
515 /* Copy the data files, but not the linkages. */
516 comp -> starts = lease -> starts;
517 if (lease -> uid) {
518 if (lease -> uid_len < sizeof (lease -> uid_buf)) {
519 memcpy (comp -> uid_buf,
520 lease -> uid, lease -> uid_len);
521 comp -> uid = &comp -> uid_buf [0];
522 comp -> uid_max = sizeof comp -> uid_buf;
523 } else if (lease -> uid != &lease -> uid_buf [0]) {
524 comp -> uid = lease -> uid;
525 comp -> uid_max = lease -> uid_max;
526 lease -> uid = (unsigned char *)0;
527 lease -> uid_max = 0;
528 } else {
529 error ("corrupt lease uid."); /* XXX */
530 }
531 } else {
532 comp -> uid = (unsigned char *)0;
533 comp -> uid_max = 0;
534 }
535 comp -> uid_len = lease -> uid_len;
536 comp -> host = lease -> host;
537 comp -> hardware_addr = lease -> hardware_addr;
538 comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) |
539 (comp -> flags & ~EPHEMERAL_FLAGS));
540
541 /* Record the lease in the uid hash if necessary. */
542 if (enter_uid && lease -> uid) {
543 uid_hash_add (comp);
544 }
545
546 /* Record it in the hardware address hash if necessary. */
547 if (enter_hwaddr && lease -> hardware_addr.htype) {
548 hw_hash_add (comp);
549 }
550
551 /* Remove the lease from its current place in the
552 timeout sequence. */
553 if (comp -> prev) {
554 comp -> prev -> next = comp -> next;
555 } else {
556 comp -> shared_network -> leases = comp -> next;
557 }
558 if (comp -> next) {
559 comp -> next -> prev = comp -> prev;
560 }
561 if (comp -> shared_network -> last_lease == comp) {
562 comp -> shared_network -> last_lease = comp -> prev;
563 }
564
565 /* Find the last insertion point... */
566 if (comp == comp -> shared_network -> insertion_point ||
567 !comp -> shared_network -> insertion_point) {
568 lp = comp -> shared_network -> leases;
569 } else {
570 lp = comp -> shared_network -> insertion_point;
571 }
572
573 if (!lp) {
574 /* Nothing on the list yet? Just make comp the
575 head of the list. */
576 comp -> shared_network -> leases = comp;
577 comp -> shared_network -> last_lease = comp;
578 } else if (lp -> ends > lease -> ends) {
579 /* Skip down the list until we run out of list
580 or find a place for comp. */
581 while (lp -> next && lp -> ends > lease -> ends) {
582 lp = lp -> next;
583 }
584 if (lp -> ends > lease -> ends) {
585 /* If we ran out of list, put comp
586 at the end. */
587 lp -> next = comp;
588 comp -> prev = lp;
589 comp -> next = (struct lease *)0;
590 comp -> shared_network -> last_lease = comp;
591 } else {
592 /* If we didn't, put it between lp and
593 the previous item on the list. */
594 if ((comp -> prev = lp -> prev))
595 comp -> prev -> next = comp;
596 comp -> next = lp;
597 lp -> prev = comp;
598 }
599 } else {
600 /* Skip up the list until we run out of list
601 or find a place for comp. */
602 while (lp -> prev && lp -> ends < lease -> ends) {
603 lp = lp -> prev;
604 }
605 if (lp -> ends < lease -> ends) {
606 /* If we ran out of list, put comp
607 at the beginning. */
608 lp -> prev = comp;
609 comp -> next = lp;
610 comp -> prev = (struct lease *)0;
611 comp -> shared_network -> leases = comp;
612 } else {
613 /* If we didn't, put it between lp and
614 the next item on the list. */
615 if ((comp -> next = lp -> next))
616 comp -> next -> prev = comp;
617 comp -> prev = lp;
618 lp -> next = comp;
619 }
620 }
621 comp -> shared_network -> insertion_point = comp;
622 comp -> ends = lease -> ends;
623 }
624
625 /* Return zero if we didn't commit the lease to permanent storage;
626 nonzero if we did. */
627 return commit && write_lease (comp) && commit_leases ();
628 }
629
630 /* Release the specified lease and re-hash it as appropriate. */
631
632 void release_lease (struct _lease *lease)
633 {
634 struct _lease lt;
635
636 lt = *lease;
637 if (lt.ends > cur_time) {
638 lt.ends = cur_time;
639 supersede_lease (lease, &lt, 1);
640 }
641 }
642
643 /* Abandon the specified lease (set its timeout to infinity and its
644 particulars to zero, and re-hash it as appropriate. */
645
646 void abandon_lease (struct _lease *lease, char *message)
647 {
648 struct _lease lt;
649
650 lease -> flags |= ABANDONED_LEASE;
651 lt = *lease;
652 lt.ends = cur_time;
653 warn ("Abandoning IP address %s: %s",
654 piaddr (lease -> ip_addr), message);
655 lt.hardware_addr.htype = 0;
656 lt.hardware_addr.hlen = 0;
657 lt.uid = (unsigned char *)0;
658 lt.uid_len = 0;
659 supersede_lease (lease, &lt, 1);
660 }
661
662 /* Locate the lease associated with a given IP address... */
663
664 lease *find_lease_by_ip_addr (iaddr addr)
665 {
666 lease *lease = (struct _lease *)hash_lookup (lease_ip_addr_hash,
667 addr.iabuf,
668 addr.len);
669 return lease;
670 }
671
672 lease *find_lease_by_uid (unsigned char *uid, int len)
673 {
674 lease *lease = (struct lease *)hash_lookup (lease_uid_hash,
675 uid, len);
676 return lease;
677 }
678
679 lease *find_lease_by_hw_addr (unsigned char *hwaddr, int hwlen)
680 {
681 struct _lease *lease =
682 (struct _lease *)hash_lookup (lease_hw_addr_hash,
683 hwaddr, hwlen);
684 return lease;
685 }
686
687 /* Add the specified lease to the uid hash. */
688
689 void uid_hash_add (lease *lease)
690 {
691 struct _lease *head = find_lease_by_uid (lease -> uid, lease -> uid_len);
692 struct _lease *scan;
693
694 #ifdef DEBUG
695 if (lease -> n_uid)
696 abort ();
697 #endif
698
699 /* If it's not in the hash, just add it. */
700 if (!head)
701 add_hash (lease_uid_hash, lease -> uid,
702 lease -> uid_len, (unsigned char *)lease);
703 else {
704 /* Otherwise, attach it to the end of the list. */
705 for (scan = head; scan -> n_uid; scan = scan -> n_uid)
706 #ifdef DEBUG
707 if (scan == lease)
708 abort ()
709 #endif
710 ;
711 scan -> n_uid = lease;
712 }
713 }
714
715 /* Delete the specified lease from the uid hash. */
716
717 void uid_hash_delete (lease *lease)
718 {
719 struct _lease *head =
720 find_lease_by_uid (lease -> uid, lease -> uid_len);
721 struct _lease *scan;
722
723 /* If it's not in the hash, we have no work to do. */
724 if (!head) {
725 lease -> n_uid = (struct lease *)0;
726 return;
727 }
728
729 /* If the lease we're freeing is at the head of the list,
730 remove the hash table entry and add a new one with the
731 next lease on the list (if there is one). */
732 if (head == lease) {
733 delete_hash_entry (lease_uid_hash,
734 lease -> uid, lease -> uid_len);
735 if (lease -> n_uid)
736 add_hash (lease_uid_hash,
737 lease -> n_uid -> uid,
738 lease -> n_uid -> uid_len,
739 (unsigned char *)(lease -> n_uid));
740 } else {
741 /* Otherwise, look for the lease in the list of leases
742 attached to the hash table entry, and remove it if
743 we find it. */
744 for (scan = head; scan -> n_uid; scan = scan -> n_uid) {
745 if (scan -> n_uid == lease) {
746 scan -> n_uid = scan -> n_uid -> n_uid;
747 break;
748 }
749 }
750 }
751 lease -> n_uid = (struct lease *)0;
752 }
753
754 /* Add the specified lease to the hardware address hash. */
755
756 void hw_hash_add (lease *lease)
757 {
758 struct _lease *head =
759 find_lease_by_hw_addr (lease -> hardware_addr.haddr,
760 lease -> hardware_addr.hlen);
761 struct _lease *scan;
762
763 /* If it's not in the hash, just add it. */
764 if (!head)
765 add_hash (lease_hw_addr_hash,
766 lease -> hardware_addr.haddr,
767 lease -> hardware_addr.hlen,
768 (unsigned char *)lease);
769 else {
770 /* Otherwise, attach it to the end of the list. */
771 for (scan = head; scan -> n_hw; scan = scan -> n_hw)
772 ;
773 scan -> n_hw = lease;
774 }
775 }
776
777 /* Delete the specified lease from the hardware address hash. */
778
779 void hw_hash_delete (lease *lease)
780 {
781 struct _lease *head =
782 find_lease_by_hw_addr (lease -> hardware_addr.haddr,
783 lease -> hardware_addr.hlen);
784 struct _lease *scan;
785
786 /* If it's not in the hash, we have no work to do. */
787 if (!head) {
788 lease -> n_hw = (struct lease *)0;
789 return;
790 }
791
792 /* If the lease we're freeing is at the head of the list,
793 remove the hash table entry and add a new one with the
794 next lease on the list (if there is one). */
795 if (head == lease) {
796 delete_hash_entry (lease_hw_addr_hash,
797 lease -> hardware_addr.haddr,
798 lease -> hardware_addr.hlen);
799 if (lease -> n_hw)
800 add_hash (lease_hw_addr_hash,
801 lease -> n_hw -> hardware_addr.haddr,
802 lease -> n_hw -> hardware_addr.hlen,
803 (unsigned char *)(lease -> n_hw));
804 } else {
805 /* Otherwise, look for the lease in the list of leases
806 attached to the hash table entry, and remove it if
807 we find it. */
808 for (scan = head; scan -> n_hw; scan = scan -> n_hw) {
809 if (scan -> n_hw == lease) {
810 scan -> n_hw = scan -> n_hw -> n_hw;
811 break;
812 }
813 }
814 }
815 lease -> n_hw = (struct lease *)0;
816 }
817
818
819 struct class *add_class (type, name)
820 int type;
821 char *name;
822 {
823 struct class *class = new_class ("add_class");
824 char *tname = (char *)malloc (strlen (name) + 1);
825
826 if (!vendor_class_hash)
827 vendor_class_hash = new_hash ();
828 if (!user_class_hash)
829 user_class_hash = new_hash ();
830
831 if (!tname || !class || !vendor_class_hash || !user_class_hash)
832 {
833 if (tname != NULL)
834 free(tname);
835 return (struct class *)0;
836 }
837
838 memset (class, 0, sizeof *class);
839 strcpy (tname, name);
840 class -> name = tname;
841
842 if (type)
843 add_hash (user_class_hash,
844 (unsigned char *)tname, strlen (tname),
845 (unsigned char *)class);
846 else
847 add_hash (vendor_class_hash,
848 (unsigned char *)tname, strlen (tname),
849 (unsigned char *)class);
850 return class;
851 }
852
853 struct class *find_class (type, name, len)
854 int type;
855 unsigned char *name;
856 int len;
857 {
858 struct class *class =
859 (struct class *)hash_lookup (type
860 ? user_class_hash
861 : vendor_class_hash, name, len);
862 return class;
863 }
864
865 struct group *clone_group (group, caller)
866 struct group *group;
867 char *caller;
868 {
869 struct group *g = new_group (caller);
870 if (!g)
871 error ("%s: can't allocate new group", caller);
872 *g = *group;
873 return g;
874 }
875
876 /* Write all interesting leases to permanent storage. */
877
878 void write_leases ()
879 {
880 lease *l;
881 shared_network *s;
882
883 for (s = shared_networks; s; s = (shared_network *)s -> next) {
884 for (l = s -> leases; l; l = l -> next) {
885 if (l -> hardware_addr.hlen ||
886 l -> uid_len ||
887 (l -> flags & ABANDONED_LEASE))
888 if (!write_lease (l))
889 error ("Can't rewrite lease database");
890 }
891 }
892 if (!commit_leases ())
893 error ("Can't commit leases to new database: %m");
894 }
895
896 void dump_subnets ()
897 {
898 struct _lease *l;
899 shared_network *s;
900 subnet *n;
901
902 note ("Subnets:");
903 for (n = subnets; n; n = n -> next_subnet) {
904 debug (" Subnet %s", piaddr (n -> net));
905 debug (" netmask %s",
906 piaddr (n -> netmask));
907 }
908 note ("Shared networks:");
909 for (s = shared_networks; s; s = (shared_network *)s -> next) {
910 note (" %s", s -> name);
911 for (l = s -> leases; l; l = l -> next) {
912 print_lease (l);
913 }
914 if (s -> last_lease) {
915 debug (" Last Lease:");
916 print_lease (s -> last_lease);
917 }
918 }
919 }