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
= 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
);
384 link_enter_failed(link
);
387 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
388 r
= dhcp6_lease_ip_acquired(client
, link
);
390 link_enter_failed(link
);
395 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
396 r
= dhcp6_lease_information_acquired(client
, link
);
398 link_enter_failed(link
);
403 log_link_warning_errno(link
, event
, "DHCPv6 error: %m");
405 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
410 int dhcp6_start_on_ra(Link
*link
, bool information_request
) {
414 assert(link
->dhcp6_client
);
415 assert(link
->network
);
416 assert(in6_addr_is_link_local(&link
->ipv6ll_address
));
418 if (link_get_dhcp6_client_start_mode(link
) != DHCP6_CLIENT_START_MODE_NO
)
419 /* When WithoutRA= is specified, then the DHCPv6 client should be already running in
420 * the requested mode. Hence, ignore the requests by RA. */
423 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
430 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
434 if (inf_req
== information_request
)
435 /* The client is already running in the requested mode. */
440 "The DHCPv6 client is already running in the managed mode, "
441 "refusing to start the client in the information requesting mode.");
446 "The DHCPv6 client is running in the information requesting mode. "
447 "Restarting the client in the managed mode.");
449 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
453 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
458 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, information_request
);
462 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
469 int dhcp6_start(Link
*link
) {
470 DHCP6ClientStartMode start_mode
;
474 assert(link
->network
);
476 if (!link
->dhcp6_client
)
479 if (!link_dhcp6_enabled(link
))
482 if (!link_has_carrier(link
))
485 if (sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0)
488 if (!in6_addr_is_link_local(&link
->ipv6ll_address
)) {
489 log_link_debug(link
, "IPv6 link-local address is not set, delaying to start DHCPv6 client.");
493 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
497 start_mode
= link_get_dhcp6_client_start_mode(link
);
498 if (start_mode
== DHCP6_CLIENT_START_MODE_NO
)
501 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
,
502 start_mode
== DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
);
506 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
513 static int dhcp6_set_hostname(sd_dhcp6_client
*client
, Link
*link
) {
514 _cleanup_free_
char *hostname
= NULL
;
520 if (!link
->network
->dhcp_send_hostname
)
522 else if (link
->network
->dhcp_hostname
)
523 hn
= link
->network
->dhcp_hostname
;
525 r
= gethostname_strict(&hostname
);
526 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
527 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to get hostname: %m");
532 r
= sd_dhcp6_client_set_fqdn(client
, hn
);
533 if (r
== -EINVAL
&& hostname
)
534 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
535 log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
537 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set hostname: %m");
542 static int dhcp6_set_identifier(Link
*link
, sd_dhcp6_client
*client
) {
547 assert(link
->network
);
550 r
= sd_dhcp6_client_set_mac(client
, link
->hw_addr
.bytes
, link
->hw_addr
.length
, link
->iftype
);
554 if (link
->network
->dhcp6_iaid_set
) {
555 r
= sd_dhcp6_client_set_iaid(client
, link
->network
->dhcp6_iaid
);
560 duid
= link_get_dhcp6_duid(link
);
561 if (duid
->type
== DUID_TYPE_LLT
&& duid
->raw_data_len
== 0)
562 r
= sd_dhcp6_client_set_duid_llt(client
, duid
->llt_time
);
564 r
= sd_dhcp6_client_set_duid(client
,
566 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
574 static int dhcp6_configure(Link
*link
) {
575 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
576 sd_dhcp6_option
*vendor_option
;
577 sd_dhcp6_option
*send_option
;
578 void *request_options
;
582 assert(link
->network
);
584 if (link
->dhcp6_client
)
585 return log_link_debug_errno(link
, SYNTHETIC_ERRNO(EBUSY
), "DHCPv6 client is already configured.");
587 r
= sd_dhcp6_client_new(&client
);
589 return log_oom_debug();
591 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to create DHCPv6 client: %m");
593 r
= sd_dhcp6_client_attach_event(client
, link
->manager
->event
, 0);
595 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to attach event: %m");
597 r
= dhcp6_set_identifier(link
, client
);
599 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set identifier: %m");
601 ORDERED_HASHMAP_FOREACH(send_option
, link
->network
->dhcp6_client_send_options
) {
602 r
= sd_dhcp6_client_add_option(client
, send_option
);
606 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set option: %m");
609 r
= dhcp6_set_hostname(client
, link
);
613 r
= sd_dhcp6_client_set_ifindex(client
, link
->ifindex
);
615 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set ifindex: %m");
617 if (link
->network
->dhcp6_mudurl
) {
618 r
= sd_dhcp6_client_set_request_mud_url(client
, link
->network
->dhcp6_mudurl
);
620 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
623 if (link
->network
->dhcp6_use_dns
) {
624 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVER
);
626 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request DNS servers: %m");
629 if (link
->network
->dhcp6_use_domains
> 0) {
630 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN
);
632 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request domains: %m");
635 if (link
->network
->dhcp6_use_ntp
) {
636 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
);
638 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request NTP servers: %m");
640 /* If the server does not provide NTP servers, then we fallback to use SNTP servers. */
641 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVER
);
643 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to request SNTP servers: %m");
646 SET_FOREACH(request_options
, link
->network
->dhcp6_request_options
) {
647 uint32_t option
= PTR_TO_UINT32(request_options
);
649 r
= sd_dhcp6_client_set_request_option(client
, option
);
651 log_link_debug(link
, "DHCPv6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option
);
655 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set request flag for '%u': %m", option
);
658 if (link
->network
->dhcp6_user_class
) {
659 r
= sd_dhcp6_client_set_request_user_class(client
, link
->network
->dhcp6_user_class
);
661 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set user class: %m");
664 if (link
->network
->dhcp6_vendor_class
) {
665 r
= sd_dhcp6_client_set_request_vendor_class(client
, link
->network
->dhcp6_vendor_class
);
667 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor class: %m");
670 ORDERED_HASHMAP_FOREACH(vendor_option
, link
->network
->dhcp6_client_send_vendor_options
) {
671 r
= sd_dhcp6_client_add_vendor_option(client
, vendor_option
);
675 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set vendor option: %m");
678 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
680 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set callback: %m");
682 r
= sd_dhcp6_client_set_prefix_delegation(client
, link
->network
->dhcp6_use_pd_prefix
);
684 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting prefixes to be delegated: %m",
685 enable_disable(link
->network
->dhcp6_use_pd_prefix
));
687 /* Even if UseAddress=no, we need to request IA_NA, as the dhcp6 client may be started in solicit mode. */
688 r
= sd_dhcp6_client_set_address_request(client
, link
->network
->dhcp6_use_pd_prefix
? link
->network
->dhcp6_use_address
: true);
690 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to %s requesting address: %m",
691 enable_disable(link
->network
->dhcp6_use_address
));
693 if (link
->network
->dhcp6_pd_prefix_length
> 0) {
694 r
= sd_dhcp6_client_set_prefix_delegation_hint(client
,
695 link
->network
->dhcp6_pd_prefix_length
,
696 &link
->network
->dhcp6_pd_prefix_hint
);
698 return log_link_debug_errno(link
, r
, "DHCPv6 CLIENT: Failed to set prefix delegation hint: %m");
701 r
= sd_dhcp6_client_set_rapid_commit(client
, link
->network
->dhcp6_use_rapid_commit
);
703 return log_link_debug_errno(link
, r
,
704 "DHCPv6 CLIENT: Failed to %s rapid commit: %m",
705 enable_disable(link
->network
->dhcp6_use_rapid_commit
));
707 link
->dhcp6_client
= TAKE_PTR(client
);
712 int dhcp6_update_mac(Link
*link
) {
718 if (!link
->dhcp6_client
)
721 restart
= sd_dhcp6_client_is_running(link
->dhcp6_client
) > 0;
724 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
729 r
= dhcp6_set_identifier(link
, link
->dhcp6_client
);
734 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
736 return log_link_warning_errno(link
, r
, "Could not restart DHCPv6 client: %m");
742 static int dhcp6_process_request(Request
*req
, Link
*link
, void *userdata
) {
747 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
750 r
= dhcp_configure_duid(link
, link_get_dhcp6_duid(link
));
754 r
= dhcp6_configure(link
);
756 return log_link_warning_errno(link
, r
, "Failed to configure DHCPv6 client: %m");
758 r
= ndisc_start(link
);
760 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
762 r
= dhcp6_start(link
);
764 return log_link_warning_errno(link
, r
, "Failed to start DHCPv6 client: %m");
766 log_link_debug(link
, "DHCPv6 client is configured%s.",
767 r
> 0 ? ", acquiring DHCPv6 lease" : "");
771 int link_request_dhcp6_client(Link
*link
) {
776 if (!link_dhcp6_enabled(link
) && !link_ipv6_accept_ra_enabled(link
))
779 if (link
->dhcp6_client
)
782 r
= link_queue_request(link
, REQUEST_TYPE_DHCP6_CLIENT
, dhcp6_process_request
, NULL
);
784 return log_link_warning_errno(link
, r
, "Failed to request configuring of the DHCPv6 client: %m");
786 log_link_debug(link
, "Requested configuring of the DHCPv6 client.");
790 int link_serialize_dhcp6_client(Link
*link
, FILE *f
) {
791 _cleanup_free_
char *duid
= NULL
;
797 if (!link
->dhcp6_client
)
800 r
= sd_dhcp6_client_get_iaid(link
->dhcp6_client
, &iaid
);
802 fprintf(f
, "DHCP6_CLIENT_IAID=0x%x\n", iaid
);
804 r
= sd_dhcp6_client_duid_as_string(link
->dhcp6_client
, &duid
);
806 fprintf(f
, "DHCP6_CLIENT_DUID=%s\n", duid
);
811 int config_parse_dhcp6_pd_prefix_hint(
813 const char *filename
,
816 unsigned section_line
,
823 Network
*network
= ASSERT_PTR(userdata
);
824 union in_addr_union u
;
825 unsigned char prefixlen
;
832 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &u
, &prefixlen
);
834 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
835 "Failed to parse %s=%s, ignoring assignment.", lvalue
, rvalue
);
839 if (prefixlen
< 1 || prefixlen
> 128) {
840 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
841 "Invalid prefix length in %s=%s, ignoring assignment.", lvalue
, rvalue
);
845 network
->dhcp6_pd_prefix_hint
= u
.in6
;
846 network
->dhcp6_pd_prefix_length
= prefixlen
;
851 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp6_client_start_mode
, dhcp6_client_start_mode
, DHCP6ClientStartMode
,
852 "Failed to parse WithoutRA= setting");
854 static const char* const dhcp6_client_start_mode_table
[_DHCP6_CLIENT_START_MODE_MAX
] = {
855 [DHCP6_CLIENT_START_MODE_NO
] = "no",
856 [DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST
] = "information-request",
857 [DHCP6_CLIENT_START_MODE_SOLICIT
] = "solicit",
860 DEFINE_STRING_TABLE_LOOKUP(dhcp6_client_start_mode
, DHCP6ClientStartMode
);