1 /* $NetBSD: mdb6.c,v 1.5 2014/07/12 12:09:38 spz Exp $ */
3 * Copyright (C) 2007-2013 by Internet Systems Consortium, Inc. ("ISC")
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/cdefs.h>
19 __RCSID("$NetBSD: mdb6.c,v 1.5 2014/07/12 12:09:38 spz Exp $");
23 * \todo simplify functions, as pool is now in iaaddr
26 /*! \file server/mdb6.c
28 * \page ipv6structures IPv6 Structures Overview
30 * A brief description of the IPv6 structures as reverse engineered.
32 * There are four major data structures in the lease configuraion.
34 * - shared_network - The shared network is the outer enclosing scope for a
35 * network region that shares a broadcast domain. It is
36 * composed of one or more subnets all of which are valid
37 * in the given region. The share network may be
38 * explicitly defined or implicitly created if there is
39 * only a subnet statement. This structrure is shared
40 * with v4. Each shared network statment or naked subnet
41 * will map to one of these structures
43 * - subnet - The subnet structure mostly specifies the address range
44 * that could be valid in a given region. This structute
45 * doesn't include the addresses that the server can delegate
46 * those are in the ipv6_pool. This structure is also shared
47 * with v4. Each subnet statement will map to one of these
50 * - ipv6_pond - The pond structure is a grouping of the address and prefix
51 * information via the pointers to the ipv6_pool and the
52 * allowability of this pool for given clinets via the permit
53 * lists and the valid TIMEs. This is equivilent to the v4
54 * pool structure and would have been named ip6_pool except
55 * that the name was already in use. Generally each pool6
56 * statement will map to one of these structures. In addition
57 * there may be one or for each group of naked range6 and
58 * prefix6 statements within a shared network that share
59 * the same group of statements.
61 * - ipv6_pool - this contains information about a pool of addresses or prefixes
62 * that the server is using. This includes a hash table that
63 * tracks the active items and a pair of heap tables one for
64 * active items and one for non-active items. The heap tables
65 * are used to determine the next items to be modified due to
66 * timing events (expire mostly).
68 * The linkages then look like this:
70 *+--------------+ +-------------+
71 *|Shared Network| | ipv6_pond |
77 *| Subnets | | pools |
78 *+-----|--------+ +------|------+
94 * | +---------- shared |
99 * The shared network contains a list of all the subnets that are on a broadcast
100 * doamin. These can be used to determine if an address makes sense in a given
101 * domain, but the subnets do not contain the addresses the server can delegate.
102 * Those are stored in the ponds and pools.
104 * In the simple case to find an acceptable address the server would first find
105 * the shared network the client is on based on either the interface used to
106 * receive the request or the relay agent's information. From the shared
107 * network the server will walk through it's list of ponds. For each pond it
108 * will evaluate the permit information against the (already done) classification.
109 * If it finds an acceptable pond it will then walk through the pools for that
110 * pond. The server first checks the type of the pool (NA, TA and PD) agaisnt the
111 * request and if they match it attemps to find an address within that pool. On
112 * success the address is used, on failure the server steps to the next pool and
113 * if necessary to the next pond.
115 * When the server is successful in finding an address it will execute any
116 * statements assocaited with the pond, then the subnet, then the shared
117 * network the group field is for in the above picture).
119 * In configurations that don't include either a shared network or a pool6
120 * statement (or both) the missing pieces are created.
123 * There are three major data structuress involved in the lease database:
125 * - ipv6_pool - see above
126 * - ia_xx - this contains information about a single IA from a request
127 * normally it will contain one pointer to a lease for the client
128 * but it may contain more in some circumstances. There are 3
129 * hash tables to aid in accessing these one each for NA, TA and PD.
130 * - iasubopt - the v6 lease structure. These are created dynamically when
131 * a client asks for something and will eventually be destroyed
132 * if the client doesn't re-ask for that item. A lease has space
133 * for backpointers to the IA and to the pool to which it belongs.
134 * The pool backpointer is always filled, the IA pointer may not be.
136 * In normal use we then have something like this:
140 * ia_na_active +----------------+
141 * ia_ta_active +------------+ | pool |
142 * ia_pd_active | iasubopt |<--| active hash |
143 * +-----------------+ | aka lease |<--| active heap |
144 * | ia_xx | | pool ptr |-->| |
145 * | iasubopt array |<---| iaptr |<--| inactive heap |
146 * | lease ptr |--->| | | |
147 * +-----------------+ +------------+ +----------------+
150 * For the pool either the inactive heap will have a pointer
151 * or both the active heap and the active hash will have pointers.
153 * I think there are several major items to notice. The first is
154 * that as a lease moves around it will be added to and removed
155 * from the address hash table in the pool and between the active
156 * and inactive hash tables. The hash table and the active heap
157 * are used when the lease is either active or abandoned. The
158 * inactive heap is used for all other states. In particular a
159 * lease that has expired or been released will be cleaned
160 * (DDNS removal etc) and then moved to the inactive heap. After
161 * some time period (currently 1 hour) it will be freed.
163 * The second is that when a client requests specific addresses,
164 * either because it previously owned them or if the server supplied
165 * them as part of a solicit, the server will try to lookup the ia_xx
166 * associated with the client and find the addresses there. If it
167 * does find appropriate leases it moves them from the old IA to
168 * a new IA and eventually replaces the old IA with the new IA
169 * in the IA hash tables.
174 #include <sys/types.h>
176 #include <netinet/in.h>
180 #include "omapip/omapip.h"
181 #include "omapip/hash.h"
184 HASH_FUNCTIONS(ia
, unsigned char *, struct ia_xx
, ia_hash_t
,
185 ia_reference
, ia_dereference
, do_string_hash
)
187 ia_hash_t
*ia_na_active
;
188 ia_hash_t
*ia_ta_active
;
189 ia_hash_t
*ia_pd_active
;
191 HASH_FUNCTIONS(iasubopt
, struct in6_addr
*, struct iasubopt
, iasubopt_hash_t
,
192 iasubopt_reference
, iasubopt_dereference
, do_string_hash
)
194 struct ipv6_pool
**pools
;
198 * Create a new IAADDR/PREFIX structure.
200 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
201 * initialized to NULL
204 iasubopt_allocate(struct iasubopt
**iasubopt
, const char *file
, int line
) {
205 struct iasubopt
*tmp
;
207 if (iasubopt
== NULL
) {
208 log_error("%s(%d): NULL pointer reference", file
, line
);
209 return DHCP_R_INVALIDARG
;
211 if (*iasubopt
!= NULL
) {
212 log_error("%s(%d): non-NULL pointer", file
, line
);
213 return DHCP_R_INVALIDARG
;
216 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
218 return ISC_R_NOMEMORY
;
222 tmp
->state
= FTS_FREE
;
223 tmp
->heap_index
= -1;
227 return ISC_R_SUCCESS
;
231 * Reference an IAADDR/PREFIX structure.
233 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
234 * initialized to NULL
237 iasubopt_reference(struct iasubopt
**iasubopt
, struct iasubopt
*src
,
238 const char *file
, int line
) {
239 if (iasubopt
== NULL
) {
240 log_error("%s(%d): NULL pointer reference", file
, line
);
241 return DHCP_R_INVALIDARG
;
243 if (*iasubopt
!= NULL
) {
244 log_error("%s(%d): non-NULL pointer", file
, line
);
245 return DHCP_R_INVALIDARG
;
248 log_error("%s(%d): NULL pointer reference", file
, line
);
249 return DHCP_R_INVALIDARG
;
253 return ISC_R_SUCCESS
;
258 * Dereference an IAADDR/PREFIX structure.
260 * If it is the last reference, then the memory for the
261 * structure is freed.
264 iasubopt_dereference(struct iasubopt
**iasubopt
, const char *file
, int line
) {
265 struct iasubopt
*tmp
;
267 if ((iasubopt
== NULL
) || (*iasubopt
== NULL
)) {
268 log_error("%s(%d): NULL pointer", file
, line
);
269 return DHCP_R_INVALIDARG
;
276 if (tmp
->refcnt
< 0) {
277 log_error("%s(%d): negative refcnt", file
, line
);
280 if (tmp
->refcnt
== 0) {
281 if (tmp
->ia
!= NULL
) {
282 ia_dereference(&(tmp
->ia
), file
, line
);
284 if (tmp
->ipv6_pool
!= NULL
) {
285 ipv6_pool_dereference(&(tmp
->ipv6_pool
), file
, line
);
287 if (tmp
->scope
!= NULL
) {
288 binding_scope_dereference(&tmp
->scope
, file
, line
);
291 if (tmp
->on_star
.on_expiry
!= NULL
) {
292 executable_statement_dereference
293 (&tmp
->on_star
.on_expiry
, MDL
);
295 if (tmp
->on_star
.on_commit
!= NULL
) {
296 executable_statement_dereference
297 (&tmp
->on_star
.on_commit
, MDL
);
299 if (tmp
->on_star
.on_release
!= NULL
) {
300 executable_statement_dereference
301 (&tmp
->on_star
.on_release
, MDL
);
304 dfree(tmp
, file
, line
);
307 return ISC_R_SUCCESS
;
311 * Make the key that we use for IA.
314 ia_make_key(struct data_string
*key
, u_int32_t iaid
,
315 const char *duid
, unsigned int duid_len
,
316 const char *file
, int line
) {
318 memset(key
, 0, sizeof(*key
));
319 key
->len
= duid_len
+ sizeof(iaid
);
320 if (!buffer_allocate(&(key
->buffer
), key
->len
, file
, line
)) {
321 return ISC_R_NOMEMORY
;
323 key
->data
= key
->buffer
->data
;
324 memcpy((char *)key
->data
, &iaid
, sizeof(iaid
));
325 memcpy((char *)key
->data
+ sizeof(iaid
), duid
, duid_len
);
327 return ISC_R_SUCCESS
;
331 * Create a new IA structure.
333 * - ia must be a pointer to a (struct ia_xx *) pointer previously
334 * initialized to NULL
335 * - iaid and duid are values from the client
337 * XXXsk: we don't concern ourself with the byte order of the IAID,
338 * which might be a problem if we transfer this structure
339 * between machines of different byte order
342 ia_allocate(struct ia_xx
**ia
, u_int32_t iaid
,
343 const char *duid
, unsigned int duid_len
,
344 const char *file
, int line
) {
348 log_error("%s(%d): NULL pointer reference", file
, line
);
349 return DHCP_R_INVALIDARG
;
352 log_error("%s(%d): non-NULL pointer", file
, line
);
353 return DHCP_R_INVALIDARG
;
356 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
358 return ISC_R_NOMEMORY
;
361 if (ia_make_key(&tmp
->iaid_duid
, iaid
,
362 duid
, duid_len
, file
, line
) != ISC_R_SUCCESS
) {
363 dfree(tmp
, file
, line
);
364 return ISC_R_NOMEMORY
;
370 return ISC_R_SUCCESS
;
374 * Reference an IA structure.
376 * - ia must be a pointer to a (struct ia_xx *) pointer previously
377 * initialized to NULL
380 ia_reference(struct ia_xx
**ia
, struct ia_xx
*src
,
381 const char *file
, int line
) {
383 log_error("%s(%d): NULL pointer reference", file
, line
);
384 return DHCP_R_INVALIDARG
;
387 log_error("%s(%d): non-NULL pointer", file
, line
);
388 return DHCP_R_INVALIDARG
;
391 log_error("%s(%d): NULL pointer reference", file
, line
);
392 return DHCP_R_INVALIDARG
;
396 return ISC_R_SUCCESS
;
400 * Dereference an IA structure.
402 * If it is the last reference, then the memory for the
403 * structure is freed.
406 ia_dereference(struct ia_xx
**ia
, const char *file
, int line
) {
410 if ((ia
== NULL
) || (*ia
== NULL
)) {
411 log_error("%s(%d): NULL pointer", file
, line
);
412 return DHCP_R_INVALIDARG
;
419 if (tmp
->refcnt
< 0) {
420 log_error("%s(%d): negative refcnt", file
, line
);
423 if (tmp
->refcnt
== 0) {
424 if (tmp
->iasubopt
!= NULL
) {
425 for (i
=0; i
<tmp
->num_iasubopt
; i
++) {
426 iasubopt_dereference(&(tmp
->iasubopt
[i
]),
429 dfree(tmp
->iasubopt
, file
, line
);
431 data_string_forget(&(tmp
->iaid_duid
), file
, line
);
432 dfree(tmp
, file
, line
);
434 return ISC_R_SUCCESS
;
439 * Add an IAADDR/PREFIX entry to an IA structure.
442 ia_add_iasubopt(struct ia_xx
*ia
, struct iasubopt
*iasubopt
,
443 const char *file
, int line
) {
445 struct iasubopt
**new;
448 * Grow our array if we need to.
450 * Note: we pick 4 as the increment, as that seems a reasonable
451 * guess as to how many addresses/prefixes we might expect
454 if (ia
->max_iasubopt
<= ia
->num_iasubopt
) {
455 max
= ia
->max_iasubopt
+ 4;
456 new = dmalloc(max
* sizeof(struct iasubopt
*), file
, line
);
458 return ISC_R_NOMEMORY
;
460 memcpy(new, ia
->iasubopt
,
461 ia
->num_iasubopt
* sizeof(struct iasubopt
*));
463 ia
->max_iasubopt
= max
;
466 iasubopt_reference(&(ia
->iasubopt
[ia
->num_iasubopt
]), iasubopt
,
470 return ISC_R_SUCCESS
;
474 * Remove an IAADDR/PREFIX entry to an IA structure.
476 * Note: if a suboption appears more than once, then only ONE will be removed.
479 ia_remove_iasubopt(struct ia_xx
*ia
, struct iasubopt
*iasubopt
,
480 const char *file
, int line
) {
482 if (ia
== NULL
|| iasubopt
== NULL
)
485 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
486 if (ia
->iasubopt
[i
] == iasubopt
) {
487 /* remove this sub option */
488 iasubopt_dereference(&(ia
->iasubopt
[i
]), file
, line
);
489 /* move remaining suboption pointers down one */
490 for (j
=i
+1; j
< ia
->num_iasubopt
; j
++) {
491 ia
->iasubopt
[j
-1] = ia
->iasubopt
[j
];
493 /* decrease our total count */
494 /* remove the back-reference in the suboption itself */
495 ia_dereference(&iasubopt
->ia
, file
, line
);
500 log_error("%s(%d): IAADDR/PREFIX not in IA", file
, line
);
504 * Remove all addresses/prefixes from an IA.
507 ia_remove_all_lease(struct ia_xx
*ia
, const char *file
, int line
) {
510 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
511 ia_dereference(&(ia
->iasubopt
[i
]->ia
), file
, line
);
512 iasubopt_dereference(&(ia
->iasubopt
[i
]), file
, line
);
514 ia
->num_iasubopt
= 0;
521 ia_equal(const struct ia_xx
*a
, const struct ia_xx
*b
)
527 * Handle cases where one or both of the inputs is NULL.
538 * Check the type is the same.
540 if (a
->ia_type
!= b
->ia_type
) {
545 * Check the DUID is the same.
547 if (a
->iaid_duid
.len
!= b
->iaid_duid
.len
) {
550 if (memcmp(a
->iaid_duid
.data
,
551 b
->iaid_duid
.data
, a
->iaid_duid
.len
) != 0) {
556 * Make sure we have the same number of addresses/prefixes in each.
558 if (a
->num_iasubopt
!= b
->num_iasubopt
) {
563 * Check that each address/prefix is present in both.
565 for (i
=0; i
<a
->num_iasubopt
; i
++) {
567 for (j
=0; j
<a
->num_iasubopt
; j
++) {
568 if (a
->iasubopt
[i
]->plen
!= b
->iasubopt
[i
]->plen
)
570 if (memcmp(&(a
->iasubopt
[i
]->addr
),
571 &(b
->iasubopt
[j
]->addr
),
572 sizeof(struct in6_addr
)) == 0) {
583 * These are the same in every way we care about.
589 * Helper function for lease heaps.
590 * Makes the top of the heap the oldest lease.
593 lease_older(void *a
, void *b
) {
594 struct iasubopt
*la
= (struct iasubopt
*)a
;
595 struct iasubopt
*lb
= (struct iasubopt
*)b
;
597 if (la
->hard_lifetime_end_time
== lb
->hard_lifetime_end_time
) {
598 return difftime(la
->soft_lifetime_end_time
,
599 lb
->soft_lifetime_end_time
) < 0;
601 return difftime(la
->hard_lifetime_end_time
,
602 lb
->hard_lifetime_end_time
) < 0;
607 * Helper function for lease address/prefix heaps.
608 * Callback when an address's position in the heap changes.
611 lease_index_changed(void *iasubopt
, unsigned int new_heap_index
) {
612 ((struct iasubopt
*)iasubopt
)-> heap_index
= new_heap_index
;
618 * \brief Create a new IPv6 lease pool structure
620 * Allocate space for a new ipv6_pool structure and return a reference
621 * to it, includes setting the reference count to 1.
623 * \param pool = space for returning a referenced pointer to the pool.
624 * This must point to a space that has been initialzied
625 * to NULL by the caller.
626 * \param[in] type = The type of the pool NA, TA or PD
627 * \param[in] start_addr = The first address in the range for the pool
628 * \param[in] bits = The contiguous bits of the pool
632 * ISC_R_SUCCESS = The pool was successfully created, pool points to it.
633 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
635 * ISC_R_NOMEMORY = The system wasn't able to allocate memory, pool has
639 ipv6_pool_allocate(struct ipv6_pool
**pool
, u_int16_t type
,
640 const struct in6_addr
*start_addr
, int bits
,
641 int units
, const char *file
, int line
) {
642 struct ipv6_pool
*tmp
;
645 log_error("%s(%d): NULL pointer reference", file
, line
);
646 return DHCP_R_INVALIDARG
;
649 log_error("%s(%d): non-NULL pointer", file
, line
);
650 return DHCP_R_INVALIDARG
;
653 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
655 return ISC_R_NOMEMORY
;
659 tmp
->pool_type
= type
;
660 tmp
->start_addr
= *start_addr
;
663 if (!iasubopt_new_hash(&tmp
->leases
, DEFAULT_HASH_SIZE
, file
, line
)) {
664 dfree(tmp
, file
, line
);
665 return ISC_R_NOMEMORY
;
667 if (isc_heap_create(dhcp_gbl_ctx
.mctx
, lease_older
, lease_index_changed
,
668 0, &(tmp
->active_timeouts
)) != ISC_R_SUCCESS
) {
669 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
670 dfree(tmp
, file
, line
);
671 return ISC_R_NOMEMORY
;
673 if (isc_heap_create(dhcp_gbl_ctx
.mctx
, lease_older
, lease_index_changed
,
674 0, &(tmp
->inactive_timeouts
)) != ISC_R_SUCCESS
) {
675 isc_heap_destroy(&(tmp
->active_timeouts
));
676 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
677 dfree(tmp
, file
, line
);
678 return ISC_R_NOMEMORY
;
682 return ISC_R_SUCCESS
;
687 * \brief reference an IPv6 pool structure.
689 * This function genreates a reference to an ipv6_pool structure
690 * and increments the reference count on the structure.
692 * \param[out] pool = space for returning a referenced pointer to the pool.
693 * This must point to a space that has been initialzied
694 * to NULL by the caller.
695 * \param[in] src = A pointer to the pool to reference. This must not be
699 * ISC_R_SUCCESS = The pool was successfully referenced, pool now points
701 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
705 ipv6_pool_reference(struct ipv6_pool
**pool
, struct ipv6_pool
*src
,
706 const char *file
, int line
) {
708 log_error("%s(%d): NULL pointer reference", file
, line
);
709 return DHCP_R_INVALIDARG
;
712 log_error("%s(%d): non-NULL pointer", file
, line
);
713 return DHCP_R_INVALIDARG
;
716 log_error("%s(%d): NULL pointer reference", file
, line
);
717 return DHCP_R_INVALIDARG
;
721 return ISC_R_SUCCESS
;
725 * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
726 * to prevent the lease from being garbage collected out from under the
729 * The references are made from the hash and from the heap. The following
730 * helper functions dereference these when a pool is destroyed.
734 * Helper function for pool cleanup.
735 * Dereference each of the hash entries in a pool.
738 dereference_hash_entry(const void *name
, unsigned len
, void *value
) {
739 struct iasubopt
*iasubopt
= (struct iasubopt
*)value
;
741 iasubopt_dereference(&iasubopt
, MDL
);
742 return ISC_R_SUCCESS
;
746 * Helper function for pool cleanup.
747 * Dereference each of the heap entries in a pool.
750 dereference_heap_entry(void *value
, void *dummy
) {
751 struct iasubopt
*iasubopt
= (struct iasubopt
*)value
;
753 iasubopt_dereference(&iasubopt
, MDL
);
758 * \brief de-reference an IPv6 pool structure.
760 * This function decrements the reference count in an ipv6_pool structure.
761 * If this was the last reference then the memory for the structure is
764 * \param[in] pool = A pointer to the pointer to the pool that should be
765 * de-referenced. On success the pointer to the pool
766 * is cleared. It must not be NULL and must not point
770 * ISC_R_SUCCESS = The pool was successfully de-referenced, pool now points
772 * DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
776 ipv6_pool_dereference(struct ipv6_pool
**pool
, const char *file
, int line
) {
777 struct ipv6_pool
*tmp
;
779 if ((pool
== NULL
) || (*pool
== NULL
)) {
780 log_error("%s(%d): NULL pointer", file
, line
);
781 return DHCP_R_INVALIDARG
;
788 if (tmp
->refcnt
< 0) {
789 log_error("%s(%d): negative refcnt", file
, line
);
792 if (tmp
->refcnt
== 0) {
793 iasubopt_hash_foreach(tmp
->leases
, dereference_hash_entry
);
794 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
795 isc_heap_foreach(tmp
->active_timeouts
,
796 dereference_heap_entry
, NULL
);
797 isc_heap_destroy(&(tmp
->active_timeouts
));
798 isc_heap_foreach(tmp
->inactive_timeouts
,
799 dereference_heap_entry
, NULL
);
800 isc_heap_destroy(&(tmp
->inactive_timeouts
));
801 dfree(tmp
, file
, line
);
804 return ISC_R_SUCCESS
;
808 * Create an address by hashing the input, and using that for
809 * the non-network part.
812 build_address6(struct in6_addr
*addr
,
813 const struct in6_addr
*net_start_addr
, int net_bits
,
814 const struct data_string
*input
) {
822 * Use MD5 to get a nice 128 bit hash of the input.
823 * Yes, we know MD5 isn't cryptographically sound.
827 isc_md5_update(&ctx
, input
->data
, input
->len
);
828 isc_md5_final(&ctx
, (unsigned char *)addr
);
831 * Copy the [0..128] network bits over.
834 net_str
= (const char *)net_start_addr
;
835 net_bytes
= net_bits
/ 8;
836 for (i
= 0; i
< net_bytes
; i
++) {
839 switch (net_bits
% 8) {
840 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
841 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
842 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
843 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
844 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
845 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
846 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
850 * Set the universal/local bit ("u bit") to zero for /64s. The
851 * individual/group bit ("g bit") is unchanged, because the g-bit
852 * has no meaning when the u-bit is cleared.
859 * Create a temporary address by a variant of RFC 4941 algo.
860 * Note: this should not be used for prefixes shorter than 64 bits.
863 build_temporary6(struct in6_addr
*addr
,
864 const struct in6_addr
*net_start_addr
, int net_bits
,
865 const struct data_string
*input
) {
866 static u_int32_t history
[2];
867 static u_int32_t counter
= 0;
869 unsigned char md
[16];
872 * First time/time to reseed.
873 * Please use a good pseudo-random generator here!
876 isc_random_get(&history
[0]);
877 isc_random_get(&history
[1]);
881 * Use MD5 as recommended by RFC 4941.
884 isc_md5_update(&ctx
, (unsigned char *)&history
[0], 8UL);
885 isc_md5_update(&ctx
, input
->data
, input
->len
);
886 isc_md5_final(&ctx
, md
);
891 if (net_bits
== 64) {
892 memcpy(&addr
->s6_addr
[0], &net_start_addr
->s6_addr
[0], 8);
893 memcpy(&addr
->s6_addr
[8], md
, 8);
894 addr
->s6_addr
[8] &= ~0x02;
902 * Copy the [0..128] network bits over.
905 net_str
= (const char *)net_start_addr
;
906 net_bytes
= net_bits
/ 8;
907 for (i
= 0; i
< net_bytes
; i
++) {
910 memcpy(str
+ net_bytes
, md
, 16 - net_bytes
);
911 switch (net_bits
% 8) {
912 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
913 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
914 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
915 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
916 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
917 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
918 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
924 * Save history for the next call.
926 memcpy((unsigned char *)&history
[0], md
+ 8, 8);
930 /* Reserved Subnet Router Anycast ::0:0:0:0. */
931 static struct in6_addr rtany
;
932 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
933 static struct in6_addr resany
;
936 * Create a lease for the given address and client duid.
938 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
939 * initialized to NULL
941 * Right now we simply hash the DUID, and if we get a collision, we hash
942 * again until we find a free address. We try this a fixed number of times,
943 * to avoid getting stuck in a loop (this is important on small pools
944 * where we can run out of space).
946 * We return the number of attempts that it took to find an available
947 * lease. This tells callers when a pool is are filling up, as
948 * well as an indication of how full the pool is; statistically the
949 * more full a pool is the more attempts must be made before finding
950 * a free lease. Realistically this will only happen in very full
953 * We probably want different algorithms depending on the network size, in
957 create_lease6(struct ipv6_pool
*pool
, struct iasubopt
**addr
,
958 unsigned int *attempts
,
959 const struct data_string
*uid
, time_t soft_lifetime_end_time
) {
960 struct data_string ds
;
962 struct iasubopt
*test_iaaddr
;
963 struct data_string new_ds
;
964 struct iasubopt
*iaaddr
;
966 isc_boolean_t reserved_iid
;
967 static isc_boolean_t init_resiid
= ISC_FALSE
;
970 * Fill the reserved IIDs.
973 memset(&rtany
, 0, 16);
974 memset(&resany
, 0, 8);
975 resany
.s6_addr
[8] = 0xfd;
976 memset(&resany
.s6_addr
[9], 0xff, 6);
977 init_resiid
= ISC_TRUE
;
981 * Use the UID as our initial seed for the hash
983 memset(&ds
, 0, sizeof(ds
));
984 data_string_copy(&ds
, (struct data_string
*)uid
, MDL
);
989 * Give up at some point.
991 if (++(*attempts
) > 100) {
992 data_string_forget(&ds
, MDL
);
993 return ISC_R_NORESOURCES
;
999 switch (pool
->pool_type
) {
1002 build_address6(&tmp
, &pool
->start_addr
,
1006 /* temporary address */
1007 build_temporary6(&tmp
, &pool
->start_addr
,
1012 log_error("create_lease6: prefix pool.");
1013 return DHCP_R_INVALIDARG
;
1015 log_error("create_lease6: untyped pool.");
1016 return DHCP_R_INVALIDARG
;
1020 * Avoid reserved interface IDs. (cf. RFC 5453)
1022 reserved_iid
= ISC_FALSE
;
1023 if (memcmp(&tmp
.s6_addr
[8], &rtany
.s6_addr
[8], 8) == 0) {
1024 reserved_iid
= ISC_TRUE
;
1026 if (!reserved_iid
&&
1027 (memcmp(&tmp
.s6_addr
[8], &resany
.s6_addr
[8], 7) == 0) &&
1028 ((tmp
.s6_addr
[15] & 0x80) == 0x80)) {
1029 reserved_iid
= ISC_TRUE
;
1033 * If this address is not in use, we're happy with it
1036 if (!reserved_iid
&&
1037 (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
1038 &tmp
, sizeof(tmp
), MDL
) == 0)) {
1041 if (test_iaaddr
!= NULL
)
1042 iasubopt_dereference(&test_iaaddr
, MDL
);
1045 * Otherwise, we create a new input, adding the address
1047 memset(&new_ds
, 0, sizeof(new_ds
));
1048 new_ds
.len
= ds
.len
+ sizeof(tmp
);
1049 if (!buffer_allocate(&new_ds
.buffer
, new_ds
.len
, MDL
)) {
1050 data_string_forget(&ds
, MDL
);
1051 return ISC_R_NOMEMORY
;
1053 new_ds
.data
= new_ds
.buffer
->data
;
1054 memcpy(new_ds
.buffer
->data
, ds
.data
, ds
.len
);
1055 memcpy(new_ds
.buffer
->data
+ ds
.len
, &tmp
, sizeof(tmp
));
1056 data_string_forget(&ds
, MDL
);
1057 data_string_copy(&ds
, &new_ds
, MDL
);
1058 data_string_forget(&new_ds
, MDL
);
1061 data_string_forget(&ds
, MDL
);
1064 * We're happy with the address, create an IAADDR
1068 result
= iasubopt_allocate(&iaaddr
, MDL
);
1069 if (result
!= ISC_R_SUCCESS
) {
1073 memcpy(&iaaddr
->addr
, &tmp
, sizeof(iaaddr
->addr
));
1076 * Add the lease to the pool (note state is free, not active?!).
1078 result
= add_lease6(pool
, iaaddr
, soft_lifetime_end_time
);
1079 if (result
== ISC_R_SUCCESS
) {
1080 iasubopt_reference(addr
, iaaddr
, MDL
);
1082 iasubopt_dereference(&iaaddr
, MDL
);
1089 * \brief Cleans up leases when reading from a lease file
1091 * This function is only expected to be run when reading leases in from a file.
1092 * It checks to see if a lease already exists for the new leases's address.
1093 * We don't add expired leases to the structures when reading a lease file
1094 * which limits what can happen. We have two variables the owners of the leases
1095 * being the same or different and the new lease being active or non-active:
1097 * same no remove old lease and its connections
1098 * same yes nothing to do, other code will update the structures.
1099 * diff no nothing to do
1100 * diff yes this combination shouldn't happen, we should only have a
1101 * single active lease per address at a time and that lease
1102 * should move to non-active before any other lease can
1103 * become active for that address.
1104 * Currently we delete the previous lease and pass an error
1105 * to the caller who should log an error.
1107 * When we remove a lease we remove it from the hash table and active heap
1108 * (remember only active leases are in the structures at this time) for the
1109 * pool, and from the IA's array. If, after we've removed the pointer from
1110 * IA's array to the lease, the IA has no more pointers we remove it from
1111 * the appropriate hash table as well.
1113 * \param[in] ia_table = the hash table for the IA
1114 * \param[in] pool = the pool to update
1115 * \param[in] lease = the new lease we want to add
1116 * \param[in] ia = the new ia we are building
1119 * ISC_R_SUCCESS = the incoming lease and any previous lease were in
1120 * an expected state - one of the first 3 options above.
1121 * If necessary the old lease was removed.
1122 * ISC_R_FAILURE = there is already an active lease for the address in
1123 * the incoming lease. This shouldn't happen if it does
1124 * flag an error for the caller to log.
1128 cleanup_lease6(ia_hash_t
*ia_table
,
1129 struct ipv6_pool
*pool
,
1130 struct iasubopt
*lease
,
1133 struct iasubopt
*test_iasubopt
, *tmp_iasubopt
;
1134 struct ia_xx
*old_ia
;
1135 isc_result_t status
= ISC_R_SUCCESS
;
1137 test_iasubopt
= NULL
;
1141 * Look up the address - if we don't find a lease
1142 * we don't need to do anything.
1144 if (iasubopt_hash_lookup(&test_iasubopt
, pool
->leases
,
1145 &lease
->addr
, sizeof(lease
->addr
),
1147 return (ISC_R_SUCCESS
);
1150 if (test_iasubopt
->ia
== NULL
) {
1151 /* no old ia, no work to do */
1152 iasubopt_dereference(&test_iasubopt
, MDL
);
1156 ia_reference(&old_ia
, test_iasubopt
->ia
, MDL
);
1158 if ((old_ia
->iaid_duid
.len
== ia
->iaid_duid
.len
) &&
1159 (memcmp((unsigned char *)ia
->iaid_duid
.data
,
1160 (unsigned char *)old_ia
->iaid_duid
.data
,
1161 ia
->iaid_duid
.len
) == 0)) {
1163 if ((lease
->state
== FTS_ACTIVE
) ||
1164 (lease
->state
== FTS_ABANDONED
)) {
1165 /* still active, no need to delete */
1170 if ((lease
->state
!= FTS_ACTIVE
) &&
1171 (lease
->state
!= FTS_ABANDONED
)) {
1172 /* new lease isn't active, no work */
1177 * We appear to have two active leases, this shouldn't happen.
1178 * Before a second lease can be set to active the first lease
1179 * should be set to inactive (released, expired etc). For now
1180 * delete the previous lease and indicate a failure to the
1181 * caller so it can generate a warning.
1182 * In the future we may try and determine which is the better
1186 status
= ISC_R_FAILURE
;
1190 * Remove the old lease from the active heap and from the hash table
1191 * then remove the lease from the IA and clean up the IA if necessary.
1193 isc_heap_delete(pool
->active_timeouts
, test_iasubopt
->heap_index
);
1196 iasubopt_hash_delete(pool
->leases
, &test_iasubopt
->addr
,
1197 sizeof(test_iasubopt
->addr
), MDL
);
1198 ia_remove_iasubopt(old_ia
, test_iasubopt
, MDL
);
1199 if (old_ia
->num_iasubopt
<= 0) {
1200 ia_hash_delete(ia_table
,
1201 (unsigned char *)old_ia
->iaid_duid
.data
,
1202 old_ia
->iaid_duid
.len
, MDL
);
1206 * We derefenrece the subopt here as we've just removed it from
1207 * the hash table in the pool. We need to make a copy as we
1208 * need to derefernece it again later.
1210 tmp_iasubopt
= test_iasubopt
;
1211 iasubopt_dereference(&tmp_iasubopt
, MDL
);
1214 ia_dereference(&old_ia
, MDL
);
1217 * Clean up the reference, this is in addition to the deference
1218 * above after removing the entry from the hash table
1220 iasubopt_dereference(&test_iasubopt
, MDL
);
1226 * Put a lease in the pool directly. This is intended to be used when
1227 * loading leases from the file.
1230 add_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
,
1231 time_t valid_lifetime_end_time
) {
1232 isc_result_t insert_result
;
1233 struct iasubopt
*test_iasubopt
;
1234 struct iasubopt
*tmp_iasubopt
;
1236 /* If a state was not assigned by the caller, assume active. */
1237 if (lease
->state
== 0)
1238 lease
->state
= FTS_ACTIVE
;
1240 ipv6_pool_reference(&lease
->ipv6_pool
, pool
, MDL
);
1243 * If this IAADDR/PREFIX is already in our structures, remove the
1246 test_iasubopt
= NULL
;
1247 if (iasubopt_hash_lookup(&test_iasubopt
, pool
->leases
,
1248 &lease
->addr
, sizeof(lease
->addr
), MDL
)) {
1249 /* XXX: we should probably ask the lease what heap it is on
1250 * (as a consistency check).
1251 * XXX: we should probably have one function to "put this lease
1252 * on its heap" rather than doing these if's everywhere. If
1253 * you add more states to this list, don't.
1255 if ((test_iasubopt
->state
== FTS_ACTIVE
) ||
1256 (test_iasubopt
->state
== FTS_ABANDONED
)) {
1257 isc_heap_delete(pool
->active_timeouts
,
1258 test_iasubopt
->heap_index
);
1261 isc_heap_delete(pool
->inactive_timeouts
,
1262 test_iasubopt
->heap_index
);
1263 pool
->num_inactive
--;
1266 iasubopt_hash_delete(pool
->leases
, &test_iasubopt
->addr
,
1267 sizeof(test_iasubopt
->addr
), MDL
);
1270 * We're going to do a bit of evil trickery here.
1272 * We need to dereference the entry once to remove our
1273 * current reference (in test_iasubopt), and then one
1274 * more time to remove the reference left when the
1275 * address was added to the pool before.
1277 tmp_iasubopt
= test_iasubopt
;
1278 iasubopt_dereference(&test_iasubopt
, MDL
);
1279 iasubopt_dereference(&tmp_iasubopt
, MDL
);
1283 * Add IAADDR/PREFIX to our structures.
1285 tmp_iasubopt
= NULL
;
1286 iasubopt_reference(&tmp_iasubopt
, lease
, MDL
);
1287 if ((tmp_iasubopt
->state
== FTS_ACTIVE
) ||
1288 (tmp_iasubopt
->state
== FTS_ABANDONED
)) {
1289 tmp_iasubopt
->hard_lifetime_end_time
= valid_lifetime_end_time
;
1290 iasubopt_hash_add(pool
->leases
, &tmp_iasubopt
->addr
,
1291 sizeof(tmp_iasubopt
->addr
), lease
, MDL
);
1292 insert_result
= isc_heap_insert(pool
->active_timeouts
,
1294 if (insert_result
== ISC_R_SUCCESS
)
1297 tmp_iasubopt
->soft_lifetime_end_time
= valid_lifetime_end_time
;
1298 insert_result
= isc_heap_insert(pool
->inactive_timeouts
,
1300 if (insert_result
== ISC_R_SUCCESS
)
1301 pool
->num_inactive
++;
1303 if (insert_result
!= ISC_R_SUCCESS
) {
1304 iasubopt_hash_delete(pool
->leases
, &lease
->addr
,
1305 sizeof(lease
->addr
), MDL
);
1306 iasubopt_dereference(&tmp_iasubopt
, MDL
);
1307 return insert_result
;
1311 * Note: we intentionally leave tmp_iasubopt referenced; there
1312 * is a reference in the heap/hash, after all.
1315 return ISC_R_SUCCESS
;
1319 * Determine if an address is present in a pool or not.
1322 lease6_exists(const struct ipv6_pool
*pool
, const struct in6_addr
*addr
) {
1323 struct iasubopt
*test_iaaddr
;
1326 if (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
1327 (void *)addr
, sizeof(*addr
), MDL
)) {
1328 iasubopt_dereference(&test_iaaddr
, MDL
);
1337 * \brief Check if address is available to a lease
1339 * Determine if the address in the lease is available to that
1340 * lease. Either the address isn't in use or it is in use
1341 * but by that lease.
1343 * \param[in] lease = lease to check
1346 * ISC_TRUE = The lease is allowed to use that address
1347 * ISC_FALSE = The lease isn't allowed to use that address
1350 lease6_usable(struct iasubopt
*lease
) {
1351 struct iasubopt
*test_iaaddr
;
1352 isc_boolean_t status
= ISC_TRUE
;
1355 if (iasubopt_hash_lookup(&test_iaaddr
, lease
->ipv6_pool
->leases
,
1356 (void *)&lease
->addr
,
1357 sizeof(lease
->addr
), MDL
)) {
1358 if (test_iaaddr
!= lease
) {
1361 iasubopt_dereference(&test_iaaddr
, MDL
);
1368 * Put the lease on our active pool.
1371 move_lease_to_active(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1372 isc_result_t insert_result
;
1375 old_heap_index
= lease
->heap_index
;
1376 insert_result
= isc_heap_insert(pool
->active_timeouts
, lease
);
1377 if (insert_result
== ISC_R_SUCCESS
) {
1378 iasubopt_hash_add(pool
->leases
, &lease
->addr
,
1379 sizeof(lease
->addr
), lease
, MDL
);
1380 isc_heap_delete(pool
->inactive_timeouts
, old_heap_index
);
1382 pool
->num_inactive
--;
1383 lease
->state
= FTS_ACTIVE
;
1385 return insert_result
;
1390 * \brief Renew a lease in the pool.
1392 * The hard_lifetime_end_time of the lease should be set to
1393 * the current expiration time.
1394 * The soft_lifetime_end_time of the lease should be set to
1395 * the desired expiration time.
1397 * This routine will compare the two and call the correct
1398 * heap routine to move the lease. If the lease is active
1399 * and the new expiration time is greater (the normal case)
1400 * then we call isc_heap_decreased() as a larger time is a
1401 * lower priority. If the new expiration time is less then
1402 * we call isc_heap_increased().
1404 * If the lease is abandoned then it will be on the active list
1405 * and we will always call isc_heap_increased() as the previous
1406 * expiration would have been all 1s (as close as we can get
1409 * If the lease is moving to active we call that routine
1410 * which will move it from the inactive list to the active list.
1412 * \param pool = a pool the lease belongs to
1413 * \param lease = the lease to be renewed
1415 * \return result of the renew operation (ISC_R_SUCCESS if successful,
1416 ISC_R_NOMEMORY when run out of memory)
1419 renew_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1420 time_t old_end_time
= lease
->hard_lifetime_end_time
;
1421 lease
->hard_lifetime_end_time
= lease
->soft_lifetime_end_time
;
1422 lease
->soft_lifetime_end_time
= 0;
1424 if (lease
->state
== FTS_ACTIVE
) {
1425 if (old_end_time
<= lease
->hard_lifetime_end_time
) {
1426 isc_heap_decreased(pool
->active_timeouts
,
1429 isc_heap_increased(pool
->active_timeouts
,
1432 return ISC_R_SUCCESS
;
1433 } else if (lease
->state
== FTS_ABANDONED
) {
1434 char tmp_addr
[INET6_ADDRSTRLEN
];
1435 lease
->state
= FTS_ACTIVE
;
1436 isc_heap_increased(pool
->active_timeouts
, lease
->heap_index
);
1437 log_info("Reclaiming previously abandoned address %s",
1438 inet_ntop(AF_INET6
, &(lease
->addr
), tmp_addr
,
1440 return ISC_R_SUCCESS
;
1442 return move_lease_to_active(pool
, lease
);
1447 * Put the lease on our inactive pool, with the specified state.
1450 move_lease_to_inactive(struct ipv6_pool
*pool
, struct iasubopt
*lease
,
1451 binding_state_t state
) {
1452 isc_result_t insert_result
;
1455 old_heap_index
= lease
->heap_index
;
1456 insert_result
= isc_heap_insert(pool
->inactive_timeouts
, lease
);
1457 if (insert_result
== ISC_R_SUCCESS
) {
1459 * Handle expire and release statements
1460 * To get here we must be active and have done a commit so
1461 * we should run the proper statements if they exist, though
1462 * that will change when we remove the inactive heap.
1463 * In addition we get rid of the references for both as we
1464 * can only do one (expire or release) on a lease
1466 if (lease
->on_star
.on_expiry
!= NULL
) {
1467 if (state
== FTS_EXPIRED
) {
1468 execute_statements(NULL
, NULL
, NULL
,
1471 lease
->on_star
.on_expiry
,
1474 executable_statement_dereference
1475 (&lease
->on_star
.on_expiry
, MDL
);
1478 if (lease
->on_star
.on_release
!= NULL
) {
1479 if (state
== FTS_RELEASED
) {
1480 execute_statements(NULL
, NULL
, NULL
,
1483 lease
->on_star
.on_release
,
1486 executable_statement_dereference
1487 (&lease
->on_star
.on_release
, MDL
);
1490 #if defined (NSUPDATE)
1491 /* Process events upon expiration. */
1492 if (pool
->pool_type
!= D6O_IA_PD
) {
1493 (void) ddns_removals(NULL
, lease
, NULL
, ISC_FALSE
);
1497 /* Binding scopes are no longer valid after expiry or
1500 if (lease
->scope
!= NULL
) {
1501 binding_scope_dereference(&lease
->scope
, MDL
);
1504 iasubopt_hash_delete(pool
->leases
,
1505 &lease
->addr
, sizeof(lease
->addr
), MDL
);
1506 isc_heap_delete(pool
->active_timeouts
, old_heap_index
);
1507 lease
->state
= state
;
1509 pool
->num_inactive
++;
1511 return insert_result
;
1515 * Expire the oldest lease if it's lifetime_end_time is
1516 * older than the given time.
1518 * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1519 * initialized to NULL
1521 * On return leasep has a reference to the removed entry. It is left
1522 * pointing to NULL if the oldest lease has not expired.
1525 expire_lease6(struct iasubopt
**leasep
, struct ipv6_pool
*pool
, time_t now
) {
1526 struct iasubopt
*tmp
;
1527 isc_result_t result
;
1529 if (leasep
== NULL
) {
1530 log_error("%s(%d): NULL pointer reference", MDL
);
1531 return DHCP_R_INVALIDARG
;
1533 if (*leasep
!= NULL
) {
1534 log_error("%s(%d): non-NULL pointer", MDL
);
1535 return DHCP_R_INVALIDARG
;
1538 if (pool
->num_active
> 0) {
1539 tmp
= (struct iasubopt
*)
1540 isc_heap_element(pool
->active_timeouts
, 1);
1541 if (now
> tmp
->hard_lifetime_end_time
) {
1542 result
= move_lease_to_inactive(pool
, tmp
,
1544 if (result
== ISC_R_SUCCESS
) {
1545 iasubopt_reference(leasep
, tmp
, MDL
);
1550 return ISC_R_SUCCESS
;
1555 * For a declined lease, leave it on the "active" pool, but mark
1556 * it as declined. Give it an infinite (well, really long) life.
1559 decline_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1560 isc_result_t result
;
1562 if ((lease
->state
!= FTS_ACTIVE
) &&
1563 (lease
->state
!= FTS_ABANDONED
)) {
1564 result
= move_lease_to_active(pool
, lease
);
1565 if (result
!= ISC_R_SUCCESS
) {
1569 lease
->state
= FTS_ABANDONED
;
1570 lease
->hard_lifetime_end_time
= MAX_TIME
;
1571 isc_heap_decreased(pool
->active_timeouts
, lease
->heap_index
);
1572 return ISC_R_SUCCESS
;
1576 * Put the returned lease on our inactive pool.
1579 release_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1580 if (lease
->state
== FTS_ACTIVE
) {
1581 return move_lease_to_inactive(pool
, lease
, FTS_RELEASED
);
1583 return ISC_R_SUCCESS
;
1588 * Create a prefix by hashing the input, and using that for
1589 * the part subject to allocation.
1592 build_prefix6(struct in6_addr
*pref
,
1593 const struct in6_addr
*net_start_pref
,
1594 int pool_bits
, int pref_bits
,
1595 const struct data_string
*input
) {
1600 const char *net_str
;
1603 * Use MD5 to get a nice 128 bit hash of the input.
1604 * Yes, we know MD5 isn't cryptographically sound.
1605 * No, we don't care.
1608 isc_md5_update(&ctx
, input
->data
, input
->len
);
1609 isc_md5_final(&ctx
, (unsigned char *)pref
);
1612 * Copy the network bits over.
1615 net_str
= (const char *)net_start_pref
;
1616 net_bytes
= pool_bits
/ 8;
1617 for (i
= 0; i
< net_bytes
; i
++) {
1618 str
[i
] = net_str
[i
];
1621 switch (pool_bits
% 8) {
1622 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
1623 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
1624 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
1625 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
1626 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
1627 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
1628 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
1631 * Zero the remaining bits.
1633 net_bytes
= pref_bits
/ 8;
1634 for (i
=net_bytes
+1; i
<16; i
++) {
1638 switch (pref_bits
% 8) {
1639 case 0: str
[i
] &= 0; break;
1640 case 1: str
[i
] &= 0x80; break;
1641 case 2: str
[i
] &= 0xC0; break;
1642 case 3: str
[i
] &= 0xE0; break;
1643 case 4: str
[i
] &= 0xF0; break;
1644 case 5: str
[i
] &= 0xF8; break;
1645 case 6: str
[i
] &= 0xFC; break;
1646 case 7: str
[i
] &= 0xFE; break;
1651 * Create a lease for the given prefix and client duid.
1653 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1654 * initialized to NULL
1656 * Right now we simply hash the DUID, and if we get a collision, we hash
1657 * again until we find a free prefix. We try this a fixed number of times,
1658 * to avoid getting stuck in a loop (this is important on small pools
1659 * where we can run out of space).
1661 * We return the number of attempts that it took to find an available
1662 * prefix. This tells callers when a pool is are filling up, as
1663 * well as an indication of how full the pool is; statistically the
1664 * more full a pool is the more attempts must be made before finding
1665 * a free prefix. Realistically this will only happen in very full
1668 * We probably want different algorithms depending on the network size, in
1672 create_prefix6(struct ipv6_pool
*pool
, struct iasubopt
**pref
,
1673 unsigned int *attempts
,
1674 const struct data_string
*uid
,
1675 time_t soft_lifetime_end_time
) {
1676 struct data_string ds
;
1677 struct in6_addr tmp
;
1678 struct iasubopt
*test_iapref
;
1679 struct data_string new_ds
;
1680 struct iasubopt
*iapref
;
1681 isc_result_t result
;
1684 * Use the UID as our initial seed for the hash
1686 memset(&ds
, 0, sizeof(ds
));
1687 data_string_copy(&ds
, (struct data_string
*)uid
, MDL
);
1692 * Give up at some point.
1694 if (++(*attempts
) > 10) {
1695 data_string_forget(&ds
, MDL
);
1696 return ISC_R_NORESOURCES
;
1702 build_prefix6(&tmp
, &pool
->start_addr
,
1703 pool
->bits
, pool
->units
, &ds
);
1706 * If this prefix is not in use, we're happy with it
1709 if (iasubopt_hash_lookup(&test_iapref
, pool
->leases
,
1710 &tmp
, sizeof(tmp
), MDL
) == 0) {
1713 iasubopt_dereference(&test_iapref
, MDL
);
1716 * Otherwise, we create a new input, adding the prefix
1718 memset(&new_ds
, 0, sizeof(new_ds
));
1719 new_ds
.len
= ds
.len
+ sizeof(tmp
);
1720 if (!buffer_allocate(&new_ds
.buffer
, new_ds
.len
, MDL
)) {
1721 data_string_forget(&ds
, MDL
);
1722 return ISC_R_NOMEMORY
;
1724 new_ds
.data
= new_ds
.buffer
->data
;
1725 memcpy(new_ds
.buffer
->data
, ds
.data
, ds
.len
);
1726 memcpy(new_ds
.buffer
->data
+ ds
.len
, &tmp
, sizeof(tmp
));
1727 data_string_forget(&ds
, MDL
);
1728 data_string_copy(&ds
, &new_ds
, MDL
);
1729 data_string_forget(&new_ds
, MDL
);
1732 data_string_forget(&ds
, MDL
);
1735 * We're happy with the prefix, create an IAPREFIX
1739 result
= iasubopt_allocate(&iapref
, MDL
);
1740 if (result
!= ISC_R_SUCCESS
) {
1743 iapref
->plen
= (u_int8_t
)pool
->units
;
1744 memcpy(&iapref
->addr
, &tmp
, sizeof(iapref
->addr
));
1747 * Add the prefix to the pool (note state is free, not active?!).
1749 result
= add_lease6(pool
, iapref
, soft_lifetime_end_time
);
1750 if (result
== ISC_R_SUCCESS
) {
1751 iasubopt_reference(pref
, iapref
, MDL
);
1753 iasubopt_dereference(&iapref
, MDL
);
1758 * Determine if a prefix is present in a pool or not.
1761 prefix6_exists(const struct ipv6_pool
*pool
,
1762 const struct in6_addr
*pref
, u_int8_t plen
) {
1763 struct iasubopt
*test_iapref
;
1765 if ((int)plen
!= pool
->units
)
1769 if (iasubopt_hash_lookup(&test_iapref
, pool
->leases
,
1770 (void *)pref
, sizeof(*pref
), MDL
)) {
1771 iasubopt_dereference(&test_iapref
, MDL
);
1779 * Mark an IPv6 address/prefix as unavailable from a pool.
1781 * This is used for host entries and the addresses of the server itself.
1784 mark_lease_unavailable(struct ipv6_pool
*pool
, const struct in6_addr
*addr
) {
1785 struct iasubopt
*dummy_iasubopt
;
1786 isc_result_t result
;
1788 dummy_iasubopt
= NULL
;
1789 result
= iasubopt_allocate(&dummy_iasubopt
, MDL
);
1790 if (result
== ISC_R_SUCCESS
) {
1791 dummy_iasubopt
->addr
= *addr
;
1792 iasubopt_hash_add(pool
->leases
, &dummy_iasubopt
->addr
,
1793 sizeof(*addr
), dummy_iasubopt
, MDL
);
1802 add_ipv6_pool(struct ipv6_pool
*pool
) {
1803 struct ipv6_pool
**new_pools
;
1805 new_pools
= dmalloc(sizeof(struct ipv6_pool
*) * (num_pools
+1), MDL
);
1806 if (new_pools
== NULL
) {
1807 return ISC_R_NOMEMORY
;
1810 if (num_pools
> 0) {
1811 memcpy(new_pools
, pools
,
1812 sizeof(struct ipv6_pool
*) * num_pools
);
1817 pools
[num_pools
] = NULL
;
1818 ipv6_pool_reference(&pools
[num_pools
], pool
, MDL
);
1820 return ISC_R_SUCCESS
;
1824 cleanup_old_expired(struct ipv6_pool
*pool
) {
1825 struct iasubopt
*tmp
;
1827 struct ia_xx
*ia_active
;
1828 unsigned char *tmpd
;
1831 while (pool
->num_inactive
> 0) {
1832 tmp
= (struct iasubopt
*)
1833 isc_heap_element(pool
->inactive_timeouts
, 1);
1834 if (tmp
->hard_lifetime_end_time
!= 0) {
1835 timeout
= tmp
->hard_lifetime_end_time
;
1836 timeout
+= EXPIRED_IPV6_CLEANUP_TIME
;
1838 timeout
= tmp
->soft_lifetime_end_time
;
1840 if (cur_time
< timeout
) {
1844 isc_heap_delete(pool
->inactive_timeouts
, tmp
->heap_index
);
1845 pool
->num_inactive
--;
1847 if (tmp
->ia
!= NULL
) {
1849 * Check to see if this IA is in an active list,
1850 * but has no remaining resources. If so, remove it
1851 * from the active list.
1854 ia_reference(&ia
, tmp
->ia
, MDL
);
1855 ia_remove_iasubopt(ia
, tmp
, MDL
);
1857 tmpd
= (unsigned char *)ia
->iaid_duid
.data
;
1858 if ((ia
->ia_type
== D6O_IA_NA
) &&
1859 (ia
->num_iasubopt
<= 0) &&
1860 (ia_hash_lookup(&ia_active
, ia_na_active
, tmpd
,
1861 ia
->iaid_duid
.len
, MDL
) == 0) &&
1862 (ia_active
== ia
)) {
1863 ia_hash_delete(ia_na_active
, tmpd
,
1864 ia
->iaid_duid
.len
, MDL
);
1866 if ((ia
->ia_type
== D6O_IA_TA
) &&
1867 (ia
->num_iasubopt
<= 0) &&
1868 (ia_hash_lookup(&ia_active
, ia_ta_active
, tmpd
,
1869 ia
->iaid_duid
.len
, MDL
) == 0) &&
1870 (ia_active
== ia
)) {
1871 ia_hash_delete(ia_ta_active
, tmpd
,
1872 ia
->iaid_duid
.len
, MDL
);
1874 if ((ia
->ia_type
== D6O_IA_PD
) &&
1875 (ia
->num_iasubopt
<= 0) &&
1876 (ia_hash_lookup(&ia_active
, ia_pd_active
, tmpd
,
1877 ia
->iaid_duid
.len
, MDL
) == 0) &&
1878 (ia_active
== ia
)) {
1879 ia_hash_delete(ia_pd_active
, tmpd
,
1880 ia
->iaid_duid
.len
, MDL
);
1882 ia_dereference(&ia
, MDL
);
1884 iasubopt_dereference(&tmp
, MDL
);
1889 lease_timeout_support(void *vpool
) {
1890 struct ipv6_pool
*pool
;
1891 struct iasubopt
*lease
;
1893 pool
= (struct ipv6_pool
*)vpool
;
1896 * Get the next lease scheduled to expire.
1898 * Note that if there are no leases in the pool,
1899 * expire_lease6() will return ISC_R_SUCCESS with
1902 * expire_lease6() will call move_lease_to_inactive() which
1903 * calls ddns_removals() do we want that on the standard
1904 * expiration timer or a special 'depref' timer? Original
1905 * query from DH, moved here by SAR.
1908 if (expire_lease6(&lease
, pool
, cur_time
) != ISC_R_SUCCESS
) {
1911 if (lease
== NULL
) {
1915 write_ia(lease
->ia
);
1917 iasubopt_dereference(&lease
, MDL
);
1921 * If appropriate commit and rotate the lease file
1922 * As commit_leases_timed() checks to see if we've done any writes
1923 * we don't bother tracking if this function called write _ia
1925 (void) commit_leases_timed();
1928 * Do some cleanup of our expired leases.
1930 cleanup_old_expired(pool
);
1933 * Schedule next round of expirations.
1935 schedule_lease_timeout(pool
);
1939 * For a given pool, add a timer that will remove the next
1943 schedule_lease_timeout(struct ipv6_pool
*pool
) {
1944 struct iasubopt
*tmp
;
1946 time_t next_timeout
;
1949 next_timeout
= MAX_TIME
;
1951 if (pool
->num_active
> 0) {
1952 tmp
= (struct iasubopt
*)
1953 isc_heap_element(pool
->active_timeouts
, 1);
1954 if (tmp
->hard_lifetime_end_time
< next_timeout
) {
1955 next_timeout
= tmp
->hard_lifetime_end_time
+ 1;
1959 if (pool
->num_inactive
> 0) {
1960 tmp
= (struct iasubopt
*)
1961 isc_heap_element(pool
->inactive_timeouts
, 1);
1962 if (tmp
->hard_lifetime_end_time
!= 0) {
1963 timeout
= tmp
->hard_lifetime_end_time
;
1964 timeout
+= EXPIRED_IPV6_CLEANUP_TIME
;
1966 timeout
= tmp
->soft_lifetime_end_time
+ 1;
1968 if (timeout
< next_timeout
) {
1969 next_timeout
= timeout
;
1973 if (next_timeout
< MAX_TIME
) {
1974 tv
.tv_sec
= next_timeout
;
1976 add_timeout(&tv
, lease_timeout_support
, pool
,
1977 (tvref_t
)ipv6_pool_reference
,
1978 (tvunref_t
)ipv6_pool_dereference
);
1983 * Schedule timeouts across all pools.
1986 schedule_all_ipv6_lease_timeouts(void) {
1989 for (i
=0; i
<num_pools
; i
++) {
1990 schedule_lease_timeout(pools
[i
]);
1995 * Given an address and the length of the network mask, return
1996 * only the network portion.
2000 * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
2001 * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
2004 ipv6_network_portion(struct in6_addr
*result
,
2005 const struct in6_addr
*addr
, int bits
) {
2006 unsigned char *addrp
;
2012 static const unsigned char bitmasks
[] = {
2013 0x00, 0xFE, 0xFC, 0xF8,
2014 0xF0, 0xE0, 0xC0, 0x80,
2018 * Sanity check our bits. ;)
2020 if ((bits
< 0) || (bits
> 128)) {
2021 log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
2026 * Copy our address portion.
2029 addrp
= ((unsigned char *)result
) + 15;
2032 * Zero out masked portion.
2034 mask_bits
= 128 - bits
;
2035 bytes
= mask_bits
/ 8;
2036 extra_bits
= mask_bits
% 8;
2038 for (i
=0; i
<bytes
; i
++) {
2043 *addrp
&= bitmasks
[extra_bits
];
2048 * Determine if the given address/prefix is in the pool.
2051 ipv6_in_pool(const struct in6_addr
*addr
, const struct ipv6_pool
*pool
) {
2052 struct in6_addr tmp
;
2054 ipv6_network_portion(&tmp
, addr
, pool
->bits
);
2055 if (memcmp(&tmp
, &pool
->start_addr
, sizeof(tmp
)) == 0) {
2063 * Find the pool that contains the given address.
2065 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
2066 * initialized to NULL
2069 find_ipv6_pool(struct ipv6_pool
**pool
, u_int16_t type
,
2070 const struct in6_addr
*addr
) {
2074 log_error("%s(%d): NULL pointer reference", MDL
);
2075 return DHCP_R_INVALIDARG
;
2077 if (*pool
!= NULL
) {
2078 log_error("%s(%d): non-NULL pointer", MDL
);
2079 return DHCP_R_INVALIDARG
;
2082 for (i
=0; i
<num_pools
; i
++) {
2083 if (pools
[i
]->pool_type
!= type
)
2085 if (ipv6_in_pool(addr
, pools
[i
])) {
2086 ipv6_pool_reference(pool
, pools
[i
], MDL
);
2087 return ISC_R_SUCCESS
;
2090 return ISC_R_NOTFOUND
;
2094 * Helper function for the various functions that act across all
2098 change_leases(struct ia_xx
*ia
,
2099 isc_result_t (*change_func
)(struct ipv6_pool
*,
2100 struct iasubopt
*)) {
2101 isc_result_t retval
;
2102 isc_result_t renew_retval
;
2103 struct ipv6_pool
*pool
;
2104 struct in6_addr
*addr
;
2107 retval
= ISC_R_SUCCESS
;
2108 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
2110 addr
= &ia
->iasubopt
[i
]->addr
;
2111 if (find_ipv6_pool(&pool
, ia
->ia_type
,
2112 addr
) == ISC_R_SUCCESS
) {
2113 renew_retval
= change_func(pool
, ia
->iasubopt
[i
]);
2114 if (renew_retval
!= ISC_R_SUCCESS
) {
2115 retval
= renew_retval
;
2118 /* XXXsk: should we warn if we don't find a pool? */
2124 * Renew all leases in an IA from all pools.
2126 * The new lifetime should be in the soft_lifetime_end_time
2127 * and will be moved to hard_lifetime_end_time by renew_lease6.
2130 renew_leases(struct ia_xx
*ia
) {
2131 return change_leases(ia
, renew_lease6
);
2135 * Release all leases in an IA from all pools.
2138 release_leases(struct ia_xx
*ia
) {
2139 return change_leases(ia
, release_lease6
);
2143 * Decline all leases in an IA from all pools.
2146 decline_leases(struct ia_xx
*ia
) {
2147 return change_leases(ia
, decline_lease6
);
2152 * Helper function to output leases.
2154 static int write_error
;
2157 write_ia_leases(const void *name
, unsigned len
, void *value
) {
2158 struct ia_xx
*ia
= (struct ia_xx
*)value
;
2161 if (!write_ia(ia
)) {
2165 return ISC_R_SUCCESS
;
2169 * Write all DHCPv6 information.
2172 write_leases6(void) {
2176 write_server_duid();
2177 nas
= ia_hash_foreach(ia_na_active
, write_ia_leases
);
2181 tas
= ia_hash_foreach(ia_ta_active
, write_ia_leases
);
2185 pds
= ia_hash_foreach(ia_pd_active
, write_ia_leases
);
2190 log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
2197 mark_hosts_unavailable_support(const void *name
, unsigned len
, void *value
) {
2198 struct host_decl
*h
;
2199 struct data_string fixed_addr
;
2200 struct in6_addr addr
;
2201 struct ipv6_pool
*p
;
2203 h
= (struct host_decl
*)value
;
2206 * If the host has no address, we don't need to mark anything.
2208 if (h
->fixed_addr
== NULL
) {
2209 return ISC_R_SUCCESS
;
2213 * Evaluate the fixed address.
2215 memset(&fixed_addr
, 0, sizeof(fixed_addr
));
2216 if (!evaluate_option_cache(&fixed_addr
, NULL
, NULL
, NULL
, NULL
, NULL
,
2217 &global_scope
, h
->fixed_addr
, MDL
)) {
2218 log_error("mark_hosts_unavailable: "
2219 "error evaluating host address.");
2220 return ISC_R_SUCCESS
;
2222 if (fixed_addr
.len
!= 16) {
2223 log_error("mark_hosts_unavailable: "
2224 "host address is not 128 bits.");
2225 return ISC_R_SUCCESS
;
2227 memcpy(&addr
, fixed_addr
.data
, 16);
2228 data_string_forget(&fixed_addr
, MDL
);
2231 * Find the pool holding this host, and mark the address.
2232 * (I suppose it is arguably valid to have a host that does not
2236 if (find_ipv6_pool(&p
, D6O_IA_NA
, &addr
) == ISC_R_SUCCESS
) {
2237 mark_lease_unavailable(p
, &addr
);
2238 ipv6_pool_dereference(&p
, MDL
);
2240 if (find_ipv6_pool(&p
, D6O_IA_TA
, &addr
) == ISC_R_SUCCESS
) {
2241 mark_lease_unavailable(p
, &addr
);
2242 ipv6_pool_dereference(&p
, MDL
);
2245 return ISC_R_SUCCESS
;
2249 mark_hosts_unavailable(void) {
2250 hash_foreach(host_name_hash
, mark_hosts_unavailable_support
);
2254 mark_phosts_unavailable_support(const void *name
, unsigned len
, void *value
) {
2255 struct host_decl
*h
;
2256 struct iaddrcidrnetlist
*l
;
2257 struct in6_addr pref
;
2258 struct ipv6_pool
*p
;
2260 h
= (struct host_decl
*)value
;
2263 * If the host has no prefix, we don't need to mark anything.
2265 if (h
->fixed_prefix
== NULL
) {
2266 return ISC_R_SUCCESS
;
2270 * Get the fixed prefixes.
2272 for (l
= h
->fixed_prefix
; l
!= NULL
; l
= l
->next
) {
2273 if (l
->cidrnet
.lo_addr
.len
!= 16) {
2276 memcpy(&pref
, l
->cidrnet
.lo_addr
.iabuf
, 16);
2279 * Find the pool holding this host, and mark the prefix.
2280 * (I suppose it is arguably valid to have a host that does not
2284 if (find_ipv6_pool(&p
, D6O_IA_PD
, &pref
) != ISC_R_SUCCESS
) {
2287 if (l
->cidrnet
.bits
!= p
->units
) {
2288 ipv6_pool_dereference(&p
, MDL
);
2291 mark_lease_unavailable(p
, &pref
);
2292 ipv6_pool_dereference(&p
, MDL
);
2295 return ISC_R_SUCCESS
;
2299 mark_phosts_unavailable(void) {
2300 hash_foreach(host_name_hash
, mark_phosts_unavailable_support
);
2304 mark_interfaces_unavailable(void) {
2305 struct interface_info
*ip
;
2307 struct ipv6_pool
*p
;
2310 while (ip
!= NULL
) {
2311 for (i
=0; i
<ip
->v6address_count
; i
++) {
2313 if (find_ipv6_pool(&p
, D6O_IA_NA
, &ip
->v6addresses
[i
])
2315 mark_lease_unavailable(p
,
2316 &ip
->v6addresses
[i
]);
2317 ipv6_pool_dereference(&p
, MDL
);
2319 if (find_ipv6_pool(&p
, D6O_IA_TA
, &ip
->v6addresses
[i
])
2321 mark_lease_unavailable(p
,
2322 &ip
->v6addresses
[i
]);
2323 ipv6_pool_dereference(&p
, MDL
);
2331 * \brief Create a new IPv6 pond structure.
2333 * Allocate space for a new ipv6_pond structure and return a reference
2334 * to it, includes setting the reference count to 1.
2336 * \param pond = space for returning a referenced pointer to the pond.
2337 * This must point to a space that has been initialzied
2338 * to NULL by the caller.
2341 * ISC_R_SUCCESS = The pond was successfully created, pond points to it.
2342 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2344 * ISC_R_NOMEMORY = The system wasn't able to allocate memory, pond has
2345 * not been modified.
2348 ipv6_pond_allocate(struct ipv6_pond
**pond
, const char *file
, int line
) {
2349 struct ipv6_pond
*tmp
;
2352 log_error("%s(%d): NULL pointer reference", file
, line
);
2353 return DHCP_R_INVALIDARG
;
2355 if (*pond
!= NULL
) {
2356 log_error("%s(%d): non-NULL pointer", file
, line
);
2357 return DHCP_R_INVALIDARG
;
2360 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
2362 return ISC_R_NOMEMORY
;
2368 return ISC_R_SUCCESS
;
2373 * \brief reference an IPv6 pond structure.
2375 * This function genreates a reference to an ipv6_pond structure
2376 * and increments the reference count on the structure.
2378 * \param[out] pond = space for returning a referenced pointer to the pond.
2379 * This must point to a space that has been initialzied
2380 * to NULL by the caller.
2381 * \param[in] src = A pointer to the pond to reference. This must not be
2385 * ISC_R_SUCCESS = The pond was successfully referenced, pond now points
2387 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2391 ipv6_pond_reference(struct ipv6_pond
**pond
, struct ipv6_pond
*src
,
2392 const char *file
, int line
) {
2394 log_error("%s(%d): NULL pointer reference", file
, line
);
2395 return DHCP_R_INVALIDARG
;
2397 if (*pond
!= NULL
) {
2398 log_error("%s(%d): non-NULL pointer", file
, line
);
2399 return DHCP_R_INVALIDARG
;
2402 log_error("%s(%d): NULL pointer reference", file
, line
);
2403 return DHCP_R_INVALIDARG
;
2407 return ISC_R_SUCCESS
;
2412 * \brief de-reference an IPv6 pond structure.
2414 * This function decrements the reference count in an ipv6_pond structure.
2415 * If this was the last reference then the memory for the structure is
2418 * \param[in] pond = A pointer to the pointer to the pond that should be
2419 * de-referenced. On success the pointer to the pond
2420 * is cleared. It must not be NULL and must not point
2424 * ISC_R_SUCCESS = The pond was successfully de-referenced, pond now points
2426 * DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
2431 ipv6_pond_dereference(struct ipv6_pond
**pond
, const char *file
, int line
) {
2432 struct ipv6_pond
*tmp
;
2434 if ((pond
== NULL
) || (*pond
== NULL
)) {
2435 log_error("%s(%d): NULL pointer", file
, line
);
2436 return DHCP_R_INVALIDARG
;
2443 if (tmp
->refcnt
< 0) {
2444 log_error("%s(%d): negative refcnt", file
, line
);
2447 if (tmp
->refcnt
== 0) {
2448 dfree(tmp
, file
, line
);
2451 return ISC_R_SUCCESS
;
2454 /* unittest moved to server/tests/mdb6_unittest.c */