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
) {
54 assert(link
->manager
);
57 link
->dhcp6_configured
= false;
59 SET_FOREACH(route
, link
->manager
->routes
) {
60 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
62 if (only_marked
&& !route_is_marked(route
))
65 RET_GATHER(ret
, route_remove_and_cancel(route
, link
->manager
));
68 SET_FOREACH(address
, link
->addresses
) {
69 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
71 if (only_marked
&& !address_is_marked(address
))
74 RET_GATHER(ret
, address_remove_and_cancel(address
, link
));
80 static int dhcp6_address_ready_callback(Address
*address
) {
84 assert(address
->link
);
86 SET_FOREACH(a
, address
->link
->addresses
)
87 if (a
->source
== NETWORK_CONFIG_SOURCE_DHCP6
)
90 return dhcp6_check_ready(address
->link
);
93 int dhcp6_check_ready(Link
*link
) {
97 assert(link
->network
);
99 if (link
->dhcp6_messages
> 0) {
100 log_link_debug(link
, "%s(): DHCPv6 addresses and routes are not set.", __func__
);
104 if (link
->network
->dhcp6_use_address
&&
105 !link_check_addresses_ready(link
, NETWORK_CONFIG_SOURCE_DHCP6
)) {
108 SET_FOREACH(address
, link
->addresses
)
109 if (address
->source
== NETWORK_CONFIG_SOURCE_DHCP6
)
110 address
->callback
= dhcp6_address_ready_callback
;
112 log_link_debug(link
, "%s(): no DHCPv6 address is ready.", __func__
);
116 link
->dhcp6_configured
= true;
117 log_link_debug(link
, "DHCPv6 addresses and routes set.");
119 r
= dhcp6_remove(link
, /* only_marked = */ true);
123 link_check_ready(link
);
127 static int dhcp6_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
132 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set DHCPv6 address");
136 r
= dhcp6_check_ready(link
);
138 link_enter_failed(link
);
143 static int verify_dhcp6_address(Link
*link
, const Address
*address
) {
144 bool by_ndisc
= false;
150 assert(address
->family
== AF_INET6
);
152 const char *pretty
= IN6_ADDR_TO_STRING(&address
->in_addr
.in6
);
154 if (address_get_harder(link
, address
, &existing
) < 0) {
156 log_level
= LOG_INFO
;
159 log_level
= LOG_DEBUG
;
161 if (address
->prefixlen
== existing
->prefixlen
)
162 /* Currently, only conflict in prefix length is reported. */
165 if (existing
->source
== NETWORK_CONFIG_SOURCE_NDISC
)
168 log_link_warning(link
, "Ignoring DHCPv6 address %s/%u (valid %s, preferred %s) which conflicts with %s/%u%s.",
169 pretty
, address
->prefixlen
,
170 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
171 FORMAT_LIFETIME(address
->lifetime_preferred_usec
),
172 pretty
, existing
->prefixlen
,
173 by_ndisc
? " assigned by NDisc" : "");
175 log_link_warning(link
, "Hint: use IPv6Token= setting to change the address generated by NDisc or set UseAutonomousPrefix=no.");
180 log_link_full(link
, log_level
, "DHCPv6 address %s/%u (valid %s, preferred %s)",
181 pretty
, address
->prefixlen
,
182 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
183 FORMAT_LIFETIME(address
->lifetime_preferred_usec
));
187 static int dhcp6_request_address(
189 const struct in6_addr
*server_address
,
190 const struct in6_addr
*ip6_addr
,
191 usec_t lifetime_preferred_usec
,
192 usec_t lifetime_valid_usec
) {
194 _cleanup_(address_unrefp
) Address
*addr
= NULL
;
198 r
= address_new(&addr
);
202 addr
->source
= NETWORK_CONFIG_SOURCE_DHCP6
;
203 addr
->provider
.in6
= *server_address
;
204 addr
->family
= AF_INET6
;
205 addr
->in_addr
.in6
= *ip6_addr
;
206 addr
->flags
= IFA_F_NOPREFIXROUTE
;
207 addr
->prefixlen
= 128;
208 addr
->lifetime_preferred_usec
= lifetime_preferred_usec
;
209 addr
->lifetime_valid_usec
= lifetime_valid_usec
;
211 if (verify_dhcp6_address(link
, addr
) < 0)
214 r
= free_and_strdup_warn(&addr
->netlabel
, link
->network
->dhcp6_netlabel
);
218 if (address_get(link
, addr
, &existing
) < 0)
219 link
->dhcp6_configured
= false;
221 address_unmark(existing
);
223 r
= link_request_address(link
, addr
, &link
->dhcp6_messages
,
224 dhcp6_address_handler
, NULL
);
226 return log_link_error_errno(link
, r
, "Failed to request DHCPv6 address %s/128: %m",
227 IN6_ADDR_TO_STRING(ip6_addr
));
231 static int dhcp6_address_acquired(Link
*link
) {
232 struct in6_addr server_address
;
236 assert(link
->network
);
237 assert(link
->dhcp6_lease
);
239 if (!link
->network
->dhcp6_use_address
)
242 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &server_address
);
244 return log_link_warning_errno(link
, r
, "Failed to get server address of DHCPv6 lease: %m");
246 FOREACH_DHCP6_ADDRESS(link
->dhcp6_lease
) {
247 usec_t lifetime_preferred_usec
, lifetime_valid_usec
;
248 struct in6_addr ip6_addr
;
250 r
= sd_dhcp6_lease_get_address(link
->dhcp6_lease
, &ip6_addr
);
254 r
= sd_dhcp6_lease_get_address_lifetime_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
,
255 &lifetime_preferred_usec
, &lifetime_valid_usec
);
259 r
= dhcp6_request_address(link
, &server_address
, &ip6_addr
,
260 lifetime_preferred_usec
,
261 lifetime_valid_usec
);
266 if (link
->network
->dhcp6_use_hostname
) {
267 const char *dhcpname
= NULL
;
268 _cleanup_free_
char *hostname
= NULL
;
270 (void) sd_dhcp6_lease_get_fqdn(link
->dhcp6_lease
, &dhcpname
);
273 r
= shorten_overlong(dhcpname
, &hostname
);
275 log_link_warning_errno(link
, r
, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname
);
277 log_link_notice(link
, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname
, hostname
);
280 r
= manager_set_hostname(link
->manager
, hostname
);
282 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
289 static int dhcp6_lease_ip_acquired(sd_dhcp6_client
*client
, Link
*link
) {
290 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease_old
= NULL
;
291 sd_dhcp6_lease
*lease
;
294 link_mark_addresses(link
, NETWORK_CONFIG_SOURCE_DHCP6
);
295 manager_mark_routes(link
->manager
, NULL
, NETWORK_CONFIG_SOURCE_DHCP6
);
297 r
= sd_dhcp6_client_get_lease(client
, &lease
);
299 return log_link_error_errno(link
, r
, "Failed to get DHCPv6 lease: %m");
301 lease_old
= TAKE_PTR(link
->dhcp6_lease
);
302 link
->dhcp6_lease
= sd_dhcp6_lease_ref(lease
);
304 r
= dhcp6_address_acquired(link
);
308 if (sd_dhcp6_lease_has_pd_prefix(lease
)) {
309 r
= dhcp6_pd_prefix_acquired(link
);
312 } else if (sd_dhcp6_lease_has_pd_prefix(lease_old
))
313 /* When we had PD prefixes but not now, we need to remove them. */
314 dhcp_pd_prefix_lost(link
);
316 if (link
->dhcp6_messages
== 0) {
317 link
->dhcp6_configured
= true;
319 r
= dhcp6_remove(link
, /* only_marked = */ true);
323 log_link_debug(link
, "Setting DHCPv6 addresses and routes");
325 if (!link
->dhcp6_configured
)
326 link_set_state(link
, LINK_STATE_CONFIGURING
);
328 link_check_ready(link
);
332 static int dhcp6_lease_information_acquired(sd_dhcp6_client
*client
, Link
*link
) {
333 sd_dhcp6_lease
*lease
;
339 r
= sd_dhcp6_client_get_lease(client
, &lease
);
341 return log_link_error_errno(link
, r
, "Failed to get DHCPv6 lease: %m");
343 unref_and_replace_full(link
->dhcp6_lease
, lease
, sd_dhcp6_lease_ref
, sd_dhcp6_lease_unref
);
349 static int dhcp6_lease_lost(Link
*link
) {
353 assert(link
->manager
);
355 log_link_info(link
, "DHCPv6 lease lost");
357 if (sd_dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
))
358 dhcp_pd_prefix_lost(link
);
360 link
->dhcp6_lease
= sd_dhcp6_lease_unref(link
->dhcp6_lease
);
362 r
= dhcp6_remove(link
, /* only_marked = */ false);
369 static void dhcp6_handler(sd_dhcp6_client
*client
, int event
, void *userdata
) {
370 Link
*link
= ASSERT_PTR(userdata
);
373 assert(link
->network
);
375 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
379 case SD_DHCP6_CLIENT_EVENT_STOP
:
380 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
:
381 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
:
382 r
= dhcp6_lease_lost(link
);
385 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
386 r
= dhcp6_lease_ip_acquired(client
, link
);
389 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
390 r
= dhcp6_lease_information_acquired(client
, link
);
395 log_link_warning_errno(link
, event
, "DHCPv6 error, ignoring: %m");
397 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
400 link_enter_failed(link
);
403 int dhcp6_start_on_ra(Link
*link
, bool information_request
) {
407 assert(link
->dhcp6_client
);
408 assert(link
->network
);
409 assert(in6_addr_is_link_local(&link
->ipv6ll_address
));
411 if (link_get_dhcp6_client_start_mode(link
) != DHCP6_CLIENT_START_MODE_NO
)
412 /* When WithoutRA= is specified, then the DHCPv6 client should be already running in
413 * the requested mode. Hence, ignore the requests by RA. */
416 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
423 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
427 if (inf_req
== information_request
)
428 /* The client is already running in the requested mode. */
433 "The DHCPv6 client is already running in the managed mode, "
434 "refusing to start the client in the information requesting mode.");
439 "The DHCPv6 client is running in the information requesting mode. "
440 "Restarting the client in the managed mode.");
442 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
446 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
451 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, information_request
);
455 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
462 int dhcp6_start(Link
*link
) {
463 DHCP6ClientStartMode start_mode
;
467 assert(link
->network
);
469 if (!link
->dhcp6_client
)
472 if (!link_dhcp6_enabled(link
))
475 if (!link_has_carrier(link
))
478 if (sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0)
481 if (!in6_addr_is_link_local(&link
->ipv6ll_address
)) {
482 log_link_debug(link
, "IPv6 link-local address is not set, delaying to start DHCPv6 client.");
486 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
490 start_mode
= link_get_dhcp6_client_start_mode(link
);
491 if (start_mode
== DHCP6_CLIENT_START_MODE_NO
)
494 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
,
495 start_mode
== DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
);
499 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
506 static int dhcp6_set_hostname(sd_dhcp6_client
*client
, Link
*link
) {
507 _cleanup_free_
char *hostname
= NULL
;
513 if (!link
->network
->dhcp6_send_hostname
)
515 else if (link
->network
->dhcp6_hostname
)
516 hn
= link
->network
->dhcp6_hostname
;
518 r
= gethostname_strict(&hostname
);
519 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
520 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to get hostname: %m");
525 r
= sd_dhcp6_client_set_fqdn(client
, hn
);
526 if (r
== -EINVAL
&& hostname
)
527 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
528 log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
530 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname: %m");
535 static int dhcp6_set_identifier(Link
*link
, sd_dhcp6_client
*client
) {
540 assert(link
->network
);
543 r
= sd_dhcp6_client_set_mac(client
, link
->hw_addr
.bytes
, link
->hw_addr
.length
, link
->iftype
);
547 if (link
->network
->dhcp6_iaid_set
) {
548 r
= sd_dhcp6_client_set_iaid(client
, link
->network
->dhcp6_iaid
);
553 duid
= link_get_dhcp6_duid(link
);
555 if (duid
->raw_data_len
== 0)
556 switch (duid
->type
) {
558 r
= sd_dhcp6_client_set_duid_llt(client
, duid
->llt_time
);
561 r
= sd_dhcp6_client_set_duid_ll(client
);
564 r
= sd_dhcp6_client_set_duid_en(client
);
567 r
= sd_dhcp6_client_set_duid_uuid(client
);
570 r
= sd_dhcp6_client_set_duid_raw(client
, duid
->type
, NULL
, 0);
573 r
= sd_dhcp6_client_set_duid_raw(client
, duid
->type
, duid
->raw_data
, duid
->raw_data_len
);
580 static int dhcp6_configure(Link
*link
) {
581 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
582 sd_dhcp6_option
*vendor_option
;
583 sd_dhcp6_option
*send_option
;
584 void *request_options
;
588 assert(link
->network
);
590 if (link
->dhcp6_client
)
591 return log_link_debug_errno(link
, SYNTHETIC_ERRNO(EBUSY
), "DHCPv6 client is already configured.");
593 r
= sd_dhcp6_client_new(&client
);
595 return log_oom_debug();
597 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
599 r
= sd_dhcp6_client_attach_event(client
, link
->manager
->event
, 0);
601 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to attach event: %m");
603 r
= sd_dhcp6_client_attach_device(client
, link
->dev
);
605 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to attach device: %m");
607 r
= dhcp6_set_identifier(link
, client
);
609 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set identifier: %m");
611 ORDERED_HASHMAP_FOREACH(send_option
, link
->network
->dhcp6_client_send_options
) {
612 r
= sd_dhcp6_client_add_option(client
, send_option
);
616 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set option: %m");
619 r
= dhcp6_set_hostname(client
, link
);
623 r
= sd_dhcp6_client_set_ifindex(client
, link
->ifindex
);
625 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set ifindex: %m");
627 if (link
->network
->dhcp6_mudurl
) {
628 r
= sd_dhcp6_client_set_request_mud_url(client
, link
->network
->dhcp6_mudurl
);
630 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
633 if (link
->network
->dhcp6_use_dns
) {
634 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVER
);
636 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request DNS servers: %m");
639 if (link
->network
->dhcp6_use_domains
> 0) {
640 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN
);
642 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request domains: %m");
645 if (link
->network
->dhcp6_use_captive_portal
> 0) {
646 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CAPTIVE_PORTAL
);
648 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request captive portal: %m");
651 if (link
->network
->dhcp6_use_ntp
) {
652 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
);
654 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request NTP servers: %m");
656 /* If the server does not provide NTP servers, then we fallback to use SNTP servers. */
657 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVER
);
659 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request SNTP servers: %m");
662 SET_FOREACH(request_options
, link
->network
->dhcp6_request_options
) {
663 uint32_t option
= PTR_TO_UINT32(request_options
);
665 r
= sd_dhcp6_client_set_request_option(client
, option
);
667 log_link_debug(link
, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option
);
671 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option
);
674 if (link
->network
->dhcp6_user_class
) {
675 r
= sd_dhcp6_client_set_request_user_class(client
, link
->network
->dhcp6_user_class
);
677 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set user class: %m");
680 if (link
->network
->dhcp6_vendor_class
) {
681 r
= sd_dhcp6_client_set_request_vendor_class(client
, link
->network
->dhcp6_vendor_class
);
683 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor class: %m");
686 ORDERED_HASHMAP_FOREACH(vendor_option
, link
->network
->dhcp6_client_send_vendor_options
) {
687 r
= sd_dhcp6_client_add_vendor_option(client
, vendor_option
);
691 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor option: %m");
694 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
696 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set callback: %m");
698 r
= dhcp6_client_set_state_callback(client
, dhcp6_client_callback_bus
, link
);
700 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set state change callback: %m");
702 r
= sd_dhcp6_client_set_prefix_delegation(client
, link
->network
->dhcp6_use_pd_prefix
);
704 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting prefixes to be delegated: %m",
705 enable_disable(link
->network
->dhcp6_use_pd_prefix
));
707 /* Even if UseAddress=no, we need to request IA_NA, as the dhcp6 client may be started in solicit mode. */
708 r
= sd_dhcp6_client_set_address_request(client
, link
->network
->dhcp6_use_pd_prefix
? link
->network
->dhcp6_use_address
: true);
710 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting address: %m",
711 enable_disable(link
->network
->dhcp6_use_address
));
713 if (link
->network
->dhcp6_pd_prefix_length
> 0) {
714 r
= sd_dhcp6_client_set_prefix_delegation_hint(client
,
715 link
->network
->dhcp6_pd_prefix_length
,
716 &link
->network
->dhcp6_pd_prefix_hint
);
718 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set prefix delegation hint: %m");
721 r
= sd_dhcp6_client_set_rapid_commit(client
, link
->network
->dhcp6_use_rapid_commit
);
723 return log_link_debug_errno(link
, r
,
724 "DHCPv6 CLIENT: Failed to %s rapid commit: %m",
725 enable_disable(link
->network
->dhcp6_use_rapid_commit
));
727 r
= sd_dhcp6_client_set_send_release(client
, link
->network
->dhcp6_send_release
);
729 return log_link_debug_errno(link
, r
,
730 "DHCPv6 CLIENT: Failed to %s sending release message on stop: %m",
731 enable_disable(link
->network
->dhcp6_send_release
));
733 link
->dhcp6_client
= TAKE_PTR(client
);
738 int dhcp6_update_mac(Link
*link
) {
744 if (!link
->dhcp6_client
)
747 restart
= sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0;
750 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
755 r
= dhcp6_set_identifier(link
, link
->dhcp6_client
);
760 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
762 return log_link_warning_errno(link
, r
, "Could not restart DHCPv6 client: %m");
768 static int dhcp6_process_request(Request
*req
, Link
*link
, void *userdata
) {
773 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
776 r
= dhcp_configure_duid(link
, link_get_dhcp6_duid(link
));
780 r
= dhcp6_configure(link
);
782 return log_link_warning_errno(link
, r
, "Failed to configure DHCPv6 client: %m");
784 r
= ndisc_start(link
);
786 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
788 r
= dhcp6_start(link
);
790 return log_link_warning_errno(link
, r
, "Failed to start DHCPv6 client: %m");
792 log_link_debug(link
, "DHCPv6 client is configured%s.",
793 r
> 0 ? ", acquiring DHCPv6 lease" : "");
797 int link_request_dhcp6_client(Link
*link
) {
802 if (!link_dhcp6_enabled(link
) && !link_ipv6_accept_ra_enabled(link
))
805 if (link
->dhcp6_client
)
808 r
= link_queue_request(link
, REQUEST_TYPE_DHCP6_CLIENT
, dhcp6_process_request
, NULL
);
810 return log_link_warning_errno(link
, r
, "Failed to request configuring of the DHCPv6 client: %m");
812 log_link_debug(link
, "Requested configuring of the DHCPv6 client.");
816 int link_serialize_dhcp6_client(Link
*link
, FILE *f
) {
817 _cleanup_free_
char *duid
= NULL
;
823 if (!link
->dhcp6_client
)
826 r
= sd_dhcp6_client_get_iaid(link
->dhcp6_client
, &iaid
);
828 fprintf(f
, "DHCP6_CLIENT_IAID=0x%x\n", iaid
);
830 r
= sd_dhcp6_client_get_duid_as_string(link
->dhcp6_client
, &duid
);
832 fprintf(f
, "DHCP6_CLIENT_DUID=%s\n", duid
);
837 int config_parse_dhcp6_pd_prefix_hint(
839 const char *filename
,
842 unsigned section_line
,
849 Network
*network
= ASSERT_PTR(userdata
);
850 union in_addr_union u
;
851 unsigned char prefixlen
;
858 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &u
, &prefixlen
);
860 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
861 "Failed to parse %s=%s, ignoring assignment.", lvalue
, rvalue
);
865 if (prefixlen
< 1 || prefixlen
> 128) {
866 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
867 "Invalid prefix length in %s=%s, ignoring assignment.", lvalue
, rvalue
);
871 network
->dhcp6_pd_prefix_hint
= u
.in6
;
872 network
->dhcp6_pd_prefix_length
= prefixlen
;
877 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp6_client_start_mode
, dhcp6_client_start_mode
, DHCP6ClientStartMode
,
878 "Failed to parse WithoutRA= setting");
880 static const char* const dhcp6_client_start_mode_table
[_DHCP6_CLIENT_START_MODE_MAX
] = {
881 [DHCP6_CLIENT_START_MODE_NO
] = "no",
882 [DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
] = "information-request",
883 [DHCP6_CLIENT_START_MODE_SOLICIT
] = "solicit",
886 DEFINE_STRING_TABLE_LOOKUP(dhcp6_client_start_mode
, DHCP6ClientStartMode
);