1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/in.h>
8 #include <linux/if_arp.h>
11 #include "sd-dhcp6-client.h"
15 #include "hostname-util.h"
16 #include "missing_network.h"
17 #include "network-internal.h"
18 #include "networkd-dhcp6.h"
19 #include "networkd-link.h"
20 #include "networkd-manager.h"
21 #include "siphash24.h"
22 #include "string-util.h"
23 #include "radv-internal.h"
26 static int dhcp6_lease_address_acquired(sd_dhcp6_client
*client
, Link
*link
);
27 static Link
*dhcp6_prefix_get(Manager
*m
, struct in6_addr
*addr
);
28 static int dhcp6_prefix_add(Manager
*m
, struct in6_addr
*addr
, Link
*link
);
29 static int dhcp6_prefix_remove_all(Manager
*m
, Link
*link
);
30 static bool dhcp6_link_has_dhcpv6_prefix(Link
*link
);
31 static int dhcp6_assign_delegated_prefix(Link
*link
, const struct in6_addr
*prefix
,
33 uint32_t lifetime_preferred
,
34 uint32_t lifetime_valid
);
36 static bool dhcp6_get_prefix_delegation(Link
*link
) {
40 return IN_SET(link
->network
->router_prefix_delegation
,
41 RADV_PREFIX_DELEGATION_DHCP6
,
42 RADV_PREFIX_DELEGATION_BOTH
);
45 static bool dhcp6_has_preferred_subnet_id(Link
*link
) {
49 return link
->network
->router_prefix_subnet_id
>= 0;
52 static int dhcp6_get_preferred_delegated_prefix(
55 const struct in6_addr
*pd_prefix
,
56 uint8_t pd_prefix_len
,
57 struct in6_addr
*ret_addr
) {
59 int64_t subnet_id
= link
->network
->router_prefix_subnet_id
;
60 uint8_t prefix_bits
= 64 - pd_prefix_len
;
61 uint64_t n_prefixes
= UINT64_C(1) << prefix_bits
;
62 _cleanup_free_
char *assigned_buf
= NULL
;
63 union in_addr_union pd_prefix_union
= {
66 /* We start off with the original PD prefix we have been assigned and
67 * iterate from there */
68 union in_addr_union prefix
= {
73 assert(pd_prefix_len
<= 64);
76 assert(link
->network
);
79 /* If the link has a preference for a particular subnet id try to allocate that */
80 if ((uint64_t)subnet_id
>= n_prefixes
)
81 return log_link_debug_errno(link
,
82 SYNTHETIC_ERRNO(ERANGE
),
83 "subnet id %" PRIi64
" is out of range. Only have %" PRIu64
" subnets.",
87 r
= in_addr_prefix_nth(AF_INET6
, &prefix
, 64, subnet_id
);
89 return log_link_debug_errno(link
,
91 "subnet id %" PRIi64
" is out of range. Only have %" PRIu64
" subnets.",
95 /* Verify that the prefix we did calculate fits in the pd prefix.
96 * This should not fail as we checked the prefix size beforehand */
97 assert_se(in_addr_prefix_covers(AF_INET6
, &pd_prefix_union
, pd_prefix_len
, &prefix
) > 0);
99 Link
* assigned_link
= dhcp6_prefix_get(manager
, &prefix
.in6
);
101 (void) in_addr_to_string(AF_INET6
, &prefix
, &assigned_buf
);
103 if (assigned_link
&& assigned_link
!= link
)
104 return log_link_error_errno(link
, SYNTHETIC_ERRNO(EAGAIN
),
105 "The requested prefix %s is already assigned to another link: %s",
106 strnull(assigned_buf
),
107 strnull(assigned_link
->ifname
));
109 *ret_addr
= prefix
.in6
;
111 log_link_debug(link
, "The requested prefix %s is available. Using it.",
112 strnull(assigned_buf
));
115 for (uint64_t n
= 0; n
< n_prefixes
; n
++) {
116 /* if we do not have an allocation preference just iterate
117 * through the address space and return the first free prefix. */
118 Link
* assigned_link
= dhcp6_prefix_get(manager
, &prefix
.in6
);
120 if (!assigned_link
|| assigned_link
== link
) {
121 *ret_addr
= prefix
.in6
;
125 r
= in_addr_prefix_next(AF_INET6
, &prefix
, 64);
127 return log_link_error_errno(link
,
129 "Can't allocate another prefix. Out of address space?");
132 log_link_warning(link
, "Couldn't find a suitable prefix. Ran out of address space.");
138 static bool dhcp6_enable_prefix_delegation(Link
*dhcp6_link
) {
145 manager
= dhcp6_link
->manager
;
148 HASHMAP_FOREACH(l
, manager
->links
, i
) {
152 if (!dhcp6_get_prefix_delegation(l
))
161 static int dhcp6_lease_information_acquired(sd_dhcp6_client
*client
,
166 static int dhcp6_pd_prefix_assign(Link
*link
, struct in6_addr
*prefix
,
168 uint32_t lifetime_preferred
,
169 uint32_t lifetime_valid
) {
170 sd_radv
*radv
= link
->radv
;
172 _cleanup_(sd_radv_prefix_unrefp
) sd_radv_prefix
*p
= NULL
;
174 r
= sd_radv_prefix_new(&p
);
178 r
= sd_radv_prefix_set_prefix(p
, prefix
, prefix_len
);
182 r
= sd_radv_prefix_set_preferred_lifetime(p
, lifetime_preferred
);
186 r
= sd_radv_prefix_set_valid_lifetime(p
, lifetime_valid
);
190 r
= sd_radv_stop(radv
);
194 r
= sd_radv_add_prefix(radv
, p
, true);
195 if (r
< 0 && r
!= -EEXIST
)
198 r
= dhcp6_prefix_add(link
->manager
, prefix
, link
);
202 if (link
->network
->dhcp6_pd_assign_prefix
) {
203 r
= dhcp6_assign_delegated_prefix(link
, prefix
, prefix_len
, lifetime_preferred
, lifetime_valid
);
208 return sd_radv_start(radv
);
211 static int dhcp6_route_remove_handler(sd_netlink
*nl
, sd_netlink_message
*m
, Link
*link
) {
216 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
219 r
= sd_netlink_message_get_errno(m
);
221 log_link_message_warning_errno(link
, m
, r
, "Received error on unreachable route removal for DHCPv6 delegated subnet");
226 int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client
*client
, Link
* link
) {
227 uint32_t lifetime_preferred
, lifetime_valid
;
228 union in_addr_union pd_prefix
;
229 uint8_t pd_prefix_len
;
230 sd_dhcp6_lease
*lease
;
233 r
= sd_dhcp6_client_get_lease(client
, &lease
);
237 sd_dhcp6_lease_reset_pd_prefix_iter(lease
);
239 while (sd_dhcp6_lease_get_pd(lease
, &pd_prefix
.in6
, &pd_prefix_len
,
241 &lifetime_valid
) >= 0) {
242 _cleanup_free_
char *buf
= NULL
;
243 _cleanup_(route_freep
) Route
*route
= NULL
;
245 if (pd_prefix_len
>= 64)
248 (void) in_addr_to_string(AF_INET6
, &pd_prefix
, &buf
);
250 r
= route_new(&route
);
254 route
->family
= AF_INET6
;
255 route
->dst
= pd_prefix
;
256 route
->dst_prefixlen
= pd_prefix_len
;
257 route
->type
= RTN_UNREACHABLE
;
259 r
= route_remove(route
, link
, dhcp6_route_remove_handler
);
261 log_link_warning_errno(link
, r
, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
267 log_link_debug(link
, "Removing unreachable route %s/%u",
268 strnull(buf
), pd_prefix_len
);
274 static int dhcp6_pd_prefix_distribute(Link
*dhcp6_link
,
275 struct in6_addr
*pd_prefix
,
276 uint8_t pd_prefix_len
,
277 uint32_t lifetime_preferred
,
278 uint32_t lifetime_valid
,
279 bool assign_preferred_subnet_id
) {
281 _cleanup_free_
char *assigned_buf
= NULL
, *buf
= NULL
;
282 Manager
*manager
= dhcp6_link
->manager
;
283 union in_addr_union prefix
= {
286 bool pool_depleted
= false;
293 assert(pd_prefix_len
<= 64);
295 r
= in_addr_mask(AF_INET6
, &prefix
, pd_prefix_len
);
299 n_prefixes
= UINT64_C(1) << (64 - pd_prefix_len
);
301 (void) in_addr_to_string(AF_INET6
, &prefix
, &buf
);
302 log_link_debug(dhcp6_link
, "Assigning up to %" PRIu64
" prefixes from %s/%u",
303 n_prefixes
, strnull(buf
), pd_prefix_len
);
305 HASHMAP_FOREACH(link
, manager
->links
, i
) {
306 union in_addr_union assigned_prefix
;
308 if (link
== dhcp6_link
)
311 if (!dhcp6_get_prefix_delegation(link
))
314 if (dhcp6_link_has_dhcpv6_prefix(link
))
317 if (assign_preferred_subnet_id
!= dhcp6_has_preferred_subnet_id(link
))
320 r
= dhcp6_get_preferred_delegated_prefix(manager
, link
, &prefix
.in6
, pd_prefix_len
,
321 &assigned_prefix
.in6
);
323 if (assign_preferred_subnet_id
&& r
== -EAGAIN
) {
324 /* A link has a preferred subnet_id but that one is
325 * already taken by another link. Now all the remaining
326 * links will also not obtain a prefix. */
327 pool_depleted
= true;
332 (void) in_addr_to_string(AF_INET6
, &assigned_prefix
, &assigned_buf
);
333 r
= dhcp6_pd_prefix_assign(link
, &assigned_prefix
.in6
, 64,
334 lifetime_preferred
, lifetime_valid
);
336 log_link_error_errno(link
, r
, "Unable to assign/update prefix %s/64 from %s/%u for link: %m",
337 strnull(assigned_buf
),
338 strnull(buf
), pd_prefix_len
);
340 log_link_debug(link
, "Assigned prefix %s/64 from %s/%u to link",
341 strnull(assigned_buf
),
342 strnull(buf
), pd_prefix_len
);
345 /* If one of the link requests couldn't be fulfilled, signal that we
346 should try again with another prefix. */
353 static int dhcp6_route_handler(sd_netlink
*nl
, sd_netlink_message
*m
, Link
*link
) {
358 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
361 r
= sd_netlink_message_get_errno(m
);
362 if (r
< 0 && r
!= -EEXIST
)
363 log_link_message_warning_errno(link
, m
, r
, "Received error when adding unreachable route for DHCPv6 delegated subnet");
368 static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client
*client
, Link
*link
) {
369 uint32_t lifetime_preferred
, lifetime_valid
;
370 union in_addr_union pd_prefix
;
371 sd_dhcp6_lease
*lease
;
372 uint8_t pd_prefix_len
;
375 r
= sd_dhcp6_client_get_lease(client
, &lease
);
379 sd_dhcp6_lease_reset_pd_prefix_iter(lease
);
381 while (sd_dhcp6_lease_get_pd(lease
, &pd_prefix
.in6
, &pd_prefix_len
,
383 &lifetime_valid
) >= 0) {
385 _cleanup_free_
char *buf
= NULL
;
387 (void) in_addr_to_string(AF_INET6
, &pd_prefix
, &buf
);
389 if (pd_prefix_len
> 64) {
390 log_link_debug(link
, "PD Prefix length > 64, ignoring prefix %s/%u",
391 strnull(buf
), pd_prefix_len
);
395 if (pd_prefix_len
< 48)
396 log_link_warning(link
, "PD Prefix length < 48, looks unusual %s/%u",
397 strnull(buf
), pd_prefix_len
);
399 if (pd_prefix_len
< 64) {
400 _cleanup_(route_freep
) Route
*route
= NULL
;
402 r
= route_new(&route
);
406 route
->family
= AF_INET6
;
407 route
->dst
= pd_prefix
;
408 route
->dst_prefixlen
= pd_prefix_len
;
409 route
->table
= link_get_dhcp_route_table(link
);
410 route
->type
= RTN_UNREACHABLE
;
412 r
= route_configure(route
, link
, dhcp6_route_handler
);
414 log_link_warning_errno(link
, r
, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
420 log_link_debug(link
, "Configuring unreachable route for %s/%u",
421 strnull(buf
), pd_prefix_len
);
423 log_link_debug(link
, "Not adding a blocking route since distributed prefix is /64");
425 /* We are doing prefix allocation in two steps:
426 * 1. all those links that have a preferred subnet id will be assigned their subnet
427 * 2. all those links that remain will receive prefixes in sequential
428 * order. Prefixes that were previously already allocated to another
429 * link will be skipped.
431 * If a subnet id request couldn't be fulfilled the failure will be logged (as error)
432 * and no further attempts at obtaining a prefix will be made.
434 * The assignment has to be split in two phases since subnet id
435 * preferences should be honored. Meaning that any subnet id should be
436 * handed out to the requesting link and not to some link that didn't
437 * specify any preference. */
439 r
= dhcp6_pd_prefix_distribute(link
, &pd_prefix
.in6
,
444 if (r
< 0 && r
!= -EAGAIN
)
447 /* if r == -EAGAIN then the allocation failed because we ran
448 * out of addresses for the preferred subnet id's. This doesn't
449 * mean we can't fulfill other prefix requests.
451 * Since we do not have dedicated lists of links that request
452 * specific subnet id's and those that accept any prefix we
453 * *must* reset the iterator to the start as otherwise some
454 * links might not get their requested prefix. */
456 r
= dhcp6_pd_prefix_distribute(link
, &pd_prefix
.in6
,
461 if (r
< 0 && r
!= -EAGAIN
)
464 /* If the prefix distribution did return -EAGAIN we will try to
465 * fulfill those with the next available pd delegated prefix. */
471 int dhcp6_request_prefix_delegation(Link
*link
) {
475 assert_return(link
, -EINVAL
);
476 assert_return(link
->manager
, -EOPNOTSUPP
);
478 if (dhcp6_get_prefix_delegation(link
) <= 0)
481 log_link_debug(link
, "Requesting DHCPv6 prefixes to be delegated for new link");
483 HASHMAP_FOREACH(l
, link
->manager
->links
, i
) {
489 if (!l
->dhcp6_client
)
492 r
= sd_dhcp6_client_get_prefix_delegation(l
->dhcp6_client
, &enabled
);
494 log_link_warning_errno(l
, r
, "Cannot get prefix delegation when adding new link");
499 r
= sd_dhcp6_client_set_prefix_delegation(l
->dhcp6_client
, 1);
501 log_link_warning_errno(l
, r
, "Cannot enable prefix delegation when adding new link");
506 r
= sd_dhcp6_client_is_running(l
->dhcp6_client
);
511 log_link_debug(l
, "Requesting re-assignment of delegated prefixes after adding new link");
512 (void) dhcp6_lease_pd_prefix_acquired(l
->dhcp6_client
, l
);
517 r
= sd_dhcp6_client_stop(l
->dhcp6_client
);
519 log_link_warning_errno(l
, r
, "Cannot stop DHCPv6 prefix delegation client after adding new link");
523 r
= sd_dhcp6_client_start(l
->dhcp6_client
);
525 log_link_warning_errno(l
, r
, "Cannot restart DHCPv6 prefix delegation client after adding new link");
529 log_link_debug(l
, "Restarted DHCPv6 client to acquire prefix delegations after adding new link");
535 static int dhcp6_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
540 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
543 r
= sd_netlink_message_get_errno(m
);
544 if (r
< 0 && r
!= -EEXIST
) {
545 log_link_message_warning_errno(link
, m
, r
, "Could not set DHCPv6 address");
546 link_enter_failed(link
);
549 (void) manager_rtnl_process_address(rtnl
, m
, link
->manager
);
551 r
= link_request_set_routes(link
);
553 link_enter_failed(link
);
560 static int dhcp6_address_change(
562 struct in6_addr
*ip6_addr
,
563 uint32_t lifetime_preferred
,
564 uint32_t lifetime_valid
) {
566 _cleanup_(address_freep
) Address
*addr
= NULL
;
567 _cleanup_free_
char *buffer
= NULL
;
570 r
= address_new(&addr
);
574 addr
->family
= AF_INET6
;
575 addr
->in_addr
.in6
= *ip6_addr
;
576 addr
->flags
= IFA_F_NOPREFIXROUTE
;
577 addr
->prefixlen
= 128;
578 addr
->cinfo
.ifa_prefered
= lifetime_preferred
;
579 addr
->cinfo
.ifa_valid
= lifetime_valid
;
581 (void) in_addr_to_string(addr
->family
, &addr
->in_addr
, &buffer
);
583 "DHCPv6 address %s/%d timeout preferred %d valid %d",
584 strnull(buffer
), addr
->prefixlen
, lifetime_preferred
, lifetime_valid
);
586 r
= address_configure(addr
, link
, dhcp6_address_handler
, true);
588 return log_link_warning_errno(link
, r
, "Could not assign DHCPv6 address: %m");
593 static int dhcp6_lease_address_acquired(sd_dhcp6_client
*client
, Link
*link
) {
595 sd_dhcp6_lease
*lease
;
596 struct in6_addr ip6_addr
;
597 uint32_t lifetime_preferred
, lifetime_valid
;
599 r
= sd_dhcp6_client_get_lease(client
, &lease
);
603 sd_dhcp6_lease_reset_address_iter(lease
);
605 while (sd_dhcp6_lease_get_address(lease
, &ip6_addr
,
607 &lifetime_valid
) >= 0) {
609 r
= dhcp6_address_change(link
, &ip6_addr
, lifetime_preferred
, lifetime_valid
);
617 static void dhcp6_handler(sd_dhcp6_client
*client
, int event
, void *userdata
) {
619 Link
*link
= userdata
;
622 assert(link
->network
);
624 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
628 case SD_DHCP6_CLIENT_EVENT_STOP
:
629 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
:
630 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
:
631 if (sd_dhcp6_client_get_lease(client
, NULL
) >= 0)
632 log_link_warning(link
, "DHCPv6 lease lost");
634 (void) dhcp6_lease_pd_prefix_lost(client
, link
);
635 (void) dhcp6_prefix_remove_all(link
->manager
, link
);
638 link
->dhcp6_configured
= false;
641 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
642 r
= dhcp6_lease_address_acquired(client
, link
);
644 link_enter_failed(link
);
648 r
= dhcp6_lease_pd_prefix_acquired(client
, link
);
650 log_link_debug(link
, "DHCPv6 did not receive prefixes to delegate");
653 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
654 r
= dhcp6_lease_information_acquired(client
, link
);
656 link_enter_failed(link
);
661 link
->dhcp6_configured
= true;
666 log_link_warning_errno(link
, event
, "DHCPv6 error: %m");
668 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
672 link_check_ready(link
);
675 int dhcp6_request_address(Link
*link
, int ir
) {
680 assert(link
->dhcp6_client
);
681 assert(link
->network
);
682 assert(in_addr_is_link_local(AF_INET6
, (const union in_addr_union
*)&link
->ipv6ll_address
) > 0);
684 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
689 r
= sd_dhcp6_client_get_prefix_delegation(link
->dhcp6_client
, &pd
);
693 if (pd
&& ir
&& link
->network
->dhcp6_force_pd_other_information
) {
694 log_link_debug(link
, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set");
696 r
= sd_dhcp6_client_set_address_request(link
->dhcp6_client
,
705 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
712 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
716 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
721 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, ir
);
725 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
732 static int dhcp6_set_hostname(sd_dhcp6_client
*client
, Link
*link
) {
733 _cleanup_free_
char *hostname
= NULL
;
739 if (!link
->network
->dhcp_send_hostname
)
741 else if (link
->network
->dhcp_hostname
)
742 hn
= link
->network
->dhcp_hostname
;
744 r
= gethostname_strict(&hostname
);
745 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
751 r
= sd_dhcp6_client_set_fqdn(client
, hn
);
752 if (r
== -EINVAL
&& hostname
)
753 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
754 log_link_warning_errno(link
, r
, "DHCP6 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
756 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set hostname: %m");
761 int dhcp6_configure(Link
*link
) {
762 _cleanup_(sd_dhcp6_client_unrefp
) sd_dhcp6_client
*client
= NULL
;
763 sd_dhcp6_option
*vendor_option
;
764 sd_dhcp6_option
*send_option
;
765 void *request_options
;
771 assert(link
->network
);
773 if (link
->dhcp6_client
)
776 r
= sd_dhcp6_client_new(&client
);
780 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to create DHCP6 client: %m");
782 r
= sd_dhcp6_client_attach_event(client
, NULL
, 0);
784 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to attach event: %m");
786 r
= sd_dhcp6_client_set_mac(client
,
787 (const uint8_t *) &link
->mac
,
788 sizeof (link
->mac
), ARPHRD_ETHER
);
790 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set MAC address: %m");
792 if (link
->network
->iaid_set
) {
793 r
= sd_dhcp6_client_set_iaid(client
, link
->network
->iaid
);
795 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set IAID: %m");
798 duid
= link_get_duid(link
);
799 if (duid
->type
== DUID_TYPE_LLT
&& duid
->raw_data_len
== 0)
800 r
= sd_dhcp6_client_set_duid_llt(client
, duid
->llt_time
);
802 r
= sd_dhcp6_client_set_duid(client
,
804 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
807 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set DUID: %m");
809 ORDERED_HASHMAP_FOREACH(send_option
, link
->network
->dhcp6_client_send_options
, i
) {
810 r
= sd_dhcp6_client_add_option(client
, send_option
);
814 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set option: %m");
817 r
= dhcp6_set_hostname(client
, link
);
821 r
= sd_dhcp6_client_set_ifindex(client
, link
->ifindex
);
823 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set ifindex: %m");
825 if (link
->network
->rapid_commit
) {
826 r
= sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_RAPID_COMMIT
);
828 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set request flag for rapid commit: %m");
831 if (link
->network
->dhcp6_mudurl
) {
832 r
= sd_dhcp6_client_set_request_mud_url(client
, link
->network
->dhcp6_mudurl
);
834 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set MUD URL: %m");
837 SET_FOREACH(request_options
, link
->network
->dhcp6_request_options
, i
) {
838 uint32_t option
= PTR_TO_UINT32(request_options
);
840 r
= sd_dhcp6_client_set_request_option(client
, option
);
842 log_link_debug(link
, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option
);
847 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option
);
850 if (link
->network
->dhcp6_user_class
) {
851 r
= sd_dhcp6_client_set_request_user_class(client
, link
->network
->dhcp6_user_class
);
853 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set user class: %m");
856 if (link
->network
->dhcp6_vendor_class
) {
857 r
= sd_dhcp6_client_set_request_vendor_class(client
, link
->network
->dhcp6_vendor_class
);
859 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set vendor class: %m");
862 ORDERED_HASHMAP_FOREACH(vendor_option
, link
->network
->dhcp6_client_send_vendor_options
, i
) {
863 r
= sd_dhcp6_client_add_vendor_option(client
, vendor_option
);
867 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set vendor option: %m");
870 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
872 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set callback: %m");
874 if (dhcp6_enable_prefix_delegation(link
)) {
875 r
= sd_dhcp6_client_set_prefix_delegation(client
, true);
877 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set prefix delegation: %m");
880 if (link
->network
->dhcp6_pd_length
> 0) {
881 r
= sd_dhcp6_client_set_prefix_delegation_hint(client
, link
->network
->dhcp6_pd_length
, &link
->network
->dhcp6_pd_address
);
883 return log_link_error_errno(link
, r
, "DHCP6 CLIENT: Failed to set prefix hint: %m");
886 link
->dhcp6_client
= TAKE_PTR(client
);
891 static Link
*dhcp6_prefix_get(Manager
*m
, struct in6_addr
*addr
) {
892 assert_return(m
, NULL
);
893 assert_return(addr
, NULL
);
895 return hashmap_get(m
->dhcp6_prefixes
, addr
);
898 static int dhcp6_route_add_handler(sd_netlink
*nl
, sd_netlink_message
*m
, Link
*link
) {
903 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
906 r
= sd_netlink_message_get_errno(m
);
907 if (r
< 0 && r
!= -EEXIST
) {
908 log_link_message_warning_errno(link
, m
, r
, "Received error adding DHCPv6 Prefix Delegation route");
909 link_enter_failed(link
);
916 static int dhcp6_prefix_add(Manager
*m
, struct in6_addr
*addr
, Link
*link
) {
917 _cleanup_(route_freep
) Route
*route
= NULL
;
918 _cleanup_free_
struct in6_addr
*a
= NULL
;
919 _cleanup_free_
char *buf
= NULL
;
923 assert_return(m
, -EINVAL
);
924 assert_return(addr
, -EINVAL
);
926 r
= route_new(&route
);
930 route
->family
= AF_INET6
;
931 route
->dst
.in6
= *addr
;
932 route
->dst_prefixlen
= 64;
934 r
= route_configure(route
, link
, dhcp6_route_add_handler
);
938 (void) in_addr_to_string(AF_INET6
, (union in_addr_union
*) addr
, &buf
);
939 log_link_debug(link
, "Adding prefix route %s/64", strnull(buf
));
941 assigned_link
= hashmap_get(m
->dhcp6_prefixes
, addr
);
943 assert(assigned_link
== link
);
947 a
= newdup(struct in6_addr
, addr
, 1);
951 r
= hashmap_ensure_allocated(&m
->dhcp6_prefixes
, &in6_addr_hash_ops
);
955 r
= hashmap_put(m
->dhcp6_prefixes
, a
, link
);
964 static int dhcp6_prefix_remove_handler(sd_netlink
*nl
, sd_netlink_message
*m
, Link
*link
) {
969 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
972 r
= sd_netlink_message_get_errno(m
);
974 log_link_message_warning_errno(link
, m
, r
, "Received error on DHCPv6 Prefix Delegation route removal");
975 link_enter_failed(link
);
982 int dhcp6_prefix_remove(Manager
*m
, struct in6_addr
*addr
) {
983 _cleanup_free_
struct in6_addr
*a
= NULL
;
984 _cleanup_(link_unrefp
) Link
*l
= NULL
;
985 _cleanup_(route_freep
) Route
*route
= NULL
;
986 _cleanup_free_
char *buf
= NULL
;
989 assert_return(m
, -EINVAL
);
990 assert_return(addr
, -EINVAL
);
992 l
= hashmap_remove2(m
->dhcp6_prefixes
, addr
, (void **) &a
);
996 (void) sd_radv_remove_prefix(l
->radv
, addr
, 64);
998 r
= route_new(&route
);
1002 route
->family
= AF_INET6
;
1003 route
->dst
.in6
= *addr
;
1004 route
->dst_prefixlen
= 64;
1006 r
= route_remove(route
, l
, dhcp6_prefix_remove_handler
);
1010 (void) in_addr_to_string(AF_INET6
, (union in_addr_union
*) addr
, &buf
);
1011 log_link_debug(l
, "Removing prefix route %s/64", strnull(buf
));
1016 static int dhcp6_prefix_remove_all(Manager
*m
, Link
*link
) {
1017 struct in6_addr
*addr
;
1021 assert_return(m
, -EINVAL
);
1022 assert_return(link
, -EINVAL
);
1024 HASHMAP_FOREACH_KEY(l
, addr
, m
->dhcp6_prefixes
, i
)
1026 (void) dhcp6_prefix_remove(m
, addr
);
1031 static bool dhcp6_link_has_dhcpv6_prefix(Link
*link
) {
1036 assert(link
->manager
);
1038 HASHMAP_FOREACH(l
, link
->manager
->dhcp6_prefixes
, i
)
1045 static int dhcp6_assign_delegated_prefix(Link
*link
,
1046 const struct in6_addr
*prefix
,
1048 uint32_t lifetime_preferred
,
1049 uint32_t lifetime_valid
) {
1051 _cleanup_(address_freep
) Address
*address
= NULL
;
1055 assert(link
->network
);
1058 if (!link
->network
->dhcp6_pd_assign_prefix
)
1061 r
= address_new(&address
);
1063 return log_link_error_errno(link
, r
, "Failed to allocate address for DHCPv6 delegated prefix: %m");
1065 address
->in_addr
.in6
= *prefix
;
1067 if (!in_addr_is_null(AF_INET6
, &link
->network
->dhcp6_delegation_prefix_token
))
1068 memcpy(&address
->in_addr
.in6
.s6_addr
+ 8, &link
->network
->dhcp6_delegation_prefix_token
.in6
.s6_addr
+ 8, 8);
1070 r
= generate_ipv6_eui_64_address(link
, &address
->in_addr
.in6
);
1072 return log_link_warning_errno(link
, r
, "Failed to generate EUI64 address for acquired DHCPv6 delegated prefix: %m");
1075 address
->prefixlen
= prefix_len
;
1076 address
->family
= AF_INET6
;
1077 address
->cinfo
.ifa_prefered
= lifetime_preferred
;
1078 address
->cinfo
.ifa_valid
= lifetime_valid
;
1080 link_set_state(link
, LINK_STATE_CONFIGURING
);
1082 r
= address_configure(address
, link
, address_handler
, true);
1084 return log_link_warning_errno(link
, r
, "Failed to set acquired DHCPv6 delegated prefix address: %m");
1086 link
->address_messages
++;
1091 int config_parse_dhcp6_pd_hint(
1093 const char *filename
,
1095 const char *section
,
1096 unsigned section_line
,
1103 Network
*network
= data
;
1111 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, (union in_addr_union
*) &network
->dhcp6_pd_address
, &network
->dhcp6_pd_length
);
1113 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue
);
1117 if (network
->dhcp6_pd_length
< 1 || network
->dhcp6_pd_length
> 128) {
1118 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid prefix length='%d', ignoring assignment", network
->dhcp6_pd_length
);
1119 network
->dhcp6_pd_length
= 0;
1126 int config_parse_dhcp6_mud_url(
1128 const char *filename
,
1130 const char *section
,
1131 unsigned section_line
,
1138 _cleanup_free_
char *unescaped
= NULL
;
1139 Network
*network
= data
;
1146 if (isempty(rvalue
)) {
1147 network
->dhcp6_mudurl
= mfree(network
->dhcp6_mudurl
);
1151 r
= cunescape(rvalue
, 0, &unescaped
);
1153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1154 "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue
);
1158 if (!http_url_is_valid(unescaped
) || strlen(unescaped
) > UINT8_MAX
) {
1159 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
1160 "Failed to parse MUD URL '%s', ignoring: %m", rvalue
);
1165 return free_and_replace(network
->dhcp6_mudurl
, unescaped
);
1168 int config_parse_dhcp6_delegated_prefix_token(
1170 const char *filename
,
1172 const char *section
,
1173 unsigned section_line
,
1180 Network
*network
= data
;
1188 if (isempty(rvalue
)) {
1189 network
->dhcp6_delegation_prefix_token
= IN_ADDR_NULL
;
1193 r
= in_addr_from_string(AF_INET6
, rvalue
, &network
->dhcp6_delegation_prefix_token
);
1195 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1196 "Failed to parse DHCPv6 %s, ignoring: %s", lvalue
, rvalue
);
1200 if (in_addr_is_null(AF_INET6
, &network
->dhcp6_delegation_prefix_token
)) {
1201 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
1202 "DHCPv6 %s cannot be the ANY address, ignoring: %s", lvalue
, rvalue
);