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 "hostname-util.h"
22 #include "in-addr-util.h"
23 #include "network-internal.h"
24 #include "random-util.h"
25 #include "socket-util.h"
26 #include "string-table.h"
30 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
32 #define IRT_DEFAULT (1 * USEC_PER_DAY)
33 #define IRT_MINIMUM (600 * USEC_PER_SEC)
35 /* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
37 DHCP6_REQUEST_IA_NA
= 1,
38 DHCP6_REQUEST_IA_TA
= 2, /* currently not used */
39 DHCP6_REQUEST_IA_PD
= 4,
42 struct sd_dhcp6_client
{
45 enum DHCP6State state
;
49 DHCP6Address hint_pd_prefix
;
50 struct in6_addr local_address
;
51 uint8_t mac_addr
[MAX_MAC_ADDR_LEN
];
56 sd_event_source
*timeout_t1
;
57 sd_event_source
*timeout_t2
;
59 be32_t transaction_id
;
60 usec_t transaction_start
;
61 struct sd_dhcp6_lease
*lease
;
63 bool information_request
;
66 size_t req_opts_allocated
;
72 sd_event_source
*receive_message
;
73 usec_t retransmit_time
;
74 uint8_t retransmit_count
;
75 sd_event_source
*timeout_resend
;
76 sd_event_source
*timeout_resend_expire
;
77 sd_dhcp6_client_callback_t callback
;
81 usec_t information_request_time_usec
;
82 usec_t information_refresh_time_usec
;
83 OrderedHashmap
*extra_options
;
84 OrderedHashmap
*vendor_options
;
87 static const uint16_t default_req_opts
[] = {
88 SD_DHCP6_OPTION_DNS_SERVERS
,
89 SD_DHCP6_OPTION_DOMAIN_LIST
,
90 SD_DHCP6_OPTION_NTP_SERVER
,
91 SD_DHCP6_OPTION_SNTP_SERVERS
,
94 const char * dhcp6_message_type_table
[_DHCP6_MESSAGE_MAX
] = {
95 [DHCP6_SOLICIT
] = "SOLICIT",
96 [DHCP6_ADVERTISE
] = "ADVERTISE",
97 [DHCP6_REQUEST
] = "REQUEST",
98 [DHCP6_CONFIRM
] = "CONFIRM",
99 [DHCP6_RENEW
] = "RENEW",
100 [DHCP6_REBIND
] = "REBIND",
101 [DHCP6_REPLY
] = "REPLY",
102 [DHCP6_RELEASE
] = "RELEASE",
103 [DHCP6_DECLINE
] = "DECLINE",
104 [DHCP6_RECONFIGURE
] = "RECONFIGURE",
105 [DHCP6_INFORMATION_REQUEST
] = "INFORMATION-REQUEST",
106 [DHCP6_RELAY_FORW
] = "RELAY-FORW",
107 [DHCP6_RELAY_REPL
] = "RELAY-REPL",
110 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type
, int);
112 const char * dhcp6_message_status_table
[_DHCP6_STATUS_MAX
] = {
113 [DHCP6_STATUS_SUCCESS
] = "Success",
114 [DHCP6_STATUS_UNSPEC_FAIL
] = "Unspecified failure",
115 [DHCP6_STATUS_NO_ADDRS_AVAIL
] = "No addresses available",
116 [DHCP6_STATUS_NO_BINDING
] = "Binding unavailable",
117 [DHCP6_STATUS_NOT_ON_LINK
] = "Not on link",
118 [DHCP6_STATUS_USE_MULTICAST
] = "Use multicast",
119 [DHCP6_STATUS_NO_PREFIX_AVAIL
] = "No prefix available",
120 [DHCP6_STATUS_UNKNOWN_QUERY_TYPE
] = "Unknown query type",
121 [DHCP6_STATUS_MALFORMED_QUERY
] = "Malformed query",
122 [DHCP6_STATUS_NOT_CONFIGURED
] = "Not configured",
123 [DHCP6_STATUS_NOT_ALLOWED
] = "Not allowed",
124 [DHCP6_STATUS_QUERY_TERMINATED
] = "Query terminated",
125 [DHCP6_STATUS_DATA_MISSING
] = "Data missing",
126 [DHCP6_STATUS_CATCHUP_COMPLETE
] = "Catch up complete",
127 [DHCP6_STATUS_NOT_SUPPORTED
] = "Not supported",
128 [DHCP6_STATUS_TLS_CONNECTION_REFUSED
] = "TLS connection refused",
129 [DHCP6_STATUS_ADDRESS_IN_USE
] = "Address in use",
130 [DHCP6_STATUS_CONFIGURATION_CONFLICT
] = "Configuration conflict",
131 [DHCP6_STATUS_MISSING_BINDING_INFORMATION
] = "Missing binding information",
132 [DHCP6_STATUS_OUTDATED_BINDING_INFORMATION
] = "Outdated binding information",
133 [DHCP6_STATUS_SERVER_SHUTTING_DOWN
] = "Server shutting down",
134 [DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED
] = "DNS update not supported",
135 [DHCP6_STATUS_EXCESSIVE_TIME_SKEW
] = "Excessive time skew",
138 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status
, int);
140 #define DHCP6_CLIENT_DONT_DESTROY(client) \
141 _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
143 static int client_start(sd_dhcp6_client
*client
, enum DHCP6State state
);
145 int sd_dhcp6_client_set_callback(
146 sd_dhcp6_client
*client
,
147 sd_dhcp6_client_callback_t cb
,
150 assert_return(client
, -EINVAL
);
152 client
->callback
= cb
;
153 client
->userdata
= userdata
;
158 int sd_dhcp6_client_set_ifindex(sd_dhcp6_client
*client
, int ifindex
) {
160 assert_return(client
, -EINVAL
);
161 assert_return(ifindex
>= -1, -EINVAL
);
162 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
164 client
->ifindex
= ifindex
;
168 int sd_dhcp6_client_set_local_address(
169 sd_dhcp6_client
*client
,
170 const struct in6_addr
*local_address
) {
172 assert_return(client
, -EINVAL
);
173 assert_return(local_address
, -EINVAL
);
174 assert_return(in_addr_is_link_local(AF_INET6
, (const union in_addr_union
*) local_address
) > 0, -EINVAL
);
176 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
178 client
->local_address
= *local_address
;
183 int sd_dhcp6_client_set_mac(
184 sd_dhcp6_client
*client
,
185 const uint8_t *addr
, size_t addr_len
,
188 assert_return(client
, -EINVAL
);
189 assert_return(addr
, -EINVAL
);
190 assert_return(addr_len
> 0 && addr_len
<= MAX_MAC_ADDR_LEN
, -EINVAL
);
191 assert_return(arp_type
> 0, -EINVAL
);
193 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
195 if (arp_type
== ARPHRD_ETHER
)
196 assert_return(addr_len
== ETH_ALEN
, -EINVAL
);
197 else if (arp_type
== ARPHRD_INFINIBAND
)
198 assert_return(addr_len
== INFINIBAND_ALEN
, -EINVAL
);
202 if (client
->mac_addr_len
== addr_len
&&
203 memcmp(&client
->mac_addr
, addr
, addr_len
) == 0)
206 memcpy(&client
->mac_addr
, addr
, addr_len
);
207 client
->mac_addr_len
= addr_len
;
208 client
->arp_type
= arp_type
;
213 int sd_dhcp6_client_set_prefix_delegation_hint(
214 sd_dhcp6_client
*client
,
216 const struct in6_addr
*pd_address
) {
218 assert_return(client
, -EINVAL
);
219 assert_return(pd_address
, -EINVAL
);
221 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
223 client
->hint_pd_prefix
.iapdprefix
.address
= *pd_address
;
224 client
->hint_pd_prefix
.iapdprefix
.prefixlen
= prefixlen
;
229 int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client
*client
, sd_dhcp6_option
*v
) {
232 assert_return(client
, -EINVAL
);
233 assert_return(v
, -EINVAL
);
235 r
= ordered_hashmap_ensure_allocated(&client
->vendor_options
, &dhcp6_option_hash_ops
);
239 r
= ordered_hashmap_put(client
->vendor_options
, v
, v
);
243 sd_dhcp6_option_ref(v
);
248 static int client_ensure_duid(sd_dhcp6_client
*client
) {
249 if (client
->duid_len
!= 0)
252 return dhcp_identifier_set_duid_en(&client
->duid
, &client
->duid_len
);
256 * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
257 * without further modification. Otherwise, if duid_type is supported, DUID
258 * is set based on that type. Otherwise, an error is returned.
260 static int dhcp6_client_set_duid_internal(
261 sd_dhcp6_client
*client
,
268 assert_return(client
, -EINVAL
);
269 assert_return(duid_len
== 0 || duid
!= NULL
, -EINVAL
);
270 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
273 r
= dhcp_validate_duid_len(duid_type
, duid_len
, true);
275 r
= dhcp_validate_duid_len(duid_type
, duid_len
, false);
277 return log_dhcp6_client_errno(client
, r
, "Failed to validate length of DUID: %m");
279 log_dhcp6_client(client
, "Using DUID of type %u of incorrect length, proceeding.", duid_type
);
282 client
->duid
.type
= htobe16(duid_type
);
283 memcpy(&client
->duid
.raw
.data
, duid
, duid_len
);
284 client
->duid_len
= sizeof(client
->duid
.type
) + duid_len
;
288 if (client
->mac_addr_len
== 0)
289 return log_dhcp6_client_errno(client
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to set DUID-LLT, MAC address is not set.");
291 r
= dhcp_identifier_set_duid_llt(&client
->duid
, llt_time
, client
->mac_addr
, client
->mac_addr_len
, client
->arp_type
, &client
->duid_len
);
293 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-LLT: %m");
296 r
= dhcp_identifier_set_duid_en(&client
->duid
, &client
->duid_len
);
298 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-EN: %m");
301 if (client
->mac_addr_len
== 0)
302 return log_dhcp6_client_errno(client
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to set DUID-LL, MAC address is not set.");
304 r
= dhcp_identifier_set_duid_ll(&client
->duid
, client
->mac_addr
, client
->mac_addr_len
, client
->arp_type
, &client
->duid_len
);
306 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-LL: %m");
309 r
= dhcp_identifier_set_duid_uuid(&client
->duid
, &client
->duid_len
);
311 return log_dhcp6_client_errno(client
, r
, "Failed to set DUID-UUID: %m");
314 return log_dhcp6_client_errno(client
, SYNTHETIC_ERRNO(EINVAL
), "Invalid DUID type");
320 int sd_dhcp6_client_set_duid(
321 sd_dhcp6_client
*client
,
325 return dhcp6_client_set_duid_internal(client
, duid_type
, duid
, duid_len
, 0);
328 int sd_dhcp6_client_set_duid_llt(
329 sd_dhcp6_client
*client
,
331 return dhcp6_client_set_duid_internal(client
, DUID_TYPE_LLT
, NULL
, 0, llt_time
);
334 int sd_dhcp6_client_set_iaid(sd_dhcp6_client
*client
, uint32_t iaid
) {
335 assert_return(client
, -EINVAL
);
336 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
338 client
->ia_na
.ia_na
.id
= htobe32(iaid
);
339 client
->ia_pd
.ia_pd
.id
= htobe32(iaid
);
340 client
->iaid_set
= true;
345 int sd_dhcp6_client_set_fqdn(
346 sd_dhcp6_client
*client
,
349 assert_return(client
, -EINVAL
);
351 /* Make sure FQDN qualifies as DNS and as Linux hostname */
353 !(hostname_is_valid(fqdn
, false) && dns_name_is_valid(fqdn
) > 0))
356 return free_and_strdup(&client
->fqdn
, fqdn
);
359 int sd_dhcp6_client_set_information_request(sd_dhcp6_client
*client
, int enabled
) {
360 assert_return(client
, -EINVAL
);
361 assert_return(IN_SET(client
->state
, DHCP6_STATE_STOPPED
), -EBUSY
);
363 client
->information_request
= enabled
;
368 int sd_dhcp6_client_get_information_request(sd_dhcp6_client
*client
, int *enabled
) {
369 assert_return(client
, -EINVAL
);
370 assert_return(enabled
, -EINVAL
);
372 *enabled
= client
->information_request
;
377 int sd_dhcp6_client_set_request_option(sd_dhcp6_client
*client
, uint16_t option
) {
380 assert_return(client
, -EINVAL
);
381 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
383 if (option
<= 0 || option
>= UINT8_MAX
)
386 for (t
= 0; t
< client
->req_opts_len
; t
++)
387 if (client
->req_opts
[t
] == htobe16(option
))
390 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
391 client
->req_opts_len
+ 1))
394 client
->req_opts
[client
->req_opts_len
++] = htobe16(option
);
399 int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client
*client
, const char *mudurl
) {
401 assert_return(client
, -EINVAL
);
402 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
403 assert_return(mudurl
, -EINVAL
);
404 assert_return(strlen(mudurl
) <= UINT8_MAX
, -EINVAL
);
405 assert_return(http_url_is_valid(mudurl
), -EINVAL
);
407 return free_and_strdup(&client
->mudurl
, mudurl
);
410 int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client
*client
, char **user_class
) {
411 _cleanup_strv_free_
char **s
= NULL
;
414 assert_return(client
, -EINVAL
);
415 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
417 assert_return(user_class
, -EINVAL
);
419 STRV_FOREACH(p
, user_class
)
420 if (strlen(*p
) > UINT16_MAX
)
421 return -ENAMETOOLONG
;
423 s
= strv_copy(user_class
);
427 client
->user_class
= TAKE_PTR(s
);
432 int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client
*client
, char **vendor_class
) {
433 _cleanup_strv_free_
char **s
= NULL
;
436 assert_return(client
, -EINVAL
);
437 assert_return(client
->state
== DHCP6_STATE_STOPPED
, -EBUSY
);
438 assert_return(vendor_class
, -EINVAL
);
440 STRV_FOREACH(p
, vendor_class
)
441 if (strlen(*p
) > UINT8_MAX
)
442 return -ENAMETOOLONG
;
444 s
= strv_copy(vendor_class
);
448 client
->vendor_class
= TAKE_PTR(s
);
453 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client
*client
, int *delegation
) {
454 assert_return(client
, -EINVAL
);
455 assert_return(delegation
, -EINVAL
);
457 *delegation
= FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
);
462 int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client
*client
, int delegation
) {
463 assert_return(client
, -EINVAL
);
465 SET_FLAG(client
->request
, DHCP6_REQUEST_IA_PD
, delegation
);
470 int sd_dhcp6_client_get_address_request(sd_dhcp6_client
*client
, int *request
) {
471 assert_return(client
, -EINVAL
);
472 assert_return(request
, -EINVAL
);
474 *request
= FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
);
479 int sd_dhcp6_client_set_address_request(sd_dhcp6_client
*client
, int request
) {
480 assert_return(client
, -EINVAL
);
482 SET_FLAG(client
->request
, DHCP6_REQUEST_IA_NA
, request
);
487 int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client
*client
, uint32_t transaction_id
) {
488 assert_return(client
, -EINVAL
);
490 client
->transaction_id
= transaction_id
;
495 int sd_dhcp6_client_get_lease(sd_dhcp6_client
*client
, sd_dhcp6_lease
**ret
) {
496 assert_return(client
, -EINVAL
);
502 *ret
= client
->lease
;
507 int sd_dhcp6_client_add_option(sd_dhcp6_client
*client
, sd_dhcp6_option
*v
) {
510 assert_return(client
, -EINVAL
);
511 assert_return(v
, -EINVAL
);
513 r
= ordered_hashmap_ensure_allocated(&client
->extra_options
, &dhcp6_option_hash_ops
);
517 r
= ordered_hashmap_put(client
->extra_options
, UINT_TO_PTR(v
->option
), v
);
521 sd_dhcp6_option_ref(v
);
525 static void client_notify(sd_dhcp6_client
*client
, int event
) {
528 if (client
->callback
)
529 client
->callback(client
, event
, client
->userdata
);
532 static int client_reset(sd_dhcp6_client
*client
) {
535 client
->lease
= sd_dhcp6_lease_unref(client
->lease
);
537 client
->receive_message
=
538 sd_event_source_unref(client
->receive_message
);
540 client
->transaction_id
= 0;
541 client
->transaction_start
= 0;
543 client
->retransmit_time
= 0;
544 client
->retransmit_count
= 0;
546 (void) event_source_disable(client
->timeout_resend
);
547 (void) event_source_disable(client
->timeout_resend_expire
);
548 (void) event_source_disable(client
->timeout_t1
);
549 (void) event_source_disable(client
->timeout_t2
);
551 client
->state
= DHCP6_STATE_STOPPED
;
556 static void client_stop(sd_dhcp6_client
*client
, int error
) {
557 DHCP6_CLIENT_DONT_DESTROY(client
);
561 client_notify(client
, error
);
563 client_reset(client
);
566 static int client_send_message(sd_dhcp6_client
*client
, usec_t time_now
) {
567 _cleanup_free_ DHCP6Message
*message
= NULL
;
568 struct in6_addr all_servers
=
569 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
570 struct sd_dhcp6_option
*j
;
571 size_t len
, optlen
= 512;
580 len
= sizeof(DHCP6Message
) + optlen
;
582 message
= malloc0(len
);
586 opt
= (uint8_t *)(message
+ 1);
588 message
->transaction_id
= client
->transaction_id
;
590 switch(client
->state
) {
591 case DHCP6_STATE_INFORMATION_REQUEST
:
592 message
->type
= DHCP6_INFORMATION_REQUEST
;
594 if (client
->mudurl
) {
595 r
= dhcp6_option_append(&opt
, &optlen
,
596 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
604 case DHCP6_STATE_SOLICITATION
:
605 message
->type
= DHCP6_SOLICIT
;
607 r
= dhcp6_option_append(&opt
, &optlen
,
608 SD_DHCP6_OPTION_RAPID_COMMIT
, 0, NULL
);
612 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
)) {
613 r
= dhcp6_option_append_ia(&opt
, &optlen
,
620 r
= dhcp6_option_append_fqdn(&opt
, &optlen
, client
->fqdn
);
625 if (client
->mudurl
) {
626 r
= dhcp6_option_append(&opt
, &optlen
,
627 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
633 if (client
->user_class
) {
634 r
= dhcp6_option_append_user_class(&opt
, &optlen
, client
->user_class
);
639 if (client
->vendor_class
) {
640 r
= dhcp6_option_append_vendor_class(&opt
, &optlen
, client
->vendor_class
);
645 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
646 r
= dhcp6_option_append_vendor_option(&opt
, &optlen
,
647 client
->vendor_options
);
652 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
)) {
653 r
= dhcp6_option_append_pd(opt
, optlen
, &client
->ia_pd
, &client
->hint_pd_prefix
);
663 case DHCP6_STATE_REQUEST
:
664 case DHCP6_STATE_RENEW
:
666 if (client
->state
== DHCP6_STATE_REQUEST
)
667 message
->type
= DHCP6_REQUEST
;
669 message
->type
= DHCP6_RENEW
;
671 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_SERVERID
,
672 client
->lease
->serverid_len
,
673 client
->lease
->serverid
);
677 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
)) {
678 r
= dhcp6_option_append_ia(&opt
, &optlen
,
685 r
= dhcp6_option_append_fqdn(&opt
, &optlen
, client
->fqdn
);
690 if (client
->mudurl
) {
691 r
= dhcp6_option_append(&opt
, &optlen
,
692 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
698 if (client
->user_class
) {
699 r
= dhcp6_option_append_user_class(&opt
, &optlen
, client
->user_class
);
704 if (client
->vendor_class
) {
705 r
= dhcp6_option_append_vendor_class(&opt
, &optlen
, client
->vendor_class
);
710 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
711 r
= dhcp6_option_append_vendor_option(&opt
, &optlen
, client
->vendor_options
);
716 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
)) {
717 r
= dhcp6_option_append_pd(opt
, optlen
, &client
->lease
->pd
, NULL
);
727 case DHCP6_STATE_REBIND
:
728 message
->type
= DHCP6_REBIND
;
730 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
)) {
731 r
= dhcp6_option_append_ia(&opt
, &optlen
, &client
->lease
->ia
);
737 r
= dhcp6_option_append_fqdn(&opt
, &optlen
, client
->fqdn
);
742 if (client
->mudurl
) {
743 r
= dhcp6_option_append(&opt
, &optlen
,
744 SD_DHCP6_OPTION_MUD_URL
, strlen(client
->mudurl
),
750 if (client
->user_class
) {
751 r
= dhcp6_option_append_user_class(&opt
, &optlen
, client
->user_class
);
756 if (client
->vendor_class
) {
757 r
= dhcp6_option_append_vendor_class(&opt
, &optlen
, client
->vendor_class
);
762 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
763 r
= dhcp6_option_append_vendor_option(&opt
, &optlen
, client
->vendor_options
);
768 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
)) {
769 r
= dhcp6_option_append_pd(opt
, optlen
, &client
->lease
->pd
, NULL
);
779 case DHCP6_STATE_STOPPED
:
780 case DHCP6_STATE_BOUND
:
784 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_ORO
,
785 client
->req_opts_len
* sizeof(be16_t
),
790 assert(client
->duid_len
);
791 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_CLIENTID
,
792 client
->duid_len
, &client
->duid
);
796 elapsed_usec
= time_now
- client
->transaction_start
;
797 if (elapsed_usec
< 0xffff * USEC_PER_MSEC
* 10)
798 elapsed_time
= htobe16(elapsed_usec
/ USEC_PER_MSEC
/ 10);
800 elapsed_time
= 0xffff;
802 r
= dhcp6_option_append(&opt
, &optlen
, SD_DHCP6_OPTION_ELAPSED_TIME
,
803 sizeof(elapsed_time
), &elapsed_time
);
807 ORDERED_HASHMAP_FOREACH(j
, client
->extra_options
, i
) {
808 r
= dhcp6_option_append(&opt
, &optlen
, j
->option
, j
->length
, j
->data
);
813 r
= dhcp6_network_send_udp_socket(client
->fd
, &all_servers
, message
,
818 log_dhcp6_client(client
, "Sent %s",
819 dhcp6_message_type_to_string(message
->type
));
824 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
825 sd_dhcp6_client
*client
= userdata
;
829 assert(client
->lease
);
831 (void) event_source_disable(client
->timeout_t2
);
833 log_dhcp6_client(client
, "Timeout T2");
835 client_start(client
, DHCP6_STATE_REBIND
);
840 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
841 sd_dhcp6_client
*client
= userdata
;
845 assert(client
->lease
);
847 (void) event_source_disable(client
->timeout_t1
);
849 log_dhcp6_client(client
, "Timeout T1");
851 client_start(client
, DHCP6_STATE_RENEW
);
856 static int client_timeout_resend_expire(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
857 sd_dhcp6_client
*client
= userdata
;
858 DHCP6_CLIENT_DONT_DESTROY(client
);
859 enum DHCP6State state
;
863 assert(client
->event
);
865 state
= client
->state
;
867 client_stop(client
, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
);
869 /* RFC 3315, section 18.1.4., says that "...the client may choose to
870 use a Solicit message to locate a new DHCP server..." */
871 if (state
== DHCP6_STATE_REBIND
)
872 client_start(client
, DHCP6_STATE_SOLICITATION
);
877 static usec_t
client_timeout_compute_random(usec_t val
) {
878 return val
- (random_u32() % USEC_PER_SEC
) * val
/ 10 / USEC_PER_SEC
;
881 static int client_timeout_resend(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
883 sd_dhcp6_client
*client
= userdata
;
884 usec_t time_now
, init_retransmit_time
= 0, max_retransmit_time
= 0;
885 usec_t max_retransmit_duration
= 0;
886 uint8_t max_retransmit_count
= 0;
887 char time_string
[FORMAT_TIMESPAN_MAX
];
891 assert(client
->event
);
893 (void) event_source_disable(client
->timeout_resend
);
895 switch (client
->state
) {
896 case DHCP6_STATE_INFORMATION_REQUEST
:
897 init_retransmit_time
= DHCP6_INF_TIMEOUT
;
898 max_retransmit_time
= DHCP6_INF_MAX_RT
;
902 case DHCP6_STATE_SOLICITATION
:
904 if (client
->retransmit_count
&& client
->lease
) {
905 client_start(client
, DHCP6_STATE_REQUEST
);
909 init_retransmit_time
= DHCP6_SOL_TIMEOUT
;
910 max_retransmit_time
= DHCP6_SOL_MAX_RT
;
914 case DHCP6_STATE_REQUEST
:
915 init_retransmit_time
= DHCP6_REQ_TIMEOUT
;
916 max_retransmit_time
= DHCP6_REQ_MAX_RT
;
917 max_retransmit_count
= DHCP6_REQ_MAX_RC
;
921 case DHCP6_STATE_RENEW
:
922 init_retransmit_time
= DHCP6_REN_TIMEOUT
;
923 max_retransmit_time
= DHCP6_REN_MAX_RT
;
925 /* RFC 3315, section 18.1.3. says max retransmit duration will
926 be the remaining time until T2. Instead of setting MRD,
927 wait for T2 to trigger with the same end result */
931 case DHCP6_STATE_REBIND
:
932 init_retransmit_time
= DHCP6_REB_TIMEOUT
;
933 max_retransmit_time
= DHCP6_REB_MAX_RT
;
935 if (event_source_is_enabled(client
->timeout_resend_expire
) <= 0) {
938 r
= dhcp6_lease_ia_rebind_expire(&client
->lease
->ia
, &expire
);
940 client_stop(client
, r
);
943 max_retransmit_duration
= expire
* USEC_PER_SEC
;
948 case DHCP6_STATE_STOPPED
:
949 case DHCP6_STATE_BOUND
:
953 if (max_retransmit_count
> 0 &&
954 client
->retransmit_count
>= max_retransmit_count
) {
955 client_stop(client
, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
);
959 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
963 r
= client_send_message(client
, time_now
);
965 client
->retransmit_count
++;
967 if (client
->retransmit_time
== 0) {
968 client
->retransmit_time
=
969 client_timeout_compute_random(init_retransmit_time
);
971 if (client
->state
== DHCP6_STATE_SOLICITATION
)
972 client
->retransmit_time
+= init_retransmit_time
/ 10;
975 if (max_retransmit_time
> 0 &&
976 client
->retransmit_time
> max_retransmit_time
/ 2)
977 client
->retransmit_time
= client_timeout_compute_random(max_retransmit_time
);
979 client
->retransmit_time
+= client_timeout_compute_random(client
->retransmit_time
);
982 log_dhcp6_client(client
, "Next retransmission in %s",
983 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, client
->retransmit_time
, USEC_PER_SEC
));
985 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
986 clock_boottime_or_monotonic(),
987 time_now
+ client
->retransmit_time
, 10 * USEC_PER_MSEC
,
988 client_timeout_resend
, client
,
989 client
->event_priority
, "dhcp6-resend-timer", true);
993 if (max_retransmit_duration
> 0 && event_source_is_enabled(client
->timeout_resend_expire
) <= 0) {
995 log_dhcp6_client(client
, "Max retransmission duration %"PRIu64
" secs",
996 max_retransmit_duration
/ USEC_PER_SEC
);
998 r
= event_reset_time(client
->event
, &client
->timeout_resend_expire
,
999 clock_boottime_or_monotonic(),
1000 time_now
+ max_retransmit_duration
, USEC_PER_SEC
,
1001 client_timeout_resend_expire
, client
,
1002 client
->event_priority
, "dhcp6-resend-expire-timer", true);
1009 client_stop(client
, r
);
1014 static int client_ensure_iaid(sd_dhcp6_client
*client
) {
1020 if (client
->iaid_set
)
1023 r
= dhcp_identifier_set_iaid(client
->ifindex
, client
->mac_addr
, client
->mac_addr_len
, true, &iaid
);
1027 client
->ia_na
.ia_na
.id
= iaid
;
1028 client
->ia_pd
.ia_pd
.id
= iaid
;
1029 client
->iaid_set
= true;
1034 static int client_parse_message(
1035 sd_dhcp6_client
*client
,
1036 DHCP6Message
*message
,
1038 sd_dhcp6_lease
*lease
) {
1040 uint16_t ia_na_status
= 0, ia_pd_status
= 0;
1041 uint32_t lt_t1
= ~0, lt_t2
= ~0;
1042 usec_t irt
= IRT_DEFAULT
;
1043 bool clientid
= false;
1049 assert(len
>= sizeof(DHCP6Message
));
1052 len
-= sizeof(DHCP6Message
);
1055 DHCP6Option
*option
= (DHCP6Option
*) &message
->options
[pos
];
1056 uint16_t optcode
, optlen
;
1061 if (len
< pos
+ offsetof(DHCP6Option
, data
))
1064 optcode
= be16toh(option
->code
);
1065 optlen
= be16toh(option
->len
);
1066 optval
= option
->data
;
1068 if (len
< pos
+ offsetof(DHCP6Option
, data
) + optlen
)
1072 case SD_DHCP6_OPTION_CLIENTID
:
1074 log_dhcp6_client(client
, "%s contains multiple clientids",
1075 dhcp6_message_type_to_string(message
->type
));
1079 if (optlen
!= client
->duid_len
||
1080 memcmp(&client
->duid
, optval
, optlen
) != 0) {
1081 log_dhcp6_client(client
, "%s DUID does not match",
1082 dhcp6_message_type_to_string(message
->type
));
1090 case SD_DHCP6_OPTION_SERVERID
:
1091 r
= dhcp6_lease_get_serverid(lease
, NULL
, NULL
);
1093 log_dhcp6_client(client
, "%s contains multiple serverids",
1094 dhcp6_message_type_to_string(message
->type
));
1098 r
= dhcp6_lease_set_serverid(lease
, optval
, optlen
);
1104 case SD_DHCP6_OPTION_PREFERENCE
:
1108 r
= dhcp6_lease_set_preference(lease
, optval
[0]);
1114 case SD_DHCP6_OPTION_STATUS_CODE
:
1115 status
= dhcp6_option_parse_status(option
, optlen
+ sizeof(DHCP6Option
));
1120 log_dhcp6_client(client
, "%s Status %s",
1121 dhcp6_message_type_to_string(message
->type
),
1122 dhcp6_message_status_to_string(status
));
1129 case SD_DHCP6_OPTION_IA_NA
:
1130 if (client
->state
== DHCP6_STATE_INFORMATION_REQUEST
) {
1131 log_dhcp6_client(client
, "Information request ignoring IA NA option");
1136 r
= dhcp6_option_parse_ia(option
, &lease
->ia
, &ia_na_status
);
1137 if (r
< 0 && r
!= -ENOMSG
)
1140 if (ia_na_status
== DHCP6_STATUS_NO_ADDRS_AVAIL
) {
1141 pos
+= offsetof(DHCP6Option
, data
) + optlen
;
1145 r
= dhcp6_lease_get_iaid(lease
, &iaid_lease
);
1149 if (client
->ia_na
.ia_na
.id
!= iaid_lease
) {
1150 log_dhcp6_client(client
, "%s has wrong IAID for IA NA",
1151 dhcp6_message_type_to_string(message
->type
));
1155 if (lease
->ia
.addresses
) {
1156 lt_t1
= MIN(lt_t1
, be32toh(lease
->ia
.ia_na
.lifetime_t1
));
1157 lt_t2
= MIN(lt_t2
, be32toh(lease
->ia
.ia_na
.lifetime_t1
));
1162 case SD_DHCP6_OPTION_IA_PD
:
1163 if (client
->state
== DHCP6_STATE_INFORMATION_REQUEST
) {
1164 log_dhcp6_client(client
, "Information request ignoring IA PD option");
1169 r
= dhcp6_option_parse_ia(option
, &lease
->pd
, &ia_pd_status
);
1170 if (r
< 0 && r
!= -ENOMSG
)
1173 if (ia_pd_status
== DHCP6_STATUS_NO_PREFIX_AVAIL
) {
1174 pos
+= offsetof(DHCP6Option
, data
) + optlen
;
1178 r
= dhcp6_lease_get_pd_iaid(lease
, &iaid_lease
);
1182 if (client
->ia_pd
.ia_pd
.id
!= iaid_lease
) {
1183 log_dhcp6_client(client
, "%s has wrong IAID for IA PD",
1184 dhcp6_message_type_to_string(message
->type
));
1188 if (lease
->pd
.addresses
) {
1189 lt_t1
= MIN(lt_t1
, be32toh(lease
->pd
.ia_pd
.lifetime_t1
));
1190 lt_t2
= MIN(lt_t2
, be32toh(lease
->pd
.ia_pd
.lifetime_t2
));
1195 case SD_DHCP6_OPTION_RAPID_COMMIT
:
1196 r
= dhcp6_lease_set_rapid_commit(lease
);
1202 case SD_DHCP6_OPTION_DNS_SERVERS
:
1203 r
= dhcp6_lease_set_dns(lease
, optval
, optlen
);
1209 case SD_DHCP6_OPTION_DOMAIN_LIST
:
1210 r
= dhcp6_lease_set_domains(lease
, optval
, optlen
);
1216 case SD_DHCP6_OPTION_NTP_SERVER
:
1217 r
= dhcp6_lease_set_ntp(lease
, optval
, optlen
);
1223 case SD_DHCP6_OPTION_SNTP_SERVERS
:
1224 r
= dhcp6_lease_set_sntp(lease
, optval
, optlen
);
1230 case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME
:
1234 irt
= unaligned_read_be32((be32_t
*) optval
) * USEC_PER_SEC
;
1238 pos
+= offsetof(DHCP6Option
, data
) + optlen
;
1241 if (ia_na_status
> 0 && ia_pd_status
> 0) {
1242 log_dhcp6_client(client
, "No IA_PD prefix or IA_NA address received. Ignoring.");
1247 log_dhcp6_client(client
, "%s has incomplete options",
1248 dhcp6_message_type_to_string(message
->type
));
1252 if (client
->state
!= DHCP6_STATE_INFORMATION_REQUEST
) {
1253 r
= dhcp6_lease_get_serverid(lease
, NULL
, NULL
);
1255 log_dhcp6_client(client
, "%s has no server id",
1256 dhcp6_message_type_to_string(message
->type
));
1261 if (lease
->ia
.addresses
) {
1262 lease
->ia
.ia_na
.lifetime_t1
= htobe32(lt_t1
);
1263 lease
->ia
.ia_na
.lifetime_t2
= htobe32(lt_t2
);
1266 if (lease
->pd
.addresses
) {
1267 lease
->pd
.ia_pd
.lifetime_t1
= htobe32(lt_t1
);
1268 lease
->pd
.ia_pd
.lifetime_t2
= htobe32(lt_t2
);
1272 client
->information_refresh_time_usec
= MAX(irt
, IRT_MINIMUM
);
1277 static int client_receive_reply(sd_dhcp6_client
*client
, DHCP6Message
*reply
, size_t len
) {
1278 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
1285 if (reply
->type
!= DHCP6_REPLY
)
1288 r
= dhcp6_lease_new(&lease
);
1292 r
= client_parse_message(client
, reply
, len
, lease
);
1296 if (client
->state
== DHCP6_STATE_SOLICITATION
) {
1297 r
= dhcp6_lease_get_rapid_commit(lease
, &rapid_commit
);
1305 sd_dhcp6_lease_unref(client
->lease
);
1306 client
->lease
= TAKE_PTR(lease
);
1308 return DHCP6_STATE_BOUND
;
1311 static int client_receive_advertise(sd_dhcp6_client
*client
, DHCP6Message
*advertise
, size_t len
) {
1312 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
1313 uint8_t pref_advertise
= 0, pref_lease
= 0;
1316 if (advertise
->type
!= DHCP6_ADVERTISE
)
1319 r
= dhcp6_lease_new(&lease
);
1323 r
= client_parse_message(client
, advertise
, len
, lease
);
1327 r
= dhcp6_lease_get_preference(lease
, &pref_advertise
);
1331 r
= dhcp6_lease_get_preference(client
->lease
, &pref_lease
);
1333 if (r
< 0 || pref_advertise
> pref_lease
) {
1334 sd_dhcp6_lease_unref(client
->lease
);
1335 client
->lease
= TAKE_PTR(lease
);
1339 if (pref_advertise
== 255 || client
->retransmit_count
> 1)
1340 r
= DHCP6_STATE_REQUEST
;
1345 static int client_receive_message(
1351 sd_dhcp6_client
*client
= userdata
;
1352 DHCP6_CLIENT_DONT_DESTROY(client
);
1353 _cleanup_free_ DHCP6Message
*message
= NULL
;
1354 ssize_t buflen
, len
;
1359 assert(client
->event
);
1361 buflen
= next_datagram_size_fd(fd
);
1362 if (buflen
== -ENETDOWN
) {
1363 /* the link is down. Don't return an error or the I/O event
1364 source will be disconnected and we won't be able to receive
1365 packets again when the link comes back. */
1371 message
= malloc(buflen
);
1375 len
= recv(fd
, message
, buflen
, 0);
1377 /* see comment above for why we shouldn't error out on ENETDOWN. */
1378 if (IN_SET(errno
, EAGAIN
, EINTR
, ENETDOWN
))
1381 return log_dhcp6_client_errno(client
, errno
, "Could not receive message from UDP socket: %m");
1384 if ((size_t) len
< sizeof(DHCP6Message
)) {
1385 log_dhcp6_client(client
, "Too small to be DHCP6 message: ignoring");
1389 switch(message
->type
) {
1397 case DHCP6_INFORMATION_REQUEST
:
1398 case DHCP6_RELAY_FORW
:
1399 case DHCP6_RELAY_REPL
:
1402 case DHCP6_ADVERTISE
:
1404 case DHCP6_RECONFIGURE
:
1408 log_dhcp6_client(client
, "Unknown message type %d", message
->type
);
1412 if (client
->transaction_id
!= (message
->transaction_id
&
1413 htobe32(0x00ffffff)))
1416 switch (client
->state
) {
1417 case DHCP6_STATE_INFORMATION_REQUEST
:
1418 r
= client_receive_reply(client
, message
, len
);
1422 client_notify(client
, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
1424 client_start(client
, DHCP6_STATE_STOPPED
);
1428 case DHCP6_STATE_SOLICITATION
:
1429 r
= client_receive_advertise(client
, message
, len
);
1431 if (r
== DHCP6_STATE_REQUEST
) {
1432 client_start(client
, r
);
1437 _fallthrough_
; /* for Soliciation Rapid Commit option check */
1438 case DHCP6_STATE_REQUEST
:
1439 case DHCP6_STATE_RENEW
:
1440 case DHCP6_STATE_REBIND
:
1442 r
= client_receive_reply(client
, message
, len
);
1446 if (r
== DHCP6_STATE_BOUND
) {
1448 r
= client_start(client
, DHCP6_STATE_BOUND
);
1450 client_stop(client
, r
);
1454 client_notify(client
, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
1459 case DHCP6_STATE_BOUND
:
1463 case DHCP6_STATE_STOPPED
:
1467 log_dhcp6_client(client
, "Recv %s",
1468 dhcp6_message_type_to_string(message
->type
));
1473 static int client_get_lifetime(sd_dhcp6_client
*client
, uint32_t *lifetime_t1
,
1474 uint32_t *lifetime_t2
) {
1475 assert_return(client
, -EINVAL
);
1476 assert_return(client
->lease
, -EINVAL
);
1478 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_NA
) && client
->lease
->ia
.addresses
) {
1479 *lifetime_t1
= be32toh(client
->lease
->ia
.ia_na
.lifetime_t1
);
1480 *lifetime_t2
= be32toh(client
->lease
->ia
.ia_na
.lifetime_t2
);
1485 if (FLAGS_SET(client
->request
, DHCP6_REQUEST_IA_PD
) && client
->lease
->pd
.addresses
) {
1486 *lifetime_t1
= be32toh(client
->lease
->pd
.ia_pd
.lifetime_t1
);
1487 *lifetime_t2
= be32toh(client
->lease
->pd
.ia_pd
.lifetime_t2
);
1495 static int client_start(sd_dhcp6_client
*client
, enum DHCP6State state
) {
1497 usec_t timeout
, time_now
;
1498 char time_string
[FORMAT_TIMESPAN_MAX
];
1499 uint32_t lifetime_t1
, lifetime_t2
;
1501 assert_return(client
, -EINVAL
);
1502 assert_return(client
->event
, -EINVAL
);
1503 assert_return(client
->ifindex
> 0, -EINVAL
);
1504 assert_return(client
->state
!= state
, -EINVAL
);
1506 (void) event_source_disable(client
->timeout_resend_expire
);
1507 (void) event_source_disable(client
->timeout_resend
);
1508 client
->retransmit_time
= 0;
1509 client
->retransmit_count
= 0;
1511 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
1515 if (!client
->receive_message
) {
1516 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
1517 client
->fd
, EPOLLIN
, client_receive_message
,
1522 r
= sd_event_source_set_priority(client
->receive_message
,
1523 client
->event_priority
);
1527 r
= sd_event_source_set_description(client
->receive_message
,
1528 "dhcp6-receive-message");
1534 case DHCP6_STATE_STOPPED
:
1535 if (client
->state
== DHCP6_STATE_INFORMATION_REQUEST
) {
1536 client
->state
= DHCP6_STATE_STOPPED
;
1542 case DHCP6_STATE_SOLICITATION
:
1543 client
->state
= DHCP6_STATE_SOLICITATION
;
1547 case DHCP6_STATE_INFORMATION_REQUEST
:
1548 case DHCP6_STATE_REQUEST
:
1549 case DHCP6_STATE_RENEW
:
1550 case DHCP6_STATE_REBIND
:
1552 client
->state
= state
;
1556 case DHCP6_STATE_BOUND
:
1558 r
= client_get_lifetime(client
, &lifetime_t1
, &lifetime_t2
);
1562 if (lifetime_t1
== 0xffffffff || lifetime_t2
== 0xffffffff) {
1563 log_dhcp6_client(client
, "Infinite T1 0x%08x or T2 0x%08x",
1564 lifetime_t1
, lifetime_t2
);
1569 timeout
= client_timeout_compute_random(lifetime_t1
* USEC_PER_SEC
);
1571 log_dhcp6_client(client
, "T1 expires in %s",
1572 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, timeout
, USEC_PER_SEC
));
1574 r
= event_reset_time(client
->event
, &client
->timeout_t1
,
1575 clock_boottime_or_monotonic(),
1576 time_now
+ timeout
, 10 * USEC_PER_SEC
,
1577 client_timeout_t1
, client
,
1578 client
->event_priority
, "dhcp6-t1-timeout", true);
1582 timeout
= client_timeout_compute_random(lifetime_t2
* USEC_PER_SEC
);
1584 log_dhcp6_client(client
, "T2 expires in %s",
1585 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, timeout
, USEC_PER_SEC
));
1587 r
= event_reset_time(client
->event
, &client
->timeout_t2
,
1588 clock_boottime_or_monotonic(),
1589 time_now
+ timeout
, 10 * USEC_PER_SEC
,
1590 client_timeout_t2
, client
,
1591 client
->event_priority
, "dhcp6-t2-timeout", true);
1595 client
->state
= state
;
1600 client
->transaction_id
= random_u32() & htobe32(0x00ffffff);
1601 client
->transaction_start
= time_now
;
1603 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1604 clock_boottime_or_monotonic(),
1606 client_timeout_resend
, client
,
1607 client
->event_priority
, "dhcp6-resend-timeout", true);
1614 client_reset(client
);
1618 int sd_dhcp6_client_stop(sd_dhcp6_client
*client
) {
1619 assert_return(client
, -EINVAL
);
1621 client_stop(client
, SD_DHCP6_CLIENT_EVENT_STOP
);
1623 client
->fd
= safe_close(client
->fd
);
1628 int sd_dhcp6_client_is_running(sd_dhcp6_client
*client
) {
1629 assert_return(client
, -EINVAL
);
1631 return client
->state
!= DHCP6_STATE_STOPPED
;
1634 int sd_dhcp6_client_start(sd_dhcp6_client
*client
) {
1635 enum DHCP6State state
= DHCP6_STATE_SOLICITATION
;
1638 assert_return(client
, -EINVAL
);
1639 assert_return(client
->event
, -EINVAL
);
1640 assert_return(client
->ifindex
> 0, -EINVAL
);
1641 assert_return(in_addr_is_link_local(AF_INET6
, (const union in_addr_union
*) &client
->local_address
) > 0, -EINVAL
);
1643 if (!IN_SET(client
->state
, DHCP6_STATE_STOPPED
))
1646 if (!client
->information_request
&& !client
->request
)
1649 r
= client_reset(client
);
1653 r
= client_ensure_iaid(client
);
1657 r
= client_ensure_duid(client
);
1661 if (client
->fd
< 0) {
1662 r
= dhcp6_network_bind_udp_socket(client
->ifindex
, &client
->local_address
);
1664 _cleanup_free_
char *p
= NULL
;
1666 (void) in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &client
->local_address
, &p
);
1667 return log_dhcp6_client_errno(client
, r
,
1668 "Failed to bind to UDP socket at address %s: %m", strna(p
));
1674 if (client
->information_request
) {
1675 usec_t t
= now(CLOCK_MONOTONIC
);
1677 if (t
< usec_add(client
->information_request_time_usec
, client
->information_refresh_time_usec
))
1680 client
->information_request_time_usec
= t
;
1681 state
= DHCP6_STATE_INFORMATION_REQUEST
;
1684 log_dhcp6_client(client
, "Started in %s mode",
1685 client
->information_request
? "Information request":
1688 return client_start(client
, state
);
1691 int sd_dhcp6_client_attach_event(sd_dhcp6_client
*client
, sd_event
*event
, int64_t priority
) {
1694 assert_return(client
, -EINVAL
);
1695 assert_return(!client
->event
, -EBUSY
);
1698 client
->event
= sd_event_ref(event
);
1700 r
= sd_event_default(&client
->event
);
1705 client
->event_priority
= priority
;
1710 int sd_dhcp6_client_detach_event(sd_dhcp6_client
*client
) {
1711 assert_return(client
, -EINVAL
);
1713 client
->event
= sd_event_unref(client
->event
);
1718 sd_event
*sd_dhcp6_client_get_event(sd_dhcp6_client
*client
) {
1719 assert_return(client
, NULL
);
1721 return client
->event
;
1724 static sd_dhcp6_client
*dhcp6_client_free(sd_dhcp6_client
*client
) {
1727 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
1728 client
->timeout_resend_expire
= sd_event_source_unref(client
->timeout_resend_expire
);
1729 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
1730 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
1732 client_reset(client
);
1734 client
->fd
= safe_close(client
->fd
);
1736 sd_dhcp6_client_detach_event(client
);
1738 free(client
->req_opts
);
1740 free(client
->mudurl
);
1742 ordered_hashmap_free(client
->extra_options
);
1743 strv_free(client
->user_class
);
1744 strv_free(client
->vendor_class
);
1746 return mfree(client
);
1749 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client
, sd_dhcp6_client
, dhcp6_client_free
);
1751 int sd_dhcp6_client_new(sd_dhcp6_client
**ret
) {
1752 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
1753 _cleanup_free_ be16_t
*req_opts
= NULL
;
1756 assert_return(ret
, -EINVAL
);
1758 req_opts
= new(be16_t
, ELEMENTSOF(default_req_opts
));
1762 for (t
= 0; t
< ELEMENTSOF(default_req_opts
); t
++)
1763 req_opts
[t
] = htobe16(default_req_opts
[t
]);
1765 client
= new(sd_dhcp6_client
, 1);
1769 *client
= (sd_dhcp6_client
) {
1771 .ia_na
.type
= SD_DHCP6_OPTION_IA_NA
,
1772 .ia_pd
.type
= SD_DHCP6_OPTION_IA_PD
,
1774 .request
= DHCP6_REQUEST_IA_NA
,
1776 .req_opts_len
= ELEMENTSOF(default_req_opts
),
1777 .hint_pd_prefix
.iapdprefix
.lifetime_preferred
= (be32_t
) -1,
1778 .hint_pd_prefix
.iapdprefix
.lifetime_valid
= (be32_t
) -1,
1779 .req_opts
= TAKE_PTR(req_opts
),
1782 *ret
= TAKE_PTR(client
);