1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include "sd-dhcp6-client.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.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-queue.h"
17 #include "networkd-route.h"
18 #include "string-table.h"
19 #include "string-util.h"
21 bool link_dhcp6_with_address_enabled(Link
*link
) {
22 if (!link_dhcp6_enabled(link
))
25 return link
->network
->dhcp6_use_address
;
28 static DHCP6ClientStartMode
link_get_dhcp6_client_start_mode(Link
*link
) {
32 return DHCP6_CLIENT_START_MODE_NO
;
34 /* When WithoutRA= is explicitly specified, then honor it. */
35 if (link
->network
->dhcp6_client_start_mode
>= 0)
36 return link
->network
->dhcp6_client_start_mode
;
38 /* When this interface itself is an uplink interface, then start dhcp6 client in solicit mode. */
39 if (dhcp_pd_is_uplink(link
, link
, /* accept_auto = */ false))
40 return DHCP6_CLIENT_START_MODE_SOLICIT
;
42 /* Otherwise, start dhcp6 client when RA is received. */
43 return DHCP6_CLIENT_START_MODE_NO
;
46 static int dhcp6_remove(Link
*link
, bool only_marked
) {
54 link
->dhcp6_configured
= false;
56 SET_FOREACH(route
, link
->routes
) {
57 if (route
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
59 if (only_marked
&& !route_is_marked(route
))
62 k
= route_remove(route
);
66 route_cancel_request(route
, link
);
69 SET_FOREACH(address
, link
->addresses
) {
70 if (address
->source
!= NETWORK_CONFIG_SOURCE_DHCP6
)
72 if (only_marked
&& !address_is_marked(address
))
75 k
= address_remove(address
);
79 address_cancel_request(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(link
, address
, &existing
) < 0 &&
167 link_get_address(link
, AF_INET6
, &address
->in_addr
, 0, &existing
) < 0) {
169 log_level
= LOG_INFO
;
172 log_level
= LOG_DEBUG
;
174 if (address
->prefixlen
== existing
->prefixlen
)
175 /* Currently, only conflict in prefix length is reported. */
178 if (existing
->source
== NETWORK_CONFIG_SOURCE_NDISC
)
181 log_link_warning(link
, "Ignoring DHCPv6 address %s/%u (valid %s, preferred %s) which conflicts with %s/%u%s.",
182 pretty
, address
->prefixlen
,
183 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
184 FORMAT_LIFETIME(address
->lifetime_preferred_usec
),
185 pretty
, existing
->prefixlen
,
186 by_ndisc
? " assigned by NDisc" : "");
188 log_link_warning(link
, "Hint: use IPv6Token= setting to change the address generated by NDisc or set UseAutonomousPrefix=no.");
193 log_link_full(link
, log_level
, "DHCPv6 address %s/%u (valid %s, preferred %s)",
194 pretty
, address
->prefixlen
,
195 FORMAT_LIFETIME(address
->lifetime_valid_usec
),
196 FORMAT_LIFETIME(address
->lifetime_preferred_usec
));
200 static int dhcp6_request_address(
202 const struct in6_addr
*server_address
,
203 const struct in6_addr
*ip6_addr
,
204 usec_t lifetime_preferred_usec
,
205 usec_t lifetime_valid_usec
) {
207 _cleanup_(address_freep
) Address
*addr
= NULL
;
211 r
= address_new(&addr
);
215 addr
->source
= NETWORK_CONFIG_SOURCE_DHCP6
;
216 addr
->provider
.in6
= *server_address
;
217 addr
->family
= AF_INET6
;
218 addr
->in_addr
.in6
= *ip6_addr
;
219 addr
->flags
= IFA_F_NOPREFIXROUTE
;
220 addr
->prefixlen
= 128;
221 addr
->lifetime_preferred_usec
= lifetime_preferred_usec
;
222 addr
->lifetime_valid_usec
= lifetime_valid_usec
;
224 if (verify_dhcp6_address(link
, addr
) < 0)
227 r
= free_and_strdup_warn(&addr
->netlabel
, link
->network
->dhcp6_netlabel
);
231 if (address_get(link
, addr
, &existing
) < 0)
232 link
->dhcp6_configured
= false;
234 address_unmark(existing
);
236 r
= link_request_address(link
, TAKE_PTR(addr
), true, &link
->dhcp6_messages
,
237 dhcp6_address_handler
, NULL
);
239 return log_link_error_errno(link
, r
, "Failed to request DHCPv6 address %s/128: %m",
240 IN6_ADDR_TO_STRING(ip6_addr
));
244 static int dhcp6_address_acquired(Link
*link
) {
245 struct in6_addr server_address
;
246 usec_t timestamp_usec
;
250 assert(link
->network
);
251 assert(link
->dhcp6_lease
);
253 if (!link
->network
->dhcp6_use_address
)
256 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &server_address
);
258 return log_link_warning_errno(link
, r
, "Failed to get server address of DHCPv6 lease: %m");
260 r
= sd_dhcp6_lease_get_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, ×tamp_usec
);
262 return log_link_warning_errno(link
, r
, "Failed to get timestamp of DHCPv6 lease: %m");
264 for (sd_dhcp6_lease_reset_address_iter(link
->dhcp6_lease
);;) {
265 uint32_t lifetime_preferred_sec
, lifetime_valid_sec
;
266 struct in6_addr ip6_addr
;
268 r
= sd_dhcp6_lease_get_address(link
->dhcp6_lease
, &ip6_addr
, &lifetime_preferred_sec
, &lifetime_valid_sec
);
272 r
= dhcp6_request_address(link
, &server_address
, &ip6_addr
,
273 sec_to_usec(lifetime_preferred_sec
, timestamp_usec
),
274 sec_to_usec(lifetime_valid_sec
, timestamp_usec
));
279 if (link
->network
->dhcp6_use_hostname
) {
280 const char *dhcpname
= NULL
;
281 _cleanup_free_
char *hostname
= NULL
;
283 (void) sd_dhcp6_lease_get_fqdn(link
->dhcp6_lease
, &dhcpname
);
286 r
= shorten_overlong(dhcpname
, &hostname
);
288 log_link_warning_errno(link
, r
, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname
);
290 log_link_notice(link
, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname
, hostname
);
293 r
= manager_set_hostname(link
->manager
, hostname
);
295 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
302 static int dhcp6_lease_ip_acquired(sd_dhcp6_client
*client
, Link
*link
) {
303 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease_old
= NULL
;
304 sd_dhcp6_lease
*lease
;
307 link_mark_addresses(link
, NETWORK_CONFIG_SOURCE_DHCP6
, NULL
);
308 link_mark_routes(link
, NETWORK_CONFIG_SOURCE_DHCP6
, NULL
);
310 r
= sd_dhcp6_client_get_lease(client
, &lease
);
312 return log_link_error_errno(link
, r
, "Failed to get DHCPv6 lease: %m");
314 lease_old
= TAKE_PTR(link
->dhcp6_lease
);
315 link
->dhcp6_lease
= sd_dhcp6_lease_ref(lease
);
317 r
= dhcp6_address_acquired(link
);
321 if (dhcp6_lease_has_pd_prefix(lease
)) {
322 r
= dhcp6_pd_prefix_acquired(link
);
325 } else if (dhcp6_lease_has_pd_prefix(lease_old
))
326 /* When we had PD prefixes but not now, we need to remove them. */
327 dhcp_pd_prefix_lost(link
);
329 if (link
->dhcp6_messages
== 0) {
330 link
->dhcp6_configured
= true;
332 r
= dhcp6_remove(link
, /* only_marked = */ true);
336 log_link_debug(link
, "Setting DHCPv6 addresses and routes");
338 if (!link
->dhcp6_configured
)
339 link_set_state(link
, LINK_STATE_CONFIGURING
);
341 link_check_ready(link
);
345 static int dhcp6_lease_information_acquired(sd_dhcp6_client
*client
, Link
*link
) {
349 static int dhcp6_lease_lost(Link
*link
) {
353 assert(link
->manager
);
355 log_link_info(link
, "DHCPv6 lease lost");
357 if (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
= userdata
;
374 assert(link
->network
);
376 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
380 case SD_DHCP6_CLIENT_EVENT_STOP
:
381 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
:
382 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
:
383 r
= dhcp6_lease_lost(link
);
385 link_enter_failed(link
);
388 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
389 r
= dhcp6_lease_ip_acquired(client
, link
);
391 link_enter_failed(link
);
396 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
397 r
= dhcp6_lease_information_acquired(client
, link
);
399 link_enter_failed(link
);
404 log_link_warning_errno(link
, event
, "DHCPv6 error: %m");
406 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
411 int dhcp6_start_on_ra(Link
*link
, bool information_request
) {
415 assert(link
->dhcp6_client
);
416 assert(link
->network
);
417 assert(in6_addr_is_link_local(&link
->ipv6ll_address
));
419 if (link_get_dhcp6_client_start_mode(link
) != DHCP6_CLIENT_START_MODE_NO
)
420 /* When WithoutRA= is specified, then the DHCPv6 client should be already running in
421 * the requested mode. Hence, ignore the requests by RA. */
424 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
431 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
435 if (inf_req
== information_request
)
436 /* The client is already running in the requested mode. */
441 "The DHCPv6 client is already running in the managed mode, "
442 "refusing to start the client in the information requesting mode.");
447 "The DHCPv6 client is running in the information requesting mode. "
448 "Restarting the client in the managed mode.");
450 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
454 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
459 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, information_request
);
463 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
470 int dhcp6_start(Link
*link
) {
471 DHCP6ClientStartMode start_mode
;
475 assert(link
->network
);
477 if (!link
->dhcp6_client
)
480 if (!link_dhcp6_enabled(link
))
483 if (!link_has_carrier(link
))
486 if (sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0)
489 if (!in6_addr_is_link_local(&link
->ipv6ll_address
)) {
490 log_link_debug(link
, "IPv6 link-local address is not set, delaying to start DHCPv6 client.");
494 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
498 start_mode
= link_get_dhcp6_client_start_mode(link
);
499 if (start_mode
== DHCP6_CLIENT_START_MODE_NO
)
502 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
,
503 start_mode
== DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
);
507 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
514 static int dhcp6_set_hostname(sd_dhcp6_client
*client
, Link
*link
) {
515 _cleanup_free_
char *hostname
= NULL
;
521 if (!link
->network
->dhcp_send_hostname
)
523 else if (link
->network
->dhcp_hostname
)
524 hn
= link
->network
->dhcp_hostname
;
526 r
= gethostname_strict(&hostname
);
527 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
528 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to get hostname: %m");
533 r
= sd_dhcp6_client_set_fqdn(client
, hn
);
534 if (r
== -EINVAL
&& hostname
)
535 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
536 log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
538 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname: %m");
543 static int dhcp6_set_identifier(Link
*link
, sd_dhcp6_client
*client
) {
548 assert(link
->network
);
551 r
= sd_dhcp6_client_set_mac(client
, link
->hw_addr
.bytes
, link
->hw_addr
.length
, link
->iftype
);
555 if (link
->network
->dhcp6_iaid_set
) {
556 r
= sd_dhcp6_client_set_iaid(client
, link
->network
->dhcp6_iaid
);
561 duid
= link_get_dhcp6_duid(link
);
562 if (duid
->type
== DUID_TYPE_LLT
&& duid
->raw_data_len
== 0)
563 r
= sd_dhcp6_client_set_duid_llt(client
, duid
->llt_time
);
565 r
= sd_dhcp6_client_set_duid(client
,
567 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
575 static int dhcp6_configure(Link
*link
) {
576 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
577 sd_dhcp6_option
*vendor_option
;
578 sd_dhcp6_option
*send_option
;
579 void *request_options
;
583 assert(link
->network
);
585 if (link
->dhcp6_client
)
586 return log_link_debug_errno(link
, SYNTHETIC_ERRNO(EBUSY
), "DHCPv6 client is already configured.");
588 r
= sd_dhcp6_client_new(&client
);
590 return log_oom_debug();
592 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
594 r
= sd_dhcp6_client_attach_event(client
, link
->manager
->event
, 0);
596 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to attach event: %m");
598 r
= dhcp6_set_identifier(link
, client
);
600 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set identifier: %m");
602 ORDERED_HASHMAP_FOREACH(send_option
, link
->network
->dhcp6_client_send_options
) {
603 r
= sd_dhcp6_client_add_option(client
, send_option
);
607 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set option: %m");
610 r
= dhcp6_set_hostname(client
, link
);
614 r
= sd_dhcp6_client_set_ifindex(client
, link
->ifindex
);
616 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set ifindex: %m");
618 if (link
->network
->dhcp6_mudurl
) {
619 r
= sd_dhcp6_client_set_request_mud_url(client
, link
->network
->dhcp6_mudurl
);
621 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
624 if (link
->network
->dhcp6_use_dns
) {
625 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVER
);
627 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request DNS servers: %m");
630 if (link
->network
->dhcp6_use_domains
> 0) {
631 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN
);
633 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request domains: %m");
636 if (link
->network
->dhcp6_use_ntp
) {
637 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
);
639 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request NTP servers: %m");
641 /* If the server does not provide NTP servers, then we fallback to use SNTP servers. */
642 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVER
);
644 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request SNTP servers: %m");
647 SET_FOREACH(request_options
, link
->network
->dhcp6_request_options
) {
648 uint32_t option
= PTR_TO_UINT32(request_options
);
650 r
= sd_dhcp6_client_set_request_option(client
, option
);
652 log_link_debug(link
, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option
);
656 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option
);
659 if (link
->network
->dhcp6_user_class
) {
660 r
= sd_dhcp6_client_set_request_user_class(client
, link
->network
->dhcp6_user_class
);
662 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set user class: %m");
665 if (link
->network
->dhcp6_vendor_class
) {
666 r
= sd_dhcp6_client_set_request_vendor_class(client
, link
->network
->dhcp6_vendor_class
);
668 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor class: %m");
671 ORDERED_HASHMAP_FOREACH(vendor_option
, link
->network
->dhcp6_client_send_vendor_options
) {
672 r
= sd_dhcp6_client_add_vendor_option(client
, vendor_option
);
676 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor option: %m");
679 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
681 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set callback: %m");
683 r
= sd_dhcp6_client_set_prefix_delegation(client
, link
->network
->dhcp6_use_pd_prefix
);
685 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting prefixes to be delegated: %m",
686 enable_disable(link
->network
->dhcp6_use_pd_prefix
));
688 /* Even if UseAddress=no, we need to request IA_NA, as the dhcp6 client may be started in solicit mode. */
689 r
= sd_dhcp6_client_set_address_request(client
, link
->network
->dhcp6_use_pd_prefix
? link
->network
->dhcp6_use_address
: true);
691 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting address: %m",
692 enable_disable(link
->network
->dhcp6_use_address
));
694 if (link
->network
->dhcp6_pd_prefix_length
> 0) {
695 r
= sd_dhcp6_client_set_prefix_delegation_hint(client
,
696 link
->network
->dhcp6_pd_prefix_length
,
697 &link
->network
->dhcp6_pd_prefix_hint
);
699 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set prefix delegation hint: %m");
702 r
= sd_dhcp6_client_set_rapid_commit(client
, link
->network
->dhcp6_use_rapid_commit
);
704 return log_link_debug_errno(link
, r
,
705 "DHCPv6 CLIENT: Failed to %s rapid commit: %m",
706 enable_disable(link
->network
->dhcp6_use_rapid_commit
));
708 link
->dhcp6_client
= TAKE_PTR(client
);
713 int dhcp6_update_mac(Link
*link
) {
719 if (!link
->dhcp6_client
)
722 restart
= sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0;
725 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
730 r
= dhcp6_set_identifier(link
, link
->dhcp6_client
);
735 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
737 return log_link_warning_errno(link
, r
, "Could not restart DHCPv6 client: %m");
743 static int dhcp6_process_request(Request
*req
, Link
*link
, void *userdata
) {
748 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
751 r
= dhcp_configure_duid(link
, link_get_dhcp6_duid(link
));
755 r
= dhcp6_configure(link
);
757 return log_link_warning_errno(link
, r
, "Failed to configure DHCPv6 client: %m");
759 r
= ndisc_start(link
);
761 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
763 r
= dhcp6_start(link
);
765 return log_link_warning_errno(link
, r
, "Failed to start DHCPv6 client: %m");
767 log_link_debug(link
, "DHCPv6 client is configured%s.",
768 r
> 0 ? ", acquiring DHCPv6 lease" : "");
772 int link_request_dhcp6_client(Link
*link
) {
777 if (!link_dhcp6_enabled(link
) && !link_ipv6_accept_ra_enabled(link
))
780 if (link
->dhcp6_client
)
783 r
= link_queue_request(link
, REQUEST_TYPE_DHCP6_CLIENT
, dhcp6_process_request
, NULL
);
785 return log_link_warning_errno(link
, r
, "Failed to request configuring of the DHCPv6 client: %m");
787 log_link_debug(link
, "Requested configuring of the DHCPv6 client.");
791 int link_serialize_dhcp6_client(Link
*link
, FILE *f
) {
792 _cleanup_free_
char *duid
= NULL
;
798 if (!link
->dhcp6_client
)
801 r
= sd_dhcp6_client_get_iaid(link
->dhcp6_client
, &iaid
);
803 fprintf(f
, "DHCP6_CLIENT_IAID=0x%x\n", iaid
);
805 r
= sd_dhcp6_client_duid_as_string(link
->dhcp6_client
, &duid
);
807 fprintf(f
, "DHCP6_CLIENT_DUID=%s\n", duid
);
812 int config_parse_dhcp6_pd_prefix_hint(
814 const char *filename
,
817 unsigned section_line
,
824 Network
*network
= userdata
;
825 union in_addr_union u
;
826 unsigned char prefixlen
;
834 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &u
, &prefixlen
);
836 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
837 "Failed to parse %s=%s, ignoring assignment.", lvalue
, rvalue
);
841 if (prefixlen
< 1 || prefixlen
> 128) {
842 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
843 "Invalid prefix length in %s=%s, ignoring assignment.", lvalue
, rvalue
);
847 network
->dhcp6_pd_prefix_hint
= u
.in6
;
848 network
->dhcp6_pd_prefix_length
= prefixlen
;
853 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp6_client_start_mode
, dhcp6_client_start_mode
, DHCP6ClientStartMode
,
854 "Failed to parse WithoutRA= setting");
856 static const char* const dhcp6_client_start_mode_table
[_DHCP6_CLIENT_START_MODE_MAX
] = {
857 [DHCP6_CLIENT_START_MODE_NO
] = "no",
858 [DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
] = "information-request",
859 [DHCP6_CLIENT_START_MODE_SOLICIT
] = "solicit",
862 DEFINE_STRING_TABLE_LOOKUP(dhcp6_client_start_mode
, DHCP6ClientStartMode
);