]> git.ipfire.org Git - thirdparty/dhcp.git/blame - server/mdb6.c
- Replaced ./configure shellscripting with GNU Autoconf. [ISC-Bugs #16405b]
[thirdparty/dhcp.git] / server / mdb6.c
CommitLineData
98bd7ca0
DH
1/*
2 * Copyright (C) 2007 Internet Systems Consortium, Inc. ("ISC")
3 *
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.
7 *
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.
15 */
16
17/* TODO: assert() */
18/* TODO: simplify functions, as pool is now in iaaddr */
19
99fe695e 20#include <sys/types.h>
98bd7ca0
DH
21#include <time.h>
22#include <netinet/in.h>
23
24#include "isc-dhcp/result.h"
25
26#include <stdarg.h>
98bd7ca0 27#include "dhcpd.h"
6705543f 28#include "omapip/omapip.h"
98bd7ca0
DH
29#include "omapip/hash.h"
30#include "dst/md5.h"
31
32HASH_FUNCTIONS(ia_na, unsigned char *, struct ia_na, ia_na_hash_t,
33 ia_na_reference, ia_na_dereference, do_string_hash);
34
35ia_na_hash_t *ia_active;
36
37HASH_FUNCTIONS(iaaddr, struct in6_addr *, struct iaaddr, iaaddr_hash_t,
38 ia_na_reference, ia_na_dereference, do_string_hash);
39
40struct ipv6_pool **pools;
41int num_pools;
42
43/*
44 * Create a new IAADDR structure.
45 *
46 * - iaaddr must be a pointer to a (struct iaaddr *) pointer previously
47 * initialized to NULL
48 */
49isc_result_t
50iaaddr_allocate(struct iaaddr **iaaddr, const char *file, int line) {
51 struct iaaddr *tmp;
52
53 if (iaaddr == NULL) {
54 log_error("%s(%d): NULL pointer reference", file, line);
55 return ISC_R_INVALIDARG;
56 }
57 if (*iaaddr != NULL) {
58 log_error("%s(%d): non-NULL pointer", file, line);
59 return ISC_R_INVALIDARG;
60 }
61
62 tmp = dmalloc(sizeof(*tmp), file, line);
63 if (tmp == NULL) {
64 return ISC_R_NOMEMORY;
65 }
66
67 tmp->refcnt = 1;
68 tmp->state = FTS_FREE;
69 tmp->heap_index = -1;
70
71 *iaaddr = tmp;
72 return ISC_R_SUCCESS;
73}
74
75/*
76 * Reference an IAADDR structure.
77 *
78 * - iaaddr must be a pointer to a (struct iaaddr *) pointer previously
79 * initialized to NULL
80 */
81isc_result_t
82iaaddr_reference(struct iaaddr **iaaddr, struct iaaddr *src,
83 const char *file, int line) {
84 if (iaaddr == NULL) {
85 log_error("%s(%d): NULL pointer reference", file, line);
86 return ISC_R_INVALIDARG;
87 }
88 if (*iaaddr != NULL) {
89 log_error("%s(%d): non-NULL pointer", file, line);
90 return ISC_R_INVALIDARG;
91 }
92 if (src == NULL) {
93 log_error("%s(%d): NULL pointer reference", file, line);
94 return ISC_R_INVALIDARG;
95 }
96 *iaaddr = src;
97 src->refcnt++;
98 return ISC_R_SUCCESS;
99}
100
101
102/*
103 * Dereference an IAADDR structure.
104 *
105 * If it is the last reference, then the memory for the
106 * structure is freed.
107 */
108isc_result_t
109iaaddr_dereference(struct iaaddr **iaaddr, const char *file, int line) {
110 struct iaaddr *tmp;
111
112 if ((iaaddr == NULL) || (*iaaddr == NULL)) {
113 log_error("%s(%d): NULL pointer", file, line);
114 return ISC_R_INVALIDARG;
115 }
116
117 tmp = *iaaddr;
118 *iaaddr = NULL;
119
120 tmp->refcnt--;
121 if (tmp->refcnt < 0) {
122 log_error("%s(%d): negative refcnt", file, line);
123 tmp->refcnt = 0;
124 }
125 if (tmp->refcnt == 0) {
126 if (tmp->ia_na != NULL) {
127 ia_na_dereference(&(tmp->ia_na), file, line);
128 }
129 if (tmp->ipv6_pool != NULL) {
130 ipv6_pool_dereference(&(tmp->ipv6_pool), file, line);
131 }
132 if (tmp->scope != NULL) {
133 binding_scope_dereference(&tmp->scope, file, line);
134 }
135 dfree(tmp, file, line);
136 }
137
138 return ISC_R_SUCCESS;
139}
140
141/*
142 * Make the key that we use for IA_NA.
143 */
144isc_result_t
145ia_na_make_key(struct data_string *key, u_int32_t iaid,
146 const char *duid, unsigned int duid_len,
147 const char *file, int line) {
148
149 memset(key, 0, sizeof(*key));
150 key->len = duid_len + sizeof(iaid);
151 if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
152 return ISC_R_NOMEMORY;
153 }
154 key->data = key->buffer->data;
155 memcpy((char *)key->data, &iaid, sizeof(iaid));
156 memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
157
158 return ISC_R_SUCCESS;
159}
160
161/*
162 * Create a new IA_NA structure.
163 *
164 * - ia_na must be a pointer to a (struct ia_na *) pointer previously
165 * initialized to NULL
166 * - iaid and duid are values from the client
167 *
168 * XXXsk: we don't concern ourself with the byte order of the IAID,
169 * which might be a problem if we transfer this structure
170 * between machines of different byte order
171 */
172isc_result_t
173ia_na_allocate(struct ia_na **ia_na, u_int32_t iaid,
174 const char *duid, unsigned int duid_len,
175 const char *file, int line) {
176 struct ia_na *tmp;
177
178 if (ia_na == NULL) {
179 log_error("%s(%d): NULL pointer reference", file, line);
180 return ISC_R_INVALIDARG;
181 }
182 if (*ia_na != NULL) {
183 log_error("%s(%d): non-NULL pointer", file, line);
184 return ISC_R_INVALIDARG;
185 }
186
187 tmp = dmalloc(sizeof(*tmp), file, line);
188 if (tmp == NULL) {
189 return ISC_R_NOMEMORY;
190 }
191
192 if (ia_na_make_key(&tmp->iaid_duid, iaid,
193 duid, duid_len, file, line) != ISC_R_SUCCESS) {
194 dfree(tmp, file, line);
195 return ISC_R_NOMEMORY;
196 }
197
198 tmp->refcnt = 1;
199
200 *ia_na = tmp;
201 return ISC_R_SUCCESS;
202}
203
204/*
205 * Reference an IA_NA structure.
206 *
207 * - ia_na must be a pointer to a (struct ia_na *) pointer previously
208 * initialized to NULL
209 */
210isc_result_t
211ia_na_reference(struct ia_na **ia_na, struct ia_na *src,
212 const char *file, int line) {
213 if (ia_na == NULL) {
214 log_error("%s(%d): NULL pointer reference", file, line);
215 return ISC_R_INVALIDARG;
216 }
217 if (*ia_na != NULL) {
218 log_error("%s(%d): non-NULL pointer", file, line);
219 return ISC_R_INVALIDARG;
220 }
221 if (src == NULL) {
222 log_error("%s(%d): NULL pointer reference", file, line);
223 return ISC_R_INVALIDARG;
224 }
225 *ia_na = src;
226 src->refcnt++;
227 return ISC_R_SUCCESS;
228}
229
230/*
231 * Dereference an IA_NA structure.
232 *
233 * If it is the last reference, then the memory for the
234 * structure is freed.
235 */
236isc_result_t
237ia_na_dereference(struct ia_na **ia_na, const char *file, int line) {
238 struct ia_na *tmp;
239 int i;
240
241 if ((ia_na == NULL) || (*ia_na == NULL)) {
242 log_error("%s(%d): NULL pointer", file, line);
243 return ISC_R_INVALIDARG;
244 }
245
246 tmp = *ia_na;
247 *ia_na = NULL;
248
249 tmp->refcnt--;
250 if (tmp->refcnt < 0) {
251 log_error("%s(%d): negative refcnt", file, line);
252 tmp->refcnt = 0;
253 }
254 if (tmp->refcnt == 0) {
255 if (tmp->iaaddr != NULL) {
256 for (i=0; i<tmp->num_iaaddr; i++) {
257 iaaddr_dereference(&(tmp->iaaddr[i]),
258 file, line);
259 }
260 dfree(tmp->iaaddr, file, line);
261 }
262 data_string_forget(&(tmp->iaid_duid), file, line);
263 dfree(tmp, file, line);
264 }
265 return ISC_R_SUCCESS;
266}
267
268
269/*
270 * Add an IAADDR entry to an IA_NA structure.
271 */
272isc_result_t
273ia_na_add_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr,
274 const char *file, int line) {
275 int max;
276 struct iaaddr **new;
277
278 /*
279 * Grow our array if we need to.
280 *
281 * Note: we pick 4 as the increment, as that seems a reasonable
282 * guess as to how many addresses we might expect on an
283 * interface.
284 */
285 if (ia_na->max_iaaddr <= ia_na->num_iaaddr) {
286 max = ia_na->max_iaaddr + 4;
287 new = dmalloc(max * sizeof(struct iaaddr *), file, line);
288 if (new == NULL) {
289 return ISC_R_NOMEMORY;
290 }
291 memcpy(new, ia_na->iaaddr,
292 ia_na->num_iaaddr * sizeof(struct iaaddr *));
293 ia_na->iaaddr = new;
294 ia_na->max_iaaddr = max;
295 }
296
297 iaaddr_reference(&(ia_na->iaaddr[ia_na->num_iaaddr]), iaaddr,
298 file, line);
299 ia_na->num_iaaddr++;
300 ia_na_reference(&iaaddr->ia_na, ia_na, file, line);
301
302 return ISC_R_SUCCESS;
303}
304
305/*
306 * Remove an IAADDR entry to an IA_NA structure.
307 *
308 * Note: if an IAADDR appears more than once, then only ONE will be removed.
309 */
310void
311ia_na_remove_iaaddr(struct ia_na *ia_na, struct iaaddr *iaaddr,
312 const char *file, int line) {
313 int i, j;
314
315 for (i=0; i<ia_na->num_iaaddr; i++) {
316 if (ia_na->iaaddr[i] == iaaddr) {
317 /* remove this IAADDR */
318 iaaddr_dereference(&(ia_na->iaaddr[i]), file, line);
319 /* move remaining IAADDR pointers down one */
320 for (j=i+1; j < ia_na->num_iaaddr; j++) {
321 ia_na->iaaddr[j-1] = ia_na->iaaddr[j];
322 }
323 /* decrease our total count */
d9b43370
SK
324 /* remove the back-reference in the IAADDR itself */
325 ia_na_dereference(&iaaddr->ia_na, file, line);
98bd7ca0
DH
326 ia_na->num_iaaddr--;
327 return;
328 }
329 }
330 log_error("%s(%d): IAADDR not in IA_NA", file, line);
331}
332
727cae26 333/*
d9b43370
SK
334 * Remove all addresses from an IA_NA.
335 */
336void
337ia_na_remove_all_iaaddr(struct ia_na *ia_na, const char *file, int line) {
338 int i, j;
339
340 for (i=0; i<ia_na->num_iaaddr; i++) {
341 iaaddr_dereference(&(ia_na->iaaddr[i]), file, line);
342 }
343 ia_na->num_iaaddr = 0;
344}
345
98bd7ca0
DH
346/*
347 * Helper function for lease heaps.
348 * Makes the top of the heap the oldest lease.
349 */
350static isc_boolean_t
351lease_older(void *a, void *b) {
352 struct iaaddr *ia = (struct iaaddr *)a;
353 struct iaaddr *ib = (struct iaaddr *)b;
354
355 return difftime(ia->valid_lifetime_end_time,
356 ib->valid_lifetime_end_time) < 0;
357}
358
359/*
360 * Helper function for lease heaps.
361 * Callback when an address's position in the heap changes.
362 */
363static void
364lease_address_index_changed(void *iaaddr, unsigned int new_heap_index) {
365 ((struct iaaddr *)iaaddr)-> heap_index = new_heap_index;
366}
367
368
369/*
370 * Create a new IPv6 lease pool structure.
371 *
372 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
373 * initialized to NULL
374 */
375isc_result_t
376ipv6_pool_allocate(struct ipv6_pool **pool,
377 const struct in6_addr *start_addr, int bits,
378 const char *file, int line) {
379 struct ipv6_pool *tmp;
380
381 if (pool == NULL) {
382 log_error("%s(%d): NULL pointer reference", file, line);
383 return ISC_R_INVALIDARG;
384 }
385 if (*pool != NULL) {
386 log_error("%s(%d): non-NULL pointer", file, line);
387 return ISC_R_INVALIDARG;
388 }
389
390 tmp = dmalloc(sizeof(*tmp), file, line);
391 if (tmp == NULL) {
392 return ISC_R_NOMEMORY;
393 }
394
395 tmp->refcnt = 1;
396 tmp->start_addr = *start_addr;
397 tmp->bits = bits;
398 if (!iaaddr_new_hash(&tmp->addrs, DEFAULT_HASH_SIZE, file, line)) {
399 dfree(tmp, file, line);
400 return ISC_R_NOMEMORY;
401 }
402 if (isc_heap_create(lease_older, lease_address_index_changed,
403 0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) {
404 iaaddr_free_hash_table(&(tmp->addrs), file, line);
405 dfree(tmp, file, line);
406 return ISC_R_NOMEMORY;
407 }
408 if (isc_heap_create(lease_older, lease_address_index_changed,
409 0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) {
410 isc_heap_destroy(&(tmp->active_timeouts));
411 iaaddr_free_hash_table(&(tmp->addrs), file, line);
412 dfree(tmp, file, line);
413 return ISC_R_NOMEMORY;
414 }
415
416 *pool = tmp;
417 return ISC_R_SUCCESS;
418}
419
420/*
421 * Reference an IPv6 pool structure.
422 *
423 * - pool must be a pointer to a (struct pool *) pointer previously
424 * initialized to NULL
425 */
426isc_result_t
427ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
428 const char *file, int line) {
429 if (pool == NULL) {
430 log_error("%s(%d): NULL pointer reference", file, line);
431 return ISC_R_INVALIDARG;
432 }
433 if (*pool != NULL) {
434 log_error("%s(%d): non-NULL pointer", file, line);
435 return ISC_R_INVALIDARG;
436 }
437 if (src == NULL) {
438 log_error("%s(%d): NULL pointer reference", file, line);
439 return ISC_R_INVALIDARG;
440 }
441 *pool = src;
442 src->refcnt++;
443 return ISC_R_SUCCESS;
444}
445
446/*
447 * Note: Each IAADDR in a pool is referenced by the pool. This is needed
448 * to prevent the IAADDR from being garbage collected out from under the
449 * pool.
450 *
451 * The references are made from the hash and from the heap. The following
452 * helper functions dereference these when a pool is destroyed.
453 */
454
455/*
456 * Helper function for pool cleanup.
457 * Dereference each of the hash entries in a pool.
458 */
459static isc_result_t
460dereference_hash_entry(const void *name, unsigned len, void *value) {
461 struct iaaddr *iaaddr = (struct iaaddr *)value;
462
463 iaaddr_dereference(&iaaddr, MDL);
464 return ISC_R_SUCCESS;
465}
466
467/*
468 * Helper function for pool cleanup.
469 * Dereference each of the heap entries in a pool.
470 */
471static void
472dereference_heap_entry(void *value, void *dummy) {
473 struct iaaddr *iaaddr = (struct iaaddr *)value;
474
475 iaaddr_dereference(&iaaddr, MDL);
476}
477
478
479/*
480 * Dereference an IPv6 pool structure.
481 *
482 * If it is the last reference, then the memory for the
483 * structure is freed.
484 */
485isc_result_t
486ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
487 struct ipv6_pool *tmp;
488
489 if ((pool == NULL) || (*pool == NULL)) {
490 log_error("%s(%d): NULL pointer", file, line);
491 return ISC_R_INVALIDARG;
492 }
493
494 tmp = *pool;
495 *pool = NULL;
496
497 tmp->refcnt--;
498 if (tmp->refcnt < 0) {
499 log_error("%s(%d): negative refcnt", file, line);
500 tmp->refcnt = 0;
501 }
502 if (tmp->refcnt == 0) {
503 iaaddr_hash_foreach(tmp->addrs, dereference_hash_entry);
504 iaaddr_free_hash_table(&(tmp->addrs), file, line);
505 isc_heap_foreach(tmp->active_timeouts,
506 dereference_heap_entry, NULL);
507 isc_heap_destroy(&(tmp->active_timeouts));
508 isc_heap_foreach(tmp->inactive_timeouts,
509 dereference_heap_entry, NULL);
510 isc_heap_destroy(&(tmp->inactive_timeouts));
511 dfree(tmp, file, line);
512 }
513
514 return ISC_R_SUCCESS;
515}
516
517/*
518 * Create an address by hashing the input, and using that for
519 * the non-network part.
520 */
521static void
522create_address(struct in6_addr *addr,
523 const struct in6_addr *net_start_addr, int net_bits,
524 const struct data_string *input) {
525 MD5_CTX ctx;
526 int net_bytes;
527 int i;
528 char *str;
529 const char *net_str;
530
531 /*
532 * Use MD5 to get a nice 128 bit hash of the input.
533 * Yes, we know MD5 isn't cryptographically sound.
534 * No, we don't care.
535 */
536 MD5_Init(&ctx);
537 MD5_Update(&ctx, input->data, input->len);
538 MD5_Final((unsigned char *)addr, &ctx);
539
540 /*
541 * Copy the network bits over.
542 */
543 str = (char *)addr;
544 net_str = (const char *)net_start_addr;
545 net_bytes = net_bits / 8;
546 for (i=0; i<net_bytes; i++) {
547 str[i] = net_str[i];
548 }
549 switch (net_bits % 8) {
550 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
551 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
552 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
553 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
554 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
555 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
556 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
557 }
558}
559
560/*
561 * Create a lease for the given address and client duid.
562 *
563 * - pool must be a pointer to a (struct pool *) pointer previously
564 * initialized to NULL
565 *
566 * Right now we simply hash the DUID, and if we get a collision, we hash
567 * again until we find a free address. We try this a fixed number of times,
568 * to avoid getting stuck in a loop (this is important on small pools
569 * where we can run out of space).
570 *
571 * We return the number of attempts that it took to find an available
572 * lease. This tells callers when a pool is are filling up, as
573 * well as an indication of how full the pool is; statistically the
574 * more full a pool is the more attempts must be made before finding
575 * a free lease. Realistically this will only happen in very full
576 * pools.
577 *
578 * We probably want different algorithms depending on the network size, in
579 * the long term.
580 */
581isc_result_t
582activate_lease6(struct ipv6_pool *pool, struct iaaddr **addr,
583 unsigned int *attempts,
584 const struct data_string *uid, time_t valid_lifetime_end_time) {
585 struct data_string ds;
586 struct in6_addr tmp;
587 struct iaaddr *test_iaaddr;
588 struct data_string new_ds;
589 struct iaaddr *iaaddr;
d9b43370 590 isc_result_t result;
98bd7ca0
DH
591
592 /*
593 * Use the UID as our initial seed for the hash
594 */
595 memset(&ds, 0, sizeof(ds));
596 data_string_copy(&ds, (struct data_string *)uid, MDL);
597
598 *attempts = 0;
599 for (;;) {
600 /*
601 * Give up at some point.
602 */
603 if (++(*attempts) > 100) {
604 data_string_forget(&ds, MDL);
605 return ISC_R_NORESOURCES;
606 }
607
608 /*
609 * Create an address
610 */
611 create_address(&tmp, &pool->start_addr, pool->bits, &ds);
612
613 /*
614 * If this address is not in use, we're happy with it
615 */
616 test_iaaddr = NULL;
617 if (iaaddr_hash_lookup(&test_iaaddr, pool->addrs,
618 &tmp, sizeof(tmp), MDL) == 0) {
619 break;
620 }
621 iaaddr_dereference(&test_iaaddr, MDL);
622
623 /*
624 * Otherwise, we create a new input, adding the address
625 */
626 memset(&new_ds, 0, sizeof(new_ds));
627 new_ds.len = ds.len + sizeof(tmp);
628 if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
629 data_string_forget(&ds, MDL);
630 return ISC_R_NOMEMORY;
631 }
632 new_ds.data = new_ds.buffer->data;
d9b43370
SK
633 memcpy(new_ds.buffer->data, ds.data, ds.len);
634 memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
98bd7ca0
DH
635 data_string_forget(&ds, MDL);
636 data_string_copy(&ds, &new_ds, MDL);
637 data_string_forget(&new_ds, MDL);
638 }
639
640 data_string_forget(&ds, MDL);
641
642 /*
643 * We're happy with the address, create an IAADDR
644 * to hold it.
645 */
646 iaaddr = NULL;
d9b43370
SK
647 result = iaaddr_allocate(&iaaddr, MDL);
648 if (result != ISC_R_SUCCESS) {
649 return result;
98bd7ca0
DH
650 }
651 memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
652
d9b43370
SK
653 /*
654 * Add the lease to the pool.
655 */
656 result = add_lease6(pool, iaaddr, valid_lifetime_end_time);
657 if (result == ISC_R_SUCCESS) {
658 iaaddr_reference(addr, iaaddr, MDL);
659 }
660 iaaddr_dereference(&iaaddr, MDL);
661 return result;
98bd7ca0
DH
662}
663
664/*
665 * Put a lease in the pool directly. This is intended to be used when
666 * loading leases from the file.
667 */
668isc_result_t
669add_lease6(struct ipv6_pool *pool, struct iaaddr *iaaddr,
670 time_t valid_lifetime_end_time) {
671 isc_result_t insert_result;
d9b43370
SK
672 struct iaaddr *test_iaaddr;
673 struct iaaddr *tmp_iaaddr;
98bd7ca0
DH
674
675 iaaddr->state = FTS_ACTIVE;
676 iaaddr->valid_lifetime_end_time = valid_lifetime_end_time;
677 ipv6_pool_reference(&iaaddr->ipv6_pool, pool, MDL);
678
d9b43370
SK
679 /*
680 * If this IAADDR is already in our structures, remove the
681 * old one.
682 */
683 test_iaaddr = NULL;
684 if (iaaddr_hash_lookup(&test_iaaddr, pool->addrs,
685 &iaaddr->addr, sizeof(iaaddr->addr), MDL)) {
686 isc_heap_delete(pool->active_timeouts, test_iaaddr->heap_index);
687 iaaddr_hash_delete(pool->addrs, &test_iaaddr->addr,
688 sizeof(test_iaaddr->addr), MDL);
689 pool->num_active--;
690
691 /*
692 * We're going to do a bit of evil trickery here.
693 *
694 * We need to dereference the entry once to remove our
695 * current reference (in test_iaaddr), and then one
696 * more time to remove the reference left when the
697 * address was added to the pool before.
698 */
699 tmp_iaaddr = test_iaaddr;
700 iaaddr_dereference(&test_iaaddr, MDL);
701 iaaddr_dereference(&tmp_iaaddr, MDL);
702 }
703
98bd7ca0
DH
704 /*
705 * Add IAADDR to our structures.
706 */
d9b43370
SK
707 tmp_iaaddr = NULL;
708 iaaddr_reference(&tmp_iaaddr, iaaddr, MDL);
709 iaaddr_hash_add(pool->addrs, &tmp_iaaddr->addr,
710 sizeof(tmp_iaaddr->addr), iaaddr, MDL);
711 insert_result = isc_heap_insert(pool->active_timeouts, tmp_iaaddr);
98bd7ca0
DH
712 if (insert_result != ISC_R_SUCCESS) {
713 iaaddr_hash_delete(pool->addrs, &iaaddr->addr,
714 sizeof(iaaddr->addr), MDL);
d9b43370 715 iaaddr_dereference(&tmp_iaaddr, MDL);
98bd7ca0
DH
716 return insert_result;
717 }
718
d9b43370
SK
719 /*
720 * Note: we intentionally leave tmp_iaaddr referenced; there
721 * is a reference in the heap/hash, after all.
722 */
723
98bd7ca0
DH
724 /*
725 * And we're done.
726 */
727 pool->num_active++;
728 return ISC_R_SUCCESS;
729}
730
d9b43370
SK
731/*
732 * Determine if an address is present in a pool or not.
733 */
98bd7ca0
DH
734isc_boolean_t
735lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
736 struct iaaddr *test_iaaddr;
737
738 test_iaaddr = NULL;
739 if (iaaddr_hash_lookup(&test_iaaddr, pool->addrs,
740 (void *)addr, sizeof(*addr), MDL)) {
741 iaaddr_dereference(&test_iaaddr, MDL);
742 return ISC_TRUE;
743 } else {
744 return ISC_FALSE;
745 }
746}
747
d9b43370
SK
748/*
749 * Put the lease on our active pool.
750 */
751static isc_result_t
752move_lease_to_active(struct ipv6_pool *pool, struct iaaddr *addr) {
753 isc_result_t insert_result;
754 int old_heap_index;
755
756 old_heap_index = addr->heap_index;
757 insert_result = isc_heap_insert(pool->active_timeouts, addr);
758 if (insert_result == ISC_R_SUCCESS) {
759 iaaddr_hash_add(pool->addrs, &addr->addr,
760 sizeof(addr->addr), addr, MDL);
761 isc_heap_delete(pool->inactive_timeouts, old_heap_index);
762 pool->num_active++;
763 pool->num_inactive--;
764 addr->state = FTS_ACTIVE;
765 }
766 return insert_result;
767}
768
98bd7ca0
DH
769/*
770 * Renew an lease in the pool.
771 *
772 * To do this, first set the new valid_lifetime_end_time for the address,
773 * and then invoke renew_lease() on the address.
774 *
775 * WARNING: lease times must only be extended, never reduced!!!
98bd7ca0
DH
776 */
777isc_result_t
778renew_lease6(struct ipv6_pool *pool, struct iaaddr *addr) {
d9b43370
SK
779 /*
780 * If we're already active, then we can just move our expiration
781 * time down the heap.
782 *
783 * Otherwise, we have to move from the inactive heap to the
784 * active heap.
785 */
786 if (addr->state == FTS_ACTIVE) {
787 isc_heap_decreased(pool->active_timeouts, addr->heap_index);
788 return ISC_R_SUCCESS;
789 } else {
790 return move_lease_to_active(pool, addr);
791 }
792}
793
794/*
795 * Put the lease on our inactive pool, with the specified state.
796 */
797static isc_result_t
798move_lease_to_inactive(struct ipv6_pool *pool, struct iaaddr *addr,
799 binding_state_t state) {
800 isc_result_t insert_result;
801 int old_heap_index;
802
803 old_heap_index = addr->heap_index;
804 insert_result = isc_heap_insert(pool->inactive_timeouts, addr);
805 if (insert_result == ISC_R_SUCCESS) {
806 iaaddr_hash_delete(pool->addrs,
807 &addr->addr, sizeof(addr->addr), MDL);
808 isc_heap_delete(pool->active_timeouts, old_heap_index);
809 addr->state = state;
810 pool->num_active--;
811 pool->num_inactive++;
812 }
813 return insert_result;
98bd7ca0
DH
814}
815
816/*
817 * Expire the oldest lease if it's lifetime_end_time is
818 * older than the given time.
819 *
820 * - iaaddr must be a pointer to a (struct iaaddr *) pointer previously
821 * initialized to NULL
822 *
823 * On return iaaddr has a reference to the removed entry. It is left
824 * pointing to NULL if the oldest lease has not expired.
825 */
826isc_result_t
827expire_lease6(struct iaaddr **addr, struct ipv6_pool *pool, time_t now) {
828 struct iaaddr *tmp;
d9b43370 829 isc_result_t result;
98bd7ca0
DH
830
831 if (addr == NULL) {
832 log_error("%s(%d): NULL pointer reference", MDL);
833 return ISC_R_INVALIDARG;
834 }
835 if (*addr != NULL) {
836 log_error("%s(%d): non-NULL pointer", MDL);
837 return ISC_R_INVALIDARG;
838 }
839
840 if (pool->num_active > 0) {
841 tmp = (struct iaaddr *)isc_heap_element(pool->active_timeouts,
842 1);
843 if (now > tmp->valid_lifetime_end_time) {
d9b43370
SK
844 result = move_lease_to_inactive(pool, tmp, FTS_EXPIRED);
845 if (result == ISC_R_SUCCESS) {
846 iaaddr_reference(addr, tmp, MDL);
98bd7ca0 847 }
d9b43370 848 return result;
98bd7ca0
DH
849 }
850 }
851 return ISC_R_SUCCESS;
852}
853
98bd7ca0
DH
854
855/*
856 * For a declined lease, leave it on the "active" pool, but mark
857 * it as declined. Give it an infinite (well, really long) life.
858 */
859isc_result_t
860decline_lease6(struct ipv6_pool *pool, struct iaaddr *addr) {
d9b43370
SK
861 isc_result_t result;
862
863 if (addr->state != FTS_ACTIVE) {
864 result = move_lease_to_active(pool, addr);
865 if (result != ISC_R_SUCCESS) {
866 return result;
867 }
868 }
98bd7ca0
DH
869 addr->state = FTS_ABANDONED;
870 addr->valid_lifetime_end_time = MAX_TIME;
871 isc_heap_decreased(pool->active_timeouts, addr->heap_index);
872 return ISC_R_SUCCESS;
873}
874
875/*
876 * Put the returned lease on our inactive pool.
877 */
878isc_result_t
879release_lease6(struct ipv6_pool *pool, struct iaaddr *addr) {
d9b43370
SK
880 if (addr->state == FTS_ACTIVE) {
881 return move_lease_to_inactive(pool, addr, FTS_RELEASED);
882 } else {
883 return ISC_R_SUCCESS;
884 }
98bd7ca0
DH
885}
886
887/*
888 * Mark an IPv6 address as unavailable from a pool.
889 *
890 * This is used for host entries and the addresses of the server itself.
891 */
892isc_result_t
893mark_address_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
894 struct iaaddr *dummy_iaaddr;
895 isc_result_t result;
896
897 dummy_iaaddr = NULL;
898 result = iaaddr_allocate(&dummy_iaaddr, MDL);
899 if (result == ISC_R_SUCCESS) {
900 dummy_iaaddr->addr = *addr;
901 iaaddr_hash_add(pool->addrs, &dummy_iaaddr->addr,
902 sizeof(*addr), dummy_iaaddr, MDL);
903 }
904 return result;
905}
906
907/*
908 * Add a pool.
909 */
910isc_result_t
911add_ipv6_pool(struct ipv6_pool *pool) {
912 struct ipv6_pool **new_pools;
913
914 new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
915 if (new_pools == NULL) {
916 return ISC_R_NOMEMORY;
917 }
918
919 if (num_pools > 0) {
920 memcpy(new_pools, pools,
921 sizeof(struct ipv6_pool *) * num_pools);
922 dfree(pools, MDL);
923 }
924 pools = new_pools;
925
926 pools[num_pools] = NULL;
927 ipv6_pool_reference(&pools[num_pools], pool, MDL);
928 num_pools++;
929 return ISC_R_SUCCESS;
930}
931
932
d9b43370
SK
933static void
934cleanup_old_expired(struct ipv6_pool *pool) {
935 struct iaaddr *tmp;
936 struct ia_na *ia_na;
937
938 while (pool->num_inactive > 0) {
939 tmp = (struct iaaddr *)isc_heap_element(pool->inactive_timeouts,
940 1);
941 if (cur_time <
942 tmp->valid_lifetime_end_time + EXPIRED_IPV6_CLEANUP_TIME) {
943 break;
944 }
945
946 isc_heap_delete(pool->inactive_timeouts, tmp->heap_index);
947 pool->num_inactive--;
948
949 ia_na = NULL;
950 ia_na_reference(&ia_na, tmp->ia_na, MDL);
951 ia_na_remove_iaaddr(ia_na, tmp, MDL);
952 iaaddr_dereference(&tmp, MDL);
953 if (ia_na->num_iaaddr <= 0) {
954 ia_na_hash_delete(ia_active,
955 (char *)ia_na->iaid_duid.data,
956 ia_na->iaid_duid.len, MDL);
957 }
958 ia_na_dereference(&ia_na, MDL);
959 }
960}
961
962static void
963lease_timeout_support(void *vpool) {
964 struct ipv6_pool *pool;
965 struct iaaddr *addr;
966
967 pool = (struct ipv6_pool *)vpool;
968 for (;;) {
969 /*
970 * Get the next lease scheduled to expire.
971 *
972 * Note that if there are no leases in the pool,
973 * expire_lease6() will return ISC_R_SUCCESS with
974 * a NULL lease.
975 */
976 addr = NULL;
977 if (expire_lease6(&addr, pool, cur_time) != ISC_R_SUCCESS) {
978 break;
979 }
980 if (addr == NULL) {
981 break;
982 }
983
984 /* Look to see if there were ddns updates, and if
985 * so, drop them.
986 *
987 * DH: Do we want to do this on a special 'depref'
988 * timer rather than expiration timer?
989 */
990 ddns_removals(NULL, addr);
991
992 write_ia_na(addr->ia_na);
993
994 iaaddr_dereference(&addr, MDL);
995 }
996
997 /*
998 * Do some cleanup of our expired leases.
999 */
1000 cleanup_old_expired(pool);
1001
1002 /*
1003 * Schedule next round of expirations.
1004 */
1005 schedule_lease_timeout(pool);
1006}
1007
98bd7ca0 1008/*
d9b43370
SK
1009 * For a given pool, add a timer that will remove the next
1010 * lease to expire.
98bd7ca0
DH
1011 */
1012void
d9b43370
SK
1013schedule_lease_timeout(struct ipv6_pool *pool) {
1014 struct iaaddr *tmp;
1015 time_t timeout;
1016 time_t next_timeout;
1017
1018 next_timeout = MAX_TIME;
1019
1020 if (pool->num_active > 0) {
1021 tmp = (struct iaaddr *)isc_heap_element(pool->active_timeouts,
1022 1);
1023 if (tmp->valid_lifetime_end_time < next_timeout) {
1024 next_timeout = tmp->valid_lifetime_end_time;
1025 }
1026 }
1027
1028 if (pool->num_inactive > 0) {
1029 tmp = (struct iaaddr *)isc_heap_element(pool->inactive_timeouts,
1030 1);
1031 timeout = tmp->valid_lifetime_end_time +
1032 EXPIRED_IPV6_CLEANUP_TIME;
1033 if (timeout < next_timeout) {
1034 next_timeout = timeout;
1035 }
1036 }
1037
1038 if (next_timeout < MAX_TIME) {
1039 add_timeout(next_timeout, lease_timeout_support, pool,
1040 (tvref_t)ipv6_pool_reference,
1041 (tvunref_t)ipv6_pool_dereference);
1042 }
1043}
1044
1045/*
1046 * Schedule timeouts across all pools.
1047 */
1048void
1049schedule_all_ipv6_lease_timeouts(void) {
98bd7ca0 1050 int i;
98bd7ca0
DH
1051
1052 for (i=0; i<num_pools; i++) {
d9b43370 1053 schedule_lease_timeout(pools[i]);
98bd7ca0
DH
1054 }
1055}
1056
1057/*
1058 * Given an address and the length of the network mask, return
1059 * only the network portion.
1060 *
1061 * Examples:
1062 *
1063 * "fe80::216:6fff:fe49:7d9b", length 64 = "fe80::"
1064 * "2001:888:1936:2:216:6fff:fe49:7d9b", length 48 = "2001:888:1936::"
1065 */
1066static void
1067ipv6_network_portion(struct in6_addr *result,
1068 const struct in6_addr *addr, int bits) {
1069 unsigned char *addrp;
1070 int mask_bits;
1071 int bytes;
1072 int extra_bits;
1073 int i;
1074
1075 static const unsigned char bitmasks[] = {
1076 0x00, 0xFE, 0xFC, 0xF8,
1077 0xF0, 0xE0, 0xC0, 0x80,
1078 };
1079
1080 /*
1081 * Sanity check our bits. ;)
1082 */
1083 if ((bits < 0) || (bits > 128)) {
1084 log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
1085 bits);
1086 }
1087
1088 /*
1089 * Copy our address portion.
1090 */
1091 *result = *addr;
1092 addrp = ((unsigned char *)result) + 15;
1093
1094 /*
1095 * Zero out masked portion.
1096 */
1097 mask_bits = 128 - bits;
1098 bytes = mask_bits / 8;
1099 extra_bits = mask_bits % 8;
1100
1101 for (i=0; i<bytes; i++) {
1102 *addrp = 0;
1103 addrp--;
1104 }
1105 if (extra_bits) {
1106 *addrp &= bitmasks[extra_bits];
1107 }
1108}
1109
1110/*
1111 * Determine if the given address is in the pool.
1112 */
1113isc_boolean_t
1114ipv6_addr_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
1115 struct in6_addr tmp;
1116
1117 ipv6_network_portion(&tmp, addr, pool->bits);
1118 if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
1119 return ISC_TRUE;
1120 } else {
1121 return ISC_FALSE;
1122 }
1123}
1124
1125/*
1126 * Find the pool that contains the given address.
1127 *
1128 * - pool must be a pointer to a (struct ipv6_pool *) pointer previously
1129 * initialized to NULL
1130 */
1131isc_result_t
1132find_ipv6_pool(struct ipv6_pool **pool, const struct in6_addr *addr) {
1133 int i;
1134
1135 if (pool == NULL) {
1136 log_error("%s(%d): NULL pointer reference", MDL);
1137 return ISC_R_INVALIDARG;
1138 }
1139 if (*pool != NULL) {
1140 log_error("%s(%d): non-NULL pointer", MDL);
1141 return ISC_R_INVALIDARG;
1142 }
1143
1144 for (i=0; i<num_pools; i++) {
1145 if (ipv6_addr_in_pool(addr, pools[i])) {
1146 ipv6_pool_reference(pool, pools[i], MDL);
1147 return ISC_R_SUCCESS;
1148 }
1149 }
1150 return ISC_R_NOTFOUND;
1151}
1152
1153/*
1154 * Helper function for the various functions that act across all
1155 * pools.
1156 */
1157static isc_result_t
1158change_leases(struct ia_na *ia_na,
1159 isc_result_t (*change_func)(struct ipv6_pool *, struct iaaddr*)) {
1160 isc_result_t retval;
1161 isc_result_t renew_retval;
1162 struct ipv6_pool *pool;
1163 struct in6_addr *addr;
1164 int i;
1165
1166 retval = ISC_R_SUCCESS;
1167 for (i=0; i<ia_na->num_iaaddr; i++) {
1168 pool = NULL;
1169 addr = &ia_na->iaaddr[i]->addr;
1170 if (find_ipv6_pool(&pool, addr) == ISC_R_SUCCESS) {
1171 renew_retval = change_func(pool, ia_na->iaaddr[i]);
1172 if (renew_retval != ISC_R_SUCCESS) {
1173 retval = renew_retval;
1174 }
1175 }
1176 /* XXXsk: should we warn if we don't find a pool? */
1177 }
1178 return retval;
1179}
1180
1181/*
1182 * Renew all leases in an IA_NA from all pools.
1183 *
1184 * The new valid_lifetime_end_time should be updated for the addresses.
1185 *
1186 * WARNING: lease times must only be extended, never reduced!!!
1187 */
1188isc_result_t
1189renew_leases(struct ia_na *ia_na) {
1190 return change_leases(ia_na, renew_lease6);
1191}
1192
1193/*
1194 * Release all leases in an IA_NA from all pools.
1195 */
1196isc_result_t
1197release_leases(struct ia_na *ia_na) {
1198 return change_leases(ia_na, release_lease6);
1199}
1200
1201/*
1202 * Decline all leases in an IA_NA from all pools.
1203 */
1204isc_result_t
1205decline_leases(struct ia_na *ia_na) {
1206 return change_leases(ia_na, decline_lease6);
1207}
1208
1209/*
1210 * Helper function to output leases.
1211 */
1212static int write_error;
1213
1214static isc_result_t
1215write_ia_na_leases(const void *name, unsigned len, void *value) {
1216 struct ia_na *ia_na = (struct ia_na *)value;
1217
1218 if (!write_error) {
1219 if (!write_ia_na(ia_na)) {
1220 write_error = 1;
1221 }
1222 }
1223 return ISC_R_SUCCESS;
1224}
1225
fe5b0fdd 1226#ifdef DHCPv6
98bd7ca0
DH
1227/*
1228 * Write all DHCPv6 information.
1229 */
1230int
1231write_leases6(void) {
1232 write_error = 0;
1233 write_server_duid();
1234 iaaddr_hash_foreach(ia_active, write_ia_na_leases);
1235 if (write_error) {
1236 return 0;
1237 }
1238 return 1;
1239}
fe5b0fdd 1240#endif /* DHCPv6 */
98bd7ca0
DH
1241
1242static isc_result_t
1243mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
1244 struct host_decl *h;
1245 struct data_string fixed_addr;
1246 struct in6_addr addr;
1247 struct ipv6_pool *p;
1248
1249 h = (struct host_decl *)value;
1250
1251 /*
1252 * If the host has no address, we don't need to mark anything.
1253 */
1254 if (h->fixed_addr == NULL) {
1255 return ISC_R_SUCCESS;
1256 }
1257
1258 /*
1259 * Evaluate the fixed address.
1260 */
1261 memset(&fixed_addr, 0, sizeof(fixed_addr));
1262 if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
1263 &global_scope, h->fixed_addr, MDL)) {
1264 log_error("mark_hosts_unavailable: "
1265 "error evaluating host address.");
1266 return ISC_R_SUCCESS;
1267 }
1268 if (fixed_addr.len != 16) {
1269 log_error("mark_hosts_unavailable: "
1270 "host address is not 128 bits.");
1271 return ISC_R_SUCCESS;
1272 }
1273 memcpy(&addr, fixed_addr.data, 16);
1274 data_string_forget(&fixed_addr, MDL);
1275
1276 /*
1277 * Find the pool holding this host, and mark the address.
1278 * (I suppose it is arguably valid to have a host that does not
1279 * sit in any pool.)
1280 */
1281 p = NULL;
1282 if (find_ipv6_pool(&p, &addr) == ISC_R_SUCCESS) {
1283 mark_address_unavailable(p, &addr);
1284 ipv6_pool_dereference(&p, MDL);
1285 }
1286
1287 return ISC_R_SUCCESS;
1288}
1289
1290void
1291mark_hosts_unavailable(void) {
1292 hash_foreach(host_name_hash, mark_hosts_unavailable_support);
1293}
1294
1295void
1296mark_interfaces_unavailable(void) {
1297 struct interface_info *ip;
1298 int i;
1299 struct ipv6_pool *p;
1300
1301 ip = interfaces;
1302 while (ip != NULL) {
1303 for (i=0; i<ip->v6address_count; i++) {
1304 p = NULL;
1305 if (find_ipv6_pool(&p, &ip->v6addresses[i])
1306 == ISC_R_SUCCESS) {
1307 mark_address_unavailable(p,
1308 &ip->v6addresses[i]);
1309 ipv6_pool_dereference(&p, MDL);
1310 }
1311 }
1312 ip = ip->next;
1313 }
1314}
1315
1316
1317#ifdef UNIT_TEST
1318#include <stdlib.h>
1319
1320int
1321main(int argc, char *argv[]) {
1322 struct iaaddr *iaaddr;
1323 struct iaaddr *iaaddr_copy;
1324 u_int32_t iaid;
1325 struct ia_na *ia_na;
1326 struct ia_na *ia_na_copy;
1327 int i;
1328 struct in6_addr addr;
1329 struct ipv6_pool *pool;
1330 struct ipv6_pool *pool_copy;
1331 char addr_buf[INET6_ADDRSTRLEN];
1332 char *uid;
1333 struct data_string ds;
1334 struct iaaddr *expired_iaaddr;
1335 unsigned int attempts;
1336
1337 /*
1338 * Test 0: Basic iaaddr manipulation.
1339 */
1340 iaaddr = NULL;
1341 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
1342 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1343 return 1;
1344 }
1345 if (iaaddr->state != FTS_FREE) {
1346 printf("ERROR: bad state %s:%d\n", MDL);
1347 return 1;
1348 }
1349 if (iaaddr->heap_index != -1) {
1350 printf("ERROR: bad heap_index %s:%d\n", MDL);
1351 return 1;
1352 }
1353 iaaddr_copy = NULL;
1354 if (iaaddr_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_SUCCESS) {
1355 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1356 return 1;
1357 }
1358 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1359 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1360 return 1;
1361 }
1362 if (iaaddr_dereference(&iaaddr_copy, MDL) != ISC_R_SUCCESS) {
1363 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1364 return 1;
1365 }
1366
1367 /*
1368 * Test 1: Error iaaddr manipulation.
1369 */
1370 /* bogus allocate arguments */
1371 if (iaaddr_allocate(NULL, MDL) != ISC_R_INVALIDARG) {
1372 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1373 return 1;
1374 }
1375 iaaddr = (struct iaaddr *)1;
1376 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_INVALIDARG) {
1377 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1378 return 1;
1379 }
1380
1381 /* bogus reference arguments */
1382 iaaddr = NULL;
1383 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
1384 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1385 return 1;
1386 }
1387 if (iaaddr_reference(NULL, iaaddr, MDL) != ISC_R_INVALIDARG) {
1388 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1389 return 1;
1390 }
1391 iaaddr_copy = (struct iaaddr *)1;
1392 if (iaaddr_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_INVALIDARG) {
1393 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1394 return 1;
1395 }
1396 iaaddr_copy = NULL;
1397 if (iaaddr_reference(&iaaddr_copy, NULL, MDL) != ISC_R_INVALIDARG) {
1398 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1399 return 1;
1400 }
1401 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1402 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1403 return 1;
1404 }
1405
1406 /* bogus dereference arguments */
1407 if (iaaddr_dereference(NULL, MDL) != ISC_R_INVALIDARG) {
1408 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1409 return 1;
1410 }
1411 iaaddr = NULL;
1412 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_INVALIDARG) {
1413 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1414 return 1;
1415 }
1416
1417 /*
1418 * Test 2: Basic ia_na manipulation.
1419 */
1420 iaid = 666;
1421 ia_na = NULL;
1422 if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
1423 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1424 return 1;
1425 }
1426 if (memcmp(ia_na->iaid_duid.data, &iaid, sizeof(iaid)) != 0) {
1427 printf("ERROR: bad IAID_DUID %s:%d\n", MDL);
1428 return 1;
1429 }
1430 if (memcmp(ia_na->iaid_duid.data+sizeof(iaid), "TestDUID", 8) != 0) {
1431 printf("ERROR: bad IAID_DUID %s:%d\n", MDL);
1432 return 1;
1433 }
1434 if (ia_na->num_iaaddr != 0) {
1435 printf("ERROR: bad num_iaaddr %s:%d\n", MDL);
1436 return 1;
1437 }
1438 ia_na_copy = NULL;
1439 if (ia_na_reference(&ia_na_copy, ia_na, MDL) != ISC_R_SUCCESS) {
1440 printf("ERROR: ia_na_reference() %s:%d\n", MDL);
1441 return 1;
1442 }
1443 iaaddr = NULL;
1444 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
1445 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1446 return 1;
1447 }
1448 if (ia_na_add_iaaddr(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) {
1449 printf("ERROR: ia_na_add_iaaddr() %s:%d\n", MDL);
1450 return 1;
1451 }
1452 ia_na_remove_iaaddr(ia_na, iaaddr, MDL);
1453 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1454 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1455 return 1;
1456 }
1457 if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) {
1458 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1459 return 1;
1460 }
1461 if (ia_na_dereference(&ia_na_copy, MDL) != ISC_R_SUCCESS) {
1462 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1463 return 1;
1464 }
1465
1466 /*
1467 * Test 3: lots of iaaddr in our ia_na
1468 */
1469
1470 /* lots of iaaddr that we delete */
1471 iaid = 666;
1472 ia_na = NULL;
1473 if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
1474 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1475 return 1;
1476 }
1477 for (i=0; i<100; i++) {
1478 iaaddr = NULL;
1479 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
1480 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1481 return 1;
1482 }
1483 if (ia_na_add_iaaddr(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) {
1484 printf("ERROR: ia_na_add_iaaddr() %s:%d\n", MDL);
1485 return 1;
1486 }
1487 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1488 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1489 return 1;
1490 }
1491 }
1492 for (i=0; i<100; i++) {
1493 iaaddr = ia_na->iaaddr[random() % ia_na->num_iaaddr];
1494 ia_na_remove_iaaddr(ia_na, iaaddr, MDL);
1495 }
1496 if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) {
1497 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1498 return 1;
1499 }
1500
1501 /* lots of iaaddr, let dereference cleanup */
1502 iaid = 666;
1503 ia_na = NULL;
1504 if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
1505 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1506 return 1;
1507 }
1508 for (i=0; i<100; i++) {
1509 iaaddr = NULL;
1510 if (iaaddr_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
1511 printf("ERROR: iaaddr_allocate() %s:%d\n", MDL);
1512 return 1;
1513 }
1514 if (ia_na_add_iaaddr(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) {
1515 printf("ERROR: ia_na_add_iaaddr() %s:%d\n", MDL);
1516 return 1;
1517 }
1518 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1519 printf("ERROR: iaaddr_reference() %s:%d\n", MDL);
1520 return 1;
1521 }
1522 }
1523 if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) {
1524 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1525 return 1;
1526 }
1527
1528 /*
1529 * Test 4: Errors in ia_na.
1530 */
1531 /* bogus allocate arguments */
1532 if (ia_na_allocate(NULL, 123, "", 0, MDL) != ISC_R_INVALIDARG) {
1533 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1534 return 1;
1535 }
1536 ia_na = (struct ia_na *)1;
1537 if (ia_na_allocate(&ia_na, 456, "", 0, MDL) != ISC_R_INVALIDARG) {
1538 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1539 return 1;
1540 }
1541
1542 /* bogus reference arguments */
1543 iaid = 666;
1544 ia_na = NULL;
1545 if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
1546 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1547 return 1;
1548 }
1549 if (ia_na_reference(NULL, ia_na, MDL) != ISC_R_INVALIDARG) {
1550 printf("ERROR: ia_na_reference() %s:%d\n", MDL);
1551 return 1;
1552 }
1553 ia_na_copy = (struct ia_na *)1;
1554 if (ia_na_reference(&ia_na_copy, ia_na, MDL) != ISC_R_INVALIDARG) {
1555 printf("ERROR: ia_na_reference() %s:%d\n", MDL);
1556 return 1;
1557 }
1558 ia_na_copy = NULL;
1559 if (ia_na_reference(&ia_na_copy, NULL, MDL) != ISC_R_INVALIDARG) {
1560 printf("ERROR: ia_na_reference() %s:%d\n", MDL);
1561 return 1;
1562 }
1563 if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) {
1564 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1565 return 1;
1566 }
1567
1568 /* bogus dereference arguments */
1569 if (ia_na_dereference(NULL, MDL) != ISC_R_INVALIDARG) {
1570 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1571 return 1;
1572 }
1573
1574 /* bogus remove */
1575 iaid = 666;
1576 ia_na = NULL;
1577 if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
1578 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1579 return 1;
1580 }
1581 ia_na_remove_iaaddr(ia_na, NULL, MDL);
1582 if (ia_na_dereference(&ia_na, MDL) != ISC_R_SUCCESS) {
1583 printf("ERROR: ia_na_dereference() %s:%d\n", MDL);
1584 return 1;
1585 }
1586
1587 /*
1588 * Test 5: Basic ipv6_pool manipulation.
1589 */
1590
1591 /* allocate, reference */
1592 inet_pton(AF_INET6, "1:2:3:4::", &addr);
1593 pool = NULL;
1594 if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_SUCCESS) {
1595 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL);
1596 return 1;
1597 }
1598 if (pool->num_active != 0) {
1599 printf("ERROR: bad num_active %s:%d\n", MDL);
1600 return 1;
1601 }
1602 if (pool->bits != 64) {
1603 printf("ERROR: bad bits %s:%d\n", MDL);
1604 return 1;
1605 }
1606 inet_ntop(AF_INET6, &pool->start_addr, addr_buf, sizeof(addr_buf));
1607 if (strcmp(inet_ntop(AF_INET6, &pool->start_addr, addr_buf,
1608 sizeof(addr_buf)), "1:2:3:4::") != 0) {
1609 printf("ERROR: bad start_addr %s:%d\n", MDL);
1610 return 1;
1611 }
1612 pool_copy = NULL;
1613 if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_SUCCESS) {
1614 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL);
1615 return 1;
1616 }
1617
1618 /* activate_lease6, renew_lease6, expire_lease6 */
1619 uid = "client0";
1620 memset(&ds, 0, sizeof(ds));
1621 ds.len = strlen(uid);
1622 if (!buffer_allocate(&ds.buffer, ds.len, MDL)) {
1623 printf("Out of memory\n");
1624 return 1;
1625 }
1626 ds.data = ds.buffer->data;
1627 memcpy((char *)ds.data, uid, ds.len);
1628 if (activate_lease6(pool, &iaaddr,
1629 &attempts, &ds, 1) != ISC_R_SUCCESS) {
1630 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1631 return 1;
1632 }
1633 if (pool->num_active != 1) {
1634 printf("ERROR: bad num_active %s:%d\n", MDL);
1635 return 1;
1636 }
1637 if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) {
1638 printf("ERROR: renew_lease6() %s:%d\n", MDL);
1639 return 1;
1640 }
1641 if (pool->num_active != 1) {
1642 printf("ERROR: bad num_active %s:%d\n", MDL);
1643 return 1;
1644 }
1645 expired_iaaddr = NULL;
1646 if (expire_lease6(&expired_iaaddr, pool, 0) != ISC_R_SUCCESS) {
1647 printf("ERROR: expire_lease6() %s:%d\n", MDL);
1648 return 1;
1649 }
1650 if (expired_iaaddr != NULL) {
1651 printf("ERROR: should not have expired a lease %s:%d\n", MDL);
1652 return 1;
1653 }
1654 if (pool->num_active != 1) {
1655 printf("ERROR: bad num_active %s:%d\n", MDL);
1656 return 1;
1657 }
1658 if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) {
1659 printf("ERROR: expire_lease6() %s:%d\n", MDL);
1660 return 1;
1661 }
1662 if (expired_iaaddr == NULL) {
1663 printf("ERROR: should have expired a lease %s:%d\n", MDL);
1664 return 1;
1665 }
1666 if (iaaddr_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) {
1667 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1668 return 1;
1669 }
1670 if (pool->num_active != 0) {
1671 printf("ERROR: bad num_active %s:%d\n", MDL);
1672 return 1;
1673 }
1674 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1675 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1676 return 1;
1677 }
1678
1679 /* release_lease6, decline_lease6 */
1680 if (activate_lease6(pool, &iaaddr, &attempts,
1681 &ds, 1) != ISC_R_SUCCESS) {
1682 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1683 return 1;
1684 }
1685 if (pool->num_active != 1) {
1686 printf("ERROR: bad num_active %s:%d\n", MDL);
1687 return 1;
1688 }
1689 if (release_lease6(pool, iaaddr) != ISC_R_SUCCESS) {
1690 printf("ERROR: decline_lease6() %s:%d\n", MDL);
1691 return 1;
1692 }
1693 if (pool->num_active != 0) {
1694 printf("ERROR: bad num_active %s:%d\n", MDL);
1695 return 1;
1696 }
1697 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1698 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1699 return 1;
1700 }
1701 if (activate_lease6(pool, &iaaddr, &attempts,
1702 &ds, 1) != ISC_R_SUCCESS) {
1703 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1704 return 1;
1705 }
1706 if (pool->num_active != 1) {
1707 printf("ERROR: bad num_active %s:%d\n", MDL);
1708 return 1;
1709 }
1710 if (decline_lease6(pool, iaaddr) != ISC_R_SUCCESS) {
1711 printf("ERROR: decline_lease6() %s:%d\n", MDL);
1712 return 1;
1713 }
1714 if (pool->num_active != 1) {
1715 printf("ERROR: bad num_active %s:%d\n", MDL);
1716 return 1;
1717 }
1718 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1719 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1720 return 1;
1721 }
1722
1723 /* dereference */
1724 if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) {
1725 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL);
1726 return 1;
1727 }
1728 if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_SUCCESS) {
1729 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL);
1730 return 1;
1731 }
1732
1733 /*
1734 * Test 6: Error ipv6_pool manipulation
1735 */
1736 if (ipv6_pool_allocate(NULL, &addr, 64, MDL) != ISC_R_INVALIDARG) {
1737 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL);
1738 return 1;
1739 }
1740 pool = (struct ipv6_pool *)1;
1741 if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_INVALIDARG) {
1742 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL);
1743 return 1;
1744 }
1745 if (ipv6_pool_reference(NULL, pool, MDL) != ISC_R_INVALIDARG) {
1746 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL);
1747 return 1;
1748 }
1749 pool_copy = (struct ipv6_pool *)1;
1750 if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_INVALIDARG) {
1751 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL);
1752 return 1;
1753 }
1754 pool_copy = NULL;
1755 if (ipv6_pool_reference(&pool_copy, NULL, MDL) != ISC_R_INVALIDARG) {
1756 printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL);
1757 return 1;
1758 }
1759 if (ipv6_pool_dereference(NULL, MDL) != ISC_R_INVALIDARG) {
1760 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1761 return 1;
1762 }
1763 if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_INVALIDARG) {
1764 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1765 return 1;
1766 }
1767
1768 /*
1769 * Test 7: order of expiration
1770 */
1771 pool = NULL;
1772 if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_SUCCESS) {
1773 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL);
1774 return 1;
1775 }
1776 for (i=10; i<100; i+=10) {
1777 if (activate_lease6(pool, &iaaddr, &attempts,
1778 &ds, i) != ISC_R_SUCCESS) {
1779 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1780 return 1;
1781 }
1782 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1783 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1784 return 1;
1785 }
1786 if (pool->num_active != (i / 10)) {
1787 printf("ERROR: bad num_active %s:%d\n", MDL);
1788 return 1;
1789 }
1790 }
1791 if (pool->num_active != 9) {
1792 printf("ERROR: bad num_active %s:%d\n", MDL);
1793 return 1;
1794 }
1795 for (i=10; i<100; i+=10) {
1796 if (expire_lease6(&expired_iaaddr,
1797 pool, 1000) != ISC_R_SUCCESS) {
1798 printf("ERROR: expire_lease6() %s:%d\n", MDL);
1799 return 1;
1800 }
1801 if (expired_iaaddr == NULL) {
1802 printf("ERROR: should have expired a lease %s:%d\n",
1803 MDL);
1804 return 1;
1805 }
1806 if (pool->num_active != (9 - (i / 10))) {
1807 printf("ERROR: bad num_active %s:%d\n", MDL);
1808 return 1;
1809 }
1810 if (expired_iaaddr->valid_lifetime_end_time != i) {
1811 printf("ERROR: bad valid_lifetime_end_time %s:%d\n",
1812 MDL);
1813 return 1;
1814 }
1815 if (iaaddr_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) {
1816 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1817 return 1;
1818 }
1819 }
1820 if (pool->num_active != 0) {
1821 printf("ERROR: bad num_active %s:%d\n", MDL);
1822 return 1;
1823 }
1824 expired_iaaddr = NULL;
1825 if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) {
1826 printf("ERROR: expire_lease6() %s:%d\n", MDL);
1827 return 1;
1828 }
1829 if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) {
1830 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1831 return 1;
1832 }
1833
1834 /*
1835 * Test 8: small pool
1836 */
1837 pool = NULL;
1838 if (ipv6_pool_allocate(&pool, &addr, 127, MDL) != ISC_R_SUCCESS) {
1839 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL);
1840 return 1;
1841 }
1842 if (activate_lease6(pool, &iaaddr, &attempts,
1843 &ds, 42) != ISC_R_SUCCESS) {
1844 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1845 return 1;
1846 }
1847 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1848 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1849 return 1;
1850 }
1851 if (activate_lease6(pool, &iaaddr, &attempts,
1852 &ds, 11) != ISC_R_SUCCESS) {
1853 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1854 return 1;
1855 }
1856 if (iaaddr_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) {
1857 printf("ERROR: iaaddr_dereference() %s:%d\n", MDL);
1858 return 1;
1859 }
1860 if (activate_lease6(pool, &iaaddr, &attempts,
1861 &ds, 11) != ISC_R_NORESOURCES) {
1862 printf("ERROR: activate_lease6() %s:%d\n", MDL);
1863 return 1;
1864 }
1865 if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) {
1866 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1867 return 1;
1868 }
1869
1870 /*
1871 * Test 9: functions across all pools
1872 */
1873 pool = NULL;
1874 if (ipv6_pool_allocate(&pool, &addr, 64, MDL) != ISC_R_SUCCESS) {
1875 printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL);
1876 return 1;
1877 }
1878 if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
1879 printf("ERROR: add_ipv6_pool() %s:%d\n", MDL);
1880 return 1;
1881 }
1882 if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) {
1883 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1884 return 1;
1885 }
1886 pool = NULL;
1887 if (find_ipv6_pool(&pool, &addr) != ISC_R_SUCCESS) {
1888 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL);
1889 return 1;
1890 }
1891 if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) {
1892 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1893 return 1;
1894 }
1895 inet_pton(AF_INET6, "1:2:3:4:ffff:ffff:ffff:ffff", &addr);
1896 pool = NULL;
1897 if (find_ipv6_pool(&pool, &addr) != ISC_R_SUCCESS) {
1898 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL);
1899 return 1;
1900 }
1901 if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) {
1902 printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL);
1903 return 1;
1904 }
1905 inet_pton(AF_INET6, "1:2:3:5::", &addr);
1906 pool = NULL;
1907 if (find_ipv6_pool(&pool, &addr) != ISC_R_NOTFOUND) {
1908 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL);
1909 return 1;
1910 }
1911 inet_pton(AF_INET6, "1:2:3:3:ffff:ffff:ffff:ffff", &addr);
1912 pool = NULL;
1913 if (find_ipv6_pool(&pool, &addr) != ISC_R_NOTFOUND) {
1914 printf("ERROR: find_ipv6_pool() %s:%d\n", MDL);
1915 return 1;
1916 }
1917
1918/* iaid = 666;
1919 ia_na = NULL;
1920 if (ia_na_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) {
1921 printf("ERROR: ia_na_allocate() %s:%d\n", MDL);
1922 return 1;
1923 }*/
1924
1925 printf("SUCCESS: all tests passed (ignore any warning messages)\n");
1926 return 0;
1927}
1928#endif