1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
8 #include <linux/if_arp.h>
9 #include <linux/if_infiniband.h>
11 #include "sd-dhcp6-client.h"
13 #include "alloc-util.h"
14 #include "dhcp-identifier.h"
15 #include "dhcp6-internal.h"
16 #include "dhcp6-lease-internal.h"
17 #include "dhcp6-protocol.h"
18 #include "dns-domain.h"
19 #include "event-util.h"
21 #include "hexdecoct.h"
22 #include "hostname-util.h"
23 #include "in-addr-util.h"
24 #include "network-internal.h"
25 #include "random-util.h"
26 #include "socket-util.h"
27 #include "string-table.h"
31 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
33 #define IRT_DEFAULT (1 * USEC_PER_DAY)
34 #define IRT_MINIMUM (600 * USEC_PER_SEC)
36 /* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
38 DHCP6_REQUEST_IA_NA
= 1,
39 DHCP6_REQUEST_IA_TA
= 2, /* currently not used */
40 DHCP6_REQUEST_IA_PD
= 4,
43 struct sd_dhcp6_client
{
46 enum DHCP6State state
;
50 DHCP6Address hint_pd_prefix
;
51 struct in6_addr local_address
;
52 uint8_t mac_addr
[MAX_MAC_ADDR_LEN
];
57 sd_event_source
*timeout_t1
;
58 sd_event_source
*timeout_t2
;
60 be32_t transaction_id
;
61 usec_t transaction_start
;
62 struct sd_dhcp6_lease
*lease
;
64 bool information_request
;
67 size_t req_opts_allocated
;
73 sd_event_source
*receive_message
;
74 usec_t retransmit_time
;
75 uint8_t retransmit_count
;
76 sd_event_source
*timeout_resend
;
77 sd_event_source
*timeout_resend_expire
;
78 sd_dhcp6_client_callback_t callback
;
82 usec_t information_request_time_usec
;
83 usec_t information_refresh_time_usec
;
84 OrderedHashmap
*extra_options
;
85 OrderedHashmap
*vendor_options
;
88 static const uint16_t default_req_opts
[] = {
89 SD_DHCP6_OPTION_DNS_SERVERS
,
90 SD_DHCP6_OPTION_DOMAIN_LIST
,
91 SD_DHCP6_OPTION_NTP_SERVER
,
92 SD_DHCP6_OPTION_SNTP_SERVERS
,
95 const char * dhcp6_message_type_table
[_DHCP6_MESSAGE_MAX
] = {
96 [DHCP6_SOLICIT
] = "SOLICIT",
97 [DHCP6_ADVERTISE
] = "ADVERTISE",
98 [DHCP6_REQUEST
] = "REQUEST",
99 [DHCP6_CONFIRM
] = "CONFIRM",
100 [DHCP6_RENEW
] = "RENEW",
101 [DHCP6_REBIND
] = "REBIND",
102 [DHCP6_REPLY
] = "REPLY",
103 [DHCP6_RELEASE
] = "RELEASE",
104 [DHCP6_DECLINE
] = "DECLINE",
105 [DHCP6_RECONFIGURE
] = "RECONFIGURE",
106 [DHCP6_INFORMATION_REQUEST
] = "INFORMATION-REQUEST",
107 [DHCP6_RELAY_FORW
] = "RELAY-FORW",
108 [DHCP6_RELAY_REPL
] = "RELAY-REPL",
111 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type
, int);
113 const char * dhcp6_message_status_table
[_DHCP6_STATUS_MAX
] = {
114 [DHCP6_STATUS_SUCCESS
] = "Success",
115 [DHCP6_STATUS_UNSPEC_FAIL
] = "Unspecified failure",
116 [DHCP6_STATUS_NO_ADDRS_AVAIL
] = "No addresses available",
117 [DHCP6_STATUS_NO_BINDING
] = "Binding unavailable",
118 [DHCP6_STATUS_NOT_ON_LINK
] = "Not on link",
119 [DHCP6_STATUS_USE_MULTICAST
] = "Use multicast",
120 [DHCP6_STATUS_NO_PREFIX_AVAIL
] = "No prefix available",
121 [DHCP6_STATUS_UNKNOWN_QUERY_TYPE
] = "Unknown query type",
122 [DHCP6_STATUS_MALFORMED_QUERY
] = "Malformed query",
123 [DHCP6_STATUS_NOT_CONFIGURED
] = "Not configured",
124 [DHCP6_STATUS_NOT_ALLOWED
] = "Not allowed",
125 [DHCP6_STATUS_QUERY_TERMINATED
] = "Query terminated",
126 [DHCP6_STATUS_DATA_MISSING
] = "Data missing",
127 [DHCP6_STATUS_CATCHUP_COMPLETE
] = "Catch up complete",
128 [DHCP6_STATUS_NOT_SUPPORTED
] = "Not supported",
129 [DHCP6_STATUS_TLS_CONNECTION_REFUSED
] = "TLS connection refused",
130 [DHCP6_STATUS_ADDRESS_IN_USE
] = "Address in use",
131 [DHCP6_STATUS_CONFIGURATION_CONFLICT
] = "Configuration conflict",
132 [DHCP6_STATUS_MISSING_BINDING_INFORMATION
] = "Missing binding information",
133 [DHCP6_STATUS_OUTDATED_BINDING_INFORMATION
] = "Outdated binding information",
134 [DHCP6_STATUS_SERVER_SHUTTING_DOWN
] = "Server shutting down",
135 [DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED
] = "DNS update not supported",
136 [DHCP6_STATUS_EXCESSIVE_TIME_SKEW
] = "Excessive time skew",
139 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status
, int);
141 #define DHCP6_CLIENT_DONT_DESTROY(client) \
142 _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
144 static int client_start(sd_dhcp6_client
*client
, enum DHCP6State state
);
146 int sd_dhcp6_client_set_callback(
147 sd_dhcp6_client
*client
,
148 sd_dhcp6_client_callback_t cb
,
151 assert_return(client
, -EINVAL
);
153 client
->callback
= cb
;
154 client
->userdata
= userdata
;
159 int sd_dhcp6_client_set_ifindex(sd_dhcp6_client
*client
, int ifindex
) {
161 assert_return(client
, -EINVAL
);
162 assert_return(ifindex
> 0, -EINVAL
);
163 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
165 client
->ifindex
= ifindex
;
169 int sd_dhcp6_client_set_local_address(
170 sd_dhcp6_client
*client
,
171 const struct in6_addr
*local_address
) {
173 assert_return(client
, -EINVAL
);
174 assert_return(local_address
, -EINVAL
);
175 assert_return(in_addr_is_link_local(AF_INET6
, (const union in_addr_union
*) local_address
) > 0, -EINVAL
);
177 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
179 client
->local_address
= *local_address
;
184 int sd_dhcp6_client_set_mac(
185 sd_dhcp6_client
*client
,
186 const uint8_t *addr
, size_t addr_len
,
189 assert_return(client
, -EINVAL
);
190 assert_return(addr
, -EINVAL
);
191 assert_return(addr_len
> 0 && addr_len
<= MAX_MAC_ADDR_LEN
, -EINVAL
);
192 assert_return(arp_type
> 0, -EINVAL
);
194 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
196 if (arp_type
== ARPHRD_ETHER
)
197 assert_return(addr_len
== ETH_ALEN
, -EINVAL
);
198 else if (arp_type
== ARPHRD_INFINIBAND
)
199 assert_return(addr_len
== INFINIBAND_ALEN
, -EINVAL
);
203 if (client
->mac_addr_len
== addr_len
&&
204 memcmp(&client
->mac_addr
, addr
, addr_len
) == 0)
207 memcpy(&client
->mac_addr
, addr
, addr_len
);
208 client
->mac_addr_len
= addr_len
;
209 client
->arp_type
= arp_type
;
214 int sd_dhcp6_client_set_prefix_delegation_hint(
215 sd_dhcp6_client
*client
,
217 const struct in6_addr
*pd_address
) {
219 assert_return(client
, -EINVAL
);
220 assert_return(pd_address
, -EINVAL
);
222 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
224 client
->hint_pd_prefix
.iapdprefix
.address
= *pd_address
;
225 client
->hint_pd_prefix
.iapdprefix
.prefixlen
= prefixlen
;
230 int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client
*client
, sd_dhcp6_option
*v
) {
233 assert_return(client
, -EINVAL
);
234 assert_return(v
, -EINVAL
);
236 r
= ordered_hashmap_ensure_allocated(&client
->vendor_options
, &dhcp6_option_hash_ops
);
240 r
= ordered_hashmap_put(client
->vendor_options
, v
, v
);
244 sd_dhcp6_option_ref(v
);
249 static int client_ensure_duid(sd_dhcp6_client
*client
) {
250 if (client
->duid_len
!= 0)
253 return dhcp_identifier_set_duid_en(&client
->duid
, &client
->duid_len
);
257 * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
258 * without further modification. Otherwise, if duid_type is supported, DUID
259 * is set based on that type. Otherwise, an error is returned.
261 static int dhcp6_client_set_duid_internal(
262 sd_dhcp6_client
*client
,
269 assert_return(client
, -EINVAL
);
270 assert_return(duid_len
== 0 || duid
!= NULL
, -EINVAL
);
271 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
274 r
= dhcp_validate_duid_len(duid_type
, duid_len
, true);
276 r
= dhcp_validate_duid_len(duid_type
, duid_len
, false);
278 return log_dhcp6_client_errno(client
, r
, "Failed to validate length of DUID: %m");
280 log_dhcp6_client(client
, "Using DUID of type %u of incorrect length, proceeding.", duid_type
);
283 client
->duid
.type
= htobe16(duid_type
);
284 memcpy(&client
->duid
.raw
.data
, duid
, duid_len
);
285 client
->duid_len
= sizeof(client
->duid
.type
) + duid_len
;
289 if (client
->mac_addr_len
== 0)
290 return log_dhcp6_client_errno(client
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to set DUID-LLT, MAC address is not set.");
292 r
= dhcp_identifier_set_duid_llt(&client
->duid
, llt_time
, client
->mac_addr
, client
->mac_addr_len
, client
->arp_type
, &client
->duid_len
);
294 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-LLT: %m");
297 r
= dhcp_identifier_set_duid_en(&client
->duid
, &client
->duid_len
);
299 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-EN: %m");
302 if (client
->mac_addr_len
== 0)
303 return log_dhcp6_client_errno(client
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to set DUID-LL, MAC address is not set.");
305 r
= dhcp_identifier_set_duid_ll(&client
->duid
, client
->mac_addr
, client
->mac_addr_len
, client
->arp_type
, &client
->duid_len
);
307 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-LL: %m");
310 r
= dhcp_identifier_set_duid_uuid(&client
->duid
, &client
->duid_len
);
312 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-UUID: %m");
315 return log_dhcp6_client_errno(client
, SYNTHETIC_ERRNO(EINVAL
), "Invalid DUID type");
321 int sd_dhcp6_client_set_duid(
322 sd_dhcp6_client
*client
,
326 return dhcp6_client_set_duid_internal(client
, duid_type
, duid
, duid_len
, 0);
329 int sd_dhcp6_client_set_duid_llt(
330 sd_dhcp6_client
*client
,
332 return dhcp6_client_set_duid_internal(client
, DUID_TYPE_LLT
, NULL
, 0, llt_time
);
335 static const char* const dhcp6_duid_type_table
[_DUID_TYPE_MAX
] = {
336 [DUID_TYPE_LLT
] = "DUID-LLT",
337 [DUID_TYPE_EN
] = "DUID-EN/Vendor",
338 [DUID_TYPE_LL
] = "DUID-LL",
339 [DUID_TYPE_UUID
] = "UUID",
341 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(dhcp6_duid_type
, DUIDType
);
343 int sd_dhcp6_client_duid_as_string(
344 sd_dhcp6_client
*client
,
346 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *t
= NULL
;
350 assert_return(client
, -EINVAL
);
351 assert_return(client
->duid_len
> 0, -ENODATA
);
353 v
= dhcp6_duid_type_to_string(be16toh(client
->duid
.type
));
359 r
= asprintf(&s
, "%0x", client
->duid
.type
);
364 t
= hexmem(&client
->duid
.raw
.data
, client
->duid_len
);
368 p
= strjoin(s
, ":", t
);
377 int sd_dhcp6_client_set_iaid(sd_dhcp6_client
*client
, uint32_t iaid
) {
378 assert_return(client
, -EINVAL
);
379 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
381 client
->ia_na
.ia_na
.id
= htobe32(iaid
);
382 client
->ia_pd
.ia_pd
.id
= htobe32(iaid
);
383 client
->iaid_set
= true;
388 int sd_dhcp6_client_get_iaid(sd_dhcp6_client
*client
, uint32_t *iaid
) {
389 assert_return(client
, -EINVAL
);
390 assert_return(iaid
, -EINVAL
);
392 if (!client
->iaid_set
)
395 *iaid
= be32toh(client
->ia_na
.ia_na
.id
);
400 int sd_dhcp6_client_set_fqdn(
401 sd_dhcp6_client
*client
,
404 assert_return(client
, -EINVAL
);
406 /* Make sure FQDN qualifies as DNS and as Linux hostname */
408 !(hostname_is_valid(fqdn
, false) && dns_name_is_valid(fqdn
) > 0))
411 return free_and_strdup(&client
->fqdn
, fqdn
);
414 int sd_dhcp6_client_set_information_request(sd_dhcp6_client
*client
, int enabled
) {
415 assert_return(client
, -EINVAL
);
416 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
418 client
->information_request
= enabled
;
423 int sd_dhcp6_client_get_information_request(sd_dhcp6_client
*client
, int *enabled
) {
424 assert_return(client
, -EINVAL
);
425 assert_return(enabled
, -EINVAL
);
427 *enabled
= client
->information_request
;
432 int sd_dhcp6_client_set_request_option(sd_dhcp6_client
*client
, uint16_t option
) {
435 assert_return(client
, -EINVAL
);
436 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
438 if (option
<= 0 || option
>= UINT8_MAX
)
441 for (t
= 0; t
< client
->req_opts_len
; t
++)
442 if (client
->req_opts
[t
] == htobe16(option
))
445 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
446 client
->req_opts_len
+ 1))
449 client
->req_opts
[client
->req_opts_len
++] = htobe16(option
);
454 int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client
*client
, const char *mudurl
) {
456 assert_return(client
, -EINVAL
);
457 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
458 assert_return(mudurl
, -EINVAL
);
459 assert_return(strlen(mudurl
) <= UINT8_MAX
, -EINVAL
);
460 assert_return(http_url_is_valid(mudurl
), -EINVAL
);
462 return free_and_strdup(&client
->mudurl
, mudurl
);
465 int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client
*client
, char **user_class
) {
466 _cleanup_strv_free_
char **s
= NULL
;
469 assert_return(client
, -EINVAL
);
470 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
472 assert_return(user_class
, -EINVAL
);
474 STRV_FOREACH(p
, user_class
)
475 if (strlen(*p
) > UINT16_MAX
)
476 return -ENAMETOOLONG
;
478 s
= strv_copy(user_class
);
482 client
->user_class
= TAKE_PTR(s
);
487 int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client
*client
, char **vendor_class
) {
488 _cleanup_strv_free_
char **s
= NULL
;
491 assert_return(client
, -EINVAL
);
492 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
493 assert_return(vendor_class
, -EINVAL
);
495 STRV_FOREACH(p
, vendor_class
)
496 if (strlen(*p
) > UINT8_MAX
)
497 return -ENAMETOOLONG
;
499 s
= strv_copy(vendor_class
);
503 client
->vendor_class
= TAKE_PTR(s
);
508 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client
*client
, int *delegation
) {
509 assert_return(client
, -EINVAL
);
510 assert_return(delegation
, -EINVAL
);
512 *delegation
= FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
);
517 int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client
*client
, int delegation
) {
518 assert_return(client
, -EINVAL
);
520 SET_FLAG(client
->request
, DHCP6_REQUEST_IA_PD
, delegation
);
525 int sd_dhcp6_client_get_address_request(sd_dhcp6_client
*client
, int *request
) {
526 assert_return(client
, -EINVAL
);
527 assert_return(request
, -EINVAL
);
529 *request
= FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
);
534 int sd_dhcp6_client_set_address_request(sd_dhcp6_client
*client
, int request
) {
535 assert_return(client
, -EINVAL
);
537 SET_FLAG(client
->request
, DHCP6_REQUEST_IA_NA
, request
);
542 int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client
*client
, uint32_t transaction_id
) {
543 assert_return(client
, -EINVAL
);
545 client
->transaction_id
= transaction_id
;
550 int sd_dhcp6_client_get_lease(sd_dhcp6_client
*client
, sd_dhcp6_lease
**ret
) {
551 assert_return(client
, -EINVAL
);
557 *ret
= client
->lease
;
562 int sd_dhcp6_client_add_option(sd_dhcp6_client
*client
, sd_dhcp6_option
*v
) {
565 assert_return(client
, -EINVAL
);
566 assert_return(v
, -EINVAL
);
568 r
= ordered_hashmap_ensure_allocated(&client
->extra_options
, &dhcp6_option_hash_ops
);
572 r
= ordered_hashmap_put(client
->extra_options
, UINT_TO_PTR(v
->option
), v
);
576 sd_dhcp6_option_ref(v
);
580 static void client_notify(sd_dhcp6_client
*client
, int event
) {
583 if (client
->callback
)
584 client
->callback(client
, event
, client
->userdata
);
587 static int client_reset(sd_dhcp6_client
*client
) {
590 client
->lease
= sd_dhcp6_lease_unref(client
->lease
);
592 client
->receive_message
=
593 sd_event_source_unref(client
->receive_message
);
595 client
->transaction_id
= 0;
596 client
->transaction_start
= 0;
598 client
->retransmit_time
= 0;
599 client
->retransmit_count
= 0;
601 (void) event_source_disable(client
->timeout_resend
);
602 (void) event_source_disable(client
->timeout_resend_expire
);
603 (void) event_source_disable(client
->timeout_t1
);
604 (void) event_source_disable(client
->timeout_t2
);
606 client
->state
= DHCP6_STATE_STOPPED
;
611 static void client_stop(sd_dhcp6_client
*client
, int error
) {
612 DHCP6_CLIENT_DONT_DESTROY(client
);
616 client_notify(client
, error
);
618 client_reset(client
);
621 static int client_send_message(sd_dhcp6_client
*client
, usec_t time_now
) {
622 _cleanup_free_ DHCP6Message
*message
= NULL
;
623 struct in6_addr all_servers
=
624 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
625 struct sd_dhcp6_option
*j
;
626 size_t len
, optlen
= 512;
634 len
= sizeof(DHCP6Message
) + optlen
;
636 message
= malloc0(len
);
640 opt
= (uint8_t *)(message
+ 1);
642 message
->transaction_id
= client
->transaction_id
;
644 switch(client
->state
) {
645 case DHCP6_STATE_INFORMATION_REQUEST
:
646 message
->type
= DHCP6_INFORMATION_REQUEST
;
648 if (client
->mudurl
) {
649 r
= dhcp6_option_append(&opt
, &optlen
,
650 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
658 case DHCP6_STATE_SOLICITATION
:
659 message
->type
= DHCP6_SOLICIT
;
661 r
= dhcp6_option_append(&opt
, &optlen
,
662 SD_DHCP6_OPTION_RAPID_COMMIT
, 0, NULL
);
666 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
)) {
667 r
= dhcp6_option_append_ia(&opt
, &optlen
,
674 r
= dhcp6_option_append_fqdn(&opt
, &optlen
, client
->fqdn
);
679 if (client
->mudurl
) {
680 r
= dhcp6_option_append(&opt
, &optlen
,
681 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
687 if (client
->user_class
) {
688 r
= dhcp6_option_append_user_class(&opt
, &optlen
, client
->user_class
);
693 if (client
->vendor_class
) {
694 r
= dhcp6_option_append_vendor_class(&opt
, &optlen
, client
->vendor_class
);
699 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
700 r
= dhcp6_option_append_vendor_option(&opt
, &optlen
,
701 client
->vendor_options
);
706 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
)) {
707 r
= dhcp6_option_append_pd(opt
, optlen
, &client
->ia_pd
, &client
->hint_pd_prefix
);
717 case DHCP6_STATE_REQUEST
:
718 case DHCP6_STATE_RENEW
:
720 if (client
->state
== DHCP6_STATE_REQUEST
)
721 message
->type
= DHCP6_REQUEST
;
723 message
->type
= DHCP6_RENEW
;
725 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_SERVERID
,
726 client
->lease
->serverid_len
,
727 client
->lease
->serverid
);
731 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
)) {
732 r
= dhcp6_option_append_ia(&opt
, &optlen
,
739 r
= dhcp6_option_append_fqdn(&opt
, &optlen
, client
->fqdn
);
744 if (client
->mudurl
) {
745 r
= dhcp6_option_append(&opt
, &optlen
,
746 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
752 if (client
->user_class
) {
753 r
= dhcp6_option_append_user_class(&opt
, &optlen
, client
->user_class
);
758 if (client
->vendor_class
) {
759 r
= dhcp6_option_append_vendor_class(&opt
, &optlen
, client
->vendor_class
);
764 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
765 r
= dhcp6_option_append_vendor_option(&opt
, &optlen
, client
->vendor_options
);
770 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
)) {
771 r
= dhcp6_option_append_pd(opt
, optlen
, &client
->lease
->pd
, NULL
);
781 case DHCP6_STATE_REBIND
:
782 message
->type
= DHCP6_REBIND
;
784 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
)) {
785 r
= dhcp6_option_append_ia(&opt
, &optlen
, &client
->lease
->ia
);
791 r
= dhcp6_option_append_fqdn(&opt
, &optlen
, client
->fqdn
);
796 if (client
->mudurl
) {
797 r
= dhcp6_option_append(&opt
, &optlen
,
798 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
804 if (client
->user_class
) {
805 r
= dhcp6_option_append_user_class(&opt
, &optlen
, client
->user_class
);
810 if (client
->vendor_class
) {
811 r
= dhcp6_option_append_vendor_class(&opt
, &optlen
, client
->vendor_class
);
816 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
817 r
= dhcp6_option_append_vendor_option(&opt
, &optlen
, client
->vendor_options
);
822 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
)) {
823 r
= dhcp6_option_append_pd(opt
, optlen
, &client
->lease
->pd
, NULL
);
833 case DHCP6_STATE_STOPPED
:
834 case DHCP6_STATE_BOUND
:
838 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_ORO
,
839 client
->req_opts_len
* sizeof(be16_t
),
844 assert(client
->duid_len
);
845 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_CLIENTID
,
846 client
->duid_len
, &client
->duid
);
850 elapsed_usec
= time_now
- client
->transaction_start
;
851 if (elapsed_usec
< 0xffff * USEC_PER_MSEC
* 10)
852 elapsed_time
= htobe16(elapsed_usec
/ USEC_PER_MSEC
/ 10);
854 elapsed_time
= 0xffff;
856 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_ELAPSED_TIME
,
857 sizeof(elapsed_time
), &elapsed_time
);
861 ORDERED_HASHMAP_FOREACH(j
, client
->extra_options
) {
862 r
= dhcp6_option_append(&opt
, &optlen
, j
->option
, j
->length
, j
->data
);
867 r
= dhcp6_network_send_udp_socket(client
->fd
, &all_servers
, message
,
872 log_dhcp6_client(client
, "Sent %s",
873 dhcp6_message_type_to_string(message
->type
));
878 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
879 sd_dhcp6_client
*client
= userdata
;
883 assert(client
->lease
);
885 (void) event_source_disable(client
->timeout_t2
);
887 log_dhcp6_client(client
, "Timeout T2");
889 client_start(client
, DHCP6_STATE_REBIND
);
894 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
895 sd_dhcp6_client
*client
= userdata
;
899 assert(client
->lease
);
901 (void) event_source_disable(client
->timeout_t1
);
903 log_dhcp6_client(client
, "Timeout T1");
905 client_start(client
, DHCP6_STATE_RENEW
);
910 static int client_timeout_resend_expire(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
911 sd_dhcp6_client
*client
= userdata
;
912 DHCP6_CLIENT_DONT_DESTROY(client
);
913 enum DHCP6State state
;
917 assert(client
->event
);
919 state
= client
->state
;
921 client_stop(client
, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
);
923 /* RFC 3315, section 18.1.4., says that "...the client may choose to
924 use a Solicit message to locate a new DHCP server..." */
925 if (state
== DHCP6_STATE_REBIND
)
926 client_start(client
, DHCP6_STATE_SOLICITATION
);
931 static usec_t
client_timeout_compute_random(usec_t val
) {
932 return val
- (random_u32() % USEC_PER_SEC
) * val
/ 10 / USEC_PER_SEC
;
935 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
937 sd_dhcp6_client
*client
= userdata
;
938 usec_t time_now
, init_retransmit_time
= 0, max_retransmit_time
= 0;
939 usec_t max_retransmit_duration
= 0;
940 uint8_t max_retransmit_count
= 0;
941 char time_string
[FORMAT_TIMESPAN_MAX
];
945 assert(client
->event
);
947 (void) event_source_disable(client
->timeout_resend
);
949 switch (client
->state
) {
950 case DHCP6_STATE_INFORMATION_REQUEST
:
951 init_retransmit_time
= DHCP6_INF_TIMEOUT
;
952 max_retransmit_time
= DHCP6_INF_MAX_RT
;
956 case DHCP6_STATE_SOLICITATION
:
958 if (client
->retransmit_count
&& client
->lease
) {
959 client_start(client
, DHCP6_STATE_REQUEST
);
963 init_retransmit_time
= DHCP6_SOL_TIMEOUT
;
964 max_retransmit_time
= DHCP6_SOL_MAX_RT
;
968 case DHCP6_STATE_REQUEST
:
969 init_retransmit_time
= DHCP6_REQ_TIMEOUT
;
970 max_retransmit_time
= DHCP6_REQ_MAX_RT
;
971 max_retransmit_count
= DHCP6_REQ_MAX_RC
;
975 case DHCP6_STATE_RENEW
:
976 init_retransmit_time
= DHCP6_REN_TIMEOUT
;
977 max_retransmit_time
= DHCP6_REN_MAX_RT
;
979 /* RFC 3315, section 18.1.3. says max retransmit duration will
980 be the remaining time until T2. Instead of setting MRD,
981 wait for T2 to trigger with the same end result */
985 case DHCP6_STATE_REBIND
:
986 init_retransmit_time
= DHCP6_REB_TIMEOUT
;
987 max_retransmit_time
= DHCP6_REB_MAX_RT
;
989 if (event_source_is_enabled(client
->timeout_resend_expire
) <= 0) {
992 r
= dhcp6_lease_ia_rebind_expire(&client
->lease
->ia
, &expire
);
994 client_stop(client
, r
);
997 max_retransmit_duration
= expire
* USEC_PER_SEC
;
1002 case DHCP6_STATE_STOPPED
:
1003 case DHCP6_STATE_BOUND
:
1007 if (max_retransmit_count
> 0 &&
1008 client
->retransmit_count
>= max_retransmit_count
) {
1009 client_stop(client
, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
);
1013 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
1017 r
= client_send_message(client
, time_now
);
1019 client
->retransmit_count
++;
1021 if (client
->retransmit_time
== 0) {
1022 client
->retransmit_time
=
1023 client_timeout_compute_random(init_retransmit_time
);
1025 if (client
->state
== DHCP6_STATE_SOLICITATION
)
1026 client
->retransmit_time
+= init_retransmit_time
/ 10;
1029 if (max_retransmit_time
> 0 &&
1030 client
->retransmit_time
> max_retransmit_time
/ 2)
1031 client
->retransmit_time
= client_timeout_compute_random(max_retransmit_time
);
1033 client
->retransmit_time
+= client_timeout_compute_random(client
->retransmit_time
);
1036 log_dhcp6_client(client
, "Next retransmission in %s",
1037 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, client
->retransmit_time
, USEC_PER_SEC
));
1039 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1040 clock_boottime_or_monotonic(),
1041 time_now
+ client
->retransmit_time
, 10 * USEC_PER_MSEC
,
1042 client_timeout_resend
, client
,
1043 client
->event_priority
, "dhcp6-resend-timer", true);
1047 if (max_retransmit_duration
> 0 && event_source_is_enabled(client
->timeout_resend_expire
) <= 0) {
1049 log_dhcp6_client(client
, "Max retransmission duration %"PRIu64
" secs",
1050 max_retransmit_duration
/ USEC_PER_SEC
);
1052 r
= event_reset_time(client
->event
, &client
->timeout_resend_expire
,
1053 clock_boottime_or_monotonic(),
1054 time_now
+ max_retransmit_duration
, USEC_PER_SEC
,
1055 client_timeout_resend_expire
, client
,
1056 client
->event_priority
, "dhcp6-resend-expire-timer", true);
1063 client_stop(client
, r
);
1068 static int client_ensure_iaid(sd_dhcp6_client
*client
) {
1074 if (client
->iaid_set
)
1077 r
= dhcp_identifier_set_iaid(client
->ifindex
, client
->mac_addr
, client
->mac_addr_len
, true, &iaid
);
1081 client
->ia_na
.ia_na
.id
= iaid
;
1082 client
->ia_pd
.ia_pd
.id
= iaid
;
1083 client
->iaid_set
= true;
1088 static int client_parse_message(
1089 sd_dhcp6_client
*client
,
1090 DHCP6Message
*message
,
1092 sd_dhcp6_lease
*lease
) {
1094 uint16_t ia_na_status
= 0, ia_pd_status
= 0;
1095 uint32_t lt_t1
= ~0, lt_t2
= ~0;
1096 usec_t irt
= IRT_DEFAULT
;
1097 bool clientid
= false;
1103 assert(len
>= sizeof(DHCP6Message
));
1106 len
-= sizeof(DHCP6Message
);
1109 DHCP6Option
*option
= (DHCP6Option
*) &message
->options
[pos
];
1110 uint16_t optcode
, optlen
;
1115 if (len
< pos
+ offsetof(DHCP6Option
, data
))
1118 optcode
= be16toh(option
->code
);
1119 optlen
= be16toh(option
->len
);
1120 optval
= option
->data
;
1122 if (len
< pos
+ offsetof(DHCP6Option
, data
) + optlen
)
1126 case SD_DHCP6_OPTION_CLIENTID
:
1128 log_dhcp6_client(client
, "%s contains multiple clientids",
1129 dhcp6_message_type_to_string(message
->type
));
1133 if (optlen
!= client
->duid_len
||
1134 memcmp(&client
->duid
, optval
, optlen
) != 0) {
1135 log_dhcp6_client(client
, "%s DUID does not match",
1136 dhcp6_message_type_to_string(message
->type
));
1144 case SD_DHCP6_OPTION_SERVERID
:
1145 r
= dhcp6_lease_get_serverid(lease
, NULL
, NULL
);
1147 log_dhcp6_client(client
, "%s contains multiple serverids",
1148 dhcp6_message_type_to_string(message
->type
));
1152 r
= dhcp6_lease_set_serverid(lease
, optval
, optlen
);
1158 case SD_DHCP6_OPTION_PREFERENCE
:
1162 r
= dhcp6_lease_set_preference(lease
, optval
[0]);
1168 case SD_DHCP6_OPTION_STATUS_CODE
:
1169 status
= dhcp6_option_parse_status(option
, optlen
+ sizeof(DHCP6Option
));
1174 log_dhcp6_client(client
, "%s Status %s",
1175 dhcp6_message_type_to_string(message
->type
),
1176 dhcp6_message_status_to_string(status
));
1183 case SD_DHCP6_OPTION_IA_NA
:
1184 if (client
->state
== DHCP6_STATE_INFORMATION_REQUEST
) {
1185 log_dhcp6_client(client
, "Information request ignoring IA NA option");
1190 r
= dhcp6_option_parse_ia(option
, &lease
->ia
, &ia_na_status
);
1191 if (r
< 0 && r
!= -ENOMSG
)
1194 if (ia_na_status
== DHCP6_STATUS_NO_ADDRS_AVAIL
) {
1195 pos
+= offsetof(DHCP6Option
, data
) + optlen
;
1199 r
= dhcp6_lease_get_iaid(lease
, &iaid_lease
);
1203 if (client
->ia_na
.ia_na
.id
!= iaid_lease
) {
1204 log_dhcp6_client(client
, "%s has wrong IAID for IA NA",
1205 dhcp6_message_type_to_string(message
->type
));
1209 if (lease
->ia
.addresses
) {
1210 lt_t1
= MIN(lt_t1
, be32toh(lease
->ia
.ia_na
.lifetime_t1
));
1211 lt_t2
= MIN(lt_t2
, be32toh(lease
->ia
.ia_na
.lifetime_t1
));
1216 case SD_DHCP6_OPTION_IA_PD
:
1217 if (client
->state
== DHCP6_STATE_INFORMATION_REQUEST
) {
1218 log_dhcp6_client(client
, "Information request ignoring IA PD option");
1223 r
= dhcp6_option_parse_ia(option
, &lease
->pd
, &ia_pd_status
);
1224 if (r
< 0 && r
!= -ENOMSG
)
1227 if (ia_pd_status
== DHCP6_STATUS_NO_PREFIX_AVAIL
) {
1228 pos
+= offsetof(DHCP6Option
, data
) + optlen
;
1232 r
= dhcp6_lease_get_pd_iaid(lease
, &iaid_lease
);
1236 if (client
->ia_pd
.ia_pd
.id
!= iaid_lease
) {
1237 log_dhcp6_client(client
, "%s has wrong IAID for IA PD",
1238 dhcp6_message_type_to_string(message
->type
));
1242 if (lease
->pd
.addresses
) {
1243 lt_t1
= MIN(lt_t1
, be32toh(lease
->pd
.ia_pd
.lifetime_t1
));
1244 lt_t2
= MIN(lt_t2
, be32toh(lease
->pd
.ia_pd
.lifetime_t2
));
1249 case SD_DHCP6_OPTION_RAPID_COMMIT
:
1250 r
= dhcp6_lease_set_rapid_commit(lease
);
1256 case SD_DHCP6_OPTION_DNS_SERVERS
:
1257 r
= dhcp6_lease_set_dns(lease
, optval
, optlen
);
1263 case SD_DHCP6_OPTION_DOMAIN_LIST
:
1264 r
= dhcp6_lease_set_domains(lease
, optval
, optlen
);
1270 case SD_DHCP6_OPTION_NTP_SERVER
:
1271 r
= dhcp6_lease_set_ntp(lease
, optval
, optlen
);
1277 case SD_DHCP6_OPTION_SNTP_SERVERS
:
1278 r
= dhcp6_lease_set_sntp(lease
, optval
, optlen
);
1284 case SD_DHCP6_OPTION_FQDN
:
1285 r
= dhcp6_lease_set_fqdn(lease
, optval
, optlen
);
1291 case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME
:
1295 irt
= unaligned_read_be32((be32_t
*) optval
) * USEC_PER_SEC
;
1299 pos
+= offsetof(DHCP6Option
, data
) + optlen
;
1302 if (ia_na_status
> 0 && ia_pd_status
> 0) {
1303 log_dhcp6_client(client
, "No IA_PD prefix or IA_NA address received. Ignoring.");
1308 log_dhcp6_client(client
, "%s has incomplete options",
1309 dhcp6_message_type_to_string(message
->type
));
1313 if (client
->state
!= DHCP6_STATE_INFORMATION_REQUEST
) {
1314 r
= dhcp6_lease_get_serverid(lease
, NULL
, NULL
);
1316 log_dhcp6_client(client
, "%s has no server id",
1317 dhcp6_message_type_to_string(message
->type
));
1322 if (lease
->ia
.addresses
) {
1323 lease
->ia
.ia_na
.lifetime_t1
= htobe32(lt_t1
);
1324 lease
->ia
.ia_na
.lifetime_t2
= htobe32(lt_t2
);
1327 if (lease
->pd
.addresses
) {
1328 lease
->pd
.ia_pd
.lifetime_t1
= htobe32(lt_t1
);
1329 lease
->pd
.ia_pd
.lifetime_t2
= htobe32(lt_t2
);
1333 client
->information_refresh_time_usec
= MAX(irt
, IRT_MINIMUM
);
1338 static int client_receive_reply(sd_dhcp6_client
*client
, DHCP6Message
*reply
, size_t len
) {
1339 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
1346 if (reply
->type
!= DHCP6_REPLY
)
1349 r
= dhcp6_lease_new(&lease
);
1353 r
= client_parse_message(client
, reply
, len
, lease
);
1357 if (client
->state
== DHCP6_STATE_SOLICITATION
) {
1358 r
= dhcp6_lease_get_rapid_commit(lease
, &rapid_commit
);
1366 sd_dhcp6_lease_unref(client
->lease
);
1367 client
->lease
= TAKE_PTR(lease
);
1369 return DHCP6_STATE_BOUND
;
1372 static int client_receive_advertise(sd_dhcp6_client
*client
, DHCP6Message
*advertise
, size_t len
) {
1373 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
1374 uint8_t pref_advertise
= 0, pref_lease
= 0;
1377 if (advertise
->type
!= DHCP6_ADVERTISE
)
1380 r
= dhcp6_lease_new(&lease
);
1384 r
= client_parse_message(client
, advertise
, len
, lease
);
1388 r
= dhcp6_lease_get_preference(lease
, &pref_advertise
);
1392 r
= dhcp6_lease_get_preference(client
->lease
, &pref_lease
);
1394 if (r
< 0 || pref_advertise
> pref_lease
) {
1395 sd_dhcp6_lease_unref(client
->lease
);
1396 client
->lease
= TAKE_PTR(lease
);
1400 if (pref_advertise
== 255 || client
->retransmit_count
> 1)
1401 r
= DHCP6_STATE_REQUEST
;
1406 static int client_receive_message(
1412 sd_dhcp6_client
*client
= userdata
;
1413 DHCP6_CLIENT_DONT_DESTROY(client
);
1414 _cleanup_free_ DHCP6Message
*message
= NULL
;
1415 ssize_t buflen
, len
;
1420 assert(client
->event
);
1422 buflen
= next_datagram_size_fd(fd
);
1423 if (buflen
== -ENETDOWN
) {
1424 /* the link is down. Don't return an error or the I/O event
1425 source will be disconnected and we won't be able to receive
1426 packets again when the link comes back. */
1432 message
= malloc(buflen
);
1436 len
= recv(fd
, message
, buflen
, 0);
1438 /* see comment above for why we shouldn't error out on ENETDOWN. */
1439 if (IN_SET(errno
, EAGAIN
, EINTR
, ENETDOWN
))
1442 return log_dhcp6_client_errno(client
, errno
, "Could not receive message from UDP socket: %m");
1445 if ((size_t) len
< sizeof(DHCP6Message
)) {
1446 log_dhcp6_client(client
, "Too small to be DHCP6 message: ignoring");
1450 switch(message
->type
) {
1458 case DHCP6_INFORMATION_REQUEST
:
1459 case DHCP6_RELAY_FORW
:
1460 case DHCP6_RELAY_REPL
:
1463 case DHCP6_ADVERTISE
:
1465 case DHCP6_RECONFIGURE
:
1469 log_dhcp6_client(client
, "Unknown message type %d", message
->type
);
1473 if (client
->transaction_id
!= (message
->transaction_id
&
1474 htobe32(0x00ffffff)))
1477 switch (client
->state
) {
1478 case DHCP6_STATE_INFORMATION_REQUEST
:
1479 r
= client_receive_reply(client
, message
, len
);
1483 client_notify(client
, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
1485 client_start(client
, DHCP6_STATE_STOPPED
);
1489 case DHCP6_STATE_SOLICITATION
:
1490 r
= client_receive_advertise(client
, message
, len
);
1492 if (r
== DHCP6_STATE_REQUEST
) {
1493 client_start(client
, r
);
1498 _fallthrough_
; /* for Solicitation Rapid Commit option check */
1499 case DHCP6_STATE_REQUEST
:
1500 case DHCP6_STATE_RENEW
:
1501 case DHCP6_STATE_REBIND
:
1503 r
= client_receive_reply(client
, message
, len
);
1507 if (r
== DHCP6_STATE_BOUND
) {
1509 r
= client_start(client
, DHCP6_STATE_BOUND
);
1511 client_stop(client
, r
);
1515 client_notify(client
, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
1520 case DHCP6_STATE_BOUND
:
1524 case DHCP6_STATE_STOPPED
:
1528 log_dhcp6_client(client
, "Recv %s",
1529 dhcp6_message_type_to_string(message
->type
));
1534 static int client_get_lifetime(sd_dhcp6_client
*client
, uint32_t *lifetime_t1
,
1535 uint32_t *lifetime_t2
) {
1536 assert_return(client
, -EINVAL
);
1537 assert_return(client
->lease
, -EINVAL
);
1539 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
) && client
->lease
->ia
.addresses
) {
1540 *lifetime_t1
= be32toh(client
->lease
->ia
.ia_na
.lifetime_t1
);
1541 *lifetime_t2
= be32toh(client
->lease
->ia
.ia_na
.lifetime_t2
);
1546 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
) && client
->lease
->pd
.addresses
) {
1547 *lifetime_t1
= be32toh(client
->lease
->pd
.ia_pd
.lifetime_t1
);
1548 *lifetime_t2
= be32toh(client
->lease
->pd
.ia_pd
.lifetime_t2
);
1556 static int client_start(sd_dhcp6_client
*client
, enum DHCP6State state
) {
1558 usec_t timeout
, time_now
;
1559 char time_string
[FORMAT_TIMESPAN_MAX
];
1560 uint32_t lifetime_t1
, lifetime_t2
;
1562 assert_return(client
, -EINVAL
);
1563 assert_return(client
->event
, -EINVAL
);
1564 assert_return(client
->ifindex
> 0, -EINVAL
);
1565 assert_return(client
->state
!= state
, -EINVAL
);
1567 (void) event_source_disable(client
->timeout_resend_expire
);
1568 (void) event_source_disable(client
->timeout_resend
);
1569 client
->retransmit_time
= 0;
1570 client
->retransmit_count
= 0;
1572 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
1576 if (!client
->receive_message
) {
1577 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
1578 client
->fd
, EPOLLIN
, client_receive_message
,
1583 r
= sd_event_source_set_priority(client
->receive_message
,
1584 client
->event_priority
);
1588 r
= sd_event_source_set_description(client
->receive_message
,
1589 "dhcp6-receive-message");
1595 case DHCP6_STATE_STOPPED
:
1596 if (client
->state
== DHCP6_STATE_INFORMATION_REQUEST
) {
1597 client
->state
= DHCP6_STATE_STOPPED
;
1603 case DHCP6_STATE_SOLICITATION
:
1604 client
->state
= DHCP6_STATE_SOLICITATION
;
1608 case DHCP6_STATE_INFORMATION_REQUEST
:
1609 case DHCP6_STATE_REQUEST
:
1610 case DHCP6_STATE_RENEW
:
1611 case DHCP6_STATE_REBIND
:
1613 client
->state
= state
;
1617 case DHCP6_STATE_BOUND
:
1619 r
= client_get_lifetime(client
, &lifetime_t1
, &lifetime_t2
);
1623 if (lifetime_t1
== 0xffffffff || lifetime_t2
== 0xffffffff) {
1624 log_dhcp6_client(client
, "Infinite T1 0x%08x or T2 0x%08x",
1625 lifetime_t1
, lifetime_t2
);
1630 timeout
= client_timeout_compute_random(lifetime_t1
* USEC_PER_SEC
);
1632 log_dhcp6_client(client
, "T1 expires in %s",
1633 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, timeout
, USEC_PER_SEC
));
1635 r
= event_reset_time(client
->event
, &client
->timeout_t1
,
1636 clock_boottime_or_monotonic(),
1637 time_now
+ timeout
, 10 * USEC_PER_SEC
,
1638 client_timeout_t1
, client
,
1639 client
->event_priority
, "dhcp6-t1-timeout", true);
1643 timeout
= client_timeout_compute_random(lifetime_t2
* USEC_PER_SEC
);
1645 log_dhcp6_client(client
, "T2 expires in %s",
1646 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, timeout
, USEC_PER_SEC
));
1648 r
= event_reset_time(client
->event
, &client
->timeout_t2
,
1649 clock_boottime_or_monotonic(),
1650 time_now
+ timeout
, 10 * USEC_PER_SEC
,
1651 client_timeout_t2
, client
,
1652 client
->event_priority
, "dhcp6-t2-timeout", true);
1656 client
->state
= state
;
1661 client
->transaction_id
= random_u32() & htobe32(0x00ffffff);
1662 client
->transaction_start
= time_now
;
1664 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1665 clock_boottime_or_monotonic(),
1667 client_timeout_resend
, client
,
1668 client
->event_priority
, "dhcp6-resend-timeout", true);
1675 client_reset(client
);
1679 int sd_dhcp6_client_stop(sd_dhcp6_client
*client
) {
1680 assert_return(client
, -EINVAL
);
1682 client_stop(client
, SD_DHCP6_CLIENT_EVENT_STOP
);
1684 client
->fd
= safe_close(client
->fd
);
1689 int sd_dhcp6_client_is_running(sd_dhcp6_client
*client
) {
1690 assert_return(client
, -EINVAL
);
1692 return client
->state
!= DHCP6_STATE_STOPPED
;
1695 int sd_dhcp6_client_start(sd_dhcp6_client
*client
) {
1696 enum DHCP6State state
= DHCP6_STATE_SOLICITATION
;
1699 assert_return(client
, -EINVAL
);
1700 assert_return(client
->event
, -EINVAL
);
1701 assert_return(client
->ifindex
> 0, -EINVAL
);
1702 assert_return(in_addr_is_link_local(AF_INET6
, (const union in_addr_union
*) &client
->local_address
) > 0, -EINVAL
);
1704 if (!IN_SET(client
->state
, DHCP6_STATE_STOPPED
))
1707 if (!client
->information_request
&& !client
->request
)
1710 r
= client_reset(client
);
1714 r
= client_ensure_iaid(client
);
1718 r
= client_ensure_duid(client
);
1722 if (client
->fd
< 0) {
1723 r
= dhcp6_network_bind_udp_socket(client
->ifindex
, &client
->local_address
);
1725 _cleanup_free_
char *p
= NULL
;
1727 (void) in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &client
->local_address
, &p
);
1728 return log_dhcp6_client_errno(client
, r
,
1729 "Failed to bind to UDP socket at address %s: %m", strna(p
));
1735 if (client
->information_request
) {
1736 usec_t t
= now(CLOCK_MONOTONIC
);
1738 if (t
< usec_add(client
->information_request_time_usec
, client
->information_refresh_time_usec
))
1741 client
->information_request_time_usec
= t
;
1742 state
= DHCP6_STATE_INFORMATION_REQUEST
;
1745 log_dhcp6_client(client
, "Started in %s mode",
1746 client
->information_request
? "Information request":
1749 return client_start(client
, state
);
1752 int sd_dhcp6_client_attach_event(sd_dhcp6_client
*client
, sd_event
*event
, int64_t priority
) {
1755 assert_return(client
, -EINVAL
);
1756 assert_return(!client
->event
, -EBUSY
);
1759 client
->event
= sd_event_ref(event
);
1761 r
= sd_event_default(&client
->event
);
1766 client
->event_priority
= priority
;
1771 int sd_dhcp6_client_detach_event(sd_dhcp6_client
*client
) {
1772 assert_return(client
, -EINVAL
);
1774 client
->event
= sd_event_unref(client
->event
);
1779 sd_event
*sd_dhcp6_client_get_event(sd_dhcp6_client
*client
) {
1780 assert_return(client
, NULL
);
1782 return client
->event
;
1785 static sd_dhcp6_client
*dhcp6_client_free(sd_dhcp6_client
*client
) {
1788 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
1789 client
->timeout_resend_expire
= sd_event_source_unref(client
->timeout_resend_expire
);
1790 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
1791 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
1793 client_reset(client
);
1795 client
->fd
= safe_close(client
->fd
);
1797 sd_dhcp6_client_detach_event(client
);
1799 free(client
->req_opts
);
1801 free(client
->mudurl
);
1803 ordered_hashmap_free(client
->extra_options
);
1804 strv_free(client
->user_class
);
1805 strv_free(client
->vendor_class
);
1807 return mfree(client
);
1810 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client
, sd_dhcp6_client
, dhcp6_client_free
);
1812 int sd_dhcp6_client_new(sd_dhcp6_client
**ret
) {
1813 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
1814 _cleanup_free_ be16_t
*req_opts
= NULL
;
1817 assert_return(ret
, -EINVAL
);
1819 req_opts
= new(be16_t
, ELEMENTSOF(default_req_opts
));
1823 for (t
= 0; t
< ELEMENTSOF(default_req_opts
); t
++)
1824 req_opts
[t
] = htobe16(default_req_opts
[t
]);
1826 client
= new(sd_dhcp6_client
, 1);
1830 *client
= (sd_dhcp6_client
) {
1832 .ia_na
.type
= SD_DHCP6_OPTION_IA_NA
,
1833 .ia_pd
.type
= SD_DHCP6_OPTION_IA_PD
,
1835 .request
= DHCP6_REQUEST_IA_NA
,
1837 .req_opts_len
= ELEMENTSOF(default_req_opts
),
1838 .hint_pd_prefix
.iapdprefix
.lifetime_preferred
= (be32_t
) -1,
1839 .hint_pd_prefix
.iapdprefix
.lifetime_valid
= (be32_t
) -1,
1840 .req_opts
= TAKE_PTR(req_opts
),
1843 *ret
= TAKE_PTR(client
);