]> git.ipfire.org Git - thirdparty/dhcp.git/blame - client/dhc6.c
fix DUID-LTT epoch
[thirdparty/dhcp.git] / client / dhc6.c
CommitLineData
98bd7ca0
DH
1/* dhc6.c - DHCPv6 client routines. */
2
3/*
dccb6edf 4 * Copyright (c) 2006-2008 by Internet Systems Consortium, Inc. ("ISC")
98bd7ca0
DH
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * Internet Systems Consortium, Inc.
19 * 950 Charter Street
20 * Redwood City, CA 94063
21 * <info@isc.org>
22 * http://www.isc.org/
23 */
24
98bd7ca0
DH
25#include "dhcpd.h"
26
fe5b0fdd
DH
27#ifdef DHCPv6
28
98bd7ca0 29struct sockaddr_in6 DHCPv6DestAddr;
0c20eab3
DH
30
31/* Option definition structures that are used by the software - declared
32 * here once and assigned at startup to save lookups.
33 */
98bd7ca0 34struct option *clientid_option = NULL;
0c20eab3 35struct option *elapsed_option = NULL;
98bd7ca0 36struct option *ia_na_option = NULL;
1d9774ab
FD
37struct option *ia_ta_option = NULL;
38struct option *ia_pd_option = NULL;
98bd7ca0 39struct option *iaaddr_option = NULL;
1d9774ab 40struct option *iaprefix_option = NULL;
0c20eab3 41struct option *oro_option = NULL;
98bd7ca0
DH
42
43static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
06eb8bab
SK
44 const char *file, int line);
45static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia,
46 const char *file, int line);
98bd7ca0 47static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr,
06eb8bab 48 const char *file, int line);
e32529a5 49static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line);
98bd7ca0
DH
50static isc_result_t dhc6_parse_ia_na(struct dhc6_ia **pia,
51 struct packet *packet,
52 struct option_state *options);
1d9774ab
FD
53static isc_result_t dhc6_parse_ia_ta(struct dhc6_ia **pia,
54 struct packet *packet,
55 struct option_state *options);
56static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia,
57 struct packet *packet,
58 struct option_state *options);
98bd7ca0
DH
59static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr,
60 struct packet *packet,
61 struct option_state *options);
1d9774ab
FD
62static isc_result_t dhc6_parse_prefs(struct dhc6_addr **ppref,
63 struct packet *packet,
64 struct option_state *options);
65static struct dhc6_ia *find_ia_na(struct dhc6_ia *head, const char *id);
98bd7ca0
DH
66static struct dhc6_addr *find_addr(struct dhc6_addr *head,
67 struct iaddr *address);
68void init_handler(struct packet *packet, struct client_state *client);
6d7f9584 69void rapid_commit_handler(struct packet *packet, struct client_state *client);
98bd7ca0
DH
70void do_init6(void *input);
71void do_confirm6(void *input);
72void reply_handler(struct packet *packet, struct client_state *client);
1d9774ab
FD
73static isc_result_t dhc6_add_ia_na(struct client_state *client,
74 struct data_string *packet,
75 struct dhc6_lease *lease,
76 u_int8_t message);
98bd7ca0
DH
77static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst);
78void do_select6(void *input);
79void do_refresh6(void *input);
af5fa176 80static void do_release6(void *input);
98bd7ca0
DH
81static void start_bound(struct client_state *client);
82void bound_handler(struct packet *packet, struct client_state *client);
83void start_renew6(void *input);
84void start_rebind6(void *input);
85void do_depref(void *input);
86void do_expire(void *input);
87static void make_client6_options(struct client_state *client,
88 struct option_state **op,
89 struct dhc6_lease *lease, u_int8_t message);
06eb8bab
SK
90static void script_write_params6(struct client_state *client,
91 const char *prefix,
98bd7ca0
DH
92 struct option_state *options);
93
94/* The "best" default DUID, since we cannot predict any information
95 * about the system (such as whether or not the hardware addresses are
96 * integrated into the motherboard or similar), is the "LLT", link local
97 * plus time, DUID.
98 *
99 * Once generated, this duid is stored into the state database, and
100 * retained across restarts.
101 *
102 * For the time being, there is probably a different state database for
103 * every daemon, so this winds up being a per-interface identifier...which
104 * is not how it is intended. Upcoming rearchitecting the client should
105 * address this "one daemon model."
106 */
107void
06eb8bab 108form_duid(struct data_string *duid, const char *file, int line)
98bd7ca0
DH
109{
110 struct interface_info *ip;
111 int len;
112
113 /* For now, just use the first interface on the list. */
114 ip = interfaces;
115
116 if (ip == NULL)
117 log_fatal("Impossible condition at %s:%d.", MDL);
118
119 if ((ip->hw_address.hlen == 0) ||
120 (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
121 log_fatal("Impossible hardware address length at %s:%d.", MDL);
122
123 /* 2 bytes for the 'duid type' field.
124 * 2 bytes for the 'htype' field.
125 * 4 bytes for the 'current time'.
126 * enough bytes for the hardware address (note that hw_address has
127 * the 'htype' on byte zero).
128 */
129 len = 8 + (ip->hw_address.hlen - 1);
130 if (!buffer_allocate(&duid->buffer, len, MDL))
131 log_fatal("no memory for default DUID!");
132 duid->data = duid->buffer->data;
133 duid->len = len;
134
135 /* Basic Link Local Address type of DUID. */
136 putUShort(duid->buffer->data, DUID_LLT);
137 putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
7e9f7a1b 138 putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
98bd7ca0
DH
139 memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
140 ip->hw_address.hlen - 1);
141}
142
143/* Assign DHCPv6 port numbers as a client.
144 */
145void
146dhcpv6_client_assignments(void)
147{
148 struct servent *ent;
149 unsigned code;
150
151 if (path_dhclient_pid == NULL)
152 path_dhclient_pid = _PATH_DHCLIENT6_PID;
153 if (path_dhclient_db == NULL)
154 path_dhclient_db = _PATH_DHCLIENT6_DB;
155
156 if (local_port == 0) {
157 ent = getservbyname("dhcpv6-client", "udp");
158 if (ent == NULL)
159 local_port = htons(546);
160 else
161 local_port = ent->s_port;
162 }
163
164 if (remote_port == 0) {
165 ent = getservbyname("dhcpv6-server", "udp");
166 if (ent == NULL)
167 remote_port = htons(547);
168 else
169 remote_port = ent->s_port;
170 }
171
172 memset(&DHCPv6DestAddr, 0, sizeof(DHCPv6DestAddr));
173 DHCPv6DestAddr.sin6_family = AF_INET6;
174 DHCPv6DestAddr.sin6_port = remote_port;
175 inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
176 &DHCPv6DestAddr.sin6_addr);
177
178 code = D6O_CLIENTID;
179 if (!option_code_hash_lookup(&clientid_option,
180 dhcpv6_universe.code_hash, &code, 0, MDL))
181 log_fatal("Unable to find the CLIENTID option definition.");
182
0c20eab3
DH
183 code = D6O_ELAPSED_TIME;
184 if (!option_code_hash_lookup(&elapsed_option,
185 dhcpv6_universe.code_hash, &code, 0, MDL))
186 log_fatal("Unable to find the ELAPSED_TIME option definition.");
187
98bd7ca0
DH
188 code = D6O_IA_NA;
189 if (!option_code_hash_lookup(&ia_na_option, dhcpv6_universe.code_hash,
190 &code, 0, MDL))
191 log_fatal("Unable to find the IA_NA option definition.");
192
1d9774ab
FD
193 code = D6O_IA_TA;
194 if (!option_code_hash_lookup(&ia_ta_option, dhcpv6_universe.code_hash,
195 &code, 0, MDL))
196 log_fatal("Unable to find the IA_TA option definition.");
197
198 code = D6O_IA_PD;
199 if (!option_code_hash_lookup(&ia_pd_option, dhcpv6_universe.code_hash,
200 &code, 0, MDL))
201 log_fatal("Unable to find the IA_PD option definition.");
202
98bd7ca0
DH
203 code = D6O_IAADDR;
204 if (!option_code_hash_lookup(&iaaddr_option, dhcpv6_universe.code_hash,
205 &code, 0, MDL))
206 log_fatal("Unable to find the IAADDR option definition.");
207
1d9774ab
FD
208 code = D6O_IAPREFIX;
209 if (!option_code_hash_lookup(&iaprefix_option,
210 dhcpv6_universe.code_hash,
211 &code, 0, MDL))
212 log_fatal("Unable to find the IAPREFIX option definition.");
213
0c20eab3
DH
214 code = D6O_ORO;
215 if (!option_code_hash_lookup(&oro_option, dhcpv6_universe.code_hash,
216 &code, 0, MDL))
217 log_fatal("Unable to find the ORO option definition.");
98bd7ca0
DH
218
219#ifndef __CYGWIN32__ /* XXX */
220 endservent();
221#endif
222}
223
224/* Instead of implementing RFC3315 RAND (section 14) as a float "between"
225 * -0.1 and 0.1 non-inclusive, we implement it as an integer.
226 *
227 * The result is expected to follow this table:
228 *
229 * split range answer
230 * - ERROR - base <= 0
231 * 0 1 0..0 1 <= base <= 10
232 * 1 3 -1..1 11 <= base <= 20
233 * 2 5 -2..2 21 <= base <= 30
234 * 3 7 -3..3 31 <= base <= 40
235 * ...
236 *
237 * XXX: For this to make sense, we really need to do timing on a
238 * XXX: usec scale...we currently can assume zero for any value less than
239 * XXX: 11, which are very common in early stages of transmission for most
240 * XXX: messages.
241 */
242static TIME
243dhc6_rand(TIME base)
244{
245 TIME rval;
246 TIME range;
247 TIME split;
248
249 /* A zero or less timeout is a bad thing...we don't want to
250 * DHCP-flood anyone.
251 */
252 if (base <= 0)
253 log_fatal("Impossible condition at %s:%d.", MDL);
254
255 /* The first thing we do is count how many random integers we want
256 * in either direction (best thought of as the maximum negative
257 * integer, as we will subtract this potentially from a random 0).
258 */
259 split = (base - 1) / 10;
260
261 /* Don't bother with the rest of the math if we know we'll get 0. */
262 if (split == 0)
263 return 0;
264
265 /* Then we count the total number of integers in this set. This
266 * is twice the number of integers in positive and negative
267 * directions, plus zero (-1, 0, 1 is 3, -2..2 adds 2 to 5, so forth).
268 */
269 range = (split * 2) + 1;
270
271 /* Take a random number from [0..(range-1)]. */
272 rval = random();
273 rval %= range;
274
275 /* Offset it to uncover potential negative values. */
276 rval -= split;
277
278 return rval;
279}
280
c0216cb7 281/* Initialize message exchange timers (set RT from Initial-RT). */
98bd7ca0 282static void
c0216cb7 283dhc6_retrans_init(struct client_state *client)
98bd7ca0
DH
284{
285 int xid;
286
c0216cb7 287 /* Initialize timers. */
c0216cb7
DH
288 client->txcount = 0;
289 client->RT = client->IRT + dhc6_rand(client->IRT);
290
291 /* Generate a new random 24-bit transaction ID for this exchange. */
292
293#if (RAND_MAX >= 0x00ffffff)
294 xid = random();
295#elif (RAND_MAX >= 0x0000ffff)
296 xid = (random() << 16) ^ random();
297#elif (RAND_MAX >= 0x000000ff)
298 xid = (random() << 16) ^ (random() << 8) ^ random();
299#else
300# error "Random number generator of less than 8 bits not supported."
301#endif
98bd7ca0
DH
302
303 client->dhcpv6_transaction_id[0] = (xid >> 16) & 0xff;
304 client->dhcpv6_transaction_id[1] = (xid >> 8) & 0xff;
305 client->dhcpv6_transaction_id[2] = xid & 0xff;
306}
307
98bd7ca0
DH
308/* Advance the DHCPv6 retransmission state once. */
309static void
310dhc6_retrans_advance(struct client_state *client)
311{
be62cf06 312 struct timeval elapsed;
98bd7ca0 313
be62cf06
FD
314 /* elapsed = cur - start */
315 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
316 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
317 if (elapsed.tv_usec < 0) {
318 elapsed.tv_sec -= 1;
319 elapsed.tv_usec += 1000000;
320 }
98bd7ca0 321 /* retrans_advance is called after consuming client->RT. */
be62cf06
FD
322 /* elapsed += RT */
323 elapsed.tv_sec += client->RT / 100;
324 elapsed.tv_usec += (client->RT % 100) * 10000;
325 if (elapsed.tv_usec >= 1000000) {
326 elapsed.tv_sec += 1;
327 elapsed.tv_usec -= 1000000;
328 }
98bd7ca0
DH
329
330 /* RT for each subsequent message transmission is based on the previous
331 * value of RT:
332 *
333 * RT = 2*RTprev + RAND*RTprev
334 */
335 client->RT += client->RT + dhc6_rand(client->RT);
336
337 /* MRT specifies an upper bound on the value of RT (disregarding the
338 * randomization added by the use of RAND). If MRT has a value of 0,
339 * there is no upper limit on the value of RT. Otherwise:
340 *
341 * if (RT > MRT)
342 * RT = MRT + RAND*MRT
343 */
344 if ((client->MRT != 0) && (client->RT > client->MRT))
345 client->RT = client->MRT + dhc6_rand(client->MRT);
346
347 /* Further, if there's an MRD, we should wake up upon reaching
348 * the MRD rather than at some point after it.
349 */
be62cf06
FD
350 if (client->MRD == 0) {
351 /* Done. */
352 client->txcount++;
353 return;
354 }
355 /* elapsed += client->RT */
356 elapsed.tv_sec += client->RT / 100;
357 elapsed.tv_usec += (client->RT % 100) * 10000;
358 if (elapsed.tv_usec >= 1000000) {
359 elapsed.tv_sec += 1;
360 elapsed.tv_usec -= 1000000;
361 }
362 if (elapsed.tv_sec >= client->MRD) {
363 /*
364 * wake at RT + cur = start + MRD
365 */
366 client->RT = client->MRD +
367 (client->start_time.tv_sec - cur_tv.tv_sec);
368 client->RT = client->RT * 100 +
369 (client->start_time.tv_usec - cur_tv.tv_usec) / 10000;
98bd7ca0 370 }
98bd7ca0
DH
371 client->txcount++;
372}
373
374/* Quick validation of DHCPv6 ADVERTISE packet contents. */
375static int
376valid_reply(struct packet *packet, struct client_state *client)
377{
378 struct data_string sid, cid;
379 struct option_cache *oc;
380 int rval = ISC_TRUE;
381
382 memset(&sid, 0, sizeof(sid));
383 memset(&cid, 0, sizeof(cid));
384
385 if (!lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID)) {
9ab0cc6a 386 log_error("Response without a server identifier received.");
98bd7ca0
DH
387 rval = ISC_FALSE;
388 }
389
390 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
391 if (!oc ||
392 !evaluate_option_cache(&sid, packet, NULL, client, packet->options,
393 client->sent_options, &global_scope, oc,
394 MDL)) {
9ab0cc6a 395 log_error("Response without a client identifier.");
98bd7ca0
DH
396 rval = ISC_FALSE;
397 }
398
399 oc = lookup_option(&dhcpv6_universe, client->sent_options,
400 D6O_CLIENTID);
401 if (!oc ||
402 !evaluate_option_cache(&cid, packet, NULL, client,
403 client->sent_options, NULL, &global_scope,
404 oc, MDL)) {
405 log_error("Local client identifier is missing!");
406 rval = ISC_FALSE;
407 }
408
409 if (sid.len == 0 ||
410 sid.len != cid.len ||
411 memcmp(sid.data, cid.data, sid.len)) {
412 log_error("Advertise with matching transaction ID, but "
413 "mismatching client id.");
414 rval = ISC_FALSE;
415 }
416
417 return rval;
418}
419
420/* Create a complete copy of a DHCPv6 lease structure.
421 */
422static struct dhc6_lease *
06eb8bab 423dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line)
98bd7ca0
DH
424{
425 struct dhc6_lease *copy;
426 struct dhc6_ia **insert_ia, *ia;
427
428 copy = dmalloc(sizeof(*copy), file, line);
429 if (copy == NULL) {
430 log_error("Out of memory for v6 lease structure.");
431 return NULL;
432 }
433
434 data_string_copy(&copy->server_id, &lease->server_id, file, line);
435 copy->pref = lease->pref;
436
437 memcpy(copy->dhcpv6_transaction_id, lease->dhcpv6_transaction_id,
438 sizeof(copy->dhcpv6_transaction_id));
439
440 option_state_reference(&copy->options, lease->options, file, line);
441
442 insert_ia = &copy->bindings;
443 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
444 *insert_ia = dhc6_dup_ia(ia, file, line);
445
446 if (*insert_ia == NULL) {
e32529a5 447 dhc6_lease_destroy(&copy, file, line);
98bd7ca0
DH
448 return NULL;
449 }
450
451 insert_ia = &(*insert_ia)->next;
452 }
453
454 return copy;
455}
456
457/* Duplicate an IA structure.
458 */
459static struct dhc6_ia *
06eb8bab 460dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line)
98bd7ca0
DH
461{
462 struct dhc6_ia *copy;
463 struct dhc6_addr **insert_addr, *addr;
464
465 copy = dmalloc(sizeof(*ia), file, line);
466
467 memcpy(copy->iaid, ia->iaid, sizeof(copy->iaid));
468
1d9774ab 469 copy->ia_type = ia->ia_type;
98bd7ca0
DH
470 copy->starts = ia->starts;
471 copy->renew = ia->renew;
472 copy->rebind = ia->rebind;
473
474 insert_addr = &copy->addrs;
475 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
476 *insert_addr = dhc6_dup_addr(addr, file, line);
477
478 if (*insert_addr == NULL) {
e32529a5 479 dhc6_ia_destroy(&copy, file, line);
98bd7ca0
DH
480 return NULL;
481 }
482
483 insert_addr = &(*insert_addr)->next;
484 }
485
486 if (ia->options != NULL)
487 option_state_reference(&copy->options, ia->options,
488 file, line);
489
490 return copy;
491}
492
1d9774ab 493/* Duplicate an IAADDR or IAPREFIX structure.
98bd7ca0
DH
494 */
495static struct dhc6_addr *
06eb8bab 496dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line)
98bd7ca0
DH
497{
498 struct dhc6_addr *copy;
499
500 copy = dmalloc(sizeof(*addr), file, line);
501
502 if (copy == NULL)
503 return NULL;
504
505 memcpy(&copy->address, &addr->address, sizeof(copy->address));
506
1d9774ab 507 copy->plen = addr->plen;
98bd7ca0
DH
508 copy->flags = addr->flags;
509 copy->starts = addr->starts;
510 copy->preferred_life = addr->preferred_life;
511 copy->max_life = addr->max_life;
512
513 if (addr->options != NULL)
514 option_state_reference(&copy->options, addr->options,
515 file, line);
516
517 return copy;
518}
519
520/* Form a DHCPv6 lease structure based upon packet contents. Creates and
1d9774ab 521 * populates IA's and any IAADDR/IAPREFIX's they contain.
98bd7ca0
DH
522 */
523static struct dhc6_lease *
524dhc6_leaseify(struct packet *packet)
525{
526 struct data_string ds;
527 struct dhc6_lease *lease;
528 struct option_cache *oc;
529
530 lease = dmalloc(sizeof(*lease), MDL);
531 if (lease == NULL) {
532 log_error("Out of memory for v6 lease structure.");
533 return NULL;
534 }
535
536 memcpy(lease->dhcpv6_transaction_id, packet->dhcpv6_transaction_id, 3);
537 option_state_reference(&lease->options, packet->options, MDL);
538
539 memset(&ds, 0, sizeof(ds));
540
541 /* Determine preference (default zero). */
542 oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
543 if (oc &&
544 evaluate_option_cache(&ds, packet, NULL, NULL, lease->options,
545 NULL, &global_scope, oc, MDL)) {
546 if (ds.len != 1) {
547 log_error("Invalid length of DHCPv6 Preference option "
548 "(%d != 1)", ds.len);
549 data_string_forget(&ds, MDL);
e32529a5 550 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
551 return NULL;
552 } else {
553 lease->pref = ds.data[0];
554 log_debug("RCV: X-- Preference %u.",
555 (unsigned)lease->pref);
556 }
557
558 data_string_forget(&ds, MDL);
559 }
560
561 /* Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR
562 * options.
563 */
564 if (dhc6_parse_ia_na(&lease->bindings, packet,
565 lease->options) != ISC_R_SUCCESS) {
566 /* Error conditions are logged by the caller. */
e32529a5 567 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
568 return NULL;
569 }
1d9774ab
FD
570 /* Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR
571 * options.
572 */
573 if (dhc6_parse_ia_ta(&lease->bindings, packet,
574 lease->options) != ISC_R_SUCCESS) {
575 /* Error conditions are logged by the caller. */
576 dhc6_lease_destroy(&lease, MDL);
577 return NULL;
578 }
579 /* Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX
580 * options.
581 */
582 if (dhc6_parse_ia_pd(&lease->bindings, packet,
583 lease->options) != ISC_R_SUCCESS) {
584 /* Error conditions are logged by the caller. */
585 dhc6_lease_destroy(&lease, MDL);
586 return NULL;
587 }
98bd7ca0
DH
588
589 /* This is last because in the future we may want to make a different
590 * key based upon additional information from the packet (we may need
591 * to allow multiple leases in one client state per server, but we're
592 * not sure based on what additional keys now).
593 */
594 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
595 if (!evaluate_option_cache(&lease->server_id, packet, NULL, NULL,
596 lease->options, NULL, &global_scope,
597 oc, MDL) ||
598 lease->server_id.len == 0) {
599 /* This should be impossible due to validation checks earlier.
600 */
601 log_error("Invalid SERVERID option cache.");
e32529a5 602 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
603 return NULL;
604 } else {
605 log_debug("RCV: X-- Server ID: %s",
606 print_hex_1(lease->server_id.len,
607 lease->server_id.data, 52));
608 }
609
610 return lease;
611}
612
613static isc_result_t
614dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
615 struct option_state *options)
616{
617 struct data_string ds;
618 struct dhc6_ia *ia;
619 struct option_cache *oc;
620 isc_result_t result;
621
622 memset(&ds, 0, sizeof(ds));
623
624 oc = lookup_option(&dhcpv6_universe, options, D6O_IA_NA);
625 for ( ; oc != NULL ; oc = oc->next) {
626 ia = dmalloc(sizeof(*ia), MDL);
627 if (ia == NULL) {
628 log_error("Out of memory allocating IA_NA structure.");
629 return ISC_R_NOMEMORY;
630 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
631 options, NULL,
632 &global_scope, oc, MDL) &&
633 ds.len >= 12) {
634 memcpy(ia->iaid, ds.data, 4);
1d9774ab 635 ia->ia_type = D6O_IA_NA;
98bd7ca0
DH
636 ia->starts = cur_time;
637 ia->renew = getULong(ds.data + 4);
638 ia->rebind = getULong(ds.data + 8);
639
640 log_debug("RCV: X-- IA_NA %s",
641 print_hex_1(4, ia->iaid, 59));
642 /* XXX: This should be the printed time I think. */
643 log_debug("RCV: | X-- starts %u",
644 (unsigned)ia->starts);
645 log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
646 log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
647
648 /* RFC3315 section 22.4, discard IA_NA's that
649 * have t1 greater than t2, and both not zero.
650 * Since RFC3315 defines this behaviour, it is not
651 * an error - just normal operation.
652 *
653 * Note that RFC3315 says we MUST honor these values
654 * if they are not zero. So insane values are
655 * totally OK.
656 */
657 if ((ia->renew > 0) && (ia->rebind > 0) &&
658 (ia->renew > ia->rebind)) {
659 log_debug("RCV: | !-- INVALID renew/rebind "
660 "times, IA_NA discarded.");
661 dfree(ia, MDL);
662 data_string_forget(&ds, MDL);
663 continue;
664 }
665
666 if (ds.len > 12) {
667 log_debug("RCV: | X-- [Options]");
668
669 if (!option_state_allocate(&ia->options,
670 MDL)) {
671 log_error("Out of memory allocating "
672 "IA option state.");
673 dfree(ia, MDL);
674 data_string_forget(&ds, MDL);
675 return ISC_R_NOMEMORY;
676 }
677
678 if (!parse_option_buffer(ia->options,
679 ds.data + 12,
680 ds.len - 12,
681 &dhcpv6_universe)) {
682 log_error("Corrupt IA_NA options.");
683 option_state_dereference(&ia->options,
684 MDL);
685 dfree(ia, MDL);
686 data_string_forget(&ds, MDL);
687 return ISC_R_BADPARSE;
688 }
689 }
690 data_string_forget(&ds, MDL);
691
692 if (ia->options != NULL) {
693 result = dhc6_parse_addrs(&ia->addrs, packet,
694 ia->options);
695 if (result != ISC_R_SUCCESS) {
696 option_state_dereference(&ia->options,
697 MDL);
698 dfree(ia, MDL);
699 return result;
700 }
701 }
702
703 *pia = ia;
704 pia = &ia->next;
705 } else {
706 log_error("Invalid IA_NA option cache.");
707 dfree(ia, MDL);
708 if (ds.len != 0)
709 data_string_forget(&ds, MDL);
710 return ISC_R_UNEXPECTED;
711 }
712 }
713
714 return ISC_R_SUCCESS;
715}
716
1d9774ab
FD
717static isc_result_t
718dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet,
719 struct option_state *options)
720{
721 struct data_string ds;
722 struct dhc6_ia *ia;
723 struct option_cache *oc;
724 isc_result_t result;
725
726 memset(&ds, 0, sizeof(ds));
727
728 oc = lookup_option(&dhcpv6_universe, options, D6O_IA_TA);
729 for ( ; oc != NULL ; oc = oc->next) {
730 ia = dmalloc(sizeof(*ia), MDL);
731 if (ia == NULL) {
732 log_error("Out of memory allocating IA_TA structure.");
733 return ISC_R_NOMEMORY;
734 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
735 options, NULL,
736 &global_scope, oc, MDL) &&
737 ds.len >= 4) {
738 memcpy(ia->iaid, ds.data, 4);
739 ia->ia_type = D6O_IA_TA;
740 ia->starts = cur_time;
741
742 log_debug("RCV: X-- IA_TA %s",
743 print_hex_1(4, ia->iaid, 59));
744 /* XXX: This should be the printed time I think. */
745 log_debug("RCV: | X-- starts %u",
746 (unsigned)ia->starts);
747
748 if (ds.len > 4) {
749 log_debug("RCV: | X-- [Options]");
750
751 if (!option_state_allocate(&ia->options,
752 MDL)) {
753 log_error("Out of memory allocating "
754 "IA option state.");
755 dfree(ia, MDL);
756 data_string_forget(&ds, MDL);
757 return ISC_R_NOMEMORY;
758 }
759
760 if (!parse_option_buffer(ia->options,
761 ds.data + 4,
762 ds.len - 4,
763 &dhcpv6_universe)) {
764 log_error("Corrupt IA_TA options.");
765 option_state_dereference(&ia->options,
766 MDL);
767 dfree(ia, MDL);
768 data_string_forget(&ds, MDL);
769 return ISC_R_BADPARSE;
770 }
771 }
772 data_string_forget(&ds, MDL);
773
774 if (ia->options != NULL) {
775 result = dhc6_parse_addrs(&ia->addrs, packet,
776 ia->options);
777 if (result != ISC_R_SUCCESS) {
778 option_state_dereference(&ia->options,
779 MDL);
780 dfree(ia, MDL);
781 return result;
782 }
783 }
784
785 *pia = ia;
786 pia = &ia->next;
787 } else {
788 log_error("Invalid IA_TA option cache.");
789 dfree(ia, MDL);
790 if (ds.len != 0)
791 data_string_forget(&ds, MDL);
792 return ISC_R_UNEXPECTED;
793 }
794 }
795
796 return ISC_R_SUCCESS;
797}
798
799static isc_result_t
800dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
801 struct option_state *options)
802{
803 struct data_string ds;
804 struct dhc6_ia *ia;
805 struct option_cache *oc;
806 isc_result_t result;
807
808 memset(&ds, 0, sizeof(ds));
809
810 oc = lookup_option(&dhcpv6_universe, options, D6O_IA_PD);
811 for ( ; oc != NULL ; oc = oc->next) {
812 ia = dmalloc(sizeof(*ia), MDL);
813 if (ia == NULL) {
814 log_error("Out of memory allocating IA_PD structure.");
815 return ISC_R_NOMEMORY;
816 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
817 options, NULL,
818 &global_scope, oc, MDL) &&
819 ds.len >= 12) {
820 memcpy(ia->iaid, ds.data, 4);
821 ia->ia_type = D6O_IA_PD;
822 ia->starts = cur_time;
823 ia->renew = getULong(ds.data + 4);
824 ia->rebind = getULong(ds.data + 8);
825
826 log_debug("RCV: X-- IA_PD %s",
827 print_hex_1(4, ia->iaid, 59));
828 /* XXX: This should be the printed time I think. */
829 log_debug("RCV: | X-- starts %u",
830 (unsigned)ia->starts);
831 log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
832 log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
833
834 /* RFC3315 section 22.4, discard IA_PD's that
835 * have t1 greater than t2, and both not zero.
836 * Since RFC3315 defines this behaviour, it is not
837 * an error - just normal operation.
838 */
839 if ((ia->renew > 0) && (ia->rebind > 0) &&
840 (ia->renew > ia->rebind)) {
841 log_debug("RCV: | !-- INVALID renew/rebind "
842 "times, IA_PD discarded.");
843 dfree(ia, MDL);
844 data_string_forget(&ds, MDL);
845 continue;
846 }
847
848 if (ds.len > 12) {
849 log_debug("RCV: | X-- [Options]");
850
851 if (!option_state_allocate(&ia->options,
852 MDL)) {
853 log_error("Out of memory allocating "
854 "IA option state.");
855 dfree(ia, MDL);
856 data_string_forget(&ds, MDL);
857 return ISC_R_NOMEMORY;
858 }
859
860 if (!parse_option_buffer(ia->options,
861 ds.data + 12,
862 ds.len - 12,
863 &dhcpv6_universe)) {
864 log_error("Corrupt IA_PD options.");
865 option_state_dereference(&ia->options,
866 MDL);
867 dfree(ia, MDL);
868 data_string_forget(&ds, MDL);
869 return ISC_R_BADPARSE;
870 }
871 }
872 data_string_forget(&ds, MDL);
873
874 if (ia->options != NULL) {
875 result = dhc6_parse_prefs(&ia->addrs, packet,
876 ia->options);
877 if (result != ISC_R_SUCCESS) {
878 option_state_dereference(&ia->options,
879 MDL);
880 dfree(ia, MDL);
881 return result;
882 }
883 }
884
885 *pia = ia;
886 pia = &ia->next;
887 } else {
888 log_error("Invalid IA_PD option cache.");
889 dfree(ia, MDL);
890 if (ds.len != 0)
891 data_string_forget(&ds, MDL);
892 return ISC_R_UNEXPECTED;
893 }
894 }
895
896 return ISC_R_SUCCESS;
897}
898
98bd7ca0
DH
899
900static isc_result_t
901dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
902 struct option_state *options)
903{
904 struct data_string ds;
905 struct option_cache *oc;
906 struct dhc6_addr *addr;
907
908 memset(&ds, 0, sizeof(ds));
909
910 oc = lookup_option(&dhcpv6_universe, options, D6O_IAADDR);
911 for ( ; oc != NULL ; oc = oc->next) {
912 addr = dmalloc(sizeof(*addr), MDL);
913 if (addr == NULL) {
914 log_error("Out of memory allocating "
915 "address structure.");
916 return ISC_R_NOMEMORY;
917 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
918 options, NULL, &global_scope,
919 oc, MDL) &&
920 (ds.len >= 24)) {
921
922 addr->address.len = 16;
923 memcpy(addr->address.iabuf, ds.data, 16);
924 addr->starts = cur_time;
925 addr->preferred_life = getULong(ds.data + 16);
926 addr->max_life = getULong(ds.data + 20);
927
928 log_debug("RCV: | | X-- IAADDR %s",
929 piaddr(addr->address));
930 log_debug("RCV: | | | X-- Preferred lifetime %u.",
931 addr->preferred_life);
932 log_debug("RCV: | | | X-- Max lifetime %u.",
933 addr->max_life);
934
935 /* RFC 3315 section 22.6 says we must discard
936 * addresses whose pref is later than valid.
937 */
938 if ((addr->preferred_life > addr->max_life)) {
939 log_debug("RCV: | | | !-- INVALID lifetimes, "
940 "IAADDR discarded. Check your "
941 "server configuration.");
942 dfree(addr, MDL);
943 data_string_forget(&ds, MDL);
944 continue;
945 }
946
947 /* Fortunately this is the last recursion in the
948 * protocol.
949 */
950 if (ds.len > 24) {
951 if (!option_state_allocate(&addr->options,
952 MDL)) {
953 log_error("Out of memory allocating "
954 "IAADDR option state.");
955 dfree(addr, MDL);
956 data_string_forget(&ds, MDL);
957 return ISC_R_NOMEMORY;
958 }
959
960 if (!parse_option_buffer(addr->options,
961 ds.data + 24,
962 ds.len - 24,
963 &dhcpv6_universe)) {
964 log_error("Corrupt IAADDR options.");
965 option_state_dereference(&addr->options,
966 MDL);
967 dfree(addr, MDL);
968 data_string_forget(&ds, MDL);
969 return ISC_R_BADPARSE;
970 }
971 }
972
973 if (addr->options != NULL)
974 log_debug("RCV: | | | X-- "
975 "[Options]");
976
977 data_string_forget(&ds, MDL);
978
979 *paddr = addr;
980 paddr = &addr->next;
981 } else {
982 log_error("Invalid IAADDR option cache.");
983 dfree(addr, MDL);
984 if (ds.len != 0)
985 data_string_forget(&ds, MDL);
986 return ISC_R_UNEXPECTED;
987 }
988 }
989
990 return ISC_R_SUCCESS;
991}
992
1d9774ab
FD
993static isc_result_t
994dhc6_parse_prefs(struct dhc6_addr **ppref, struct packet *packet,
995 struct option_state *options)
996{
997 struct data_string ds;
998 struct option_cache *oc;
999 struct dhc6_addr *pref;
1000
1001 memset(&ds, 0, sizeof(ds));
1002
1003 oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX);
1004 for ( ; oc != NULL ; oc = oc->next) {
1005 pref = dmalloc(sizeof(*pref), MDL);
1006 if (pref == NULL) {
1007 log_error("Out of memory allocating "
1008 "prefix structure.");
1009 return ISC_R_NOMEMORY;
1010 } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
1011 options, NULL, &global_scope,
1012 oc, MDL) &&
1013 (ds.len >= 25)) {
1014
1015 pref->plen = getUChar(ds.data);
1016 pref->address.len = 16;
1017 memcpy(pref->address.iabuf, ds.data + 1, 16);
1018 pref->starts = cur_time;
1019 pref->preferred_life = getULong(ds.data + 17);
1020 pref->max_life = getULong(ds.data + 21);
1021
1022 log_debug("RCV: | | X-- IAPREFIX %s/%d",
1023 piaddr(pref->address), (int)pref->plen);
1024 log_debug("RCV: | | | X-- Preferred lifetime %u.",
1025 pref->preferred_life);
1026 log_debug("RCV: | | | X-- Max lifetime %u.",
1027 pref->max_life);
1028
1029 /* Sanity check over the prefix length */
1030 if ((pref->plen < 4) || (pref->plen > 128)) {
1031 log_debug("RCV: | | | !-- INVALID prefix "
1032 "length, IAPREFIX discarded. "
1033 "Check your server configuration.");
1034 dfree(pref, MDL);
1035 data_string_forget(&ds, MDL);
1036 continue;
1037 }
1038 /* RFC 3315 section 22.6 says we must discard
1039 * prefixes whose pref is later than valid.
1040 */
1041 if ((pref->preferred_life > pref->max_life)) {
1042 log_debug("RCV: | | | !-- INVALID lifetimes, "
1043 "IAPREFIX discarded. Check your "
1044 "server configuration.");
1045 dfree(pref, MDL);
1046 data_string_forget(&ds, MDL);
1047 continue;
1048 }
1049
1050 /* Fortunately this is the last recursion in the
1051 * protocol.
1052 */
1053 if (ds.len > 25) {
1054 if (!option_state_allocate(&pref->options,
1055 MDL)) {
1056 log_error("Out of memory allocating "
1057 "IAPREFIX option state.");
1058 dfree(pref, MDL);
1059 data_string_forget(&ds, MDL);
1060 return ISC_R_NOMEMORY;
1061 }
1062
1063 if (!parse_option_buffer(pref->options,
1064 ds.data + 25,
1065 ds.len - 25,
1066 &dhcpv6_universe)) {
1067 log_error("Corrupt IAPREFIX options.");
1068 option_state_dereference(&pref->options,
1069 MDL);
1070 dfree(pref, MDL);
1071 data_string_forget(&ds, MDL);
1072 return ISC_R_BADPARSE;
1073 }
1074 }
1075
1076 if (pref->options != NULL)
1077 log_debug("RCV: | | | X-- "
1078 "[Options]");
1079
1080 data_string_forget(&ds, MDL);
1081
1082 *ppref = pref;
1083 ppref = &pref->next;
1084 } else {
1085 log_error("Invalid IAPREFIX option cache.");
1086 dfree(pref, MDL);
1087 if (ds.len != 0)
1088 data_string_forget(&ds, MDL);
1089 return ISC_R_UNEXPECTED;
1090 }
1091 }
1092
1093 return ISC_R_SUCCESS;
1094}
1095
e32529a5 1096/* Clean up a lease object, deallocate all its parts, and set it to NULL. */
98bd7ca0 1097void
e32529a5 1098dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line)
98bd7ca0
DH
1099{
1100 struct dhc6_ia *ia, *nia;
e32529a5 1101 struct dhc6_lease *lease;
98bd7ca0 1102
e32529a5
EH
1103 if (src == NULL || *src == NULL) {
1104 log_error("Attempt to destroy null lease.");
98bd7ca0 1105 return;
e32529a5
EH
1106 }
1107 lease = *src;
98bd7ca0
DH
1108
1109 if (lease->server_id.len != 0)
1110 data_string_forget(&lease->server_id, file, line);
1111
1112 for (ia = lease->bindings ; ia != NULL ; ia = nia) {
1113 nia = ia->next;
1114
e32529a5 1115 dhc6_ia_destroy(&ia, file, line);
98bd7ca0
DH
1116 }
1117
1118 if (lease->options != NULL)
1119 option_state_dereference(&lease->options, file, line);
1120
1121 dfree(lease, file, line);
e32529a5 1122 *src = NULL;
98bd7ca0
DH
1123}
1124
e32529a5
EH
1125/*
1126 * Traverse the addresses list, and destroy their contents, and NULL the
1127 * list pointer.
1128 */
98bd7ca0 1129static void
e32529a5 1130dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line)
98bd7ca0
DH
1131{
1132 struct dhc6_addr *addr, *naddr;
e32529a5
EH
1133 struct dhc6_ia *ia;
1134
1135 if (src == NULL || *src == NULL) {
1136 log_error("Attempt to destroy null IA.");
1137 return;
1138 }
af9271c5 1139 ia = *src;
98bd7ca0
DH
1140
1141 for (addr = ia->addrs ; addr != NULL ; addr = naddr) {
1142 naddr = addr->next;
1143
1144 if (addr->options != NULL)
1145 option_state_dereference(&addr->options, file, line);
1146
1147 dfree(addr, file, line);
1148 }
1149
1150 if (ia->options != NULL)
1151 option_state_dereference(&ia->options, file, line);
1152
1153 dfree(ia, file, line);
e32529a5 1154 *src = NULL;
98bd7ca0
DH
1155}
1156
1157/* For a given lease, insert it into the tail of the lease list. Upon
1158 * finding a duplicate by server id, remove it and take over its position.
1159 */
1160static void
1161insert_lease(struct dhc6_lease **head, struct dhc6_lease *new)
1162{
1163 while (*head != NULL) {
1164 if ((*head)->server_id.len == new->server_id.len &&
1165 memcmp((*head)->server_id.data, new->server_id.data,
1166 new->server_id.len) == 0) {
1167 new->next = (*head)->next;
e32529a5 1168 dhc6_lease_destroy(head, MDL);
98bd7ca0
DH
1169 break;
1170 }
1171
1172 head= &(*head)->next;
1173 }
1174
1175 *head = new;
1176 return;
1177}
1178
1179/* Not really clear what to do here yet.
1180 */
1181static int
0c20eab3 1182dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
98bd7ca0
DH
1183{
1184 struct dhc6_ia *ia;
1185 struct dhc6_addr *addr;
0c20eab3
DH
1186 struct option **req;
1187 int i;
98bd7ca0
DH
1188
1189 if (lease->score)
1190 return lease->score;
1191
1192 lease->score = 1;
1193
0c20eab3
DH
1194 /* If this lease lacks a required option, dump it. */
1195 /* XXX: we should be able to cache the failure... */
1196 req = client->config->required_options;
1197 if (req != NULL) {
1198 for (i = 0 ; req[i] != NULL ; i++) {
1199 if (lookup_option(&dhcpv6_universe, lease->options,
1200 req[i]->code) == NULL) {
1201 lease->score = 0;
1202 return lease->score;
1203 }
1204 }
1205 }
1206
1207 /* If this lease contains a requested option, improve its
1208 * score.
1209 */
1210 req = client->config->requested_options;
1211 if (req != NULL) {
1212 for (i = 0 ; req[i] != NULL ; i++) {
1213 if (lookup_option(&dhcpv6_universe, lease->options,
1214 req[i]->code) != NULL)
1215 lease->score++;
1216 }
98bd7ca0 1217 }
98bd7ca0
DH
1218
1219 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
1220 lease->score += 50;
1221
1222 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
1223 lease->score += 100;
1224 }
1225 }
1226
1227 return lease->score;
1228}
1229
1230/* start_init6() kicks off the process, transmitting a packet and
1231 * scheduling a retransmission event.
1232 */
1233void
1234start_init6(struct client_state *client)
1235{
be62cf06
FD
1236 struct timeval tv;
1237
98bd7ca0
DH
1238 log_debug("PRC: Soliciting for leases (INIT).");
1239 client->state = S_INIT;
1240
98bd7ca0 1241 /* Initialize timers, RFC3315 section 17.1.2. */
be62cf06
FD
1242 client->IRT = SOL_TIMEOUT * 100;
1243 client->MRT = SOL_MAX_RT * 100;
98bd7ca0
DH
1244 client->MRC = 0;
1245 client->MRD = 0;
1246
1247 dhc6_retrans_init(client);
1248 /* RFC3315 section 17.1.2 goes out of its way:
1249 *
1250 * Also, the first RT MUST be selected to be strictly greater than IRT
1251 * by choosing RAND to be strictly greater than 0.
1252 */
be62cf06
FD
1253 /* if RAND < 0 then RAND = -RAND */
1254 if (client->RT <= client->IRT)
1255 client->RT = client->IRT + (client->IRT - client->RT);
1256 /* if RAND == 0 then RAND = 1 */
98bd7ca0
DH
1257 if (client->RT <= client->IRT)
1258 client->RT = client->IRT + 1;
1259
1260 client->v6_handler = init_handler;
1261
1262 /* RFC3315 section 17.1.2 says we MUST start the first packet
1263 * between 0 and SOL_MAX_DELAY seconds. The good news is
1264 * SOL_MAX_DELAY is 1.
1265 */
be62cf06
FD
1266 tv.tv_sec = cur_tv.tv_sec;
1267 tv.tv_usec = cur_tv.tv_usec;
1268 tv.tv_usec += (random() % (SOL_MAX_DELAY * 100)) * 10000;
1269 if (tv.tv_usec >= 1000000) {
1270 tv.tv_sec += 1;
1271 tv.tv_usec -= 1000000;
1272 }
1273 add_timeout(&tv, do_init6, client, NULL, NULL);
8ea19a71
DH
1274
1275 if (nowait)
1276 go_daemon();
98bd7ca0
DH
1277}
1278
1279/* start_init6() kicks off an "init-reboot" version of the process, at
1280 * startup to find out if old bindings are 'fair' and at runtime whenever
1281 * a link cycles state we'll eventually want to do this.
1282 */
1283void
1284start_confirm6(struct client_state *client)
1285{
be62cf06
FD
1286 struct timeval tv;
1287
98bd7ca0
DH
1288 /* If there is no active lease, there is nothing to check. */
1289 if (client->active_lease == NULL) {
1290 start_init6(client);
1291 return;
1292 }
1293
1294 log_debug("PRC: Confirming active lease (INIT-REBOOT).");
1295 client->state = S_REBOOTING;
1296
98bd7ca0 1297 /* Initialize timers, RFC3315 section 17.1.3. */
be62cf06
FD
1298 client->IRT = CNF_TIMEOUT * 100;
1299 client->MRT = CNF_MAX_RT * 100;
98bd7ca0
DH
1300 client->MRC = 0;
1301 client->MRD = CNF_MAX_RD;
1302
1303 dhc6_retrans_init(client);
1304
1305 client->v6_handler = reply_handler;
1306
be62cf06
FD
1307 /* RFC3315 section 18.1.2 says we MUST start the first packet
1308 * between 0 and CNF_MAX_DELAY seconds. The good news is
1309 * CNF_MAX_DELAY is 1.
1310 */
1311 tv.tv_sec = cur_tv.tv_sec;
1312 tv.tv_usec = cur_tv.tv_usec;
1313 tv.tv_usec += (random() % (CNF_MAX_DELAY * 100)) * 10000;
1314 if (tv.tv_usec >= 1000000) {
1315 tv.tv_sec += 1;
1316 tv.tv_usec -= 1000000;
1317 }
1318 add_timeout(&tv, do_confirm6, client, NULL, NULL);
98bd7ca0
DH
1319}
1320
1321/* do_init6() marshals and transmits a solicit.
1322 */
1323void
1324do_init6(void *input)
1325{
1326 struct client_state *client;
1327 struct dhc6_ia *old_ia;
1328 struct dhc6_addr *old_addr;
1329 struct data_string ds;
1330 struct data_string ia;
1331 struct data_string addr;
be62cf06 1332 struct timeval elapsed, tv;
98bd7ca0 1333 u_int32_t t1, t2;
28868515 1334 int idx, len, send_ret;
98bd7ca0
DH
1335
1336 client = input;
1337
1338 /* In RFC3315 section 17.1.2, the retransmission timer is
1339 * used as the selecting timer.
1340 */
1341 if (client->advertised_leases != NULL) {
1342 start_selecting6(client);
1343 return;
1344 }
1345
1346 if ((client->MRC != 0) && (client->txcount > client->MRC)) {
1347 log_info("Max retransmission count exceeded.");
1348 return;
1349 }
1350
be62cf06
FD
1351 /*
1352 * Start_time starts at the first transmission.
1353 */
1354 if (client->txcount == 0) {
1355 client->start_time.tv_sec = cur_tv.tv_sec;
1356 client->start_time.tv_usec = cur_tv.tv_usec;
1357 }
1358
1359 /* elapsed = cur - start */
1360 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
1361 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
1362 if (elapsed.tv_usec < 0) {
1363 elapsed.tv_sec -= 1;
1364 elapsed.tv_usec += 1000000;
1365 }
1366 if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
98bd7ca0
DH
1367 log_info("Max retransmission duration exceeded.");
1368 return;
1369 }
1370
1371 memset(&ds, 0, sizeof(ds));
1372 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
1373 log_error("Unable to allocate memory for SOLICIT.");
1374 return;
1375 }
1376 ds.data = ds.buffer->data;
1377 ds.len = 4;
1378
1379 ds.buffer->data[0] = DHCPV6_SOLICIT;
1380 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
1381
1382 /* Form an elapsed option. */
be62cf06
FD
1383 /* Maximum value is 65535 1/100s coded as 0xffff. */
1384 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
1385 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
98bd7ca0 1386 client->elapsed = 0xffff;
be62cf06
FD
1387 } else {
1388 client->elapsed = elapsed.tv_sec * 100;
1389 client->elapsed += elapsed.tv_usec / 10000;
1390 }
98bd7ca0 1391
be62cf06
FD
1392 if (client->elapsed == 0)
1393 log_debug("XMT: Forming Solicit, 0 ms elapsed.");
1394 else
1395 log_debug("XMT: Forming Solicit, %u0 ms elapsed.",
1396 (unsigned)client->elapsed);
98bd7ca0
DH
1397
1398 client->elapsed = htons(client->elapsed);
1399
1400 make_client6_options(client, &client->sent_options, NULL,
1401 DHCPV6_SOLICIT);
1402
1403 /* Fetch any configured 'sent' options (includes DUID) in wire format.
1404 */
1405 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
1406 NULL, client->sent_options, &global_scope,
1407 &dhcpv6_universe);
1408
6d7f9584
FD
1409 /* Use a specific handler with rapid-commit.
1410 */
1411 if (lookup_option(&dhcpv6_universe, client->sent_options,
1412 D6O_RAPID_COMMIT) != NULL) {
1413 client->v6_handler = rapid_commit_handler;
1414 }
1415
98bd7ca0
DH
1416 /* Append an IA_NA. */
1417 /* XXX: maybe the IA_NA('s) should be put into the sent_options
1418 * cache. They'd have to be pulled down as they also contain
1419 * different option caches in the same universe...
1420 */
1421 memset(&ia, 0, sizeof(ia));
1422 if (!buffer_allocate(&ia.buffer, 12, MDL)) {
1423 log_error("Unable to allocate memory for IA_NA.");
1424 data_string_forget(&ds, MDL);
1425 return;
1426 }
1427 ia.data = ia.buffer->data;
1428 ia.len = 12;
1429
1430 /* A simple IAID is the last 4 bytes of the hardware address. */
1431 if (client->interface->hw_address.hlen > 4) {
1432 idx = client->interface->hw_address.hlen - 4;
1433 len = 4;
1434 } else {
1435 idx = 0;
1436 len = client->interface->hw_address.hlen;
1437 }
1438 memcpy(ia.buffer->data, client->interface->hw_address.hbuf + idx, len);
1439
1440 t1 = client->config->requested_lease / 2;
1441 t2 = t1 + (t1 / 2);
1442 putULong(ia.buffer->data + 4, t1);
1443 putULong(ia.buffer->data + 8, t2);
1444
1445 log_debug("XMT: X-- IA_NA %s", print_hex_1(4, ia.buffer->data, 55));
1446 log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
1447 log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
1448
1449 if ((client->active_lease != NULL) &&
1d9774ab
FD
1450 ((old_ia = find_ia_na(client->active_lease->bindings,
1451 (char *)ia.buffer->data)) != NULL)) {
98bd7ca0
DH
1452 /* For each address in the old IA, request a binding. */
1453 memset(&addr, 0, sizeof(addr));
1454 for (old_addr = old_ia->addrs ; old_addr != NULL ;
1455 old_addr = old_addr->next) {
1456 if (old_addr->address.len != 16) {
1457 log_error("Invalid IPv6 address length %d. "
1458 "Ignoring. (%s:%d)",
1459 old_addr->address.len, MDL);
1460 continue;
1461 }
1462
1463 if (!buffer_allocate(&addr.buffer, 24, MDL)) {
1464 log_error("Unable to allocate memory for "
1465 "IAADDR.");
1466 data_string_forget(&ia, MDL);
1467 data_string_forget(&ds, MDL);
1468 return;
1469 }
1470 addr.data = addr.buffer->data;
1471 addr.len = 24;
1472
1473 memcpy(addr.buffer->data, old_addr->address.iabuf, 16);
1474
1475 t1 = client->config->requested_lease;
1476 t2 = t1 + (t1 / 2);
1477 putULong(addr.buffer->data + 16, t1);
1478 putULong(addr.buffer->data + 20, t2);
1479
1480 log_debug("XMT: | X-- Request address %s.",
1481 piaddr(old_addr->address));
1482 log_debug("XMT: | | X-- Request preferred in +%u",
1483 (unsigned)t1);
1484 log_debug("XMT: | | X-- Request valid in +%u",
1485 (unsigned)t2);
1486
1487 append_option(&ia, &dhcpv6_universe, iaaddr_option,
1488 &addr);
1489
1490 data_string_forget(&addr, MDL);
1491 }
1492 }
1493
1494 append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
1495 data_string_forget(&ia, MDL);
1496
1497 /* Transmit and wait. */
1498
be62cf06 1499 log_info("XMT: Solicit on %s, interval %ld0ms.",
98bd7ca0 1500 client->name ? client->name : client->interface->name,
9aa669fc 1501 (long int)client->RT);
98bd7ca0
DH
1502
1503 send_ret = send_packet6(client->interface,
1504 ds.data, ds.len, &DHCPv6DestAddr);
1505 if (send_ret != ds.len) {
1506 log_error("dhc6: send_packet6() sent %d of %d bytes",
1507 send_ret, ds.len);
1508 }
1509
1510 data_string_forget(&ds, MDL);
1511
be62cf06
FD
1512 /* Wait RT */
1513 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
1514 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
1515 if (tv.tv_usec >= 1000000) {
1516 tv.tv_sec += 1;
1517 tv.tv_usec -= 1000000;
1518 }
1519 add_timeout(&tv, do_init6, client, NULL, NULL);
98bd7ca0
DH
1520
1521 dhc6_retrans_advance(client);
1522}
1523
1524/* do_confirm6() creates a Confirm packet and transmits it. This function
1525 * is called on every timeout to (re)transmit.
1526 */
1527void
1528do_confirm6(void *input)
1529{
1530 struct client_state *client;
98bd7ca0 1531 struct data_string ds;
98bd7ca0 1532 int send_ret;
be62cf06 1533 struct timeval elapsed, tv;
98bd7ca0
DH
1534
1535 client = input;
1536
1537 if (client->active_lease == NULL)
1538 log_fatal("Impossible condition at %s:%d.", MDL);
1539
1540 /* In section 17.1.3, it is said:
1541 *
1542 * If the client receives no responses before the message
1543 * transmission process terminates, as described in section 14,
1544 * the client SHOULD continue to use any IP addresses, using the
1545 * last known lifetimes for those addresses, and SHOULD continue
1546 * to use any other previously obtained configuration parameters.
1547 *
1548 * So if confirm times out, we go active.
1549 *
1550 * XXX: Should we reduce all IA's t1 to 0, so that we renew and
1551 * stick there until we get a reply?
1552 */
1553
1554 if ((client->MRC != 0) && (client->txcount > client->MRC)) {
1555 log_info("Max retransmission count exceeded.");
1556 start_bound(client);
1557 return;
1558 }
1559
be62cf06
FD
1560 /*
1561 * Start_time starts at the first transmission.
1562 */
1563 if (client->txcount == 0) {
1564 client->start_time.tv_sec = cur_tv.tv_sec;
1565 client->start_time.tv_usec = cur_tv.tv_usec;
1566 }
1567
1568 /* elapsed = cur - start */
1569 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
1570 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
1571 if (elapsed.tv_usec < 0) {
1572 elapsed.tv_sec -= 1;
1573 elapsed.tv_usec += 1000000;
1574 }
1575 if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
98bd7ca0
DH
1576 log_info("Max retransmission duration exceeded.");
1577 start_bound(client);
1578 return;
1579 }
1580
1581 memset(&ds, 0, sizeof(ds));
1582 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
1583 log_error("Unable to allocate memory for Confirm.");
1584 return;
1585 }
1586 ds.data = ds.buffer->data;
1587 ds.len = 4;
1588
1589 ds.buffer->data[0] = DHCPV6_CONFIRM;
1590 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
1591
1592 /* Form an elapsed option. */
be62cf06
FD
1593 /* Maximum value is 65535 1/100s coded as 0xffff. */
1594 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
1595 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
98bd7ca0 1596 client->elapsed = 0xffff;
be62cf06
FD
1597 } else {
1598 client->elapsed = elapsed.tv_sec * 100;
1599 client->elapsed += elapsed.tv_usec / 10000;
1600 }
98bd7ca0 1601
be62cf06
FD
1602 if (client->elapsed == 0)
1603 log_debug("XMT: Forming Confirm, 0 ms elapsed.");
1604 else
1605 log_debug("XMT: Forming Confirm, %u0 ms elapsed.",
1606 (unsigned)client->elapsed);
98bd7ca0
DH
1607
1608 client->elapsed = htons(client->elapsed);
1609
1610 make_client6_options(client, &client->sent_options,
1611 client->active_lease, DHCPV6_CONFIRM);
1612
1613 /* Fetch any configured 'sent' options (includes DUID') in wire format.
1614 */
1615 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
1616 client->sent_options, &global_scope,
1617 &dhcpv6_universe);
1618
1619 /* Append IA's. */
1d9774ab
FD
1620 if (dhc6_add_ia_na(client, &ds, client->active_lease,
1621 DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
af5fa176
EH
1622 data_string_forget(&ds, MDL);
1623 return;
1624 }
98bd7ca0 1625
af5fa176 1626 /* Transmit and wait. */
98bd7ca0 1627
be62cf06 1628 log_info("XMT: Confirm on %s, interval %ld0ms.",
af5fa176 1629 client->name ? client->name : client->interface->name,
9aa669fc 1630 (long int)client->RT);
98bd7ca0 1631
af5fa176
EH
1632 send_ret = send_packet6(client->interface, ds.data, ds.len,
1633 &DHCPv6DestAddr);
1634 if (send_ret != ds.len) {
1635 log_error("dhc6: sendpacket6() sent %d of %d bytes",
1636 send_ret, ds.len);
1637 }
98bd7ca0 1638
af5fa176 1639 data_string_forget(&ds, MDL);
98bd7ca0 1640
be62cf06
FD
1641 /* Wait RT */
1642 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
1643 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
1644 if (tv.tv_usec >= 1000000) {
1645 tv.tv_sec += 1;
1646 tv.tv_usec -= 1000000;
1647 }
1648 add_timeout(&tv, do_confirm6, client, NULL, NULL);
98bd7ca0 1649
af5fa176
EH
1650 dhc6_retrans_advance(client);
1651}
98bd7ca0 1652
af5fa176
EH
1653/*
1654 * Release addresses.
1655 */
1656void
1657start_release6(struct client_state *client)
1658{
af5fa176
EH
1659 /* Cancel any pending transmissions */
1660 cancel_timeout(do_confirm6, client);
1661 cancel_timeout(do_select6, client);
1662 cancel_timeout(do_refresh6, client);
1663 cancel_timeout(do_release6, client);
1664 client->state = S_STOPPED;
1665
1666 /*
1667 * It is written: "The client MUST NOT use any of the addresses it
1668 * is releasing as the source address in the Release message or in
1669 * any subsequently transmitted message." So unconfigure now.
1670 */
1671 unconfigure6(client, "RELEASE6");
1672
af5fa176 1673 /* Set timers per RFC3315 section 18.1.1. */
be62cf06 1674 client->IRT = REL_TIMEOUT * 100;
af5fa176 1675 client->MRT = 0;
be62cf06 1676 client->MRC = REL_MAX_RC * 100;
af5fa176 1677 client->MRD = 0;
98bd7ca0 1678
af5fa176
EH
1679 dhc6_retrans_init(client);
1680 client->v6_handler = reply_handler;
1681
1682 /* ("re")transmit the first packet. */
1683 do_release6(client);
1684}
1685/*
1686 * do_release6() creates a Release packet and transmits it.
1687 */
1688static void
1689do_release6(void *input)
1690{
1691 struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr;
1692 struct client_state *client;
af5fa176 1693 struct data_string ds;
af5fa176 1694 struct option_cache *oc;
af5fa176 1695 int send_ret;
be62cf06 1696 struct timeval tv;
af5fa176
EH
1697
1698 client = input;
1699
1700 if (client->active_lease == NULL)
96b620e5 1701 return;
af5fa176
EH
1702
1703 if ((client->MRC != 0) && (client->txcount > client->MRC)) {
1704 log_info("Max retransmission count exceeded.");
1705 return;
1706 }
1707
be62cf06
FD
1708 /*
1709 * Start_time starts at the first transmission.
1710 */
1711 if (client->txcount == 0) {
1712 client->start_time.tv_sec = cur_tv.tv_sec;
1713 client->start_time.tv_usec = cur_tv.tv_usec;
1714 }
1715
af5fa176
EH
1716 /*
1717 * Check whether the server has sent a unicast option; if so, we can
1718 * use the address it specified.
1719 */
06eb8bab
SK
1720 oc = lookup_option(&dhcpv6_universe,
1721 client->active_lease->options, D6O_UNICAST);
af5fa176 1722 if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
06eb8bab
SK
1723 client->active_lease->options,
1724 NULL, &global_scope, oc, MDL)) {
af5fa176
EH
1725 if (ds.len < 16) {
1726 log_error("Invalid unicast option length %d.", ds.len);
1727 } else {
1728 memset(&unicast, 0, sizeof(DHCPv6DestAddr));
1729 unicast.sin6_family = AF_INET6;
1730 unicast.sin6_port = remote_port;
1731 memcpy(&unicast.sin6_addr, ds.data, 16);
1732 dest_addr = &unicast;
98bd7ca0
DH
1733 }
1734
af5fa176
EH
1735 data_string_forget(&ds, MDL);
1736 }
98bd7ca0 1737
af5fa176
EH
1738 memset(&ds, 0, sizeof(ds));
1739 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
1740 log_error("Unable to allocate memory for Release.");
1741 return;
98bd7ca0
DH
1742 }
1743
af5fa176
EH
1744 ds.data = ds.buffer->data;
1745 ds.len = 4;
1746 ds.buffer->data[0] = DHCPV6_RELEASE;
1747 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
98bd7ca0 1748
af5fa176
EH
1749 log_debug("XMT: Forming Release.");
1750 make_client6_options(client, &client->sent_options,
1751 client->active_lease, DHCPV6_RELEASE);
1752 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
1753 client->sent_options, &global_scope,
1754 &dhcpv6_universe);
1755
1756 /* Append IA's. */
1d9774ab
FD
1757 if (dhc6_add_ia_na(client, &ds, client->active_lease,
1758 DHCPV6_RELEASE) != ISC_R_SUCCESS) {
af5fa176
EH
1759 data_string_forget(&ds, MDL);
1760 return;
1761 }
1762
1763 /* Transmit and wait. */
be62cf06 1764 log_info("XMT: Release on %s, interval %ld0ms.",
98bd7ca0 1765 client->name ? client->name : client->interface->name,
9aa669fc 1766 (long int)client->RT);
98bd7ca0
DH
1767
1768 send_ret = send_packet6(client->interface, ds.data, ds.len,
1769 &DHCPv6DestAddr);
1770 if (send_ret != ds.len) {
1771 log_error("dhc6: sendpacket6() sent %d of %d bytes",
1772 send_ret, ds.len);
1773 }
1774
1775 data_string_forget(&ds, MDL);
1776
be62cf06
FD
1777 /* Wait RT */
1778 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
1779 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
1780 if (tv.tv_usec >= 1000000) {
1781 tv.tv_sec += 1;
1782 tv.tv_usec -= 1000000;
1783 }
1784 add_timeout(&tv, do_release6, client, NULL, NULL);
98bd7ca0
DH
1785 dhc6_retrans_advance(client);
1786}
1787
1788/* status_log() just puts a status code into displayable form and logs it
1789 * to info level.
1790 */
1791static void
06eb8bab 1792status_log(int code, const char *scope, const char *additional, int len)
98bd7ca0 1793{
06eb8bab 1794 const char *msg = NULL;
98bd7ca0
DH
1795
1796 switch(code) {
1797 case STATUS_Success:
e32529a5 1798 msg = "Success";
98bd7ca0
DH
1799 break;
1800
1801 case STATUS_UnspecFail:
1802 msg = "UnspecFail";
1803 break;
1804 case STATUS_NoAddrsAvail:
1805 msg = "NoAddrsAvail";
1806 break;
1807
1808 case STATUS_NoBinding:
1809 msg = "NoBinding";
1810 break;
1811
1812 case STATUS_NotOnLink:
1813 msg = "NotOnLink";
1814 break;
1815
1816 case STATUS_UseMulticast:
1817 msg = "UseMulticast";
1818 break;
1819
1820 default:
1821 msg = "UNKNOWN";
1822 break;
1823 }
1824
1825 if (len > 0)
1826 log_info("%s status code %s: %s", scope, msg,
06eb8bab
SK
1827 print_hex_1(len,
1828 (const unsigned char *)additional, 50));
98bd7ca0
DH
1829 else
1830 log_info("%s status code %s.", scope, msg);
1831}
1832
1833/* Acquire a status code.
1834 */
1835static isc_result_t
1836dhc6_get_status_code(struct option_state *options, unsigned *code,
1837 struct data_string *msg)
1838{
1839 struct option_cache *oc;
1840 struct data_string ds;
1841 isc_result_t rval = ISC_R_SUCCESS;
1842
1843 if ((options == NULL) || (code == NULL))
1844 return ISC_R_INVALIDARG;
1845
1846 if ((msg != NULL) && (msg->len != 0))
1847 return ISC_R_INVALIDARG;
1848
1849 memset(&ds, 0, sizeof(ds));
1850
1851 /* Assume success if there is no option. */
1852 *code = STATUS_Success;
1853
1854 oc = lookup_option(&dhcpv6_universe, options, D6O_STATUS_CODE);
1855 if ((oc != NULL) &&
1856 evaluate_option_cache(&ds, NULL, NULL, NULL, options,
1857 NULL, &global_scope, oc, MDL)) {
1858 if (ds.len < 2) {
1859 log_error("Invalid status code length %d.", ds.len);
1860 rval = ISC_R_FORMERR;
1861 } else
1862 *code = getUShort(ds.data);
1863
1864 if ((msg != NULL) && (ds.len > 2)) {
1865 data_string_copy(msg, &ds, MDL);
1866 msg->data += 2;
1867 msg->len -= 2;
1868 }
1869
1870 data_string_forget(&ds, MDL);
1871 return rval;
1872 }
1873
1874 return ISC_R_NOTFOUND;
1875}
1876
1877/* Look at status codes in an advertise, and reform the return value.
1878 */
1879static isc_result_t
1880dhc6_check_status(isc_result_t rval, struct option_state *options,
06eb8bab 1881 const char *scope, unsigned *code)
98bd7ca0
DH
1882{
1883 struct data_string msg;
1884 isc_result_t status;
1885
1886 if ((scope == NULL) || (code == NULL))
1887 return ISC_R_INVALIDARG;
1888
1889 /* If we don't find a code, we assume success. */
1890 *code = STATUS_Success;
1891
1892 /* If there is no options cache, then there is no code. */
1893 if (options != NULL) {
1894 memset(&msg, 0, sizeof(msg));
1895 status = dhc6_get_status_code(options, code, &msg);
1896
1897 if (status == ISC_R_SUCCESS) {
28868515 1898 status_log(*code, scope, (char *)msg.data, msg.len);
98bd7ca0
DH
1899 data_string_forget(&msg, MDL);
1900
1901 if (*code != STATUS_Success)
1902 rval = ISC_R_FAILURE;
1903
1904 } else if (status != ISC_R_NOTFOUND)
1905 rval = status;
1906 }
1907
1908 return rval;
1909}
1910
1911/* Look in the packet, any IA's, and any IAADDR's within those IA's to find
1912 * status code options that are not SUCCESS.
1913 */
1914static isc_result_t
1915dhc6_check_advertise(struct dhc6_lease *lease)
1916{
1917 struct dhc6_ia *ia;
1918 struct dhc6_addr *addr;
1919 isc_result_t rval = ISC_R_SUCCESS;
1920 int have_addrs = ISC_FALSE;
1921 unsigned code;
1d9774ab 1922 const char *scope;
98bd7ca0
DH
1923
1924 rval = dhc6_check_status(rval, lease->options, "message", &code);
1925
1926 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
1927 switch (ia->ia_type) {
1928 case D6O_IA_NA:
1929 default:
1930 scope = "IA_NA";
1931 break;
1932 case D6O_IA_TA:
1933 scope = "IA_TA";
1934 break;
1935 case D6O_IA_PD:
1936 scope = "IA_PD";
1937 break;
1938 }
1939 rval = dhc6_check_status(rval, ia->options, scope, &code);
98bd7ca0
DH
1940
1941 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
1d9774ab
FD
1942 if (ia->ia_type != D6O_IA_PD)
1943 scope = "IAADDR";
1944 else
1945 scope = "IAPREFIX";
98bd7ca0 1946 rval = dhc6_check_status(rval, addr->options,
1d9774ab 1947 scope, &code);
98bd7ca0
DH
1948 have_addrs = ISC_TRUE;
1949 }
1950 }
1951
1952 if (have_addrs != ISC_TRUE)
1953 rval = ISC_R_ADDRNOTAVAIL;
1954
1955 return rval;
1956}
1957
6d7f9584
FD
1958/* status code <-> action matrix for the client in INIT state
1959 * (rapid/commit). Returns always false as no action is defined.
1960 */
1961static isc_boolean_t
1962dhc6_init_action(struct client_state *client, isc_result_t rval,
1963 unsigned code)
1964{
1965 if (client == NULL)
1966 return ISC_R_INVALIDARG;
1967
1968 if (rval == ISC_R_SUCCESS)
1969 return ISC_FALSE;
1970
1971 /* No possible action in any case... */
1972 return ISC_FALSE;
1973}
1974
98bd7ca0
DH
1975/* status code <-> action matrix for the client in SELECT state
1976 * (request/reply). Returns true if action was taken (and the
1977 * packet should be ignored), or false if no action was taken.
1978 */
1979static isc_boolean_t
1980dhc6_select_action(struct client_state *client, isc_result_t rval,
1981 unsigned code)
1982{
1983 struct dhc6_lease *lease;
1984
1985 if (client == NULL)
1986 return ISC_R_INVALIDARG;
1987
1988 if (rval == ISC_R_SUCCESS)
1989 return ISC_FALSE;
1990
1991 switch (code) {
1992 /* We may have an earlier failure status code (so no
1993 * success rval), and a success code now. This
1994 * doesn't upgrade the rval to success, but it does
1995 * mean we take no action here.
1996 */
1997 case STATUS_Success:
1998 /* Gimpy server, or possibly an attacker. */
1999 case STATUS_NoBinding:
2000 case STATUS_UseMulticast:
2001 /* Take no action. */
2002 return ISC_FALSE;
2003
2004 /* If the server can't deal with us, either try the
2005 * next advertised server, or continue retrying if there
2006 * weren't any.
2007 */
2008 default:
2009 case STATUS_UnspecFail:
2010 if (client->advertised_leases != NULL) {
e32529a5 2011 dhc6_lease_destroy(&client->selected_lease, MDL);
98bd7ca0
DH
2012 client->selected_lease = NULL;
2013
2014 start_selecting6(client);
2015
2016 break;
2017 } else /* Take no action - continue to retry. */
2018 return ISC_FALSE;
2019
2020 /* If the server has no addresses, try other servers if
2021 * we got some, otherwise go to INIT to hope for more
2022 * servers.
2023 */
2024 case STATUS_NoAddrsAvail:
2025 if (client->state == S_REBOOTING)
2026 return ISC_FALSE;
2027
2028 if (client->selected_lease == NULL)
2029 log_fatal("Impossible case at %s:%d.", MDL);
2030
e32529a5 2031 dhc6_lease_destroy(&client->selected_lease, MDL);
98bd7ca0
DH
2032 client->selected_lease = NULL;
2033
2034 if (client->advertised_leases != NULL)
2035 start_selecting6(client);
2036 else
2037 start_init6(client);
2038
2039 break;
2040
2041 /* If we got a NotOnLink from a Confirm, then we're not
2042 * on link. Kill the old-active binding and start over.
2043 *
2044 * If we got a NotOnLink from our Request, something weird
2045 * happened. Start over from scratch anyway.
2046 */
2047 case STATUS_NotOnLink:
2048 if (client->state == S_REBOOTING) {
2049 if (client->active_lease == NULL)
2050 log_fatal("Impossible case at %s:%d.", MDL);
2051
e32529a5 2052 dhc6_lease_destroy(&client->active_lease, MDL);
98bd7ca0
DH
2053 } else {
2054 if (client->selected_lease == NULL)
2055 log_fatal("Impossible case at %s:%d.", MDL);
2056
e32529a5 2057 dhc6_lease_destroy(&client->selected_lease, MDL);
98bd7ca0
DH
2058 client->selected_lease = NULL;
2059
2060 while (client->advertised_leases != NULL) {
2061 lease = client->advertised_leases;
2062 client->advertised_leases = lease->next;
2063
e32529a5 2064 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
2065 }
2066 }
2067
2068 start_init6(client);
2069 break;
2070 }
2071
2072 return ISC_TRUE;
2073}
2074
2075static void
2076dhc6_withdraw_lease(struct client_state *client)
2077{
2078 struct dhc6_ia *ia;
2079 struct dhc6_addr *addr;
98bd7ca0
DH
2080
2081 if ((client == NULL) || (client->active_lease == NULL))
2082 return;
2083
2084 for (ia = client->active_lease->bindings ; ia != NULL ;
2085 ia = ia->next) {
2086 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
2087 addr->max_life = addr->preferred_life = 0;
2088 }
2089 }
2090
2091 /* Perform expiry. */
2092 do_expire(client);
2093}
2094
2095/* status code <-> action matrix for the client in BOUND state
2096 * (request/reply). Returns true if action was taken (and the
2097 * packet should be ignored), or false if no action was taken.
2098 */
2099static isc_boolean_t
2100dhc6_reply_action(struct client_state *client, isc_result_t rval,
2101 unsigned code)
2102{
2103
2104 if (client == NULL)
2105 return ISC_R_INVALIDARG;
2106
2107 if (rval == ISC_R_SUCCESS)
2108 return ISC_FALSE;
2109
2110 switch (code) {
2111 /* It's possible an earlier status code set rval to a failure
2112 * code, and we've encountered a later success.
2113 */
2114 case STATUS_Success:
2115 /* In "refreshes" (where we get replies), we probably
2116 * still have a valid lease. So "take no action" and
2117 * the upper levels will keep retrying until the lease
2118 * expires (or we rebind).
2119 */
2120 case STATUS_UnspecFail:
2121 /* For unknown codes...it's a soft (retryable) error. */
2122 default:
2123 return ISC_FALSE;
2124
2125 /* The server is telling us to use a multicast address, so
2126 * we have to delete the unicast option from the active
2127 * lease, then allow retransmission to occur normally.
2128 * (XXX: It might be preferable in this case to retransmit
2129 * sooner than the current interval, but for now we don't.)
2130 */
2131 case STATUS_UseMulticast:
2132 if(client->active_lease != NULL)
2133 delete_option(&dhcp_universe,
2134 client->active_lease->options,
2135 D6O_UNICAST);
2136 return ISC_FALSE;
2137
2138 /* "When the client receives a NotOnLink status from the
2139 * server in response to a Request, the client can either
2140 * re-issue the Request without specifying any addresses
2141 * or restart the DHCP server discovery process."
2142 *
2143 * This is strange. If competing server evaluation is
2144 * useful (and therefore in the protocol), then why would
2145 * a client's first reaction be to request from the same
2146 * server on a different link? Surely you'd want to
2147 * re-evaluate your server selection.
2148 *
2149 * Well, I guess that's the answer.
2150 */
2151 case STATUS_NotOnLink:
2152 /* In this case, we need to rescind all current active
2153 * bindings (just 'expire' them all normally, if early).
2154 * They're no use to us on the wrong link. Then head back
2155 * to init, redo server selection and get new addresses.
2156 */
2157 dhc6_withdraw_lease(client);
2158 return ISC_TRUE;
2159
2160 /* "If the status code is NoAddrsAvail, the client has
2161 * received no usable addresses in the IA and may choose
2162 * to try obtaining addresses for the IA from another
2163 * server."
2164 */
2165 case STATUS_NoAddrsAvail:
2166 /* Head back to init, keeping any active bindings (!). */
2167 start_init6(client);
2168 break;
2169
2170 /* - sends a Request message if the IA contained a Status
2171 * Code option with the NoBinding status (and does not
2172 * send any additional Renew/Rebind messages)
2173 */
2174 case STATUS_NoBinding:
2175 if (client->advertised_leases != NULL)
2176 log_fatal("Impossible condition at %s:%d.", MDL);
2177
2178 client->advertised_leases =
2179 dhc6_dup_lease(client->active_lease, MDL);
2180 start_selecting6(client);
2181 break;
2182 }
2183
2184 return ISC_TRUE;
2185}
2186
2187/* Look at a new and old lease, and make sure the new information is not
2188 * losing us any state.
2189 */
2190static isc_result_t
2191dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
2192{
2193 isc_boolean_t (*action)(struct client_state *, isc_result_t, unsigned);
2194 struct dhc6_ia *ia;
2195 struct dhc6_addr *addr;
28868515 2196 isc_result_t rval = ISC_R_SUCCESS;
98bd7ca0 2197 unsigned code;
1d9774ab 2198 const char *scope;
98bd7ca0
DH
2199 int nscore, sscore;
2200
2201 if ((client == NULL) || (new == NULL))
2202 return ISC_R_INVALIDARG;
2203
2204 switch (client->state) {
6d7f9584
FD
2205 case S_INIT:
2206 action = dhc6_init_action;
2207 break;
2208
98bd7ca0
DH
2209 case S_SELECTING:
2210 case S_REBOOTING:
2211 action = dhc6_select_action;
2212 break;
2213
2214 case S_RENEWING:
2215 case S_REBINDING:
2216 action = dhc6_reply_action;
2217 break;
2218
2219 default:
2220 log_fatal("Impossible condition at %s:%d.", MDL);
2221 return ISC_R_CANCELED;
2222 }
2223
2224 /* If there is a code to extract, and if there is some
2225 * action to take based on that code, then take the action
2226 * and do not continue.
2227 */
2228 rval = dhc6_check_status(rval, new->options, "message", &code);
2229 if (action(client, rval, code))
2230 return ISC_R_CANCELED;
2231
2232 for (ia = new->bindings ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
2233 switch (ia->ia_type) {
2234 case D6O_IA_NA:
2235 default:
2236 scope = "IA_NA";
2237 break;
2238 case D6O_IA_TA:
2239 scope = "IA_TA";
2240 break;
2241 case D6O_IA_PD:
2242 scope = "IA_PD";
2243 break;
2244 }
2245 rval = dhc6_check_status(rval, ia->options,
2246 scope, &code);
98bd7ca0
DH
2247 if (action(client, rval, code))
2248 return ISC_R_CANCELED;
2249
2250 for (addr = ia->addrs ; addr != NULL ;
2251 addr = addr->next) {
1d9774ab
FD
2252 if (ia->ia_type != D6O_IA_PD)
2253 scope = "IAADDR";
2254 else
2255 scope = "IAPREFIX";
98bd7ca0 2256 rval = dhc6_check_status(rval, addr->options,
1d9774ab 2257 scope, &code);
98bd7ca0
DH
2258 if (action(client, rval, code))
2259 return ISC_R_CANCELED;
2260 }
2261 }
2262
9ab0cc6a
DH
2263 /* A Confirm->Reply is unsuitable for comparison to the old lease. */
2264 if (client->state == S_REBOOTING)
2265 return rval;
2266
6d7f9584
FD
2267 /* No old lease in rapid-commit. */
2268 if (client->state == S_INIT)
2269 return rval;
2270
98bd7ca0
DH
2271 switch (client->state) {
2272 case S_SELECTING:
2273 /* Compare the new lease with the selected lease to make
2274 * sure there is no risky business.
2275 */
0c20eab3
DH
2276 nscore = dhc6_score_lease(client, new);
2277 sscore = dhc6_score_lease(client, client->selected_lease);
98bd7ca0
DH
2278 if ((client->advertised_leases != NULL) &&
2279 (nscore < (sscore / 2))) {
2280 /* XXX: An attacker might reply this way to make
2281 * XXX: sure we latch onto their configuration.
2282 * XXX: We might want to ignore the packet and
2283 * XXX: schedule re-selection at the next timeout?
2284 */
2285 log_error("PRC: BAIT AND SWITCH detected. Score of "
2286 "supplied lease (%d) is substantially "
2287 "smaller than the advertised score (%d). "
2288 "Trying other servers.",
2289 nscore, sscore);
2290
e32529a5 2291 dhc6_lease_destroy(&client->selected_lease, MDL);
98bd7ca0
DH
2292 client->selected_lease = NULL;
2293
2294 start_selecting6(client);
2295
2296 return ISC_R_CANCELED;
2297 }
2298 break;
2299
2300 case S_RENEWING:
2301 case S_REBINDING:
2302 /* This leaves one RFC3315 status check unimplemented:
2303 *
2304 * - sends a Renew/Rebind if the IA is not in the Reply
2305 * message
2306 *
2307 * We rely on the scheduling system to note that the IA has
2308 * not left Renewal/Rebinding/whatever since it still carries
2309 * old times from the last successful binding. So this is
2310 * implemented actually, just not explicitly.
2311 */
2312 break;
2313
2314 default:
2315 log_fatal("REALLY impossible condition at %s:%d.", MDL);
2316 return ISC_R_CANCELED;
2317 }
2318
2319 return rval;
2320}
2321
2322/* While in init state, we only collect advertisements. If there happens
2323 * to be an advertisement with a preference option of 255, that's an
2324 * automatic exit. Otherwise, we collect advertisements until our timeout
2325 * expires (client->RT).
2326 */
2327void
2328init_handler(struct packet *packet, struct client_state *client)
2329{
28868515 2330 struct dhc6_lease *lease;
98bd7ca0
DH
2331
2332 /* In INIT state, we send solicits, we only expect to get
6d7f9584 2333 * advertises (rapid commit has its own handler).
98bd7ca0
DH
2334 */
2335 if (packet->dhcpv6_msg_type != DHCPV6_ADVERTISE)
2336 return;
2337
2338 /* RFC3315 section 15.3 validation (same as 15.10 since we
2339 * always include a client id).
2340 */
2341 if (!valid_reply(packet, client)) {
2342 log_error("Invalid Advertise - rejecting.");
2343 return;
2344 }
2345
2346 lease = dhc6_leaseify(packet);
2347
2348 if (dhc6_check_advertise(lease) != ISC_R_SUCCESS) {
2349 log_debug("PRC: Lease failed to satisfy.");
e32529a5 2350 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
2351 return;
2352 }
2353
2354 insert_lease(&client->advertised_leases, lease);
2355
2356 /* According to RFC3315 section 17.1.2, the client MUST wait for
2357 * the first RT before selecting a lease. But on the 400th RT,
2358 * we dont' want to wait the full timeout if we finally get an
2359 * advertise. We could probably wait a second, but ohwell,
2360 * RFC3315 doesn't say so.
2361 *
2362 * If the lease is highest possible preference, 255, RFC3315 claims
2363 * we should continue immediately even on the first RT. We probably
2364 * should not if the advertise contains less than one IA and address.
2365 */
2366 if ((client->txcount > 1) ||
0c20eab3
DH
2367 ((lease->pref == 255) &&
2368 (dhc6_score_lease(client, lease) > 150))) {
98bd7ca0
DH
2369 log_debug("RCV: Advertisement immediately selected.");
2370 cancel_timeout(do_init6, client);
2371 start_selecting6(client);
2372 } else
2373 log_debug("RCV: Advertisement recorded.");
2374}
2375
6d7f9584
FD
2376/* Specific version of init_handler() for rapid-commit.
2377 */
2378void
2379rapid_commit_handler(struct packet *packet, struct client_state *client)
2380{
2381 struct dhc6_lease *lease;
2382 isc_result_t check_status;
2383
2384 /* On ADVERTISE just fall back to the init_handler().
2385 */
2386 if (packet->dhcpv6_msg_type == DHCPV6_ADVERTISE) {
2387 init_handler(packet, client);
2388 return;
2389 } else if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
2390 return;
2391
2392 /* RFC3315 section 15.10 validation (same as 15.3 since we
2393 * always include a client id).
2394 */
2395 if (!valid_reply(packet, client)) {
2396 log_error("Invalid Reply - rejecting.");
2397 return;
2398 }
2399
2400 /* A rapid-commit option MUST be here. */
2401 if (lookup_option(&dhcpv6_universe, packet->options,
2402 D6O_RAPID_COMMIT) == 0) {
2403 log_error("Reply without Rapid-Commit - rejecting.");
2404 return;
2405 }
2406
2407 lease = dhc6_leaseify(packet);
2408
2409 /* This is an out of memory condition...hopefully a temporary
2410 * problem. Returning now makes us try to retransmit later.
2411 */
2412 if (lease == NULL)
2413 return;
2414
2415 check_status = dhc6_check_reply(client, lease);
2416 if (check_status != ISC_R_SUCCESS) {
2417 dhc6_lease_destroy(&lease, MDL);
2418 return;
2419 }
2420
2421 /* Jump to the selecting state. */
2422 cancel_timeout(do_init6, client);
2423 client->state = S_SELECTING;
2424
2425 /* Merge any bindings in the active lease (if there is one) into
2426 * the new active lease.
2427 */
2428 dhc6_merge_lease(client->active_lease, lease);
2429
2430 /* Cleanup if a previous attempt to go bound failed. */
2431 if (client->old_lease != NULL) {
2432 dhc6_lease_destroy(&client->old_lease, MDL);
2433 client->old_lease = NULL;
2434 }
2435
2436 /* Make this lease active and BIND to it. */
2437 if (client->active_lease != NULL)
2438 client->old_lease = client->active_lease;
2439 client->active_lease = lease;
2440
2441 /* We're done with the ADVERTISEd leases, if any. */
2442 while(client->advertised_leases != NULL) {
2443 lease = client->advertised_leases;
2444 client->advertised_leases = lease->next;
2445
2446 dhc6_lease_destroy(&lease, MDL);
2447 }
2448
2449 start_bound(client);
2450}
2451
98bd7ca0
DH
2452/* Find the 'best' lease in the cache of advertised leases (usually). From
2453 * RFC3315 Section 17.1.3:
2454 *
2455 * Upon receipt of one or more valid Advertise messages, the client
2456 * selects one or more Advertise messages based upon the following
2457 * criteria.
2458 *
2459 * - Those Advertise messages with the highest server preference value
2460 * are preferred over all other Advertise messages.
2461 *
2462 * - Within a group of Advertise messages with the same server
2463 * preference value, a client MAY select those servers whose
2464 * Advertise messages advertise information of interest to the
2465 * client. For example, the client may choose a server that returned
2466 * an advertisement with configuration options of interest to the
2467 * client.
2468 *
2469 * - The client MAY choose a less-preferred server if that server has a
2470 * better set of advertised parameters, such as the available
2471 * addresses advertised in IAs.
2472 *
2473 * Note that the first and third contradict each other. The third should
2474 * probably be taken to mean that the client should prefer answers that
2475 * offer bindings, even if that violates the preference rule.
2476 *
2477 * The above also isn't deterministic where there are ties. So the final
2478 * tiebreaker we add, if all other values are equal, is to compare the
2479 * server identifiers and to select the numerically lower one.
2480 */
2481static struct dhc6_lease *
0c20eab3 2482dhc6_best_lease(struct client_state *client, struct dhc6_lease **head)
98bd7ca0
DH
2483{
2484 struct dhc6_lease **rpos, *rval, **candp, *cand;
2485 int cscore, rscore;
2486
2487 if (head == NULL || *head == NULL)
2488 return NULL;
2489
2490 rpos = head;
2491 rval = *rpos;
0c20eab3 2492 rscore = dhc6_score_lease(client, rval);
98bd7ca0
DH
2493 candp = &rval->next;
2494 cand = *candp;
2495
2496 log_debug("PRC: Considering best lease.");
2497 log_debug("PRC: X-- Initial candidate %s (s: %d, p: %u).",
2498 print_hex_1(rval->server_id.len,
2499 rval->server_id.data, 48),
2500 rscore, (unsigned)rval->pref);
2501
2502 for (; cand != NULL ; candp = &cand->next, cand = *candp) {
0c20eab3 2503 cscore = dhc6_score_lease(client, cand);
98bd7ca0
DH
2504
2505 log_debug("PRC: X-- Candidate %s (s: %d, p: %u).",
2506 print_hex_1(cand->server_id.len,
2507 cand->server_id.data, 48),
2508 cscore, (unsigned)cand->pref);
2509
2510 /* Above you'll find quoted RFC3315 Section 17.1.3.
2511 *
2512 * The third clause tells us to give up on leases that
2513 * have no bindings even if their preference is better.
2514 * So where our 'selected' lease's score is less than 150
2515 * (1 ia + 1 addr), choose any candidate >= 150.
2516 *
2517 * The first clause tells us to make preference the primary
2518 * deciding factor. So if it's lower, reject, if it's
2519 * higher, select.
2520 *
2521 * The second clause tells us where the preference is
2522 * equal, we should use 'our judgement' of what we like
2523 * to see in an advertisement primarily.
2524 *
2525 * But there can still be a tie. To make this deterministic,
2526 * we compare the server identifiers and select the binary
2527 * lowest.
2528 *
2529 * Since server id's are unique in this list, there is
2530 * no further tie to break.
2531 */
2532 if ((rscore < 150) && (cscore >= 150)) {
a0006737 2533 log_debug("PRC: | X-- Selected, has bindings.");
98bd7ca0
DH
2534 } else if (cand->pref < rval->pref) {
2535 log_debug("PRC: | X-- Rejected, lower preference.");
2536 continue;
2537 } else if (cand->pref > rval->pref) {
2538 log_debug("PRC: | X-- Selected, higher preference.");
2539 } else if (cscore > rscore) {
2540 log_debug("PRC: | X-- Selected, equal preference, "
2541 "higher score.");
2542 } else if (cscore < rscore) {
2543 log_debug("PRC: | X-- Rejected, equal preference, "
2544 "lower score.");
2545 continue;
2546 } else if ((cand->server_id.len < rval->server_id.len) ||
2547 ((cand->server_id.len == rval->server_id.len) &&
2548 (memcmp(cand->server_id.data,
2549 rval->server_id.data,
2550 cand->server_id.len) < 0))) {
2551 log_debug("PRC: | X-- Selected, equal preference, "
2552 "equal score, binary lesser server ID.");
2553 } else {
2554 log_debug("PRC: | X-- Rejected, equal preference, "
2555 "equal score, binary greater server ID.");
2556 continue;
2557 }
2558
2559 rpos = candp;
2560 rval = cand;
2561 rscore = cscore;
2562 }
2563
2564 /* Remove the selected lease from the chain. */
2565 *rpos = rval->next;
2566
2567 return rval;
2568}
2569
2570/* Select a lease out of the advertised leases and setup state to try and
2571 * acquire that lease.
2572 */
2573void
2574start_selecting6(struct client_state *client)
2575{
2576 struct dhc6_lease *lease;
98bd7ca0
DH
2577
2578 if (client->advertised_leases == NULL) {
2579 log_error("Can not enter DHCPv6 SELECTING state with no "
2580 "leases to select from!");
2581 return;
2582 }
2583
2584 log_debug("PRC: Selecting best advertised lease.");
2585 client->state = S_SELECTING;
2586
0c20eab3 2587 lease = dhc6_best_lease(client, &client->advertised_leases);
98bd7ca0
DH
2588
2589 if (lease == NULL)
2590 log_fatal("Impossible error at %s:%d.", MDL);
2591
2592 client->selected_lease = lease;
2593
98bd7ca0 2594 /* Set timers per RFC3315 section 18.1.1. */
be62cf06
FD
2595 client->IRT = REQ_TIMEOUT * 100;
2596 client->MRT = REQ_MAX_RT * 100;
98bd7ca0
DH
2597 client->MRC = REQ_MAX_RC;
2598 client->MRD = 0;
2599
2600 dhc6_retrans_init(client);
2601
2602 client->v6_handler = reply_handler;
2603
2604 /* ("re")transmit the first packet. */
2605 do_select6(client);
2606}
2607
2608/* Transmit a Request to select a lease offered in Advertisements. In
2609 * the event of failure, either move on to the next-best advertised lease,
2610 * or head back to INIT state if there are none.
2611 */
2612void
2613do_select6(void *input)
2614{
2615 struct client_state *client;
2616 struct dhc6_lease *lease;
98bd7ca0 2617 struct data_string ds;
be62cf06 2618 struct timeval elapsed, tv;
98bd7ca0 2619 int abort = ISC_FALSE;
28868515 2620 int send_ret;
98bd7ca0
DH
2621
2622 client = input;
2623
2624 /* 'lease' is fewer characters to type. */
2625 lease = client->selected_lease;
2626 if (lease == NULL || lease->bindings == NULL) {
2627 log_error("Illegal to attempt selection without selecting "
2628 "a lease.");
2629 return;
2630 }
2631
2632 if ((client->MRC != 0) && (client->txcount > client->MRC)) {
2633 log_info("Max retransmission count exceeded.");
2634 abort = ISC_TRUE;
2635 }
2636
be62cf06
FD
2637 /*
2638 * Start_time starts at the first transmission.
2639 */
2640 if (client->txcount == 0) {
2641 client->start_time.tv_sec = cur_tv.tv_sec;
2642 client->start_time.tv_usec = cur_tv.tv_usec;
2643 }
2644
2645 /* elapsed = cur - start */
2646 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
2647 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
2648 if (elapsed.tv_usec < 0) {
2649 elapsed.tv_sec -= 1;
2650 elapsed.tv_usec += 1000000;
2651 }
2652 if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
98bd7ca0
DH
2653 log_info("Max retransmission duration exceeded.");
2654 abort = ISC_TRUE;
2655 }
2656
2657 if (abort) {
2658 log_debug("PRC: Lease %s failed.",
2659 print_hex_1(lease->server_id.len,
2660 lease->server_id.data, 56));
2661
2662 /* Get rid of the lease that timed/counted out. */
e32529a5 2663 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
2664 client->selected_lease = NULL;
2665
2666 /* If there are more leases great. If not, get more. */
2667 if (client->advertised_leases != NULL)
2668 start_selecting6(client);
2669 else
2670 start_init6(client);
2671
2672 return;
2673 }
2674
2675 /* Now make a packet that looks suspiciously like the one we
2676 * got from the server. But different.
2677 *
2678 * XXX: I guess IAID is supposed to be something the client
2679 * indicates and uses as a key to its internal state. It is
2680 * kind of odd to ask the server for IA's whose IAID the client
2681 * did not manufacture. We first need a formal dhclient.conf
2682 * construct for the iaid, then we can delve into this matter
2683 * more properly. In the time being, this will work.
2684 */
2685 memset(&ds, 0, sizeof(ds));
2686 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
2687 log_error("Unable to allocate memory for REQUEST.");
2688 return;
2689 }
2690 ds.data = ds.buffer->data;
2691 ds.len = 4;
2692
2693 ds.buffer->data[0] = DHCPV6_REQUEST;
2694 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
2695
2696 /* Form an elapsed option. */
be62cf06
FD
2697 /* Maximum value is 65535 1/100s coded as 0xffff. */
2698 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
2699 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
98bd7ca0 2700 client->elapsed = 0xffff;
be62cf06
FD
2701 } else {
2702 client->elapsed = elapsed.tv_sec * 100;
2703 client->elapsed += elapsed.tv_usec / 10000;
2704 }
98bd7ca0 2705
be62cf06
FD
2706 if (client->elapsed == 0)
2707 log_debug("XMT: Forming Request, 0 ms elapsed.");
2708 else
2709 log_debug("XMT: Forming Request, %u0 ms elapsed.",
2710 (unsigned)client->elapsed);
98bd7ca0
DH
2711
2712 client->elapsed = htons(client->elapsed);
2713
2714 make_client6_options(client, &client->sent_options, lease,
2715 DHCPV6_REQUEST);
2716
2717 /* Fetch any configured 'sent' options (includes DUID) in wire format.
2718 */
2719 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
2720 NULL, client->sent_options, &global_scope,
2721 &dhcpv6_universe);
2722
1d9774ab
FD
2723 /* Now append any IA's, and within them any IAADDR/IAPREFIXs. */
2724 if (dhc6_add_ia_na(client, &ds, lease,
2725 DHCPV6_REQUEST) != ISC_R_SUCCESS) {
98bd7ca0
DH
2726 data_string_forget(&ds, MDL);
2727 return;
2728 }
2729
be62cf06 2730 log_info("XMT: Request on %s, interval %ld0ms.",
98bd7ca0 2731 client->name ? client->name : client->interface->name,
9aa669fc 2732 (long int)client->RT);
98bd7ca0
DH
2733
2734 send_ret = send_packet6(client->interface,
2735 ds.data, ds.len, &DHCPv6DestAddr);
2736 if (send_ret != ds.len) {
2737 log_error("dhc6: send_packet6() sent %d of %d bytes",
2738 send_ret, ds.len);
2739 }
2740
2741 data_string_forget(&ds, MDL);
2742
be62cf06
FD
2743 /* Wait RT */
2744 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
2745 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
2746 if (tv.tv_usec >= 1000000) {
2747 tv.tv_sec += 1;
2748 tv.tv_usec -= 1000000;
2749 }
2750 add_timeout(&tv, do_select6, client, NULL, NULL);
98bd7ca0
DH
2751
2752 dhc6_retrans_advance(client);
2753}
2754
1d9774ab
FD
2755/* For each IA_NA in the lease, for each address in the IA_NA,
2756 * append that information onto the packet-so-far.
98bd7ca0
DH
2757 */
2758static isc_result_t
1d9774ab
FD
2759dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
2760 struct dhc6_lease *lease, u_int8_t message)
98bd7ca0
DH
2761{
2762 struct data_string iads;
2763 struct data_string addrds;
2764 struct dhc6_addr *addr;
2765 struct dhc6_ia *ia;
2766 isc_result_t rval = ISC_R_SUCCESS;
2767 TIME t1, t2;
af5fa176 2768
98bd7ca0
DH
2769 memset(&iads, 0, sizeof(iads));
2770 memset(&addrds, 0, sizeof(addrds));
af5fa176
EH
2771 for (ia = lease->bindings;
2772 ia != NULL && rval == ISC_R_SUCCESS;
2773 ia = ia->next) {
1d9774ab
FD
2774 if (ia->ia_type != D6O_IA_NA)
2775 continue;
2776
98bd7ca0 2777 if (!buffer_allocate(&iads.buffer, 12, MDL)) {
af5fa176
EH
2778 log_error("Unable to allocate memory for IA_NA.");
2779 rval = ISC_R_NOMEMORY;
98bd7ca0
DH
2780 break;
2781 }
98bd7ca0 2782
af5fa176 2783 /* Copy the IAID into the packet buffer. */
98bd7ca0 2784 memcpy(iads.buffer->data, ia->iaid, 4);
af5fa176
EH
2785 iads.data = iads.buffer->data;
2786 iads.len = 12;
98bd7ca0 2787
af5fa176
EH
2788 switch (message) {
2789 case DHCPV6_REQUEST:
2790 case DHCPV6_RENEW:
2791 case DHCPV6_REBIND:
2792
2793 t1 = client->config->requested_lease / 2;
2794 t2 = t1 + (t1 / 2);
98bd7ca0 2795#if MAX_TIME > 0xffffffff
af5fa176
EH
2796 if (t1 > 0xffffffff)
2797 t1 = 0xffffffff;
2798 if (t2 > 0xffffffff)
2799 t2 = 0xffffffff;
98bd7ca0 2800#endif
af5fa176
EH
2801 putULong(iads.buffer->data + 4, t1);
2802 putULong(iads.buffer->data + 8, t2);
2803
2804 log_debug("XMT: X-- IA_NA %s",
2805 print_hex_1(4, iads.data, 59));
2806 log_debug("XMT: | X-- Requested renew +%u",
2807 (unsigned) t1);
2808 log_debug("XMT: | X-- Requested rebind +%u",
2809 (unsigned) t2);
2810 break;
2811
2812 case DHCPV6_CONFIRM:
2813 case DHCPV6_RELEASE:
2814 /* Set t1 and t2 to zero; server will ignore them */
2815 memset(iads.buffer->data + 4, 0, 8);
2816 log_debug("XMT: X-- IA_NA %s",
2817 print_hex_1(4, iads.buffer->data, 55));
2818
2819 break;
2820
2821 default:
2822 log_fatal("Impossible condition at %s:%d.", MDL);
2823 }
98bd7ca0 2824
af5fa176 2825 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
703873ab
DH
2826 /*
2827 * Do not confirm expired addresses, do not request
2828 * expired addresses (but we keep them around for
2829 * solicit).
2830 */
2831 if (addr->flags & DHC6_ADDR_EXPIRED)
2832 continue;
2833
af5fa176
EH
2834 if (addr->address.len != 16) {
2835 log_error("Illegal IPv6 address length (%d), "
2836 "ignoring. (%s:%d)",
2837 addr->address.len, MDL);
2838 continue;
2839 }
98bd7ca0 2840
98bd7ca0
DH
2841 if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
2842 log_error("Unable to allocate memory for "
2843 "IAADDR.");
af5fa176 2844 rval = ISC_R_NOMEMORY;
98bd7ca0
DH
2845 break;
2846 }
af5fa176 2847
98bd7ca0
DH
2848 addrds.data = addrds.buffer->data;
2849 addrds.len = 24;
2850
af5fa176 2851 /* Copy the address into the packet buffer. */
98bd7ca0 2852 memcpy(addrds.buffer->data, addr->address.iabuf, 16);
98bd7ca0 2853
af5fa176
EH
2854 /* Copy in additional information as appropriate */
2855 switch (message) {
2856 case DHCPV6_REQUEST:
2857 case DHCPV6_RENEW:
2858 case DHCPV6_REBIND:
2859 t1 = client->config->requested_lease;
2860 t2 = t1 + 300;
2861 putULong(addrds.buffer->data + 16, t1);
2862 putULong(addrds.buffer->data + 20, t2);
2863
2864 log_debug("XMT: | | X-- IAADDR %s",
2865 piaddr(addr->address));
2866 log_debug("XMT: | | | X-- Preferred "
2867 "lifetime +%u", (unsigned)t1);
2868 log_debug("XMT: | | | X-- Max lifetime +%u",
2869 (unsigned)t2);
2870
2871 break;
2872
2873 case DHCPV6_CONFIRM:
2874 /*
2875 * Set preferred and max life to zero,
2876 * per 17.1.3.
2877 */
2878 memset(addrds.buffer->data + 16, 0, 8);
2879 log_debug("XMT: | X-- Confirm Address %s",
2880 piaddr(addr->address));
2881 break;
2882
2883 case DHCPV6_RELEASE:
2884 /* Preferred and max life are irrelevant */
2885 memset(addrds.buffer->data + 16, 0, 8);
2886 log_debug("XMT: | X-- Release Address %s",
2887 piaddr(addr->address));
2888 break;
2889
2890 default:
2891 log_fatal("Impossible condition at %s:%d.",
2892 MDL);
2893 }
98bd7ca0
DH
2894
2895 append_option(&iads, &dhcpv6_universe, iaaddr_option,
af5fa176 2896 &addrds);
98bd7ca0
DH
2897 data_string_forget(&addrds, MDL);
2898 }
2899
af5fa176
EH
2900 /*
2901 * It doesn't make sense to make a request without an
98bd7ca0
DH
2902 * address.
2903 */
af5fa176
EH
2904 if (ia->addrs == NULL) {
2905 log_debug("!!!: V IA_NA has no IAADDRs - removed.");
2906 rval = ISC_R_FAILURE;
2907 } else if (rval == ISC_R_SUCCESS) {
98bd7ca0
DH
2908 log_debug("XMT: V IA_NA appended.");
2909 append_option(packet, &dhcpv6_universe, ia_na_option,
2910 &iads);
98bd7ca0
DH
2911 }
2912
2913 data_string_forget(&iads, MDL);
2914 }
2915
af5fa176 2916 return rval;
98bd7ca0
DH
2917}
2918
2919/* reply_handler() accepts a Reply while we're attempting Select or Renew or
2920 * Rebind. Basically any Reply packet.
2921 */
2922void
2923reply_handler(struct packet *packet, struct client_state *client)
2924{
28868515 2925 struct dhc6_lease *lease;
98bd7ca0
DH
2926 isc_result_t check_status;
2927
2928 if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
2929 return;
2930
2931 /* RFC3315 section 15.10 validation (same as 15.3 since we
2932 * always include a client id).
2933 */
2934 if (!valid_reply(packet, client)) {
7b22a9b4 2935 log_error("Invalid Reply - rejecting.");
98bd7ca0
DH
2936 return;
2937 }
2938
2939 lease = dhc6_leaseify(packet);
2940
2941 /* This is an out of memory condition...hopefully a temporary
2942 * problem. Returning now makes us try to retransmit later.
2943 */
2944 if (lease == NULL)
2945 return;
2946
2947 check_status = dhc6_check_reply(client, lease);
2948 if (check_status != ISC_R_SUCCESS) {
e32529a5 2949 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
2950
2951 /* If no action was taken, but there is an error, then
2952 * we wait for a retransmission.
2953 */
2954 if (check_status != ISC_R_CANCELED)
2955 return;
2956 }
2957
a0006737 2958 /* We're done retransmitting at this point. */
98bd7ca0
DH
2959 cancel_timeout(do_confirm6, client);
2960 cancel_timeout(do_select6, client);
2961 cancel_timeout(do_refresh6, client);
af5fa176 2962 cancel_timeout(do_release6, client);
98bd7ca0
DH
2963
2964 /* Action was taken, so now that we've torn down our scheduled
2965 * retransmissions, return.
2966 */
2967 if (check_status == ISC_R_CANCELED)
2968 return;
2969
2970 if (client->selected_lease != NULL) {
e32529a5 2971 dhc6_lease_destroy(&client->selected_lease, MDL);
98bd7ca0
DH
2972 client->selected_lease = NULL;
2973 }
2974
af5fa176
EH
2975 /* If this is in response to a Release, clean up and return. */
2976 if (client->state == S_STOPPED) {
2977 if (client->active_lease == NULL)
2978 log_fatal("Impossible condition at %s:%d.", MDL);
2979
e32529a5 2980 dhc6_lease_destroy(&client->active_lease, MDL);
af5fa176
EH
2981 client->active_lease = NULL;
2982 return;
2983 }
2984
98bd7ca0
DH
2985 /* If this is in response to a confirm, we use the lease we've
2986 * already got, not the reply we were sent.
2987 */
2988 if (client->state == S_REBOOTING) {
2989 if (client->active_lease == NULL)
2990 log_fatal("Impossible condition at %s:%d.", MDL);
2991
e32529a5 2992 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
2993 start_bound(client);
2994 return;
2995 }
2996
2997 /* Merge any bindings in the active lease (if there is one) into
2998 * the new active lease.
2999 */
3000 dhc6_merge_lease(client->active_lease, lease);
3001
3002 /* Cleanup if a previous attempt to go bound failed. */
3003 if (client->old_lease != NULL) {
e32529a5 3004 dhc6_lease_destroy(&client->old_lease, MDL);
98bd7ca0
DH
3005 client->old_lease = NULL;
3006 }
3007
3008 /* Make this lease active and BIND to it. */
3009 if (client->active_lease != NULL)
3010 client->old_lease = client->active_lease;
3011 client->active_lease = lease;
3012
3013 /* We're done with the ADVERTISEd leases, if any. */
3014 while(client->advertised_leases != NULL) {
3015 lease = client->advertised_leases;
3016 client->advertised_leases = lease->next;
3017
e32529a5 3018 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
3019 }
3020
3021 start_bound(client);
3022}
3023
3024/* DHCPv6 packets are a little sillier than they needed to be - the root
3025 * packet contains options, then IA's which contain options, then within
3026 * that IAADDR's which contain options.
3027 *
3028 * To sort this out at dhclient-script time (which fetches config parameters
3029 * in environment variables), start_bound() iterates over each IAADDR, and
3030 * calls this function to marshall an environment variable set that includes
3031 * the most-specific option values related to that IAADDR in particular.
3032 *
a0006737 3033 * To achieve this, we load environment variables for the root options space,
98bd7ca0
DH
3034 * then the IA, then the IAADDR. Any duplicate option names will be
3035 * over-written by the later versions.
3036 */
3037static void
06eb8bab 3038dhc6_marshall_values(const char *prefix, struct client_state *client,
98bd7ca0
DH
3039 struct dhc6_lease *lease, struct dhc6_ia *ia,
3040 struct dhc6_addr *addr)
3041{
3042 /* Option cache contents, in descending order of
3043 * scope.
3044 */
3045 if ((lease != NULL) && (lease->options != NULL))
3046 script_write_params6(client, prefix, lease->options);
3047 if ((ia != NULL) && (ia->options != NULL))
3048 script_write_params6(client, prefix, ia->options);
3049 if ((addr != NULL) && (addr->options != NULL))
3050 script_write_params6(client, prefix, addr->options);
3051
3052 /* addr fields. */
3053 if (addr != NULL) {
3054 /* Current practice is that all subnets are /64's, but
3055 * some suspect this may not be permanent.
3056 */
3057 client_envadd(client, prefix, "ip6_prefixlen", "%d", 64);
3058 client_envadd(client, prefix, "ip6_address", "%s",
3059 piaddr(addr->address));
3060 client_envadd(client, prefix, "life_starts", "%d",
3061 (int)(addr->starts));
3062 client_envadd(client, prefix, "preferred_life", "%d",
3063 (int)(addr->preferred_life));
3064 client_envadd(client, prefix, "max_life", "%d",
3065 (int)(addr->max_life));
3066 }
3067
3068 /* ia fields. */
3069 if (ia != NULL) {
3070 client_envadd(client, prefix, "iaid", "%s",
3071 print_hex_1(4, ia->iaid, 12));
3072 client_envadd(client, prefix, "starts", "%d",
3073 (int)(ia->starts));
3074 client_envadd(client, prefix, "renew", "%u", ia->renew);
3075 client_envadd(client, prefix, "rebind", "%u", ia->rebind);
3076 }
3077}
3078
3079/* Look at where the client's active lease is sitting. If it's looking to
3080 * time out on renew, rebind, depref, or expiration, do those things.
3081 */
3082static void
3083dhc6_check_times(struct client_state *client)
3084{
3085 struct dhc6_lease *lease;
3086 struct dhc6_ia *ia;
3087 struct dhc6_addr *addr;
3088 TIME renew=MAX_TIME, rebind=MAX_TIME, depref=MAX_TIME,
3089 lo_expire=MAX_TIME, hi_expire=0, tmp;
3090 int has_addrs = ISC_FALSE;
be62cf06 3091 struct timeval tv;
98bd7ca0
DH
3092
3093 lease = client->active_lease;
3094
3095 /* Bit spammy. We should probably keep record of scheduled
3096 * events instead.
3097 */
3098 cancel_timeout(start_renew6, client);
3099 cancel_timeout(start_rebind6, client);
3100 cancel_timeout(do_depref, client);
3101 cancel_timeout(do_expire, client);
3102
3103 for(ia = lease->bindings ; ia != NULL ; ia = ia->next) {
703873ab
DH
3104 TIME this_ia_lo_expire, this_ia_hi_expire, use_expire;
3105
1d9774ab
FD
3106 if (ia->ia_type != D6O_IA_NA)
3107 continue;
3108
703873ab
DH
3109 this_ia_lo_expire = MAX_TIME;
3110 this_ia_hi_expire = 0;
3111
98bd7ca0
DH
3112 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3113 if(!(addr->flags & DHC6_ADDR_DEPREFFED)) {
3114 if (addr->preferred_life == 0xffffffff)
3115 tmp = MAX_TIME;
3116 else
3117 tmp = addr->starts +
3118 addr->preferred_life;
3119
3120 if (tmp < depref)
3121 depref = tmp;
3122 }
3123
3124 if (!(addr->flags & DHC6_ADDR_EXPIRED)) {
703873ab 3125 /* Find EPOCH-relative expiration. */
98bd7ca0
DH
3126 if (addr->max_life == 0xffffffff)
3127 tmp = MAX_TIME;
3128 else
3129 tmp = addr->starts + addr->max_life;
3130
703873ab
DH
3131 /* Make the times ia->starts relative. */
3132 tmp -= ia->starts;
3133
3134 if (tmp > this_ia_hi_expire)
3135 this_ia_hi_expire = tmp;
3136 if (tmp < this_ia_lo_expire)
3137 this_ia_lo_expire = tmp;
98bd7ca0
DH
3138
3139 has_addrs = ISC_TRUE;
3140 }
3141 }
3142
703873ab
DH
3143 /* These times are ia->starts relative. */
3144 if (this_ia_lo_expire <= (this_ia_hi_expire / 2))
3145 use_expire = this_ia_hi_expire;
3146 else
3147 use_expire = this_ia_lo_expire;
3148
3149 /*
3150 * If the auto-selected expiration time is "infinite", or
3151 * zero, assert a reasonable default.
3152 */
3153 if ((use_expire == MAX_TIME) || (use_expire <= 1))
3154 use_expire = client->config->requested_lease / 2;
3155 else
3156 use_expire /= 2;
98bd7ca0 3157
703873ab
DH
3158 if (ia->renew == 0) {
3159 tmp = ia->starts + use_expire;
98bd7ca0
DH
3160 } else if(ia->renew == 0xffffffff)
3161 tmp = MAX_TIME;
3162 else
3163 tmp = ia->starts + ia->renew;
3164
3165 if (tmp < renew)
3166 renew = tmp;
3167
3168 if (ia->rebind == 0) {
703873ab
DH
3169 /* Set rebind to 3/4 expiration interval. */
3170 tmp = ia->starts + use_expire + (use_expire / 2);
98bd7ca0
DH
3171 } else if (ia->renew == 0xffffffff)
3172 tmp = MAX_TIME;
3173 else
3174 tmp = ia->starts + ia->rebind;
3175
3176 if (tmp < rebind)
3177 rebind = tmp;
703873ab
DH
3178
3179 /*
3180 * Return expiration ranges to EPOCH relative for event
3181 * scheduling (add_timeout()).
3182 */
3183 this_ia_hi_expire += ia->starts;
3184 this_ia_lo_expire += ia->starts;
3185
3186 if (this_ia_hi_expire > hi_expire)
3187 hi_expire = this_ia_hi_expire;
3188 if (this_ia_lo_expire < lo_expire)
3189 lo_expire = this_ia_lo_expire;
98bd7ca0
DH
3190 }
3191
3192 /* If there are no addresses, give up, go to INIT.
3193 * Note that if an address is unexpired with a date in the past,
3194 * we're scheduling an expiration event to ocurr in the past. We
3195 * could probably optimize this to expire now (but then there's
3196 * recursion).
3197 *
3198 * In the future, we may decide that we're done here, or to
3199 * schedule a future request (using 4-pkt info-request model).
3200 */
3201 if (has_addrs == ISC_FALSE) {
e32529a5 3202 dhc6_lease_destroy(&client->active_lease, MDL);
98bd7ca0
DH
3203 client->active_lease = NULL;
3204
3205 /* Go back to the beginning. */
3206 start_init6(client);
3207 return;
3208 }
3209
3210 switch(client->state) {
3211 case S_BOUND:
3212 /* We'd like to hit renewing, but if rebinding has already
3213 * passed (time warp), head straight there.
3214 */
3215 if ((rebind > cur_time) && (renew < rebind)) {
3216 log_debug("PRC: Renewal event scheduled in %d seconds, "
3217 "to run for %u seconds.",
3218 (int)(renew - cur_time),
3219 (unsigned)(rebind - renew));
be62cf06
FD
3220 client->next_MRD = rebind;
3221 tv.tv_sec = renew;
3222 tv.tv_usec = 0;
3223 add_timeout(&tv, start_renew6, client, NULL, NULL);
98bd7ca0
DH
3224
3225 break;
3226 }
3227 /* FALL THROUGH */
3228 case S_RENEWING:
3229 /* While actively renewing, MRD is bounded by the time
3230 * we stop renewing and start rebinding. This helps us
3231 * process the state change on time.
3232 */
3233 client->MRD = rebind - cur_time;
3234 if (rebind != MAX_TIME) {
3235 log_debug("PRC: Rebind event scheduled in %d seconds, "
3236 "to run for %d seconds.",
3237 (int)(rebind - cur_time),
3238 (int)(hi_expire - rebind));
be62cf06
FD
3239 client->next_MRD = hi_expire;
3240 tv.tv_sec = rebind;
3241 tv.tv_usec = 0;
3242 add_timeout(&tv, start_rebind6, client, NULL, NULL);
98bd7ca0
DH
3243 }
3244 break;
3245
3246 case S_REBINDING:
3247 /* For now, we rebind up until the last lease expires. In
3248 * the future, we might want to start SOLICITing when we've
3249 * depreffed an address.
3250 */
3251 client->MRD = hi_expire - cur_time;
3252 break;
3253
3254 default:
3255 log_fatal("Impossible condition at %s:%d.", MDL);
3256 }
3257
3258 /* Separately, set a time at which we will depref and expire
3259 * leases. This might happen with multiple addresses while we
3260 * keep trying to refresh.
3261 */
3262 if (depref != MAX_TIME) {
3263 log_debug("PRC: Depreference scheduled in %d seconds.",
3264 (int)(depref - cur_time));
be62cf06
FD
3265 tv.tv_sec = depref;
3266 tv.tv_usec = 0;
3267 add_timeout(&tv, do_depref, client, NULL, NULL);
98bd7ca0
DH
3268 }
3269 if (lo_expire != MAX_TIME) {
3270 log_debug("PRC: Expiration scheduled in %d seconds.",
3271 (int)(lo_expire - cur_time));
be62cf06
FD
3272 tv.tv_sec = lo_expire;
3273 tv.tv_usec = 0;
3274 add_timeout(&tv, do_expire, client, NULL, NULL);
98bd7ca0
DH
3275 }
3276}
3277
3278/* In a given IA chain, find the IA with the same 'iaid'. */
3279static struct dhc6_ia *
1d9774ab 3280find_ia_na(struct dhc6_ia *head, const char *id)
98bd7ca0
DH
3281{
3282 struct dhc6_ia *ia;
3283
3284 for (ia = head ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
3285 if (ia->ia_type != D6O_IA_NA)
3286 continue;
98bd7ca0
DH
3287 if (memcmp(ia->iaid, id, 4) == 0)
3288 return ia;
3289 }
3290
3291 return NULL;
3292}
3293
3294/* In a given address chain, find a matching address. */
3295static struct dhc6_addr *
3296find_addr(struct dhc6_addr *head, struct iaddr *address)
3297{
3298 struct dhc6_addr *addr;
3299
3300 for (addr = head ; addr != NULL ; addr = addr->next) {
3301 if ((addr->address.len == address->len) &&
3302 (memcmp(addr->address.iabuf, address->iabuf,
3303 address->len) == 0))
3304 return addr;
3305 }
3306
3307 return NULL;
3308}
3309
3310/* Merge the bindings from the source lease into the destination lease
3311 * structure, where they are missing. We have to copy the stateful
3312 * objects rather than move them over, because later code needs to be
3313 * able to compare new versus old if they contain any bindings.
3314 */
3315static void
3316dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
3317{
3318 struct dhc6_ia *sia, *dia, *tia;
3319 struct dhc6_addr *saddr, *daddr, *taddr;
3320 int changes = 0;
3321
3322 if ((dst == NULL) || (src == NULL))
3323 return;
3324
3325 for (sia = src->bindings ; sia != NULL ; sia = sia->next) {
1d9774ab
FD
3326 if (sia->ia_type != D6O_IA_NA)
3327 continue;
3328 dia = find_ia_na(dst->bindings, (char *)sia->iaid);
98bd7ca0
DH
3329
3330 if (dia == NULL) {
3331 tia = dhc6_dup_ia(sia, MDL);
3332
3333 if (tia == NULL)
3334 log_fatal("Out of memory merging lease - "
3335 "Unable to continue without losing "
3336 "state! (%s:%d)", MDL);
3337
3338 /* XXX: consider sorting? */
3339 tia->next = dst->bindings;
3340 dst->bindings = tia;
3341 changes = 1;
3342 } else {
3343 for (saddr = sia->addrs ; saddr != NULL ;
3344 saddr = saddr->next) {
3345 daddr = find_addr(dia->addrs,
3346 &saddr->address);
3347
3348 if (daddr == NULL) {
3349 taddr = dhc6_dup_addr(saddr, MDL);
3350
3351 if (taddr == NULL)
3352 log_fatal("Out of memory "
3353 "merging lease - "
3354 "Unable to continue "
3355 "without losing "
3356 "state! (%s:%d)",
3357 MDL);
3358
3359 /* XXX: consider sorting? */
3360 taddr->next = dia->addrs;
3361 dia->addrs = taddr;
3362 changes = 1;
3363 }
3364 }
3365 }
3366 }
3367
3368 /* If we made changes, reset the score to 0 so it is recalculated. */
3369 if (changes)
3370 dst->score = 0;
3371}
3372
3373/* We've either finished selecting or succeeded in Renew or Rebinding our
3374 * lease. In all cases we got a Reply. Give dhclient-script a tickle
3375 * to inform it about the new values, and then lay in wait for the next
3376 * event.
3377 */
3378void
3379start_bound(struct client_state *client)
3380{
3381 struct dhc6_ia *ia, *oldia;
3382 struct dhc6_addr *addr, *oldaddr;
3383 struct dhc6_lease *lease, *old;
06eb8bab 3384 const char *reason;
98bd7ca0
DH
3385 TIME dns_update_offset = 1;
3386
3387 lease = client->active_lease;
3388 if (lease == NULL) {
3389 log_error("Cannot enter bound state unless an active lease "
3390 "is selected.");
3391 return;
3392 }
3393 old = client->old_lease;
3394
3395 client->v6_handler = bound_handler;
3396
3397 switch (client->state) {
3398 case S_SELECTING:
3399 case S_REBOOTING: /* Pretend we got bound. */
3400 reason = "BOUND6";
3401 break;
3402
3403 case S_RENEWING:
3404 reason = "RENEW6";
3405 break;
3406
3407 case S_REBINDING:
3408 reason = "REBIND6";
3409 break;
3410
3411 default:
3412 log_fatal("Impossible condition at %s:%d.", MDL);
6705543f
DH
3413 /* Silence compiler warnings. */
3414 return;
98bd7ca0
DH
3415 }
3416
3417 log_debug("PRC: Bound to lease %s.",
3418 print_hex_1(client->active_lease->server_id.len,
3419 client->active_lease->server_id.data, 55));
3420 client->state = S_BOUND;
3421
3422 write_client6_lease(client, lease, 0, 1);
3423
3424 oldia = NULL;
3425 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
3426 if (ia->ia_type != D6O_IA_NA)
3427 continue;
3428
98bd7ca0 3429 if (old != NULL)
1d9774ab 3430 oldia = find_ia_na(old->bindings, (char *)ia->iaid);
98bd7ca0
DH
3431 else
3432 oldia = NULL;
3433
3434 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3435 if (oldia != NULL)
3436 oldaddr = find_addr(oldia->addrs,
3437 &addr->address);
3438 else
3439 oldaddr = NULL;
3440
3441 if (oldaddr == NULL)
3442 dhclient_schedule_updates(client,
3443 &addr->address,
3444 dns_update_offset++);
3445
3446 /* Shell out to setup the new binding. */
3447 script_init(client, reason, NULL);
3448
3449 if (old != NULL)
3450 dhc6_marshall_values("old_", client, old,
3451 oldia, oldaddr);
3452 dhc6_marshall_values("new_", client, lease, ia, addr);
3453
3454 script_go(client);
3455 }
3456
3457 /* XXX: maybe we should loop on the old values instead? */
3458 if (ia->addrs == NULL) {
3459 script_init(client, reason, NULL);
3460
3461 if (old != NULL)
3462 dhc6_marshall_values("old_", client, old,
8ea19a71
DH
3463 oldia,
3464 oldia != NULL ?
3465 oldia->addrs : NULL);
98bd7ca0
DH
3466
3467 dhc6_marshall_values("new_", client, lease, ia,
3468 NULL);
8ea19a71
DH
3469
3470 script_go(client);
98bd7ca0
DH
3471 }
3472 }
3473
3474 /* XXX: maybe we should loop on the old values instead? */
3475 if (lease->bindings == NULL) {
3476 script_init(client, reason, NULL);
3477
3478 if (old != NULL)
3479 dhc6_marshall_values("old_", client, old,
3480 old->bindings,
3481 (old->bindings != NULL) ?
3482 old->bindings->addrs : NULL);
3483
3484 dhc6_marshall_values("new_", client, lease, NULL, NULL);
8ea19a71
DH
3485
3486 script_go(client);
98bd7ca0
DH
3487 }
3488
8ea19a71
DH
3489 go_daemon();
3490
98bd7ca0 3491 if (client->old_lease != NULL) {
e32529a5 3492 dhc6_lease_destroy(&client->old_lease, MDL);
98bd7ca0
DH
3493 client->old_lease = NULL;
3494 }
3495
3496 /* Schedule events. */
3497 dhc6_check_times(client);
3498}
3499
3500/* While bound, ignore packets. In the future we'll want to answer
3501 * Reconfigure-Request messages and the like.
3502 */
3503void
3504bound_handler(struct packet *packet, struct client_state *client)
3505{
3506 log_debug("RCV: Input packets are ignored once bound.");
3507}
3508
3509/* start_renew6() gets us all ready to go to start transmitting Renew packets.
be62cf06
FD
3510 * Note that client->next_MRD must be set before entering this function -
3511 * it must be set to the time at which the client should start Rebinding.
98bd7ca0
DH
3512 */
3513void
3514start_renew6(void *input)
3515{
3516 struct client_state *client;
3517
3518 client = (struct client_state *)input;
3519
3520 log_info("PRC: Renewing lease on %s.",
3521 client->name ? client->name : client->interface->name);
3522 client->state = S_RENEWING;
3523
3524 client->v6_handler = reply_handler;
3525
3526 /* Times per RFC3315 section 18.1.3. */
be62cf06
FD
3527 client->IRT = REN_TIMEOUT * 100;
3528 client->MRT = REN_MAX_RT * 100;
98bd7ca0
DH
3529 client->MRC = 0;
3530 /* MRD is special in renew - we need to set it by checking timer
3531 * state.
3532 */
be62cf06 3533 client->MRD = client->next_MRD - cur_time;
98bd7ca0
DH
3534
3535 dhc6_retrans_init(client);
3536
3537 client->refresh_type = DHCPV6_RENEW;
3538 do_refresh6(client);
3539}
3540
3541/* do_refresh6() transmits one DHCPv6 packet, be it a Renew or Rebind, and
3542 * gives the retransmission state a bump for the next time. Note that
3543 * client->refresh_type must be set before entering this function.
3544 */
3545void
3546do_refresh6(void *input)
3547{
3548 struct option_cache *oc;
3549 struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr;
3550 struct data_string ds;
3551 struct client_state *client;
3552 struct dhc6_lease *lease;
be62cf06 3553 struct timeval elapsed, tv;
98bd7ca0
DH
3554 int send_ret;
3555
3556 client = (struct client_state *)input;
3557
3558 lease = client->active_lease;
3559 if (lease == NULL) {
3560 log_error("Cannot renew without an active binding.");
3561 return;
3562 }
3563
3564 /* Ensure we're emitting a valid message type. */
3565 switch (client->refresh_type) {
3566 case DHCPV6_RENEW:
3567 case DHCPV6_REBIND:
3568 break;
3569
3570 default:
3571 log_fatal("Internal inconsistency (%d) at %s:%d.",
3572 client->refresh_type, MDL);
3573 }
3574
be62cf06
FD
3575 /*
3576 * Start_time starts at the first transmission.
3577 */
3578 if (client->txcount == 0) {
3579 client->start_time.tv_sec = cur_tv.tv_sec;
3580 client->start_time.tv_usec = cur_tv.tv_usec;
3581 }
3582
3583 /* elapsed = cur - start */
3584 elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
3585 elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
3586 if (elapsed.tv_usec < 0) {
3587 elapsed.tv_sec -= 1;
3588 elapsed.tv_usec += 1000000;
3589 }
98bd7ca0 3590 if (((client->MRC != 0) && (client->txcount > client->MRC)) ||
be62cf06 3591 ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD))) {
98bd7ca0
DH
3592 /* We're done. Move on to the next phase, if any. */
3593 dhc6_check_times(client);
3594 return;
3595 }
3596
3597 /*
3598 * Check whether the server has sent a unicast option; if so, we can
b51c785f 3599 * use the address it specified for RENEWs.
98bd7ca0
DH
3600 */
3601 oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST);
3602 if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
3603 lease->options, NULL, &global_scope,
3604 oc, MDL)) {
3605 if (ds.len < 16) {
3606 log_error("Invalid unicast option length %d.", ds.len);
3607 } else {
3608 memset(&unicast, 0, sizeof(DHCPv6DestAddr));
3609 unicast.sin6_family = AF_INET6;
3610 unicast.sin6_port = remote_port;
3611 memcpy(&unicast.sin6_addr, ds.data, 16);
b51c785f
FD
3612 if (client->refresh_type == DHCPV6_RENEW) {
3613 dest_addr = &unicast;
3614 }
98bd7ca0
DH
3615 }
3616
3617 data_string_forget(&ds, MDL);
3618 }
3619
3620 /* Commence forming a renew packet. */
3621 memset(&ds, 0, sizeof(ds));
3622 if (!buffer_allocate(&ds.buffer, 4, MDL)) {
3623 log_error("Unable to allocate memory for packet.");
3624 return;
3625 }
3626 ds.data = ds.buffer->data;
3627 ds.len = 4;
3628
3629 ds.buffer->data[0] = client->refresh_type;
3630 memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
3631
be62cf06
FD
3632 /* Form an elapsed option. */
3633 /* Maximum value is 65535 1/100s coded as 0xffff. */
3634 if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
3635 ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
98bd7ca0 3636 client->elapsed = 0xffff;
be62cf06
FD
3637 } else {
3638 client->elapsed = elapsed.tv_sec * 100;
3639 client->elapsed += elapsed.tv_usec / 10000;
3640 }
98bd7ca0 3641
be62cf06
FD
3642 if (client->elapsed == 0)
3643 log_debug("XMT: Forming %s, 0 ms elapsed.",
3644 dhcpv6_type_names[client->refresh_type]);
3645 else
3646 log_debug("XMT: Forming %s, %u0 ms elapsed.",
3647 dhcpv6_type_names[client->refresh_type],
3648 (unsigned)client->elapsed);
98bd7ca0
DH
3649
3650 client->elapsed = htons(client->elapsed);
3651
3652 make_client6_options(client, &client->sent_options, lease,
3653 client->refresh_type);
3654
3655 /* Put in any options from the sent cache. */
3656 dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
3657 client->sent_options, &global_scope,
3658 &dhcpv6_universe);
3659
af5fa176 3660 /* Append IA's */
1d9774ab
FD
3661 if (dhc6_add_ia_na(client, &ds, lease,
3662 client->refresh_type) != ISC_R_SUCCESS) {
98bd7ca0
DH
3663 data_string_forget(&ds, MDL);
3664 return;
3665 }
3666
be62cf06 3667 log_info("XMT: %s on %s, interval %ld0ms.",
98bd7ca0
DH
3668 dhcpv6_type_names[client->refresh_type],
3669 client->name ? client->name : client->interface->name,
9aa669fc 3670 (long int)client->RT);
98bd7ca0
DH
3671
3672 send_ret = send_packet6(client->interface, ds.data, ds.len, dest_addr);
3673
3674 if (send_ret != ds.len) {
3675 log_error("dhc6: send_packet6() sent %d of %d bytes",
3676 send_ret, ds.len);
3677 }
3678
3679 data_string_forget(&ds, MDL);
3680
be62cf06
FD
3681 /* Wait RT */
3682 tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
3683 tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
3684 if (tv.tv_usec >= 1000000) {
3685 tv.tv_sec += 1;
3686 tv.tv_usec -= 1000000;
3687 }
3688 add_timeout(&tv, do_refresh6, client, NULL, NULL);
98bd7ca0
DH
3689
3690 dhc6_retrans_advance(client);
3691}
3692
3693/* start_rebind6() gets us all set up to go and rebind a lease. Note that
be62cf06 3694 * client->next_MRD must be set before entering this function. In this case,
98bd7ca0
DH
3695 * MRD must be set to the maximum time any address in the packet will
3696 * expire.
3697 */
3698void
3699start_rebind6(void *input)
3700{
3701 struct client_state *client;
3702
3703 client = (struct client_state *)input;
3704
3705 log_info("PRC: Rebinding lease on %s.",
3706 client->name ? client->name : client->interface->name);
3707 client->state = S_REBINDING;
3708
3709 client->v6_handler = reply_handler;
3710
3711 /* Times per RFC3315 section 18.1.4. */
be62cf06
FD
3712 client->IRT = REB_TIMEOUT * 100;
3713 client->MRT = REB_MAX_RT * 100;
98bd7ca0
DH
3714 client->MRC = 0;
3715 /* MRD is special in rebind - it's determined by the timer
3716 * state.
3717 */
be62cf06 3718 client->MRD = client->next_MRD - cur_time;
98bd7ca0
DH
3719
3720 dhc6_retrans_init(client);
3721
3722 client->refresh_type = DHCPV6_REBIND;
3723 do_refresh6(client);
3724}
3725
3726/* do_depref() runs through a given lease's addresses, for each that has
3727 * not yet been depreffed, shells out to the dhclient-script to inform it
3728 * of the status change. The dhclient-script should then do...something...
3729 * to encourage applications to move off the address and onto one of the
3730 * remaining 'preferred' addresses.
3731 */
3732void
3733do_depref(void *input)
3734{
3735 struct client_state *client;
3736 struct dhc6_lease *lease;
3737 struct dhc6_ia *ia;
3738 struct dhc6_addr *addr;
3739
3740 client = (struct client_state *)input;
3741
3742 lease = client->active_lease;
3743 if (lease == NULL)
3744 return;
3745
3746 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
3747 if (ia->ia_type != D6O_IA_NA)
3748 continue;
98bd7ca0
DH
3749 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3750 if (addr->flags & DHC6_ADDR_DEPREFFED)
3751 continue;
3752
3753 if (addr->starts + addr->preferred_life <= cur_time) {
3754 script_init(client, "DEPREF6", NULL);
3755 dhc6_marshall_values("cur_", client, lease,
3756 ia, addr);
3757 script_go(client);
3758
3759 log_info("PRC: Address %s depreferred.",
3760 print_hex_1(addr->address.len,
3761 addr->address.iabuf,
3762 50));
3763
3764
3765 addr->flags |= DHC6_ADDR_DEPREFFED;
3766
3767 /* Remove DDNS bindings at depref time. */
3768 if (client->config->do_forward_update)
3769 client_dns_update(client, 0, 0,
3770 &addr->address);
3771 }
3772 }
3773 }
3774
3775 dhc6_check_times(client);
3776}
3777
3778/* do_expire() searches through all the addresses on a given lease, and
3779 * expires/removes any addresses that are no longer valid.
3780 */
3781void
3782do_expire(void *input)
3783{
3784 struct client_state *client;
3785 struct dhc6_lease *lease;
3786 struct dhc6_ia *ia;
3787 struct dhc6_addr *addr;
3788 int has_addrs = ISC_FALSE;
3789
3790 client = (struct client_state *)input;
3791
3792 lease = client->active_lease;
3793 if (lease == NULL)
3794 return;
3795
3796 for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
3797 if (ia->ia_type != D6O_IA_NA)
3798 continue;
98bd7ca0
DH
3799 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3800 if (addr->flags & DHC6_ADDR_EXPIRED)
3801 continue;
3802
3803 if (addr->starts + addr->max_life <= cur_time) {
3804 script_init(client, "EXPIRE6", NULL);
3805 dhc6_marshall_values("old_", client, lease,
3806 ia, addr);
3807 script_go(client);
3808
3809 addr->flags |= DHC6_ADDR_EXPIRED;
3810
3811 log_info("PRC: Address %s expired.",
3812 print_hex_1(addr->address.len,
3813 addr->address.iabuf,
3814 50));
3815
3816 /* We remove DNS records at depref time, but
3817 * it is possible that we might get here
3818 * without depreffing.
3819 */
3820 if (client->config->do_forward_update &&
3821 !(addr->flags & DHC6_ADDR_DEPREFFED))
3822 client_dns_update(client, 0, 0,
3823 &addr->address);
3824
3825 continue;
3826 }
3827
3828 has_addrs = ISC_TRUE;
3829 }
3830 }
3831
3832 /* Clean up empty leases. */
3833 if (has_addrs == ISC_FALSE) {
3834 log_info("PRC: Bound lease is devoid of active addresses."
3835 " Re-initializing.");
3836
e32529a5 3837 dhc6_lease_destroy(&lease, MDL);
98bd7ca0
DH
3838 client->active_lease = NULL;
3839
3840 start_init6(client);
3841 return;
3842 }
3843
3844 /* Schedule the next run through. */
3845 dhc6_check_times(client);
3846}
3847
af5fa176
EH
3848/*
3849 * Run client script to unconfigure interface.
3850 * Called with reason STOP6 when dhclient -x is run, or with reason
3851 * RELEASE6 when server has replied to a Release message.
3852 */
3853void
3854unconfigure6(struct client_state *client, const char *reason)
3855{
af5fa176
EH
3856 struct dhc6_ia *ia;
3857 struct dhc6_addr *addr;
3858
3859 if (client->active_lease == NULL)
3860 return;
3861
3862 for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) {
1d9774ab
FD
3863 if (ia->ia_type != D6O_IA_NA)
3864 continue;
3865
af5fa176
EH
3866 for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3867 script_init(client, reason, NULL);
06eb8bab
SK
3868 dhc6_marshall_values("old_", client,
3869 client->active_lease, ia, addr);
af5fa176
EH
3870 script_go(client);
3871
3872 if (client->config->do_forward_update)
3873 client_dns_update(client, 0, 0, &addr->address);
3874 }
3875 }
3876}
3877
98bd7ca0
DH
3878/* make_client6_options() fetches option caches relevant to the client's
3879 * scope and places them into the sent_options cache. This cache is later
3880 * used to populate DHCPv6 output packets with options.
3881 */
3882static void
3883make_client6_options(struct client_state *client, struct option_state **op,
3884 struct dhc6_lease *lease, u_int8_t message)
3885{
98bd7ca0 3886 struct option_cache *oc;
0c20eab3 3887 struct option **req;
e5d83524
DH
3888 struct buffer *buffer;
3889 int buflen, i, oro_len;
98bd7ca0
DH
3890
3891 if ((op == NULL) || (client == NULL))
3892 return;
3893
3894 if (*op)
3895 option_state_dereference(op, MDL);
3896
0c20eab3 3897 /* Create a cache to carry options to transmission. */
98bd7ca0
DH
3898 option_state_allocate(op, MDL);
3899
0c20eab3 3900 /* Create and store an 'elapsed time' option in the cache. */
98bd7ca0
DH
3901 oc = NULL;
3902 if (option_cache_allocate(&oc, MDL)) {
3903 const unsigned char *cdata;
3904
3905 cdata = (unsigned char *)&client->elapsed;
3906
3907 if (make_const_data(&oc->expression, cdata, 2, 0, 0, MDL)) {
3908 option_reference(&oc->option, elapsed_option, MDL);
3909 save_option(&dhcpv6_universe, *op, oc);
3910 }
3911
3912 option_cache_dereference(&oc, MDL);
3913 }
3914
9ab0cc6a
DH
3915 /* Bring in any configured options to send. */
3916 if (client->config->on_transmission)
3917 execute_statements_in_scope(NULL, NULL, NULL, client,
3918 lease ? lease->options : NULL,
3919 *op, &global_scope,
3920 client->config->on_transmission,
3921 NULL);
3922
6d7f9584
FD
3923 /* Rapid-commit is only for SOLICITs. */
3924 if (message != DHCPV6_SOLICIT)
3925 delete_option(&dhcpv6_universe, *op, D6O_RAPID_COMMIT);
3926
98bd7ca0
DH
3927 /* See if the user configured a DUID in a relevant scope. If not,
3928 * introduce our default manufactured id.
3929 */
3930 if ((oc = lookup_option(&dhcpv6_universe, *op,
3931 D6O_CLIENTID)) == NULL) {
3932 if (!option_cache(&oc, &default_duid, NULL, clientid_option,
3933 MDL))
3934 log_fatal("Failure assembling a DUID.");
3935
3936 save_option(&dhcpv6_universe, *op, oc);
3937 option_cache_dereference(&oc, MDL);
3938 }
3939
3940 /* In cases where we're responding to a single server, put the
3941 * server's id in the response.
3942 *
3943 * Note that lease is NULL for SOLICIT or INFO request messages,
3944 * and otherwise MUST be present.
3945 */
3946 if (lease == NULL) {
3947 if ((message != DHCPV6_SOLICIT) &&
3948 (message != DHCPV6_INFORMATION_REQUEST))
3949 log_fatal("Impossible condition at %s:%d.", MDL);
3950 } else if ((message != DHCPV6_REBIND) &&
3951 (message != DHCPV6_CONFIRM)) {
3952 oc = lookup_option(&dhcpv6_universe, lease->options,
3953 D6O_SERVERID);
3954 if (oc != NULL)
3955 save_option(&dhcpv6_universe, *op, oc);
3956 }
3957
0c20eab3
DH
3958 /* 'send dhcp6.oro foo;' syntax we used in 4.0.0a1/a2 has been
3959 * deprecated by adjustments to the 'request' syntax also used for
3960 * DHCPv4.
3961 */
9ab0cc6a 3962 if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) != NULL)
0c20eab3 3963 log_error("'send dhcp6.oro' syntax is deprecated, please "
44a67e65 3964 "use the 'request' syntax (\"man dhclient.conf\").");
0c20eab3
DH
3965
3966 /* Construct and store an ORO (Option Request Option). It is a
3967 * fatal error to fail to send an ORO (of at least zero length).
3968 *
3969 * Discussion: RFC3315 appears to be inconsistent in its statements
3970 * of whether or not the ORO is mandatory. In section 18.1.1
3971 * ("Creation and Transmission of Request Messages"):
3972 *
3973 * The client MUST include an Option Request option (see section
3974 * 22.7) to indicate the options the client is interested in
3975 * receiving. The client MAY include options with data values as
3976 * hints to the server about parameter values the client would like
3977 * to have returned.
3978 *
3979 * This MUST is missing from the creation/transmission of other
3980 * messages (such as Renew and Rebind), and the section 22.7 ("Option
3981 * Request Option" format and definition):
3982 *
3983 * A client MAY include an Option Request option in a Solicit,
3984 * Request, Renew, Rebind, Confirm or Information-request message to
3985 * inform the server about options the client wants the server to
3986 * send to the client. A server MAY include an Option Request
3987 * option in a Reconfigure option to indicate which options the
3988 * client should request from the server.
3989 *
3990 * seems to relax the requirement from MUST to MAY (and still other
3991 * language in RFC3315 supports this).
3992 *
3993 * In lieu of a clarification of RFC3315, we will conform with the
3994 * MUST. Instead of an absent ORO, we will if there are no options
3995 * to request supply an empty ORO. Theoretically, an absent ORO is
3996 * difficult to interpret (does the client want all options or no
3997 * options?). A zero-length ORO is intuitively clear: requesting
3998 * nothing.
3999 */
e5d83524
DH
4000 buffer = NULL;
4001 oro_len = 0;
0c20eab3 4002 buflen = 32;
e5d83524 4003 if (!buffer_allocate(&buffer, buflen, MDL))
0c20eab3 4004 log_fatal("Out of memory constructing DHCPv6 ORO.");
0c20eab3
DH
4005 req = client->config->requested_options;
4006 if (req != NULL) {
4007 for (i = 0 ; req[i] != NULL ; i++) {
e5d83524 4008 if (buflen == oro_len) {
0c20eab3
DH
4009 struct buffer *tmpbuf = NULL;
4010
4011 buflen += 32;
4012
4013 /* Shell game. */
e5d83524
DH
4014 buffer_reference(&tmpbuf, buffer, MDL);
4015 buffer_dereference(&buffer, MDL);
0c20eab3 4016
e5d83524 4017 if (!buffer_allocate(&buffer, buflen, MDL))
0c20eab3
DH
4018 log_fatal("Out of memory resizing "
4019 "DHCPv6 ORO buffer.");
4020
e5d83524 4021 memcpy(buffer->data, tmpbuf->data, oro_len);
0c20eab3
DH
4022
4023 buffer_dereference(&tmpbuf, MDL);
4024 }
4025
4026 if (req[i]->universe == &dhcpv6_universe) {
4027 /* Append the code to the ORO. */
e5d83524 4028 putUShort(buffer->data + oro_len,
0c20eab3 4029 req[i]->code);
e5d83524 4030 oro_len += 2;
0c20eab3
DH
4031 }
4032 }
4033 }
4034
4035 oc = NULL;
e5d83524
DH
4036 if (make_const_option_cache(&oc, &buffer, NULL, oro_len,
4037 oro_option, MDL)) {
0c20eab3
DH
4038 save_option(&dhcpv6_universe, *op, oc);
4039 } else {
4040 log_fatal("Unable to create ORO option cache.");
4041 }
4042
e5d83524
DH
4043 /*
4044 * Note: make_const_option_cache() consumes the buffer, we do not
4045 * need to dereference it (XXX).
98bd7ca0 4046 */
e5d83524 4047 option_cache_dereference(&oc, MDL);
98bd7ca0
DH
4048}
4049
4050/* A clone of the DHCPv4 script_write_params() minus the DHCPv4-specific
4051 * filename, server-name, etc specifics.
4052 *
4053 * Simply, store all values present in all universes of the option state
4054 * (probably derived from a DHCPv6 packet) into environment variables
4055 * named after the option names (and universe names) but with the 'prefix'
4056 * prepended.
4057 *
4058 * Later, dhclient-script may compare for example "new_time_servers" and
4059 * "old_time_servers" for differences, and only upon detecting a change
4060 * bother to rewrite ntp.conf and restart it. Or something along those
4061 * generic lines.
4062 */
4063static void
06eb8bab 4064script_write_params6(struct client_state *client, const char *prefix,
98bd7ca0
DH
4065 struct option_state *options)
4066{
4067 struct envadd_state es;
4068 int i;
4069
4070 if (options == NULL)
4071 return;
4072
4073 es.client = client;
4074 es.prefix = prefix;
4075
4076 for (i = 0 ; i < options->universe_count ; i++) {
4077 option_space_foreach(NULL, NULL, client, NULL, options,
4078 &global_scope, universes[i], &es,
4079 client_option_envadd);
4080 }
4081}
4082
fe5b0fdd 4083#endif /* DHCPv6 */