2 * Copyright (C) 2007-2012 by Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
18 /* TODO: simplify functions, as pool is now in iaaddr */
22 #include <sys/types.h>
24 #include <netinet/in.h>
28 #include "omapip/omapip.h"
29 #include "omapip/hash.h"
32 HASH_FUNCTIONS(ia
, unsigned char *, struct ia_xx
, ia_hash_t
,
33 ia_reference
, ia_dereference
, do_string_hash
)
35 ia_hash_t
*ia_na_active
;
36 ia_hash_t
*ia_ta_active
;
37 ia_hash_t
*ia_pd_active
;
39 HASH_FUNCTIONS(iasubopt
, struct in6_addr
*, struct iasubopt
, iasubopt_hash_t
,
40 iasubopt_reference
, iasubopt_dereference
, do_string_hash
)
42 struct ipv6_pool
**pools
;
46 * Create a new IAADDR/PREFIX structure.
48 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
52 iasubopt_allocate(struct iasubopt
**iasubopt
, const char *file
, int line
) {
55 if (iasubopt
== NULL
) {
56 log_error("%s(%d): NULL pointer reference", file
, line
);
57 return DHCP_R_INVALIDARG
;
59 if (*iasubopt
!= NULL
) {
60 log_error("%s(%d): non-NULL pointer", file
, line
);
61 return DHCP_R_INVALIDARG
;
64 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
66 return ISC_R_NOMEMORY
;
70 tmp
->state
= FTS_FREE
;
79 * Reference an IAADDR/PREFIX structure.
81 * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously
85 iasubopt_reference(struct iasubopt
**iasubopt
, struct iasubopt
*src
,
86 const char *file
, int line
) {
87 if (iasubopt
== NULL
) {
88 log_error("%s(%d): NULL pointer reference", file
, line
);
89 return DHCP_R_INVALIDARG
;
91 if (*iasubopt
!= NULL
) {
92 log_error("%s(%d): non-NULL pointer", file
, line
);
93 return DHCP_R_INVALIDARG
;
96 log_error("%s(%d): NULL pointer reference", file
, line
);
97 return DHCP_R_INVALIDARG
;
101 return ISC_R_SUCCESS
;
106 * Dereference an IAADDR/PREFIX structure.
108 * If it is the last reference, then the memory for the
109 * structure is freed.
112 iasubopt_dereference(struct iasubopt
**iasubopt
, const char *file
, int line
) {
113 struct iasubopt
*tmp
;
115 if ((iasubopt
== NULL
) || (*iasubopt
== NULL
)) {
116 log_error("%s(%d): NULL pointer", file
, line
);
117 return DHCP_R_INVALIDARG
;
124 if (tmp
->refcnt
< 0) {
125 log_error("%s(%d): negative refcnt", file
, line
);
128 if (tmp
->refcnt
== 0) {
129 if (tmp
->ia
!= NULL
) {
130 ia_dereference(&(tmp
->ia
), file
, line
);
132 if (tmp
->ipv6_pool
!= NULL
) {
133 ipv6_pool_dereference(&(tmp
->ipv6_pool
), file
, line
);
135 if (tmp
->scope
!= NULL
) {
136 binding_scope_dereference(&tmp
->scope
, file
, line
);
138 dfree(tmp
, file
, line
);
141 return ISC_R_SUCCESS
;
145 * Make the key that we use for IA.
148 ia_make_key(struct data_string
*key
, u_int32_t iaid
,
149 const char *duid
, unsigned int duid_len
,
150 const char *file
, int line
) {
152 memset(key
, 0, sizeof(*key
));
153 key
->len
= duid_len
+ sizeof(iaid
);
154 if (!buffer_allocate(&(key
->buffer
), key
->len
, file
, line
)) {
155 return ISC_R_NOMEMORY
;
157 key
->data
= key
->buffer
->data
;
158 memcpy((char *)key
->data
, &iaid
, sizeof(iaid
));
159 memcpy((char *)key
->data
+ sizeof(iaid
), duid
, duid_len
);
161 return ISC_R_SUCCESS
;
165 * Create a new IA structure.
167 * - ia must be a pointer to a (struct ia_xx *) pointer previously
168 * initialized to NULL
169 * - iaid and duid are values from the client
171 * XXXsk: we don't concern ourself with the byte order of the IAID,
172 * which might be a problem if we transfer this structure
173 * between machines of different byte order
176 ia_allocate(struct ia_xx
**ia
, u_int32_t iaid
,
177 const char *duid
, unsigned int duid_len
,
178 const char *file
, int line
) {
182 log_error("%s(%d): NULL pointer reference", file
, line
);
183 return DHCP_R_INVALIDARG
;
186 log_error("%s(%d): non-NULL pointer", file
, line
);
187 return DHCP_R_INVALIDARG
;
190 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
192 return ISC_R_NOMEMORY
;
195 if (ia_make_key(&tmp
->iaid_duid
, iaid
,
196 duid
, duid_len
, file
, line
) != ISC_R_SUCCESS
) {
197 dfree(tmp
, file
, line
);
198 return ISC_R_NOMEMORY
;
204 return ISC_R_SUCCESS
;
208 * Reference an IA structure.
210 * - ia must be a pointer to a (struct ia_xx *) pointer previously
211 * initialized to NULL
214 ia_reference(struct ia_xx
**ia
, struct ia_xx
*src
,
215 const char *file
, int line
) {
217 log_error("%s(%d): NULL pointer reference", file
, line
);
218 return DHCP_R_INVALIDARG
;
221 log_error("%s(%d): non-NULL pointer", file
, line
);
222 return DHCP_R_INVALIDARG
;
225 log_error("%s(%d): NULL pointer reference", file
, line
);
226 return DHCP_R_INVALIDARG
;
230 return ISC_R_SUCCESS
;
234 * Dereference an IA structure.
236 * If it is the last reference, then the memory for the
237 * structure is freed.
240 ia_dereference(struct ia_xx
**ia
, const char *file
, int line
) {
244 if ((ia
== NULL
) || (*ia
== NULL
)) {
245 log_error("%s(%d): NULL pointer", file
, line
);
246 return DHCP_R_INVALIDARG
;
253 if (tmp
->refcnt
< 0) {
254 log_error("%s(%d): negative refcnt", file
, line
);
257 if (tmp
->refcnt
== 0) {
258 if (tmp
->iasubopt
!= NULL
) {
259 for (i
=0; i
<tmp
->num_iasubopt
; i
++) {
260 iasubopt_dereference(&(tmp
->iasubopt
[i
]),
263 dfree(tmp
->iasubopt
, file
, line
);
265 data_string_forget(&(tmp
->iaid_duid
), file
, line
);
266 dfree(tmp
, file
, line
);
268 return ISC_R_SUCCESS
;
273 * Add an IAADDR/PREFIX entry to an IA structure.
276 ia_add_iasubopt(struct ia_xx
*ia
, struct iasubopt
*iasubopt
,
277 const char *file
, int line
) {
279 struct iasubopt
**new;
282 * Grow our array if we need to.
284 * Note: we pick 4 as the increment, as that seems a reasonable
285 * guess as to how many addresses/prefixes we might expect
288 if (ia
->max_iasubopt
<= ia
->num_iasubopt
) {
289 max
= ia
->max_iasubopt
+ 4;
290 new = dmalloc(max
* sizeof(struct iasubopt
*), file
, line
);
292 return ISC_R_NOMEMORY
;
294 memcpy(new, ia
->iasubopt
,
295 ia
->num_iasubopt
* sizeof(struct iasubopt
*));
297 ia
->max_iasubopt
= max
;
300 iasubopt_reference(&(ia
->iasubopt
[ia
->num_iasubopt
]), iasubopt
,
304 return ISC_R_SUCCESS
;
308 * Remove an IAADDR/PREFIX entry to an IA structure.
310 * Note: if a suboption appears more than once, then only ONE will be removed.
313 ia_remove_iasubopt(struct ia_xx
*ia
, struct iasubopt
*iasubopt
,
314 const char *file
, int line
) {
317 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
318 if (ia
->iasubopt
[i
] == iasubopt
) {
319 /* remove this sub option */
320 iasubopt_dereference(&(ia
->iasubopt
[i
]), file
, line
);
321 /* move remaining suboption pointers down one */
322 for (j
=i
+1; j
< ia
->num_iasubopt
; j
++) {
323 ia
->iasubopt
[j
-1] = ia
->iasubopt
[j
];
325 /* decrease our total count */
326 /* remove the back-reference in the suboption itself */
327 ia_dereference(&iasubopt
->ia
, file
, line
);
332 log_error("%s(%d): IAADDR/PREFIX not in IA", file
, line
);
336 * Remove all addresses/prefixes from an IA.
339 ia_remove_all_lease(struct ia_xx
*ia
, const char *file
, int line
) {
342 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
343 ia_dereference(&(ia
->iasubopt
[i
]->ia
), file
, line
);
344 iasubopt_dereference(&(ia
->iasubopt
[i
]), file
, line
);
346 ia
->num_iasubopt
= 0;
353 ia_equal(const struct ia_xx
*a
, const struct ia_xx
*b
)
359 * Handle cases where one or both of the inputs is NULL.
370 * Check the type is the same.
372 if (a
->ia_type
!= b
->ia_type
) {
377 * Check the DUID is the same.
379 if (a
->iaid_duid
.len
!= b
->iaid_duid
.len
) {
382 if (memcmp(a
->iaid_duid
.data
,
383 b
->iaid_duid
.data
, a
->iaid_duid
.len
) != 0) {
388 * Make sure we have the same number of addresses/prefixes in each.
390 if (a
->num_iasubopt
!= b
->num_iasubopt
) {
395 * Check that each address/prefix is present in both.
397 for (i
=0; i
<a
->num_iasubopt
; i
++) {
399 for (j
=0; j
<a
->num_iasubopt
; j
++) {
400 if (a
->iasubopt
[i
]->plen
!= b
->iasubopt
[i
]->plen
)
402 if (memcmp(&(a
->iasubopt
[i
]->addr
),
403 &(b
->iasubopt
[j
]->addr
),
404 sizeof(struct in6_addr
)) == 0) {
415 * These are the same in every way we care about.
421 * Helper function for lease heaps.
422 * Makes the top of the heap the oldest lease.
425 lease_older(void *a
, void *b
) {
426 struct iasubopt
*la
= (struct iasubopt
*)a
;
427 struct iasubopt
*lb
= (struct iasubopt
*)b
;
429 if (la
->hard_lifetime_end_time
== lb
->hard_lifetime_end_time
) {
430 return difftime(la
->soft_lifetime_end_time
,
431 lb
->soft_lifetime_end_time
) < 0;
433 return difftime(la
->hard_lifetime_end_time
,
434 lb
->hard_lifetime_end_time
) < 0;
439 * Helper function for lease address/prefix heaps.
440 * Callback when an address's position in the heap changes.
443 lease_index_changed(void *iasubopt
, unsigned int new_heap_index
) {
444 ((struct iasubopt
*)iasubopt
)-> heap_index
= new_heap_index
;
449 * Create a new IPv6 lease pool structure.
451 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
452 * initialized to NULL
455 ipv6_pool_allocate(struct ipv6_pool
**pool
, u_int16_t type
,
456 const struct in6_addr
*start_addr
, int bits
,
457 int units
, const char *file
, int line
) {
458 struct ipv6_pool
*tmp
;
461 log_error("%s(%d): NULL pointer reference", file
, line
);
462 return DHCP_R_INVALIDARG
;
465 log_error("%s(%d): non-NULL pointer", file
, line
);
466 return DHCP_R_INVALIDARG
;
469 tmp
= dmalloc(sizeof(*tmp
), file
, line
);
471 return ISC_R_NOMEMORY
;
475 tmp
->pool_type
= type
;
476 tmp
->start_addr
= *start_addr
;
479 if (!iasubopt_new_hash(&tmp
->leases
, DEFAULT_HASH_SIZE
, file
, line
)) {
480 dfree(tmp
, file
, line
);
481 return ISC_R_NOMEMORY
;
483 if (isc_heap_create(dhcp_gbl_ctx
.mctx
, lease_older
, lease_index_changed
,
484 0, &(tmp
->active_timeouts
)) != ISC_R_SUCCESS
) {
485 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
486 dfree(tmp
, file
, line
);
487 return ISC_R_NOMEMORY
;
489 if (isc_heap_create(dhcp_gbl_ctx
.mctx
, lease_older
, lease_index_changed
,
490 0, &(tmp
->inactive_timeouts
)) != ISC_R_SUCCESS
) {
491 isc_heap_destroy(&(tmp
->active_timeouts
));
492 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
493 dfree(tmp
, file
, line
);
494 return ISC_R_NOMEMORY
;
498 return ISC_R_SUCCESS
;
502 * Reference an IPv6 pool structure.
504 * - pool must be a pointer to a (struct pool *) pointer previously
505 * initialized to NULL
508 ipv6_pool_reference(struct ipv6_pool
**pool
, struct ipv6_pool
*src
,
509 const char *file
, int line
) {
511 log_error("%s(%d): NULL pointer reference", file
, line
);
512 return DHCP_R_INVALIDARG
;
515 log_error("%s(%d): non-NULL pointer", file
, line
);
516 return DHCP_R_INVALIDARG
;
519 log_error("%s(%d): NULL pointer reference", file
, line
);
520 return DHCP_R_INVALIDARG
;
524 return ISC_R_SUCCESS
;
528 * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed
529 * to prevent the lease from being garbage collected out from under the
532 * The references are made from the hash and from the heap. The following
533 * helper functions dereference these when a pool is destroyed.
537 * Helper function for pool cleanup.
538 * Dereference each of the hash entries in a pool.
541 dereference_hash_entry(const void *name
, unsigned len
, void *value
) {
542 struct iasubopt
*iasubopt
= (struct iasubopt
*)value
;
544 iasubopt_dereference(&iasubopt
, MDL
);
545 return ISC_R_SUCCESS
;
549 * Helper function for pool cleanup.
550 * Dereference each of the heap entries in a pool.
553 dereference_heap_entry(void *value
, void *dummy
) {
554 struct iasubopt
*iasubopt
= (struct iasubopt
*)value
;
556 iasubopt_dereference(&iasubopt
, MDL
);
561 * Dereference an IPv6 pool structure.
563 * If it is the last reference, then the memory for the
564 * structure is freed.
567 ipv6_pool_dereference(struct ipv6_pool
**pool
, const char *file
, int line
) {
568 struct ipv6_pool
*tmp
;
570 if ((pool
== NULL
) || (*pool
== NULL
)) {
571 log_error("%s(%d): NULL pointer", file
, line
);
572 return DHCP_R_INVALIDARG
;
579 if (tmp
->refcnt
< 0) {
580 log_error("%s(%d): negative refcnt", file
, line
);
583 if (tmp
->refcnt
== 0) {
584 iasubopt_hash_foreach(tmp
->leases
, dereference_hash_entry
);
585 iasubopt_free_hash_table(&(tmp
->leases
), file
, line
);
586 isc_heap_foreach(tmp
->active_timeouts
,
587 dereference_heap_entry
, NULL
);
588 isc_heap_destroy(&(tmp
->active_timeouts
));
589 isc_heap_foreach(tmp
->inactive_timeouts
,
590 dereference_heap_entry
, NULL
);
591 isc_heap_destroy(&(tmp
->inactive_timeouts
));
592 dfree(tmp
, file
, line
);
595 return ISC_R_SUCCESS
;
599 * Create an address by hashing the input, and using that for
600 * the non-network part.
603 build_address6(struct in6_addr
*addr
,
604 const struct in6_addr
*net_start_addr
, int net_bits
,
605 const struct data_string
*input
) {
613 * Use MD5 to get a nice 128 bit hash of the input.
614 * Yes, we know MD5 isn't cryptographically sound.
618 isc_md5_update(&ctx
, input
->data
, input
->len
);
619 isc_md5_final(&ctx
, (unsigned char *)addr
);
622 * Copy the [0..128] network bits over.
625 net_str
= (const char *)net_start_addr
;
626 net_bytes
= net_bits
/ 8;
627 for (i
= 0; i
< net_bytes
; i
++) {
630 switch (net_bits
% 8) {
631 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
632 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
633 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
634 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
635 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
636 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
637 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
641 * Set the universal/local bit ("u bit") to zero for /64s. The
642 * individual/group bit ("g bit") is unchanged, because the g-bit
643 * has no meaning when the u-bit is cleared.
650 * Create a temporary address by a variant of RFC 4941 algo.
651 * Note: this should not be used for prefixes shorter than 64 bits.
654 build_temporary6(struct in6_addr
*addr
,
655 const struct in6_addr
*net_start_addr
, int net_bits
,
656 const struct data_string
*input
) {
657 static u_int32_t history
[2];
658 static u_int32_t counter
= 0;
660 unsigned char md
[16];
663 * First time/time to reseed.
664 * Please use a good pseudo-random generator here!
667 isc_random_get(&history
[0]);
668 isc_random_get(&history
[1]);
672 * Use MD5 as recommended by RFC 4941.
675 isc_md5_update(&ctx
, (unsigned char *)&history
[0], 8UL);
676 isc_md5_update(&ctx
, input
->data
, input
->len
);
677 isc_md5_final(&ctx
, md
);
682 if (net_bits
== 64) {
683 memcpy(&addr
->s6_addr
[0], &net_start_addr
->s6_addr
[0], 8);
684 memcpy(&addr
->s6_addr
[8], md
, 8);
685 addr
->s6_addr
[8] &= ~0x02;
693 * Copy the [0..128] network bits over.
696 net_str
= (const char *)net_start_addr
;
697 net_bytes
= net_bits
/ 8;
698 for (i
= 0; i
< net_bytes
; i
++) {
701 memcpy(str
+ net_bytes
, md
, 16 - net_bytes
);
702 switch (net_bits
% 8) {
703 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
704 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
705 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
706 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
707 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
708 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
709 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
715 * Save history for the next call.
717 memcpy((unsigned char *)&history
[0], md
+ 8, 8);
721 /* Reserved Subnet Router Anycast ::0:0:0:0. */
722 static struct in6_addr rtany
;
723 /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */
724 static struct in6_addr resany
;
727 * Create a lease for the given address and client duid.
729 * - pool must be a pointer to a (struct pool *) pointer previously
730 * initialized to NULL
732 * Right now we simply hash the DUID, and if we get a collision, we hash
733 * again until we find a free address. We try this a fixed number of times,
734 * to avoid getting stuck in a loop (this is important on small pools
735 * where we can run out of space).
737 * We return the number of attempts that it took to find an available
738 * lease. This tells callers when a pool is are filling up, as
739 * well as an indication of how full the pool is; statistically the
740 * more full a pool is the more attempts must be made before finding
741 * a free lease. Realistically this will only happen in very full
744 * We probably want different algorithms depending on the network size, in
748 create_lease6(struct ipv6_pool
*pool
, struct iasubopt
**addr
,
749 unsigned int *attempts
,
750 const struct data_string
*uid
, time_t soft_lifetime_end_time
) {
751 struct data_string ds
;
753 struct iasubopt
*test_iaaddr
;
754 struct data_string new_ds
;
755 struct iasubopt
*iaaddr
;
757 isc_boolean_t reserved_iid
;
758 static isc_boolean_t init_resiid
= ISC_FALSE
;
761 * Fill the reserved IIDs.
764 memset(&rtany
, 0, 16);
765 memset(&resany
, 0, 8);
766 resany
.s6_addr
[8] = 0xfd;
767 memset(&resany
.s6_addr
[9], 0xff, 6);
768 init_resiid
= ISC_TRUE
;
772 * Use the UID as our initial seed for the hash
774 memset(&ds
, 0, sizeof(ds
));
775 data_string_copy(&ds
, (struct data_string
*)uid
, MDL
);
780 * Give up at some point.
782 if (++(*attempts
) > 100) {
783 data_string_forget(&ds
, MDL
);
784 return ISC_R_NORESOURCES
;
790 switch (pool
->pool_type
) {
793 build_address6(&tmp
, &pool
->start_addr
,
797 /* temporary address */
798 build_temporary6(&tmp
, &pool
->start_addr
,
803 log_error("create_lease6: prefix pool.");
804 return DHCP_R_INVALIDARG
;
806 log_error("create_lease6: untyped pool.");
807 return DHCP_R_INVALIDARG
;
811 * Avoid reserved interface IDs. (cf. RFC 5453)
813 reserved_iid
= ISC_FALSE
;
814 if (memcmp(&tmp
.s6_addr
[8], &rtany
.s6_addr
[8], 8) == 0) {
815 reserved_iid
= ISC_TRUE
;
818 (memcmp(&tmp
.s6_addr
[8], &resany
.s6_addr
[8], 7) == 0) &&
819 ((tmp
.s6_addr
[15] & 0x80) == 0x80)) {
820 reserved_iid
= ISC_TRUE
;
824 * If this address is not in use, we're happy with it
828 (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
829 &tmp
, sizeof(tmp
), MDL
) == 0)) {
832 if (test_iaaddr
!= NULL
)
833 iasubopt_dereference(&test_iaaddr
, MDL
);
836 * Otherwise, we create a new input, adding the address
838 memset(&new_ds
, 0, sizeof(new_ds
));
839 new_ds
.len
= ds
.len
+ sizeof(tmp
);
840 if (!buffer_allocate(&new_ds
.buffer
, new_ds
.len
, MDL
)) {
841 data_string_forget(&ds
, MDL
);
842 return ISC_R_NOMEMORY
;
844 new_ds
.data
= new_ds
.buffer
->data
;
845 memcpy(new_ds
.buffer
->data
, ds
.data
, ds
.len
);
846 memcpy(new_ds
.buffer
->data
+ ds
.len
, &tmp
, sizeof(tmp
));
847 data_string_forget(&ds
, MDL
);
848 data_string_copy(&ds
, &new_ds
, MDL
);
849 data_string_forget(&new_ds
, MDL
);
852 data_string_forget(&ds
, MDL
);
855 * We're happy with the address, create an IAADDR
859 result
= iasubopt_allocate(&iaaddr
, MDL
);
860 if (result
!= ISC_R_SUCCESS
) {
864 memcpy(&iaaddr
->addr
, &tmp
, sizeof(iaaddr
->addr
));
867 * Add the lease to the pool (note state is free, not active?!).
869 result
= add_lease6(pool
, iaaddr
, soft_lifetime_end_time
);
870 if (result
== ISC_R_SUCCESS
) {
871 iasubopt_reference(addr
, iaaddr
, MDL
);
873 iasubopt_dereference(&iaaddr
, MDL
);
878 * Put a lease in the pool directly. This is intended to be used when
879 * loading leases from the file.
882 add_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
,
883 time_t valid_lifetime_end_time
) {
884 isc_result_t insert_result
;
885 struct iasubopt
*test_iasubopt
;
886 struct iasubopt
*tmp_iasubopt
;
888 /* If a state was not assigned by the caller, assume active. */
889 if (lease
->state
== 0)
890 lease
->state
= FTS_ACTIVE
;
892 ipv6_pool_reference(&lease
->ipv6_pool
, pool
, MDL
);
895 * If this IAADDR/PREFIX is already in our structures, remove the
898 test_iasubopt
= NULL
;
899 if (iasubopt_hash_lookup(&test_iasubopt
, pool
->leases
,
900 &lease
->addr
, sizeof(lease
->addr
), MDL
)) {
901 /* XXX: we should probably ask the lease what heap it is on
902 * (as a consistency check).
903 * XXX: we should probably have one function to "put this lease
904 * on its heap" rather than doing these if's everywhere. If
905 * you add more states to this list, don't.
907 if ((test_iasubopt
->state
== FTS_ACTIVE
) ||
908 (test_iasubopt
->state
== FTS_ABANDONED
)) {
909 isc_heap_delete(pool
->active_timeouts
,
910 test_iasubopt
->heap_index
);
913 isc_heap_delete(pool
->inactive_timeouts
,
914 test_iasubopt
->heap_index
);
915 pool
->num_inactive
--;
918 iasubopt_hash_delete(pool
->leases
, &test_iasubopt
->addr
,
919 sizeof(test_iasubopt
->addr
), MDL
);
922 * We're going to do a bit of evil trickery here.
924 * We need to dereference the entry once to remove our
925 * current reference (in test_iasubopt), and then one
926 * more time to remove the reference left when the
927 * address was added to the pool before.
929 tmp_iasubopt
= test_iasubopt
;
930 iasubopt_dereference(&test_iasubopt
, MDL
);
931 iasubopt_dereference(&tmp_iasubopt
, MDL
);
935 * Add IAADDR/PREFIX to our structures.
938 iasubopt_reference(&tmp_iasubopt
, lease
, MDL
);
939 if ((tmp_iasubopt
->state
== FTS_ACTIVE
) ||
940 (tmp_iasubopt
->state
== FTS_ABANDONED
)) {
941 tmp_iasubopt
->hard_lifetime_end_time
= valid_lifetime_end_time
;
942 iasubopt_hash_add(pool
->leases
, &tmp_iasubopt
->addr
,
943 sizeof(tmp_iasubopt
->addr
), lease
, MDL
);
944 insert_result
= isc_heap_insert(pool
->active_timeouts
,
946 if (insert_result
== ISC_R_SUCCESS
)
949 tmp_iasubopt
->soft_lifetime_end_time
= valid_lifetime_end_time
;
950 insert_result
= isc_heap_insert(pool
->inactive_timeouts
,
952 if (insert_result
== ISC_R_SUCCESS
)
953 pool
->num_inactive
++;
955 if (insert_result
!= ISC_R_SUCCESS
) {
956 iasubopt_hash_delete(pool
->leases
, &lease
->addr
,
957 sizeof(lease
->addr
), MDL
);
958 iasubopt_dereference(&tmp_iasubopt
, MDL
);
959 return insert_result
;
963 * Note: we intentionally leave tmp_iasubopt referenced; there
964 * is a reference in the heap/hash, after all.
967 return ISC_R_SUCCESS
;
971 * Determine if an address is present in a pool or not.
974 lease6_exists(const struct ipv6_pool
*pool
, const struct in6_addr
*addr
) {
975 struct iasubopt
*test_iaaddr
;
978 if (iasubopt_hash_lookup(&test_iaaddr
, pool
->leases
,
979 (void *)addr
, sizeof(*addr
), MDL
)) {
980 iasubopt_dereference(&test_iaaddr
, MDL
);
988 * Put the lease on our active pool.
991 move_lease_to_active(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
992 isc_result_t insert_result
;
995 old_heap_index
= lease
->heap_index
;
996 insert_result
= isc_heap_insert(pool
->active_timeouts
, lease
);
997 if (insert_result
== ISC_R_SUCCESS
) {
998 iasubopt_hash_add(pool
->leases
, &lease
->addr
,
999 sizeof(lease
->addr
), lease
, MDL
);
1000 isc_heap_delete(pool
->inactive_timeouts
, old_heap_index
);
1002 pool
->num_inactive
--;
1003 lease
->state
= FTS_ACTIVE
;
1005 return insert_result
;
1009 * Renew an lease in the pool.
1011 * To do this, first set the new hard_lifetime_end_time for the resource,
1012 * and then invoke renew_lease6() on it.
1014 * WARNING: lease times must only be extended, never reduced!!!
1017 renew_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1019 * If we're already active, then we can just move our expiration
1020 * time down the heap.
1022 * If we're abandoned then we are already on the active list
1023 * but we need to retag the lease and move our expiration
1024 * from infinite to the current value
1026 * Otherwise, we have to move from the inactive heap to the
1029 if (lease
->state
== FTS_ACTIVE
) {
1030 isc_heap_decreased(pool
->active_timeouts
, lease
->heap_index
);
1031 return ISC_R_SUCCESS
;
1032 } else if (lease
->state
== FTS_ABANDONED
) {
1033 char tmp_addr
[INET6_ADDRSTRLEN
];
1034 lease
->state
= FTS_ACTIVE
;
1035 isc_heap_increased(pool
->active_timeouts
, lease
->heap_index
);
1036 log_info("Reclaiming previously abandoned address %s",
1037 inet_ntop(AF_INET6
, &(lease
->addr
), tmp_addr
,
1039 return ISC_R_SUCCESS
;
1041 return move_lease_to_active(pool
, lease
);
1046 * Put the lease on our inactive pool, with the specified state.
1049 move_lease_to_inactive(struct ipv6_pool
*pool
, struct iasubopt
*lease
,
1050 binding_state_t state
) {
1051 isc_result_t insert_result
;
1054 old_heap_index
= lease
->heap_index
;
1055 insert_result
= isc_heap_insert(pool
->inactive_timeouts
, lease
);
1056 if (insert_result
== ISC_R_SUCCESS
) {
1057 #if defined (NSUPDATE)
1058 /* Process events upon expiration. */
1059 if (pool
->pool_type
!= D6O_IA_PD
) {
1060 ddns_removals(NULL
, lease
, NULL
, ISC_FALSE
);
1064 /* Binding scopes are no longer valid after expiry or
1067 if (lease
->scope
!= NULL
) {
1068 binding_scope_dereference(&lease
->scope
, MDL
);
1071 iasubopt_hash_delete(pool
->leases
,
1072 &lease
->addr
, sizeof(lease
->addr
), MDL
);
1073 isc_heap_delete(pool
->active_timeouts
, old_heap_index
);
1074 lease
->state
= state
;
1076 pool
->num_inactive
++;
1078 return insert_result
;
1082 * Expire the oldest lease if it's lifetime_end_time is
1083 * older than the given time.
1085 * - leasep must be a pointer to a (struct iasubopt *) pointer previously
1086 * initialized to NULL
1088 * On return leasep has a reference to the removed entry. It is left
1089 * pointing to NULL if the oldest lease has not expired.
1092 expire_lease6(struct iasubopt
**leasep
, struct ipv6_pool
*pool
, time_t now
) {
1093 struct iasubopt
*tmp
;
1094 isc_result_t result
;
1096 if (leasep
== NULL
) {
1097 log_error("%s(%d): NULL pointer reference", MDL
);
1098 return DHCP_R_INVALIDARG
;
1100 if (*leasep
!= NULL
) {
1101 log_error("%s(%d): non-NULL pointer", MDL
);
1102 return DHCP_R_INVALIDARG
;
1105 if (pool
->num_active
> 0) {
1106 tmp
= (struct iasubopt
*)
1107 isc_heap_element(pool
->active_timeouts
, 1);
1108 if (now
> tmp
->hard_lifetime_end_time
) {
1109 result
= move_lease_to_inactive(pool
, tmp
,
1111 if (result
== ISC_R_SUCCESS
) {
1112 iasubopt_reference(leasep
, tmp
, MDL
);
1117 return ISC_R_SUCCESS
;
1122 * For a declined lease, leave it on the "active" pool, but mark
1123 * it as declined. Give it an infinite (well, really long) life.
1126 decline_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1127 isc_result_t result
;
1129 if ((lease
->state
!= FTS_ACTIVE
) &&
1130 (lease
->state
!= FTS_ABANDONED
)) {
1131 result
= move_lease_to_active(pool
, lease
);
1132 if (result
!= ISC_R_SUCCESS
) {
1136 lease
->state
= FTS_ABANDONED
;
1137 lease
->hard_lifetime_end_time
= MAX_TIME
;
1138 isc_heap_decreased(pool
->active_timeouts
, lease
->heap_index
);
1139 return ISC_R_SUCCESS
;
1143 * Put the returned lease on our inactive pool.
1146 release_lease6(struct ipv6_pool
*pool
, struct iasubopt
*lease
) {
1147 if (lease
->state
== FTS_ACTIVE
) {
1148 return move_lease_to_inactive(pool
, lease
, FTS_RELEASED
);
1150 return ISC_R_SUCCESS
;
1155 * Create a prefix by hashing the input, and using that for
1156 * the part subject to allocation.
1159 build_prefix6(struct in6_addr
*pref
,
1160 const struct in6_addr
*net_start_pref
,
1161 int pool_bits
, int pref_bits
,
1162 const struct data_string
*input
) {
1167 const char *net_str
;
1170 * Use MD5 to get a nice 128 bit hash of the input.
1171 * Yes, we know MD5 isn't cryptographically sound.
1172 * No, we don't care.
1175 isc_md5_update(&ctx
, input
->data
, input
->len
);
1176 isc_md5_final(&ctx
, (unsigned char *)pref
);
1179 * Copy the network bits over.
1182 net_str
= (const char *)net_start_pref
;
1183 net_bytes
= pool_bits
/ 8;
1184 for (i
= 0; i
< net_bytes
; i
++) {
1185 str
[i
] = net_str
[i
];
1188 switch (pool_bits
% 8) {
1189 case 1: str
[i
] = (str
[i
] & 0x7F) | (net_str
[i
] & 0x80); break;
1190 case 2: str
[i
] = (str
[i
] & 0x3F) | (net_str
[i
] & 0xC0); break;
1191 case 3: str
[i
] = (str
[i
] & 0x1F) | (net_str
[i
] & 0xE0); break;
1192 case 4: str
[i
] = (str
[i
] & 0x0F) | (net_str
[i
] & 0xF0); break;
1193 case 5: str
[i
] = (str
[i
] & 0x07) | (net_str
[i
] & 0xF8); break;
1194 case 6: str
[i
] = (str
[i
] & 0x03) | (net_str
[i
] & 0xFC); break;
1195 case 7: str
[i
] = (str
[i
] & 0x01) | (net_str
[i
] & 0xFE); break;
1198 * Zero the remaining bits.
1200 net_bytes
= pref_bits
/ 8;
1201 for (i
=net_bytes
+1; i
<16; i
++) {
1205 switch (pref_bits
% 8) {
1206 case 0: str
[i
] &= 0; break;
1207 case 1: str
[i
] &= 0x80; break;
1208 case 2: str
[i
] &= 0xC0; break;
1209 case 3: str
[i
] &= 0xE0; break;
1210 case 4: str
[i
] &= 0xF0; break;
1211 case 5: str
[i
] &= 0xF8; break;
1212 case 6: str
[i
] &= 0xFC; break;
1213 case 7: str
[i
] &= 0xFE; break;
1218 * Create a lease for the given prefix and client duid.
1220 * - pool must be a pointer to a (struct pool *) pointer previously
1221 * initialized to NULL
1223 * Right now we simply hash the DUID, and if we get a collision, we hash
1224 * again until we find a free prefix. We try this a fixed number of times,
1225 * to avoid getting stuck in a loop (this is important on small pools
1226 * where we can run out of space).
1228 * We return the number of attempts that it took to find an available
1229 * prefix. This tells callers when a pool is are filling up, as
1230 * well as an indication of how full the pool is; statistically the
1231 * more full a pool is the more attempts must be made before finding
1232 * a free prefix. Realistically this will only happen in very full
1235 * We probably want different algorithms depending on the network size, in
1239 create_prefix6(struct ipv6_pool
*pool
, struct iasubopt
**pref
,
1240 unsigned int *attempts
,
1241 const struct data_string
*uid
,
1242 time_t soft_lifetime_end_time
) {
1243 struct data_string ds
;
1244 struct in6_addr tmp
;
1245 struct iasubopt
*test_iapref
;
1246 struct data_string new_ds
;
1247 struct iasubopt
*iapref
;
1248 isc_result_t result
;
1251 * Use the UID as our initial seed for the hash
1253 memset(&ds
, 0, sizeof(ds
));
1254 data_string_copy(&ds
, (struct data_string
*)uid
, MDL
);
1259 * Give up at some point.
1261 if (++(*attempts
) > 10) {
1262 data_string_forget(&ds
, MDL
);
1263 return ISC_R_NORESOURCES
;
1269 build_prefix6(&tmp
, &pool
->start_addr
,
1270 pool
->bits
, pool
->units
, &ds
);
1273 * If this prefix is not in use, we're happy with it
1276 if (iasubopt_hash_lookup(&test_iapref
, pool
->leases
,
1277 &tmp
, sizeof(tmp
), MDL
) == 0) {
1280 iasubopt_dereference(&test_iapref
, MDL
);
1283 * Otherwise, we create a new input, adding the prefix
1285 memset(&new_ds
, 0, sizeof(new_ds
));
1286 new_ds
.len
= ds
.len
+ sizeof(tmp
);
1287 if (!buffer_allocate(&new_ds
.buffer
, new_ds
.len
, MDL
)) {
1288 data_string_forget(&ds
, MDL
);
1289 return ISC_R_NOMEMORY
;
1291 new_ds
.data
= new_ds
.buffer
->data
;
1292 memcpy(new_ds
.buffer
->data
, ds
.data
, ds
.len
);
1293 memcpy(new_ds
.buffer
->data
+ ds
.len
, &tmp
, sizeof(tmp
));
1294 data_string_forget(&ds
, MDL
);
1295 data_string_copy(&ds
, &new_ds
, MDL
);
1296 data_string_forget(&new_ds
, MDL
);
1299 data_string_forget(&ds
, MDL
);
1302 * We're happy with the prefix, create an IAPREFIX
1306 result
= iasubopt_allocate(&iapref
, MDL
);
1307 if (result
!= ISC_R_SUCCESS
) {
1310 iapref
->plen
= (u_int8_t
)pool
->units
;
1311 memcpy(&iapref
->addr
, &tmp
, sizeof(iapref
->addr
));
1314 * Add the prefix to the pool (note state is free, not active?!).
1316 result
= add_lease6(pool
, iapref
, soft_lifetime_end_time
);
1317 if (result
== ISC_R_SUCCESS
) {
1318 iasubopt_reference(pref
, iapref
, MDL
);
1320 iasubopt_dereference(&iapref
, MDL
);
1325 * Determine if a prefix is present in a pool or not.
1328 prefix6_exists(const struct ipv6_pool
*pool
,
1329 const struct in6_addr
*pref
, u_int8_t plen
) {
1330 struct iasubopt
*test_iapref
;
1332 if ((int)plen
!= pool
->units
)
1336 if (iasubopt_hash_lookup(&test_iapref
, pool
->leases
,
1337 (void *)pref
, sizeof(*pref
), MDL
)) {
1338 iasubopt_dereference(&test_iapref
, MDL
);
1346 * Mark an IPv6 address/prefix as unavailable from a pool.
1348 * This is used for host entries and the addresses of the server itself.
1351 mark_lease_unavailable(struct ipv6_pool
*pool
, const struct in6_addr
*addr
) {
1352 struct iasubopt
*dummy_iasubopt
;
1353 isc_result_t result
;
1355 dummy_iasubopt
= NULL
;
1356 result
= iasubopt_allocate(&dummy_iasubopt
, MDL
);
1357 if (result
== ISC_R_SUCCESS
) {
1358 dummy_iasubopt
->addr
= *addr
;
1359 iasubopt_hash_add(pool
->leases
, &dummy_iasubopt
->addr
,
1360 sizeof(*addr
), dummy_iasubopt
, MDL
);
1369 add_ipv6_pool(struct ipv6_pool
*pool
) {
1370 struct ipv6_pool
**new_pools
;
1372 new_pools
= dmalloc(sizeof(struct ipv6_pool
*) * (num_pools
+1), MDL
);
1373 if (new_pools
== NULL
) {
1374 return ISC_R_NOMEMORY
;
1377 if (num_pools
> 0) {
1378 memcpy(new_pools
, pools
,
1379 sizeof(struct ipv6_pool
*) * num_pools
);
1384 pools
[num_pools
] = NULL
;
1385 ipv6_pool_reference(&pools
[num_pools
], pool
, MDL
);
1387 return ISC_R_SUCCESS
;
1391 cleanup_old_expired(struct ipv6_pool
*pool
) {
1392 struct iasubopt
*tmp
;
1394 struct ia_xx
*ia_active
;
1395 unsigned char *tmpd
;
1398 while (pool
->num_inactive
> 0) {
1399 tmp
= (struct iasubopt
*)
1400 isc_heap_element(pool
->inactive_timeouts
, 1);
1401 if (tmp
->hard_lifetime_end_time
!= 0) {
1402 timeout
= tmp
->hard_lifetime_end_time
;
1403 timeout
+= EXPIRED_IPV6_CLEANUP_TIME
;
1405 timeout
= tmp
->soft_lifetime_end_time
;
1407 if (cur_time
< timeout
) {
1411 isc_heap_delete(pool
->inactive_timeouts
, tmp
->heap_index
);
1412 pool
->num_inactive
--;
1414 if (tmp
->ia
!= NULL
) {
1416 * Check to see if this IA is in an active list,
1417 * but has no remaining resources. If so, remove it
1418 * from the active list.
1421 ia_reference(&ia
, tmp
->ia
, MDL
);
1422 ia_remove_iasubopt(ia
, tmp
, MDL
);
1424 tmpd
= (unsigned char *)ia
->iaid_duid
.data
;
1425 if ((ia
->ia_type
== D6O_IA_NA
) &&
1426 (ia
->num_iasubopt
<= 0) &&
1427 (ia_hash_lookup(&ia_active
, ia_na_active
, tmpd
,
1428 ia
->iaid_duid
.len
, MDL
) == 0) &&
1429 (ia_active
== ia
)) {
1430 ia_hash_delete(ia_na_active
, tmpd
,
1431 ia
->iaid_duid
.len
, MDL
);
1433 if ((ia
->ia_type
== D6O_IA_TA
) &&
1434 (ia
->num_iasubopt
<= 0) &&
1435 (ia_hash_lookup(&ia_active
, ia_ta_active
, tmpd
,
1436 ia
->iaid_duid
.len
, MDL
) == 0) &&
1437 (ia_active
== ia
)) {
1438 ia_hash_delete(ia_ta_active
, tmpd
,
1439 ia
->iaid_duid
.len
, MDL
);
1441 if ((ia
->ia_type
== D6O_IA_PD
) &&
1442 (ia
->num_iasubopt
<= 0) &&
1443 (ia_hash_lookup(&ia_active
, ia_pd_active
, tmpd
,
1444 ia
->iaid_duid
.len
, MDL
) == 0) &&
1445 (ia_active
== ia
)) {
1446 ia_hash_delete(ia_pd_active
, tmpd
,
1447 ia
->iaid_duid
.len
, MDL
);
1449 ia_dereference(&ia
, MDL
);
1451 iasubopt_dereference(&tmp
, MDL
);
1456 lease_timeout_support(void *vpool
) {
1457 struct ipv6_pool
*pool
;
1458 struct iasubopt
*lease
;
1460 pool
= (struct ipv6_pool
*)vpool
;
1463 * Get the next lease scheduled to expire.
1465 * Note that if there are no leases in the pool,
1466 * expire_lease6() will return ISC_R_SUCCESS with
1469 * expire_lease6() will call move_lease_to_inactive() which
1470 * calls ddns_removals() do we want that on the standard
1471 * expiration timer or a special 'depref' timer? Original
1472 * query from DH, moved here by SAR.
1475 if (expire_lease6(&lease
, pool
, cur_time
) != ISC_R_SUCCESS
) {
1478 if (lease
== NULL
) {
1482 write_ia(lease
->ia
);
1484 iasubopt_dereference(&lease
, MDL
);
1488 * Do some cleanup of our expired leases.
1490 cleanup_old_expired(pool
);
1493 * Schedule next round of expirations.
1495 schedule_lease_timeout(pool
);
1499 * For a given pool, add a timer that will remove the next
1503 schedule_lease_timeout(struct ipv6_pool
*pool
) {
1504 struct iasubopt
*tmp
;
1506 time_t next_timeout
;
1509 next_timeout
= MAX_TIME
;
1511 if (pool
->num_active
> 0) {
1512 tmp
= (struct iasubopt
*)
1513 isc_heap_element(pool
->active_timeouts
, 1);
1514 if (tmp
->hard_lifetime_end_time
< next_timeout
) {
1515 next_timeout
= tmp
->hard_lifetime_end_time
+ 1;
1519 if (pool
->num_inactive
> 0) {
1520 tmp
= (struct iasubopt
*)
1521 isc_heap_element(pool
->inactive_timeouts
, 1);
1522 if (tmp
->hard_lifetime_end_time
!= 0) {
1523 timeout
= tmp
->hard_lifetime_end_time
;
1524 timeout
+= EXPIRED_IPV6_CLEANUP_TIME
;
1526 timeout
= tmp
->soft_lifetime_end_time
+ 1;
1528 if (timeout
< next_timeout
) {
1529 next_timeout
= timeout
;
1533 if (next_timeout
< MAX_TIME
) {
1534 tv
.tv_sec
= next_timeout
;
1536 add_timeout(&tv
, lease_timeout_support
, pool
,
1537 (tvref_t
)ipv6_pool_reference
,
1538 (tvunref_t
)ipv6_pool_dereference
);
1543 * Schedule timeouts across all pools.
1546 schedule_all_ipv6_lease_timeouts(void) {
1549 for (i
=0; i
<num_pools
; i
++) {
1550 schedule_lease_timeout(pools
[i
]);
1555 * Given an address and the length of the network mask, return
1556 * only the network portion.
1560 * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
1561 * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
1564 ipv6_network_portion(struct in6_addr
*result
,
1565 const struct in6_addr
*addr
, int bits
) {
1566 unsigned char *addrp
;
1572 static const unsigned char bitmasks
[] = {
1573 0x00, 0xFE, 0xFC, 0xF8,
1574 0xF0, 0xE0, 0xC0, 0x80,
1578 * Sanity check our bits. ;)
1580 if ((bits
< 0) || (bits
> 128)) {
1581 log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
1586 * Copy our address portion.
1589 addrp
= ((unsigned char *)result
) + 15;
1592 * Zero out masked portion.
1594 mask_bits
= 128 - bits
;
1595 bytes
= mask_bits
/ 8;
1596 extra_bits
= mask_bits
% 8;
1598 for (i
=0; i
<bytes
; i
++) {
1603 *addrp
&= bitmasks
[extra_bits
];
1608 * Determine if the given address/prefix is in the pool.
1611 ipv6_in_pool(const struct in6_addr
*addr
, const struct ipv6_pool
*pool
) {
1612 struct in6_addr tmp
;
1614 ipv6_network_portion(&tmp
, addr
, pool
->bits
);
1615 if (memcmp(&tmp
, &pool
->start_addr
, sizeof(tmp
)) == 0) {
1623 * Find the pool that contains the given address.
1625 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1626 * initialized to NULL
1629 find_ipv6_pool(struct ipv6_pool
**pool
, u_int16_t type
,
1630 const struct in6_addr
*addr
) {
1634 log_error("%s(%d): NULL pointer reference", MDL
);
1635 return DHCP_R_INVALIDARG
;
1637 if (*pool
!= NULL
) {
1638 log_error("%s(%d): non-NULL pointer", MDL
);
1639 return DHCP_R_INVALIDARG
;
1642 for (i
=0; i
<num_pools
; i
++) {
1643 if (pools
[i
]->pool_type
!= type
)
1645 if (ipv6_in_pool(addr
, pools
[i
])) {
1646 ipv6_pool_reference(pool
, pools
[i
], MDL
);
1647 return ISC_R_SUCCESS
;
1650 return ISC_R_NOTFOUND
;
1654 * Helper function for the various functions that act across all
1658 change_leases(struct ia_xx
*ia
,
1659 isc_result_t (*change_func
)(struct ipv6_pool
*,
1660 struct iasubopt
*)) {
1661 isc_result_t retval
;
1662 isc_result_t renew_retval
;
1663 struct ipv6_pool
*pool
;
1664 struct in6_addr
*addr
;
1667 retval
= ISC_R_SUCCESS
;
1668 for (i
=0; i
<ia
->num_iasubopt
; i
++) {
1670 addr
= &ia
->iasubopt
[i
]->addr
;
1671 if (find_ipv6_pool(&pool
, ia
->ia_type
,
1672 addr
) == ISC_R_SUCCESS
) {
1673 renew_retval
= change_func(pool
, ia
->iasubopt
[i
]);
1674 if (renew_retval
!= ISC_R_SUCCESS
) {
1675 retval
= renew_retval
;
1678 /* XXXsk: should we warn if we don't find a pool? */
1684 * Renew all leases in an IA from all pools.
1686 * The new hard_lifetime_end_time should be updated for the addresses/prefixes.
1688 * WARNING: lease times must only be extended, never reduced!!!
1691 renew_leases(struct ia_xx
*ia
) {
1692 return change_leases(ia
, renew_lease6
);
1696 * Release all leases in an IA from all pools.
1699 release_leases(struct ia_xx
*ia
) {
1700 return change_leases(ia
, release_lease6
);
1704 * Decline all leases in an IA from all pools.
1707 decline_leases(struct ia_xx
*ia
) {
1708 return change_leases(ia
, decline_lease6
);
1713 * Helper function to output leases.
1715 static int write_error
;
1718 write_ia_leases(const void *name
, unsigned len
, void *value
) {
1719 struct ia_xx
*ia
= (struct ia_xx
*)value
;
1722 if (!write_ia(ia
)) {
1726 return ISC_R_SUCCESS
;
1730 * Write all DHCPv6 information.
1733 write_leases6(void) {
1735 write_server_duid();
1736 ia_hash_foreach(ia_na_active
, write_ia_leases
);
1740 ia_hash_foreach(ia_ta_active
, write_ia_leases
);
1744 ia_hash_foreach(ia_pd_active
, write_ia_leases
);
1753 mark_hosts_unavailable_support(const void *name
, unsigned len
, void *value
) {
1754 struct host_decl
*h
;
1755 struct data_string fixed_addr
;
1756 struct in6_addr addr
;
1757 struct ipv6_pool
*p
;
1759 h
= (struct host_decl
*)value
;
1762 * If the host has no address, we don't need to mark anything.
1764 if (h
->fixed_addr
== NULL
) {
1765 return ISC_R_SUCCESS
;
1769 * Evaluate the fixed address.
1771 memset(&fixed_addr
, 0, sizeof(fixed_addr
));
1772 if (!evaluate_option_cache(&fixed_addr
, NULL
, NULL
, NULL
, NULL
, NULL
,
1773 &global_scope
, h
->fixed_addr
, MDL
)) {
1774 log_error("mark_hosts_unavailable: "
1775 "error evaluating host address.");
1776 return ISC_R_SUCCESS
;
1778 if (fixed_addr
.len
!= 16) {
1779 log_error("mark_hosts_unavailable: "
1780 "host address is not 128 bits.");
1781 return ISC_R_SUCCESS
;
1783 memcpy(&addr
, fixed_addr
.data
, 16);
1784 data_string_forget(&fixed_addr
, MDL
);
1787 * Find the pool holding this host, and mark the address.
1788 * (I suppose it is arguably valid to have a host that does not
1792 if (find_ipv6_pool(&p
, D6O_IA_NA
, &addr
) == ISC_R_SUCCESS
) {
1793 mark_lease_unavailable(p
, &addr
);
1794 ipv6_pool_dereference(&p
, MDL
);
1796 if (find_ipv6_pool(&p
, D6O_IA_TA
, &addr
) == ISC_R_SUCCESS
) {
1797 mark_lease_unavailable(p
, &addr
);
1798 ipv6_pool_dereference(&p
, MDL
);
1801 return ISC_R_SUCCESS
;
1805 mark_hosts_unavailable(void) {
1806 hash_foreach(host_name_hash
, mark_hosts_unavailable_support
);
1810 mark_phosts_unavailable_support(const void *name
, unsigned len
, void *value
) {
1811 struct host_decl
*h
;
1812 struct iaddrcidrnetlist
*l
;
1813 struct in6_addr pref
;
1814 struct ipv6_pool
*p
;
1816 h
= (struct host_decl
*)value
;
1819 * If the host has no prefix, we don't need to mark anything.
1821 if (h
->fixed_prefix
== NULL
) {
1822 return ISC_R_SUCCESS
;
1826 * Get the fixed prefixes.
1828 for (l
= h
->fixed_prefix
; l
!= NULL
; l
= l
->next
) {
1829 if (l
->cidrnet
.lo_addr
.len
!= 16) {
1832 memcpy(&pref
, l
->cidrnet
.lo_addr
.iabuf
, 16);
1835 * Find the pool holding this host, and mark the prefix.
1836 * (I suppose it is arguably valid to have a host that does not
1840 if (find_ipv6_pool(&p
, D6O_IA_PD
, &pref
) != ISC_R_SUCCESS
) {
1843 if (l
->cidrnet
.bits
!= p
->units
) {
1844 ipv6_pool_dereference(&p
, MDL
);
1847 mark_lease_unavailable(p
, &pref
);
1848 ipv6_pool_dereference(&p
, MDL
);
1851 return ISC_R_SUCCESS
;
1855 mark_phosts_unavailable(void) {
1856 hash_foreach(host_name_hash
, mark_phosts_unavailable_support
);
1860 mark_interfaces_unavailable(void) {
1861 struct interface_info
*ip
;
1863 struct ipv6_pool
*p
;
1866 while (ip
!= NULL
) {
1867 for (i
=0; i
<ip
->v6address_count
; i
++) {
1869 if (find_ipv6_pool(&p
, D6O_IA_NA
, &ip
->v6addresses
[i
])
1871 mark_lease_unavailable(p
,
1872 &ip
->v6addresses
[i
]);
1873 ipv6_pool_dereference(&p
, MDL
);
1875 if (find_ipv6_pool(&p
, D6O_IA_TA
, &ip
->v6addresses
[i
])
1877 mark_lease_unavailable(p
,
1878 &ip
->v6addresses
[i
]);
1879 ipv6_pool_dereference(&p
, MDL
);
1891 main(int argc
, char *argv
[]) {
1892 struct iasubopt
*iaaddr
;
1893 struct iasubopt
*iaaddr_copy
;
1895 struct ia_xx
*ia_na
;
1896 struct ia_xx
*ia_na_copy
;
1898 struct in6_addr addr
;
1899 struct ipv6_pool
*pool
;
1900 struct ipv6_pool
*pool_copy
;
1901 char addr_buf
[INET6_ADDRSTRLEN
];
1903 struct data_string ds
;
1904 struct iasubopt
*expired_iaaddr
;
1905 unsigned int attempts
;
1908 * Test 0: Basic iaaddr manipulation.
1911 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
1912 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
1915 if (iaaddr
->state
!= FTS_FREE
) {
1916 printf("ERROR: bad state %s:%d\n", MDL
);
1919 if (iaaddr
->heap_index
!= -1) {
1920 printf("ERROR: bad heap_index %s:%d\n", MDL
);
1924 if (iasubopt_reference(&iaaddr_copy
, iaaddr
, MDL
) != ISC_R_SUCCESS
) {
1925 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1928 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
1929 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1932 if (iasubopt_dereference(&iaaddr_copy
, MDL
) != ISC_R_SUCCESS
) {
1933 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1938 * Test 1: Error iaaddr manipulation.
1940 /* bogus allocate arguments */
1941 if (iasubopt_allocate(NULL
, MDL
) != DHCP_R_INVALIDARG
) {
1942 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
1945 iaaddr
= (struct iasubopt
*)1;
1946 if (iasubopt_allocate(&iaaddr
, MDL
) != DHCP_R_INVALIDARG
) {
1947 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
1951 /* bogus reference arguments */
1953 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
1954 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
1957 if (iasubopt_reference(NULL
, iaaddr
, MDL
) != DHCP_R_INVALIDARG
) {
1958 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1961 iaaddr_copy
= (struct iasubopt
*)1;
1962 if (iasubopt_reference(&iaaddr_copy
, iaaddr
,
1963 MDL
) != DHCP_R_INVALIDARG
) {
1964 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1968 if (iasubopt_reference(&iaaddr_copy
, NULL
, MDL
) != DHCP_R_INVALIDARG
) {
1969 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1972 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
1973 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
1977 /* bogus dereference arguments */
1978 if (iasubopt_dereference(NULL
, MDL
) != DHCP_R_INVALIDARG
) {
1979 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
1983 if (iasubopt_dereference(&iaaddr
, MDL
) != DHCP_R_INVALIDARG
) {
1984 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
1989 * Test 2: Basic ia_na manipulation.
1993 if (ia_allocate(&ia_na
, iaid
, "TestDUID", 8, MDL
) != ISC_R_SUCCESS
) {
1994 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
1997 if (memcmp(ia_na
->iaid_duid
.data
, &iaid
, sizeof(iaid
)) != 0) {
1998 printf("ERROR: bad IAID_DUID %s:%d\n", MDL
);
2001 if (memcmp(ia_na
->iaid_duid
.data
+sizeof(iaid
), "TestDUID", 8) != 0) {
2002 printf("ERROR: bad IAID_DUID %s:%d\n", MDL
);
2005 if (ia_na
->num_iasubopt
!= 0) {
2006 printf("ERROR: bad num_iasubopt %s:%d\n", MDL
);
2010 if (ia_reference(&ia_na_copy
, ia_na
, MDL
) != ISC_R_SUCCESS
) {
2011 printf("ERROR: ia_reference() %s:%d\n", MDL
);
2015 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2016 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
2019 if (ia_add_iasubopt(ia_na
, iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2020 printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL
);
2023 ia_remove_iasubopt(ia_na
, iaaddr
, MDL
);
2024 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2025 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
2028 if (ia_dereference(&ia_na
, MDL
) != ISC_R_SUCCESS
) {
2029 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2032 if (ia_dereference(&ia_na_copy
, MDL
) != ISC_R_SUCCESS
) {
2033 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2038 * Test 3: lots of iaaddr in our ia_na
2041 /* lots of iaaddr that we delete */
2044 if (ia_allocate(&ia_na
, iaid
, "TestDUID", 8, MDL
) != ISC_R_SUCCESS
) {
2045 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
2048 for (i
=0; i
<100; i
++) {
2050 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2051 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
2054 if (ia_add_iasubopt(ia_na
, iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2055 printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL
);
2058 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2059 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
2063 for (i
=0; i
<100; i
++) {
2064 iaaddr
= ia_na
->iasubopt
[random() % ia_na
->num_iasubopt
];
2065 ia_remove_iasubopt(ia_na
, iaaddr
, MDL
);
2067 if (ia_dereference(&ia_na
, MDL
) != ISC_R_SUCCESS
) {
2068 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2072 /* lots of iaaddr, let dereference cleanup */
2075 if (ia_allocate(&ia_na
, iaid
, "TestDUID", 8, MDL
) != ISC_R_SUCCESS
) {
2076 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
2079 for (i
=0; i
<100; i
++) {
2081 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2082 printf("ERROR: iasubopt_allocate() %s:%d\n", MDL
);
2085 if (ia_add_iasubopt(ia_na
, iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2086 printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL
);
2089 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2090 printf("ERROR: iasubopt_reference() %s:%d\n", MDL
);
2094 if (ia_dereference(&ia_na
, MDL
) != ISC_R_SUCCESS
) {
2095 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2100 * Test 4: Errors in ia_na.
2102 /* bogus allocate arguments */
2103 if (ia_allocate(NULL
, 123, "", 0, MDL
) != DHCP_R_INVALIDARG
) {
2104 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
2107 ia_na
= (struct ia_na
*)1;
2108 if (ia_allocate(&ia_na
, 456, "", 0, MDL
) != DHCP_R_INVALIDARG
) {
2109 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
2113 /* bogus reference arguments */
2116 if (ia_allocate(&ia_na
, iaid
, "TestDUID", 8, MDL
) != ISC_R_SUCCESS
) {
2117 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
2120 if (ia_reference(NULL
, ia_na
, MDL
) != DHCP_R_INVALIDARG
) {
2121 printf("ERROR: ia_reference() %s:%d\n", MDL
);
2124 ia_na_copy
= (struct ia_na
*)1;
2125 if (ia_reference(&ia_na_copy
, ia_na
, MDL
) != DHCP_R_INVALIDARG
) {
2126 printf("ERROR: ia_reference() %s:%d\n", MDL
);
2130 if (ia_reference(&ia_na_copy
, NULL
, MDL
) != DHCP_R_INVALIDARG
) {
2131 printf("ERROR: ia_reference() %s:%d\n", MDL
);
2134 if (ia_dereference(&ia_na
, MDL
) != ISC_R_SUCCESS
) {
2135 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2139 /* bogus dereference arguments */
2140 if (ia_dereference(NULL
, MDL
) != DHCP_R_INVALIDARG
) {
2141 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2148 if (ia_allocate(&ia_na
, iaid
, "TestDUID", 8, MDL
) != ISC_R_SUCCESS
) {
2149 printf("ERROR: ia_allocate() %s:%d\n", MDL
);
2152 ia_remove_iasubopt(ia_na
, NULL
, MDL
);
2153 if (ia_dereference(&ia_na
, MDL
) != ISC_R_SUCCESS
) {
2154 printf("ERROR: ia_dereference() %s:%d\n", MDL
);
2159 * Test 5: Basic ipv6_pool manipulation.
2162 /* allocate, reference */
2163 inet_pton(AF_INET6
, "1:2:3:4::", &addr
);
2165 if (ipv6_pool_allocate(&pool
, 0, &addr
, 64, 128, MDL
) != ISC_R_SUCCESS
) {
2166 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL
);
2169 if (pool
->num_active
!= 0) {
2170 printf("ERROR: bad num_active %s:%d\n", MDL
);
2173 if (pool
->bits
!= 64) {
2174 printf("ERROR: bad bits %s:%d\n", MDL
);
2177 inet_ntop(AF_INET6
, &pool
->start_addr
, addr_buf
, sizeof(addr_buf
));
2178 if (strcmp(inet_ntop(AF_INET6
, &pool
->start_addr
, addr_buf
,
2179 sizeof(addr_buf
)), "1:2:3:4::") != 0) {
2180 printf("ERROR: bad start_addr %s:%d\n", MDL
);
2184 if (ipv6_pool_reference(&pool_copy
, pool
, MDL
) != ISC_R_SUCCESS
) {
2185 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL
);
2189 /* create_lease6, renew_lease6, expire_lease6 */
2191 memset(&ds
, 0, sizeof(ds
));
2192 ds
.len
= strlen(uid
);
2193 if (!buffer_allocate(&ds
.buffer
, ds
.len
, MDL
)) {
2194 printf("Out of memory\n");
2197 ds
.data
= ds
.buffer
->data
;
2198 memcpy((char *)ds
.data
, uid
, ds
.len
);
2199 if (create_lease6(pool
, &iaaddr
,
2200 &attempts
, &ds
, 1) != ISC_R_SUCCESS
) {
2201 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2204 if (pool
->num_inactive
!= 1) {
2205 printf("ERROR: bad num_inactive %s:%d\n", MDL
);
2208 if (renew_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2209 printf("ERROR: renew_lease6() %s:%d\n", MDL
);
2212 if (pool
->num_active
!= 1) {
2213 printf("ERROR: bad num_active %s:%d\n", MDL
);
2216 expired_iaaddr
= NULL
;
2217 if (expire_lease6(&expired_iaaddr
, pool
, 0) != ISC_R_SUCCESS
) {
2218 printf("ERROR: expire_lease6() %s:%d\n", MDL
);
2221 if (expired_iaaddr
!= NULL
) {
2222 printf("ERROR: should not have expired a lease %s:%d\n", MDL
);
2225 if (pool
->num_active
!= 1) {
2226 printf("ERROR: bad num_active %s:%d\n", MDL
);
2229 if (expire_lease6(&expired_iaaddr
, pool
, 1000) != ISC_R_SUCCESS
) {
2230 printf("ERROR: expire_lease6() %s:%d\n", MDL
);
2233 if (expired_iaaddr
== NULL
) {
2234 printf("ERROR: should have expired a lease %s:%d\n", MDL
);
2237 if (iasubopt_dereference(&expired_iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2238 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2241 if (pool
->num_active
!= 0) {
2242 printf("ERROR: bad num_active %s:%d\n", MDL
);
2245 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2246 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2250 /* release_lease6, decline_lease6 */
2251 if (create_lease6(pool
, &iaaddr
, &attempts
,
2252 &ds
, 1) != ISC_R_SUCCESS
) {
2253 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2256 if (renew_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2257 printf("ERROR: renew_lease6() %s:%d\n", MDL
);
2260 if (pool
->num_active
!= 1) {
2261 printf("ERROR: bad num_active %s:%d\n", MDL
);
2264 if (release_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2265 printf("ERROR: decline_lease6() %s:%d\n", MDL
);
2268 if (pool
->num_active
!= 0) {
2269 printf("ERROR: bad num_active %s:%d\n", MDL
);
2272 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2273 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2276 if (create_lease6(pool
, &iaaddr
, &attempts
,
2277 &ds
, 1) != ISC_R_SUCCESS
) {
2278 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2281 if (renew_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2282 printf("ERROR: renew_lease6() %s:%d\n", MDL
);
2285 if (pool
->num_active
!= 1) {
2286 printf("ERROR: bad num_active %s:%d\n", MDL
);
2289 if (decline_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2290 printf("ERROR: decline_lease6() %s:%d\n", MDL
);
2293 if (pool
->num_active
!= 1) {
2294 printf("ERROR: bad num_active %s:%d\n", MDL
);
2297 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2298 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2303 if (ipv6_pool_dereference(&pool
, MDL
) != ISC_R_SUCCESS
) {
2304 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL
);
2307 if (ipv6_pool_dereference(&pool_copy
, MDL
) != ISC_R_SUCCESS
) {
2308 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL
);
2313 * Test 6: Error ipv6_pool manipulation
2315 if (ipv6_pool_allocate(NULL
, 0, &addr
,
2316 64, 128, MDL
) != DHCP_R_INVALIDARG
) {
2317 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL
);
2320 pool
= (struct ipv6_pool
*)1;
2321 if (ipv6_pool_allocate(&pool
, 0, &addr
,
2322 64, 128, MDL
) != DHCP_R_INVALIDARG
) {
2323 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL
);
2326 if (ipv6_pool_reference(NULL
, pool
, MDL
) != DHCP_R_INVALIDARG
) {
2327 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL
);
2330 pool_copy
= (struct ipv6_pool
*)1;
2331 if (ipv6_pool_reference(&pool_copy
, pool
, MDL
) != DHCP_R_INVALIDARG
) {
2332 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL
);
2336 if (ipv6_pool_reference(&pool_copy
, NULL
, MDL
) != DHCP_R_INVALIDARG
) {
2337 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL
);
2340 if (ipv6_pool_dereference(NULL
, MDL
) != DHCP_R_INVALIDARG
) {
2341 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2344 if (ipv6_pool_dereference(&pool_copy
, MDL
) != DHCP_R_INVALIDARG
) {
2345 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2350 * Test 7: order of expiration
2353 if (ipv6_pool_allocate(&pool
, 0, &addr
, 64, 128, MDL
) != ISC_R_SUCCESS
) {
2354 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL
);
2357 for (i
=10; i
<100; i
+=10) {
2358 if (create_lease6(pool
, &iaaddr
, &attempts
,
2359 &ds
, i
) != ISC_R_SUCCESS
) {
2360 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2363 if (renew_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2364 printf("ERROR: renew_lease6() %s:%d\n", MDL
);
2367 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2368 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2371 if (pool
->num_active
!= (i
/ 10)) {
2372 printf("ERROR: bad num_active %s:%d\n", MDL
);
2376 if (pool
->num_active
!= 9) {
2377 printf("ERROR: bad num_active %s:%d\n", MDL
);
2380 for (i
=10; i
<100; i
+=10) {
2381 if (expire_lease6(&expired_iaaddr
,
2382 pool
, 1000) != ISC_R_SUCCESS
) {
2383 printf("ERROR: expire_lease6() %s:%d\n", MDL
);
2386 if (expired_iaaddr
== NULL
) {
2387 printf("ERROR: should have expired a lease %s:%d\n",
2391 if (pool
->num_active
!= (9 - (i
/ 10))) {
2392 printf("ERROR: bad num_active %s:%d\n", MDL
);
2395 if (expired_iaaddr
->hard_lifetime_end_time
!= i
) {
2396 printf("ERROR: bad hard_lifetime_end_time %s:%d\n",
2400 if (iasubopt_dereference(&expired_iaaddr
, MDL
) !=
2402 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2406 if (pool
->num_active
!= 0) {
2407 printf("ERROR: bad num_active %s:%d\n", MDL
);
2410 expired_iaaddr
= NULL
;
2411 if (expire_lease6(&expired_iaaddr
, pool
, 1000) != ISC_R_SUCCESS
) {
2412 printf("ERROR: expire_lease6() %s:%d\n", MDL
);
2415 if (ipv6_pool_dereference(&pool
, MDL
) != ISC_R_SUCCESS
) {
2416 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2421 * Test 8: small pool
2424 addr
.s6_addr
[14] = 0x81;
2425 if (ipv6_pool_allocate(&pool
, 0, &addr
, 127, 128, MDL
) != ISC_R_SUCCESS
) {
2426 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL
);
2429 if (create_lease6(pool
, &iaaddr
, &attempts
,
2430 &ds
, 42) != ISC_R_SUCCESS
) {
2431 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2434 if (renew_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2435 printf("ERROR: renew_lease6() %s:%d\n", MDL
);
2438 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2439 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2442 if (create_lease6(pool
, &iaaddr
, &attempts
,
2443 &ds
, 11) != ISC_R_SUCCESS
) {
2444 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2447 if (renew_lease6(pool
, iaaddr
) != ISC_R_SUCCESS
) {
2448 printf("ERROR: renew_lease6() %s:%d\n", MDL
);
2451 if (iasubopt_dereference(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
2452 printf("ERROR: iasubopt_dereference() %s:%d\n", MDL
);
2455 if (create_lease6(pool
, &iaaddr
, &attempts
,
2456 &ds
, 11) != ISC_R_NORESOURCES
) {
2457 printf("ERROR: create_lease6() %s:%d\n", MDL
);
2460 if (ipv6_pool_dereference(&pool
, MDL
) != ISC_R_SUCCESS
) {
2461 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2464 addr
.s6_addr
[14] = 0;
2467 * Test 9: functions across all pools
2470 if (ipv6_pool_allocate(&pool
, 0, &addr
, 64, 128, MDL
) != ISC_R_SUCCESS
) {
2471 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL
);
2474 if (add_ipv6_pool(pool
) != ISC_R_SUCCESS
) {
2475 printf("ERROR: add_ipv6_pool() %s:%d\n", MDL
);
2478 if (ipv6_pool_dereference(&pool
, MDL
) != ISC_R_SUCCESS
) {
2479 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2483 if (find_ipv6_pool(&pool
, 0, &addr
) != ISC_R_SUCCESS
) {
2484 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL
);
2487 if (ipv6_pool_dereference(&pool
, MDL
) != ISC_R_SUCCESS
) {
2488 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2491 inet_pton(AF_INET6
, "1:2:3:4:ffff:ffff:ffff:ffff", &addr
);
2493 if (find_ipv6_pool(&pool
, 0, &addr
) != ISC_R_SUCCESS
) {
2494 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL
);
2497 if (ipv6_pool_dereference(&pool
, MDL
) != ISC_R_SUCCESS
) {
2498 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL
);
2501 inet_pton(AF_INET6
, "1:2:3:5::", &addr
);
2503 if (find_ipv6_pool(&pool
, 0, &addr
) != ISC_R_NOTFOUND
) {
2504 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL
);
2507 inet_pton(AF_INET6
, "1:2:3:3:ffff:ffff:ffff:ffff", &addr
);
2509 if (find_ipv6_pool(&pool
, 0, &addr
) != ISC_R_NOTFOUND
) {
2510 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL
);
2516 if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
2517 printf("ERROR: ia_allocate() %s:%d\n", MDL);
2523 struct data_string ds
;
2528 memset(&ds
, 0, sizeof(ds
));
2529 memset(data
, 0xaa, sizeof(data
));
2533 inet_pton(AF_INET6
, "3ffe:501:ffff:100::", &addr
);
2534 for (i
= 32; i
< 42; i
++)
2535 for (j
= i
+ 1; j
< 49; j
++) {
2536 memset(&r
, 0, sizeof(r
));
2538 build_prefix6(&r
, &addr
, i
, j
, &ds
);
2539 inet_ntop(AF_INET6
, &r
, buf
, 64);
2540 printf("%d,%d-> %s/%d\n", i
, j
, buf
, j
);
2544 printf("SUCCESS: all tests passed (ignore any warning messages)\n");