00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "dhcpd.h"
00027
00028 #ifdef DHCPv6
00029
00030 struct sockaddr_in6 DHCPv6DestAddr;
00031
00032
00033
00034
00035
00036 struct option *clientid_option = NULL;
00037 struct option *elapsed_option = NULL;
00038 struct option *ia_na_option = NULL;
00039 struct option *ia_ta_option = NULL;
00040 struct option *ia_pd_option = NULL;
00041 struct option *iaaddr_option = NULL;
00042 struct option *iaprefix_option = NULL;
00043 struct option *oro_option = NULL;
00044 struct option *irt_option = NULL;
00045
00046 static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
00047 const char *file, int line);
00048 static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia,
00049 const char *file, int line);
00050 static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr,
00051 const char *file, int line);
00052 static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line);
00053 static isc_result_t dhc6_parse_ia_na(struct dhc6_ia **pia,
00054 struct packet *packet,
00055 struct option_state *options);
00056 static isc_result_t dhc6_parse_ia_ta(struct dhc6_ia **pia,
00057 struct packet *packet,
00058 struct option_state *options);
00059 static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia,
00060 struct packet *packet,
00061 struct option_state *options);
00062 static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr,
00063 struct packet *packet,
00064 struct option_state *options);
00065 static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppref,
00066 struct packet *packet,
00067 struct option_state *options);
00068 static struct dhc6_ia *find_ia(struct dhc6_ia *head,
00069 u_int16_t type, const char *id);
00070 static struct dhc6_addr *find_addr(struct dhc6_addr *head,
00071 struct iaddr *address);
00072 static struct dhc6_addr *find_pref(struct dhc6_addr *head,
00073 struct iaddr *prefix, u_int8_t plen);
00074 void init_handler(struct packet *packet, struct client_state *client);
00075 void info_request_handler(struct packet *packet, struct client_state *client);
00076 void rapid_commit_handler(struct packet *packet, struct client_state *client);
00077 void do_init6(void *input);
00078 void do_info_request6(void *input);
00079 void do_confirm6(void *input);
00080 void reply_handler(struct packet *packet, struct client_state *client);
00081 static isc_result_t dhc6_add_ia_na(struct client_state *client,
00082 struct data_string *packet,
00083 struct dhc6_lease *lease,
00084 u_int8_t message);
00085 static isc_result_t dhc6_add_ia_ta(struct client_state *client,
00086 struct data_string *packet,
00087 struct dhc6_lease *lease,
00088 u_int8_t message);
00089 static isc_result_t dhc6_add_ia_pd(struct client_state *client,
00090 struct data_string *packet,
00091 struct dhc6_lease *lease,
00092 u_int8_t message);
00093 static isc_boolean_t stopping_finished(void);
00094 static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst);
00095 void do_select6(void *input);
00096 void do_refresh6(void *input);
00097 static void do_release6(void *input);
00098 static void start_bound(struct client_state *client);
00099 static void start_decline6(struct client_state *client);
00100 static void do_decline6(void *input);
00101 static void start_informed(struct client_state *client);
00102 void informed_handler(struct packet *packet, struct client_state *client);
00103 void bound_handler(struct packet *packet, struct client_state *client);
00104 void start_renew6(void *input);
00105 void start_rebind6(void *input);
00106 void do_depref(void *input);
00107 void do_expire(void *input);
00108 static void make_client6_options(struct client_state *client,
00109 struct option_state **op,
00110 struct dhc6_lease *lease, u_int8_t message);
00111 static void script_write_params6(struct client_state *client,
00112 const char *prefix,
00113 struct option_state *options);
00114 static void script_write_requested6(struct client_state *client);
00115 static isc_boolean_t active_prefix(struct client_state *client);
00116
00117 static int check_timing6(struct client_state *client, u_int8_t msg_type,
00118 char *msg_str, struct dhc6_lease *lease,
00119 struct data_string *ds);
00120
00121 extern int onetry;
00122 extern int stateless;
00123
00124
00125
00126
00127 void
00128 dhcpv6_client_assignments(void)
00129 {
00130 struct servent *ent;
00131 unsigned code;
00132
00133 if (path_dhclient_pid == NULL)
00134 path_dhclient_pid = _PATH_DHCLIENT6_PID;
00135 if (path_dhclient_db == NULL)
00136 path_dhclient_db = _PATH_DHCLIENT6_DB;
00137
00138 if (local_port == 0) {
00139 ent = getservbyname("dhcpv6-client", "udp");
00140 if (ent == NULL)
00141 local_port = htons(546);
00142 else
00143 local_port = ent->s_port;
00144 }
00145
00146 if (remote_port == 0) {
00147 ent = getservbyname("dhcpv6-server", "udp");
00148 if (ent == NULL)
00149 remote_port = htons(547);
00150 else
00151 remote_port = ent->s_port;
00152 }
00153
00154 memset(&DHCPv6DestAddr, 0, sizeof(DHCPv6DestAddr));
00155 DHCPv6DestAddr.sin6_family = AF_INET6;
00156 DHCPv6DestAddr.sin6_port = remote_port;
00157 if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
00158 &DHCPv6DestAddr.sin6_addr) <= 0) {
00159 log_fatal("Bad address %s", All_DHCP_Relay_Agents_and_Servers);
00160 }
00161
00162 code = D6O_CLIENTID;
00163 if (!option_code_hash_lookup(&clientid_option,
00164 dhcpv6_universe.code_hash, &code, 0, MDL))
00165 log_fatal("Unable to find the CLIENTID option definition.");
00166
00167 code = D6O_ELAPSED_TIME;
00168 if (!option_code_hash_lookup(&elapsed_option,
00169 dhcpv6_universe.code_hash, &code, 0, MDL))
00170 log_fatal("Unable to find the ELAPSED_TIME option definition.");
00171
00172 code = D6O_IA_NA;
00173 if (!option_code_hash_lookup(&ia_na_option, dhcpv6_universe.code_hash,
00174 &code, 0, MDL))
00175 log_fatal("Unable to find the IA_NA option definition.");
00176
00177 code = D6O_IA_TA;
00178 if (!option_code_hash_lookup(&ia_ta_option, dhcpv6_universe.code_hash,
00179 &code, 0, MDL))
00180 log_fatal("Unable to find the IA_TA option definition.");
00181
00182 code = D6O_IA_PD;
00183 if (!option_code_hash_lookup(&ia_pd_option, dhcpv6_universe.code_hash,
00184 &code, 0, MDL))
00185 log_fatal("Unable to find the IA_PD option definition.");
00186
00187 code = D6O_IAADDR;
00188 if (!option_code_hash_lookup(&iaaddr_option, dhcpv6_universe.code_hash,
00189 &code, 0, MDL))
00190 log_fatal("Unable to find the IAADDR option definition.");
00191
00192 code = D6O_IAPREFIX;
00193 if (!option_code_hash_lookup(&iaprefix_option,
00194 dhcpv6_universe.code_hash,
00195 &code, 0, MDL))
00196 log_fatal("Unable to find the IAPREFIX option definition.");
00197
00198 code = D6O_ORO;
00199 if (!option_code_hash_lookup(&oro_option, dhcpv6_universe.code_hash,
00200 &code, 0, MDL))
00201 log_fatal("Unable to find the ORO option definition.");
00202
00203 code = D6O_INFORMATION_REFRESH_TIME;
00204 if (!option_code_hash_lookup(&irt_option, dhcpv6_universe.code_hash,
00205 &code, 0, MDL))
00206 log_fatal("Unable to find the IRT option definition.");
00207
00208 #ifndef __CYGWIN32__
00209 endservent();
00210 #endif
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 static TIME
00233 dhc6_rand(TIME base)
00234 {
00235 TIME rval;
00236 TIME range;
00237 TIME split;
00238
00239
00240
00241
00242
00243 if (base <= 0)
00244 log_fatal("Impossible condition at %s:%d.", MDL);
00245
00246
00247
00248
00249
00250
00251 split = (base - 1) / 10;
00252
00253
00254 if (split == 0)
00255 return 0;
00256
00257
00258
00259
00260
00261
00262 range = (split * 2) + 1;
00263
00264
00265 rval = random();
00266 rval %= range;
00267
00268
00269 rval -= split;
00270
00271 return rval;
00272 }
00273
00274
00275 static void
00276 dhc6_retrans_init(struct client_state *client)
00277 {
00278 int xid;
00279
00280
00281 client->txcount = 0;
00282 client->RT = client->IRT + dhc6_rand(client->IRT);
00283
00284
00285
00286 #if (RAND_MAX >= 0x00ffffff)
00287 xid = random();
00288 #elif (RAND_MAX >= 0x0000ffff)
00289 xid = (random() << 16) ^ random();
00290 #elif (RAND_MAX >= 0x000000ff)
00291 xid = (random() << 16) ^ (random() << 8) ^ random();
00292 #else
00293 # error "Random number generator of less than 8 bits not supported."
00294 #endif
00295
00296 client->dhcpv6_transaction_id[0] = (xid >> 16) & 0xff;
00297 client->dhcpv6_transaction_id[1] = (xid >> 8) & 0xff;
00298 client->dhcpv6_transaction_id[2] = xid & 0xff;
00299 }
00300
00301
00302 static void
00303 dhc6_retrans_advance(struct client_state *client)
00304 {
00305 struct timeval elapsed;
00306
00307
00308 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
00309 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
00310 if (elapsed.tv_usec < 0) {
00311 elapsed.tv_sec -= 1;
00312 elapsed.tv_usec += 1000000;
00313 }
00314
00315
00316 elapsed.tv_sec += client->RT / 100;
00317 elapsed.tv_usec += (client->RT % 100) * 10000;
00318 if (elapsed.tv_usec >= 1000000) {
00319 elapsed.tv_sec += 1;
00320 elapsed.tv_usec -= 1000000;
00321 }
00322
00323
00324
00325
00326
00327
00328
00329 client->RT += client->RT + dhc6_rand(client->RT);
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 if ((client->MRT != 0) && (client->RT > client->MRT))
00340 client->RT = client->MRT + dhc6_rand(client->MRT);
00341
00342
00343
00344
00345
00346 if (client->MRD == 0) {
00347
00348 client->txcount++;
00349 return;
00350 }
00351
00352 elapsed.tv_sec += client->RT / 100;
00353 elapsed.tv_usec += (client->RT % 100) * 10000;
00354 if (elapsed.tv_usec >= 1000000) {
00355 elapsed.tv_sec += 1;
00356 elapsed.tv_usec -= 1000000;
00357 }
00358 if (elapsed.tv_sec >= client->MRD) {
00359
00360
00361
00362 client->RT = client->MRD +
00363 (client->start_time.tv_sec - cur_tv.tv_sec);
00364 client->RT = client->RT * 100 +
00365 (client->start_time.tv_usec - cur_tv.tv_usec) / 10000;
00366 }
00367 client->txcount++;
00368 }
00369
00370
00371 static int
00372 valid_reply(struct packet *packet, struct client_state *client)
00373 {
00374 struct data_string sid, cid;
00375 struct option_cache *oc;
00376 int rval = ISC_TRUE;
00377
00378 memset(&sid, 0, sizeof(sid));
00379 memset(&cid, 0, sizeof(cid));
00380
00381 if (!lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID)) {
00382 log_error("Response without a server identifier received.");
00383 rval = ISC_FALSE;
00384 }
00385
00386 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
00387 if (!oc ||
00388 !evaluate_option_cache(&sid, packet, NULL, client, packet->options,
00389 client->sent_options, &global_scope, oc,
00390 MDL)) {
00391 log_error("Response without a client identifier.");
00392 rval = ISC_FALSE;
00393 }
00394
00395 oc = lookup_option(&dhcpv6_universe, client->sent_options,
00396 D6O_CLIENTID);
00397 if (!oc ||
00398 !evaluate_option_cache(&cid, packet, NULL, client,
00399 client->sent_options, NULL, &global_scope,
00400 oc, MDL)) {
00401 log_error("Local client identifier is missing!");
00402 rval = ISC_FALSE;
00403 }
00404
00405 if (sid.len == 0 ||
00406 sid.len != cid.len ||
00407 memcmp(sid.data, cid.data, sid.len)) {
00408 log_error("Advertise with matching transaction ID, but "
00409 "mismatching client id.");
00410 rval = ISC_FALSE;
00411 }
00412
00413 return rval;
00414 }
00415
00416
00417
00418
00419 static struct dhc6_lease *
00420 dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line)
00421 {
00422 struct dhc6_lease *copy;
00423 struct dhc6_ia **insert_ia, *ia;
00424
00425 copy = dmalloc(sizeof(*copy), file, line);
00426 if (copy == NULL) {
00427 log_error("Out of memory for v6 lease structure.");
00428 return NULL;
00429 }
00430
00431 data_string_copy(©->server_id, &lease->server_id, file, line);
00432 copy->pref = lease->pref;
00433
00434 memcpy(copy->dhcpv6_transaction_id, lease->dhcpv6_transaction_id,
00435 sizeof(copy->dhcpv6_transaction_id));
00436
00437 option_state_reference(©->options, lease->options, file, line);
00438
00439 insert_ia = ©->bindings;
00440 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
00441 *insert_ia = dhc6_dup_ia(ia, file, line);
00442
00443 if (*insert_ia == NULL) {
00444 dhc6_lease_destroy(©, file, line);
00445 return NULL;
00446 }
00447
00448 insert_ia = &(*insert_ia)->next;
00449 }
00450
00451 return copy;
00452 }
00453
00454
00455
00456
00457 static struct dhc6_ia *
00458 dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line)
00459 {
00460 struct dhc6_ia *copy;
00461 struct dhc6_addr **insert_addr, *addr;
00462
00463 copy = dmalloc(sizeof(*ia), file, line);
00464
00465 memcpy(copy->iaid, ia->iaid, sizeof(copy->iaid));
00466
00467 copy->ia_type = ia->ia_type;
00468 copy->starts = ia->starts;
00469 copy->renew = ia->renew;
00470 copy->rebind = ia->rebind;
00471
00472 insert_addr = ©->addrs;
00473 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
00474 *insert_addr = dhc6_dup_addr(addr, file, line);
00475
00476 if (*insert_addr == NULL) {
00477 dhc6_ia_destroy(©, file, line);
00478 return NULL;
00479 }
00480
00481 insert_addr = &(*insert_addr)->next;
00482 }
00483
00484 if (ia->options != NULL)
00485 option_state_reference(©->options, ia->options,
00486 file, line);
00487
00488 return copy;
00489 }
00490
00491
00492
00493
00494 static struct dhc6_addr *
00495 dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line)
00496 {
00497 struct dhc6_addr *copy;
00498
00499 copy = dmalloc(sizeof(*addr), file, line);
00500
00501 if (copy == NULL)
00502 return NULL;
00503
00504 memcpy(©->address, &addr->address, sizeof(copy->address));
00505
00506 copy->plen = addr->plen;
00507 copy->flags = addr->flags;
00508 copy->starts = addr->starts;
00509 copy->preferred_life = addr->preferred_life;
00510 copy->max_life = addr->max_life;
00511
00512 if (addr->options != NULL)
00513 option_state_reference(©->options, addr->options,
00514 file, line);
00515
00516 return copy;
00517 }
00518
00519
00520
00521
00522
00523
00524 static struct dhc6_lease *
00525 dhc6_leaseify(struct packet *packet)
00526 {
00527 struct data_string ds;
00528 struct dhc6_lease *lease;
00529 struct option_cache *oc;
00530
00531 lease = dmalloc(sizeof(*lease), MDL);
00532 if (lease == NULL) {
00533 log_error("Out of memory for v6 lease structure.");
00534 return NULL;
00535 }
00536
00537 memcpy(lease->dhcpv6_transaction_id, packet->dhcpv6_transaction_id, 3);
00538 option_state_reference(&lease->options, packet->options, MDL);
00539
00540 memset(&ds, 0, sizeof(ds));
00541
00542
00543 oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
00544 if (oc &&
00545 evaluate_option_cache(&ds, packet, NULL, NULL, lease->options,
00546 NULL, &global_scope, oc, MDL)) {
00547 if (ds.len != 1) {
00548 log_error("Invalid length of DHCPv6 Preference option "
00549 "(%d != 1)", ds.len);
00550 data_string_forget(&ds, MDL);
00551 dhc6_lease_destroy(&lease, MDL);
00552 return NULL;
00553 } else {
00554 lease->pref = ds.data[0];
00555 log_debug("RCV: X-- Preference %u.",
00556 (unsigned)lease->pref);
00557 }
00558
00559 data_string_forget(&ds, MDL);
00560 }
00561 delete_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
00562
00563
00564
00565
00566
00567 if (dhc6_parse_ia_na(&lease->bindings, packet,
00568 lease->options) != ISC_R_SUCCESS) {
00569
00570 dhc6_lease_destroy(&lease, MDL);
00571 return NULL;
00572 }
00573
00574
00575
00576
00577 if (dhc6_parse_ia_ta(&lease->bindings, packet,
00578 lease->options) != ISC_R_SUCCESS) {
00579
00580 dhc6_lease_destroy(&lease, MDL);
00581 return NULL;
00582 }
00583
00584
00585
00586
00587 if (dhc6_parse_ia_pd(&lease->bindings, packet,
00588 lease->options) != ISC_R_SUCCESS) {
00589
00590 dhc6_lease_destroy(&lease, MDL);
00591 return NULL;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
00601 if ((oc == NULL) ||
00602 !evaluate_option_cache(&lease->server_id, packet, NULL, NULL,
00603 lease->options, NULL, &global_scope,
00604 oc, MDL) ||
00605 lease->server_id.len == 0) {
00606
00607
00608 log_error("Invalid SERVERID option cache.");
00609 dhc6_lease_destroy(&lease, MDL);
00610 return NULL;
00611 } else {
00612 log_debug("RCV: X-- Server ID: %s",
00613 print_hex_1(lease->server_id.len,
00614 lease->server_id.data, 52));
00615 }
00616
00617 return lease;
00618 }
00619
00620 static isc_result_t
00621 dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
00622 struct option_state *options)
00623 {
00624 struct data_string ds;
00625 struct dhc6_ia *ia;
00626 struct option_cache *oc;
00627 isc_result_t result;
00628
00629 memset(&ds, 0, sizeof(ds));
00630
00631 oc = lookup_option(&dhcpv6_universe, options, D6O_IA_NA);
00632 for ( ; oc != NULL ; oc = oc->next) {
00633 ia = dmalloc(sizeof(*ia), MDL);
00634 if (ia == NULL) {
00635 log_error("Out of memory allocating IA_NA structure.");
00636 return ISC_R_NOMEMORY;
00637 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
00638 options, NULL,
00639 &global_scope, oc, MDL) &&
00640 ds.len >= 12) {
00641 memcpy(ia->iaid, ds.data, 4);
00642 ia->ia_type = D6O_IA_NA;
00643 ia->starts = cur_time;
00644 ia->renew = getULong(ds.data + 4);
00645 ia->rebind = getULong(ds.data + 8);
00646
00647 log_debug("RCV: X-- IA_NA %s",
00648 print_hex_1(4, ia->iaid, 59));
00649
00650 log_debug("RCV: | X-- starts %u",
00651 (unsigned)ia->starts);
00652 log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
00653 log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 if ((ia->renew > 0) && (ia->rebind > 0) &&
00666 (ia->renew > ia->rebind)) {
00667 log_debug("RCV: | !-- INVALID renew/rebind "
00668 "times, IA_NA discarded.");
00669 dfree(ia, MDL);
00670 data_string_forget(&ds, MDL);
00671 continue;
00672 }
00673
00674 if (ds.len > 12) {
00675 log_debug("RCV: | X-- [Options]");
00676
00677 if (!option_state_allocate(&ia->options,
00678 MDL)) {
00679 log_error("Out of memory allocating "
00680 "IA_NA option state.");
00681 dfree(ia, MDL);
00682 data_string_forget(&ds, MDL);
00683 return ISC_R_NOMEMORY;
00684 }
00685
00686 if (!parse_option_buffer(ia->options,
00687 ds.data + 12,
00688 ds.len - 12,
00689 &dhcpv6_universe)) {
00690 log_error("Corrupt IA_NA options.");
00691 option_state_dereference(&ia->options,
00692 MDL);
00693 dfree(ia, MDL);
00694 data_string_forget(&ds, MDL);
00695 return DHCP_R_BADPARSE;
00696 }
00697 }
00698 data_string_forget(&ds, MDL);
00699
00700 if (ia->options != NULL) {
00701 result = dhc6_parse_addrs(&ia->addrs, packet,
00702 ia->options);
00703 if (result != ISC_R_SUCCESS) {
00704 option_state_dereference(&ia->options,
00705 MDL);
00706 dfree(ia, MDL);
00707 return result;
00708 }
00709 }
00710
00711 while (*pia != NULL)
00712 pia = &(*pia)->next;
00713 *pia = ia;
00714 pia = &ia->next;
00715 } else {
00716 log_error("Invalid IA_NA option cache.");
00717 dfree(ia, MDL);
00718 if (ds.len != 0)
00719 data_string_forget(&ds, MDL);
00720 return ISC_R_UNEXPECTED;
00721 }
00722 }
00723 delete_option(&dhcpv6_universe, options, D6O_IA_NA);
00724
00725 return ISC_R_SUCCESS;
00726 }
00727
00728 static isc_result_t
00729 dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet,
00730 struct option_state *options)
00731 {
00732 struct data_string ds;
00733 struct dhc6_ia *ia;
00734 struct option_cache *oc;
00735 isc_result_t result;
00736
00737 memset(&ds, 0, sizeof(ds));
00738
00739 oc = lookup_option(&dhcpv6_universe, options, D6O_IA_TA);
00740 for ( ; oc != NULL ; oc = oc->next) {
00741 ia = dmalloc(sizeof(*ia), MDL);
00742 if (ia == NULL) {
00743 log_error("Out of memory allocating IA_TA structure.");
00744 return ISC_R_NOMEMORY;
00745 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
00746 options, NULL,
00747 &global_scope, oc, MDL) &&
00748 ds.len >= 4) {
00749 memcpy(ia->iaid, ds.data, 4);
00750 ia->ia_type = D6O_IA_TA;
00751 ia->starts = cur_time;
00752
00753 log_debug("RCV: X-- IA_TA %s",
00754 print_hex_1(4, ia->iaid, 59));
00755
00756 log_debug("RCV: | X-- starts %u",
00757 (unsigned)ia->starts);
00758
00759 if (ds.len > 4) {
00760 log_debug("RCV: | X-- [Options]");
00761
00762 if (!option_state_allocate(&ia->options,
00763 MDL)) {
00764 log_error("Out of memory allocating "
00765 "IA_TA option state.");
00766 dfree(ia, MDL);
00767 data_string_forget(&ds, MDL);
00768 return ISC_R_NOMEMORY;
00769 }
00770
00771 if (!parse_option_buffer(ia->options,
00772 ds.data + 4,
00773 ds.len - 4,
00774 &dhcpv6_universe)) {
00775 log_error("Corrupt IA_TA options.");
00776 option_state_dereference(&ia->options,
00777 MDL);
00778 dfree(ia, MDL);
00779 data_string_forget(&ds, MDL);
00780 return DHCP_R_BADPARSE;
00781 }
00782 }
00783 data_string_forget(&ds, MDL);
00784
00785 if (ia->options != NULL) {
00786 result = dhc6_parse_addrs(&ia->addrs, packet,
00787 ia->options);
00788 if (result != ISC_R_SUCCESS) {
00789 option_state_dereference(&ia->options,
00790 MDL);
00791 dfree(ia, MDL);
00792 return result;
00793 }
00794 }
00795
00796 while (*pia != NULL)
00797 pia = &(*pia)->next;
00798 *pia = ia;
00799 pia = &ia->next;
00800 } else {
00801 log_error("Invalid IA_TA option cache.");
00802 dfree(ia, MDL);
00803 if (ds.len != 0)
00804 data_string_forget(&ds, MDL);
00805 return ISC_R_UNEXPECTED;
00806 }
00807 }
00808 delete_option(&dhcpv6_universe, options, D6O_IA_TA);
00809
00810 return ISC_R_SUCCESS;
00811 }
00812
00813 static isc_result_t
00814 dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
00815 struct option_state *options)
00816 {
00817 struct data_string ds;
00818 struct dhc6_ia *ia;
00819 struct option_cache *oc;
00820 isc_result_t result;
00821
00822 memset(&ds, 0, sizeof(ds));
00823
00824 oc = lookup_option(&dhcpv6_universe, options, D6O_IA_PD);
00825 for ( ; oc != NULL ; oc = oc->next) {
00826 ia = dmalloc(sizeof(*ia), MDL);
00827 if (ia == NULL) {
00828 log_error("Out of memory allocating IA_PD structure.");
00829 return ISC_R_NOMEMORY;
00830 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
00831 options, NULL,
00832 &global_scope, oc, MDL) &&
00833 ds.len >= 12) {
00834 memcpy(ia->iaid, ds.data, 4);
00835 ia->ia_type = D6O_IA_PD;
00836 ia->starts = cur_time;
00837 ia->renew = getULong(ds.data + 4);
00838 ia->rebind = getULong(ds.data + 8);
00839
00840 log_debug("RCV: X-- IA_PD %s",
00841 print_hex_1(4, ia->iaid, 59));
00842
00843 log_debug("RCV: | X-- starts %u",
00844 (unsigned)ia->starts);
00845 log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
00846 log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
00847
00848
00849
00850
00851
00852
00853
00854 if ((ia->renew > 0) && (ia->rebind > 0) &&
00855 (ia->renew > ia->rebind)) {
00856 log_debug("RCV: | !-- INVALID renew/rebind "
00857 "times, IA_PD discarded.");
00858 dfree(ia, MDL);
00859 data_string_forget(&ds, MDL);
00860 continue;
00861 }
00862
00863 if (ds.len > 12) {
00864 log_debug("RCV: | X-- [Options]");
00865
00866 if (!option_state_allocate(&ia->options,
00867 MDL)) {
00868 log_error("Out of memory allocating "
00869 "IA_PD option state.");
00870 dfree(ia, MDL);
00871 data_string_forget(&ds, MDL);
00872 return ISC_R_NOMEMORY;
00873 }
00874
00875 if (!parse_option_buffer(ia->options,
00876 ds.data + 12,
00877 ds.len - 12,
00878 &dhcpv6_universe)) {
00879 log_error("Corrupt IA_PD options.");
00880 option_state_dereference(&ia->options,
00881 MDL);
00882 dfree(ia, MDL);
00883 data_string_forget(&ds, MDL);
00884 return DHCP_R_BADPARSE;
00885 }
00886 }
00887 data_string_forget(&ds, MDL);
00888
00889 if (ia->options != NULL) {
00890 result = dhc6_parse_prefixes(&ia->addrs,
00891 packet,
00892 ia->options);
00893 if (result != ISC_R_SUCCESS) {
00894 option_state_dereference(&ia->options,
00895 MDL);
00896 dfree(ia, MDL);
00897 return result;
00898 }
00899 }
00900
00901 while (*pia != NULL)
00902 pia = &(*pia)->next;
00903 *pia = ia;
00904 pia = &ia->next;
00905 } else {
00906 log_error("Invalid IA_PD option cache.");
00907 dfree(ia, MDL);
00908 if (ds.len != 0)
00909 data_string_forget(&ds, MDL);
00910 return ISC_R_UNEXPECTED;
00911 }
00912 }
00913 delete_option(&dhcpv6_universe, options, D6O_IA_PD);
00914
00915 return ISC_R_SUCCESS;
00916 }
00917
00918
00919 static isc_result_t
00920 dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
00921 struct option_state *options)
00922 {
00923 struct data_string ds;
00924 struct option_cache *oc;
00925 struct dhc6_addr *addr;
00926
00927 memset(&ds, 0, sizeof(ds));
00928
00929 oc = lookup_option(&dhcpv6_universe, options, D6O_IAADDR);
00930 for ( ; oc != NULL ; oc = oc->next) {
00931 addr = dmalloc(sizeof(*addr), MDL);
00932 if (addr == NULL) {
00933 log_error("Out of memory allocating "
00934 "address structure.");
00935 return ISC_R_NOMEMORY;
00936 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
00937 options, NULL, &global_scope,
00938 oc, MDL) &&
00939 (ds.len >= 24)) {
00940
00941 addr->address.len = 16;
00942 memcpy(addr->address.iabuf, ds.data, 16);
00943 addr->starts = cur_time;
00944 addr->preferred_life = getULong(ds.data + 16);
00945 addr->max_life = getULong(ds.data + 20);
00946
00947 log_debug("RCV: | | X-- IAADDR %s",
00948 piaddr(addr->address));
00949 log_debug("RCV: | | | X-- Preferred lifetime %u.",
00950 addr->preferred_life);
00951 log_debug("RCV: | | | X-- Max lifetime %u.",
00952 addr->max_life);
00953
00954
00955
00956
00957
00958 if ((addr->preferred_life > addr->max_life)) {
00959 log_debug("RCV: | | | !-- INVALID lifetimes, "
00960 "IAADDR discarded. Check your "
00961 "server configuration.");
00962 dfree(addr, MDL);
00963 data_string_forget(&ds, MDL);
00964 continue;
00965 }
00966
00967
00968
00969
00970
00971 if (ds.len > 24) {
00972 if (!option_state_allocate(&addr->options,
00973 MDL)) {
00974 log_error("Out of memory allocating "
00975 "IAADDR option state.");
00976 dfree(addr, MDL);
00977 data_string_forget(&ds, MDL);
00978 return ISC_R_NOMEMORY;
00979 }
00980
00981 if (!parse_option_buffer(addr->options,
00982 ds.data + 24,
00983 ds.len - 24,
00984 &dhcpv6_universe)) {
00985 log_error("Corrupt IAADDR options.");
00986 option_state_dereference(&addr->options,
00987 MDL);
00988 dfree(addr, MDL);
00989 data_string_forget(&ds, MDL);
00990 return DHCP_R_BADPARSE;
00991 }
00992 }
00993
00994 if (addr->options != NULL)
00995 log_debug("RCV: | | | X-- "
00996 "[Options]");
00997
00998 data_string_forget(&ds, MDL);
00999
01000 *paddr = addr;
01001 paddr = &addr->next;
01002 } else {
01003 log_error("Invalid IAADDR option cache.");
01004 dfree(addr, MDL);
01005 if (ds.len != 0)
01006 data_string_forget(&ds, MDL);
01007 return ISC_R_UNEXPECTED;
01008 }
01009 }
01010 delete_option(&dhcpv6_universe, options, D6O_IAADDR);
01011
01012 return ISC_R_SUCCESS;
01013 }
01014
01015 static isc_result_t
01016 dhc6_parse_prefixes(struct dhc6_addr **ppfx, struct packet *packet,
01017 struct option_state *options)
01018 {
01019 struct data_string ds;
01020 struct option_cache *oc;
01021 struct dhc6_addr *pfx;
01022
01023 memset(&ds, 0, sizeof(ds));
01024
01025 oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX);
01026 for ( ; oc != NULL ; oc = oc->next) {
01027 pfx = dmalloc(sizeof(*pfx), MDL);
01028 if (pfx == NULL) {
01029 log_error("Out of memory allocating "
01030 "prefix structure.");
01031 return ISC_R_NOMEMORY;
01032 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
01033 options, NULL, &global_scope,
01034 oc, MDL) &&
01035 (ds.len >= 25)) {
01036
01037 pfx->preferred_life = getULong(ds.data);
01038 pfx->max_life = getULong(ds.data + 4);
01039 pfx->plen = getUChar(ds.data + 8);
01040 pfx->address.len = 16;
01041 memcpy(pfx->address.iabuf, ds.data + 9, 16);
01042 pfx->starts = cur_time;
01043
01044 log_debug("RCV: | | X-- IAPREFIX %s/%d",
01045 piaddr(pfx->address), (int)pfx->plen);
01046 log_debug("RCV: | | | X-- Preferred lifetime %u.",
01047 pfx->preferred_life);
01048 log_debug("RCV: | | | X-- Max lifetime %u.",
01049 pfx->max_life);
01050
01051
01052 if ((pfx->plen < 4) || (pfx->plen > 128)) {
01053 log_debug("RCV: | | | !-- INVALID prefix "
01054 "length, IAPREFIX discarded. "
01055 "Check your server configuration.");
01056 dfree(pfx, MDL);
01057 data_string_forget(&ds, MDL);
01058 continue;
01059 }
01060
01061
01062
01063
01064 if ((pfx->preferred_life > pfx->max_life)) {
01065 log_debug("RCV: | | | !-- INVALID lifetimes, "
01066 "IAPREFIX discarded. Check your "
01067 "server configuration.");
01068 dfree(pfx, MDL);
01069 data_string_forget(&ds, MDL);
01070 continue;
01071 }
01072
01073
01074
01075
01076
01077 if (ds.len > 25) {
01078 if (!option_state_allocate(&pfx->options,
01079 MDL)) {
01080 log_error("Out of memory allocating "
01081 "IAPREFIX option state.");
01082 dfree(pfx, MDL);
01083 data_string_forget(&ds, MDL);
01084 return ISC_R_NOMEMORY;
01085 }
01086
01087 if (!parse_option_buffer(pfx->options,
01088 ds.data + 25,
01089 ds.len - 25,
01090 &dhcpv6_universe)) {
01091 log_error("Corrupt IAPREFIX options.");
01092 option_state_dereference(&pfx->options,
01093 MDL);
01094 dfree(pfx, MDL);
01095 data_string_forget(&ds, MDL);
01096 return DHCP_R_BADPARSE;
01097 }
01098 }
01099
01100 if (pfx->options != NULL)
01101 log_debug("RCV: | | | X-- "
01102 "[Options]");
01103
01104 data_string_forget(&ds, MDL);
01105
01106 *ppfx = pfx;
01107 ppfx = &pfx->next;
01108 } else {
01109 log_error("Invalid IAPREFIX option cache.");
01110 dfree(pfx, MDL);
01111 if (ds.len != 0)
01112 data_string_forget(&ds, MDL);
01113 return ISC_R_UNEXPECTED;
01114 }
01115 }
01116 delete_option(&dhcpv6_universe, options, D6O_IAPREFIX);
01117
01118 return ISC_R_SUCCESS;
01119 }
01120
01121
01122 void
01123 dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line)
01124 {
01125 struct dhc6_ia *ia, *nia;
01126 struct dhc6_lease *lease;
01127
01128 if (src == NULL || *src == NULL) {
01129 log_error("Attempt to destroy null lease.");
01130 return;
01131 }
01132 lease = *src;
01133
01134 if (lease->server_id.len != 0)
01135 data_string_forget(&lease->server_id, file, line);
01136
01137 for (ia = lease->bindings ; ia != NULL ; ia = nia) {
01138 nia = ia->next;
01139
01140 dhc6_ia_destroy(&ia, file, line);
01141 }
01142
01143 if (lease->options != NULL)
01144 option_state_dereference(&lease->options, file, line);
01145
01146 dfree(lease, file, line);
01147 *src = NULL;
01148 }
01149
01150
01151
01152
01153
01154 static void
01155 dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line)
01156 {
01157 struct dhc6_addr *addr, *naddr;
01158 struct dhc6_ia *ia;
01159
01160 if (src == NULL || *src == NULL) {
01161 log_error("Attempt to destroy null IA.");
01162 return;
01163 }
01164 ia = *src;
01165
01166 for (addr = ia->addrs ; addr != NULL ; addr = naddr) {
01167 naddr = addr->next;
01168
01169 if (addr->options != NULL)
01170 option_state_dereference(&addr->options, file, line);
01171
01172 dfree(addr, file, line);
01173 }
01174
01175 if (ia->options != NULL)
01176 option_state_dereference(&ia->options, file, line);
01177
01178 dfree(ia, file, line);
01179 *src = NULL;
01180 }
01181
01182
01183
01184
01185
01186 static void
01187 insert_lease(struct dhc6_lease **head, struct dhc6_lease *new)
01188 {
01189 while (*head != NULL) {
01190 if ((*head)->server_id.len == new->server_id.len &&
01191 memcmp((*head)->server_id.data, new->server_id.data,
01192 new->server_id.len) == 0) {
01193 new->next = (*head)->next;
01194 dhc6_lease_destroy(head, MDL);
01195 break;
01196 }
01197
01198 head= &(*head)->next;
01199 }
01200
01201 *head = new;
01202 return;
01203 }
01204
01205
01206
01207
01208 static int
01209 dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
01210 {
01211 struct dhc6_ia *ia;
01212 struct dhc6_addr *addr;
01213 struct option **req;
01214 int i;
01215
01216 if (lease->score)
01217 return lease->score;
01218
01219 lease->score = 1;
01220
01221
01222
01223 req = client->config->required_options;
01224 if (req != NULL) {
01225 for (i = 0 ; req[i] != NULL ; i++) {
01226 if (lookup_option(&dhcpv6_universe, lease->options,
01227 req[i]->code) == NULL) {
01228 lease->score = 0;
01229 return lease->score;
01230 }
01231 }
01232 }
01233
01234
01235 req = client->config->requested_options;
01236 if (req != NULL) {
01237 for (i = 0 ; req[i] != NULL ; i++) {
01238 if (lookup_option(&dhcpv6_universe, lease->options,
01239 req[i]->code) != NULL)
01240 lease->score++;
01241 }
01242 }
01243
01244 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
01245 lease->score += 50;
01246
01247 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
01248 lease->score += 100;
01249 }
01250 }
01251
01252 return lease->score;
01253 }
01254
01255
01256
01257
01258
01259 void
01260 start_init6(struct client_state *client)
01261 {
01262 struct timeval tv;
01263
01264 log_debug("PRC: Soliciting for leases (INIT).");
01265 client->state = S_INIT;
01266
01267
01268 client->IRT = SOL_TIMEOUT * 100;
01269 client->MRT = SOL_MAX_RT * 100;
01270 client->MRC = 0;
01271
01272 if (!onetry)
01273 client->MRD = 0;
01274 else
01275 client->MRD = client->config->timeout;
01276
01277 dhc6_retrans_init(client);
01278
01279
01280
01281
01282
01283
01284
01285 if (client->RT <= client->IRT)
01286 client->RT = client->IRT + (client->IRT - client->RT);
01287
01288 if (client->RT <= client->IRT)
01289 client->RT = client->IRT + 1;
01290
01291 client->v6_handler = init_handler;
01292
01293
01294
01295
01296
01297
01298 tv.tv_sec = cur_tv.tv_sec;
01299 tv.tv_usec = cur_tv.tv_usec;
01300 tv.tv_usec += (random() % (SOL_MAX_DELAY * 100)) * 10000;
01301 if (tv.tv_usec >= 1000000) {
01302 tv.tv_sec += 1;
01303 tv.tv_usec -= 1000000;
01304 }
01305 add_timeout(&tv, do_init6, client, NULL, NULL);
01306
01307 if (nowait)
01308 go_daemon();
01309 }
01310
01311
01312
01313
01314
01315 void
01316 start_info_request6(struct client_state *client)
01317 {
01318 struct timeval tv;
01319
01320 log_debug("PRC: Requesting information (INIT).");
01321 client->state = S_INIT;
01322
01323
01324 client->IRT = INF_TIMEOUT * 100;
01325 client->MRT = INF_MAX_RT * 100;
01326 client->MRC = 0;
01327
01328 if (!onetry)
01329 client->MRD = 0;
01330 else
01331 client->MRD = client->config->timeout;
01332
01333 dhc6_retrans_init(client);
01334
01335 client->v6_handler = info_request_handler;
01336
01337
01338
01339
01340
01341
01342 tv.tv_sec = cur_tv.tv_sec;
01343 tv.tv_usec = cur_tv.tv_usec;
01344 tv.tv_usec += (random() % (INF_MAX_DELAY * 100)) * 10000;
01345 if (tv.tv_usec >= 1000000) {
01346 tv.tv_sec += 1;
01347 tv.tv_usec -= 1000000;
01348 }
01349 add_timeout(&tv, do_info_request6, client, NULL, NULL);
01350
01351 if (nowait)
01352 go_daemon();
01353 }
01354
01355
01356
01357
01358 isc_boolean_t
01359 unexpired_address_in_lease(struct dhc6_lease *lease)
01360 {
01361 struct dhc6_ia *ia;
01362 struct dhc6_addr *addr;
01363
01364 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
01365 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
01366 if (addr->flags & DHC6_ADDR_EXPIRED)
01367 continue;
01368
01369 if (addr->starts + addr->max_life > cur_time) {
01370 return ISC_TRUE;
01371 }
01372 }
01373 }
01374
01375 log_info("PRC: Previous lease is devoid of active addresses."
01376 " Re-initializing.");
01377
01378 return ISC_FALSE;
01379 }
01380
01381
01382
01383
01384
01385
01386 void
01387 start_confirm6(struct client_state *client)
01388 {
01389 struct timeval tv;
01390
01391
01392 if ((client->active_lease == NULL) ||
01393 !active_prefix(client) ||
01394 client->active_lease->released ||
01395 !unexpired_address_in_lease(client->active_lease)) {
01396 dhc6_lease_destroy(&client->active_lease, MDL);
01397 start_init6(client);
01398 return;
01399 }
01400
01401 log_debug("PRC: Confirming active lease (INIT-REBOOT).");
01402 client->state = S_REBOOTING;
01403
01404
01405 client->IRT = CNF_TIMEOUT * 100;
01406 client->MRT = CNF_MAX_RT * 100;
01407 client->MRC = 0;
01408 client->MRD = CNF_MAX_RD;
01409
01410 dhc6_retrans_init(client);
01411
01412 client->v6_handler = reply_handler;
01413
01414
01415
01416
01417
01418
01419 tv.tv_sec = cur_tv.tv_sec;
01420 tv.tv_usec = cur_tv.tv_usec;
01421 tv.tv_usec += (random() % (CNF_MAX_DELAY * 100)) * 10000;
01422 if (tv.tv_usec >= 1000000) {
01423 tv.tv_sec += 1;
01424 tv.tv_usec -= 1000000;
01425 }
01426 if (wanted_ia_pd != 0) {
01427 client->state = S_REBINDING;
01428 client->refresh_type = DHCPV6_REBIND;
01429 add_timeout(&tv, do_refresh6, client, NULL, NULL);
01430 } else
01431 add_timeout(&tv, do_confirm6, client, NULL, NULL);
01432 }
01433
01434
01435
01436
01437
01438 #define CHK_TIM_SUCCESS 0
01439 #define CHK_TIM_MRC_EXCEEDED 1
01440 #define CHK_TIM_MRD_EXCEEDED 2
01441 #define CHK_TIM_ALLOC_FAILURE 3
01442
01443 int
01444 check_timing6 (struct client_state *client, u_int8_t msg_type,
01445 char *msg_str, struct dhc6_lease *lease,
01446 struct data_string *ds)
01447 {
01448 struct timeval elapsed;
01449
01450
01451
01452
01453 if (client->txcount == 0) {
01454 client->start_time.tv_sec = cur_tv.tv_sec;
01455 client->start_time.tv_usec = cur_tv.tv_usec;
01456 } else if ((client->MRC != 0) && (client->txcount > client->MRC)) {
01457 log_info("Max retransmission count exceeded.");
01458 return(CHK_TIM_MRC_EXCEEDED);
01459 }
01460
01461
01462 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
01463 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
01464 if (elapsed.tv_usec < 0) {
01465 elapsed.tv_sec -= 1;
01466 elapsed.tv_usec += 1000000;
01467 }
01468
01469
01470 if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
01471 log_info("Max retransmission duration exceeded.");
01472 return(CHK_TIM_MRD_EXCEEDED);
01473 }
01474
01475 memset(ds, 0, sizeof(*ds));
01476 if (!buffer_allocate(&(ds->buffer), 4, MDL)) {
01477 log_error("Unable to allocate memory for %s.", msg_str);
01478 return(CHK_TIM_ALLOC_FAILURE);
01479 }
01480 ds->data = ds->buffer->data;
01481 ds->len = 4;
01482
01483 ds->buffer->data[0] = msg_type;
01484 memcpy(ds->buffer->data + 1, client->dhcpv6_transaction_id, 3);
01485
01486
01487
01488 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
01489 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
01490 client->elapsed = 0xffff;
01491 } else {
01492 client->elapsed = elapsed.tv_sec * 100;
01493 client->elapsed += elapsed.tv_usec / 10000;
01494 }
01495
01496 if (client->elapsed == 0)
01497 log_debug("XMT: Forming %s, 0 ms elapsed.", msg_str);
01498 else
01499 log_debug("XMT: Forming %s, %u0 ms elapsed.", msg_str,
01500 (unsigned)client->elapsed);
01501
01502 client->elapsed = htons(client->elapsed);
01503
01504 make_client6_options(client, &client->sent_options, lease, msg_type);
01505
01506 return(CHK_TIM_SUCCESS);
01507 }
01508
01509
01510
01511
01512 void
01513 do_init6(void *input)
01514 {
01515 struct client_state *client;
01516 struct dhc6_ia *old_ia;
01517 struct dhc6_addr *old_addr;
01518 struct data_string ds;
01519 struct data_string ia;
01520 struct data_string addr;
01521 struct timeval tv;
01522 u_int32_t t1, t2;
01523 int i, idx, len, send_ret;
01524
01525 client = input;
01526
01527
01528
01529
01530
01531 if (client->advertised_leases != NULL) {
01532 start_selecting6(client);
01533 return;
01534 }
01535
01536 switch(check_timing6(client, DHCPV6_SOLICIT, "Solicit", NULL, &ds)) {
01537 case CHK_TIM_MRC_EXCEEDED:
01538 case CHK_TIM_ALLOC_FAILURE:
01539 return;
01540 case CHK_TIM_MRD_EXCEEDED:
01541 client->state = S_STOPPED;
01542 if (client->active_lease != NULL) {
01543 dhc6_lease_destroy(&client->active_lease, MDL);
01544 client->active_lease = NULL;
01545 }
01546
01547 if (stopping_finished())
01548 exit(2);
01549 return;
01550 }
01551
01552
01553
01554
01555 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
01556 NULL, client->sent_options, &global_scope,
01557 &dhcpv6_universe);
01558
01559
01560 if (lookup_option(&dhcpv6_universe, client->sent_options,
01561 D6O_RAPID_COMMIT) != NULL) {
01562 client->v6_handler = rapid_commit_handler;
01563 }
01564
01565
01566 for (i = 0; i < wanted_ia_na; i++) {
01567
01568
01569
01570
01571
01572 memset(&ia, 0, sizeof(ia));
01573 if (!buffer_allocate(&ia.buffer, 12, MDL)) {
01574 log_error("Unable to allocate memory for IA_NA.");
01575 data_string_forget(&ds, MDL);
01576 return;
01577 }
01578 ia.data = ia.buffer->data;
01579 ia.len = 12;
01580
01581
01582
01583
01584
01585 if (client->interface->hw_address.hlen > 4) {
01586 idx = client->interface->hw_address.hlen - 4;
01587 len = 4;
01588 } else {
01589 idx = 0;
01590 len = client->interface->hw_address.hlen;
01591 }
01592 memcpy(ia.buffer->data,
01593 client->interface->hw_address.hbuf + idx,
01594 len);
01595 if (i)
01596 ia.buffer->data[3] += i;
01597
01598 t1 = client->config->requested_lease / 2;
01599 t2 = t1 + (t1 / 2);
01600 putULong(ia.buffer->data + 4, t1);
01601 putULong(ia.buffer->data + 8, t2);
01602
01603 log_debug("XMT: X-- IA_NA %s",
01604 print_hex_1(4, ia.buffer->data, 55));
01605 log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
01606 log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
01607
01608 if ((client->active_lease != NULL) &&
01609 ((old_ia = find_ia(client->active_lease->bindings,
01610 D6O_IA_NA,
01611 (char *)ia.buffer->data)) != NULL)) {
01612
01613
01614
01615
01616 memset(&addr, 0, sizeof(addr));
01617 for (old_addr = old_ia->addrs ; old_addr != NULL ;
01618 old_addr = old_addr->next) {
01619 if (old_addr->address.len != 16) {
01620 log_error("Invalid IPv6 address "
01621 "length %d. "
01622 "Ignoring. (%s:%d)",
01623 old_addr->address.len,
01624 MDL);
01625 continue;
01626 }
01627
01628 if (!buffer_allocate(&addr.buffer, 24, MDL)) {
01629 log_error("Unable to allocate memory "
01630 "for IAADDR.");
01631 data_string_forget(&ia, MDL);
01632 data_string_forget(&ds, MDL);
01633 return;
01634 }
01635 addr.data = addr.buffer->data;
01636 addr.len = 24;
01637
01638 memcpy(addr.buffer->data,
01639 old_addr->address.iabuf,
01640 16);
01641
01642 t1 = client->config->requested_lease;
01643 t2 = t1 + (t1 / 2);
01644 putULong(addr.buffer->data + 16, t1);
01645 putULong(addr.buffer->data + 20, t2);
01646
01647 log_debug("XMT: | X-- Request address %s.",
01648 piaddr(old_addr->address));
01649 log_debug("XMT: | | X-- Request "
01650 "preferred in +%u",
01651 (unsigned)t1);
01652 log_debug("XMT: | | X-- Request valid "
01653 "in +%u",
01654 (unsigned)t2);
01655
01656 append_option(&ia, &dhcpv6_universe,
01657 iaaddr_option,
01658 &addr);
01659
01660 data_string_forget(&addr, MDL);
01661 }
01662 }
01663
01664 append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
01665 data_string_forget(&ia, MDL);
01666 }
01667
01668
01669 for (i = 0; i < wanted_ia_ta; i++) {
01670
01671
01672
01673
01674
01675 memset(&ia, 0, sizeof(ia));
01676 if (!buffer_allocate(&ia.buffer, 4, MDL)) {
01677 log_error("Unable to allocate memory for IA_TA.");
01678 data_string_forget(&ds, MDL);
01679 return;
01680 }
01681 ia.data = ia.buffer->data;
01682 ia.len = 4;
01683
01684
01685
01686
01687
01688 if (client->interface->hw_address.hlen > 4) {
01689 idx = client->interface->hw_address.hlen - 4;
01690 len = 4;
01691 } else {
01692 idx = 0;
01693 len = client->interface->hw_address.hlen;
01694 }
01695 memcpy(ia.buffer->data,
01696 client->interface->hw_address.hbuf + idx,
01697 len);
01698 if (i)
01699 ia.buffer->data[3] += i;
01700
01701 log_debug("XMT: X-- IA_TA %s",
01702 print_hex_1(4, ia.buffer->data, 55));
01703
01704 if ((client->active_lease != NULL) &&
01705 ((old_ia = find_ia(client->active_lease->bindings,
01706 D6O_IA_TA,
01707 (char *)ia.buffer->data)) != NULL)) {
01708
01709
01710
01711
01712 memset(&addr, 0, sizeof(addr));
01713 for (old_addr = old_ia->addrs ; old_addr != NULL ;
01714 old_addr = old_addr->next) {
01715 if (old_addr->address.len != 16) {
01716 log_error("Invalid IPv6 address "
01717 "length %d. "
01718 "Ignoring. (%s:%d)",
01719 old_addr->address.len,
01720 MDL);
01721 continue;
01722 }
01723
01724 if (!buffer_allocate(&addr.buffer, 24, MDL)) {
01725 log_error("Unable to allocate memory "
01726 "for IAADDR.");
01727 data_string_forget(&ia, MDL);
01728 data_string_forget(&ds, MDL);
01729 return;
01730 }
01731 addr.data = addr.buffer->data;
01732 addr.len = 24;
01733
01734 memcpy(addr.buffer->data,
01735 old_addr->address.iabuf,
01736 16);
01737
01738 t1 = client->config->requested_lease;
01739 t2 = t1 + (t1 / 2);
01740 putULong(addr.buffer->data + 16, t1);
01741 putULong(addr.buffer->data + 20, t2);
01742
01743 log_debug("XMT: | X-- Request address %s.",
01744 piaddr(old_addr->address));
01745 log_debug("XMT: | | X-- Request "
01746 "preferred in +%u",
01747 (unsigned)t1);
01748 log_debug("XMT: | | X-- Request valid "
01749 "in +%u",
01750 (unsigned)t2);
01751
01752 append_option(&ia, &dhcpv6_universe,
01753 iaaddr_option,
01754 &addr);
01755
01756 data_string_forget(&addr, MDL);
01757 }
01758 }
01759
01760 append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia);
01761 data_string_forget(&ia, MDL);
01762 }
01763
01764
01765 for (i = 0; i < wanted_ia_pd; i++) {
01766
01767
01768
01769
01770
01771 memset(&ia, 0, sizeof(ia));
01772 if (!buffer_allocate(&ia.buffer, 12, MDL)) {
01773 log_error("Unable to allocate memory for IA_PD.");
01774 data_string_forget(&ds, MDL);
01775 return;
01776 }
01777 ia.data = ia.buffer->data;
01778 ia.len = 12;
01779
01780
01781
01782
01783
01784 if (client->interface->hw_address.hlen > 4) {
01785 idx = client->interface->hw_address.hlen - 4;
01786 len = 4;
01787 } else {
01788 idx = 0;
01789 len = client->interface->hw_address.hlen;
01790 }
01791 memcpy(ia.buffer->data,
01792 client->interface->hw_address.hbuf + idx,
01793 len);
01794 if (i)
01795 ia.buffer->data[3] += i;
01796
01797 t1 = client->config->requested_lease / 2;
01798 t2 = t1 + (t1 / 2);
01799 putULong(ia.buffer->data + 4, t1);
01800 putULong(ia.buffer->data + 8, t2);
01801
01802 log_debug("XMT: X-- IA_PD %s",
01803 print_hex_1(4, ia.buffer->data, 55));
01804 log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
01805 log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
01806
01807 if ((client->active_lease != NULL) &&
01808 ((old_ia = find_ia(client->active_lease->bindings,
01809 D6O_IA_PD,
01810 (char *)ia.buffer->data)) != NULL)) {
01811
01812
01813
01814
01815 memset(&addr, 0, sizeof(addr));
01816 for (old_addr = old_ia->addrs ; old_addr != NULL ;
01817 old_addr = old_addr->next) {
01818 if (old_addr->address.len != 16) {
01819 log_error("Invalid IPv6 prefix, "
01820 "Ignoring. (%s:%d)",
01821 MDL);
01822 continue;
01823 }
01824
01825 if (!buffer_allocate(&addr.buffer, 25, MDL)) {
01826 log_error("Unable to allocate memory "
01827 "for IAPREFIX.");
01828 data_string_forget(&ia, MDL);
01829 data_string_forget(&ds, MDL);
01830 return;
01831 }
01832 addr.data = addr.buffer->data;
01833 addr.len = 25;
01834
01835 t1 = client->config->requested_lease;
01836 t2 = t1 + (t1 / 2);
01837 putULong(addr.buffer->data, t1);
01838 putULong(addr.buffer->data + 4, t2);
01839
01840 putUChar(addr.buffer->data + 8,
01841 old_addr->plen);
01842 memcpy(addr.buffer->data + 9,
01843 old_addr->address.iabuf,
01844 16);
01845
01846 log_debug("XMT: | X-- Request prefix %s/%u.",
01847 piaddr(old_addr->address),
01848 (unsigned) old_addr->plen);
01849 log_debug("XMT: | | X-- Request "
01850 "preferred in +%u",
01851 (unsigned)t1);
01852 log_debug("XMT: | | X-- Request valid "
01853 "in +%u",
01854 (unsigned)t2);
01855
01856 append_option(&ia, &dhcpv6_universe,
01857 iaprefix_option,
01858 &addr);
01859
01860 data_string_forget(&addr, MDL);
01861 }
01862 }
01863
01864 append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia);
01865 data_string_forget(&ia, MDL);
01866 }
01867
01868
01869
01870 log_info("XMT: Solicit on %s, interval %ld0ms.",
01871 client->name ? client->name : client->interface->name,
01872 (long int)client->RT);
01873
01874 send_ret = send_packet6(client->interface,
01875 ds.data, ds.len, &DHCPv6DestAddr);
01876 if (send_ret != ds.len) {
01877 log_error("dhc6: send_packet6() sent %d of %d bytes",
01878 send_ret, ds.len);
01879 }
01880
01881 data_string_forget(&ds, MDL);
01882
01883
01884 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
01885 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
01886 if (tv.tv_usec >= 1000000) {
01887 tv.tv_sec += 1;
01888 tv.tv_usec -= 1000000;
01889 }
01890 add_timeout(&tv, do_init6, client, NULL, NULL);
01891
01892 dhc6_retrans_advance(client);
01893 }
01894
01895
01896 void
01897 do_info_request6(void *input)
01898 {
01899 struct client_state *client;
01900 struct data_string ds;
01901 struct timeval tv;
01902 int send_ret;
01903
01904 client = input;
01905
01906 switch(check_timing6(client, DHCPV6_INFORMATION_REQUEST,
01907 "Info-Request", NULL, &ds)) {
01908 case CHK_TIM_MRC_EXCEEDED:
01909 case CHK_TIM_ALLOC_FAILURE:
01910 return;
01911 case CHK_TIM_MRD_EXCEEDED:
01912 exit(2);
01913 case CHK_TIM_SUCCESS:
01914 break;
01915 }
01916
01917
01918
01919 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
01920 NULL, client->sent_options, &global_scope,
01921 &dhcpv6_universe);
01922
01923
01924
01925 log_info("XMT: Info-Request on %s, interval %ld0ms.",
01926 client->name ? client->name : client->interface->name,
01927 (long int)client->RT);
01928
01929 send_ret = send_packet6(client->interface,
01930 ds.data, ds.len, &DHCPv6DestAddr);
01931 if (send_ret != ds.len) {
01932 log_error("dhc6: send_packet6() sent %d of %d bytes",
01933 send_ret, ds.len);
01934 }
01935
01936 data_string_forget(&ds, MDL);
01937
01938
01939 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
01940 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
01941 if (tv.tv_usec >= 1000000) {
01942 tv.tv_sec += 1;
01943 tv.tv_usec -= 1000000;
01944 }
01945 add_timeout(&tv, do_info_request6, client, NULL, NULL);
01946
01947 dhc6_retrans_advance(client);
01948 }
01949
01950
01951
01952
01953 void
01954 do_confirm6(void *input)
01955 {
01956 struct client_state *client;
01957 struct data_string ds;
01958 int send_ret;
01959 struct timeval tv;
01960
01961 client = input;
01962
01963 if (client->active_lease == NULL)
01964 log_fatal("Impossible condition at %s:%d.", MDL);
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980 switch(check_timing6(client, DHCPV6_CONFIRM, "Confirm",
01981 client->active_lease, &ds)) {
01982 case CHK_TIM_MRC_EXCEEDED:
01983 case CHK_TIM_MRD_EXCEEDED:
01984 start_bound(client);
01985 return;
01986 case CHK_TIM_ALLOC_FAILURE:
01987 return;
01988 case CHK_TIM_SUCCESS:
01989 break;
01990 }
01991
01992
01993
01994 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
01995 client->sent_options, &global_scope,
01996 &dhcpv6_universe);
01997
01998
01999 if (wanted_ia_na &&
02000 dhc6_add_ia_na(client, &ds, client->active_lease,
02001 DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
02002 data_string_forget(&ds, MDL);
02003 return;
02004 }
02005 if (wanted_ia_ta &&
02006 dhc6_add_ia_ta(client, &ds, client->active_lease,
02007 DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
02008 data_string_forget(&ds, MDL);
02009 return;
02010 }
02011
02012
02013
02014 log_info("XMT: Confirm on %s, interval %ld0ms.",
02015 client->name ? client->name : client->interface->name,
02016 (long int)client->RT);
02017
02018 send_ret = send_packet6(client->interface, ds.data, ds.len,
02019 &DHCPv6DestAddr);
02020 if (send_ret != ds.len) {
02021 log_error("dhc6: sendpacket6() sent %d of %d bytes",
02022 send_ret, ds.len);
02023 }
02024
02025 data_string_forget(&ds, MDL);
02026
02027
02028 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
02029 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
02030 if (tv.tv_usec >= 1000000) {
02031 tv.tv_sec += 1;
02032 tv.tv_usec -= 1000000;
02033 }
02034 add_timeout(&tv, do_confirm6, client, NULL, NULL);
02035
02036 dhc6_retrans_advance(client);
02037 }
02038
02039
02040
02041
02042 void
02043 start_release6(struct client_state *client)
02044 {
02045
02046 cancel_timeout(do_confirm6, client);
02047 cancel_timeout(do_select6, client);
02048 cancel_timeout(do_refresh6, client);
02049 cancel_timeout(do_release6, client);
02050 cancel_timeout(do_decline6, client);
02051 client->state = S_STOPPED;
02052
02053
02054
02055
02056
02057
02058 unconfigure6(client, "RELEASE6");
02059
02060
02061 if (client->active_lease == NULL)
02062 return;
02063 client->active_lease->released = ISC_TRUE;
02064 write_client6_lease(client, client->active_lease, 0, 1);
02065
02066
02067 client->IRT = REL_TIMEOUT * 100;
02068 client->MRT = 0;
02069 client->MRC = REL_MAX_RC;
02070 client->MRD = 0;
02071
02072 dhc6_retrans_init(client);
02073 client->v6_handler = reply_handler;
02074
02075 do_release6(client);
02076 }
02077
02078
02079
02080 static void
02081 do_release6(void *input)
02082 {
02083 struct client_state *client;
02084 struct data_string ds;
02085 int send_ret;
02086 struct timeval tv;
02087
02088 client = input;
02089
02090 if ((client->active_lease == NULL) || !active_prefix(client))
02091 return;
02092
02093 switch(check_timing6(client, DHCPV6_RELEASE, "Release",
02094 client->active_lease, &ds)) {
02095 case CHK_TIM_MRC_EXCEEDED:
02096 case CHK_TIM_ALLOC_FAILURE:
02097 case CHK_TIM_MRD_EXCEEDED:
02098 goto release_done;
02099 case CHK_TIM_SUCCESS:
02100 break;
02101 }
02102
02103
02104
02105
02106
02107
02108 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
02109 client->sent_options, &global_scope,
02110 &dhcpv6_universe);
02111
02112
02113 if (wanted_ia_na &&
02114 dhc6_add_ia_na(client, &ds, client->active_lease,
02115 DHCPV6_RELEASE) != ISC_R_SUCCESS) {
02116 data_string_forget(&ds, MDL);
02117 goto release_done;
02118 }
02119 if (wanted_ia_pd &&
02120 dhc6_add_ia_pd(client, &ds, client->active_lease,
02121 DHCPV6_RELEASE) != ISC_R_SUCCESS) {
02122 data_string_forget(&ds, MDL);
02123 goto release_done;
02124 }
02125
02126
02127 log_info("XMT: Release on %s, interval %ld0ms.",
02128 client->name ? client->name : client->interface->name,
02129 (long int)client->RT);
02130
02131 send_ret = send_packet6(client->interface, ds.data, ds.len,
02132 &DHCPv6DestAddr);
02133 if (send_ret != ds.len) {
02134 log_error("dhc6: sendpacket6() sent %d of %d bytes",
02135 send_ret, ds.len);
02136 }
02137
02138 data_string_forget(&ds, MDL);
02139
02140
02141 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
02142 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
02143 if (tv.tv_usec >= 1000000) {
02144 tv.tv_sec += 1;
02145 tv.tv_usec -= 1000000;
02146 }
02147 add_timeout(&tv, do_release6, client, NULL, NULL);
02148 dhc6_retrans_advance(client);
02149 return;
02150
02151 release_done:
02152 dhc6_lease_destroy(&client->active_lease, MDL);
02153 client->active_lease = NULL;
02154 if (stopping_finished())
02155 exit(0);
02156 }
02157
02158
02159
02160
02161 static void
02162 status_log(int code, const char *scope, const char *additional, int len)
02163 {
02164 const char *msg = NULL;
02165
02166 switch(code) {
02167 case STATUS_Success:
02168 msg = "Success";
02169 break;
02170
02171 case STATUS_UnspecFail:
02172 msg = "UnspecFail";
02173 break;
02174
02175 case STATUS_NoAddrsAvail:
02176 msg = "NoAddrsAvail";
02177 break;
02178
02179 case STATUS_NoBinding:
02180 msg = "NoBinding";
02181 break;
02182
02183 case STATUS_NotOnLink:
02184 msg = "NotOnLink";
02185 break;
02186
02187 case STATUS_UseMulticast:
02188 msg = "UseMulticast";
02189 break;
02190
02191 case STATUS_NoPrefixAvail:
02192 msg = "NoPrefixAvail";
02193 break;
02194
02195 default:
02196 msg = "UNKNOWN";
02197 break;
02198 }
02199
02200 if (len > 0)
02201 log_info("%s status code %s: %s", scope, msg,
02202 print_hex_1(len,
02203 (const unsigned char *)additional, 50));
02204 else
02205 log_info("%s status code %s.", scope, msg);
02206 }
02207
02208
02209
02210 static isc_result_t
02211 dhc6_get_status_code(struct option_state *options, unsigned *code,
02212 struct data_string *msg)
02213 {
02214 struct option_cache *oc;
02215 struct data_string ds;
02216 isc_result_t rval = ISC_R_SUCCESS;
02217
02218 if ((options == NULL) || (code == NULL))
02219 return DHCP_R_INVALIDARG;
02220
02221 if ((msg != NULL) && (msg->len != 0))
02222 return DHCP_R_INVALIDARG;
02223
02224 memset(&ds, 0, sizeof(ds));
02225
02226
02227 *code = STATUS_Success;
02228
02229 oc = lookup_option(&dhcpv6_universe, options, D6O_STATUS_CODE);
02230 if ((oc != NULL) &&
02231 evaluate_option_cache(&ds, NULL, NULL, NULL, options,
02232 NULL, &global_scope, oc, MDL)) {
02233 if (ds.len < 2) {
02234 log_error("Invalid status code length %d.", ds.len);
02235 rval = DHCP_R_FORMERR;
02236 } else
02237 *code = getUShort(ds.data);
02238
02239 if ((msg != NULL) && (ds.len > 2)) {
02240 data_string_copy(msg, &ds, MDL);
02241 msg->data += 2;
02242 msg->len -= 2;
02243 }
02244
02245 data_string_forget(&ds, MDL);
02246 return rval;
02247 }
02248
02249 return ISC_R_NOTFOUND;
02250 }
02251
02252
02253
02254 static isc_result_t
02255 dhc6_check_status(isc_result_t rval, struct option_state *options,
02256 const char *scope, unsigned *code)
02257 {
02258 struct data_string msg;
02259 isc_result_t status;
02260
02261 if ((scope == NULL) || (code == NULL))
02262 return DHCP_R_INVALIDARG;
02263
02264
02265 *code = STATUS_Success;
02266
02267
02268 if (options != NULL) {
02269 memset(&msg, 0, sizeof(msg));
02270 status = dhc6_get_status_code(options, code, &msg);
02271
02272 if (status == ISC_R_SUCCESS) {
02273 status_log(*code, scope, (char *)msg.data, msg.len);
02274 data_string_forget(&msg, MDL);
02275
02276 if (*code != STATUS_Success)
02277 rval = ISC_R_FAILURE;
02278
02279 } else if (status != ISC_R_NOTFOUND)
02280 rval = status;
02281 }
02282
02283 return rval;
02284 }
02285
02286
02287
02288
02289 static isc_result_t
02290 dhc6_check_advertise(struct dhc6_lease *lease)
02291 {
02292 struct dhc6_ia *ia;
02293 struct dhc6_addr *addr;
02294 isc_result_t rval = ISC_R_SUCCESS;
02295 int have_addrs = ISC_FALSE;
02296 unsigned code;
02297 const char *scope;
02298
02299 rval = dhc6_check_status(rval, lease->options, "message", &code);
02300
02301 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
02302 switch (ia->ia_type) {
02303 case D6O_IA_NA:
02304 scope = "IA_NA";
02305 break;
02306 case D6O_IA_TA:
02307 scope = "IA_TA";
02308 break;
02309 case D6O_IA_PD:
02310 scope = "IA_PD";
02311 break;
02312 default:
02313 log_error("dhc6_check_advertise: no type.");
02314 return ISC_R_FAILURE;
02315 }
02316 rval = dhc6_check_status(rval, ia->options, scope, &code);
02317
02318 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
02319 if (ia->ia_type != D6O_IA_PD)
02320 scope = "IAADDR";
02321 else
02322 scope = "IAPREFIX";
02323 rval = dhc6_check_status(rval, addr->options,
02324 scope, &code);
02325 have_addrs = ISC_TRUE;
02326 }
02327 }
02328
02329 if (have_addrs != ISC_TRUE)
02330 rval = ISC_R_ADDRNOTAVAIL;
02331
02332 return rval;
02333 }
02334
02335
02336
02337
02338 static isc_boolean_t
02339 dhc6_init_action(struct client_state *client, isc_result_t *rvalp,
02340 unsigned code)
02341 {
02342 if (rvalp == NULL)
02343 log_fatal("Impossible condition at %s:%d.", MDL);
02344
02345 if (client == NULL) {
02346 *rvalp = DHCP_R_INVALIDARG;
02347 return ISC_FALSE;
02348 }
02349
02350 if (*rvalp == ISC_R_SUCCESS)
02351 return ISC_FALSE;
02352
02353
02354 return ISC_FALSE;
02355 }
02356
02357
02358
02359
02360
02361 static isc_boolean_t
02362 dhc6_select_action(struct client_state *client, isc_result_t *rvalp,
02363 unsigned code)
02364 {
02365 struct dhc6_lease *lease;
02366 isc_result_t rval;
02367
02368 if (rvalp == NULL)
02369 log_fatal("Impossible condition at %s:%d.", MDL);
02370
02371 if (client == NULL) {
02372 *rvalp = DHCP_R_INVALIDARG;
02373 return ISC_FALSE;
02374 }
02375 rval = *rvalp;
02376
02377 if (rval == ISC_R_SUCCESS)
02378 return ISC_FALSE;
02379
02380 switch (code) {
02381
02382
02383
02384
02385
02386 case STATUS_Success:
02387
02388 case STATUS_NoBinding:
02389 case STATUS_UseMulticast:
02390
02391 return ISC_FALSE;
02392
02393
02394
02395
02396
02397 default:
02398 case STATUS_UnspecFail:
02399 if (client->advertised_leases != NULL) {
02400 dhc6_lease_destroy(&client->selected_lease, MDL);
02401 client->selected_lease = NULL;
02402
02403 start_selecting6(client);
02404
02405 break;
02406 } else
02407 return ISC_FALSE;
02408
02409
02410
02411
02412
02413 case STATUS_NoAddrsAvail:
02414 case STATUS_NoPrefixAvail:
02415 if (client->state == S_REBOOTING)
02416 return ISC_FALSE;
02417
02418 if (client->selected_lease == NULL)
02419 log_fatal("Impossible case at %s:%d.", MDL);
02420
02421 dhc6_lease_destroy(&client->selected_lease, MDL);
02422 client->selected_lease = NULL;
02423
02424 if (client->advertised_leases != NULL)
02425 start_selecting6(client);
02426 else
02427 start_init6(client);
02428
02429 break;
02430
02431
02432
02433
02434
02435
02436
02437 case STATUS_NotOnLink:
02438 if (client->state == S_REBOOTING) {
02439 if (client->active_lease == NULL)
02440 log_fatal("Impossible case at %s:%d.", MDL);
02441
02442 dhc6_lease_destroy(&client->active_lease, MDL);
02443 } else {
02444 if (client->selected_lease == NULL)
02445 log_fatal("Impossible case at %s:%d.", MDL);
02446
02447 dhc6_lease_destroy(&client->selected_lease, MDL);
02448 client->selected_lease = NULL;
02449
02450 while (client->advertised_leases != NULL) {
02451 lease = client->advertised_leases;
02452 client->advertised_leases = lease->next;
02453
02454 dhc6_lease_destroy(&lease, MDL);
02455 }
02456 }
02457
02458 start_init6(client);
02459 break;
02460 }
02461
02462 return ISC_TRUE;
02463 }
02464
02465 static void
02466 dhc6_withdraw_lease(struct client_state *client)
02467 {
02468 struct dhc6_ia *ia;
02469 struct dhc6_addr *addr;
02470
02471 if ((client == NULL) || (client->active_lease == NULL))
02472 return;
02473
02474 for (ia = client->active_lease->bindings ; ia != NULL ;
02475 ia = ia->next) {
02476 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
02477 addr->max_life = addr->preferred_life = 0;
02478 }
02479 }
02480
02481
02482 do_expire(client);
02483 }
02484
02485
02486
02487
02488
02489 static isc_boolean_t
02490 dhc6_reply_action(struct client_state *client, isc_result_t *rvalp,
02491 unsigned code)
02492 {
02493 isc_result_t rval;
02494
02495 if (rvalp == NULL)
02496 log_fatal("Impossible condition at %s:%d.", MDL);
02497
02498 if (client == NULL) {
02499 *rvalp = DHCP_R_INVALIDARG;
02500 return ISC_FALSE;
02501 }
02502 rval = *rvalp;
02503
02504 if (rval == ISC_R_SUCCESS)
02505 return ISC_FALSE;
02506
02507 switch (code) {
02508
02509
02510
02511 case STATUS_Success:
02512
02513
02514
02515
02516
02517 case STATUS_UnspecFail:
02518
02519 default:
02520 return ISC_FALSE;
02521
02522
02523
02524
02525
02526
02527
02528 case STATUS_UseMulticast:
02529 if (client->active_lease != NULL)
02530 delete_option(&dhcp_universe,
02531 client->active_lease->options,
02532 D6O_UNICAST);
02533 return ISC_FALSE;
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544
02545
02546
02547
02548 case STATUS_NotOnLink:
02549
02550
02551
02552
02553
02554 dhc6_withdraw_lease(client);
02555 break;
02556
02557
02558
02559
02560
02561
02562 case STATUS_NoAddrsAvail:
02563 case STATUS_NoPrefixAvail:
02564
02565 start_init6(client);
02566 break;
02567
02568
02569
02570
02571
02572 case STATUS_NoBinding:
02573 if (client->advertised_leases != NULL)
02574 log_fatal("Impossible condition at %s:%d.", MDL);
02575
02576 client->advertised_leases =
02577 dhc6_dup_lease(client->active_lease, MDL);
02578 start_selecting6(client);
02579 break;
02580 }
02581
02582 return ISC_TRUE;
02583 }
02584
02585
02586
02587
02588
02589
02590 static isc_boolean_t
02591 dhc6_stop_action(struct client_state *client, isc_result_t *rvalp,
02592 unsigned code)
02593 {
02594 isc_result_t rval;
02595
02596 if (rvalp == NULL)
02597 log_fatal("Impossible condition at %s:%d.", MDL);
02598
02599 if (client == NULL) {
02600 *rvalp = DHCP_R_INVALIDARG;
02601 return ISC_FALSE;
02602 }
02603 rval = *rvalp;
02604
02605 if (rval == ISC_R_SUCCESS)
02606 return ISC_FALSE;
02607
02608 switch (code) {
02609
02610
02611
02612 case STATUS_Success:
02613
02614 case STATUS_UnspecFail:
02615 default:
02616 return ISC_FALSE;
02617
02618
02619 case STATUS_NoBinding:
02620 if (rval == ISC_R_FAILURE)
02621 *rvalp = ISC_R_SUCCESS;
02622 return ISC_FALSE;
02623
02624
02625 case STATUS_NoAddrsAvail:
02626 case STATUS_NoPrefixAvail:
02627 break;
02628
02629
02630 case STATUS_NotOnLink:
02631 break;
02632
02633
02634
02635
02636
02637
02638
02639 case STATUS_UseMulticast:
02640 if (client->active_lease != NULL)
02641 delete_option(&dhcp_universe,
02642 client->active_lease->options,
02643 D6O_UNICAST);
02644 return ISC_FALSE;
02645 }
02646
02647 return ISC_TRUE;
02648 }
02649
02650
02651
02652
02653 static isc_result_t
02654 dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
02655 {
02656 isc_boolean_t (*action)(struct client_state *,
02657 isc_result_t *, unsigned);
02658 struct dhc6_ia *ia;
02659 struct dhc6_addr *addr;
02660 isc_result_t rval = ISC_R_SUCCESS;
02661 unsigned code;
02662 const char *scope;
02663 int nscore, sscore;
02664
02665 if ((client == NULL) || (new == NULL))
02666 return DHCP_R_INVALIDARG;
02667
02668 switch (client->state) {
02669 case S_INIT:
02670 action = dhc6_init_action;
02671 break;
02672
02673 case S_SELECTING:
02674 case S_REBOOTING:
02675 action = dhc6_select_action;
02676 break;
02677
02678 case S_RENEWING:
02679 case S_REBINDING:
02680 action = dhc6_reply_action;
02681 break;
02682
02683 case S_STOPPED:
02684 case S_DECLINED:
02685 action = dhc6_stop_action;
02686 break;
02687
02688 default:
02689 log_fatal("Impossible condition at %s:%d.", MDL);
02690 return ISC_R_CANCELED;
02691 }
02692
02693
02694
02695
02696
02697 rval = dhc6_check_status(rval, new->options, "message", &code);
02698 if (action(client, &rval, code))
02699 return ISC_R_CANCELED;
02700
02701 for (ia = new->bindings ; ia != NULL ; ia = ia->next) {
02702 switch (ia->ia_type) {
02703 case D6O_IA_NA:
02704 scope = "IA_NA";
02705 break;
02706 case D6O_IA_TA:
02707 scope = "IA_TA";
02708 break;
02709 case D6O_IA_PD:
02710 scope = "IA_PD";
02711 break;
02712 default:
02713 log_error("dhc6_check_reply: no type.");
02714 return DHCP_R_INVALIDARG;
02715 }
02716 rval = dhc6_check_status(rval, ia->options,
02717 scope, &code);
02718 if (action(client, &rval, code))
02719 return ISC_R_CANCELED;
02720
02721 for (addr = ia->addrs ; addr != NULL ;
02722 addr = addr->next) {
02723 if (ia->ia_type != D6O_IA_PD)
02724 scope = "IAADDR";
02725 else
02726 scope = "IAPREFIX";
02727 rval = dhc6_check_status(rval, addr->options,
02728 scope, &code);
02729 if (action(client, &rval, code))
02730 return ISC_R_CANCELED;
02731 }
02732 }
02733
02734
02735 if (client->state == S_REBOOTING)
02736 return rval;
02737
02738
02739 if (client->state == S_INIT)
02740 return rval;
02741
02742 switch (client->state) {
02743 case S_SELECTING:
02744
02745
02746
02747 nscore = dhc6_score_lease(client, new);
02748 sscore = dhc6_score_lease(client, client->selected_lease);
02749 if ((client->advertised_leases != NULL) &&
02750 (nscore < (sscore / 2))) {
02751
02752
02753
02754
02755
02756 log_error("PRC: BAIT AND SWITCH detected. Score of "
02757 "supplied lease (%d) is substantially "
02758 "smaller than the advertised score (%d). "
02759 "Trying other servers.",
02760 nscore, sscore);
02761
02762 dhc6_lease_destroy(&client->selected_lease, MDL);
02763 client->selected_lease = NULL;
02764
02765 start_selecting6(client);
02766
02767 return ISC_R_CANCELED;
02768 }
02769 break;
02770
02771 case S_RENEWING:
02772 case S_REBINDING:
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783 break;
02784
02785 case S_STOPPED:
02786 case S_DECLINED:
02787
02788 break;
02789
02790 default:
02791 log_fatal("REALLY impossible condition at %s:%d.", MDL);
02792 return ISC_R_CANCELED;
02793 }
02794
02795 return rval;
02796 }
02797
02798
02799
02800
02801
02802
02803 void
02804 init_handler(struct packet *packet, struct client_state *client)
02805 {
02806 struct dhc6_lease *lease;
02807
02808
02809
02810
02811 if (packet->dhcpv6_msg_type != DHCPV6_ADVERTISE)
02812 return;
02813
02814
02815
02816
02817 if (!valid_reply(packet, client)) {
02818 log_error("Invalid Advertise - rejecting.");
02819 return;
02820 }
02821
02822 lease = dhc6_leaseify(packet);
02823
02824 if (dhc6_check_advertise(lease) != ISC_R_SUCCESS) {
02825 log_debug("PRC: Lease failed to satisfy.");
02826 dhc6_lease_destroy(&lease, MDL);
02827 return;
02828 }
02829
02830 insert_lease(&client->advertised_leases, lease);
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842 if ((client->txcount > 1) ||
02843 ((lease->pref == 255) &&
02844 (dhc6_score_lease(client, lease) > 150))) {
02845 log_debug("RCV: Advertisement immediately selected.");
02846 cancel_timeout(do_init6, client);
02847 start_selecting6(client);
02848 } else
02849 log_debug("RCV: Advertisement recorded.");
02850 }
02851
02852
02853
02854 void
02855 info_request_handler(struct packet *packet, struct client_state *client)
02856 {
02857 isc_result_t check_status;
02858 unsigned code;
02859
02860 if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
02861 return;
02862
02863
02864
02865
02866 if (!valid_reply(packet, client)) {
02867 log_error("Invalid Reply - rejecting.");
02868 return;
02869 }
02870
02871 check_status = dhc6_check_status(ISC_R_SUCCESS, packet->options,
02872 "message", &code);
02873 if (check_status != ISC_R_SUCCESS) {
02874
02875
02876
02877 if (check_status != ISC_R_CANCELED)
02878 return;
02879 }
02880
02881
02882 cancel_timeout(do_info_request6, client);
02883
02884
02885
02886
02887 if (check_status == ISC_R_CANCELED)
02888 return;
02889
02890
02891 if (client->old_lease != NULL) {
02892 dhc6_lease_destroy(&client->old_lease, MDL);
02893 client->old_lease = NULL;
02894 }
02895
02896
02897 if (client->active_lease != NULL)
02898 client->old_lease = client->active_lease;
02899 client->active_lease = dmalloc(sizeof(struct dhc6_lease), MDL);
02900 if (client->active_lease == NULL)
02901 log_fatal("Out of memory for v6 lease structure.");
02902 option_state_reference(&client->active_lease->options,
02903 packet->options, MDL);
02904
02905 start_informed(client);
02906 }
02907
02908
02909
02910 void
02911 rapid_commit_handler(struct packet *packet, struct client_state *client)
02912 {
02913 struct dhc6_lease *lease;
02914 isc_result_t check_status;
02915
02916
02917
02918 if (packet->dhcpv6_msg_type == DHCPV6_ADVERTISE) {
02919 init_handler(packet, client);
02920 return;
02921 } else if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
02922 return;
02923
02924
02925
02926
02927 if (!valid_reply(packet, client)) {
02928 log_error("Invalid Reply - rejecting.");
02929 return;
02930 }
02931
02932
02933 if (lookup_option(&dhcpv6_universe, packet->options,
02934 D6O_RAPID_COMMIT) == 0) {
02935 log_error("Reply without Rapid-Commit - rejecting.");
02936 return;
02937 }
02938
02939 lease = dhc6_leaseify(packet);
02940
02941
02942
02943
02944 if (lease == NULL)
02945 return;
02946
02947 check_status = dhc6_check_reply(client, lease);
02948 if (check_status != ISC_R_SUCCESS) {
02949 dhc6_lease_destroy(&lease, MDL);
02950 return;
02951 }
02952
02953
02954 cancel_timeout(do_init6, client);
02955 client->state = S_SELECTING;
02956
02957
02958
02959
02960 dhc6_merge_lease(client->active_lease, lease);
02961
02962
02963 if (client->old_lease != NULL) {
02964 dhc6_lease_destroy(&client->old_lease, MDL);
02965 client->old_lease = NULL;
02966 }
02967
02968
02969 if (client->active_lease != NULL)
02970 client->old_lease = client->active_lease;
02971 client->active_lease = lease;
02972
02973
02974 while(client->advertised_leases != NULL) {
02975 lease = client->advertised_leases;
02976 client->advertised_leases = lease->next;
02977
02978 dhc6_lease_destroy(&lease, MDL);
02979 }
02980
02981 start_bound(client);
02982 }
02983
02984
02985
02986
02987
02988
02989
02990
02991
02992
02993
02994
02995
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013 static struct dhc6_lease *
03014 dhc6_best_lease(struct client_state *client, struct dhc6_lease **head)
03015 {
03016 struct dhc6_lease **rpos, *rval, **candp, *cand;
03017 int cscore, rscore;
03018
03019 if (head == NULL || *head == NULL)
03020 return NULL;
03021
03022 rpos = head;
03023 rval = *rpos;
03024 rscore = dhc6_score_lease(client, rval);
03025 candp = &rval->next;
03026 cand = *candp;
03027
03028 log_debug("PRC: Considering best lease.");
03029 log_debug("PRC: X-- Initial candidate %s (s: %d, p: %u).",
03030 print_hex_1(rval->server_id.len,
03031 rval->server_id.data, 48),
03032 rscore, (unsigned)rval->pref);
03033
03034 for (; cand != NULL ; candp = &cand->next, cand = *candp) {
03035 cscore = dhc6_score_lease(client, cand);
03036
03037 log_debug("PRC: X-- Candidate %s (s: %d, p: %u).",
03038 print_hex_1(cand->server_id.len,
03039 cand->server_id.data, 48),
03040 cscore, (unsigned)cand->pref);
03041
03042
03043
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053
03054
03055
03056
03057
03058
03059
03060
03061
03062
03063
03064 if ((rscore < 150) && (cscore >= 150)) {
03065 log_debug("PRC: | X-- Selected, has bindings.");
03066 } else if (cand->pref < rval->pref) {
03067 log_debug("PRC: | X-- Rejected, lower preference.");
03068 continue;
03069 } else if (cand->pref > rval->pref) {
03070 log_debug("PRC: | X-- Selected, higher preference.");
03071 } else if (cscore > rscore) {
03072 log_debug("PRC: | X-- Selected, equal preference, "
03073 "higher score.");
03074 } else if (cscore < rscore) {
03075 log_debug("PRC: | X-- Rejected, equal preference, "
03076 "lower score.");
03077 continue;
03078 } else if ((cand->server_id.len < rval->server_id.len) ||
03079 ((cand->server_id.len == rval->server_id.len) &&
03080 (memcmp(cand->server_id.data,
03081 rval->server_id.data,
03082 cand->server_id.len) < 0))) {
03083 log_debug("PRC: | X-- Selected, equal preference, "
03084 "equal score, binary lesser server ID.");
03085 } else {
03086 log_debug("PRC: | X-- Rejected, equal preference, "
03087 "equal score, binary greater server ID.");
03088 continue;
03089 }
03090
03091 rpos = candp;
03092 rval = cand;
03093 rscore = cscore;
03094 }
03095
03096
03097 *rpos = rval->next;
03098
03099 return rval;
03100 }
03101
03102
03103
03104
03105 void
03106 start_selecting6(struct client_state *client)
03107 {
03108 struct dhc6_lease *lease;
03109
03110 if (client->advertised_leases == NULL) {
03111 log_error("Can not enter DHCPv6 SELECTING state with no "
03112 "leases to select from!");
03113 return;
03114 }
03115
03116 log_debug("PRC: Selecting best advertised lease.");
03117 client->state = S_SELECTING;
03118
03119 lease = dhc6_best_lease(client, &client->advertised_leases);
03120
03121 if (lease == NULL)
03122 log_fatal("Impossible error at %s:%d.", MDL);
03123
03124 client->selected_lease = lease;
03125
03126
03127 client->IRT = REQ_TIMEOUT * 100;
03128 client->MRT = REQ_MAX_RT * 100;
03129 client->MRC = REQ_MAX_RC;
03130 client->MRD = 0;
03131
03132 dhc6_retrans_init(client);
03133
03134 client->v6_handler = reply_handler;
03135
03136
03137 do_select6(client);
03138 }
03139
03140
03141
03142
03143
03144 void
03145 do_select6(void *input)
03146 {
03147 struct client_state *client;
03148 struct dhc6_lease *lease;
03149 struct data_string ds;
03150 struct timeval tv;
03151 int send_ret;
03152
03153 client = input;
03154
03155
03156 lease = client->selected_lease;
03157 if (lease == NULL || lease->bindings == NULL) {
03158 log_error("Illegal to attempt selection without selecting "
03159 "a lease.");
03160 return;
03161 }
03162
03163 switch(check_timing6(client, DHCPV6_REQUEST, "Request", lease, &ds)) {
03164 case CHK_TIM_MRC_EXCEEDED:
03165 case CHK_TIM_MRD_EXCEEDED:
03166 log_debug("PRC: Lease %s failed.",
03167 print_hex_1(lease->server_id.len,
03168 lease->server_id.data, 56));
03169
03170
03171 dhc6_lease_destroy(&lease, MDL);
03172 client->selected_lease = NULL;
03173
03174
03175 if (client->advertised_leases != NULL)
03176 start_selecting6(client);
03177 else
03178 start_init6(client);
03179 return;
03180 case CHK_TIM_ALLOC_FAILURE:
03181 return;
03182 case CHK_TIM_SUCCESS:
03183 break;
03184 }
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
03200 NULL, client->sent_options, &global_scope,
03201 &dhcpv6_universe);
03202
03203
03204 if (wanted_ia_na &&
03205 dhc6_add_ia_na(client, &ds, lease,
03206 DHCPV6_REQUEST) != ISC_R_SUCCESS) {
03207 data_string_forget(&ds, MDL);
03208 return;
03209 }
03210 if (wanted_ia_ta &&
03211 dhc6_add_ia_ta(client, &ds, lease,
03212 DHCPV6_REQUEST) != ISC_R_SUCCESS) {
03213 data_string_forget(&ds, MDL);
03214 return;
03215 }
03216 if (wanted_ia_pd &&
03217 dhc6_add_ia_pd(client, &ds, lease,
03218 DHCPV6_REQUEST) != ISC_R_SUCCESS) {
03219 data_string_forget(&ds, MDL);
03220 return;
03221 }
03222
03223 log_info("XMT: Request on %s, interval %ld0ms.",
03224 client->name ? client->name : client->interface->name,
03225 (long int)client->RT);
03226
03227 send_ret = send_packet6(client->interface,
03228 ds.data, ds.len, &DHCPv6DestAddr);
03229 if (send_ret != ds.len) {
03230 log_error("dhc6: send_packet6() sent %d of %d bytes",
03231 send_ret, ds.len);
03232 }
03233
03234 data_string_forget(&ds, MDL);
03235
03236
03237 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
03238 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
03239 if (tv.tv_usec >= 1000000) {
03240 tv.tv_sec += 1;
03241 tv.tv_usec -= 1000000;
03242 }
03243 add_timeout(&tv, do_select6, client, NULL, NULL);
03244
03245 dhc6_retrans_advance(client);
03246 }
03247
03248
03249
03250
03251 static isc_result_t
03252 dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
03253 struct dhc6_lease *lease, u_int8_t message)
03254 {
03255 struct data_string iads;
03256 struct data_string addrds;
03257 struct dhc6_addr *addr;
03258 struct dhc6_ia *ia;
03259 isc_result_t rval = ISC_R_SUCCESS;
03260 TIME t1, t2;
03261
03262 memset(&iads, 0, sizeof(iads));
03263 memset(&addrds, 0, sizeof(addrds));
03264 for (ia = lease->bindings;
03265 ia != NULL && rval == ISC_R_SUCCESS;
03266 ia = ia->next) {
03267 if (ia->ia_type != D6O_IA_NA)
03268 continue;
03269
03270 if (!buffer_allocate(&iads.buffer, 12, MDL)) {
03271 log_error("Unable to allocate memory for IA_NA.");
03272 rval = ISC_R_NOMEMORY;
03273 break;
03274 }
03275
03276
03277 memcpy(iads.buffer->data, ia->iaid, 4);
03278 iads.data = iads.buffer->data;
03279 iads.len = 12;
03280
03281 switch (message) {
03282 case DHCPV6_REQUEST:
03283 case DHCPV6_RENEW:
03284 case DHCPV6_REBIND:
03285
03286 t1 = client->config->requested_lease / 2;
03287 t2 = t1 + (t1 / 2);
03288 #if MAX_TIME > 0xffffffff
03289 if (t1 > 0xffffffff)
03290 t1 = 0xffffffff;
03291 if (t2 > 0xffffffff)
03292 t2 = 0xffffffff;
03293 #endif
03294 putULong(iads.buffer->data + 4, t1);
03295 putULong(iads.buffer->data + 8, t2);
03296
03297 log_debug("XMT: X-- IA_NA %s",
03298 print_hex_1(4, iads.data, 59));
03299 log_debug("XMT: | X-- Requested renew +%u",
03300 (unsigned) t1);
03301 log_debug("XMT: | X-- Requested rebind +%u",
03302 (unsigned) t2);
03303 break;
03304
03305 case DHCPV6_CONFIRM:
03306 case DHCPV6_RELEASE:
03307 case DHCPV6_DECLINE:
03308
03309 memset(iads.buffer->data + 4, 0, 8);
03310 log_debug("XMT: X-- IA_NA %s",
03311 print_hex_1(4, iads.buffer->data, 55));
03312
03313 break;
03314
03315 default:
03316 log_fatal("Impossible condition at %s:%d.", MDL);
03317 }
03318
03319 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
03320
03321
03322
03323
03324
03325 if (addr->flags & DHC6_ADDR_EXPIRED)
03326 continue;
03327
03328 if (addr->address.len != 16) {
03329 log_error("Illegal IPv6 address length (%d), "
03330 "ignoring. (%s:%d)",
03331 addr->address.len, MDL);
03332 continue;
03333 }
03334
03335 if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
03336 log_error("Unable to allocate memory for "
03337 "IAADDR.");
03338 rval = ISC_R_NOMEMORY;
03339 break;
03340 }
03341
03342 addrds.data = addrds.buffer->data;
03343 addrds.len = 24;
03344
03345
03346 memcpy(addrds.buffer->data, addr->address.iabuf, 16);
03347
03348
03349 switch (message) {
03350 case DHCPV6_REQUEST:
03351 case DHCPV6_RENEW:
03352 case DHCPV6_REBIND:
03353 t1 = client->config->requested_lease;
03354 t2 = t1 + 300;
03355 putULong(addrds.buffer->data + 16, t1);
03356 putULong(addrds.buffer->data + 20, t2);
03357
03358 log_debug("XMT: | | X-- IAADDR %s",
03359 piaddr(addr->address));
03360 log_debug("XMT: | | | X-- Preferred "
03361 "lifetime +%u", (unsigned)t1);
03362 log_debug("XMT: | | | X-- Max lifetime +%u",
03363 (unsigned)t2);
03364
03365 break;
03366
03367 case DHCPV6_CONFIRM:
03368
03369
03370
03371
03372 memset(addrds.buffer->data + 16, 0, 8);
03373 log_debug("XMT: | X-- Confirm Address %s",
03374 piaddr(addr->address));
03375 break;
03376
03377 case DHCPV6_RELEASE:
03378
03379 memset(addrds.buffer->data + 16, 0, 8);
03380 log_debug("XMT: | X-- Release Address %s",
03381 piaddr(addr->address));
03382 break;
03383
03384 case DHCPV6_DECLINE:
03385
03386 memset(addrds.buffer->data + 16, 0, 8);
03387 log_debug("XMT: | X-- Decline Address %s",
03388 piaddr(addr->address));
03389 break;
03390
03391 default:
03392 log_fatal("Impossible condition at %s:%d.",
03393 MDL);
03394 }
03395
03396 append_option(&iads, &dhcpv6_universe, iaaddr_option,
03397 &addrds);
03398 data_string_forget(&addrds, MDL);
03399 }
03400
03401
03402
03403
03404
03405 if (ia->addrs == NULL) {
03406 log_debug("!!!: V IA_NA has no IAADDRs - removed.");
03407 rval = ISC_R_FAILURE;
03408 } else if (rval == ISC_R_SUCCESS) {
03409 log_debug("XMT: V IA_NA appended.");
03410 append_option(packet, &dhcpv6_universe, ia_na_option,
03411 &iads);
03412 }
03413
03414 data_string_forget(&iads, MDL);
03415 }
03416
03417 return rval;
03418 }
03419
03420
03421
03422
03423 static isc_result_t
03424 dhc6_add_ia_ta(struct client_state *client, struct data_string *packet,
03425 struct dhc6_lease *lease, u_int8_t message)
03426 {
03427 struct data_string iads;
03428 struct data_string addrds;
03429 struct dhc6_addr *addr;
03430 struct dhc6_ia *ia;
03431 isc_result_t rval = ISC_R_SUCCESS;
03432 TIME t1, t2;
03433
03434 memset(&iads, 0, sizeof(iads));
03435 memset(&addrds, 0, sizeof(addrds));
03436 for (ia = lease->bindings;
03437 ia != NULL && rval == ISC_R_SUCCESS;
03438 ia = ia->next) {
03439 if (ia->ia_type != D6O_IA_TA)
03440 continue;
03441
03442 if (!buffer_allocate(&iads.buffer, 4, MDL)) {
03443 log_error("Unable to allocate memory for IA_TA.");
03444 rval = ISC_R_NOMEMORY;
03445 break;
03446 }
03447
03448
03449 memcpy(iads.buffer->data, ia->iaid, 4);
03450 iads.data = iads.buffer->data;
03451 iads.len = 4;
03452
03453 log_debug("XMT: X-- IA_TA %s",
03454 print_hex_1(4, iads.buffer->data, 55));
03455
03456 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
03457
03458
03459
03460
03461
03462 if (addr->flags & DHC6_ADDR_EXPIRED)
03463 continue;
03464
03465 if (addr->address.len != 16) {
03466 log_error("Illegal IPv6 address length (%d), "
03467 "ignoring. (%s:%d)",
03468 addr->address.len, MDL);
03469 continue;
03470 }
03471
03472 if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
03473 log_error("Unable to allocate memory for "
03474 "IAADDR.");
03475 rval = ISC_R_NOMEMORY;
03476 break;
03477 }
03478
03479 addrds.data = addrds.buffer->data;
03480 addrds.len = 24;
03481
03482
03483 memcpy(addrds.buffer->data, addr->address.iabuf, 16);
03484
03485
03486 switch (message) {
03487 case DHCPV6_REQUEST:
03488 case DHCPV6_RENEW:
03489 case DHCPV6_REBIND:
03490 t1 = client->config->requested_lease;
03491 t2 = t1 + 300;
03492 putULong(addrds.buffer->data + 16, t1);
03493 putULong(addrds.buffer->data + 20, t2);
03494
03495 log_debug("XMT: | | X-- IAADDR %s",
03496 piaddr(addr->address));
03497 log_debug("XMT: | | | X-- Preferred "
03498 "lifetime +%u", (unsigned)t1);
03499 log_debug("XMT: | | | X-- Max lifetime +%u",
03500 (unsigned)t2);
03501
03502 break;
03503
03504 case DHCPV6_CONFIRM:
03505
03506
03507
03508
03509 memset(addrds.buffer->data + 16, 0, 8);
03510 log_debug("XMT: | X-- Confirm Address %s",
03511 piaddr(addr->address));
03512 break;
03513
03514 case DHCPV6_RELEASE:
03515
03516 memset(addrds.buffer->data + 16, 0, 8);
03517 log_debug("XMT: | X-- Release Address %s",
03518 piaddr(addr->address));
03519 break;
03520
03521 default:
03522 log_fatal("Impossible condition at %s:%d.",
03523 MDL);
03524 }
03525
03526 append_option(&iads, &dhcpv6_universe, iaaddr_option,
03527 &addrds);
03528 data_string_forget(&addrds, MDL);
03529 }
03530
03531
03532
03533
03534
03535 if (ia->addrs == NULL) {
03536 log_debug("!!!: V IA_TA has no IAADDRs - removed.");
03537 rval = ISC_R_FAILURE;
03538 } else if (rval == ISC_R_SUCCESS) {
03539 log_debug("XMT: V IA_TA appended.");
03540 append_option(packet, &dhcpv6_universe, ia_ta_option,
03541 &iads);
03542 }
03543
03544 data_string_forget(&iads, MDL);
03545 }
03546
03547 return rval;
03548 }
03549
03550
03551
03552
03553 static isc_result_t
03554 dhc6_add_ia_pd(struct client_state *client, struct data_string *packet,
03555 struct dhc6_lease *lease, u_int8_t message)
03556 {
03557 struct data_string iads;
03558 struct data_string prefds;
03559 struct dhc6_addr *pref;
03560 struct dhc6_ia *ia;
03561 isc_result_t rval = ISC_R_SUCCESS;
03562 TIME t1, t2;
03563
03564 memset(&iads, 0, sizeof(iads));
03565 memset(&prefds, 0, sizeof(prefds));
03566 for (ia = lease->bindings;
03567 ia != NULL && rval == ISC_R_SUCCESS;
03568 ia = ia->next) {
03569 if (ia->ia_type != D6O_IA_PD)
03570 continue;
03571
03572 if (!buffer_allocate(&iads.buffer, 12, MDL)) {
03573 log_error("Unable to allocate memory for IA_PD.");
03574 rval = ISC_R_NOMEMORY;
03575 break;
03576 }
03577
03578
03579 memcpy(iads.buffer->data, ia->iaid, 4);
03580 iads.data = iads.buffer->data;
03581 iads.len = 12;
03582
03583 switch (message) {
03584 case DHCPV6_REQUEST:
03585 case DHCPV6_RENEW:
03586 case DHCPV6_REBIND:
03587
03588 t1 = client->config->requested_lease / 2;
03589 t2 = t1 + (t1 / 2);
03590 #if MAX_TIME > 0xffffffff
03591 if (t1 > 0xffffffff)
03592 t1 = 0xffffffff;
03593 if (t2 > 0xffffffff)
03594 t2 = 0xffffffff;
03595 #endif
03596 putULong(iads.buffer->data + 4, t1);
03597 putULong(iads.buffer->data + 8, t2);
03598
03599 log_debug("XMT: X-- IA_PD %s",
03600 print_hex_1(4, iads.data, 59));
03601 log_debug("XMT: | X-- Requested renew +%u",
03602 (unsigned) t1);
03603 log_debug("XMT: | X-- Requested rebind +%u",
03604 (unsigned) t2);
03605 break;
03606
03607 case DHCPV6_RELEASE:
03608
03609 memset(iads.buffer->data + 4, 0, 8);
03610 log_debug("XMT: X-- IA_PD %s",
03611 print_hex_1(4, iads.buffer->data, 55));
03612
03613 break;
03614
03615 default:
03616 log_fatal("Impossible condition at %s:%d.", MDL);
03617 }
03618
03619 for (pref = ia->addrs ; pref != NULL ; pref = pref->next) {
03620
03621
03622
03623
03624
03625 if (pref->flags & DHC6_ADDR_EXPIRED)
03626 continue;
03627
03628 if (pref->address.len != 16) {
03629 log_error("Illegal IPv6 prefix "
03630 "ignoring. (%s:%d)",
03631 MDL);
03632 continue;
03633 }
03634
03635 if (pref->plen == 0) {
03636 log_info("Null IPv6 prefix, "
03637 "ignoring. (%s:%d)",
03638 MDL);
03639 }
03640
03641 if (!buffer_allocate(&prefds.buffer, 25, MDL)) {
03642 log_error("Unable to allocate memory for "
03643 "IAPREFIX.");
03644 rval = ISC_R_NOMEMORY;
03645 break;
03646 }
03647
03648 prefds.data = prefds.buffer->data;
03649 prefds.len = 25;
03650
03651
03652 putUChar(prefds.buffer->data + 8, pref->plen);
03653 memcpy(prefds.buffer->data + 9,
03654 pref->address.iabuf,
03655 16);
03656
03657
03658 switch (message) {
03659 case DHCPV6_REQUEST:
03660 case DHCPV6_RENEW:
03661 case DHCPV6_REBIND:
03662 t1 = client->config->requested_lease;
03663 t2 = t1 + 300;
03664 putULong(prefds.buffer->data, t1);
03665 putULong(prefds.buffer->data + 4, t2);
03666
03667 log_debug("XMT: | | X-- IAPREFIX %s/%u",
03668 piaddr(pref->address),
03669 (unsigned) pref->plen);
03670 log_debug("XMT: | | | X-- Preferred "
03671 "lifetime +%u", (unsigned)t1);
03672 log_debug("XMT: | | | X-- Max lifetime +%u",
03673 (unsigned)t2);
03674
03675 break;
03676
03677 case DHCPV6_RELEASE:
03678
03679 memset(prefds.buffer->data, 0, 8);
03680 log_debug("XMT: | X-- Release Prefix %s/%u",
03681 piaddr(pref->address),
03682 (unsigned) pref->plen);
03683 break;
03684
03685 default:
03686 log_fatal("Impossible condition at %s:%d.",
03687 MDL);
03688 }
03689
03690 append_option(&iads, &dhcpv6_universe,
03691 iaprefix_option, &prefds);
03692 data_string_forget(&prefds, MDL);
03693 }
03694
03695
03696
03697
03698
03699 if (ia->addrs == NULL) {
03700 log_debug("!!!: V IA_PD has no IAPREFIXs - removed.");
03701 rval = ISC_R_FAILURE;
03702 } else if (rval == ISC_R_SUCCESS) {
03703 log_debug("XMT: V IA_PD appended.");
03704 append_option(packet, &dhcpv6_universe,
03705 ia_pd_option, &iads);
03706 }
03707
03708 data_string_forget(&iads, MDL);
03709 }
03710
03711 return rval;
03712 }
03713
03714
03715
03716 static isc_boolean_t
03717 stopping_finished(void)
03718 {
03719 struct interface_info *ip;
03720 struct client_state *client;
03721
03722 for (ip = interfaces; ip; ip = ip -> next) {
03723 for (client = ip -> client; client; client = client -> next) {
03724 if (client->state != S_STOPPED)
03725 return ISC_FALSE;
03726 if (client->active_lease != NULL)
03727 return ISC_FALSE;
03728 }
03729 }
03730 return ISC_TRUE;
03731 }
03732
03733
03734
03735
03736 void
03737 reply_handler(struct packet *packet, struct client_state *client)
03738 {
03739 struct dhc6_lease *lease;
03740 isc_result_t check_status;
03741
03742 if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
03743 return;
03744
03745
03746
03747
03748 if (!valid_reply(packet, client)) {
03749 log_error("Invalid Reply - rejecting.");
03750 return;
03751 }
03752
03753 lease = dhc6_leaseify(packet);
03754
03755
03756
03757
03758 if (lease == NULL)
03759 return;
03760
03761 check_status = dhc6_check_reply(client, lease);
03762 if (check_status != ISC_R_SUCCESS) {
03763 dhc6_lease_destroy(&lease, MDL);
03764
03765
03766
03767
03768 if (check_status != ISC_R_CANCELED)
03769 return;
03770 }
03771
03772
03773 cancel_timeout(do_confirm6, client);
03774 cancel_timeout(do_select6, client);
03775 cancel_timeout(do_refresh6, client);
03776 cancel_timeout(do_release6, client);
03777 cancel_timeout(do_decline6, client);
03778
03779
03780 if ((client->state == S_STOPPED) ||
03781 (client->state == S_DECLINED)) {
03782
03783 if (client->active_lease != NULL) {
03784 dhc6_lease_destroy(&client->active_lease, MDL);
03785 client->active_lease = NULL;
03786
03787 if (stopping_finished())
03788 exit(0);
03789 }
03790
03791 if (client->state == S_DECLINED)
03792 start_init6(client);
03793
03794 return;
03795 }
03796
03797
03798
03799
03800 if (check_status == ISC_R_CANCELED)
03801 return;
03802
03803 if (client->selected_lease != NULL) {
03804 dhc6_lease_destroy(&client->selected_lease, MDL);
03805 client->selected_lease = NULL;
03806 }
03807
03808
03809
03810
03811 if (client->state == S_REBOOTING) {
03812 if (client->active_lease == NULL)
03813 log_fatal("Impossible condition at %s:%d.", MDL);
03814
03815 dhc6_lease_destroy(&lease, MDL);
03816 start_bound(client);
03817 return;
03818 }
03819
03820
03821
03822
03823 dhc6_merge_lease(client->active_lease, lease);
03824
03825
03826 if (client->old_lease != NULL) {
03827 dhc6_lease_destroy(&client->old_lease, MDL);
03828 client->old_lease = NULL;
03829 }
03830
03831
03832 if (client->active_lease != NULL)
03833 client->old_lease = client->active_lease;
03834 client->active_lease = lease;
03835
03836
03837 while(client->advertised_leases != NULL) {
03838 lease = client->advertised_leases;
03839 client->advertised_leases = lease->next;
03840
03841 dhc6_lease_destroy(&lease, MDL);
03842 }
03843
03844 start_bound(client);
03845 }
03846
03847
03848
03849
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859
03860 static void
03861 dhc6_marshall_values(const char *prefix, struct client_state *client,
03862 struct dhc6_lease *lease, struct dhc6_ia *ia,
03863 struct dhc6_addr *addr)
03864 {
03865
03866
03867
03868 if ((lease != NULL) && (lease->options != NULL))
03869 script_write_params6(client, prefix, lease->options);
03870 if ((ia != NULL) && (ia->options != NULL))
03871 script_write_params6(client, prefix, ia->options);
03872 if ((addr != NULL) && (addr->options != NULL))
03873 script_write_params6(client, prefix, addr->options);
03874
03875
03876 if (addr != NULL) {
03877 if ((ia != NULL) && (ia->ia_type == D6O_IA_PD)) {
03878 client_envadd(client, prefix,
03879 "ip6_prefix", "%s/%u",
03880 piaddr(addr->address),
03881 (unsigned) addr->plen);
03882 } else {
03883
03884
03885
03886 client_envadd(client, prefix, "ip6_prefixlen",
03887 "%d", 64);
03888 client_envadd(client, prefix, "ip6_address",
03889 "%s", piaddr(addr->address));
03890 }
03891 if ((ia != NULL) && (ia->ia_type == D6O_IA_TA)) {
03892 client_envadd(client, prefix,
03893 "ip6_type", "temporary");
03894 }
03895 client_envadd(client, prefix, "life_starts", "%d",
03896 (int)(addr->starts));
03897 client_envadd(client, prefix, "preferred_life", "%d",
03898 (int)(addr->preferred_life));
03899 client_envadd(client, prefix, "max_life", "%d",
03900 (int)(addr->max_life));
03901 }
03902
03903
03904 if (ia != NULL) {
03905 client_envadd(client, prefix, "iaid", "%s",
03906 print_hex_1(4, ia->iaid, 12));
03907 client_envadd(client, prefix, "starts", "%d",
03908 (int)(ia->starts));
03909 client_envadd(client, prefix, "renew", "%u", ia->renew);
03910 client_envadd(client, prefix, "rebind", "%u", ia->rebind);
03911 }
03912 }
03913
03914
03915
03916
03917 static void
03918 dhc6_check_times(struct client_state *client)
03919 {
03920 struct dhc6_lease *lease;
03921 struct dhc6_ia *ia;
03922 struct dhc6_addr *addr;
03923 TIME renew=MAX_TIME, rebind=MAX_TIME, depref=MAX_TIME,
03924 lo_expire=MAX_TIME, hi_expire=0, tmp;
03925 int has_addrs = ISC_FALSE;
03926 struct timeval tv;
03927
03928 lease = client->active_lease;
03929
03930
03931
03932
03933 cancel_timeout(start_renew6, client);
03934 cancel_timeout(start_rebind6, client);
03935 cancel_timeout(do_depref, client);
03936 cancel_timeout(do_expire, client);
03937
03938 for(ia = lease->bindings ; ia != NULL ; ia = ia->next) {
03939 TIME this_ia_lo_expire, this_ia_hi_expire, use_expire;
03940
03941 this_ia_lo_expire = MAX_TIME;
03942 this_ia_hi_expire = 0;
03943
03944 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
03945 if(!(addr->flags & DHC6_ADDR_DEPREFFED)) {
03946 if (addr->preferred_life == 0xffffffff)
03947 tmp = MAX_TIME;
03948 else
03949 tmp = addr->starts +
03950 addr->preferred_life;
03951
03952 if (tmp < depref)
03953 depref = tmp;
03954 }
03955
03956 if (!(addr->flags & DHC6_ADDR_EXPIRED)) {
03957
03958 if (addr->max_life == 0xffffffff)
03959 tmp = MAX_TIME;
03960 else
03961 tmp = addr->starts + addr->max_life;
03962
03963
03964 tmp -= ia->starts;
03965
03966 if (tmp > this_ia_hi_expire)
03967 this_ia_hi_expire = tmp;
03968 if (tmp < this_ia_lo_expire)
03969 this_ia_lo_expire = tmp;
03970
03971 has_addrs = ISC_TRUE;
03972 }
03973 }
03974
03975
03976 if (this_ia_lo_expire <= (this_ia_hi_expire / 2))
03977 use_expire = this_ia_hi_expire;
03978 else
03979 use_expire = this_ia_lo_expire;
03980
03981
03982
03983
03984
03985 if ((use_expire == MAX_TIME) || (use_expire <= 1))
03986 use_expire = client->config->requested_lease / 2;
03987 else
03988 use_expire /= 2;
03989
03990
03991 if (ia->ia_type != D6O_IA_TA) {
03992
03993 if (ia->renew == 0) {
03994 tmp = ia->starts + use_expire;
03995 } else if (ia->renew == 0xffffffff)
03996 tmp = MAX_TIME;
03997 else
03998 tmp = ia->starts + ia->renew;
03999
04000 if (tmp < renew)
04001 renew = tmp;
04002
04003 if (ia->rebind == 0) {
04004
04005 tmp = ia->starts;
04006 tmp += use_expire + (use_expire / 2);
04007 } else if (ia->rebind == 0xffffffff)
04008 tmp = MAX_TIME;
04009 else
04010 tmp = ia->starts + ia->rebind;
04011
04012 if (tmp < rebind)
04013 rebind = tmp;
04014 }
04015
04016
04017
04018
04019
04020 this_ia_hi_expire += ia->starts;
04021 this_ia_lo_expire += ia->starts;
04022
04023 if (this_ia_hi_expire > hi_expire)
04024 hi_expire = this_ia_hi_expire;
04025 if (this_ia_lo_expire < lo_expire)
04026 lo_expire = this_ia_lo_expire;
04027 }
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038 if (has_addrs == ISC_FALSE) {
04039 dhc6_lease_destroy(&client->active_lease, MDL);
04040 client->active_lease = NULL;
04041
04042
04043 start_init6(client);
04044 return;
04045 }
04046
04047 switch(client->state) {
04048 case S_BOUND:
04049
04050
04051
04052 if ((rebind > cur_time) && (renew < rebind)) {
04053 log_debug("PRC: Renewal event scheduled in %d seconds, "
04054 "to run for %u seconds.",
04055 (int)(renew - cur_time),
04056 (unsigned)(rebind - renew));
04057 client->next_MRD = rebind;
04058 tv.tv_sec = renew;
04059 tv.tv_usec = 0;
04060 add_timeout(&tv, start_renew6, client, NULL, NULL);
04061
04062 break;
04063 }
04064
04065 case S_RENEWING:
04066
04067
04068
04069
04070 client->MRD = rebind - cur_time;
04071 if (rebind != MAX_TIME) {
04072 log_debug("PRC: Rebind event scheduled in %d seconds, "
04073 "to run for %d seconds.",
04074 (int)(rebind - cur_time),
04075 (int)(hi_expire - rebind));
04076 client->next_MRD = hi_expire;
04077 tv.tv_sec = rebind;
04078 tv.tv_usec = 0;
04079 add_timeout(&tv, start_rebind6, client, NULL, NULL);
04080 }
04081 break;
04082
04083 case S_REBINDING:
04084
04085
04086
04087
04088 client->MRD = hi_expire - cur_time;
04089 break;
04090
04091 default:
04092 log_fatal("Impossible condition at %s:%d.", MDL);
04093 }
04094
04095
04096
04097
04098
04099 if (depref != MAX_TIME) {
04100 log_debug("PRC: Depreference scheduled in %d seconds.",
04101 (int)(depref - cur_time));
04102 tv.tv_sec = depref;
04103 tv.tv_usec = 0;
04104 add_timeout(&tv, do_depref, client, NULL, NULL);
04105 }
04106 if (lo_expire != MAX_TIME) {
04107 log_debug("PRC: Expiration scheduled in %d seconds.",
04108 (int)(lo_expire - cur_time));
04109 tv.tv_sec = lo_expire;
04110 tv.tv_usec = 0;
04111 add_timeout(&tv, do_expire, client, NULL, NULL);
04112 }
04113 }
04114
04115
04116 static struct dhc6_ia *
04117 find_ia(struct dhc6_ia *head, u_int16_t type, const char *id)
04118 {
04119 struct dhc6_ia *ia;
04120
04121 for (ia = head ; ia != NULL ; ia = ia->next) {
04122 if (ia->ia_type != type)
04123 continue;
04124 if (memcmp(ia->iaid, id, 4) == 0)
04125 return ia;
04126 }
04127
04128 return NULL;
04129 }
04130
04131
04132 static struct dhc6_addr *
04133 find_addr(struct dhc6_addr *head, struct iaddr *address)
04134 {
04135 struct dhc6_addr *addr;
04136
04137 for (addr = head ; addr != NULL ; addr = addr->next) {
04138 if ((addr->address.len == address->len) &&
04139 (memcmp(addr->address.iabuf, address->iabuf,
04140 address->len) == 0))
04141 return addr;
04142 }
04143
04144 return NULL;
04145 }
04146
04147
04148 static struct dhc6_addr *
04149 find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen)
04150 {
04151 struct dhc6_addr *pref;
04152
04153 for (pref = head ; pref != NULL ; pref = pref->next) {
04154 if ((pref->address.len == prefix->len) &&
04155 (pref->plen == plen) &&
04156 (memcmp(pref->address.iabuf, prefix->iabuf,
04157 prefix->len) == 0))
04158 return pref;
04159 }
04160
04161 return NULL;
04162 }
04163
04164
04165
04166
04167
04168
04169 static void
04170 dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
04171 {
04172 struct dhc6_ia *sia, *dia, *tia;
04173 struct dhc6_addr *saddr, *daddr, *taddr;
04174 int changes = 0;
04175
04176 if ((dst == NULL) || (src == NULL))
04177 return;
04178
04179 for (sia = src->bindings ; sia != NULL ; sia = sia->next) {
04180 dia = find_ia(dst->bindings, sia->ia_type, (char *)sia->iaid);
04181
04182 if (dia == NULL) {
04183 tia = dhc6_dup_ia(sia, MDL);
04184
04185 if (tia == NULL)
04186 log_fatal("Out of memory merging lease - "
04187 "Unable to continue without losing "
04188 "state! (%s:%d)", MDL);
04189
04190
04191 tia->next = dst->bindings;
04192 dst->bindings = tia;
04193 changes = 1;
04194 } else {
04195 for (saddr = sia->addrs ; saddr != NULL ;
04196 saddr = saddr->next) {
04197 if (sia->ia_type != D6O_IA_PD)
04198 daddr = find_addr(dia->addrs,
04199 &saddr->address);
04200 else
04201 daddr = find_pref(dia->addrs,
04202 &saddr->address,
04203 saddr->plen);
04204
04205 if (daddr == NULL) {
04206 taddr = dhc6_dup_addr(saddr, MDL);
04207
04208 if (taddr == NULL)
04209 log_fatal("Out of memory "
04210 "merging lease - "
04211 "Unable to continue "
04212 "without losing "
04213 "state! (%s:%d)",
04214 MDL);
04215
04216
04217 taddr->next = dia->addrs;
04218 dia->addrs = taddr;
04219 changes = 1;
04220 }
04221 }
04222 }
04223 }
04224
04225
04226 if (changes)
04227 dst->score = 0;
04228 }
04229
04230
04231
04232
04233
04234
04235 static void
04236 start_bound(struct client_state *client)
04237 {
04238 struct dhc6_ia *ia, *oldia;
04239 struct dhc6_addr *addr, *oldaddr;
04240 struct dhc6_lease *lease, *old;
04241 const char *reason;
04242 #if defined (NSUPDATE)
04243 TIME dns_update_offset = 1;
04244 #endif
04245
04246 lease = client->active_lease;
04247 if (lease == NULL) {
04248 log_error("Cannot enter bound state unless an active lease "
04249 "is selected.");
04250 return;
04251 }
04252 lease->released = ISC_FALSE;
04253 old = client->old_lease;
04254
04255 client->v6_handler = bound_handler;
04256
04257 switch (client->state) {
04258 case S_SELECTING:
04259 case S_REBOOTING:
04260 reason = "BOUND6";
04261 break;
04262
04263 case S_RENEWING:
04264 reason = "RENEW6";
04265 break;
04266
04267 case S_REBINDING:
04268 reason = "REBIND6";
04269 break;
04270
04271 default:
04272 log_fatal("Impossible condition at %s:%d.", MDL);
04273
04274 return;
04275 }
04276
04277 log_debug("PRC: Bound to lease %s.",
04278 print_hex_1(client->active_lease->server_id.len,
04279 client->active_lease->server_id.data, 55));
04280 client->state = S_BOUND;
04281
04282 write_client6_lease(client, lease, 0, 1);
04283
04284 oldia = NULL;
04285 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
04286 if (old != NULL)
04287 oldia = find_ia(old->bindings,
04288 ia->ia_type,
04289 (char *)ia->iaid);
04290 else
04291 oldia = NULL;
04292
04293 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
04294 if (oldia != NULL) {
04295 if (ia->ia_type != D6O_IA_PD)
04296 oldaddr = find_addr(oldia->addrs,
04297 &addr->address);
04298 else
04299 oldaddr = find_pref(oldia->addrs,
04300 &addr->address,
04301 addr->plen);
04302 } else
04303 oldaddr = NULL;
04304
04305 #if defined (NSUPDATE)
04306 if ((oldaddr == NULL) && (ia->ia_type == D6O_IA_NA))
04307 dhclient_schedule_updates(client,
04308 &addr->address,
04309 dns_update_offset++);
04310 #endif
04311
04312
04313 script_init(client, reason, NULL);
04314
04315 if (old != NULL)
04316 dhc6_marshall_values("old_", client, old,
04317 oldia, oldaddr);
04318 dhc6_marshall_values("new_", client, lease, ia, addr);
04319 script_write_requested6(client);
04320
04321
04322 if (script_go(client) == 3) {
04323 start_decline6(client);
04324 return;
04325 }
04326 }
04327
04328
04329 if (ia->addrs == NULL) {
04330 script_init(client, reason, NULL);
04331
04332 if (old != NULL)
04333 dhc6_marshall_values("old_", client, old,
04334 oldia,
04335 oldia != NULL ?
04336 oldia->addrs : NULL);
04337
04338 dhc6_marshall_values("new_", client, lease, ia,
04339 NULL);
04340 script_write_requested6(client);
04341
04342 script_go(client);
04343 }
04344 }
04345
04346
04347 if (lease->bindings == NULL) {
04348 script_init(client, reason, NULL);
04349
04350 if (old != NULL)
04351 dhc6_marshall_values("old_", client, old,
04352 old->bindings,
04353 (old->bindings != NULL) ?
04354 old->bindings->addrs : NULL);
04355
04356 dhc6_marshall_values("new_", client, lease, NULL, NULL);
04357 script_write_requested6(client);
04358
04359 script_go(client);
04360 }
04361
04362 go_daemon();
04363
04364 if (client->old_lease != NULL) {
04365 dhc6_lease_destroy(&client->old_lease, MDL);
04366 client->old_lease = NULL;
04367 }
04368
04369
04370 dhc6_check_times(client);
04371 }
04372
04373
04374
04375
04376 void
04377 start_decline6(struct client_state *client)
04378 {
04379
04380 cancel_timeout(do_confirm6, client);
04381 cancel_timeout(do_select6, client);
04382 cancel_timeout(do_refresh6, client);
04383 cancel_timeout(do_release6, client);
04384 cancel_timeout(do_decline6, client);
04385 client->state = S_DECLINED;
04386
04387 if (client->active_lease == NULL)
04388 return;
04389
04390
04391 client->IRT = DEC_TIMEOUT * 100;
04392 client->MRT = 0;
04393 client->MRC = DEC_MAX_RC;
04394 client->MRD = 0;
04395
04396 dhc6_retrans_init(client);
04397 client->v6_handler = reply_handler;
04398
04399 client->refresh_type = DHCPV6_DECLINE;
04400 do_decline6(client);
04401 }
04402
04403
04404
04405
04406 static void
04407 do_decline6(void *input)
04408 {
04409 struct client_state *client;
04410 struct data_string ds;
04411 int send_ret;
04412 struct timeval elapsed, tv;
04413
04414 client = input;
04415
04416 if ((client->active_lease == NULL) || !active_prefix(client))
04417 return;
04418
04419 if ((client->MRC != 0) && (client->txcount > client->MRC)) {
04420 log_info("Max retransmission count exceeded.");
04421 goto decline_done;
04422 }
04423
04424
04425
04426
04427 if (client->txcount == 0) {
04428 client->start_time.tv_sec = cur_tv.tv_sec;
04429 client->start_time.tv_usec = cur_tv.tv_usec;
04430 }
04431
04432
04433 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
04434 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
04435 if (elapsed.tv_usec < 0) {
04436 elapsed.tv_sec -= 1;
04437 elapsed.tv_usec += 1000000;
04438 }
04439
04440 memset(&ds, 0, sizeof(ds));
04441 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
04442 log_error("Unable to allocate memory for Decline.");
04443 goto decline_done;
04444 }
04445
04446 ds.data = ds.buffer->data;
04447 ds.len = 4;
04448 ds.buffer->data[0] = DHCPV6_DECLINE;
04449 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
04450
04451
04452
04453 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
04454 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
04455 client->elapsed = 0xffff;
04456 } else {
04457 client->elapsed = elapsed.tv_sec * 100;
04458 client->elapsed += elapsed.tv_usec / 10000;
04459 }
04460
04461 client->elapsed = htons(client->elapsed);
04462
04463 log_debug("XMT: Forming Decline.");
04464 make_client6_options(client, &client->sent_options,
04465 client->active_lease, DHCPV6_DECLINE);
04466 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
04467 client->sent_options, &global_scope,
04468 &dhcpv6_universe);
04469
04470
04471 if (wanted_ia_na &&
04472 dhc6_add_ia_na(client, &ds, client->active_lease,
04473 DHCPV6_DECLINE) != ISC_R_SUCCESS) {
04474 data_string_forget(&ds, MDL);
04475 goto decline_done;
04476 }
04477 if (wanted_ia_pd &&
04478 dhc6_add_ia_pd(client, &ds, client->active_lease,
04479 DHCPV6_DECLINE) != ISC_R_SUCCESS) {
04480 data_string_forget(&ds, MDL);
04481 goto decline_done;
04482 }
04483
04484
04485 log_info("XMT: Decline on %s, interval %ld0ms.",
04486 client->name ? client->name : client->interface->name,
04487 (long int)client->RT);
04488
04489 send_ret = send_packet6(client->interface, ds.data, ds.len,
04490 &DHCPv6DestAddr);
04491 if (send_ret != ds.len) {
04492 log_error("dhc6: sendpacket6() sent %d of %d bytes",
04493 send_ret, ds.len);
04494 }
04495
04496 data_string_forget(&ds, MDL);
04497
04498
04499 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
04500 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
04501 if (tv.tv_usec >= 1000000) {
04502 tv.tv_sec += 1;
04503 tv.tv_usec -= 1000000;
04504 }
04505 add_timeout(&tv, do_decline6, client, NULL, NULL);
04506 dhc6_retrans_advance(client);
04507 return;
04508
04509 decline_done:
04510 dhc6_lease_destroy(&client->active_lease, MDL);
04511 client->active_lease = NULL;
04512 start_init6(client);
04513 return;
04514 }
04515
04516
04517
04518
04519 void
04520 bound_handler(struct packet *packet, struct client_state *client)
04521 {
04522 log_debug("RCV: Input packets are ignored once bound.");
04523 }
04524
04525
04526
04527
04528
04529 void
04530 start_renew6(void *input)
04531 {
04532 struct client_state *client;
04533
04534 client = (struct client_state *)input;
04535
04536 log_info("PRC: Renewing lease on %s.",
04537 client->name ? client->name : client->interface->name);
04538 client->state = S_RENEWING;
04539
04540 client->v6_handler = reply_handler;
04541
04542
04543 client->IRT = REN_TIMEOUT * 100;
04544 client->MRT = REN_MAX_RT * 100;
04545 client->MRC = 0;
04546
04547
04548
04549 client->MRD = client->next_MRD - cur_time;
04550
04551 dhc6_retrans_init(client);
04552
04553 client->refresh_type = DHCPV6_RENEW;
04554 do_refresh6(client);
04555 }
04556
04557
04558
04559
04560
04561 void
04562 do_refresh6(void *input)
04563 {
04564 struct option_cache *oc;
04565 struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr;
04566 struct data_string ds;
04567 struct client_state *client;
04568 struct dhc6_lease *lease;
04569 struct timeval elapsed, tv;
04570 int send_ret;
04571
04572 client = (struct client_state *)input;
04573 memset(&ds, 0, sizeof(ds));
04574
04575 lease = client->active_lease;
04576 if (lease == NULL) {
04577 log_error("Cannot renew without an active binding.");
04578 return;
04579 }
04580
04581
04582 switch (client->refresh_type) {
04583 case DHCPV6_RENEW:
04584 case DHCPV6_REBIND:
04585 break;
04586
04587 default:
04588 log_fatal("Internal inconsistency (%d) at %s:%d.",
04589 client->refresh_type, MDL);
04590 }
04591
04592
04593
04594
04595 if (client->txcount == 0) {
04596 client->start_time.tv_sec = cur_tv.tv_sec;
04597 client->start_time.tv_usec = cur_tv.tv_usec;
04598 }
04599
04600
04601 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
04602 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
04603 if (elapsed.tv_usec < 0) {
04604 elapsed.tv_sec -= 1;
04605 elapsed.tv_usec += 1000000;
04606 }
04607 if (((client->MRC != 0) && (client->txcount > client->MRC)) ||
04608 ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD))) {
04609
04610 dhc6_check_times(client);
04611 return;
04612 }
04613
04614
04615
04616
04617
04618 oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST);
04619 if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
04620 lease->options, NULL, &global_scope,
04621 oc, MDL)) {
04622 if (ds.len < 16) {
04623 log_error("Invalid unicast option length %d.", ds.len);
04624 } else {
04625 memset(&unicast, 0, sizeof(DHCPv6DestAddr));
04626 unicast.sin6_family = AF_INET6;
04627 unicast.sin6_port = remote_port;
04628 memcpy(&unicast.sin6_addr, ds.data, 16);
04629 if (client->refresh_type == DHCPV6_RENEW) {
04630 dest_addr = &unicast;
04631 }
04632 }
04633
04634 data_string_forget(&ds, MDL);
04635 }
04636
04637
04638 memset(&ds, 0, sizeof(ds));
04639 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
04640 log_error("Unable to allocate memory for packet.");
04641 return;
04642 }
04643 ds.data = ds.buffer->data;
04644 ds.len = 4;
04645
04646 ds.buffer->data[0] = client->refresh_type;
04647 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
04648
04649
04650
04651 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
04652 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
04653 client->elapsed = 0xffff;
04654 } else {
04655 client->elapsed = elapsed.tv_sec * 100;
04656 client->elapsed += elapsed.tv_usec / 10000;
04657 }
04658
04659 if (client->elapsed == 0)
04660 log_debug("XMT: Forming %s, 0 ms elapsed.",
04661 dhcpv6_type_names[client->refresh_type]);
04662 else
04663 log_debug("XMT: Forming %s, %u0 ms elapsed.",
04664 dhcpv6_type_names[client->refresh_type],
04665 (unsigned)client->elapsed);
04666
04667 client->elapsed = htons(client->elapsed);
04668
04669 make_client6_options(client, &client->sent_options, lease,
04670 client->refresh_type);
04671
04672
04673 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
04674 client->sent_options, &global_scope,
04675 &dhcpv6_universe);
04676
04677
04678 if (wanted_ia_na &&
04679 dhc6_add_ia_na(client, &ds, lease,
04680 client->refresh_type) != ISC_R_SUCCESS) {
04681 data_string_forget(&ds, MDL);
04682 return;
04683 }
04684 if (wanted_ia_pd &&
04685 dhc6_add_ia_pd(client, &ds, lease,
04686 client->refresh_type) != ISC_R_SUCCESS) {
04687 data_string_forget(&ds, MDL);
04688 return;
04689 }
04690
04691 log_info("XMT: %s on %s, interval %ld0ms.",
04692 dhcpv6_type_names[client->refresh_type],
04693 client->name ? client->name : client->interface->name,
04694 (long int)client->RT);
04695
04696 send_ret = send_packet6(client->interface, ds.data, ds.len, dest_addr);
04697
04698 if (send_ret != ds.len) {
04699 log_error("dhc6: send_packet6() sent %d of %d bytes",
04700 send_ret, ds.len);
04701 }
04702
04703 data_string_forget(&ds, MDL);
04704
04705
04706 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
04707 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
04708 if (tv.tv_usec >= 1000000) {
04709 tv.tv_sec += 1;
04710 tv.tv_usec -= 1000000;
04711 }
04712 add_timeout(&tv, do_refresh6, client, NULL, NULL);
04713
04714 dhc6_retrans_advance(client);
04715 }
04716
04717
04718
04719
04720
04721
04722 void
04723 start_rebind6(void *input)
04724 {
04725 struct client_state *client;
04726
04727 client = (struct client_state *)input;
04728
04729 log_info("PRC: Rebinding lease on %s.",
04730 client->name ? client->name : client->interface->name);
04731 client->state = S_REBINDING;
04732
04733 client->v6_handler = reply_handler;
04734
04735
04736 client->IRT = REB_TIMEOUT * 100;
04737 client->MRT = REB_MAX_RT * 100;
04738 client->MRC = 0;
04739
04740
04741
04742 client->MRD = client->next_MRD - cur_time;
04743
04744 dhc6_retrans_init(client);
04745
04746 client->refresh_type = DHCPV6_REBIND;
04747 do_refresh6(client);
04748 }
04749
04750
04751
04752
04753
04754
04755
04756 void
04757 do_depref(void *input)
04758 {
04759 struct client_state *client;
04760 struct dhc6_lease *lease;
04761 struct dhc6_ia *ia;
04762 struct dhc6_addr *addr;
04763
04764 client = (struct client_state *)input;
04765
04766 lease = client->active_lease;
04767 if (lease == NULL)
04768 return;
04769
04770 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
04771 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
04772 if (addr->flags & DHC6_ADDR_DEPREFFED)
04773 continue;
04774
04775 if (addr->starts + addr->preferred_life <= cur_time) {
04776 script_init(client, "DEPREF6", NULL);
04777 dhc6_marshall_values("cur_", client, lease,
04778 ia, addr);
04779 script_write_requested6(client);
04780 script_go(client);
04781
04782 addr->flags |= DHC6_ADDR_DEPREFFED;
04783
04784 if (ia->ia_type != D6O_IA_PD)
04785 log_info("PRC: Address %s depreferred.",
04786 piaddr(addr->address));
04787 else
04788 log_info("PRC: Prefix %s/%u depreferred.",
04789 piaddr(addr->address),
04790 (unsigned) addr->plen);
04791
04792 #if defined (NSUPDATE)
04793
04794 if ((ia->ia_type == D6O_IA_NA) &&
04795 client->config->do_forward_update)
04796 client_dns_remove(client,
04797 &addr->address);
04798 #endif
04799 }
04800 }
04801 }
04802
04803 dhc6_check_times(client);
04804 }
04805
04806
04807
04808
04809 void
04810 do_expire(void *input)
04811 {
04812 struct client_state *client;
04813 struct dhc6_lease *lease;
04814 struct dhc6_ia *ia;
04815 struct dhc6_addr *addr;
04816 int has_addrs = ISC_FALSE;
04817
04818 client = (struct client_state *)input;
04819
04820 lease = client->active_lease;
04821 if (lease == NULL)
04822 return;
04823
04824 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
04825 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
04826 if (addr->flags & DHC6_ADDR_EXPIRED)
04827 continue;
04828
04829 if (addr->starts + addr->max_life <= cur_time) {
04830 script_init(client, "EXPIRE6", NULL);
04831 dhc6_marshall_values("old_", client, lease,
04832 ia, addr);
04833 script_write_requested6(client);
04834 script_go(client);
04835
04836 addr->flags |= DHC6_ADDR_EXPIRED;
04837
04838 if (ia->ia_type != D6O_IA_PD)
04839 log_info("PRC: Address %s expired.",
04840 piaddr(addr->address));
04841 else
04842 log_info("PRC: Prefix %s/%u expired.",
04843 piaddr(addr->address),
04844 (unsigned) addr->plen);
04845
04846 #if defined (NSUPDATE)
04847
04848
04849
04850
04851 if ((ia->ia_type == D6O_IA_NA) &&
04852 client->config->do_forward_update &&
04853 !(addr->flags & DHC6_ADDR_DEPREFFED))
04854 client_dns_remove(client,
04855 &addr->address);
04856 #endif
04857
04858 continue;
04859 }
04860
04861 has_addrs = ISC_TRUE;
04862 }
04863 }
04864
04865
04866 if (has_addrs == ISC_FALSE) {
04867 log_info("PRC: Bound lease is devoid of active addresses."
04868 " Re-initializing.");
04869
04870 dhc6_lease_destroy(&lease, MDL);
04871 client->active_lease = NULL;
04872
04873 start_init6(client);
04874 return;
04875 }
04876
04877
04878 dhc6_check_times(client);
04879 }
04880
04881
04882
04883
04884
04885
04886
04887 void
04888 unconfigure6(struct client_state *client, const char *reason)
04889 {
04890 struct dhc6_ia *ia;
04891 struct dhc6_addr *addr;
04892
04893 if (stateless) {
04894 script_init(client, reason, NULL);
04895 if (client->active_lease != NULL)
04896 script_write_params6(client, "old_",
04897 client->active_lease->options);
04898 script_write_requested6(client);
04899 script_go(client);
04900 return;
04901 }
04902
04903 if (client->active_lease == NULL)
04904 return;
04905
04906 for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) {
04907 if (ia->ia_type == D6O_IA_TA)
04908 continue;
04909
04910 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
04911 script_init(client, reason, NULL);
04912 dhc6_marshall_values("old_", client,
04913 client->active_lease, ia, addr);
04914 script_write_requested6(client);
04915 script_go(client);
04916
04917 #if defined (NSUPDATE)
04918 if ((ia->ia_type == D6O_IA_NA) &&
04919 client->config->do_forward_update)
04920 client_dns_remove(client, &addr->address);
04921 #endif
04922 }
04923 }
04924 }
04925
04926 void
04927 refresh_info_request6(void *input)
04928 {
04929 struct client_state *client;
04930
04931 client = (struct client_state *)input;
04932 start_info_request6(client);
04933 }
04934
04935
04936
04937 static void
04938 dhc6_check_irt(struct client_state *client)
04939 {
04940 struct option **req;
04941 struct option_cache *oc;
04942 TIME expire = MAX_TIME;
04943 struct timeval tv;
04944 int i;
04945 isc_boolean_t found = ISC_FALSE;
04946
04947 cancel_timeout(refresh_info_request6, client);
04948
04949 req = client->config->requested_options;
04950 for (i = 0; req[i] != NULL; i++) {
04951 if (req[i] == irt_option) {
04952 found = ISC_TRUE;
04953 break;
04954 }
04955 }
04956
04957 if (!found)
04958 exit(0);
04959
04960 oc = lookup_option(&dhcpv6_universe, client->active_lease->options,
04961 D6O_INFORMATION_REFRESH_TIME);
04962 if (oc != NULL) {
04963 struct data_string irt;
04964
04965 memset(&irt, 0, sizeof(irt));
04966 if (!evaluate_option_cache(&irt, NULL, NULL, client,
04967 client->active_lease->options,
04968 NULL, &global_scope, oc, MDL) ||
04969 (irt.len < 4)) {
04970 log_error("Can't evaluate IRT.");
04971 } else {
04972 expire = getULong(irt.data);
04973 if (expire < IRT_MINIMUM)
04974 expire = IRT_MINIMUM;
04975 if (expire == 0xffffffff)
04976 expire = MAX_TIME;
04977 }
04978 data_string_forget(&irt, MDL);
04979 } else
04980 expire = IRT_DEFAULT;
04981
04982 if (expire != MAX_TIME) {
04983 log_debug("PRC: Refresh event scheduled in %u seconds.",
04984 (unsigned) expire);
04985 tv.tv_sec = cur_time + expire;
04986 tv.tv_usec = 0;
04987 add_timeout(&tv, refresh_info_request6, client, NULL, NULL);
04988 }
04989 }
04990
04991
04992
04993
04994 static void
04995 start_informed(struct client_state *client)
04996 {
04997 client->v6_handler = informed_handler;
04998
04999 log_debug("PRC: Done.");
05000
05001 client->state = S_BOUND;
05002
05003 script_init(client, "RENEW6", NULL);
05004 if (client->old_lease != NULL)
05005 script_write_params6(client, "old_",
05006 client->old_lease->options);
05007 script_write_params6(client, "new_", client->active_lease->options);
05008 script_write_requested6(client);
05009 script_go(client);
05010
05011 go_daemon();
05012
05013 if (client->old_lease != NULL) {
05014 dhc6_lease_destroy(&client->old_lease, MDL);
05015 client->old_lease = NULL;
05016 }
05017
05018
05019 dhc6_check_irt(client);
05020 }
05021
05022
05023
05024 void
05025 informed_handler(struct packet *packet, struct client_state *client)
05026 {
05027 log_debug("RCV: Input packets are ignored once bound.");
05028 }
05029
05030
05031
05032
05033
05034 static void
05035 make_client6_options(struct client_state *client, struct option_state **op,
05036 struct dhc6_lease *lease, u_int8_t message)
05037 {
05038 struct option_cache *oc;
05039 struct option **req;
05040 struct buffer *buffer;
05041 int buflen, i, oro_len;
05042
05043 if ((op == NULL) || (client == NULL))
05044 return;
05045
05046 if (*op)
05047 option_state_dereference(op, MDL);
05048
05049
05050 option_state_allocate(op, MDL);
05051
05052
05053 oc = NULL;
05054 if (option_cache_allocate(&oc, MDL)) {
05055 const unsigned char *cdata;
05056
05057 cdata = (unsigned char *)&client->elapsed;
05058
05059 if (make_const_data(&oc->expression, cdata, 2, 0, 0, MDL)) {
05060 option_reference(&oc->option, elapsed_option, MDL);
05061 save_option(&dhcpv6_universe, *op, oc);
05062 }
05063
05064 option_cache_dereference(&oc, MDL);
05065 }
05066
05067
05068 if (client->config->on_transmission)
05069 execute_statements_in_scope(NULL, NULL, NULL, client,
05070 lease ? lease->options : NULL,
05071 *op, &global_scope,
05072 client->config->on_transmission,
05073 NULL, NULL);
05074
05075
05076 if (message != DHCPV6_SOLICIT)
05077 delete_option(&dhcpv6_universe, *op, D6O_RAPID_COMMIT);
05078
05079
05080
05081
05082 if ((oc = lookup_option(&dhcpv6_universe, *op,
05083 D6O_CLIENTID)) == NULL) {
05084 if (default_duid.len == 0 ||
05085 !option_cache(&oc, &default_duid, NULL, clientid_option,
05086 MDL))
05087 log_fatal("Failure assembling a DUID.");
05088
05089 save_option(&dhcpv6_universe, *op, oc);
05090 option_cache_dereference(&oc, MDL);
05091 }
05092
05093
05094
05095
05096
05097
05098
05099 if (lease == NULL) {
05100 if ((message != DHCPV6_SOLICIT) &&
05101 (message != DHCPV6_INFORMATION_REQUEST))
05102 log_fatal("Impossible condition at %s:%d.", MDL);
05103 } else if ((message != DHCPV6_REBIND) &&
05104 (message != DHCPV6_CONFIRM)) {
05105 oc = lookup_option(&dhcpv6_universe, lease->options,
05106 D6O_SERVERID);
05107 if (oc != NULL)
05108 save_option(&dhcpv6_universe, *op, oc);
05109 }
05110
05111
05112
05113
05114
05115 if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) != NULL)
05116 log_error("'send dhcp6.oro' syntax is deprecated, please "
05117 "use the 'request' syntax (\"man dhclient.conf\").");
05118
05119
05120
05121
05122
05123
05124
05125
05126
05127
05128
05129
05130
05131
05132
05133
05134
05135
05136
05137
05138
05139
05140
05141
05142
05143
05144
05145
05146
05147
05148
05149
05150
05151
05152
05153 buffer = NULL;
05154 oro_len = 0;
05155 buflen = 32;
05156 if (!buffer_allocate(&buffer, buflen, MDL))
05157 log_fatal("Out of memory constructing DHCPv6 ORO.");
05158 req = client->config->requested_options;
05159 if (req != NULL) {
05160 for (i = 0 ; req[i] != NULL ; i++) {
05161 if (buflen == oro_len) {
05162 struct buffer *tmpbuf = NULL;
05163
05164 buflen += 32;
05165
05166
05167 buffer_reference(&tmpbuf, buffer, MDL);
05168 buffer_dereference(&buffer, MDL);
05169
05170 if (!buffer_allocate(&buffer, buflen, MDL))
05171 log_fatal("Out of memory resizing "
05172 "DHCPv6 ORO buffer.");
05173
05174 memcpy(buffer->data, tmpbuf->data, oro_len);
05175
05176 buffer_dereference(&tmpbuf, MDL);
05177 }
05178
05179 if (req[i]->universe == &dhcpv6_universe) {
05180
05181 putUShort(buffer->data + oro_len,
05182 req[i]->code);
05183 oro_len += 2;
05184 }
05185 }
05186 }
05187
05188 oc = NULL;
05189 if (make_const_option_cache(&oc, &buffer, NULL, oro_len,
05190 oro_option, MDL)) {
05191 save_option(&dhcpv6_universe, *op, oc);
05192 } else {
05193 log_fatal("Unable to create ORO option cache.");
05194 }
05195
05196
05197
05198
05199
05200 option_cache_dereference(&oc, MDL);
05201 }
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216 static void
05217 script_write_params6(struct client_state *client, const char *prefix,
05218 struct option_state *options)
05219 {
05220 struct envadd_state es;
05221 int i;
05222
05223 if (options == NULL)
05224 return;
05225
05226 es.client = client;
05227 es.prefix = prefix;
05228
05229 for (i = 0 ; i < options->universe_count ; i++) {
05230 option_space_foreach(NULL, NULL, client, NULL, options,
05231 &global_scope, universes[i], &es,
05232 client_option_envadd);
05233 }
05234 }
05235
05236
05237
05238
05239
05240
05241
05242
05243 static void script_write_requested6(client)
05244 struct client_state *client;
05245 {
05246 int i;
05247 struct option **req;
05248 char name[256];
05249 req = client->config->requested_options;
05250
05251 if (req == NULL)
05252 return;
05253
05254 for (i = 0 ; req[i] != NULL ; i++) {
05255 if ((req[i]->universe == &dhcpv6_universe) &&
05256 dhcp_option_ev_name (name, sizeof(name), req[i])) {
05257 client_envadd(client, "requested_", name, "%d", 1);
05258 }
05259 }
05260 }
05261
05262
05263
05264
05265 static isc_boolean_t
05266 active_prefix(struct client_state *client)
05267 {
05268 struct dhc6_lease *lease;
05269 struct dhc6_ia *ia;
05270 struct dhc6_addr *pref;
05271 char zeros[16];
05272
05273 lease = client->active_lease;
05274 if (lease == NULL)
05275 return ISC_FALSE;
05276 memset(zeros, 0, 16);
05277 for (ia = lease->bindings; ia != NULL; ia = ia->next) {
05278 if (ia->ia_type != D6O_IA_PD)
05279 continue;
05280 for (pref = ia->addrs; pref != NULL; pref = pref->next) {
05281 if (pref->plen == 0)
05282 return ISC_FALSE;
05283 if (pref->address.len != 16)
05284 return ISC_FALSE;
05285 if (memcmp(pref->address.iabuf, zeros, 16) == 0)
05286 return ISC_FALSE;
05287 }
05288 }
05289 return ISC_TRUE;
05290 }
05291 #endif