00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00168 #include "config.h"
00169
00170 #include <sys/types.h>
00171 #include <time.h>
00172 #include <netinet/in.h>
00173
00174 #include <stdarg.h>
00175 #include "dhcpd.h"
00176 #include "omapip/omapip.h"
00177 #include "omapip/hash.h"
00178 #include <isc/md5.h>
00179
00180 HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t,
00181 ia_reference, ia_dereference, do_string_hash)
00182
00183 ia_hash_t *ia_na_active;
00184 ia_hash_t *ia_ta_active;
00185 ia_hash_t *ia_pd_active;
00186
00187 HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t,
00188 iasubopt_reference, iasubopt_dereference, do_string_hash)
00189
00190 struct ipv6_pool **pools;
00191 int num_pools;
00192
00193
00194
00195
00196
00197
00198
00199 isc_result_t
00200 iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) {
00201 struct iasubopt *tmp;
00202
00203 if (iasubopt == NULL) {
00204 log_error("%s(%d): NULL pointer reference", file, line);
00205 return DHCP_R_INVALIDARG;
00206 }
00207 if (*iasubopt != NULL) {
00208 log_error("%s(%d): non-NULL pointer", file, line);
00209 return DHCP_R_INVALIDARG;
00210 }
00211
00212 tmp = dmalloc(sizeof(*tmp), file, line);
00213 if (tmp == NULL) {
00214 return ISC_R_NOMEMORY;
00215 }
00216
00217 tmp->refcnt = 1;
00218 tmp->state = FTS_FREE;
00219 tmp->heap_index = -1;
00220 tmp->plen = 255;
00221
00222 *iasubopt = tmp;
00223 return ISC_R_SUCCESS;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232 isc_result_t
00233 iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src,
00234 const char *file, int line) {
00235 if (iasubopt == NULL) {
00236 log_error("%s(%d): NULL pointer reference", file, line);
00237 return DHCP_R_INVALIDARG;
00238 }
00239 if (*iasubopt != NULL) {
00240 log_error("%s(%d): non-NULL pointer", file, line);
00241 return DHCP_R_INVALIDARG;
00242 }
00243 if (src == NULL) {
00244 log_error("%s(%d): NULL pointer reference", file, line);
00245 return DHCP_R_INVALIDARG;
00246 }
00247 *iasubopt = src;
00248 src->refcnt++;
00249 return ISC_R_SUCCESS;
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259 isc_result_t
00260 iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) {
00261 struct iasubopt *tmp;
00262
00263 if ((iasubopt == NULL) || (*iasubopt == NULL)) {
00264 log_error("%s(%d): NULL pointer", file, line);
00265 return DHCP_R_INVALIDARG;
00266 }
00267
00268 tmp = *iasubopt;
00269 *iasubopt = NULL;
00270
00271 tmp->refcnt--;
00272 if (tmp->refcnt < 0) {
00273 log_error("%s(%d): negative refcnt", file, line);
00274 tmp->refcnt = 0;
00275 }
00276 if (tmp->refcnt == 0) {
00277 if (tmp->ia != NULL) {
00278 ia_dereference(&(tmp->ia), file, line);
00279 }
00280 if (tmp->ipv6_pool != NULL) {
00281 ipv6_pool_dereference(&(tmp->ipv6_pool), file, line);
00282 }
00283 if (tmp->scope != NULL) {
00284 binding_scope_dereference(&tmp->scope, file, line);
00285 }
00286
00287 if (tmp->on_star.on_expiry != NULL) {
00288 executable_statement_dereference
00289 (&tmp->on_star.on_expiry, MDL);
00290 }
00291 if (tmp->on_star.on_commit != NULL) {
00292 executable_statement_dereference
00293 (&tmp->on_star.on_commit, MDL);
00294 }
00295 if (tmp->on_star.on_release != NULL) {
00296 executable_statement_dereference
00297 (&tmp->on_star.on_release, MDL);
00298 }
00299
00300 dfree(tmp, file, line);
00301 }
00302
00303 return ISC_R_SUCCESS;
00304 }
00305
00306
00307
00308
00309 isc_result_t
00310 ia_make_key(struct data_string *key, u_int32_t iaid,
00311 const char *duid, unsigned int duid_len,
00312 const char *file, int line) {
00313
00314 memset(key, 0, sizeof(*key));
00315 key->len = duid_len + sizeof(iaid);
00316 if (!buffer_allocate(&(key->buffer), key->len, file, line)) {
00317 return ISC_R_NOMEMORY;
00318 }
00319 key->data = key->buffer->data;
00320 memcpy((char *)key->data, &iaid, sizeof(iaid));
00321 memcpy((char *)key->data + sizeof(iaid), duid, duid_len);
00322
00323 return ISC_R_SUCCESS;
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 isc_result_t
00338 ia_allocate(struct ia_xx **ia, u_int32_t iaid,
00339 const char *duid, unsigned int duid_len,
00340 const char *file, int line) {
00341 struct ia_xx *tmp;
00342
00343 if (ia == NULL) {
00344 log_error("%s(%d): NULL pointer reference", file, line);
00345 return DHCP_R_INVALIDARG;
00346 }
00347 if (*ia != NULL) {
00348 log_error("%s(%d): non-NULL pointer", file, line);
00349 return DHCP_R_INVALIDARG;
00350 }
00351
00352 tmp = dmalloc(sizeof(*tmp), file, line);
00353 if (tmp == NULL) {
00354 return ISC_R_NOMEMORY;
00355 }
00356
00357 if (ia_make_key(&tmp->iaid_duid, iaid,
00358 duid, duid_len, file, line) != ISC_R_SUCCESS) {
00359 dfree(tmp, file, line);
00360 return ISC_R_NOMEMORY;
00361 }
00362
00363 tmp->refcnt = 1;
00364
00365 *ia = tmp;
00366 return ISC_R_SUCCESS;
00367 }
00368
00369
00370
00371
00372
00373
00374
00375 isc_result_t
00376 ia_reference(struct ia_xx **ia, struct ia_xx *src,
00377 const char *file, int line) {
00378 if (ia == NULL) {
00379 log_error("%s(%d): NULL pointer reference", file, line);
00380 return DHCP_R_INVALIDARG;
00381 }
00382 if (*ia != NULL) {
00383 log_error("%s(%d): non-NULL pointer", file, line);
00384 return DHCP_R_INVALIDARG;
00385 }
00386 if (src == NULL) {
00387 log_error("%s(%d): NULL pointer reference", file, line);
00388 return DHCP_R_INVALIDARG;
00389 }
00390 *ia = src;
00391 src->refcnt++;
00392 return ISC_R_SUCCESS;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401 isc_result_t
00402 ia_dereference(struct ia_xx **ia, const char *file, int line) {
00403 struct ia_xx *tmp;
00404 int i;
00405
00406 if ((ia == NULL) || (*ia == NULL)) {
00407 log_error("%s(%d): NULL pointer", file, line);
00408 return DHCP_R_INVALIDARG;
00409 }
00410
00411 tmp = *ia;
00412 *ia = NULL;
00413
00414 tmp->refcnt--;
00415 if (tmp->refcnt < 0) {
00416 log_error("%s(%d): negative refcnt", file, line);
00417 tmp->refcnt = 0;
00418 }
00419 if (tmp->refcnt == 0) {
00420 if (tmp->iasubopt != NULL) {
00421 for (i=0; i<tmp->num_iasubopt; i++) {
00422 iasubopt_dereference(&(tmp->iasubopt[i]),
00423 file, line);
00424 }
00425 dfree(tmp->iasubopt, file, line);
00426 }
00427 data_string_forget(&(tmp->iaid_duid), file, line);
00428 dfree(tmp, file, line);
00429 }
00430 return ISC_R_SUCCESS;
00431 }
00432
00433
00434
00435
00436
00437 isc_result_t
00438 ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
00439 const char *file, int line) {
00440 int max;
00441 struct iasubopt **new;
00442
00443
00444
00445
00446
00447
00448
00449
00450 if (ia->max_iasubopt <= ia->num_iasubopt) {
00451 max = ia->max_iasubopt + 4;
00452 new = dmalloc(max * sizeof(struct iasubopt *), file, line);
00453 if (new == NULL) {
00454 return ISC_R_NOMEMORY;
00455 }
00456 memcpy(new, ia->iasubopt,
00457 ia->num_iasubopt * sizeof(struct iasubopt *));
00458 ia->iasubopt = new;
00459 ia->max_iasubopt = max;
00460 }
00461
00462 iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt,
00463 file, line);
00464 ia->num_iasubopt++;
00465
00466 return ISC_R_SUCCESS;
00467 }
00468
00469
00470
00471
00472
00473
00474 void
00475 ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt,
00476 const char *file, int line) {
00477 int i, j;
00478 if (ia == NULL || iasubopt == NULL)
00479 return;
00480
00481 for (i=0; i<ia->num_iasubopt; i++) {
00482 if (ia->iasubopt[i] == iasubopt) {
00483
00484 iasubopt_dereference(&(ia->iasubopt[i]), file, line);
00485
00486 for (j=i+1; j < ia->num_iasubopt; j++) {
00487 ia->iasubopt[j-1] = ia->iasubopt[j];
00488 }
00489
00490
00491 ia_dereference(&iasubopt->ia, file, line);
00492 ia->num_iasubopt--;
00493 return;
00494 }
00495 }
00496 log_error("%s(%d): IAADDR/PREFIX not in IA", file, line);
00497 }
00498
00499
00500
00501
00502 void
00503 ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) {
00504 int i;
00505
00506 for (i=0; i<ia->num_iasubopt; i++) {
00507 ia_dereference(&(ia->iasubopt[i]->ia), file, line);
00508 iasubopt_dereference(&(ia->iasubopt[i]), file, line);
00509 }
00510 ia->num_iasubopt = 0;
00511 }
00512
00513
00514
00515
00516 isc_boolean_t
00517 ia_equal(const struct ia_xx *a, const struct ia_xx *b)
00518 {
00519 isc_boolean_t found;
00520 int i, j;
00521
00522
00523
00524
00525 if (a == NULL) {
00526 if (b == NULL) {
00527 return ISC_TRUE;
00528 } else {
00529 return ISC_FALSE;
00530 }
00531 }
00532
00533
00534
00535
00536 if (a->ia_type != b->ia_type) {
00537 return ISC_FALSE;
00538 }
00539
00540
00541
00542
00543 if (a->iaid_duid.len != b->iaid_duid.len) {
00544 return ISC_FALSE;
00545 }
00546 if (memcmp(a->iaid_duid.data,
00547 b->iaid_duid.data, a->iaid_duid.len) != 0) {
00548 return ISC_FALSE;
00549 }
00550
00551
00552
00553
00554 if (a->num_iasubopt != b->num_iasubopt) {
00555 return ISC_FALSE;
00556 }
00557
00558
00559
00560
00561 for (i=0; i<a->num_iasubopt; i++) {
00562 found = ISC_FALSE;
00563 for (j=0; j<a->num_iasubopt; j++) {
00564 if (a->iasubopt[i]->plen != b->iasubopt[i]->plen)
00565 continue;
00566 if (memcmp(&(a->iasubopt[i]->addr),
00567 &(b->iasubopt[j]->addr),
00568 sizeof(struct in6_addr)) == 0) {
00569 found = ISC_TRUE;
00570 break;
00571 }
00572 }
00573 if (!found) {
00574 return ISC_FALSE;
00575 }
00576 }
00577
00578
00579
00580
00581 return ISC_TRUE;
00582 }
00583
00584
00585
00586
00587
00588 static isc_boolean_t
00589 lease_older(void *a, void *b) {
00590 struct iasubopt *la = (struct iasubopt *)a;
00591 struct iasubopt *lb = (struct iasubopt *)b;
00592
00593 if (la->hard_lifetime_end_time == lb->hard_lifetime_end_time) {
00594 return difftime(la->soft_lifetime_end_time,
00595 lb->soft_lifetime_end_time) < 0;
00596 } else {
00597 return difftime(la->hard_lifetime_end_time,
00598 lb->hard_lifetime_end_time) < 0;
00599 }
00600 }
00601
00602
00603
00604
00605
00606 static void
00607 lease_index_changed(void *iasubopt, unsigned int new_heap_index) {
00608 ((struct iasubopt *)iasubopt)-> heap_index = new_heap_index;
00609 }
00610
00611
00634 isc_result_t
00635 ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
00636 const struct in6_addr *start_addr, int bits,
00637 int units, const char *file, int line) {
00638 struct ipv6_pool *tmp;
00639
00640 if (pool == NULL) {
00641 log_error("%s(%d): NULL pointer reference", file, line);
00642 return DHCP_R_INVALIDARG;
00643 }
00644 if (*pool != NULL) {
00645 log_error("%s(%d): non-NULL pointer", file, line);
00646 return DHCP_R_INVALIDARG;
00647 }
00648
00649 tmp = dmalloc(sizeof(*tmp), file, line);
00650 if (tmp == NULL) {
00651 return ISC_R_NOMEMORY;
00652 }
00653
00654 tmp->refcnt = 1;
00655 tmp->pool_type = type;
00656 tmp->start_addr = *start_addr;
00657 tmp->bits = bits;
00658 tmp->units = units;
00659 if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) {
00660 dfree(tmp, file, line);
00661 return ISC_R_NOMEMORY;
00662 }
00663 if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed,
00664 0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) {
00665 iasubopt_free_hash_table(&(tmp->leases), file, line);
00666 dfree(tmp, file, line);
00667 return ISC_R_NOMEMORY;
00668 }
00669 if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed,
00670 0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) {
00671 isc_heap_destroy(&(tmp->active_timeouts));
00672 iasubopt_free_hash_table(&(tmp->leases), file, line);
00673 dfree(tmp, file, line);
00674 return ISC_R_NOMEMORY;
00675 }
00676
00677 *pool = tmp;
00678 return ISC_R_SUCCESS;
00679 }
00680
00700 isc_result_t
00701 ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
00702 const char *file, int line) {
00703 if (pool == NULL) {
00704 log_error("%s(%d): NULL pointer reference", file, line);
00705 return DHCP_R_INVALIDARG;
00706 }
00707 if (*pool != NULL) {
00708 log_error("%s(%d): non-NULL pointer", file, line);
00709 return DHCP_R_INVALIDARG;
00710 }
00711 if (src == NULL) {
00712 log_error("%s(%d): NULL pointer reference", file, line);
00713 return DHCP_R_INVALIDARG;
00714 }
00715 *pool = src;
00716 src->refcnt++;
00717 return ISC_R_SUCCESS;
00718 }
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 static isc_result_t
00734 dereference_hash_entry(const void *name, unsigned len, void *value) {
00735 struct iasubopt *iasubopt = (struct iasubopt *)value;
00736
00737 iasubopt_dereference(&iasubopt, MDL);
00738 return ISC_R_SUCCESS;
00739 }
00740
00741
00742
00743
00744
00745 static void
00746 dereference_heap_entry(void *value, void *dummy) {
00747 struct iasubopt *iasubopt = (struct iasubopt *)value;
00748
00749 iasubopt_dereference(&iasubopt, MDL);
00750 }
00751
00771 isc_result_t
00772 ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
00773 struct ipv6_pool *tmp;
00774
00775 if ((pool == NULL) || (*pool == NULL)) {
00776 log_error("%s(%d): NULL pointer", file, line);
00777 return DHCP_R_INVALIDARG;
00778 }
00779
00780 tmp = *pool;
00781 *pool = NULL;
00782
00783 tmp->refcnt--;
00784 if (tmp->refcnt < 0) {
00785 log_error("%s(%d): negative refcnt", file, line);
00786 tmp->refcnt = 0;
00787 }
00788 if (tmp->refcnt == 0) {
00789 iasubopt_hash_foreach(tmp->leases, dereference_hash_entry);
00790 iasubopt_free_hash_table(&(tmp->leases), file, line);
00791 isc_heap_foreach(tmp->active_timeouts,
00792 dereference_heap_entry, NULL);
00793 isc_heap_destroy(&(tmp->active_timeouts));
00794 isc_heap_foreach(tmp->inactive_timeouts,
00795 dereference_heap_entry, NULL);
00796 isc_heap_destroy(&(tmp->inactive_timeouts));
00797 dfree(tmp, file, line);
00798 }
00799
00800 return ISC_R_SUCCESS;
00801 }
00802
00803
00804
00805
00806
00807 static void
00808 build_address6(struct in6_addr *addr,
00809 const struct in6_addr *net_start_addr, int net_bits,
00810 const struct data_string *input) {
00811 isc_md5_t ctx;
00812 int net_bytes;
00813 int i;
00814 char *str;
00815 const char *net_str;
00816
00817
00818
00819
00820
00821
00822 isc_md5_init(&ctx);
00823 isc_md5_update(&ctx, input->data, input->len);
00824 isc_md5_final(&ctx, (unsigned char *)addr);
00825
00826
00827
00828
00829 str = (char *)addr;
00830 net_str = (const char *)net_start_addr;
00831 net_bytes = net_bits / 8;
00832 for (i = 0; i < net_bytes; i++) {
00833 str[i] = net_str[i];
00834 }
00835 switch (net_bits % 8) {
00836 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
00837 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
00838 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
00839 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
00840 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
00841 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
00842 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
00843 }
00844
00845
00846
00847
00848
00849
00850 if (net_bits == 64)
00851 str[8] &= ~0x02;
00852 }
00853
00854
00855
00856
00857
00858 static void
00859 build_temporary6(struct in6_addr *addr,
00860 const struct in6_addr *net_start_addr, int net_bits,
00861 const struct data_string *input) {
00862 static u_int32_t history[2];
00863 static u_int32_t counter = 0;
00864 isc_md5_t ctx;
00865 unsigned char md[16];
00866
00867
00868
00869
00870
00871 if (counter == 0) {
00872 isc_random_get(&history[0]);
00873 isc_random_get(&history[1]);
00874 }
00875
00876
00877
00878
00879 isc_md5_init(&ctx);
00880 isc_md5_update(&ctx, (unsigned char *)&history[0], 8UL);
00881 isc_md5_update(&ctx, input->data, input->len);
00882 isc_md5_final(&ctx, md);
00883
00884
00885
00886
00887 if (net_bits == 64) {
00888 memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8);
00889 memcpy(&addr->s6_addr[8], md, 8);
00890 addr->s6_addr[8] &= ~0x02;
00891 } else {
00892 int net_bytes;
00893 int i;
00894 char *str;
00895 const char *net_str;
00896
00897
00898
00899
00900 str = (char *)addr;
00901 net_str = (const char *)net_start_addr;
00902 net_bytes = net_bits / 8;
00903 for (i = 0; i < net_bytes; i++) {
00904 str[i] = net_str[i];
00905 }
00906 memcpy(str + net_bytes, md, 16 - net_bytes);
00907 switch (net_bits % 8) {
00908 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
00909 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
00910 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
00911 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
00912 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
00913 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
00914 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
00915 }
00916 }
00917
00918
00919
00920
00921
00922 memcpy((unsigned char *)&history[0], md + 8, 8);
00923 counter++;
00924 }
00925
00926
00927 static struct in6_addr rtany;
00928
00929 static struct in6_addr resany;
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952 isc_result_t
00953 create_lease6(struct ipv6_pool *pool, struct iasubopt **addr,
00954 unsigned int *attempts,
00955 const struct data_string *uid, time_t soft_lifetime_end_time) {
00956 struct data_string ds;
00957 struct in6_addr tmp;
00958 struct iasubopt *test_iaaddr;
00959 struct data_string new_ds;
00960 struct iasubopt *iaaddr;
00961 isc_result_t result;
00962 isc_boolean_t reserved_iid;
00963 static isc_boolean_t init_resiid = ISC_FALSE;
00964
00965
00966
00967
00968 if (!init_resiid) {
00969 memset(&rtany, 0, 16);
00970 memset(&resany, 0, 8);
00971 resany.s6_addr[8] = 0xfd;
00972 memset(&resany.s6_addr[9], 0xff, 6);
00973 init_resiid = ISC_TRUE;
00974 }
00975
00976
00977
00978
00979 memset(&ds, 0, sizeof(ds));
00980 data_string_copy(&ds, (struct data_string *)uid, MDL);
00981
00982 *attempts = 0;
00983 for (;;) {
00984
00985
00986
00987 if (++(*attempts) > 100) {
00988 data_string_forget(&ds, MDL);
00989 return ISC_R_NORESOURCES;
00990 }
00991
00992
00993
00994
00995 switch (pool->pool_type) {
00996 case D6O_IA_NA:
00997
00998 build_address6(&tmp, &pool->start_addr,
00999 pool->bits, &ds);
01000 break;
01001 case D6O_IA_TA:
01002
01003 build_temporary6(&tmp, &pool->start_addr,
01004 pool->bits, &ds);
01005 break;
01006 case D6O_IA_PD:
01007
01008 log_error("create_lease6: prefix pool.");
01009 return DHCP_R_INVALIDARG;
01010 default:
01011 log_error("create_lease6: untyped pool.");
01012 return DHCP_R_INVALIDARG;
01013 }
01014
01015
01016
01017
01018 reserved_iid = ISC_FALSE;
01019 if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) {
01020 reserved_iid = ISC_TRUE;
01021 }
01022 if (!reserved_iid &&
01023 (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
01024 ((tmp.s6_addr[15] & 0x80) == 0x80)) {
01025 reserved_iid = ISC_TRUE;
01026 }
01027
01028
01029
01030
01031 test_iaaddr = NULL;
01032 if (!reserved_iid &&
01033 (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
01034 &tmp, sizeof(tmp), MDL) == 0)) {
01035 break;
01036 }
01037 if (test_iaaddr != NULL)
01038 iasubopt_dereference(&test_iaaddr, MDL);
01039
01040
01041
01042
01043 memset(&new_ds, 0, sizeof(new_ds));
01044 new_ds.len = ds.len + sizeof(tmp);
01045 if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
01046 data_string_forget(&ds, MDL);
01047 return ISC_R_NOMEMORY;
01048 }
01049 new_ds.data = new_ds.buffer->data;
01050 memcpy(new_ds.buffer->data, ds.data, ds.len);
01051 memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
01052 data_string_forget(&ds, MDL);
01053 data_string_copy(&ds, &new_ds, MDL);
01054 data_string_forget(&new_ds, MDL);
01055 }
01056
01057 data_string_forget(&ds, MDL);
01058
01059
01060
01061
01062
01063 iaaddr = NULL;
01064 result = iasubopt_allocate(&iaaddr, MDL);
01065 if (result != ISC_R_SUCCESS) {
01066 return result;
01067 }
01068 iaaddr->plen = 0;
01069 memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
01070
01071
01072
01073
01074 result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
01075 if (result == ISC_R_SUCCESS) {
01076 iasubopt_reference(addr, iaaddr, MDL);
01077 }
01078 iasubopt_dereference(&iaaddr, MDL);
01079 return result;
01080 }
01081
01082
01123 isc_result_t
01124 cleanup_lease6(ia_hash_t *ia_table,
01125 struct ipv6_pool *pool,
01126 struct iasubopt *lease,
01127 struct ia_xx *ia) {
01128
01129 struct iasubopt *test_iasubopt, *tmp_iasubopt;
01130 struct ia_xx *old_ia;
01131 isc_result_t status = ISC_R_SUCCESS;
01132
01133 test_iasubopt = NULL;
01134 old_ia = NULL;
01135
01136
01137
01138
01139
01140 if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
01141 &lease->addr, sizeof(lease->addr),
01142 MDL) == 0) {
01143 return (ISC_R_SUCCESS);
01144 }
01145
01146 if (test_iasubopt->ia == NULL) {
01147
01148 iasubopt_dereference(&test_iasubopt, MDL);
01149 return (status);
01150 }
01151
01152 ia_reference(&old_ia, test_iasubopt->ia, MDL);
01153
01154 if ((old_ia->iaid_duid.len == ia->iaid_duid.len) &&
01155 (memcmp((unsigned char *)ia->iaid_duid.data,
01156 (unsigned char *)old_ia->iaid_duid.data,
01157 ia->iaid_duid.len) == 0)) {
01158
01159 if ((lease->state == FTS_ACTIVE) ||
01160 (lease->state == FTS_ABANDONED)) {
01161
01162 goto cleanup;
01163 }
01164 } else {
01165
01166 if ((lease->state != FTS_ACTIVE) &&
01167 (lease->state != FTS_ABANDONED)) {
01168
01169 goto cleanup;
01170 }
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182 status = ISC_R_FAILURE;
01183 }
01184
01185
01186
01187
01188
01189 isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index);
01190 pool->num_active--;
01191
01192 iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
01193 sizeof(test_iasubopt->addr), MDL);
01194 ia_remove_iasubopt(old_ia, test_iasubopt, MDL);
01195 if (old_ia->num_iasubopt <= 0) {
01196 ia_hash_delete(ia_table,
01197 (unsigned char *)old_ia->iaid_duid.data,
01198 old_ia->iaid_duid.len, MDL);
01199 }
01200
01201
01202
01203
01204
01205
01206 tmp_iasubopt = test_iasubopt;
01207 iasubopt_dereference(&tmp_iasubopt, MDL);
01208
01209 cleanup:
01210 ia_dereference(&old_ia, MDL);
01211
01212
01213
01214
01215
01216 iasubopt_dereference(&test_iasubopt, MDL);
01217
01218 return (status);
01219 }
01220
01221
01222
01223
01224
01225 isc_result_t
01226 add_lease6(struct ipv6_pool *pool, struct iasubopt *lease,
01227 time_t valid_lifetime_end_time) {
01228 isc_result_t insert_result;
01229 struct iasubopt *test_iasubopt;
01230 struct iasubopt *tmp_iasubopt;
01231
01232
01233 if (lease->state == 0)
01234 lease->state = FTS_ACTIVE;
01235
01236 ipv6_pool_reference(&lease->ipv6_pool, pool, MDL);
01237
01238
01239
01240
01241
01242 test_iasubopt = NULL;
01243 if (iasubopt_hash_lookup(&test_iasubopt, pool->leases,
01244 &lease->addr, sizeof(lease->addr), MDL)) {
01245
01246
01247
01248
01249
01250
01251 if ((test_iasubopt->state == FTS_ACTIVE) ||
01252 (test_iasubopt->state == FTS_ABANDONED)) {
01253 isc_heap_delete(pool->active_timeouts,
01254 test_iasubopt->heap_index);
01255 pool->num_active--;
01256 } else {
01257 isc_heap_delete(pool->inactive_timeouts,
01258 test_iasubopt->heap_index);
01259 pool->num_inactive--;
01260 }
01261
01262 iasubopt_hash_delete(pool->leases, &test_iasubopt->addr,
01263 sizeof(test_iasubopt->addr), MDL);
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273 tmp_iasubopt = test_iasubopt;
01274 iasubopt_dereference(&test_iasubopt, MDL);
01275 iasubopt_dereference(&tmp_iasubopt, MDL);
01276 }
01277
01278
01279
01280
01281 tmp_iasubopt = NULL;
01282 iasubopt_reference(&tmp_iasubopt, lease, MDL);
01283 if ((tmp_iasubopt->state == FTS_ACTIVE) ||
01284 (tmp_iasubopt->state == FTS_ABANDONED)) {
01285 tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time;
01286 iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr,
01287 sizeof(tmp_iasubopt->addr), lease, MDL);
01288 insert_result = isc_heap_insert(pool->active_timeouts,
01289 tmp_iasubopt);
01290 if (insert_result == ISC_R_SUCCESS)
01291 pool->num_active++;
01292 } else {
01293 tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time;
01294 insert_result = isc_heap_insert(pool->inactive_timeouts,
01295 tmp_iasubopt);
01296 if (insert_result == ISC_R_SUCCESS)
01297 pool->num_inactive++;
01298 }
01299 if (insert_result != ISC_R_SUCCESS) {
01300 iasubopt_hash_delete(pool->leases, &lease->addr,
01301 sizeof(lease->addr), MDL);
01302 iasubopt_dereference(&tmp_iasubopt, MDL);
01303 return insert_result;
01304 }
01305
01306
01307
01308
01309
01310
01311 return ISC_R_SUCCESS;
01312 }
01313
01314
01315
01316
01317 isc_boolean_t
01318 lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) {
01319 struct iasubopt *test_iaaddr;
01320
01321 test_iaaddr = NULL;
01322 if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
01323 (void *)addr, sizeof(*addr), MDL)) {
01324 iasubopt_dereference(&test_iaaddr, MDL);
01325 return ISC_TRUE;
01326 } else {
01327 return ISC_FALSE;
01328 }
01329 }
01330
01345 isc_boolean_t
01346 lease6_usable(struct iasubopt *lease) {
01347 struct iasubopt *test_iaaddr;
01348 isc_boolean_t status = ISC_TRUE;
01349
01350 test_iaaddr = NULL;
01351 if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases,
01352 (void *)&lease->addr,
01353 sizeof(lease->addr), MDL)) {
01354 if (test_iaaddr != lease) {
01355 status = ISC_FALSE;
01356 }
01357 iasubopt_dereference(&test_iaaddr, MDL);
01358 }
01359
01360 return (status);
01361 }
01362
01363
01364
01365
01366 static isc_result_t
01367 move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
01368 isc_result_t insert_result;
01369 int old_heap_index;
01370
01371 old_heap_index = lease->heap_index;
01372 insert_result = isc_heap_insert(pool->active_timeouts, lease);
01373 if (insert_result == ISC_R_SUCCESS) {
01374 iasubopt_hash_add(pool->leases, &lease->addr,
01375 sizeof(lease->addr), lease, MDL);
01376 isc_heap_delete(pool->inactive_timeouts, old_heap_index);
01377 pool->num_active++;
01378 pool->num_inactive--;
01379 lease->state = FTS_ACTIVE;
01380 }
01381 return insert_result;
01382 }
01383
01414 isc_result_t
01415 renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
01416 time_t old_end_time = lease->hard_lifetime_end_time;
01417 lease->hard_lifetime_end_time = lease->soft_lifetime_end_time;
01418 lease->soft_lifetime_end_time = 0;
01419
01420 if (lease->state == FTS_ACTIVE) {
01421 if (old_end_time <= lease->hard_lifetime_end_time) {
01422 isc_heap_decreased(pool->active_timeouts,
01423 lease->heap_index);
01424 } else {
01425 isc_heap_increased(pool->active_timeouts,
01426 lease->heap_index);
01427 }
01428 return ISC_R_SUCCESS;
01429 } else if (lease->state == FTS_ABANDONED) {
01430 char tmp_addr[INET6_ADDRSTRLEN];
01431 lease->state = FTS_ACTIVE;
01432 isc_heap_increased(pool->active_timeouts, lease->heap_index);
01433 log_info("Reclaiming previously abandoned address %s",
01434 inet_ntop(AF_INET6, &(lease->addr), tmp_addr,
01435 sizeof(tmp_addr)));
01436 return ISC_R_SUCCESS;
01437 } else {
01438 return move_lease_to_active(pool, lease);
01439 }
01440 }
01441
01442
01443
01444
01445 static isc_result_t
01446 move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease,
01447 binding_state_t state) {
01448 isc_result_t insert_result;
01449 int old_heap_index;
01450
01451 old_heap_index = lease->heap_index;
01452 insert_result = isc_heap_insert(pool->inactive_timeouts, lease);
01453 if (insert_result == ISC_R_SUCCESS) {
01454
01455
01456
01457
01458
01459
01460
01461
01462 if (lease->on_star.on_expiry != NULL) {
01463 if (state == FTS_EXPIRED) {
01464 execute_statements(NULL, NULL, NULL,
01465 NULL, NULL, NULL,
01466 &lease->scope,
01467 lease->on_star.on_expiry,
01468 &lease->on_star);
01469 }
01470 executable_statement_dereference
01471 (&lease->on_star.on_expiry, MDL);
01472 }
01473
01474 if (lease->on_star.on_release != NULL) {
01475 if (state == FTS_RELEASED) {
01476 execute_statements(NULL, NULL, NULL,
01477 NULL, NULL, NULL,
01478 &lease->scope,
01479 lease->on_star.on_release,
01480 &lease->on_star);
01481 }
01482 executable_statement_dereference
01483 (&lease->on_star.on_release, MDL);
01484 }
01485
01486 #if defined (NSUPDATE)
01487
01488 if (pool->pool_type != D6O_IA_PD) {
01489 (void) ddns_removals(NULL, lease, NULL, ISC_FALSE);
01490 }
01491 #endif
01492
01493
01494
01495
01496 if (lease->scope != NULL) {
01497 binding_scope_dereference(&lease->scope, MDL);
01498 }
01499
01500 iasubopt_hash_delete(pool->leases,
01501 &lease->addr, sizeof(lease->addr), MDL);
01502 isc_heap_delete(pool->active_timeouts, old_heap_index);
01503 lease->state = state;
01504 pool->num_active--;
01505 pool->num_inactive++;
01506 }
01507 return insert_result;
01508 }
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 isc_result_t
01521 expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) {
01522 struct iasubopt *tmp;
01523 isc_result_t result;
01524
01525 if (leasep == NULL) {
01526 log_error("%s(%d): NULL pointer reference", MDL);
01527 return DHCP_R_INVALIDARG;
01528 }
01529 if (*leasep != NULL) {
01530 log_error("%s(%d): non-NULL pointer", MDL);
01531 return DHCP_R_INVALIDARG;
01532 }
01533
01534 if (pool->num_active > 0) {
01535 tmp = (struct iasubopt *)
01536 isc_heap_element(pool->active_timeouts, 1);
01537 if (now > tmp->hard_lifetime_end_time) {
01538 result = move_lease_to_inactive(pool, tmp,
01539 FTS_EXPIRED);
01540 if (result == ISC_R_SUCCESS) {
01541 iasubopt_reference(leasep, tmp, MDL);
01542 }
01543 return result;
01544 }
01545 }
01546 return ISC_R_SUCCESS;
01547 }
01548
01549
01550
01551
01552
01553
01554 isc_result_t
01555 decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
01556 isc_result_t result;
01557
01558 if ((lease->state != FTS_ACTIVE) &&
01559 (lease->state != FTS_ABANDONED)) {
01560 result = move_lease_to_active(pool, lease);
01561 if (result != ISC_R_SUCCESS) {
01562 return result;
01563 }
01564 }
01565 lease->state = FTS_ABANDONED;
01566 lease->hard_lifetime_end_time = MAX_TIME;
01567 isc_heap_decreased(pool->active_timeouts, lease->heap_index);
01568 return ISC_R_SUCCESS;
01569 }
01570
01571
01572
01573
01574 isc_result_t
01575 release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) {
01576 if (lease->state == FTS_ACTIVE) {
01577 return move_lease_to_inactive(pool, lease, FTS_RELEASED);
01578 } else {
01579 return ISC_R_SUCCESS;
01580 }
01581 }
01582
01583
01584
01585
01586
01587 void
01588 build_prefix6(struct in6_addr *pref,
01589 const struct in6_addr *net_start_pref,
01590 int pool_bits, int pref_bits,
01591 const struct data_string *input) {
01592 isc_md5_t ctx;
01593 int net_bytes;
01594 int i;
01595 char *str;
01596 const char *net_str;
01597
01598
01599
01600
01601
01602
01603 isc_md5_init(&ctx);
01604 isc_md5_update(&ctx, input->data, input->len);
01605 isc_md5_final(&ctx, (unsigned char *)pref);
01606
01607
01608
01609
01610 str = (char *)pref;
01611 net_str = (const char *)net_start_pref;
01612 net_bytes = pool_bits / 8;
01613 for (i = 0; i < net_bytes; i++) {
01614 str[i] = net_str[i];
01615 }
01616 i = net_bytes;
01617 switch (pool_bits % 8) {
01618 case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break;
01619 case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break;
01620 case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break;
01621 case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break;
01622 case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break;
01623 case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break;
01624 case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break;
01625 }
01626
01627
01628
01629 net_bytes = pref_bits / 8;
01630 for (i=net_bytes+1; i<16; i++) {
01631 str[i] = 0;
01632 }
01633 i = net_bytes;
01634 switch (pref_bits % 8) {
01635 case 0: str[i] &= 0; break;
01636 case 1: str[i] &= 0x80; break;
01637 case 2: str[i] &= 0xC0; break;
01638 case 3: str[i] &= 0xE0; break;
01639 case 4: str[i] &= 0xF0; break;
01640 case 5: str[i] &= 0xF8; break;
01641 case 6: str[i] &= 0xFC; break;
01642 case 7: str[i] &= 0xFE; break;
01643 }
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667 isc_result_t
01668 create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref,
01669 unsigned int *attempts,
01670 const struct data_string *uid,
01671 time_t soft_lifetime_end_time) {
01672 struct data_string ds;
01673 struct in6_addr tmp;
01674 struct iasubopt *test_iapref;
01675 struct data_string new_ds;
01676 struct iasubopt *iapref;
01677 isc_result_t result;
01678
01679
01680
01681
01682 memset(&ds, 0, sizeof(ds));
01683 data_string_copy(&ds, (struct data_string *)uid, MDL);
01684
01685 *attempts = 0;
01686 for (;;) {
01687
01688
01689
01690 if (++(*attempts) > 10) {
01691 data_string_forget(&ds, MDL);
01692 return ISC_R_NORESOURCES;
01693 }
01694
01695
01696
01697
01698 build_prefix6(&tmp, &pool->start_addr,
01699 pool->bits, pool->units, &ds);
01700
01701
01702
01703
01704 test_iapref = NULL;
01705 if (iasubopt_hash_lookup(&test_iapref, pool->leases,
01706 &tmp, sizeof(tmp), MDL) == 0) {
01707 break;
01708 }
01709 iasubopt_dereference(&test_iapref, MDL);
01710
01711
01712
01713
01714 memset(&new_ds, 0, sizeof(new_ds));
01715 new_ds.len = ds.len + sizeof(tmp);
01716 if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) {
01717 data_string_forget(&ds, MDL);
01718 return ISC_R_NOMEMORY;
01719 }
01720 new_ds.data = new_ds.buffer->data;
01721 memcpy(new_ds.buffer->data, ds.data, ds.len);
01722 memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp));
01723 data_string_forget(&ds, MDL);
01724 data_string_copy(&ds, &new_ds, MDL);
01725 data_string_forget(&new_ds, MDL);
01726 }
01727
01728 data_string_forget(&ds, MDL);
01729
01730
01731
01732
01733
01734 iapref = NULL;
01735 result = iasubopt_allocate(&iapref, MDL);
01736 if (result != ISC_R_SUCCESS) {
01737 return result;
01738 }
01739 iapref->plen = (u_int8_t)pool->units;
01740 memcpy(&iapref->addr, &tmp, sizeof(iapref->addr));
01741
01742
01743
01744
01745 result = add_lease6(pool, iapref, soft_lifetime_end_time);
01746 if (result == ISC_R_SUCCESS) {
01747 iasubopt_reference(pref, iapref, MDL);
01748 }
01749 iasubopt_dereference(&iapref, MDL);
01750 return result;
01751 }
01752
01753
01754
01755
01756 isc_boolean_t
01757 prefix6_exists(const struct ipv6_pool *pool,
01758 const struct in6_addr *pref, u_int8_t plen) {
01759 struct iasubopt *test_iapref;
01760
01761 if ((int)plen != pool->units)
01762 return ISC_FALSE;
01763
01764 test_iapref = NULL;
01765 if (iasubopt_hash_lookup(&test_iapref, pool->leases,
01766 (void *)pref, sizeof(*pref), MDL)) {
01767 iasubopt_dereference(&test_iapref, MDL);
01768 return ISC_TRUE;
01769 } else {
01770 return ISC_FALSE;
01771 }
01772 }
01773
01774
01775
01776
01777
01778
01779 isc_result_t
01780 mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) {
01781 struct iasubopt *dummy_iasubopt;
01782 isc_result_t result;
01783
01784 dummy_iasubopt = NULL;
01785 result = iasubopt_allocate(&dummy_iasubopt, MDL);
01786 if (result == ISC_R_SUCCESS) {
01787 dummy_iasubopt->addr = *addr;
01788 iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr,
01789 sizeof(*addr), dummy_iasubopt, MDL);
01790 }
01791 return result;
01792 }
01793
01794
01795
01796
01797 isc_result_t
01798 add_ipv6_pool(struct ipv6_pool *pool) {
01799 struct ipv6_pool **new_pools;
01800
01801 new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL);
01802 if (new_pools == NULL) {
01803 return ISC_R_NOMEMORY;
01804 }
01805
01806 if (num_pools > 0) {
01807 memcpy(new_pools, pools,
01808 sizeof(struct ipv6_pool *) * num_pools);
01809 dfree(pools, MDL);
01810 }
01811 pools = new_pools;
01812
01813 pools[num_pools] = NULL;
01814 ipv6_pool_reference(&pools[num_pools], pool, MDL);
01815 num_pools++;
01816 return ISC_R_SUCCESS;
01817 }
01818
01819 static void
01820 cleanup_old_expired(struct ipv6_pool *pool) {
01821 struct iasubopt *tmp;
01822 struct ia_xx *ia;
01823 struct ia_xx *ia_active;
01824 unsigned char *tmpd;
01825 time_t timeout;
01826
01827 while (pool->num_inactive > 0) {
01828 tmp = (struct iasubopt *)
01829 isc_heap_element(pool->inactive_timeouts, 1);
01830 if (tmp->hard_lifetime_end_time != 0) {
01831 timeout = tmp->hard_lifetime_end_time;
01832 timeout += EXPIRED_IPV6_CLEANUP_TIME;
01833 } else {
01834 timeout = tmp->soft_lifetime_end_time;
01835 }
01836 if (cur_time < timeout) {
01837 break;
01838 }
01839
01840 isc_heap_delete(pool->inactive_timeouts, tmp->heap_index);
01841 pool->num_inactive--;
01842
01843 if (tmp->ia != NULL) {
01844
01845
01846
01847
01848
01849 ia = NULL;
01850 ia_reference(&ia, tmp->ia, MDL);
01851 ia_remove_iasubopt(ia, tmp, MDL);
01852 ia_active = NULL;
01853 tmpd = (unsigned char *)ia->iaid_duid.data;
01854 if ((ia->ia_type == D6O_IA_NA) &&
01855 (ia->num_iasubopt <= 0) &&
01856 (ia_hash_lookup(&ia_active, ia_na_active, tmpd,
01857 ia->iaid_duid.len, MDL) == 0) &&
01858 (ia_active == ia)) {
01859 ia_hash_delete(ia_na_active, tmpd,
01860 ia->iaid_duid.len, MDL);
01861 }
01862 if ((ia->ia_type == D6O_IA_TA) &&
01863 (ia->num_iasubopt <= 0) &&
01864 (ia_hash_lookup(&ia_active, ia_ta_active, tmpd,
01865 ia->iaid_duid.len, MDL) == 0) &&
01866 (ia_active == ia)) {
01867 ia_hash_delete(ia_ta_active, tmpd,
01868 ia->iaid_duid.len, MDL);
01869 }
01870 if ((ia->ia_type == D6O_IA_PD) &&
01871 (ia->num_iasubopt <= 0) &&
01872 (ia_hash_lookup(&ia_active, ia_pd_active, tmpd,
01873 ia->iaid_duid.len, MDL) == 0) &&
01874 (ia_active == ia)) {
01875 ia_hash_delete(ia_pd_active, tmpd,
01876 ia->iaid_duid.len, MDL);
01877 }
01878 ia_dereference(&ia, MDL);
01879 }
01880 iasubopt_dereference(&tmp, MDL);
01881 }
01882 }
01883
01884 static void
01885 lease_timeout_support(void *vpool) {
01886 struct ipv6_pool *pool;
01887 struct iasubopt *lease;
01888
01889 pool = (struct ipv6_pool *)vpool;
01890 for (;;) {
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903 lease = NULL;
01904 if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) {
01905 break;
01906 }
01907 if (lease == NULL) {
01908 break;
01909 }
01910
01911 write_ia(lease->ia);
01912
01913 iasubopt_dereference(&lease, MDL);
01914 }
01915
01916
01917
01918
01919
01920
01921 (void) commit_leases_timed();
01922
01923
01924
01925
01926 cleanup_old_expired(pool);
01927
01928
01929
01930
01931 schedule_lease_timeout(pool);
01932 }
01933
01934
01935
01936
01937
01938 void
01939 schedule_lease_timeout(struct ipv6_pool *pool) {
01940 struct iasubopt *tmp;
01941 time_t timeout;
01942 time_t next_timeout;
01943 struct timeval tv;
01944
01945 next_timeout = MAX_TIME;
01946
01947 if (pool->num_active > 0) {
01948 tmp = (struct iasubopt *)
01949 isc_heap_element(pool->active_timeouts, 1);
01950 if (tmp->hard_lifetime_end_time < next_timeout) {
01951 next_timeout = tmp->hard_lifetime_end_time + 1;
01952 }
01953 }
01954
01955 if (pool->num_inactive > 0) {
01956 tmp = (struct iasubopt *)
01957 isc_heap_element(pool->inactive_timeouts, 1);
01958 if (tmp->hard_lifetime_end_time != 0) {
01959 timeout = tmp->hard_lifetime_end_time;
01960 timeout += EXPIRED_IPV6_CLEANUP_TIME;
01961 } else {
01962 timeout = tmp->soft_lifetime_end_time + 1;
01963 }
01964 if (timeout < next_timeout) {
01965 next_timeout = timeout;
01966 }
01967 }
01968
01969 if (next_timeout < MAX_TIME) {
01970 tv.tv_sec = next_timeout;
01971 tv.tv_usec = 0;
01972 add_timeout(&tv, lease_timeout_support, pool,
01973 (tvref_t)ipv6_pool_reference,
01974 (tvunref_t)ipv6_pool_dereference);
01975 }
01976 }
01977
01978
01979
01980
01981 void
01982 schedule_all_ipv6_lease_timeouts(void) {
01983 int i;
01984
01985 for (i=0; i<num_pools; i++) {
01986 schedule_lease_timeout(pools[i]);
01987 }
01988 }
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999 static void
02000 ipv6_network_portion(struct in6_addr *result,
02001 const struct in6_addr *addr, int bits) {
02002 unsigned char *addrp;
02003 int mask_bits;
02004 int bytes;
02005 int extra_bits;
02006 int i;
02007
02008 static const unsigned char bitmasks[] = {
02009 0x00, 0xFE, 0xFC, 0xF8,
02010 0xF0, 0xE0, 0xC0, 0x80,
02011 };
02012
02013
02014
02015
02016 if ((bits < 0) || (bits > 128)) {
02017 log_fatal("ipv6_network_portion: bits %d not between 0 and 128",
02018 bits);
02019 }
02020
02021
02022
02023
02024 *result = *addr;
02025 addrp = ((unsigned char *)result) + 15;
02026
02027
02028
02029
02030 mask_bits = 128 - bits;
02031 bytes = mask_bits / 8;
02032 extra_bits = mask_bits % 8;
02033
02034 for (i=0; i<bytes; i++) {
02035 *addrp = 0;
02036 addrp--;
02037 }
02038 if (extra_bits) {
02039 *addrp &= bitmasks[extra_bits];
02040 }
02041 }
02042
02043
02044
02045
02046 isc_boolean_t
02047 ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool) {
02048 struct in6_addr tmp;
02049
02050 ipv6_network_portion(&tmp, addr, pool->bits);
02051 if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) {
02052 return ISC_TRUE;
02053 } else {
02054 return ISC_FALSE;
02055 }
02056 }
02057
02058
02059
02060
02061
02062
02063
02064 isc_result_t
02065 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
02066 const struct in6_addr *addr) {
02067 int i;
02068
02069 if (pool == NULL) {
02070 log_error("%s(%d): NULL pointer reference", MDL);
02071 return DHCP_R_INVALIDARG;
02072 }
02073 if (*pool != NULL) {
02074 log_error("%s(%d): non-NULL pointer", MDL);
02075 return DHCP_R_INVALIDARG;
02076 }
02077
02078 for (i=0; i<num_pools; i++) {
02079 if (pools[i]->pool_type != type)
02080 continue;
02081 if (ipv6_in_pool(addr, pools[i])) {
02082 ipv6_pool_reference(pool, pools[i], MDL);
02083 return ISC_R_SUCCESS;
02084 }
02085 }
02086 return ISC_R_NOTFOUND;
02087 }
02088
02089
02090
02091
02092
02093 static isc_result_t
02094 change_leases(struct ia_xx *ia,
02095 isc_result_t (*change_func)(struct ipv6_pool *,
02096 struct iasubopt *)) {
02097 isc_result_t retval;
02098 isc_result_t renew_retval;
02099 struct ipv6_pool *pool;
02100 struct in6_addr *addr;
02101 int i;
02102
02103 retval = ISC_R_SUCCESS;
02104 for (i=0; i<ia->num_iasubopt; i++) {
02105 pool = NULL;
02106 addr = &ia->iasubopt[i]->addr;
02107 if (find_ipv6_pool(&pool, ia->ia_type,
02108 addr) == ISC_R_SUCCESS) {
02109 renew_retval = change_func(pool, ia->iasubopt[i]);
02110 if (renew_retval != ISC_R_SUCCESS) {
02111 retval = renew_retval;
02112 }
02113 }
02114
02115 }
02116 return retval;
02117 }
02118
02119
02120
02121
02122
02123
02124
02125 isc_result_t
02126 renew_leases(struct ia_xx *ia) {
02127 return change_leases(ia, renew_lease6);
02128 }
02129
02130
02131
02132
02133 isc_result_t
02134 release_leases(struct ia_xx *ia) {
02135 return change_leases(ia, release_lease6);
02136 }
02137
02138
02139
02140
02141 isc_result_t
02142 decline_leases(struct ia_xx *ia) {
02143 return change_leases(ia, decline_lease6);
02144 }
02145
02146 #ifdef DHCPv6
02147
02148
02149
02150 static int write_error;
02151
02152 static isc_result_t
02153 write_ia_leases(const void *name, unsigned len, void *value) {
02154 struct ia_xx *ia = (struct ia_xx *)value;
02155
02156 if (!write_error) {
02157 if (!write_ia(ia)) {
02158 write_error = 1;
02159 }
02160 }
02161 return ISC_R_SUCCESS;
02162 }
02163
02164
02165
02166
02167 int
02168 write_leases6(void) {
02169 int nas, tas, pds;
02170
02171 write_error = 0;
02172 write_server_duid();
02173 nas = ia_hash_foreach(ia_na_active, write_ia_leases);
02174 if (write_error) {
02175 return 0;
02176 }
02177 tas = ia_hash_foreach(ia_ta_active, write_ia_leases);
02178 if (write_error) {
02179 return 0;
02180 }
02181 pds = ia_hash_foreach(ia_pd_active, write_ia_leases);
02182 if (write_error) {
02183 return 0;
02184 }
02185
02186 log_info("Wrote %d NA, %d TA, %d PD leases to lease file.",
02187 nas, tas, pds);
02188 return 1;
02189 }
02190 #endif
02191
02192 static isc_result_t
02193 mark_hosts_unavailable_support(const void *name, unsigned len, void *value) {
02194 struct host_decl *h;
02195 struct data_string fixed_addr;
02196 struct in6_addr addr;
02197 struct ipv6_pool *p;
02198
02199 h = (struct host_decl *)value;
02200
02201
02202
02203
02204 if (h->fixed_addr == NULL) {
02205 return ISC_R_SUCCESS;
02206 }
02207
02208
02209
02210
02211 memset(&fixed_addr, 0, sizeof(fixed_addr));
02212 if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL,
02213 &global_scope, h->fixed_addr, MDL)) {
02214 log_error("mark_hosts_unavailable: "
02215 "error evaluating host address.");
02216 return ISC_R_SUCCESS;
02217 }
02218 if (fixed_addr.len != 16) {
02219 log_error("mark_hosts_unavailable: "
02220 "host address is not 128 bits.");
02221 return ISC_R_SUCCESS;
02222 }
02223 memcpy(&addr, fixed_addr.data, 16);
02224 data_string_forget(&fixed_addr, MDL);
02225
02226
02227
02228
02229
02230
02231 p = NULL;
02232 if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) {
02233 mark_lease_unavailable(p, &addr);
02234 ipv6_pool_dereference(&p, MDL);
02235 }
02236 if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) {
02237 mark_lease_unavailable(p, &addr);
02238 ipv6_pool_dereference(&p, MDL);
02239 }
02240
02241 return ISC_R_SUCCESS;
02242 }
02243
02244 void
02245 mark_hosts_unavailable(void) {
02246 hash_foreach(host_name_hash, mark_hosts_unavailable_support);
02247 }
02248
02249 static isc_result_t
02250 mark_phosts_unavailable_support(const void *name, unsigned len, void *value) {
02251 struct host_decl *h;
02252 struct iaddrcidrnetlist *l;
02253 struct in6_addr pref;
02254 struct ipv6_pool *p;
02255
02256 h = (struct host_decl *)value;
02257
02258
02259
02260
02261 if (h->fixed_prefix == NULL) {
02262 return ISC_R_SUCCESS;
02263 }
02264
02265
02266
02267
02268 for (l = h->fixed_prefix; l != NULL; l = l->next) {
02269 if (l->cidrnet.lo_addr.len != 16) {
02270 continue;
02271 }
02272 memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16);
02273
02274
02275
02276
02277
02278
02279 p = NULL;
02280 if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) {
02281 continue;
02282 }
02283 if (l->cidrnet.bits != p->units) {
02284 ipv6_pool_dereference(&p, MDL);
02285 continue;
02286 }
02287 mark_lease_unavailable(p, &pref);
02288 ipv6_pool_dereference(&p, MDL);
02289 }
02290
02291 return ISC_R_SUCCESS;
02292 }
02293
02294 void
02295 mark_phosts_unavailable(void) {
02296 hash_foreach(host_name_hash, mark_phosts_unavailable_support);
02297 }
02298
02299 void
02300 mark_interfaces_unavailable(void) {
02301 struct interface_info *ip;
02302 int i;
02303 struct ipv6_pool *p;
02304
02305 ip = interfaces;
02306 while (ip != NULL) {
02307 for (i=0; i<ip->v6address_count; i++) {
02308 p = NULL;
02309 if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i])
02310 == ISC_R_SUCCESS) {
02311 mark_lease_unavailable(p,
02312 &ip->v6addresses[i]);
02313 ipv6_pool_dereference(&p, MDL);
02314 }
02315 if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i])
02316 == ISC_R_SUCCESS) {
02317 mark_lease_unavailable(p,
02318 &ip->v6addresses[i]);
02319 ipv6_pool_dereference(&p, MDL);
02320 }
02321 }
02322 ip = ip->next;
02323 }
02324 }
02325
02343 isc_result_t
02344 ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
02345 struct ipv6_pond *tmp;
02346
02347 if (pond == NULL) {
02348 log_error("%s(%d): NULL pointer reference", file, line);
02349 return DHCP_R_INVALIDARG;
02350 }
02351 if (*pond != NULL) {
02352 log_error("%s(%d): non-NULL pointer", file, line);
02353 return DHCP_R_INVALIDARG;
02354 }
02355
02356 tmp = dmalloc(sizeof(*tmp), file, line);
02357 if (tmp == NULL) {
02358 return ISC_R_NOMEMORY;
02359 }
02360
02361 tmp->refcnt = 1;
02362
02363 *pond = tmp;
02364 return ISC_R_SUCCESS;
02365 }
02366
02386 isc_result_t
02387 ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
02388 const char *file, int line) {
02389 if (pond == NULL) {
02390 log_error("%s(%d): NULL pointer reference", file, line);
02391 return DHCP_R_INVALIDARG;
02392 }
02393 if (*pond != NULL) {
02394 log_error("%s(%d): non-NULL pointer", file, line);
02395 return DHCP_R_INVALIDARG;
02396 }
02397 if (src == NULL) {
02398 log_error("%s(%d): NULL pointer reference", file, line);
02399 return DHCP_R_INVALIDARG;
02400 }
02401 *pond = src;
02402 src->refcnt++;
02403 return ISC_R_SUCCESS;
02404 }
02405
02426 isc_result_t
02427 ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
02428 struct ipv6_pond *tmp;
02429
02430 if ((pond == NULL) || (*pond == NULL)) {
02431 log_error("%s(%d): NULL pointer", file, line);
02432 return DHCP_R_INVALIDARG;
02433 }
02434
02435 tmp = *pond;
02436 *pond = NULL;
02437
02438 tmp->refcnt--;
02439 if (tmp->refcnt < 0) {
02440 log_error("%s(%d): negative refcnt", file, line);
02441 tmp->refcnt = 0;
02442 }
02443 if (tmp->refcnt == 0) {
02444 dfree(tmp, file, line);
02445 }
02446
02447 return ISC_R_SUCCESS;
02448 }
02449
02450