1/*	$NetBSD: mdb6.c,v 1.7 2022/09/23 12:30:52 christos Exp $	*/
2
3/*
4 * Copyright (C) 2007-2017 by Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/cdefs.h>
20__RCSID("$NetBSD: mdb6.c,v 1.7 2022/09/23 12:30:52 christos Exp $");
21
22
23/*!
24 * \todo assert()
25 * \todo simplify functions, as pool is now in iaaddr
26 */
27
28/*! \file server/mdb6.c
29 *
30 * \page ipv6structures IPv6 Structures Overview
31 *
32 * A brief description of the IPv6 structures as reverse engineered.
33 *
34 * There are four major data structures in the lease configuraion.
35 *
36 * - shared_network - The shared network is the outer enclosing scope for a
37 *                    network region that shares a broadcast domain.  It is
38 *                    composed of one or more subnets all of which are valid
39 *                    in the given region.  The share network may be
40 *                    explicitly defined or implicitly created if there is
41 *                    only a subnet statement.  This structrure is shared
42 *                    with v4.  Each shared network statment or naked subnet
43 *                    will map to one of these structures
44 *
45 * - subnet     - The subnet structure mostly specifies the address range
46 *                that could be valid in a given region.  This structute
47 *                doesn't include the addresses that the server can delegate
48 *                those are in the ipv6_pool.  This structure is also shared
49 *                with v4.  Each subnet statement will map to one of these
50 *                structures.
51 *
52 * - ipv6_pond  - The pond structure is a grouping of the address and prefix
53 *                information via the pointers to the ipv6_pool and the
54 *                allowability of this pool for given clinets via the permit
55 *                lists and the valid TIMEs.  This is equivilent to the v4
56 *                pool structure and would have been named ip6_pool except
57 *                that the name was already in use.  Generally each pool6
58 *                statement will map to one of these structures. In addition
59 *                there may be one or for each group of naked range6 and
60 *                prefix6 statements within a shared network that share
61 *                the same group of statements.
62 *
63 * - ipv6_pool - this contains information about a pool of addresses or prefixes
64 *               that the server is using.  This includes a hash table that
65 *               tracks the active items and a pair of heap tables one for
66 *               active items and one for non-active items.  The heap tables
67 *               are used to determine the next items to be modified due to
68 *               timing events (expire mostly).
69 *
70 * The linkages then look like this:
71 * \verbatim
72 *+--------------+   +-------------+
73 *|Shared Network|   | ipv6_pond   |
74 *|   group      |   |   group     |
75 *|              |   | permit info |
76 *|              |   |    next    ---->
77 *|    ponds    ---->|             |
78 *|              |<----  shared    |
79 *|   Subnets    |   |    pools    |
80 *+-----|--------+   +------|------+
81 *      |  ^                |    ^
82 *      |  |                v    |
83 *      |  |         +-----------|-+
84 *      |  |         | ipv6_pool | |
85 *      |  |         |    type   | |
86 *      |  |         |   ipv6_pond |
87 *      |  |         |             |
88 *      |  |         |    next    ---->
89 *      |  |         |             |
90 *      |  |         |   subnet    |
91 *      |  |         +-----|-------+
92 *      |  |               |
93 *      |  |               v
94 *      |  |         +-------------+
95 *      |  |         |   subnet    |
96 *      |  +----------   shared    |
97 *      +----------->|             |
98 *                   |   group     |
99 *                   +-------------+
100 *
101 * The shared network contains a list of all the subnets that are on a broadcast
102 * doamin.  These can be used to determine if an address makes sense in a given
103 * domain, but the subnets do not contain the addresses the server can delegate.
104 * Those are stored in the ponds and pools.
105 *
106 * In the simple case to find an acceptable address the server would first find
107 * the shared network the client is on based on either the interface used to
108 * receive the request or the relay agent's information.  From the shared
109 * network the server will walk through it's list of ponds.  For each pond it
110 * will evaluate the permit information against the (already done) classification.
111 * If it finds an acceptable pond it will then walk through the pools for that
112 * pond.  The server first checks the type of the pool (NA, TA and PD) agaisnt the
113 * request and if they match it attemps to find an address within that pool.  On
114 * success the address is used, on failure the server steps to the next pool and
115 * if necessary to the next pond.
116 *
117 * When the server is successful in finding an address it will execute any
118 * statements assocaited with the pond, then the subnet, then the shared
119 * network the group field is for in the above picture).
120 *
121 * In configurations that don't include either a shared network or a pool6
122 * statement (or both) the missing pieces are created.
123 *
124 *
125 * There are three major data structuress involved in the lease database:
126 *
127 * - ipv6_pool - see above
128 * - ia_xx   - this contains information about a single IA from a request
129 *             normally it will contain one pointer to a lease for the client
130 *             but it may contain more in some circumstances.  There are 3
131 *             hash tables to aid in accessing these one each for NA, TA and PD.
132 * - iasubopt - the v6 lease structure.  These are created dynamically when
133 *              a client asks for something and will eventually be destroyed
134 *              if the client doesn't re-ask for that item.  A lease has space
135 *              for backpointers to the IA and to the pool to which it belongs.
136 *              The pool backpointer is always filled, the IA pointer may not be.
137 *
138 * In normal use we then have something like this:
139 *
140 * \verbatim
141 * ia hash tables
142 *  ia_na_active                           +----------------+
143 *  ia_ta_active          +------------+   | pool           |
144 *  ia_pd_active          | iasubopt   |<--|  active hash   |
145 * +-----------------+    | aka lease  |<--|  active heap   |
146 * | ia_xx           |    |  pool ptr  |-->|                |
147 * |  iasubopt array |<---|  iaptr     |<--|  inactive heap |
148 * |   lease ptr     |--->|            |   |                |
149 * +-----------------+    +------------+   +----------------+
150 * \endverbatim
151 *
152 * For the pool either the inactive heap will have a pointer
153 * or both the active heap and the active hash will have pointers.
154 *
155 * I think there are several major items to notice.   The first is
156 * that as a lease moves around it will be added to and removed
157 * from the address hash table in the pool and between the active
158 * and inactive hash tables.  The hash table and the active heap
159 * are used when the lease is either active or abandoned.  The
160 * inactive heap is used for all other states.  In particular a
161 * lease that has expired or been released will be cleaned
162 * (DDNS removal etc) and then moved to the inactive heap.  After
163 * some time period (currently 1 hour) it will be freed.
164 *
165 * The second is that when a client requests specific addresses,
166 * either because it previously owned them or if the server supplied
167 * them as part of a solicit, the server will try to lookup the ia_xx
168 * associated with the client and find the addresses there.  If it
169 * does find appropriate leases it moves them from the old IA to
170 * a new IA and eventually replaces the old IA with the new IA
171 * in the IA hash tables.
172 *
173 */
174#include "config.h"
175
176#include <sys/types.h>
177#include <time.h>
178#include <netinet/in.h>
179
180#include <stdarg.h>
181#include "dhcpd.h"
182#include "omapip/omapip.h"
183#include "omapip/hash.h"
184#include <isc/md.h>
185
186HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t,
187	       ia_reference, ia_dereference, do_string_hash)
188
189ia_hash_t *ia_na_active;
190ia_hash_t *ia_ta_active;
191ia_hash_t *ia_pd_active;
192
193HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t,
194	       iasubopt_reference, iasubopt_dereference, do_string_hash)
195
196struct ipv6_pool **pools;
197int num_pools;
198
199/*
200 * Create a new IAADDR/PREFIX structure.
201 *
202 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
203 *   initialized to NULL
204 */
205isc_result_t
206iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) {
207	struct iasubopt *tmp;
208
209	if (iasubopt == NULL) {
210		log_error("%s(%d): NULL pointer reference", file, line);
211		return DHCP_R_INVALIDARG;
212	}
213	if (*iasubopt != NULL) {
214		log_error("%s(%d): non-NULL pointer", file, line);
215		return DHCP_R_INVALIDARG;
216	}
217
218	tmp = dmalloc(sizeof(*tmp), file, line);
219	if (tmp == NULL) {
220		return ISC_R_NOMEMORY;
221	}
222
223	tmp->refcnt = 1;
224	tmp->state = FTS_FREE;
225	tmp->active_index = 0;
226	tmp->inactive_index = 0;
227	tmp->plen = 255;
228
229	*iasubopt = tmp;
230	return ISC_R_SUCCESS;
231}
232
233/*
234 * Reference an IAADDR/PREFIX structure.
235 *
236 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
237 *   initialized to NULL
238 */
239isc_result_t
240iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src,
241		 const char *file, int line) {
242	if (iasubopt == NULL) {
243		log_error("%s(%d): NULL pointer reference", file, line);
244		return DHCP_R_INVALIDARG;
245	}
246	if (*iasubopt != NULL) {
247		log_error("%s(%d): non-NULL pointer", file, line);
248		return DHCP_R_INVALIDARG;
249	}
250	if (src == NULL) {
251		log_error("%s(%d): NULL pointer reference", file, line);
252		return DHCP_R_INVALIDARG;
253	}
254	*iasubopt = src;
255	src->refcnt++;
256	return ISC_R_SUCCESS;
257}
258
259
260/*
261 * Dereference an IAADDR/PREFIX structure.
262 *
263 * If it is the last reference, then the memory for the
264 * structure is freed.
265 */
266isc_result_t
267iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) {
268	struct iasubopt *tmp;
269
270	if ((iasubopt == NULL) || (*iasubopt == NULL)) {
271		log_error("%s(%d): NULL pointer", file, line);
272		return DHCP_R_INVALIDARG;
273	}
274
275	tmp = *iasubopt;
276	*iasubopt = NULL;
277
278	tmp->refcnt--;
279	if (tmp->refcnt < 0) {
280		log_error("%s(%d): negative refcnt", file, line);
281		tmp->refcnt = 0;
282	}
283	if (tmp->refcnt == 0) {
284		if (tmp->ia != NULL) {
285			ia_dereference(&(tmp->ia), file, line);
286		}
287		if (tmp->ipv6_pool != NULL) {
288			ipv6_pool_dereference(&(tmp->ipv6_pool), file, line);
289		}
290		if (tmp->scope != NULL) {
291			binding_scope_dereference(&tmp->scope, file, line);
292		}
293
294		if (tmp->on_star.on_expiry != NULL) {
295			executable_statement_dereference
296				(&tmp->on_star.on_expiry, MDL);
297		}
298		if (tmp->on_star.on_commit != NULL) {
299			executable_statement_dereference
300				(&tmp->on_star.on_commit, MDL);
301		}
302		if (tmp->on_star.on_release != NULL) {
303			executable_statement_dereference
304				(&tmp->on_star.on_release, MDL);
305		}
306
307		dfree(tmp, file, line);
308	}
309
310	return ISC_R_SUCCESS;
311}
312
313/*
314 * Make the key that we use for IA.
315 */
316isc_result_t
317ia_make_key(struct data_string *key, u_int32_t iaid,
318	    const char *duid, unsigned int duid_len,
319	    const char *file, int line) {
320
321	memset(key, 0, sizeof(*key));
322	key->len = duid_len + sizeof(iaid);
323	if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
324		return ISC_R_NOMEMORY;
325	}
326	key->data = key->buffer->data;
327	memcpy((char *)key->data, &iaid, sizeof(iaid));
328	memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
329
330	return ISC_R_SUCCESS;
331}
332
333/*
334 * Create a new IA structure.
335 *
336 * - ia must be a pointer to a (struct ia_xx *) pointer previously
337 *   initialized to NULL
338 * - iaid and duid are values from the client
339 *
340 * XXXsk: we don't concern ourself with the byte order of the IAID,
341 *        which might be a problem if we transfer this structure
342 *        between machines of different byte order
343 */
344isc_result_t
345ia_allocate(struct ia_xx **ia, u_int32_t iaid,
346	    const char *duid, unsigned int duid_len,
347	    const char *file, int line) {
348	struct ia_xx *tmp;
349
350	if (ia == NULL) {
351		log_error("%s(%d): NULL pointer reference", file, line);
352		return DHCP_R_INVALIDARG;
353	}
354	if (*ia != NULL) {
355		log_error("%s(%d): non-NULL pointer", file, line);
356		return DHCP_R_INVALIDARG;
357	}
358
359	tmp = dmalloc(sizeof(*tmp), file, line);
360	if (tmp == NULL) {
361		return ISC_R_NOMEMORY;
362	}
363
364	if (ia_make_key(&tmp->iaid_duid, iaid,
365			duid, duid_len, file, line) != ISC_R_SUCCESS) {
366		dfree(tmp, file, line);
367		return ISC_R_NOMEMORY;
368	}
369
370	tmp->refcnt = 1;
371
372	*ia = tmp;
373	return ISC_R_SUCCESS;
374}
375
376/*
377 * Reference an IA structure.
378 *
379 * - ia must be a pointer to a (struct ia_xx *) pointer previously
380 *   initialized to NULL
381 */
382isc_result_t
383ia_reference(struct ia_xx **ia, struct ia_xx *src,
384	     const char *file, int line) {
385	if (ia == NULL) {
386		log_error("%s(%d): NULL pointer reference", file, line);
387		return DHCP_R_INVALIDARG;
388	}
389	if (*ia != NULL) {
390		log_error("%s(%d): non-NULL pointer", file, line);
391		return DHCP_R_INVALIDARG;
392	}
393	if (src == NULL) {
394		log_error("%s(%d): NULL pointer reference", file, line);
395		return DHCP_R_INVALIDARG;
396	}
397	*ia = src;
398	src->refcnt++;
399	return ISC_R_SUCCESS;
400}
401
402/*
403 * Dereference an IA structure.
404 *
405 * If it is the last reference, then the memory for the
406 * structure is freed.
407 */
408isc_result_t
409ia_dereference(struct ia_xx **ia, const char *file, int line) {
410	struct ia_xx *tmp;
411	int i;
412
413	if ((ia == NULL) || (*ia == NULL)) {
414		log_error("%s(%d): NULL pointer", file, line);
415		return DHCP_R_INVALIDARG;
416	}
417
418	tmp = *ia;
419	*ia = NULL;
420
421	tmp->refcnt--;
422	if (tmp->refcnt < 0) {
423		log_error("%s(%d): negative refcnt", file, line);
424		tmp->refcnt = 0;
425	}
426	if (tmp->refcnt == 0) {
427		if (tmp->iasubopt != NULL) {
428			for (i=0; i<tmp->num_iasubopt; i++) {
429				iasubopt_dereference(&(tmp->iasubopt[i]),
430						     file, line);
431			}
432			dfree(tmp->iasubopt, file, line);
433		}
434		data_string_forget(&(tmp->iaid_duid), file, line);
435		dfree(tmp, file, line);
436	}
437	return ISC_R_SUCCESS;
438}
439
440
441/*
442 * Add an IAADDR/PREFIX entry to an IA structure.
443 */
444isc_result_t
445ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
446		const char *file, int line) {
447	int max;
448	struct iasubopt **new;
449
450	/*
451	 * Grow our array if we need to.
452	 *
453	 * Note: we pick 4 as the increment, as that seems a reasonable
454	 *       guess as to how many addresses/prefixes we might expect
455	 *       on an interface.
456	 */
457	if (ia->max_iasubopt <= ia->num_iasubopt) {
458		max = ia->max_iasubopt + 4;
459		new = dmalloc(max * sizeof(struct iasubopt *), file, line);
460		if (new == NULL) {
461			return ISC_R_NOMEMORY;
462		}
463		memcpy(new, ia->iasubopt,
464		       ia->num_iasubopt * sizeof(struct iasubopt *));
465		ia->iasubopt = new;
466		ia->max_iasubopt = max;
467	}
468
469	iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt,
470			   file, line);
471	ia->num_iasubopt++;
472
473	return ISC_R_SUCCESS;
474}
475
476/*
477 * Remove an IAADDR/PREFIX entry to an IA structure.
478 *
479 * Note: if a suboption appears more than once, then only ONE will be removed.
480 */
481void
482ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
483		   const char *file, int line) {
484	int i, j;
485        if (ia == NULL || iasubopt == NULL)
486            return;
487
488	for (i=0; i<ia->num_iasubopt; i++) {
489		if (ia->iasubopt[i] == iasubopt) {
490			/* remove this sub option */
491			iasubopt_dereference(&(ia->iasubopt[i]), file, line);
492			/* move remaining suboption pointers down one */
493			for (j=i+1; j < ia->num_iasubopt; j++) {
494				ia->iasubopt[j-1] = ia->iasubopt[j];
495			}
496			/* decrease our total count */
497			/* remove the back-reference in the suboption itself */
498			ia_dereference(&iasubopt->ia, file, line);
499			ia->num_iasubopt--;
500			return;
501		}
502	}
503	log_error("%s(%d): IAADDR/PREFIX not in IA", file, line);
504}
505
506/*
507 * Remove all addresses/prefixes from an IA.
508 */
509void
510ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) {
511	int i;
512
513	for (i=0; i<ia->num_iasubopt; i++) {
514		ia_dereference(&(ia->iasubopt[i]->ia), file, line);
515		iasubopt_dereference(&(ia->iasubopt[i]), file, line);
516	}
517	ia->num_iasubopt = 0;
518}
519
520/*
521 * Compare two IA.
522 */
523isc_boolean_t
524ia_equal(const struct ia_xx *a, const struct ia_xx *b)
525{
526	isc_boolean_t found;
527	int i, j;
528
529	/*
530	 * Handle cases where one or both of the inputs is NULL.
531	 */
532	if (a == NULL) {
533		if (b == NULL) {
534			return ISC_TRUE;
535		} else {
536			return ISC_FALSE;
537		}
538	}
539
540	/*
541	 * Check the type is the same.
542	 */
543	if (a->ia_type != b->ia_type) {
544		return ISC_FALSE;
545	}
546
547	/*
548	 * Check the DUID is the same.
549	 */
550	if (a->iaid_duid.len != b->iaid_duid.len) {
551		return ISC_FALSE;
552	}
553	if (memcmp(a->iaid_duid.data,
554		   b->iaid_duid.data, a->iaid_duid.len) != 0) {
555		return ISC_FALSE;
556	}
557
558	/*
559	 * Make sure we have the same number of addresses/prefixes in each.
560	 */
561	if (a->num_iasubopt != b->num_iasubopt) {
562		return ISC_FALSE;
563	}
564
565	/*
566	 * Check that each address/prefix is present in both.
567	 */
568	for (i=0; i<a->num_iasubopt; i++) {
569		found = ISC_FALSE;
570		for (j=0; j<a->num_iasubopt; j++) {
571			if (a->iasubopt[i]->plen != b->iasubopt[i]->plen)
572				continue;
573			if (memcmp(&(a->iasubopt[i]->addr),
574			           &(b->iasubopt[j]->addr),
575				   sizeof(struct in6_addr)) == 0) {
576				found = ISC_TRUE;
577				break;
578			}
579		}
580		if (!found) {
581			return ISC_FALSE;
582		}
583	}
584
585	/*
586	 * These are the same in every way we care about.
587	 */
588	return ISC_TRUE;
589}
590
591/*
592 * Helper function for lease heaps.
593 * Makes the top of the heap the oldest lease.
594 */
595static isc_boolean_t
596lease_older(void *a, void *b) {
597	struct iasubopt *la = (struct iasubopt *)a;
598	struct iasubopt *lb = (struct iasubopt *)b;
599
600	if (la->hard_lifetime_end_time == lb->hard_lifetime_end_time) {
601		return difftime(la->soft_lifetime_end_time,
602				lb->soft_lifetime_end_time) < 0;
603	} else {
604		return difftime(la->hard_lifetime_end_time,
605				lb->hard_lifetime_end_time) < 0;
606	}
607}
608
609/*
610 * Helper functions for lease address/prefix heaps.
611 * Callback when an address's position in the heap changes.
612 */
613static void
614active_changed(void *iasubopt, unsigned int new_heap_index) {
615	((struct iasubopt *)iasubopt)->active_index = new_heap_index;
616}
617
618static void
619inactive_changed(void *iasubopt, unsigned int new_heap_index) {
620	((struct iasubopt *)iasubopt)->inactive_index = new_heap_index;
621}
622
623/*!
624 *
625 * \brief Create a new IPv6 lease pool structure
626 *
627 * Allocate space for a new ipv6_pool structure and return a reference
628 * to it, includes setting the reference count to 1.
629 *
630 * \param     pool       = space for returning a referenced pointer to the pool.
631 *			   This must point to a space that has been initialzied
632 *			   to NULL by the caller.
633 * \param[in] type       = The type of the pool NA, TA or PD
634 * \param[in] start_addr = The first address in the range for the pool
635 * \param[in] bits       = The contiguous bits of the pool
636
637 *
638 * \return
639 * ISC_R_SUCCESS     = The pool was successfully created, pool points to it.
640 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
641 *		       modified
642 * ISC_R_NOMEMORY    = The system wasn't able to allocate memory, pool has
643 *		       not been modified.
644 */
645isc_result_t
646ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
647		   const struct in6_addr *start_addr, int bits,
648		   int units, const char *file, int line) {
649	struct ipv6_pool *tmp;
650
651	if (pool == NULL) {
652		log_error("%s(%d): NULL pointer reference", file, line);
653		return DHCP_R_INVALIDARG;
654	}
655	if (*pool != NULL) {
656		log_error("%s(%d): non-NULL pointer", file, line);
657		return DHCP_R_INVALIDARG;
658	}
659
660	tmp = dmalloc(sizeof(*tmp), file, line);
661	if (tmp == NULL) {
662		return ISC_R_NOMEMORY;
663	}
664
665	tmp->refcnt = 1;
666	tmp->pool_type = type;
667	tmp->start_addr = *start_addr;
668	tmp->bits = bits;
669	tmp->units = units;
670	if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) {
671		dfree(tmp, file, line);
672		return ISC_R_NOMEMORY;
673	}
674	isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, active_changed,
675			0, &(tmp->active_timeouts));
676	isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, inactive_changed,
677			0, &(tmp->inactive_timeouts));
678
679	*pool = tmp;
680	return ISC_R_SUCCESS;
681}
682
683/*!
684 *
685 * \brief reference an IPv6 pool structure.
686 *
687 * This function genreates a reference to an ipv6_pool structure
688 * and increments the reference count on the structure.
689 *
690 * \param[out] pool = space for returning a referenced pointer to the pool.
691 *		      This must point to a space that has been initialzied
692 *		      to NULL by the caller.
693 * \param[in]  src  = A pointer to the pool to reference.  This must not be
694 *		      NULL.
695 *
696 * \return
697 * ISC_R_SUCCESS     = The pool was successfully referenced, pool now points
698 *		       to src.
699 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
700 *		       modified.
701 */
702isc_result_t
703ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
704		    const char *file, int line) {
705	if (pool == NULL) {
706		log_error("%s(%d): NULL pointer reference", file, line);
707		return DHCP_R_INVALIDARG;
708	}
709	if (*pool != NULL) {
710		log_error("%s(%d): non-NULL pointer", file, line);
711		return DHCP_R_INVALIDARG;
712	}
713	if (src == NULL) {
714		log_error("%s(%d): NULL pointer reference", file, line);
715		return DHCP_R_INVALIDARG;
716	}
717	*pool = src;
718	src->refcnt++;
719	return ISC_R_SUCCESS;
720}
721
722/*
723 * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
724 * to prevent the lease from being garbage collected out from under the
725 * pool.
726 *
727 * The references are made from the hash and from the heap. The following
728 * helper functions dereference these when a pool is destroyed.
729 */
730
731/*
732 * Helper function for pool cleanup.
733 * Dereference each of the hash entries in a pool.
734 */
735static isc_result_t
736dereference_hash_entry(const void *name, unsigned len, void *value) {
737	struct iasubopt *iasubopt = (struct iasubopt *)value;
738
739	iasubopt_dereference(&iasubopt, MDL);
740	return ISC_R_SUCCESS;
741}
742
743/*
744 * Helper function for pool cleanup.
745 * Dereference each of the heap entries in a pool.
746 */
747static void
748dereference_heap_entry(void *value, void *dummy) {
749	struct iasubopt *iasubopt = (struct iasubopt *)value;
750
751	iasubopt_dereference(&iasubopt, MDL);
752}
753
754/*!
755 *
756 * \brief de-reference an IPv6 pool structure.
757 *
758 * This function decrements the reference count in an ipv6_pool structure.
759 * If this was the last reference then the memory for the structure is
760 * freed.
761 *
762 * \param[in] pool = A pointer to the pointer to the pool that should be
763 *		     de-referenced.  On success the pointer to the pool
764 *		     is cleared.  It must not be NULL and must not point
765 *		     to NULL.
766 *
767 * \return
768 * ISC_R_SUCCESS     = The pool was successfully de-referenced, pool now points
769 *		       to NULL
770 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
771 *		       modified.
772 */
773isc_result_t
774ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
775	struct ipv6_pool *tmp;
776
777	if ((pool == NULL) || (*pool == NULL)) {
778		log_error("%s(%d): NULL pointer", file, line);
779		return DHCP_R_INVALIDARG;
780	}
781
782	tmp = *pool;
783	*pool = NULL;
784
785	tmp->refcnt--;
786	if (tmp->refcnt < 0) {
787		log_error("%s(%d): negative refcnt", file, line);
788		tmp->refcnt = 0;
789	}
790	if (tmp->refcnt == 0) {
791		iasubopt_hash_foreach(tmp->leases, dereference_hash_entry);
792		iasubopt_free_hash_table(&(tmp->leases), file, line);
793		isc_heap_foreach(tmp->active_timeouts,
794				 dereference_heap_entry, NULL);
795		isc_heap_destroy(&(tmp->active_timeouts));
796		isc_heap_foreach(tmp->inactive_timeouts,
797				 dereference_heap_entry, NULL);
798		isc_heap_destroy(&(tmp->inactive_timeouts));
799		dfree(tmp, file, line);
800	}
801
802	return ISC_R_SUCCESS;
803}
804
805/*
806 * Create an address by hashing the input, and using that for
807 * the non-network part.
808 */
809static void
810build_address6(struct in6_addr *addr,
811	       const struct in6_addr *net_start_addr, int net_bits,
812	       const struct data_string *input) {
813	int net_bytes;
814	int i;
815	unsigned int len;
816	char *str;
817	const char *net_str;
818
819	isc_md(ISC_MD_MD5, input->data, input->len, (void *)addr, &len);
820
821	/*
822	 * Copy the [0..128] network bits over.
823	 */
824	str = (char *)addr;
825	net_str = (const char *)net_start_addr;
826	net_bytes = net_bits / 8;
827	for (i = 0; i < net_bytes; i++) {
828		str[i] = net_str[i];
829	}
830	switch (net_bits % 8) {
831		case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
832		case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
833		case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
834		case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
835		case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
836		case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
837		case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
838	}
839
840	/*
841	 * Set the universal/local bit ("u bit") to zero for /64s.  The
842	 * individual/group bit ("g bit") is unchanged, because the g-bit
843	 * has no meaning when the u-bit is cleared.
844	 */
845	if (net_bits == 64)
846		str[8] &= ~0x02;
847}
848
849#ifdef EUI_64
850int
851valid_eui_64_duid(const struct data_string* uid, int offset) {
852	if (uid->len == (offset + EUI_64_ID_LEN)) {
853		const unsigned char* duid = uid->data + offset;
854		return (((duid[0] == 0x00 && duid[1] == 0x03)  &&
855			(duid[2] == 0x00 && duid[3] == 0x1b)));
856	}
857
858    return(0);
859}
860
861
862/*
863 * Create an EUI-64 address
864 */
865static isc_result_t
866build_address6_eui_64(struct in6_addr *addr,
867		      const struct in6_addr *net_start_addr, int net_bits,
868		      const struct data_string *iaid_duid, int duid_beg) {
869
870	if (net_bits != 64) {
871		log_error("build_address_eui_64: network is not 64 bits");
872		return (ISC_R_FAILURE);
873	}
874
875	if (valid_eui_64_duid(iaid_duid, duid_beg)) {
876		const unsigned char *duid = iaid_duid->data + duid_beg;
877
878		/* copy network prefix to the high 64 bits */
879		memcpy(addr->s6_addr, net_start_addr->s6_addr, 8);
880
881		/* copy Link-layer address to low 64 bits */
882		memcpy(addr->s6_addr + 8, duid + 4, 8);
883
884		/* RFC-3315 Any address assigned by a server that is based
885		 * on an EUI-64 identifier MUST include an interface identifier
886		 * with the "u" (universal/local) and "g" (individual/group)
887		 * bits of the interface identifier set appropriately, as
888		 * indicated in section 2.5.1 of RFC 2373 [5]. */
889		addr->s6_addr[8] |= 0x02;
890		return (ISC_R_SUCCESS);
891	}
892
893	log_error("build_address_eui_64: iaid_duid not a valid EUI-64: %s",
894		  print_hex_1(iaid_duid->len, iaid_duid->data, 60));
895	return (ISC_R_FAILURE);
896}
897
898int
899valid_for_eui_64_pool(struct ipv6_pool* pool, struct data_string* uid,
900		      int duid_beg, struct in6_addr* ia_addr) {
901        struct in6_addr test_addr;
902	/* If it's not an EUI-64 pool bail */
903        if (!pool->ipv6_pond->use_eui_64) {
904                return (0);
905        }
906
907        if (!valid_eui_64_duid(uid, duid_beg)) {
908                /* Dynamic lease in a now eui_64 pond, toss it*/
909                return (0);
910        }
911
912        /*  Call build_address6_eui_64() and compare it's result to
913	 *  this lease and see if they match. */
914        memset (&test_addr, 0, sizeof(test_addr));
915        build_address6_eui_64(&test_addr, &pool->start_addr, pool->bits,
916                              uid, duid_beg);
917
918        return (!memcmp(ia_addr, &test_addr, sizeof(test_addr)));
919}
920#endif
921
922
923/*
924 * Create a temporary address by a variant of RFC 4941 algo.
925 * Note: this should not be used for prefixes shorter than 64 bits.
926 */
927static void
928build_temporary6(struct in6_addr *addr,
929		 const struct in6_addr *net_start_addr, int net_bits,
930		 const struct data_string *input) {
931	static u_int32_t history[2];
932	static u_int32_t counter = 0;
933	unsigned char md[16] = {0};
934	unsigned int len;
935
936	/*
937	 * First time/time to reseed.
938	 * Please use a good pseudo-random generator here!
939	 */
940	if (counter == 0) {
941		history[0] = arc4random();
942		history[1] = arc4random();
943	}
944
945	/*
946	 * Use MD5 as recommended by RFC 4941.
947	 */
948	isc_md(ISC_MD_MD5, input->data, input->len, (void *)&history[0], &len);
949
950	/*
951	 * Build the address.
952	 */
953	if (net_bits == 64) {
954		memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8);
955		memcpy(&addr->s6_addr[8], md, 8);
956		addr->s6_addr[8] &= ~0x02;
957	} else {
958		int net_bytes;
959		int i;
960		char *str;
961		const char *net_str;
962
963		/*
964		 * Copy the [0..128] network bits over.
965		 */
966		str = (char *)addr;
967		net_str = (const char *)net_start_addr;
968		net_bytes = net_bits / 8;
969		for (i = 0; i < net_bytes; i++) {
970			str[i] = net_str[i];
971		}
972		memcpy(str + net_bytes, md, 16 - net_bytes);
973		switch (net_bits % 8) {
974		case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
975		case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
976		case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
977		case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
978		case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
979		case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
980		case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
981		}
982	}
983
984
985	/*
986	 * Save history for the next call.
987	 */
988	memcpy((unsigned char *)&history[0], md + 8, 8);
989	counter++;
990}
991
992/* Reserved Subnet Router Anycast ::0:0:0:0. */
993static struct in6_addr rtany;
994/* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
995static struct in6_addr resany;
996
997/*
998 * Create a lease for the given address and client duid.
999 *
1000 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1001 *   initialized to NULL
1002 *
1003 * Right now we simply hash the DUID, and if we get a collision, we hash
1004 * again until we find a free address. We try this a fixed number of times,
1005 * to avoid getting stuck in a loop (this is important on small pools
1006 * where we can run out of space).
1007 *
1008 * We return the number of attempts that it took to find an available
1009 * lease. This tells callers when a pool is are filling up, as
1010 * well as an indication of how full the pool is; statistically the
1011 * more full a pool is the more attempts must be made before finding
1012 * a free lease. Realistically this will only happen in very full
1013 * pools.
1014 *
1015 * We probably want different algorithms depending on the network size, in
1016 * the long term.
1017 */
1018isc_result_t
1019create_lease6(struct ipv6_pool *pool, struct iasubopt **addr,
1020	      unsigned int *attempts,
1021	      const struct data_string *uid, time_t soft_lifetime_end_time) {
1022	struct data_string ds;
1023	struct in6_addr tmp;
1024	struct iasubopt *test_iaaddr;
1025	struct data_string new_ds;
1026	struct iasubopt *iaaddr;
1027	isc_result_t result;
1028	isc_boolean_t reserved_iid;
1029	static isc_boolean_t init_resiid = ISC_FALSE;
1030
1031	/*
1032	 * Fill the reserved IIDs.
1033	 */
1034	if (!init_resiid) {
1035		memset(&rtany, 0, 16);
1036		memset(&resany, 0, 8);
1037		resany.s6_addr[8] = 0xfd;
1038		memset(&resany.s6_addr[9], 0xff, 6);
1039		init_resiid = ISC_TRUE;
1040	}
1041
1042	/*
1043	 * Use the UID as our initial seed for the hash
1044	 */
1045	memset(&ds, 0, sizeof(ds));
1046	data_string_copy(&ds, (struct data_string *)uid, MDL);
1047
1048	*attempts = 0;
1049	for (;;) {
1050		/*
1051		 * Give up at some point.
1052		 */
1053		if (++(*attempts) > 100) {
1054			data_string_forget(&ds, MDL);
1055			return ISC_R_NORESOURCES;
1056		}
1057
1058		/*
1059		 * Build a resource.
1060		 */
1061		switch (pool->pool_type) {
1062		case D6O_IA_NA:
1063			/* address */
1064			build_address6(&tmp, &pool->start_addr,
1065				       pool->bits, &ds);
1066			break;
1067		case D6O_IA_TA:
1068			/* temporary address */
1069			build_temporary6(&tmp, &pool->start_addr,
1070					 pool->bits, &ds);
1071			break;
1072		case D6O_IA_PD:
1073			/* prefix */
1074			log_error("create_lease6: prefix pool.");
1075			data_string_forget(&ds, MDL);
1076			return DHCP_R_INVALIDARG;
1077		default:
1078			log_error("create_lease6: untyped pool.");
1079			data_string_forget(&ds, MDL);
1080			return DHCP_R_INVALIDARG;
1081		}
1082
1083		/*
1084		 * Avoid reserved interface IDs. (cf. RFC 5453)
1085		 */
1086		reserved_iid = ISC_FALSE;
1087		if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
1088			reserved_iid = ISC_TRUE;
1089		}
1090		if (!reserved_iid &&
1091		    (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1092		    ((tmp.s6_addr[15] & 0x80) == 0x80)) {
1093			reserved_iid = ISC_TRUE;
1094		}
1095
1096		/*
1097		 * If this address is not in use, we're happy with it
1098		 */
1099		test_iaaddr = NULL;
1100		if (!reserved_iid &&
1101		    (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1102					  &tmp, sizeof(tmp), MDL) == 0)) {
1103			break;
1104		}
1105		if (test_iaaddr != NULL)
1106			iasubopt_dereference(&test_iaaddr, MDL);
1107
1108		/*
1109		 * Otherwise, we create a new input, adding the address
1110		 */
1111		memset(&new_ds, 0, sizeof(new_ds));
1112		new_ds.len = ds.len + sizeof(tmp);
1113		if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1114			data_string_forget(&ds, MDL);
1115			return ISC_R_NOMEMORY;
1116		}
1117		new_ds.data = new_ds.buffer->data;
1118		memcpy(new_ds.buffer->data, ds.data, ds.len);
1119		memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
1120		data_string_forget(&ds, MDL);
1121		data_string_copy(&ds, &new_ds, MDL);
1122		data_string_forget(&new_ds, MDL);
1123	}
1124
1125	data_string_forget(&ds, MDL);
1126
1127	/*
1128	 * We're happy with the address, create an IAADDR
1129	 * to hold it.
1130	 */
1131	iaaddr = NULL;
1132	result = iasubopt_allocate(&iaaddr, MDL);
1133	if (result != ISC_R_SUCCESS) {
1134		return result;
1135	}
1136	iaaddr->plen = 0;
1137	memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1138
1139	/*
1140	 * Add the lease to the pool (note state is free, not active?!).
1141	 */
1142	result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1143	if (result == ISC_R_SUCCESS) {
1144		iasubopt_reference(addr, iaaddr, MDL);
1145	}
1146	iasubopt_dereference(&iaaddr, MDL);
1147	return result;
1148}
1149
1150#ifdef EUI_64
1151/*!
1152 * \brief Assign an EUI-64 address from a pool for a given iaid-duid
1153 *
1154 *  \param pool - pool from which the address is assigned
1155 *  \param iaddr - pointer to the iasubopt to contain the assigned address is
1156 *  \param uid - data_string containing the iaid-duid tuple
1157 *  \param soft_lifetime_end_time - lifetime of the lease for a solicit?
1158 *
1159 *  \return status indicating success or nature of the failure
1160*/
1161isc_result_t
1162create_lease6_eui_64(struct ipv6_pool *pool, struct iasubopt **addr,
1163	      const struct data_string *uid,
1164	      time_t soft_lifetime_end_time) {
1165	struct in6_addr tmp;
1166	struct iasubopt *test_iaaddr;
1167	struct iasubopt *iaaddr;
1168	isc_result_t result;
1169	static isc_boolean_t init_resiid = ISC_FALSE;
1170
1171	/*  Fill the reserved IIDs.  */
1172	if (!init_resiid) {
1173		memset(&rtany, 0, 16);
1174		memset(&resany, 0, 8);
1175		resany.s6_addr[8] = 0xfd;
1176		memset(&resany.s6_addr[9], 0xff, 6);
1177		init_resiid = ISC_TRUE;
1178	}
1179
1180	/* Pool must be IA_NA */
1181	if (pool->pool_type != D6O_IA_NA) {
1182		log_error("create_lease6_eui_64: pool type is not IA_NA.");
1183		return (DHCP_R_INVALIDARG);
1184	}
1185
1186	/* Attempt to build the address */
1187	if (build_address6_eui_64 (&tmp, &pool->start_addr, pool->bits,
1188				   uid, IAID_LEN) != ISC_R_SUCCESS) {
1189		log_error("create_lease6_eui_64: build_address6_eui_64 failed");
1190		return (ISC_R_FAILURE);
1191	}
1192
1193	/* Avoid reserved interface IDs. (cf. RFC 5453) */
1194	if ((memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0)  ||
1195	    ((memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
1196	    ((tmp.s6_addr[15] & 0x80) == 0x80))) {
1197		log_error("create_lease6_eui_64: "
1198			  "address conflicts with reserved IID");
1199		return (ISC_R_FAILURE);
1200	}
1201
1202	/* If this address is not in use, we're happy with it */
1203	test_iaaddr = NULL;
1204	if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1205				  &tmp, sizeof(tmp), MDL) != 0) {
1206
1207		/* See if it's ours. Static leases won't have an ia */
1208		int ours = 0;
1209		if (!test_iaaddr->ia) {
1210			log_error("create_lease6_eui_64: "
1211				  "address  %s is assigned to static lease",
1212				  pin6_addr(&test_iaaddr->addr));
1213		} else {
1214			/* Not sure if this can actually happen */
1215			struct data_string* found = &test_iaaddr->ia->iaid_duid;
1216			ours = ((found->len == uid->len) &&
1217				(!memcmp(found->data, uid->data, uid->len)));
1218			log_error("create_lease6_eui_64: "
1219				  "address  %s belongs to %s",
1220				  pin6_addr(&test_iaaddr->addr),
1221				  print_hex_1(found->len, found->data, 60));
1222		}
1223
1224		iasubopt_dereference(&test_iaaddr, MDL);
1225		if (!ours) {
1226			/* Cant' use it */
1227			return (ISC_R_FAILURE);
1228		}
1229	}
1230
1231	/* We're happy with the address, create an IAADDR to hold it. */
1232	iaaddr = NULL;
1233	result = iasubopt_allocate(&iaaddr, MDL);
1234	if (result != ISC_R_SUCCESS) {
1235		log_error("create_lease6_eui_64: could not allocate iasubop");
1236		return result;
1237	}
1238	iaaddr->plen = 0;
1239	memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
1240
1241	/* Add the lease to the pool and the reply */
1242	result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
1243	if (result == ISC_R_SUCCESS) {
1244		iasubopt_reference(addr, iaaddr, MDL);
1245	}
1246
1247	iasubopt_dereference(&iaaddr, MDL);
1248	return result;
1249}
1250#endif
1251
1252/*!
1253 *
1254 * \brief Cleans up leases when reading from a lease file
1255 *
1256 * This function is only expected to be run when reading leases in from a file.
1257 * It checks to see if a lease already exists for the new leases's address.
1258 * We don't add expired leases to the structures when reading a lease file
1259 * which limits what can happen.  We have two variables the owners of the leases
1260 * being the same or different and the new lease being active or non-active:
1261 * Owners active
1262 * same   no     remove old lease and its connections
1263 * same   yes    nothing to do, other code will update the structures.
1264 * diff   no     nothing to do
1265 * diff   yes    this combination shouldn't happen, we should only have a
1266 *               single active lease per address at a time and that lease
1267 *               should move to non-active before any other lease can
1268 *               become active for that address.
1269 *               Currently we delete the previous lease and pass an error
1270 *               to the caller who should log an error.
1271 *
1272 * When we remove a lease we remove it from the hash table and active heap
1273 * (remember only active leases are in the structures at this time) for the
1274 * pool, and from the IA's array.  If, after we've removed the pointer from
1275 * IA's array to the lease, the IA has no more pointers we remove it from
1276 * the appropriate hash table as well.
1277 *
1278 * \param[in] ia_table = the hash table for the IA
1279 * \param[in] pool     = the pool to update
1280 * \param[in] lease    = the new lease we want to add
1281 * \param[in] ia       = the new ia we are building
1282 *
1283 * \return
1284 * ISC_R_SUCCESS = the incoming lease and any previous lease were in
1285 *                 an expected state - one of the first 3 options above.
1286 *                 If necessary the old lease was removed.
1287 * ISC_R_FAILURE = there is already an active lease for the address in
1288 *                 the incoming lease.  This shouldn't happen if it does
1289 *                 flag an error for the caller to log.
1290 */
1291
1292isc_result_t
1293cleanup_lease6(ia_hash_t *ia_table,
1294	       struct ipv6_pool *pool,
1295	       struct iasubopt *lease,
1296	       struct ia_xx *ia) {
1297
1298	struct iasubopt *test_iasubopt, *tmp_iasubopt;
1299	struct ia_xx *old_ia;
1300	isc_result_t status = ISC_R_SUCCESS;
1301
1302	test_iasubopt = NULL;
1303	old_ia = NULL;
1304
1305	/*
1306	 * Look up the address - if we don't find a lease
1307	 * we don't need to do anything.
1308	 */
1309	if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1310				 &lease->addr, sizeof(lease->addr),
1311				 MDL) == 0) {
1312		return (ISC_R_SUCCESS);
1313	}
1314
1315	if (test_iasubopt->ia == NULL) {
1316		/* no old ia, no work to do */
1317		iasubopt_dereference(&test_iasubopt, MDL);
1318		return (status);
1319	}
1320
1321	ia_reference(&old_ia, test_iasubopt->ia, MDL);
1322
1323	if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
1324	    (memcmp((unsigned char *)ia->iaid_duid.data,
1325		    (unsigned char *)old_ia->iaid_duid.data,
1326		    ia->iaid_duid.len) == 0)) {
1327		/* same IA */
1328		if ((lease->state == FTS_ACTIVE) ||
1329		    (lease->state == FTS_ABANDONED)) {
1330			/* still active, no need to delete */
1331			goto cleanup;
1332		}
1333	} else {
1334		/* different IA */
1335		if ((lease->state != FTS_ACTIVE) &&
1336		    (lease->state != FTS_ABANDONED)) {
1337			/* new lease isn't active, no work */
1338			goto cleanup;
1339		}
1340
1341		/*
1342		 * We appear to have two active leases, this shouldn't happen.
1343		 * Before a second lease can be set to active the first lease
1344		 * should be set to inactive (released, expired etc). For now
1345		 * delete the previous lease and indicate a failure to the
1346		 * caller so it can generate a warning.
1347		 * In the future we may try and determine which is the better
1348		 * lease to keep.
1349		 */
1350
1351		status = ISC_R_FAILURE;
1352	}
1353
1354	/*
1355	 * Remove the old lease from the active heap and from the hash table
1356	 * then remove the lease from the IA and clean up the IA if necessary.
1357	 */
1358	isc_heap_delete(pool->active_timeouts, test_iasubopt->active_index);
1359	pool->num_active--;
1360	if (pool->ipv6_pond)
1361		pool->ipv6_pond->num_active--;
1362
1363	if (lease->state == FTS_ABANDONED) {
1364		pool->num_abandoned--;
1365		if (pool->ipv6_pond)
1366			pool->ipv6_pond->num_abandoned--;
1367	}
1368
1369	iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1370			     sizeof(test_iasubopt->addr), MDL);
1371	ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
1372	if (old_ia->num_iasubopt <= 0) {
1373		ia_hash_delete(ia_table,
1374			       (unsigned char *)old_ia->iaid_duid.data,
1375			       old_ia->iaid_duid.len, MDL);
1376	}
1377
1378	/*
1379	 * We derefenrece the subopt here as we've just removed it from
1380	 * the hash table in the pool.  We need to make a copy as we
1381	 * need to derefernece it again later.
1382	 */
1383	tmp_iasubopt = test_iasubopt;
1384	iasubopt_dereference(&tmp_iasubopt, MDL);
1385
1386      cleanup:
1387	ia_dereference(&old_ia, MDL);
1388
1389	/*
1390	 * Clean up the reference, this is in addition to the deference
1391	 * above after removing the entry from the hash table
1392	 */
1393	iasubopt_dereference(&test_iasubopt, MDL);
1394
1395	return (status);
1396}
1397
1398/*
1399 * Put a lease in the pool directly. This is intended to be used when
1400 * loading leases from the file.
1401 */
1402isc_result_t
1403add_lease6(struct ipv6_pool *pool, struct iasubopt *lease,
1404	   time_t valid_lifetime_end_time) {
1405	struct iasubopt *test_iasubopt;
1406	struct iasubopt *tmp_iasubopt;
1407
1408	/* If a state was not assigned by the caller, assume active. */
1409	if (lease->state == 0)
1410		lease->state = FTS_ACTIVE;
1411
1412	ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
1413
1414	/*
1415	 * If this IAADDR/PREFIX is already in our structures, remove the
1416	 * old one.
1417	 */
1418	test_iasubopt = NULL;
1419	if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
1420				 &lease->addr, sizeof(lease->addr), MDL)) {
1421		/* XXX: we should probably ask the lease what heap it is on
1422		 * (as a consistency check).
1423		 * XXX: we should probably have one function to "put this lease
1424		 * on its heap" rather than doing these if's everywhere.  If
1425		 * you add more states to this list, don't.
1426		 */
1427		if ((test_iasubopt->state == FTS_ACTIVE) ||
1428		    (test_iasubopt->state == FTS_ABANDONED)) {
1429			isc_heap_delete(pool->active_timeouts,
1430					test_iasubopt->active_index);
1431			pool->num_active--;
1432			if (pool->ipv6_pond)
1433				pool->ipv6_pond->num_active--;
1434
1435			if (test_iasubopt->state == FTS_ABANDONED) {
1436				pool->num_abandoned--;
1437				if (pool->ipv6_pond)
1438					pool->ipv6_pond->num_abandoned--;
1439			}
1440		} else {
1441			isc_heap_delete(pool->inactive_timeouts,
1442					test_iasubopt->inactive_index);
1443			pool->num_inactive--;
1444		}
1445
1446		iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
1447				     sizeof(test_iasubopt->addr), MDL);
1448
1449		/*
1450		 * We're going to do a bit of evil trickery here.
1451		 *
1452		 * We need to dereference the entry once to remove our
1453		 * current reference (in test_iasubopt), and then one
1454		 * more time to remove the reference left when the
1455		 * address was added to the pool before.
1456		 */
1457		tmp_iasubopt = test_iasubopt;
1458		iasubopt_dereference(&test_iasubopt, MDL);
1459		iasubopt_dereference(&tmp_iasubopt, MDL);
1460	}
1461
1462	/*
1463	 * Add IAADDR/PREFIX to our structures.
1464	 */
1465	tmp_iasubopt = NULL;
1466	iasubopt_reference(&tmp_iasubopt, lease, MDL);
1467	if ((tmp_iasubopt->state == FTS_ACTIVE) ||
1468	    (tmp_iasubopt->state == FTS_ABANDONED)) {
1469		tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
1470		iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr,
1471				  sizeof(tmp_iasubopt->addr), lease, MDL);
1472		isc_heap_insert(pool->active_timeouts, tmp_iasubopt);
1473		pool->num_active++;
1474		if (pool->ipv6_pond)
1475			pool->ipv6_pond->num_active++;
1476
1477		if (tmp_iasubopt->state == FTS_ABANDONED) {
1478			pool->num_abandoned++;
1479			if (pool->ipv6_pond)
1480				pool->ipv6_pond->num_abandoned++;
1481		}
1482
1483	} else {
1484		tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
1485		isc_heap_insert(pool->inactive_timeouts, tmp_iasubopt);
1486		pool->num_inactive++;
1487	}
1488	iasubopt_hash_delete(pool->leases, &lease->addr,
1489			     sizeof(lease->addr), MDL);
1490	iasubopt_dereference(&tmp_iasubopt, MDL);
1491	/*
1492	 * Note: we intentionally leave tmp_iasubopt referenced; there
1493	 * is a reference in the heap/hash, after all.
1494	 */
1495
1496	return ISC_R_SUCCESS;
1497}
1498
1499/*
1500 * Determine if an address is present in a pool or not.
1501 */
1502isc_boolean_t
1503lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
1504	struct iasubopt *test_iaaddr;
1505
1506	test_iaaddr = NULL;
1507	if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
1508				 (void *)addr, sizeof(*addr), MDL)) {
1509		iasubopt_dereference(&test_iaaddr, MDL);
1510		return ISC_TRUE;
1511	} else {
1512		return ISC_FALSE;
1513	}
1514}
1515
1516/*!
1517 *
1518 * \brief Check if address is available to a lease
1519 *
1520 * Determine if the address in the lease is available to that
1521 * lease.  Either the address isn't in use or it is in use
1522 * but by that lease.
1523 *
1524 * \param[in] lease = lease to check
1525 *
1526 * \return
1527 * ISC_TRUE  = The lease is allowed to use that address
1528 * ISC_FALSE = The lease isn't allowed to use that address
1529 */
1530isc_boolean_t
1531lease6_usable(struct iasubopt *lease) {
1532	struct iasubopt *test_iaaddr;
1533	isc_boolean_t status = ISC_TRUE;
1534
1535	test_iaaddr = NULL;
1536	if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
1537				 (void *)&lease->addr,
1538				 sizeof(lease->addr), MDL)) {
1539		if (test_iaaddr != lease) {
1540			status = ISC_FALSE;
1541		}
1542		iasubopt_dereference(&test_iaaddr, MDL);
1543	}
1544
1545	return (status);
1546}
1547
1548/*
1549 * Put the lease on our active pool.
1550 */
1551static isc_result_t
1552move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
1553	isc_heap_insert(pool->active_timeouts, lease);
1554	iasubopt_hash_add(pool->leases, &lease->addr,
1555			  sizeof(lease->addr), lease, MDL);
1556	isc_heap_delete(pool->inactive_timeouts,
1557			lease->inactive_index);
1558	pool->num_active++;
1559	pool->num_inactive--;
1560	lease->state = FTS_ACTIVE;
1561	if (pool->ipv6_pond)
1562		pool->ipv6_pond->num_active++;
1563
1564	return ISC_R_SUCCESS;
1565}
1566
1567/*!
1568 *
1569 * \brief Renew a lease in the pool.
1570 *
1571 * The hard_lifetime_end_time of the lease should be set to
1572 * the current expiration time.
1573 * The soft_lifetime_end_time of the lease should be set to
1574 * the desired expiration time.
1575 *
1576 * This routine will compare the two and call the correct
1577 * heap routine to move the lease.  If the lease is active
1578 * and the new expiration time is greater (the normal case)
1579 * then we call isc_heap_decreased() as a larger time is a
1580 * lower priority.  If the new expiration time is less then
1581 * we call isc_heap_increased().
1582 *
1583 * If the lease is abandoned then it will be on the active list
1584 * and we will always call isc_heap_increased() as the previous
1585 * expiration would have been all 1s (as close as we can get
1586 * to infinite).
1587 *
1588 * If the lease is moving to active we call that routine
1589 * which will move it from the inactive list to the active list.
1590 *
1591 * \param pool  = a pool the lease belongs to
1592 * \param lease = the lease to be renewed
1593 *
1594 * \return result of the renew operation (ISC_R_SUCCESS if successful,
1595           ISC_R_NOMEMORY when run out of memory)
1596 */
1597isc_result_t
1598renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1599	time_t old_end_time = lease->hard_lifetime_end_time;
1600	lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
1601	lease->soft_lifetime_end_time = 0;
1602
1603	if (lease->state == FTS_ACTIVE) {
1604		if (old_end_time <= lease->hard_lifetime_end_time) {
1605			isc_heap_decreased(pool->active_timeouts,
1606					   lease->active_index);
1607		} else {
1608			isc_heap_increased(pool->active_timeouts,
1609					   lease->active_index);
1610		}
1611		return ISC_R_SUCCESS;
1612	} else if (lease->state == FTS_ABANDONED) {
1613		char tmp_addr[INET6_ADDRSTRLEN];
1614                lease->state = FTS_ACTIVE;
1615                isc_heap_increased(pool->active_timeouts, lease->active_index);
1616		log_info("Reclaiming previously abandoned address %s",
1617			 inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
1618				   sizeof(tmp_addr)));
1619
1620		pool->num_abandoned--;
1621		if (pool->ipv6_pond)
1622			pool->ipv6_pond->num_abandoned--;
1623
1624                return ISC_R_SUCCESS;
1625	} else {
1626		return move_lease_to_active(pool, lease);
1627	}
1628}
1629
1630/*
1631 * Put the lease on our inactive pool, with the specified state.
1632 */
1633static isc_result_t
1634move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
1635		       binding_state_t state) {
1636
1637	isc_heap_insert(pool->inactive_timeouts, lease);
1638	/*
1639	 * Handle expire and release statements
1640	 * To get here we must be active and have done a commit so
1641	 * we should run the proper statements if they exist, though
1642	 * that will change when we remove the inactive heap.
1643	 * In addition we get rid of the references for both as we
1644	 * can only do one (expire or release) on a lease
1645	 */
1646	if (lease->on_star.on_expiry != NULL) {
1647		if (state == FTS_EXPIRED) {
1648			execute_statements(NULL, NULL, NULL,
1649					   NULL, NULL, NULL,
1650					   &lease->scope,
1651					   lease->on_star.on_expiry,
1652					   &lease->on_star);
1653		}
1654		executable_statement_dereference
1655			(&lease->on_star.on_expiry, MDL);
1656	}
1657
1658	if (lease->on_star.on_release != NULL) {
1659		if (state == FTS_RELEASED) {
1660			execute_statements(NULL, NULL, NULL,
1661					   NULL, NULL, NULL,
1662					   &lease->scope,
1663					   lease->on_star.on_release,
1664					   &lease->on_star);
1665		}
1666		executable_statement_dereference
1667			(&lease->on_star.on_release, MDL);
1668	}
1669
1670#if defined (NSUPDATE)
1671	/* Process events upon expiration. */
1672	if (pool->pool_type != D6O_IA_PD) {
1673		(void) ddns_removals(NULL, lease, NULL, ISC_FALSE);
1674	}
1675#endif
1676
1677	/* Binding scopes are no longer valid after expiry or
1678	 * release.
1679	 */
1680	if (lease->scope != NULL) {
1681		binding_scope_dereference(&lease->scope, MDL);
1682	}
1683
1684	iasubopt_hash_delete(pool->leases,
1685			     &lease->addr, sizeof(lease->addr), MDL);
1686	isc_heap_delete(pool->active_timeouts, lease->active_index);
1687	lease->state = state;
1688	pool->num_active--;
1689	pool->num_inactive++;
1690	if (pool->ipv6_pond)
1691		pool->ipv6_pond->num_active--;
1692
1693	if (lease->state == FTS_ABANDONED) {
1694		pool->num_abandoned--;
1695		if (pool->ipv6_pond)
1696			pool->ipv6_pond->num_abandoned--;
1697	}
1698	return ISC_R_SUCCESS;
1699}
1700
1701/*
1702 * Expire the oldest lease if it's lifetime_end_time is
1703 * older than the given time.
1704 *
1705 * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1706 *   initialized to NULL
1707 *
1708 * On return leasep has a reference to the removed entry. It is left
1709 * pointing to NULL if the oldest lease has not expired.
1710 */
1711isc_result_t
1712expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
1713	struct iasubopt *tmp;
1714	isc_result_t result;
1715
1716	if (leasep == NULL) {
1717		log_error("%s(%d): NULL pointer reference", MDL);
1718		return DHCP_R_INVALIDARG;
1719	}
1720	if (*leasep != NULL) {
1721		log_error("%s(%d): non-NULL pointer", MDL);
1722		return DHCP_R_INVALIDARG;
1723	}
1724
1725	if (pool->num_active > 0) {
1726		tmp = (struct iasubopt *)
1727				isc_heap_element(pool->active_timeouts, 1);
1728		if (now > tmp->hard_lifetime_end_time) {
1729			result = move_lease_to_inactive(pool, tmp,
1730							FTS_EXPIRED);
1731			if (result == ISC_R_SUCCESS) {
1732				iasubopt_reference(leasep, tmp, MDL);
1733			}
1734			return result;
1735		}
1736	}
1737	return ISC_R_SUCCESS;
1738}
1739
1740
1741/*
1742 * For a declined lease, leave it on the "active" pool, but mark
1743 * it as declined. Give it an infinite (well, really long) life.
1744 */
1745isc_result_t
1746decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1747	isc_result_t result;
1748
1749	if ((lease->state != FTS_ACTIVE) &&
1750	    (lease->state != FTS_ABANDONED)) {
1751		result = move_lease_to_active(pool, lease);
1752		if (result != ISC_R_SUCCESS) {
1753			return result;
1754		}
1755	}
1756	lease->state = FTS_ABANDONED;
1757
1758	pool->num_abandoned++;
1759	if (pool->ipv6_pond)
1760		pool->ipv6_pond->num_abandoned++;
1761
1762	lease->hard_lifetime_end_time = MAX_TIME;
1763	isc_heap_decreased(pool->active_timeouts, lease->active_index);
1764	return ISC_R_SUCCESS;
1765}
1766
1767/*
1768 * Put the returned lease on our inactive pool.
1769 */
1770isc_result_t
1771release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
1772	if (lease->state == FTS_ACTIVE) {
1773		return move_lease_to_inactive(pool, lease, FTS_RELEASED);
1774	} else {
1775		return ISC_R_SUCCESS;
1776	}
1777}
1778
1779/*
1780 * Create a prefix by hashing the input, and using that for
1781 * the part subject to allocation.
1782 */
1783static void
1784build_prefix6(struct in6_addr *pref,
1785	      const struct in6_addr *net_start_pref,
1786	      int pool_bits, int pref_bits,
1787	      const struct data_string *input) {
1788	int net_bytes;
1789	int i;
1790	unsigned int len;
1791	char *str;
1792	const char *net_str;
1793
1794	/*
1795	 * Use MD5 to get a nice 128 bit hash of the input.
1796	 * Yes, we know MD5 isn't cryptographically sound.
1797	 * No, we don't care.
1798	 */
1799	isc_md(ISC_MD_MD5, input->data, input->len, (void *)&pref, &len);
1800
1801	/*
1802	 * Copy the network bits over.
1803	 */
1804	str = (char *)pref;
1805	net_str = (const char *)net_start_pref;
1806	net_bytes = pool_bits / 8;
1807	for (i = 0; i < net_bytes; i++) {
1808		str[i] = net_str[i];
1809	}
1810	i = net_bytes;
1811	switch (pool_bits % 8) {
1812		case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
1813		case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
1814		case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
1815		case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
1816		case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
1817		case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
1818		case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
1819	}
1820	/*
1821	 * Zero the remaining bits.
1822	 */
1823	net_bytes = pref_bits / 8;
1824	for (i=net_bytes+1; i<16; i++) {
1825		str[i] = 0;
1826	}
1827	i = net_bytes;
1828	switch (pref_bits % 8) {
1829		case 0: str[i] &= 0; break;
1830		case 1: str[i] &= 0x80; break;
1831		case 2: str[i] &= 0xC0; break;
1832		case 3: str[i] &= 0xE0; break;
1833		case 4: str[i] &= 0xF0; break;
1834		case 5: str[i] &= 0xF8; break;
1835		case 6: str[i] &= 0xFC; break;
1836		case 7: str[i] &= 0xFE; break;
1837	}
1838}
1839
1840/*
1841 * Create a lease for the given prefix and client duid.
1842 *
1843 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1844 *   initialized to NULL
1845 *
1846 * Right now we simply hash the DUID, and if we get a collision, we hash
1847 * again until we find a free prefix. We try this a fixed number of times,
1848 * to avoid getting stuck in a loop (this is important on small pools
1849 * where we can run out of space).
1850 *
1851 * We return the number of attempts that it took to find an available
1852 * prefix. This tells callers when a pool is are filling up, as
1853 * well as an indication of how full the pool is; statistically the
1854 * more full a pool is the more attempts must be made before finding
1855 * a free prefix. Realistically this will only happen in very full
1856 * pools.
1857 *
1858 * We probably want different algorithms depending on the network size, in
1859 * the long term.
1860 */
1861isc_result_t
1862create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref,
1863	       unsigned int *attempts,
1864	       const struct data_string *uid,
1865	       time_t soft_lifetime_end_time) {
1866	struct data_string ds;
1867	struct in6_addr tmp;
1868	struct iasubopt *test_iapref;
1869	struct data_string new_ds;
1870	struct iasubopt *iapref;
1871	isc_result_t result;
1872
1873	/*
1874	 * Use the UID as our initial seed for the hash
1875	 */
1876	memset(&ds, 0, sizeof(ds));
1877	data_string_copy(&ds, (struct data_string *)uid, MDL);
1878
1879	*attempts = 0;
1880	for (;;) {
1881		/*
1882		 * Give up at some point.
1883		 */
1884		if (++(*attempts) > 10) {
1885			data_string_forget(&ds, MDL);
1886			return ISC_R_NORESOURCES;
1887		}
1888
1889		/*
1890		 * Build a prefix
1891		 */
1892		build_prefix6(&tmp, &pool->start_addr,
1893			      pool->bits, pool->units, &ds);
1894
1895		/*
1896		 * If this prefix is not in use, we're happy with it
1897		 */
1898		test_iapref = NULL;
1899		if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1900					 &tmp, sizeof(tmp), MDL) == 0) {
1901			break;
1902		}
1903		iasubopt_dereference(&test_iapref, MDL);
1904
1905		/*
1906		 * Otherwise, we create a new input, adding the prefix
1907		 */
1908		memset(&new_ds, 0, sizeof(new_ds));
1909		new_ds.len = ds.len + sizeof(tmp);
1910		if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
1911			data_string_forget(&ds, MDL);
1912			return ISC_R_NOMEMORY;
1913		}
1914		new_ds.data = new_ds.buffer->data;
1915		memcpy(new_ds.buffer->data, ds.data, ds.len);
1916		memcpy(&new_ds.buffer->data[0] + ds.len, &tmp, sizeof(tmp));
1917		data_string_forget(&ds, MDL);
1918		data_string_copy(&ds, &new_ds, MDL);
1919		data_string_forget(&new_ds, MDL);
1920	}
1921
1922	data_string_forget(&ds, MDL);
1923
1924	/*
1925	 * We're happy with the prefix, create an IAPREFIX
1926	 * to hold it.
1927	 */
1928	iapref = NULL;
1929	result = iasubopt_allocate(&iapref, MDL);
1930	if (result != ISC_R_SUCCESS) {
1931		return result;
1932	}
1933	iapref->plen = (u_int8_t)pool->units;
1934	memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
1935
1936	/*
1937	 * Add the prefix to the pool (note state is free, not active?!).
1938	 */
1939	result = add_lease6(pool, iapref, soft_lifetime_end_time);
1940	if (result == ISC_R_SUCCESS) {
1941		iasubopt_reference(pref, iapref, MDL);
1942	}
1943	iasubopt_dereference(&iapref, MDL);
1944	return result;
1945}
1946
1947/*
1948 * Determine if a prefix is present in a pool or not.
1949 */
1950isc_boolean_t
1951prefix6_exists(const struct ipv6_pool *pool,
1952	       const struct in6_addr *pref, u_int8_t plen) {
1953	struct iasubopt *test_iapref;
1954
1955	if ((int)plen != pool->units)
1956		return ISC_FALSE;
1957
1958	test_iapref = NULL;
1959	if (iasubopt_hash_lookup(&test_iapref, pool->leases,
1960				 (void *)pref, sizeof(*pref), MDL)) {
1961		iasubopt_dereference(&test_iapref, MDL);
1962		return ISC_TRUE;
1963	} else {
1964		return ISC_FALSE;
1965	}
1966}
1967
1968/*
1969 * Mark an IPv6 address/prefix as unavailable from a pool.
1970 *
1971 * This is used for host entries and the addresses of the server itself.
1972 */
1973static isc_result_t
1974mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
1975	struct iasubopt *dummy_iasubopt;
1976	isc_result_t result;
1977
1978	dummy_iasubopt = NULL;
1979	result = iasubopt_allocate(&dummy_iasubopt, MDL);
1980	if (result == ISC_R_SUCCESS) {
1981		dummy_iasubopt->addr = *addr;
1982		iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
1983				  sizeof(*addr), dummy_iasubopt, MDL);
1984	}
1985	return result;
1986}
1987
1988/*
1989 * Add a pool.
1990 */
1991isc_result_t
1992add_ipv6_pool(struct ipv6_pool *pool) {
1993	struct ipv6_pool **new_pools;
1994
1995	new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
1996	if (new_pools == NULL) {
1997		return ISC_R_NOMEMORY;
1998	}
1999
2000	if (num_pools > 0) {
2001		memcpy(new_pools, pools,
2002		       sizeof(struct ipv6_pool *) * num_pools);
2003		dfree(pools, MDL);
2004	}
2005	pools = new_pools;
2006
2007	pools[num_pools] = NULL;
2008	ipv6_pool_reference(&pools[num_pools], pool, MDL);
2009	num_pools++;
2010	return ISC_R_SUCCESS;
2011}
2012
2013static void
2014cleanup_old_expired(struct ipv6_pool *pool) {
2015	struct iasubopt *tmp;
2016	struct ia_xx *ia;
2017	struct ia_xx *ia_active;
2018	unsigned char *tmpd;
2019	time_t timeout;
2020
2021	while (pool->num_inactive > 0) {
2022		tmp = (struct iasubopt *)
2023				isc_heap_element(pool->inactive_timeouts, 1);
2024		if (tmp->hard_lifetime_end_time != 0) {
2025			timeout = tmp->hard_lifetime_end_time;
2026			timeout += EXPIRED_IPV6_CLEANUP_TIME;
2027		} else {
2028			timeout = tmp->soft_lifetime_end_time;
2029		}
2030		if (cur_time < timeout) {
2031			break;
2032		}
2033
2034		isc_heap_delete(pool->inactive_timeouts, tmp->inactive_index);
2035		pool->num_inactive--;
2036
2037		if (tmp->ia != NULL) {
2038			/*
2039			 * Check to see if this IA is in an active list,
2040			 * but has no remaining resources. If so, remove it
2041			 * from the active list.
2042			 */
2043			ia = NULL;
2044			ia_reference(&ia, tmp->ia, MDL);
2045			ia_remove_iasubopt(ia, tmp, MDL);
2046			ia_active = NULL;
2047			tmpd = (unsigned char *)ia->iaid_duid.data;
2048			if ((ia->ia_type == D6O_IA_NA) &&
2049			    (ia->num_iasubopt <= 0) &&
2050			    (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
2051					    ia->iaid_duid.len, MDL) == 0) &&
2052			    (ia_active == ia)) {
2053				ia_hash_delete(ia_na_active, tmpd,
2054					       ia->iaid_duid.len, MDL);
2055			}
2056			if ((ia->ia_type == D6O_IA_TA) &&
2057			    (ia->num_iasubopt <= 0) &&
2058			    (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
2059					    ia->iaid_duid.len, MDL) == 0) &&
2060			    (ia_active == ia)) {
2061				ia_hash_delete(ia_ta_active, tmpd,
2062					       ia->iaid_duid.len, MDL);
2063			}
2064			if ((ia->ia_type == D6O_IA_PD) &&
2065			    (ia->num_iasubopt <= 0) &&
2066			    (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
2067					    ia->iaid_duid.len, MDL) == 0) &&
2068			    (ia_active == ia)) {
2069				ia_hash_delete(ia_pd_active, tmpd,
2070					       ia->iaid_duid.len, MDL);
2071			}
2072			ia_dereference(&ia, MDL);
2073		}
2074		iasubopt_dereference(&tmp, MDL);
2075	}
2076}
2077
2078static void
2079lease_timeout_support(void *vpool) {
2080	struct ipv6_pool *pool;
2081	struct iasubopt *lease;
2082
2083	pool = (struct ipv6_pool *)vpool;
2084	for (;;) {
2085		/*
2086		 * Get the next lease scheduled to expire.
2087		 *
2088		 * Note that if there are no leases in the pool,
2089		 * expire_lease6() will return ISC_R_SUCCESS with
2090		 * a NULL lease.
2091		 *
2092		 * expire_lease6() will call move_lease_to_inactive() which
2093		 * calls ddns_removals() do we want that on the standard
2094		 * expiration timer or a special 'depref' timer?  Original
2095		 * query from DH, moved here by SAR.
2096		 */
2097		lease = NULL;
2098		if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
2099			break;
2100		}
2101		if (lease == NULL) {
2102			break;
2103		}
2104
2105		write_ia(lease->ia);
2106
2107		iasubopt_dereference(&lease, MDL);
2108	}
2109
2110	/*
2111	 * If appropriate commit and rotate the lease file
2112	 * As commit_leases_timed() checks to see if we've done any writes
2113	 * we don't bother tracking if this function called write _ia
2114	 */
2115	(void) commit_leases_timed();
2116
2117	/*
2118	 * Do some cleanup of our expired leases.
2119	 */
2120	cleanup_old_expired(pool);
2121
2122	/*
2123	 * Schedule next round of expirations.
2124	 */
2125	schedule_lease_timeout(pool);
2126}
2127
2128/*
2129 * For a given pool, add a timer that will remove the next
2130 * lease to expire.
2131 */
2132void
2133schedule_lease_timeout(struct ipv6_pool *pool) {
2134	struct iasubopt *tmp;
2135	time_t timeout;
2136	time_t next_timeout;
2137	struct timeval tv;
2138
2139	next_timeout = MAX_TIME;
2140
2141	if (pool->num_active > 0) {
2142		tmp = (struct iasubopt *)
2143				isc_heap_element(pool->active_timeouts, 1);
2144		if (tmp->hard_lifetime_end_time < next_timeout) {
2145			next_timeout = tmp->hard_lifetime_end_time + 1;
2146		}
2147	}
2148
2149	if (pool->num_inactive > 0) {
2150		tmp = (struct iasubopt *)
2151				isc_heap_element(pool->inactive_timeouts, 1);
2152		if (tmp->hard_lifetime_end_time != 0) {
2153			timeout = tmp->hard_lifetime_end_time;
2154			timeout += EXPIRED_IPV6_CLEANUP_TIME;
2155		} else {
2156			timeout = tmp->soft_lifetime_end_time + 1;
2157		}
2158		if (timeout < next_timeout) {
2159			next_timeout = timeout;
2160		}
2161	}
2162
2163	if (next_timeout < MAX_TIME) {
2164		tv.tv_sec = next_timeout;
2165		tv.tv_usec = 0;
2166		add_timeout(&tv, lease_timeout_support, pool,
2167			    (tvref_t)ipv6_pool_reference,
2168			    (tvunref_t)ipv6_pool_dereference);
2169	}
2170}
2171
2172/*
2173 * Schedule timeouts across all pools.
2174 */
2175void
2176schedule_all_ipv6_lease_timeouts(void) {
2177	int i;
2178
2179	for (i=0; i<num_pools; i++) {
2180		schedule_lease_timeout(pools[i]);
2181	}
2182}
2183
2184/*
2185 * Given an address and the length of the network mask, return
2186 * only the network portion.
2187 *
2188 * Examples:
2189 *
2190 *   "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2191 *   "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2192 */
2193static void
2194ipv6_network_portion(struct in6_addr *result,
2195		     const struct in6_addr *addr, int bits) {
2196	unsigned char *addrp;
2197	int mask_bits;
2198	int bytes;
2199	int extra_bits;
2200	int i;
2201
2202	static const unsigned char bitmasks[] = {
2203		0x00, 0xFE, 0xFC, 0xF8,
2204		0xF0, 0xE0, 0xC0, 0x80,
2205	};
2206
2207	/*
2208	 *  Sanity check our bits. ;)
2209	 */
2210	if ((bits < 0) || (bits > 128)) {
2211		log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2212			  bits);
2213	}
2214
2215	/*
2216	 * Copy our address portion.
2217	 */
2218	*result = *addr;
2219	addrp = ((unsigned char *)result) + 15;
2220
2221	/*
2222	 * Zero out masked portion.
2223	 */
2224	mask_bits = 128 - bits;
2225	bytes = mask_bits / 8;
2226	extra_bits = mask_bits % 8;
2227
2228	for (i=0; i<bytes; i++) {
2229		*addrp = 0;
2230		addrp--;
2231	}
2232	if (extra_bits) {
2233		*addrp &= bitmasks[extra_bits];
2234	}
2235}
2236
2237/*
2238 * Determine if the given address/prefix is in the pool.
2239 */
2240isc_boolean_t
2241ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
2242	struct in6_addr tmp;
2243
2244	ipv6_network_portion(&tmp, addr, pool->bits);
2245	if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
2246		return ISC_TRUE;
2247	} else {
2248		return ISC_FALSE;
2249	}
2250}
2251
2252/*
2253 * Find the pool that contains the given address.
2254 *
2255 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2256 *   initialized to NULL
2257 */
2258isc_result_t
2259find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
2260	       const struct in6_addr *addr) {
2261	int i;
2262
2263	if (pool == NULL) {
2264		log_error("%s(%d): NULL pointer reference", MDL);
2265		return DHCP_R_INVALIDARG;
2266	}
2267	if (*pool != NULL) {
2268		log_error("%s(%d): non-NULL pointer", MDL);
2269		return DHCP_R_INVALIDARG;
2270	}
2271
2272	for (i=0; i<num_pools; i++) {
2273		if (pools[i]->pool_type != type)
2274			continue;
2275		if (ipv6_in_pool(addr, pools[i])) {
2276			ipv6_pool_reference(pool, pools[i], MDL);
2277			return ISC_R_SUCCESS;
2278		}
2279	}
2280	return ISC_R_NOTFOUND;
2281}
2282
2283/*
2284 * Helper function for the various functions that act across all
2285 * pools.
2286 */
2287static isc_result_t
2288change_leases(struct ia_xx *ia,
2289	      isc_result_t (*change_func)(struct ipv6_pool *,
2290					  struct iasubopt *)) {
2291	isc_result_t retval;
2292	isc_result_t renew_retval;
2293	struct ipv6_pool *pool;
2294	struct in6_addr *addr;
2295	int i;
2296
2297	retval = ISC_R_SUCCESS;
2298	for (i=0; i<ia->num_iasubopt; i++) {
2299		pool = NULL;
2300		addr = &ia->iasubopt[i]->addr;
2301		if (find_ipv6_pool(&pool, ia->ia_type,
2302				   addr) == ISC_R_SUCCESS) {
2303			renew_retval = change_func(pool, ia->iasubopt[i]);
2304			if (renew_retval != ISC_R_SUCCESS) {
2305				retval = renew_retval;
2306			}
2307		}
2308		/* XXXsk: should we warn if we don't find a pool? */
2309	}
2310	return retval;
2311}
2312
2313/*
2314 * Renew all leases in an IA from all pools.
2315 *
2316 * The new lifetime should be in the soft_lifetime_end_time
2317 * and will be moved to hard_lifetime_end_time by renew_lease6.
2318 */
2319isc_result_t
2320renew_leases(struct ia_xx *ia) {
2321	return change_leases(ia, renew_lease6);
2322}
2323
2324/*
2325 * Release all leases in an IA from all pools.
2326 */
2327isc_result_t
2328release_leases(struct ia_xx *ia) {
2329	return change_leases(ia, release_lease6);
2330}
2331
2332/*
2333 * Decline all leases in an IA from all pools.
2334 */
2335isc_result_t
2336decline_leases(struct ia_xx *ia) {
2337	return change_leases(ia, decline_lease6);
2338}
2339
2340#ifdef DHCPv6
2341/*
2342 * Helper function to output leases.
2343 */
2344static int write_error;
2345
2346static isc_result_t
2347write_ia_leases(const void *name, unsigned len, void *value) {
2348	struct ia_xx *ia = (struct ia_xx *)value;
2349
2350	if (!write_error) {
2351		if (!write_ia(ia)) {
2352			write_error = 1;
2353		}
2354	}
2355	return ISC_R_SUCCESS;
2356}
2357
2358/*
2359 * Write all DHCPv6 information.
2360 */
2361int
2362write_leases6(void) {
2363	int nas, tas, pds;
2364
2365	write_error = 0;
2366	write_server_duid();
2367	nas = ia_hash_foreach(ia_na_active, write_ia_leases);
2368	if (write_error) {
2369		return 0;
2370	}
2371	tas = ia_hash_foreach(ia_ta_active, write_ia_leases);
2372	if (write_error) {
2373		return 0;
2374	}
2375	pds = ia_hash_foreach(ia_pd_active, write_ia_leases);
2376	if (write_error) {
2377		return 0;
2378	}
2379
2380	log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2381		 nas, tas, pds);
2382	return 1;
2383}
2384#endif /* DHCPv6 */
2385
2386static isc_result_t
2387mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
2388	struct host_decl *h;
2389	struct data_string fixed_addr;
2390	struct in6_addr addr;
2391	struct ipv6_pool *p;
2392
2393	h = (struct host_decl *)value;
2394
2395	/*
2396	 * If the host has no address, we don't need to mark anything.
2397	 */
2398	if (h->fixed_addr == NULL) {
2399		return ISC_R_SUCCESS;
2400	}
2401
2402	/*
2403	 * Evaluate the fixed address.
2404	 */
2405	memset(&fixed_addr, 0, sizeof(fixed_addr));
2406	if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
2407				   &global_scope, h->fixed_addr, MDL)) {
2408		log_error("mark_hosts_unavailable: "
2409			  "error evaluating host address.");
2410		return ISC_R_SUCCESS;
2411	}
2412	if (fixed_addr.len != 16) {
2413		log_error("mark_hosts_unavailable: "
2414			  "host address is not 128 bits.");
2415		return ISC_R_SUCCESS;
2416	}
2417	memcpy(&addr, fixed_addr.data, 16);
2418	data_string_forget(&fixed_addr, MDL);
2419
2420	/*
2421	 * Find the pool holding this host, and mark the address.
2422	 * (I suppose it is arguably valid to have a host that does not
2423	 * sit in any pool.)
2424	 */
2425	p = NULL;
2426	if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
2427		mark_lease_unavailable(p, &addr);
2428		ipv6_pool_dereference(&p, MDL);
2429	}
2430	if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
2431		mark_lease_unavailable(p, &addr);
2432		ipv6_pool_dereference(&p, MDL);
2433	}
2434
2435	return ISC_R_SUCCESS;
2436}
2437
2438void
2439mark_hosts_unavailable(void) {
2440	hash_foreach(host_name_hash, mark_hosts_unavailable_support);
2441}
2442
2443static isc_result_t
2444mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
2445	struct host_decl *h;
2446	struct iaddrcidrnetlist *l;
2447	struct in6_addr pref;
2448	struct ipv6_pool *p;
2449
2450	h = (struct host_decl *)value;
2451
2452	/*
2453	 * If the host has no prefix, we don't need to mark anything.
2454	 */
2455	if (h->fixed_prefix == NULL) {
2456		return ISC_R_SUCCESS;
2457	}
2458
2459	/*
2460	 * Get the fixed prefixes.
2461	 */
2462	for (l = h->fixed_prefix; l != NULL; l = l->next) {
2463		if (l->cidrnet.lo_addr.len != 16) {
2464			continue;
2465		}
2466		memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
2467
2468		/*
2469		 * Find the pool holding this host, and mark the prefix.
2470		 * (I suppose it is arguably valid to have a host that does not
2471		 * sit in any pool.)
2472		 */
2473		p = NULL;
2474		if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
2475			continue;
2476		}
2477		if (l->cidrnet.bits != p->units) {
2478			ipv6_pool_dereference(&p, MDL);
2479			continue;
2480		}
2481		mark_lease_unavailable(p, &pref);
2482		ipv6_pool_dereference(&p, MDL);
2483	}
2484
2485	return ISC_R_SUCCESS;
2486}
2487
2488void
2489mark_phosts_unavailable(void) {
2490	hash_foreach(host_name_hash, mark_phosts_unavailable_support);
2491}
2492
2493void
2494mark_interfaces_unavailable(void) {
2495	struct interface_info *ip;
2496	int i;
2497	struct ipv6_pool *p;
2498
2499	ip = interfaces;
2500	while (ip != NULL) {
2501		for (i=0; i<ip->v6address_count; i++) {
2502			p = NULL;
2503			if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i])
2504							== ISC_R_SUCCESS) {
2505				mark_lease_unavailable(p,
2506						       &ip->v6addresses[i]);
2507				ipv6_pool_dereference(&p, MDL);
2508			}
2509			if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i])
2510							== ISC_R_SUCCESS) {
2511				mark_lease_unavailable(p,
2512						       &ip->v6addresses[i]);
2513				ipv6_pool_dereference(&p, MDL);
2514			}
2515		}
2516		ip = ip->next;
2517	}
2518}
2519
2520/*!
2521 * \brief Create a new IPv6 pond structure.
2522 *
2523 * Allocate space for a new ipv6_pond structure and return a reference
2524 * to it, includes setting the reference count to 1.
2525 *
2526 * \param pond = space for returning a referenced pointer to the pond.
2527 *		 This must point to a space that has been initialzied
2528 *		 to NULL by the caller.
2529 *
2530 * \return
2531 * ISC_R_SUCCESS     = The pond was successfully created, pond points to it.
2532 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2533 *		       modified
2534 * ISC_R_NOMEMORY    = The system wasn't able to allocate memory, pond has
2535 *		       not been modified.
2536 */
2537isc_result_t
2538ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
2539	struct ipv6_pond *tmp;
2540
2541	if (pond == NULL) {
2542		log_error("%s(%d): NULL pointer reference", file, line);
2543		return DHCP_R_INVALIDARG;
2544	}
2545	if (*pond != NULL) {
2546		log_error("%s(%d): non-NULL pointer", file, line);
2547		return DHCP_R_INVALIDARG;
2548	}
2549
2550	tmp = dmalloc(sizeof(*tmp), file, line);
2551	if (tmp == NULL) {
2552		return ISC_R_NOMEMORY;
2553	}
2554
2555	tmp->refcnt = 1;
2556
2557	*pond = tmp;
2558	return ISC_R_SUCCESS;
2559}
2560
2561/*!
2562 *
2563 * \brief reference an IPv6 pond structure.
2564 *
2565 * This function genreates a reference to an ipv6_pond structure
2566 * and increments the reference count on the structure.
2567 *
2568 * \param[out] pond = space for returning a referenced pointer to the pond.
2569 *		      This must point to a space that has been initialzied
2570 *		      to NULL by the caller.
2571 * \param[in]  src  = A pointer to the pond to reference.  This must not be
2572 *		      NULL.
2573 *
2574 * \return
2575 * ISC_R_SUCCESS     = The pond was successfully referenced, pond now points
2576 *		       to src.
2577 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2578 *		       modified.
2579 */
2580isc_result_t
2581ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
2582		    const char *file, int line) {
2583	if (pond == NULL) {
2584		log_error("%s(%d): NULL pointer reference", file, line);
2585		return DHCP_R_INVALIDARG;
2586	}
2587	if (*pond != NULL) {
2588		log_error("%s(%d): non-NULL pointer", file, line);
2589		return DHCP_R_INVALIDARG;
2590	}
2591	if (src == NULL) {
2592		log_error("%s(%d): NULL pointer reference", file, line);
2593		return DHCP_R_INVALIDARG;
2594	}
2595	*pond = src;
2596	src->refcnt++;
2597	return ISC_R_SUCCESS;
2598}
2599
2600/*!
2601 *
2602 * \brief de-reference an IPv6 pond structure.
2603 *
2604 * This function decrements the reference count in an ipv6_pond structure.
2605 * If this was the last reference then the memory for the structure is
2606 * freed.
2607 *
2608 * \param[in] pond = A pointer to the pointer to the pond that should be
2609 *		     de-referenced.  On success the pointer to the pond
2610 *		     is cleared.  It must not be NULL and must not point
2611 *		     to NULL.
2612 *
2613 * \return
2614 * ISC_R_SUCCESS     = The pond was successfully de-referenced, pond now points
2615 *		       to NULL
2616 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2617 *		       modified.
2618 */
2619
2620isc_result_t
2621ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
2622	struct ipv6_pond *tmp;
2623
2624	if ((pond == NULL) || (*pond == NULL)) {
2625		log_error("%s(%d): NULL pointer", file, line);
2626		return DHCP_R_INVALIDARG;
2627	}
2628
2629	tmp = *pond;
2630	*pond = NULL;
2631
2632	tmp->refcnt--;
2633	if (tmp->refcnt < 0) {
2634		log_error("%s(%d): negative refcnt", file, line);
2635		tmp->refcnt = 0;
2636	}
2637	if (tmp->refcnt == 0) {
2638		dfree(tmp, file, line);
2639	}
2640
2641	return ISC_R_SUCCESS;
2642}
2643
2644#ifdef EUI_64
2645/*
2646 * Enables/disables EUI-64 address assignment for a pond
2647 *
2648 * Excecutes statements down to the pond's scope and sets the pond's
2649 * use_eui_64 flag accordingly. In addition it iterates over the
2650 * pond's pools ensuring they are all /64.  Anything else is deemed
2651 * invalid for EUI-64.  It returns the number of invalid pools
2652 * detected.  This is done post-parsing as use-eui-64 can be set
2653 * down to the pool scope and we can't reliably do it until the
2654 * entire configuration has been parsed.
2655 */
2656int
2657set_eui_64(struct ipv6_pond *pond) {
2658	int invalid_cnt = 0;
2659	struct option_state* options = NULL;
2660	struct option_cache *oc = NULL;
2661	option_state_allocate(&options, MDL);
2662	execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, options,
2663				    &global_scope, pond->group, NULL, NULL);
2664
2665	pond->use_eui_64 =
2666		((oc = lookup_option(&server_universe, options, SV_USE_EUI_64))
2667		 &&
2668		 (evaluate_boolean_option_cache (NULL, NULL, NULL, NULL,
2669						 options, NULL, &global_scope,
2670						 oc, MDL)));
2671	if (pond->use_eui_64) {
2672		// Check all pools are valid
2673		int i = 0;
2674		struct ipv6_pool* p;
2675		while((p = pond->ipv6_pools[i++]) != NULL) {
2676			if (p->bits != 64) {
2677				log_error("Pool %s/%d cannot use EUI-64,"
2678					  " prefix must 64",
2679					  pin6_addr(&p->start_addr), p->bits);
2680				invalid_cnt++;
2681			} else {
2682				log_debug("Pool: %s/%d - will use EUI-64",
2683					  pin6_addr(&p->start_addr), p->bits);
2684			}
2685		}
2686	}
2687
2688        /* Don't need the options anymore. */
2689        option_state_dereference(&options, MDL);
2690	return (invalid_cnt);
2691}
2692#endif
2693
2694/*
2695 * Emits a log for each pond that has been flagged as being a "jumbo range"
2696 * A pond is considered a "jumbo range" when the total number of elements
2697 * exceeds the maximum value of POND_TRACK_MAX (currently maximum value
2698 * that can be stored by ipv6_pond.num_total).  Since we disable threshold
2699 * logging for jumbo ranges, we need to report this to the user.  This
2700 * function allows us to report jumbo ponds after config parsing, so the
2701 * logs can be seen both on the console (-T) and the log facility (i.e syslog).
2702 *
2703 * Note, threshold logging is done at the pond level, so we need emit a list
2704 * of the addresses ranges of the pools in the pond affected.
2705 */
2706void
2707report_jumbo_ranges() {
2708	struct shared_network* s;
2709	char log_buf[1084];
2710#ifdef EUI_64
2711	int invalid_cnt = 0;
2712#endif
2713
2714	/* Loop thru all the networks looking for jumbo range ponds */
2715	for (s = shared_networks; s; s = s -> next) {
2716		struct ipv6_pond* pond = s->ipv6_pond;
2717		while (pond) {
2718#ifdef EUI_64
2719			/* while we're here, set the pond's use_eui_64 flag */
2720			invalid_cnt += set_eui_64(pond);
2721#endif
2722			/* if its a jumbo and has pools(sanity check) */
2723			if (pond->jumbo_range == 1 && (pond->ipv6_pools)) {
2724				struct ipv6_pool* pool;
2725				char *bufptr = log_buf;
2726				size_t space_left = sizeof(log_buf) - 1;
2727				int i = 0;
2728				int used = 0;
2729
2730				/* Build list containing the start-address/CIDR
2731				 * of each pool */
2732				*bufptr = '\0';
2733				while ((pool = pond->ipv6_pools[i++]) &&
2734				        (space_left > (INET6_ADDRSTRLEN + 6))) {
2735					/* more than one so add a comma */
2736					if (i > 1) {
2737						*bufptr++ = ',';
2738						*bufptr++ = ' ';
2739						*bufptr = '\0';
2740						space_left -= 2;
2741					}
2742
2743					/* add the address */
2744					inet_ntop(AF_INET6, &pool->start_addr,
2745						  bufptr, INET6_ADDRSTRLEN);
2746
2747					used = strlen(bufptr);
2748					bufptr += used;
2749					space_left -= used;
2750
2751					/* add the CIDR */
2752					sprintf (bufptr, "/%d",pool->bits);
2753					used = strlen(bufptr);
2754					bufptr += used;
2755					space_left -= used;
2756					*bufptr = '\0';
2757				}
2758
2759				log_info("Threshold logging disabled for shared"
2760					 " subnet of ranges: %s", log_buf);
2761			}
2762			pond = pond->next;
2763		}
2764
2765	}
2766
2767#ifdef EUI_64
2768	if (invalid_cnt) {
2769		log_fatal ("%d pool(s) are invalid for EUI-64 use",
2770			   invalid_cnt);
2771	}
2772#endif
2773}
2774
2775
2776/*
2777 * \brief Tests that 16-bit hardware type is less than 256
2778 *
2779 * XXX: DHCPv6 gives a 16-bit field for the htype.  DHCPv4 gives an
2780 * 8-bit field.  To change the semantics of the generic 'hardware'
2781 * structure, we would have to adjust many DHCPv4 sources (from
2782 * interface to DHCPv4 lease code), and we would have to update the
2783 * 'hardware' config directive (probably being reverse compatible and
2784 * providing a new upgrade/replacement primitive).  This is a little
2785 * too much to change for now.  Hopefully we will revisit this before
2786 * hardware types exceeding 8 bits are assigned.
2787 *
2788 * Uses a static variable to limit log occurence to once per startup
2789 *
2790 * \param htype hardware type value to test
2791 *
2792 * \return returns 0 if the value is too large
2793 *
2794*/
2795static int
2796htype_bounds_check(uint16_t htype) {
2797	static int log_once = 0;
2798
2799	if (htype & 0xFF00) {
2800		if (!log_once) {
2801			log_error("Attention: At least one client advertises a "
2802			  "hardware type of %d, which exceeds the software "
2803			  "limitation of 255.", htype);
2804			log_once = 1;
2805		}
2806
2807		return(0);
2808	}
2809
2810	return(1);
2811}
2812
2813/*!
2814 * \brief Look for hosts by MAC address if it's available
2815 *
2816 * Checks the inbound packet against host declarations which specified:
2817 *
2818 *      "hardware ethernet <MAC>;"
2819 *
2820 * For directly connected clients, the function will use the MAC address
2821 * contained in packet:haddr if it's populated.  \TODO - While the logic is in
2822 * place for this search, the socket layer does not yet populate packet:haddr,
2823 * this is to be done under rt41523.
2824 *
2825 * For relayed clients, the function will use the MAC address from the
2826 * client-linklayer-address option if it has been supplied by the relay
2827 * directly connected to the client.
2828 *
2829 * \param hp[out] - pointer to storage for the host delcaration if found
2830 * \param packet - received packet
2831 * \param opt_state - option state to search
2832 * \param file - source file
2833 * \param line - line number
2834 *
2835 * \return non-zero if a matching host was found, zero otherwise
2836*/
2837static int
2838find_hosts_by_haddr6(struct host_decl **hp,
2839			 struct packet *packet,
2840			 struct option_state *opt_state,
2841			 const char *file, int line) {
2842	int found = 0;
2843	int htype;
2844	int hlen;
2845
2846	/* For directly connected clients, use packet:haddr if populated */
2847	if (packet->dhcpv6_container_packet == NULL) {
2848		if (packet->haddr) {
2849			htype = packet->haddr->hbuf[0];
2850			hlen = packet->haddr->hlen - 1,
2851			log_debug("find_hosts_by_haddr6: using packet->haddr,"
2852				  " type: %d, len: %d", htype, hlen);
2853			found = find_hosts_by_haddr (hp, htype,
2854						     &packet->haddr->hbuf[1],
2855						     hlen, MDL);
2856		}
2857	} else {
2858		/* The first container packet is the from the relay directly
2859		 * connected to the client. Per RFC 6939, that is only relay
2860		 * that may supply the client linklayer address option. */
2861		struct packet *relay_packet = packet->dhcpv6_container_packet;
2862		struct option_state *relay_state = relay_packet->options;
2863		struct data_string rel_addr;
2864		struct option_cache *oc;
2865
2866		/* Look for the option in the first relay packet */
2867		oc = lookup_option(&dhcpv6_universe, relay_state,
2868				   D6O_CLIENT_LINKLAYER_ADDR);
2869		if (!oc) {
2870			/* Not there, so bail */
2871			return (0);
2872		}
2873
2874		/* The option is present, fetch the address data */
2875		memset(&rel_addr, 0, sizeof(rel_addr));
2876		if (!evaluate_option_cache(&rel_addr, relay_packet, NULL, NULL,
2877					   relay_state, NULL, &global_scope,
2878					   oc, MDL)) {
2879			log_error("find_hosts_by_add6:"
2880				  "Error evaluating option cache");
2881			return (0);
2882		}
2883
2884		/* The relay address data should be:
2885		 *   byte 0 - 1 = hardware type
2886		 *   bytes 2 - hlen = hardware address
2887                 * where  hlen ( hardware address len) is option data len - 2 */
2888		hlen = rel_addr.len - 2;
2889		if (hlen > 0 && hlen <= HARDWARE_ADDR_LEN) {
2890			htype = getUShort(rel_addr.data);
2891			if (htype_bounds_check(htype)) {
2892				/* Looks valid, let's search with it */
2893				log_debug("find_hosts_by_haddr6:"
2894					  "using relayed haddr"
2895					  " type: %d, len: %d", htype, hlen);
2896				found = find_hosts_by_haddr (hp, htype,
2897							     &rel_addr.data[2],
2898							     hlen, MDL);
2899			}
2900		}
2901
2902		data_string_forget(&rel_addr, MDL);
2903        }
2904
2905	return (found);
2906}
2907
2908/*
2909 * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware'
2910 * parameter from a DHCPv6 supplied DUID (client-identifier option),
2911 * and may seek to use client or relay supplied hardware addresses.
2912 */
2913static int
2914find_hosts_by_duid_chaddr(struct host_decl **host,
2915			  const struct data_string *client_id) {
2916	int htype, hlen;
2917	const unsigned char *chaddr;
2918
2919	/*
2920	 * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte
2921	 * htype.
2922	 */
2923	if (client_id->len < 4)
2924		return 0;
2925
2926	/*
2927	 * The third and fourth octets of the DUID-LL and DUID-LLT
2928	 * is the hardware type, but in 16 bits.
2929	 */
2930	htype = getUShort(client_id->data + 2);
2931	hlen = 0;
2932	chaddr = NULL;
2933
2934	/* The first two octets of the DUID identify the type. */
2935	switch(getUShort(client_id->data)) {
2936	      case DUID_LLT:
2937		if (client_id->len > 8) {
2938			hlen = client_id->len - 8;
2939			chaddr = client_id->data + 8;
2940		}
2941		break;
2942
2943	      case DUID_LL:
2944		/*
2945		 * Note that client_id->len must be greater than or equal
2946		 * to four to get to this point in the function.
2947		 */
2948		hlen = client_id->len - 4;
2949		chaddr = client_id->data + 4;
2950		break;
2951
2952	      default:
2953		break;
2954	}
2955
2956	if ((hlen == 0) || (hlen > HARDWARE_ADDR_LEN) ||
2957	    !htype_bounds_check(htype)) {
2958		return (0);
2959	}
2960
2961	return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL);
2962}
2963
2964/*
2965 * \brief Finds a host record that matches the packet, if any
2966 *
2967 * This function centralizes the logic for matching v6 client
2968 * packets to host declarations.  We check in the following order
2969 * for matches with:
2970 *
2971 * 1. client_id if specified
2972 * 2. MAC address when explicitly available
2973 * 3. packet option
2974 * 4. synthesized hardware address - this is done last as some
2975 * synthesis methods are not consided to be reliable
2976 *
2977 * \param[out] host - pointer to storage for the located host
2978 * \param packet - inbound client packet
2979 * \param client_id - client identifier (if one)
2980 * \param file - source file
2981 * \param line - source file line number
2982 * \return non-zero if a host is found, zero otherwise
2983*/
2984int
2985find_hosts6(struct host_decl** host, struct packet* packet,
2986            const struct data_string* client_id, char* file, int line) {
2987        return (find_hosts_by_uid(host, client_id->data, client_id->len, MDL)
2988                || find_hosts_by_haddr6(host, packet, packet->options, MDL)
2989                || find_hosts_by_option(host, packet, packet->options, MDL)
2990                || find_hosts_by_duid_chaddr(host, client_id));
2991}
2992
2993/* unittest moved to server/tests/mdb6_unittest.c */
2994