1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include "dhcp6-client-internal.h"
7 #include "dhcp6-lease-internal.h"
9 #include "hostname-setup.h"
10 #include "hostname-util.h"
11 #include "networkd-address.h"
12 #include "networkd-dhcp-prefix-delegation.h"
13 #include "networkd-dhcp6-bus.h"
14 #include "networkd-dhcp6.h"
15 #include "networkd-link.h"
16 #include "networkd-manager.h"
17 #include "networkd-queue.h"
18 #include "networkd-route.h"
19 #include "networkd-state-file.h"
20 #include "string-table.h"
21 #include "string-util.h"
23 bool link_dhcp6_with_address_enabled(Link
*link
) {
24 if (!link_dhcp6_enabled(link
))
27 return link
->network
->dhcp6_use_address
;
30 static DHCP6ClientStartMode
link_get_dhcp6_client_start_mode(Link
*link
) {
34 return DHCP6_CLIENT_START_MODE_NO
;
36 /* When WithoutRA= is explicitly specified, then honor it. */
37 if (link
->network
->dhcp6_client_start_mode
>= 0)
38 return link
->network
->dhcp6_client_start_mode
;
40 /* When this interface itself is an uplink interface, then start dhcp6 client in solicit mode. */
41 if (dhcp_pd_is_uplink(link
, link
, /* accept_auto = */ false))
42 return DHCP6_CLIENT_START_MODE_SOLICIT
;
44 /* Otherwise, start dhcp6 client when RA is received. */
45 return DHCP6_CLIENT_START_MODE_NO
;
48 static int dhcp6_remove(Link
*link
, bool only_marked
) {
56 link
->dhcp6_configured
= false;
58 SET_FOREACH(route
, link
->routes
) {
59 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
61 if (only_marked
&& !route_is_marked(route
))
64 k
= route_remove(route
);
68 route_cancel_request(route
, link
);
71 SET_FOREACH(address
, link
->addresses
) {
72 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
74 if (only_marked
&& !address_is_marked(address
))
77 k
= address_remove_and_drop(address
);
85 static int dhcp6_address_ready_callback(Address
*address
) {
89 assert(address
->link
);
91 SET_FOREACH(a
, address
->link
->addresses
)
92 if (a
->source
== NETWORK_CONFIG_SOURCE_DHCP6
)
95 return dhcp6_check_ready(address
->link
);
98 int dhcp6_check_ready(Link
*link
) {
99 bool has_ready
= false;
105 if (link
->dhcp6_messages
> 0) {
106 log_link_debug(link
, "%s(): DHCPv6 addresses and routes are not set.", __func__
);
110 SET_FOREACH(address
, link
->addresses
) {
111 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
113 if (address_is_ready(address
)) {
120 SET_FOREACH(address
, link
->addresses
)
121 if (address
->source
== NETWORK_CONFIG_SOURCE_DHCP6
)
122 address
->callback
= dhcp6_address_ready_callback
;
124 log_link_debug(link
, "%s(): no DHCPv6 address is ready.", __func__
);
128 link
->dhcp6_configured
= true;
129 log_link_debug(link
, "DHCPv6 addresses and routes set.");
131 r
= dhcp6_remove(link
, /* only_marked = */ true);
135 link_check_ready(link
);
139 static int dhcp6_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
144 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set DHCPv6 address");
148 r
= dhcp6_check_ready(link
);
150 link_enter_failed(link
);
155 static int verify_dhcp6_address(Link
*link
, const Address
*address
) {
156 bool by_ndisc
= false;
162 assert(address
->family
== AF_INET6
);
164 const char *pretty
= IN6_ADDR_TO_STRING(&address
->in_addr
.in6
);
166 if (address_get_harder(link
, address
, &existing
) < 0) {
168 log_level
= LOG_INFO
;
171 log_level
= LOG_DEBUG
;
173 if (address
->prefixlen
== existing
->prefixlen
)
174 /* Currently, only conflict in prefix length is reported. */
177 if (existing
->source
== NETWORK_CONFIG_SOURCE_NDISC
)
180 log_link_warning(link
, "Ignoring DHCPv6 address %s/%u (valid %s, preferred %s) which conflicts with %s/%u%s.",
181 pretty
, address
->prefixlen
,
182 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
183 FORMAT_LIFETIME(address
->lifetime_preferred_usec
),
184 pretty
, existing
->prefixlen
,
185 by_ndisc
? " assigned by NDisc" : "");
187 log_link_warning(link
, "Hint: use IPv6Token= setting to change the address generated by NDisc or set UseAutonomousPrefix=no.");
192 log_link_full(link
, log_level
, "DHCPv6 address %s/%u (valid %s, preferred %s)",
193 pretty
, address
->prefixlen
,
194 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
195 FORMAT_LIFETIME(address
->lifetime_preferred_usec
));
199 static int dhcp6_request_address(
201 const struct in6_addr
*server_address
,
202 const struct in6_addr
*ip6_addr
,
203 usec_t lifetime_preferred_usec
,
204 usec_t lifetime_valid_usec
) {
206 _cleanup_(address_freep
) Address
*addr
= NULL
;
210 r
= address_new(&addr
);
214 addr
->source
= NETWORK_CONFIG_SOURCE_DHCP6
;
215 addr
->provider
.in6
= *server_address
;
216 addr
->family
= AF_INET6
;
217 addr
->in_addr
.in6
= *ip6_addr
;
218 addr
->flags
= IFA_F_NOPREFIXROUTE
;
219 addr
->prefixlen
= 128;
220 addr
->lifetime_preferred_usec
= lifetime_preferred_usec
;
221 addr
->lifetime_valid_usec
= lifetime_valid_usec
;
223 if (verify_dhcp6_address(link
, addr
) < 0)
226 r
= free_and_strdup_warn(&addr
->netlabel
, link
->network
->dhcp6_netlabel
);
230 if (address_get(link
, addr
, &existing
) < 0)
231 link
->dhcp6_configured
= false;
233 address_unmark(existing
);
235 r
= link_request_address(link
, addr
, &link
->dhcp6_messages
,
236 dhcp6_address_handler
, NULL
);
238 return log_link_error_errno(link
, r
, "Failed to request DHCPv6 address %s/128: %m",
239 IN6_ADDR_TO_STRING(ip6_addr
));
243 static int dhcp6_address_acquired(Link
*link
) {
244 struct in6_addr server_address
;
248 assert(link
->network
);
249 assert(link
->dhcp6_lease
);
251 if (!link
->network
->dhcp6_use_address
)
254 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &server_address
);
256 return log_link_warning_errno(link
, r
, "Failed to get server address of DHCPv6 lease: %m");
258 FOREACH_DHCP6_ADDRESS(link
->dhcp6_lease
) {
259 usec_t lifetime_preferred_usec
, lifetime_valid_usec
;
260 struct in6_addr ip6_addr
;
262 r
= sd_dhcp6_lease_get_address(link
->dhcp6_lease
, &ip6_addr
);
266 r
= sd_dhcp6_lease_get_address_lifetime_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
,
267 &lifetime_preferred_usec
, &lifetime_valid_usec
);
271 r
= dhcp6_request_address(link
, &server_address
, &ip6_addr
,
272 lifetime_preferred_usec
,
273 lifetime_valid_usec
);
278 if (link
->network
->dhcp6_use_hostname
) {
279 const char *dhcpname
= NULL
;
280 _cleanup_free_
char *hostname
= NULL
;
282 (void) sd_dhcp6_lease_get_fqdn(link
->dhcp6_lease
, &dhcpname
);
285 r
= shorten_overlong(dhcpname
, &hostname
);
287 log_link_warning_errno(link
, r
, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname
);
289 log_link_notice(link
, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname
, hostname
);
292 r
= manager_set_hostname(link
->manager
, hostname
);
294 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
301 static int dhcp6_lease_ip_acquired(sd_dhcp6_client
*client
, Link
*link
) {
302 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease_old
= NULL
;
303 sd_dhcp6_lease
*lease
;
306 link_mark_addresses(link
, NETWORK_CONFIG_SOURCE_DHCP6
);
307 link_mark_routes(link
, NETWORK_CONFIG_SOURCE_DHCP6
);
309 r
= sd_dhcp6_client_get_lease(client
, &lease
);
311 return log_link_error_errno(link
, r
, "Failed to get DHCPv6 lease: %m");
313 lease_old
= TAKE_PTR(link
->dhcp6_lease
);
314 link
->dhcp6_lease
= sd_dhcp6_lease_ref(lease
);
316 r
= dhcp6_address_acquired(link
);
320 if (sd_dhcp6_lease_has_pd_prefix(lease
)) {
321 r
= dhcp6_pd_prefix_acquired(link
);
324 } else if (sd_dhcp6_lease_has_pd_prefix(lease_old
))
325 /* When we had PD prefixes but not now, we need to remove them. */
326 dhcp_pd_prefix_lost(link
);
328 if (link
->dhcp6_messages
== 0) {
329 link
->dhcp6_configured
= true;
331 r
= dhcp6_remove(link
, /* only_marked = */ true);
335 log_link_debug(link
, "Setting DHCPv6 addresses and routes");
337 if (!link
->dhcp6_configured
)
338 link_set_state(link
, LINK_STATE_CONFIGURING
);
340 link_check_ready(link
);
344 static int dhcp6_lease_information_acquired(sd_dhcp6_client
*client
, Link
*link
) {
345 sd_dhcp6_lease
*lease
;
351 r
= sd_dhcp6_client_get_lease(client
, &lease
);
353 return log_link_error_errno(link
, r
, "Failed to get DHCPv6 lease: %m");
355 unref_and_replace_full(link
->dhcp6_lease
, lease
, sd_dhcp6_lease_ref
, sd_dhcp6_lease_unref
);
361 static int dhcp6_lease_lost(Link
*link
) {
365 assert(link
->manager
);
367 log_link_info(link
, "DHCPv6 lease lost");
369 if (sd_dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
))
370 dhcp_pd_prefix_lost(link
);
372 link
->dhcp6_lease
= sd_dhcp6_lease_unref(link
->dhcp6_lease
);
374 r
= dhcp6_remove(link
, /* only_marked = */ false);
381 static void dhcp6_handler(sd_dhcp6_client
*client
, int event
, void *userdata
) {
382 Link
*link
= ASSERT_PTR(userdata
);
385 assert(link
->network
);
387 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
391 case SD_DHCP6_CLIENT_EVENT_STOP
:
392 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
:
393 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
:
394 r
= dhcp6_lease_lost(link
);
397 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
398 r
= dhcp6_lease_ip_acquired(client
, link
);
401 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
402 r
= dhcp6_lease_information_acquired(client
, link
);
407 log_link_warning_errno(link
, event
, "DHCPv6 error, ignoring: %m");
409 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
412 link_enter_failed(link
);
415 int dhcp6_start_on_ra(Link
*link
, bool information_request
) {
419 assert(link
->dhcp6_client
);
420 assert(link
->network
);
421 assert(in6_addr_is_link_local(&link
->ipv6ll_address
));
423 if (link_get_dhcp6_client_start_mode(link
) != DHCP6_CLIENT_START_MODE_NO
)
424 /* When WithoutRA= is specified, then the DHCPv6 client should be already running in
425 * the requested mode. Hence, ignore the requests by RA. */
428 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
435 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
439 if (inf_req
== information_request
)
440 /* The client is already running in the requested mode. */
445 "The DHCPv6 client is already running in the managed mode, "
446 "refusing to start the client in the information requesting mode.");
451 "The DHCPv6 client is running in the information requesting mode. "
452 "Restarting the client in the managed mode.");
454 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
458 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
463 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, information_request
);
467 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
474 int dhcp6_start(Link
*link
) {
475 DHCP6ClientStartMode start_mode
;
479 assert(link
->network
);
481 if (!link
->dhcp6_client
)
484 if (!link_dhcp6_enabled(link
))
487 if (!link_has_carrier(link
))
490 if (sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0)
493 if (!in6_addr_is_link_local(&link
->ipv6ll_address
)) {
494 log_link_debug(link
, "IPv6 link-local address is not set, delaying to start DHCPv6 client.");
498 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
502 start_mode
= link_get_dhcp6_client_start_mode(link
);
503 if (start_mode
== DHCP6_CLIENT_START_MODE_NO
)
506 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
,
507 start_mode
== DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
);
511 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
518 static int dhcp6_set_hostname(sd_dhcp6_client
*client
, Link
*link
) {
519 _cleanup_free_
char *hostname
= NULL
;
525 if (!link
->network
->dhcp_send_hostname
)
527 else if (link
->network
->dhcp_hostname
)
528 hn
= link
->network
->dhcp_hostname
;
530 r
= gethostname_strict(&hostname
);
531 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
532 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to get hostname: %m");
537 r
= sd_dhcp6_client_set_fqdn(client
, hn
);
538 if (r
== -EINVAL
&& hostname
)
539 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
540 log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
542 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname: %m");
547 static int dhcp6_set_identifier(Link
*link
, sd_dhcp6_client
*client
) {
552 assert(link
->network
);
555 r
= sd_dhcp6_client_set_mac(client
, link
->hw_addr
.bytes
, link
->hw_addr
.length
, link
->iftype
);
559 if (link
->network
->dhcp6_iaid_set
) {
560 r
= sd_dhcp6_client_set_iaid(client
, link
->network
->dhcp6_iaid
);
565 duid
= link_get_dhcp6_duid(link
);
567 if (duid
->raw_data_len
== 0)
568 switch (duid
->type
) {
570 r
= sd_dhcp6_client_set_duid_llt(client
, duid
->llt_time
);
573 r
= sd_dhcp6_client_set_duid_ll(client
);
576 r
= sd_dhcp6_client_set_duid_en(client
);
579 r
= sd_dhcp6_client_set_duid_uuid(client
);
582 r
= sd_dhcp6_client_set_duid_raw(client
, duid
->type
, NULL
, 0);
585 r
= sd_dhcp6_client_set_duid_raw(client
, duid
->type
, duid
->raw_data
, duid
->raw_data_len
);
592 static int dhcp6_configure(Link
*link
) {
593 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
594 sd_dhcp6_option
*vendor_option
;
595 sd_dhcp6_option
*send_option
;
596 void *request_options
;
600 assert(link
->network
);
602 if (link
->dhcp6_client
)
603 return log_link_debug_errno(link
, SYNTHETIC_ERRNO(EBUSY
), "DHCPv6 client is already configured.");
605 r
= sd_dhcp6_client_new(&client
);
607 return log_oom_debug();
609 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
611 r
= sd_dhcp6_client_attach_event(client
, link
->manager
->event
, 0);
613 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to attach event: %m");
615 r
= sd_dhcp6_client_attach_device(client
, link
->dev
);
617 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to attach device: %m");
619 r
= dhcp6_set_identifier(link
, client
);
621 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set identifier: %m");
623 ORDERED_HASHMAP_FOREACH(send_option
, link
->network
->dhcp6_client_send_options
) {
624 r
= sd_dhcp6_client_add_option(client
, send_option
);
628 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set option: %m");
631 r
= dhcp6_set_hostname(client
, link
);
635 r
= sd_dhcp6_client_set_ifindex(client
, link
->ifindex
);
637 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set ifindex: %m");
639 if (link
->network
->dhcp6_mudurl
) {
640 r
= sd_dhcp6_client_set_request_mud_url(client
, link
->network
->dhcp6_mudurl
);
642 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
645 if (link
->network
->dhcp6_use_dns
) {
646 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVER
);
648 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request DNS servers: %m");
651 if (link
->network
->dhcp6_use_domains
> 0) {
652 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN
);
654 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request domains: %m");
657 if (link
->network
->dhcp6_use_captive_portal
> 0) {
658 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CAPTIVE_PORTAL
);
660 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request captive portal: %m");
663 if (link
->network
->dhcp6_use_ntp
) {
664 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
);
666 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request NTP servers: %m");
668 /* If the server does not provide NTP servers, then we fallback to use SNTP servers. */
669 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVER
);
671 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request SNTP servers: %m");
674 SET_FOREACH(request_options
, link
->network
->dhcp6_request_options
) {
675 uint32_t option
= PTR_TO_UINT32(request_options
);
677 r
= sd_dhcp6_client_set_request_option(client
, option
);
679 log_link_debug(link
, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option
);
683 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option
);
686 if (link
->network
->dhcp6_user_class
) {
687 r
= sd_dhcp6_client_set_request_user_class(client
, link
->network
->dhcp6_user_class
);
689 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set user class: %m");
692 if (link
->network
->dhcp6_vendor_class
) {
693 r
= sd_dhcp6_client_set_request_vendor_class(client
, link
->network
->dhcp6_vendor_class
);
695 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor class: %m");
698 ORDERED_HASHMAP_FOREACH(vendor_option
, link
->network
->dhcp6_client_send_vendor_options
) {
699 r
= sd_dhcp6_client_add_vendor_option(client
, vendor_option
);
703 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor option: %m");
706 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
708 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set callback: %m");
710 r
= dhcp6_client_set_state_callback(client
, dhcp6_client_callback_bus
, link
);
712 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set state change callback: %m");
714 r
= sd_dhcp6_client_set_prefix_delegation(client
, link
->network
->dhcp6_use_pd_prefix
);
716 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting prefixes to be delegated: %m",
717 enable_disable(link
->network
->dhcp6_use_pd_prefix
));
719 /* Even if UseAddress=no, we need to request IA_NA, as the dhcp6 client may be started in solicit mode. */
720 r
= sd_dhcp6_client_set_address_request(client
, link
->network
->dhcp6_use_pd_prefix
? link
->network
->dhcp6_use_address
: true);
722 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting address: %m",
723 enable_disable(link
->network
->dhcp6_use_address
));
725 if (link
->network
->dhcp6_pd_prefix_length
> 0) {
726 r
= sd_dhcp6_client_set_prefix_delegation_hint(client
,
727 link
->network
->dhcp6_pd_prefix_length
,
728 &link
->network
->dhcp6_pd_prefix_hint
);
730 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set prefix delegation hint: %m");
733 r
= sd_dhcp6_client_set_rapid_commit(client
, link
->network
->dhcp6_use_rapid_commit
);
735 return log_link_debug_errno(link
, r
,
736 "DHCPv6 CLIENT: Failed to %s rapid commit: %m",
737 enable_disable(link
->network
->dhcp6_use_rapid_commit
));
739 r
= sd_dhcp6_client_set_send_release(client
, link
->network
->dhcp6_send_release
);
741 return log_link_debug_errno(link
, r
,
742 "DHCPv6 CLIENT: Failed to %s sending release message on stop: %m",
743 enable_disable(link
->network
->dhcp6_send_release
));
745 link
->dhcp6_client
= TAKE_PTR(client
);
750 int dhcp6_update_mac(Link
*link
) {
756 if (!link
->dhcp6_client
)
759 restart
= sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0;
762 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
767 r
= dhcp6_set_identifier(link
, link
->dhcp6_client
);
772 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
774 return log_link_warning_errno(link
, r
, "Could not restart DHCPv6 client: %m");
780 static int dhcp6_process_request(Request
*req
, Link
*link
, void *userdata
) {
785 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
788 r
= dhcp_configure_duid(link
, link_get_dhcp6_duid(link
));
792 r
= dhcp6_configure(link
);
794 return log_link_warning_errno(link
, r
, "Failed to configure DHCPv6 client: %m");
796 r
= ndisc_start(link
);
798 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
800 r
= dhcp6_start(link
);
802 return log_link_warning_errno(link
, r
, "Failed to start DHCPv6 client: %m");
804 log_link_debug(link
, "DHCPv6 client is configured%s.",
805 r
> 0 ? ", acquiring DHCPv6 lease" : "");
809 int link_request_dhcp6_client(Link
*link
) {
814 if (!link_dhcp6_enabled(link
) && !link_ipv6_accept_ra_enabled(link
))
817 if (link
->dhcp6_client
)
820 r
= link_queue_request(link
, REQUEST_TYPE_DHCP6_CLIENT
, dhcp6_process_request
, NULL
);
822 return log_link_warning_errno(link
, r
, "Failed to request configuring of the DHCPv6 client: %m");
824 log_link_debug(link
, "Requested configuring of the DHCPv6 client.");
828 int link_serialize_dhcp6_client(Link
*link
, FILE *f
) {
829 _cleanup_free_
char *duid
= NULL
;
835 if (!link
->dhcp6_client
)
838 r
= sd_dhcp6_client_get_iaid(link
->dhcp6_client
, &iaid
);
840 fprintf(f
, "DHCP6_CLIENT_IAID=0x%x\n", iaid
);
842 r
= sd_dhcp6_client_duid_as_string(link
->dhcp6_client
, &duid
);
844 fprintf(f
, "DHCP6_CLIENT_DUID=%s\n", duid
);
849 int config_parse_dhcp6_pd_prefix_hint(
851 const char *filename
,
854 unsigned section_line
,
861 Network
*network
= ASSERT_PTR(userdata
);
862 union in_addr_union u
;
863 unsigned char prefixlen
;
870 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &u
, &prefixlen
);
872 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
873 "Failed to parse %s=%s, ignoring assignment.", lvalue
, rvalue
);
877 if (prefixlen
< 1 || prefixlen
> 128) {
878 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
879 "Invalid prefix length in %s=%s, ignoring assignment.", lvalue
, rvalue
);
883 network
->dhcp6_pd_prefix_hint
= u
.in6
;
884 network
->dhcp6_pd_prefix_length
= prefixlen
;
889 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp6_client_start_mode
, dhcp6_client_start_mode
, DHCP6ClientStartMode
,
890 "Failed to parse WithoutRA= setting");
892 static const char* const dhcp6_client_start_mode_table
[_DHCP6_CLIENT_START_MODE_MAX
] = {
893 [DHCP6_CLIENT_START_MODE_NO
] = "no",
894 [DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
] = "information-request",
895 [DHCP6_CLIENT_START_MODE_SOLICIT
] = "solicit",
898 DEFINE_STRING_TABLE_LOOKUP(dhcp6_client_start_mode
, DHCP6ClientStartMode
);