1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <linux/ipv6_route.h>
4 
5 #include "sd-dhcp6-client.h"
6 
7 #include "hashmap.h"
8 #include "in-addr-prefix-util.h"
9 #include "networkd-address-generation.h"
10 #include "networkd-address.h"
11 #include "networkd-dhcp-prefix-delegation.h"
12 #include "networkd-dhcp6.h"
13 #include "networkd-link.h"
14 #include "networkd-manager.h"
15 #include "networkd-queue.h"
16 #include "networkd-radv.h"
17 #include "networkd-route.h"
18 #include "networkd-setlink.h"
19 #include "parse-util.h"
20 #include "string-util.h"
21 #include "strv.h"
22 #include "tunnel.h"
23 
link_dhcp_pd_is_enabled(Link * link)24 bool link_dhcp_pd_is_enabled(Link *link) {
25         assert(link);
26 
27         if (!link->network)
28                 return false;
29 
30         return link->network->dhcp_pd;
31 }
32 
dhcp_pd_is_uplink(Link * link,Link * target,bool accept_auto)33 bool dhcp_pd_is_uplink(Link *link, Link *target, bool accept_auto) {
34         assert(link);
35         assert(target);
36 
37         if (!link_dhcp_pd_is_enabled(link))
38                 return false;
39 
40         if (link->network->dhcp_pd_uplink_name)
41                 return streq_ptr(target->ifname, link->network->dhcp_pd_uplink_name) ||
42                         strv_contains(target->alternative_names, link->network->dhcp_pd_uplink_name);
43 
44         if (link->network->dhcp_pd_uplink_index > 0)
45                 return target->ifindex == link->network->dhcp_pd_uplink_index;
46 
47         if (link->network->dhcp_pd_uplink_index == UPLINK_INDEX_SELF)
48                 return link == target;
49 
50         assert(link->network->dhcp_pd_uplink_index == UPLINK_INDEX_AUTO);
51         return accept_auto;
52 }
53 
dhcp4_lease_has_pd_prefix(sd_dhcp_lease * lease)54 bool dhcp4_lease_has_pd_prefix(sd_dhcp_lease *lease) {
55         if (!lease)
56                 return false;
57 
58         return sd_dhcp_lease_get_6rd(lease, NULL, NULL, NULL, NULL, NULL) >= 0;
59 }
60 
dhcp6_lease_has_pd_prefix(sd_dhcp6_lease * lease)61 bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
62         uint32_t lifetime_preferred_sec, lifetime_valid_sec;
63         struct in6_addr pd_prefix;
64         uint8_t pd_prefix_len;
65 
66         if (!lease)
67                 return false;
68 
69         sd_dhcp6_lease_reset_pd_prefix_iter(lease);
70 
71         return sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len, &lifetime_preferred_sec, &lifetime_valid_sec) >= 0;
72 }
73 
link_remove_dhcp_pd_subnet_prefix(Link * link,const struct in6_addr * prefix)74 static void link_remove_dhcp_pd_subnet_prefix(Link *link, const struct in6_addr *prefix) {
75         void *key;
76 
77         assert(link);
78         assert(link->manager);
79         assert(prefix);
80 
81         if (hashmap_get(link->manager->links_by_dhcp_pd_subnet_prefix, prefix) != link)
82                 return;
83 
84         hashmap_remove2(link->manager->links_by_dhcp_pd_subnet_prefix, prefix, &key);
85         free(key);
86 }
87 
link_add_dhcp_pd_subnet_prefix(Link * link,const struct in6_addr * prefix)88 static int link_add_dhcp_pd_subnet_prefix(Link *link, const struct in6_addr *prefix) {
89         _cleanup_free_ struct in6_addr *copy = NULL;
90         int r;
91 
92         assert(link);
93         assert(prefix);
94 
95         copy = newdup(struct in6_addr, prefix, 1);
96         if (!copy)
97                 return -ENOMEM;
98 
99         r = hashmap_ensure_put(&link->manager->links_by_dhcp_pd_subnet_prefix, &in6_addr_hash_ops_free, copy, link);
100         if (r < 0)
101                 return r;
102         if (r > 0)
103                 TAKE_PTR(copy);
104 
105         return 0;
106 }
107 
link_get_by_dhcp_pd_subnet_prefix(Manager * manager,const struct in6_addr * prefix,Link ** ret)108 static int link_get_by_dhcp_pd_subnet_prefix(Manager *manager, const struct in6_addr *prefix, Link **ret) {
109         Link *link;
110 
111         assert(manager);
112         assert(prefix);
113 
114         link = hashmap_get(manager->links_by_dhcp_pd_subnet_prefix, prefix);
115         if (!link)
116                 return -ENODEV;
117 
118         if (ret)
119                 *ret = link;
120         return 0;
121 }
122 
dhcp_pd_get_assigned_subnet_prefix(Link * link,const struct in6_addr * pd_prefix,uint8_t pd_prefix_len,struct in6_addr * ret)123 static int dhcp_pd_get_assigned_subnet_prefix(Link *link, const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret) {
124         assert(link);
125         assert(pd_prefix);
126 
127         if (!link_dhcp_pd_is_enabled(link))
128                 return -ENOENT;
129 
130         if (link->network->dhcp_pd_assign) {
131                 Address *address;
132 
133                 SET_FOREACH(address, link->addresses) {
134                         if (address->source != NETWORK_CONFIG_SOURCE_DHCP_PD)
135                                 continue;
136                         assert(address->family == AF_INET6);
137 
138                         if (in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &address->in_addr.in6) <= 0)
139                                 continue;
140 
141                         if (ret) {
142                                 struct in6_addr prefix = address->in_addr.in6;
143 
144                                 in6_addr_mask(&prefix, 64);
145                                 *ret = prefix;
146                         }
147                         return 0;
148                 }
149         } else {
150                 Route *route;
151 
152                 SET_FOREACH(route, link->routes) {
153                         if (route->source != NETWORK_CONFIG_SOURCE_DHCP_PD)
154                                 continue;
155                         assert(route->family == AF_INET6);
156 
157                         if (in6_addr_prefix_covers(pd_prefix, pd_prefix_len, &route->dst.in6) > 0) {
158                                 if (ret)
159                                         *ret = route->dst.in6;
160                                 return 0;
161                         }
162                 }
163         }
164 
165         return -ENOENT;
166 }
167 
dhcp_pd_remove(Link * link,bool only_marked)168 int dhcp_pd_remove(Link *link, bool only_marked) {
169         int k, r = 0;
170 
171         assert(link);
172         assert(link->manager);
173 
174         if (!link_dhcp_pd_is_enabled(link))
175                 return 0;
176 
177         if (!only_marked)
178                 link->dhcp_pd_configured = false;
179 
180         if (!link->network->dhcp_pd_assign) {
181                 Route *route;
182 
183                 SET_FOREACH(route, link->routes) {
184                         if (route->source != NETWORK_CONFIG_SOURCE_DHCP_PD)
185                                 continue;
186                         if (only_marked && !route_is_marked(route))
187                                 continue;
188 
189                         if (link->radv)
190                                 sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
191 
192                         link_remove_dhcp_pd_subnet_prefix(link, &route->dst.in6);
193 
194                         k = route_remove(route);
195                         if (k < 0)
196                                 r = k;
197 
198                         route_cancel_request(route, link);
199                 }
200         } else {
201                 Address *address;
202 
203                 SET_FOREACH(address, link->addresses) {
204                         struct in6_addr prefix;
205 
206                         if (address->source != NETWORK_CONFIG_SOURCE_DHCP_PD)
207                                 continue;
208                         if (only_marked && !address_is_marked(address))
209                                 continue;
210 
211                         prefix = address->in_addr.in6;
212                         in6_addr_mask(&prefix, 64);
213 
214                         if (link->radv)
215                                 sd_radv_remove_prefix(link->radv, &prefix, 64);
216 
217                         link_remove_dhcp_pd_subnet_prefix(link, &prefix);
218 
219                         k = address_remove(address);
220                         if (k < 0)
221                                 r = k;
222 
223                         address_cancel_request(address);
224                 }
225         }
226 
227         return r;
228 }
229 
230 static int dhcp_pd_check_ready(Link *link);
231 
dhcp_pd_address_ready_callback(Address * address)232 static int dhcp_pd_address_ready_callback(Address *address) {
233         Address *a;
234 
235         assert(address);
236         assert(address->link);
237 
238         SET_FOREACH(a, address->link->addresses)
239                 if (a->source == NETWORK_CONFIG_SOURCE_DHCP_PD)
240                         a->callback = NULL;
241 
242         return dhcp_pd_check_ready(address->link);
243 }
244 
dhcp_pd_check_ready(Link * link)245 static int dhcp_pd_check_ready(Link *link) {
246         int r;
247 
248         assert(link);
249         assert(link->network);
250 
251         if (link->dhcp_pd_messages > 0) {
252                 log_link_debug(link, "%s(): DHCP-PD addresses and routes are not set.", __func__);
253                 return 0;
254         }
255 
256         if (link->network->dhcp_pd_assign) {
257                 bool has_ready = false;
258                 Address *address;
259 
260                 SET_FOREACH(address, link->addresses) {
261                         if (address->source != NETWORK_CONFIG_SOURCE_DHCP_PD)
262                                 continue;
263                         if (address_is_ready(address)) {
264                                 has_ready = true;
265                                 break;
266                         }
267                 }
268 
269                 if (!has_ready) {
270                         SET_FOREACH(address, link->addresses)
271                                 if (address->source == NETWORK_CONFIG_SOURCE_DHCP_PD)
272                                         address->callback = dhcp_pd_address_ready_callback;
273 
274                         log_link_debug(link, "%s(): no DHCP-PD address is ready.", __func__);
275                         return 0;
276                 }
277         }
278 
279         link->dhcp_pd_configured = true;
280 
281         log_link_debug(link, "DHCP-PD addresses and routes set.");
282 
283         r = dhcp_pd_remove(link, /* only_marked = */ true);
284         if (r < 0)
285                 return r;
286 
287         link_check_ready(link);
288         return 1;
289 }
290 
dhcp_pd_route_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Route * route)291 static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
292         int r;
293 
294         assert(link);
295 
296         r = route_configure_handler_internal(rtnl, m, link, "Failed to add prefix route for DHCP delegated subnet prefix");
297         if (r <= 0)
298                 return r;
299 
300         r = dhcp_pd_check_ready(link);
301         if (r < 0)
302                 link_enter_failed(link);
303 
304         return 1;
305 }
306 
dhcp_pd_request_route(Link * link,const struct in6_addr * prefix,usec_t lifetime_usec)307 static int dhcp_pd_request_route(Link *link, const struct in6_addr *prefix, usec_t lifetime_usec) {
308         _cleanup_(route_freep) Route *route = NULL;
309         Route *existing;
310         int r;
311 
312         assert(link);
313         assert(link->network);
314         assert(prefix);
315 
316         if (link->network->dhcp_pd_assign)
317                 return 0;
318 
319         r = route_new(&route);
320         if (r < 0)
321                 return r;
322 
323         route->source = NETWORK_CONFIG_SOURCE_DHCP_PD;
324         route->family = AF_INET6;
325         route->dst.in6 = *prefix;
326         route->dst_prefixlen = 64;
327         route->protocol = RTPROT_DHCP;
328         route->priority = link->network->dhcp_pd_route_metric;
329         route->lifetime_usec = lifetime_usec;
330 
331         if (route_get(NULL, link, route, &existing) < 0)
332                 link->dhcp_pd_configured = false;
333         else
334                 route_unmark(existing);
335 
336         r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp_pd_messages,
337                                dhcp_pd_route_handler, NULL);
338         if (r < 0)
339                 return log_link_error_errno(link, r, "Failed to request DHCP-PD prefix route: %m");
340 
341         return 0;
342 }
343 
dhcp_pd_address_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Address * address)344 static int dhcp_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
345         int r;
346 
347         assert(link);
348 
349         r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCP-PD address");
350         if (r <= 0)
351                 return r;
352 
353         r = dhcp_pd_check_ready(link);
354         if (r < 0)
355                 link_enter_failed(link);
356 
357         return 1;
358 }
359 
log_dhcp_pd_address(Link * link,const Address * address)360 static void log_dhcp_pd_address(Link *link, const Address *address) {
361         _cleanup_free_ char *buffer = NULL;
362         int log_level;
363 
364         assert(address);
365         assert(address->family == AF_INET6);
366 
367         log_level = address_get(link, address, NULL) >= 0 ? LOG_DEBUG : LOG_INFO;
368 
369         if (log_level < log_get_max_level())
370                 return;
371 
372         (void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buffer);
373 
374         log_link_full(link, log_level, "DHCP-PD address %s (valid %s, preferred %s)",
375                       strna(buffer),
376                       FORMAT_LIFETIME(address->lifetime_valid_usec),
377                       FORMAT_LIFETIME(address->lifetime_preferred_usec));
378 }
379 
dhcp_pd_request_address(Link * link,const struct in6_addr * prefix,usec_t lifetime_preferred_usec,usec_t lifetime_valid_usec)380 static int dhcp_pd_request_address(
381                 Link *link,
382                 const struct in6_addr *prefix,
383                 usec_t lifetime_preferred_usec,
384                 usec_t lifetime_valid_usec) {
385 
386         _cleanup_set_free_ Set *addresses = NULL;
387         struct in6_addr *a;
388         int r;
389 
390         assert(link);
391         assert(link->network);
392         assert(prefix);
393 
394         if (!link->network->dhcp_pd_assign)
395                 return 0;
396 
397         r = dhcp_pd_generate_addresses(link, prefix, &addresses);
398         if (r < 0)
399                 return log_link_warning_errno(link, r, "Failed to generate addresses for acquired DHCP delegated prefix: %m");
400 
401         SET_FOREACH(a, addresses) {
402                 _cleanup_(address_freep) Address *address = NULL;
403                 Address *existing;
404 
405                 r = address_new(&address);
406                 if (r < 0)
407                         return log_link_error_errno(link, r, "Failed to allocate address for DHCP delegated prefix: %m");
408 
409                 address->source = NETWORK_CONFIG_SOURCE_DHCP_PD;
410                 address->family = AF_INET6;
411                 address->in_addr.in6 = *a;
412                 address->prefixlen = 64;
413                 address->lifetime_preferred_usec = lifetime_preferred_usec;
414                 address->lifetime_valid_usec = lifetime_valid_usec;
415                 SET_FLAG(address->flags, IFA_F_MANAGETEMPADDR, link->network->dhcp_pd_manage_temporary_address);
416                 address->route_metric = link->network->dhcp_pd_route_metric;
417 
418                 log_dhcp_pd_address(link, address);
419 
420                 if (address_get(link, address, &existing) < 0)
421                         link->dhcp_pd_configured = false;
422                 else
423                         address_unmark(existing);
424 
425                 r = link_request_address(link, TAKE_PTR(address), true, &link->dhcp_pd_messages,
426                                          dhcp_pd_address_handler, NULL);
427                 if (r < 0)
428                         return log_link_error_errno(link, r, "Failed to request DHCP delegated prefix address: %m");
429         }
430 
431         return 0;
432 }
433 
dhcp_pd_calculate_subnet_prefix(const struct in6_addr * pd_prefix,uint8_t pd_prefix_len,uint64_t subnet_id,struct in6_addr * ret)434 static int dhcp_pd_calculate_subnet_prefix(
435                 const struct in6_addr *pd_prefix,
436                 uint8_t pd_prefix_len,
437                 uint64_t subnet_id,
438                 struct in6_addr *ret) {
439 
440         struct in6_addr prefix;
441 
442         assert(pd_prefix);
443         assert(pd_prefix_len <= 64);
444         assert(ret);
445 
446         if (subnet_id >= UINT64_C(1) << (64 - pd_prefix_len))
447                 return -ERANGE;
448 
449         prefix = *pd_prefix;
450 
451         if (pd_prefix_len < 32)
452                 prefix.s6_addr32[0] |= htobe32(subnet_id >> 32);
453 
454         prefix.s6_addr32[1] |= htobe32(subnet_id & 0xffffffff);
455 
456         *ret = prefix;
457         return 0;
458 }
459 
dhcp_pd_get_preferred_subnet_prefix(Link * link,const struct in6_addr * pd_prefix,uint8_t pd_prefix_len,struct in6_addr * ret)460 static int dhcp_pd_get_preferred_subnet_prefix(
461                 Link *link,
462                 const struct in6_addr *pd_prefix,
463                 uint8_t pd_prefix_len,
464                 struct in6_addr *ret) {
465 
466         struct in6_addr prefix;
467         Link *assigned_link;
468         int r;
469 
470         assert(link);
471         assert(link->manager);
472         assert(link->network);
473         assert(pd_prefix);
474 
475         if (link->network->dhcp_pd_subnet_id >= 0) {
476                 /* If the link has a preference for a particular subnet id try to allocate that */
477 
478                 r = dhcp_pd_calculate_subnet_prefix(pd_prefix, pd_prefix_len, link->network->dhcp_pd_subnet_id, &prefix);
479                 if (r < 0)
480                         return log_link_warning_errno(link, r,
481                                                       "subnet id %" PRIu64 " is out of range. Only have %" PRIu64 " subnets.",
482                                                       link->network->dhcp_pd_subnet_id, UINT64_C(1) << (64 - pd_prefix_len));
483 
484                 *ret = prefix;
485                 return 0;
486         }
487 
488         if (dhcp_pd_get_assigned_subnet_prefix(link, pd_prefix, pd_prefix_len, ret) >= 0)
489                 return 0;
490 
491         for (uint64_t n = 0; ; n++) {
492                 /* If we do not have an allocation preference just iterate
493                  * through the address space and return the first free prefix. */
494 
495                 r = dhcp_pd_calculate_subnet_prefix(pd_prefix, pd_prefix_len, n, &prefix);
496                 if (r < 0)
497                         return log_link_warning_errno(link, r,
498                                                       "Couldn't find a suitable prefix. Ran out of address space.");
499 
500                 /* Do not use explicitly requested subnet IDs. Note that the corresponding link may not
501                  * appear yet. So, we need to check the ID is not used in any .network files. */
502                 if (set_contains(link->manager->dhcp_pd_subnet_ids, &n))
503                         continue;
504 
505                 /* Check that the prefix is not assigned to another link. */
506                 if (link_get_by_dhcp_pd_subnet_prefix(link->manager, &prefix, &assigned_link) < 0 ||
507                     assigned_link == link)
508                         break;
509         }
510 
511         r = link_add_dhcp_pd_subnet_prefix(link, &prefix);
512         if (r < 0)
513                 return log_link_warning_errno(link, r, "Failed to save acquired free subnet prefix: %m");
514 
515         *ret = prefix;
516         return 0;
517 }
518 
dhcp_pd_assign_subnet_prefix(Link * link,const struct in6_addr * pd_prefix,uint8_t pd_prefix_len,usec_t lifetime_preferred_usec,usec_t lifetime_valid_usec,bool is_uplink)519 static int dhcp_pd_assign_subnet_prefix(
520                 Link *link,
521                 const struct in6_addr *pd_prefix,
522                 uint8_t pd_prefix_len,
523                 usec_t lifetime_preferred_usec,
524                 usec_t lifetime_valid_usec,
525                 bool is_uplink) {
526 
527         _cleanup_free_ char *buf = NULL;
528         struct in6_addr prefix;
529         int r;
530 
531         assert(link);
532         assert(link->network);
533         assert(pd_prefix);
534 
535         r = dhcp_pd_get_preferred_subnet_prefix(link, pd_prefix, pd_prefix_len, &prefix);
536         if (r < 0)
537                 return r == -ERANGE ? 0 : r;
538 
539         (void) in6_addr_prefix_to_string(&prefix, 64, &buf);
540 
541         if (link_radv_enabled(link) && link->network->dhcp_pd_announce) {
542                 if (is_uplink)
543                         log_link_debug(link, "Ignoring Announce= setting on upstream interface.");
544                 else {
545                         r = radv_add_prefix(link, &prefix, 64, lifetime_preferred_usec, lifetime_valid_usec);
546                         if (r < 0)
547                                 return log_link_warning_errno(link, r,
548                                                               "Failed to assign/update prefix %s to IPv6 Router Advertisement: %m",
549                                                               strna(buf));
550                 }
551         }
552 
553         r = dhcp_pd_request_route(link, &prefix, lifetime_valid_usec);
554         if (r < 0)
555                 return log_link_warning_errno(link, r,
556                                               "Failed to assign/update route for prefix %s: %m",
557                                               strna(buf));
558 
559         r = dhcp_pd_request_address(link, &prefix, lifetime_preferred_usec, lifetime_valid_usec);
560         if (r < 0)
561                 return log_link_warning_errno(link, r,
562                                               "Failed to assign/update address for prefix %s: %m",
563                                               strna(buf));
564 
565         log_link_debug(link, "Assigned prefix %s", strna(buf));
566         return 1;
567 }
568 
dhcp_pd_prepare(Link * link)569 static int dhcp_pd_prepare(Link *link) {
570         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
571                 return 0;
572 
573         if (!link_dhcp_pd_is_enabled(link))
574                 return 0;
575 
576         if (link_radv_enabled(link) && link->network->dhcp_pd_announce && !link->radv)
577                 return 0;
578 
579         link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP_PD, NULL);
580         link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP_PD, NULL);
581 
582         return 1;
583 }
584 
dhcp_pd_finalize(Link * link)585 static int dhcp_pd_finalize(Link *link) {
586         int r;
587 
588         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
589                 return 0;
590 
591         if (link->dhcp_pd_messages == 0) {
592                 link->dhcp_pd_configured = false;
593 
594                 r = dhcp_pd_remove(link, /* only_marked = */ true);
595                 if (r < 0)
596                         return r;
597         }
598 
599         if (!link->dhcp_pd_configured)
600                 link_set_state(link, LINK_STATE_CONFIGURING);
601 
602         link_check_ready(link);
603         return 0;
604 }
605 
dhcp_pd_prefix_lost(Link * uplink)606 void dhcp_pd_prefix_lost(Link *uplink) {
607         Route *route;
608         Link *link;
609         int r;
610 
611         assert(uplink);
612         assert(uplink->manager);
613 
614         HASHMAP_FOREACH(link, uplink->manager->links_by_index) {
615                 if (!dhcp_pd_is_uplink(link, uplink, /* accept_auto = */ true))
616                         continue;
617 
618                 r = dhcp_pd_remove(link, /* only_marked = */ false);
619                 if (r < 0)
620                         link_enter_failed(link);
621         }
622 
623         SET_FOREACH(route, uplink->manager->routes) {
624                 if (!IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
625                         continue;
626                 if (route->family != AF_INET6)
627                         continue;
628                 if (route->type != RTN_UNREACHABLE)
629                         continue;
630                 if (!set_contains(uplink->dhcp_pd_prefixes,
631                                   &(struct in_addr_prefix) {
632                                           .family = AF_INET6,
633                                           .prefixlen = route->dst_prefixlen,
634                                           .address = route->dst }))
635                         continue;
636 
637                 (void) route_remove(route);
638 
639                 route_cancel_request(route, uplink);
640         }
641 
642         set_clear(uplink->dhcp_pd_prefixes);
643 }
644 
dhcp4_pd_prefix_lost(Link * uplink)645 void dhcp4_pd_prefix_lost(Link *uplink) {
646         Link *tunnel;
647 
648         dhcp_pd_prefix_lost(uplink);
649 
650         if (uplink->dhcp4_6rd_tunnel_name &&
651             link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &tunnel) >= 0)
652                 (void) link_remove(tunnel);
653 }
654 
dhcp4_unreachable_route_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Route * route)655 static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
656         int r;
657 
658         assert(link);
659 
660         r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv4 delegated prefix");
661         if (r <= 0)
662                 return r;
663 
664         r = dhcp4_check_ready(link);
665         if (r < 0)
666                 link_enter_failed(link);
667 
668         return 1;
669 }
670 
dhcp6_unreachable_route_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Route * route)671 static int dhcp6_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
672         int r;
673 
674         assert(link);
675 
676         r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv6 delegated prefix");
677         if (r <= 0)
678                 return r;
679 
680         r = dhcp6_check_ready(link);
681         if (r < 0)
682                 link_enter_failed(link);
683 
684         return 1;
685 }
686 
dhcp_request_unreachable_route(Link * link,const struct in6_addr * addr,uint8_t prefixlen,usec_t lifetime_usec,NetworkConfigSource source,const union in_addr_union * server_address,unsigned * counter,route_netlink_handler_t callback)687 static int dhcp_request_unreachable_route(
688                 Link *link,
689                 const struct in6_addr *addr,
690                 uint8_t prefixlen,
691                 usec_t lifetime_usec,
692                 NetworkConfigSource source,
693                 const union in_addr_union *server_address,
694                 unsigned *counter,
695                 route_netlink_handler_t callback) {
696 
697         _cleanup_(route_freep) Route *route = NULL;
698         Route *existing;
699         int r;
700 
701         assert(link);
702         assert(addr);
703         assert(IN_SET(source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6));
704         assert(server_address);
705         assert(counter);
706         assert(callback);
707 
708         if (prefixlen >= 64) {
709                 _cleanup_free_ char *buf = NULL;
710 
711                 (void) in6_addr_prefix_to_string(addr, prefixlen, &buf);
712                 log_link_debug(link, "Not adding a blocking route for DHCP delegated prefix %s since the prefix has length >= 64.",
713                                strna(buf));
714                 return 0;
715         }
716 
717         r = route_new(&route);
718         if (r < 0)
719                 return log_oom();
720 
721         route->source = source;
722         route->provider = *server_address;
723         route->family = AF_INET6;
724         route->dst.in6 = *addr;
725         route->dst_prefixlen = prefixlen;
726         route->type = RTN_UNREACHABLE;
727         route->protocol = RTPROT_DHCP;
728         route->priority = IP6_RT_PRIO_USER;
729         route->lifetime_usec = lifetime_usec;
730 
731         if (route_get(link->manager, NULL, route, &existing) < 0)
732                 link->dhcp6_configured = false;
733         else
734                 route_unmark(existing);
735 
736         r = link_request_route(link, TAKE_PTR(route), true, counter, callback, NULL);
737         if (r < 0) {
738                 _cleanup_free_ char *buf = NULL;
739 
740                 (void) in6_addr_prefix_to_string(addr, prefixlen, &buf);
741                 return log_link_error_errno(link, r, "Failed to request unreachable route for DHCP delegated prefix %s: %m",
742                                             strna(buf));
743         }
744 
745         return 0;
746 }
747 
dhcp4_request_unreachable_route(Link * link,const struct in6_addr * addr,uint8_t prefixlen,usec_t lifetime_usec,const union in_addr_union * server_address)748 static int dhcp4_request_unreachable_route(
749                 Link *link,
750                 const struct in6_addr *addr,
751                 uint8_t prefixlen,
752                 usec_t lifetime_usec,
753                 const union in_addr_union *server_address) {
754 
755         return dhcp_request_unreachable_route(link, addr, prefixlen, lifetime_usec,
756                                               NETWORK_CONFIG_SOURCE_DHCP4, server_address,
757                                               &link->dhcp4_messages, dhcp4_unreachable_route_handler);
758 }
759 
dhcp6_request_unreachable_route(Link * link,const struct in6_addr * addr,uint8_t prefixlen,usec_t lifetime_usec,const union in_addr_union * server_address)760 static int dhcp6_request_unreachable_route(
761                 Link *link,
762                 const struct in6_addr *addr,
763                 uint8_t prefixlen,
764                 usec_t lifetime_usec,
765                 const union in_addr_union *server_address) {
766 
767         return dhcp_request_unreachable_route(link, addr, prefixlen, lifetime_usec,
768                                               NETWORK_CONFIG_SOURCE_DHCP6, server_address,
769                                               &link->dhcp6_messages, dhcp6_unreachable_route_handler);
770 }
771 
dhcp_pd_prefix_add(Link * link,const struct in6_addr * prefix,uint8_t prefixlen)772 static int dhcp_pd_prefix_add(Link *link, const struct in6_addr *prefix, uint8_t prefixlen) {
773         _cleanup_free_ char *buf = NULL;
774         struct in_addr_prefix *p;
775         int r;
776 
777         assert(link);
778         assert(prefix);
779 
780         p = new(struct in_addr_prefix, 1);
781         if (!p)
782                 return log_oom();
783 
784         *p = (struct in_addr_prefix) {
785                 .family = AF_INET6,
786                 .prefixlen = prefixlen,
787                 .address.in6 = *prefix,
788         };
789 
790         (void) in6_addr_prefix_to_string(prefix, prefixlen, &buf);
791 
792         log_link_full(link,
793                       set_contains(link->dhcp_pd_prefixes, p) ? LOG_DEBUG :
794                       prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO,
795                       "DHCP: received delegated prefix %s%s",
796                       strna(buf),
797                       prefixlen > 64 ? " with prefix length > 64, ignoring." :
798                       prefixlen < 48 ? " with prefix length < 48, looks unusual.": "");
799 
800         /* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */
801         r = set_ensure_consume(&link->dhcp_pd_prefixes, &in_addr_prefix_hash_ops_free, p);
802         if (r < 0)
803                 return log_link_error_errno(link, r, "Failed to store DHCP delegated prefix %s: %m", strna(buf));
804 
805         return 0;
806 }
807 
dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link * link,const struct in_addr * br_address,usec_t lifetime_usec)808 static int dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link *link, const struct in_addr *br_address, usec_t lifetime_usec) {
809         _cleanup_(route_freep) Route *route = NULL;
810         Route *existing;
811         int r;
812 
813         assert(link);
814         assert(br_address);
815 
816         r = route_new(&route);
817         if (r < 0)
818                 return log_link_debug_errno(link, r, "Failed to allocate default gateway for DHCP delegated prefix: %m");
819 
820         route->source = NETWORK_CONFIG_SOURCE_DHCP_PD;
821         route->family = AF_INET6;
822         route->gw_family = AF_INET6;
823         route->gw.in6.s6_addr32[3] = br_address->s_addr;
824         route->scope = RT_SCOPE_UNIVERSE;
825         route->protocol = RTPROT_DHCP;
826         route->priority = IP6_RT_PRIO_USER;
827         route->lifetime_usec = lifetime_usec;
828 
829         if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
830                 link->dhcp_pd_configured = false;
831         else
832                 route_unmark(existing);
833 
834         r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp_pd_messages,
835                                dhcp_pd_route_handler, NULL);
836         if (r < 0)
837                 return log_link_debug_errno(link, r, "Failed to request default gateway for DHCP delegated prefix: %m");
838 
839         return 0;
840 }
841 
dhcp4_calculate_pd_prefix(const struct in_addr * ipv4address,uint8_t ipv4masklen,const struct in6_addr * sixrd_prefix,uint8_t sixrd_prefixlen,struct in6_addr * ret_pd_prefix,uint8_t * ret_pd_prefixlen)842 static void dhcp4_calculate_pd_prefix(
843                 const struct in_addr *ipv4address,
844                 uint8_t ipv4masklen,
845                 const struct in6_addr *sixrd_prefix,
846                 uint8_t sixrd_prefixlen,
847                 struct in6_addr *ret_pd_prefix,
848                 uint8_t *ret_pd_prefixlen) {
849 
850         struct in6_addr pd_prefix;
851 
852         assert(ipv4address);
853         assert(ipv4masklen <= 32);
854         assert(sixrd_prefix);
855         assert(32 - ipv4masklen + sixrd_prefixlen <= 128);
856         assert(ret_pd_prefix);
857 
858         pd_prefix = *sixrd_prefix;
859         for (unsigned i = 0; i < (unsigned) (32 - ipv4masklen); i++)
860                 if (ipv4address->s_addr & htobe32(UINT32_C(1) << (32 - ipv4masklen - i - 1)))
861                         pd_prefix.s6_addr[(i + sixrd_prefixlen) / 8] |= 1 << (7 - (i + sixrd_prefixlen) % 8);
862 
863         *ret_pd_prefix = pd_prefix;
864         if (ret_pd_prefixlen)
865                 *ret_pd_prefixlen = 32 - ipv4masklen + sixrd_prefixlen;
866 }
867 
dhcp4_pd_assign_subnet_prefix(Link * link,Link * uplink)868 static int dhcp4_pd_assign_subnet_prefix(Link *link, Link *uplink) {
869         uint8_t ipv4masklen, sixrd_prefixlen, pd_prefixlen;
870         struct in6_addr sixrd_prefix, pd_prefix;
871         const struct in_addr *br_addresses;
872         struct in_addr ipv4address;
873         uint32_t lifetime_sec;
874         usec_t lifetime_usec;
875         int r;
876 
877         assert(link);
878         assert(uplink);
879         assert(uplink->dhcp_lease);
880 
881         r = sd_dhcp_lease_get_address(uplink->dhcp_lease, &ipv4address);
882         if (r < 0)
883                 return log_link_warning_errno(uplink, r, "Failed to get DHCPv4 address: %m");
884 
885         r = sd_dhcp_lease_get_lifetime(uplink->dhcp_lease, &lifetime_sec);
886         if (r < 0)
887                 return log_link_warning_errno(uplink, r, "Failed to get lifetime of DHCPv4 lease: %m");
888 
889         lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(CLOCK_BOOTTIME));
890 
891         r = sd_dhcp_lease_get_6rd(uplink->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, &br_addresses, NULL);
892         if (r < 0)
893                 return log_link_warning_errno(uplink, r, "Failed to get DHCPv4 6rd option: %m");
894 
895         dhcp4_calculate_pd_prefix(&ipv4address, ipv4masklen, &sixrd_prefix, sixrd_prefixlen, &pd_prefix, &pd_prefixlen);
896 
897         if (pd_prefixlen > 64)
898                 return 0;
899 
900         r = dhcp_pd_prepare(link);
901         if (r <= 0)
902                 return r;
903 
904         if (streq_ptr(uplink->dhcp4_6rd_tunnel_name, link->ifname)) {
905                 r = dhcp4_pd_request_default_gateway_on_6rd_tunnel(link, &br_addresses[0], lifetime_usec);
906                 if (r < 0)
907                         return r;
908         }
909 
910         r = dhcp_pd_assign_subnet_prefix(link, &pd_prefix, pd_prefixlen, lifetime_usec, lifetime_usec, /* is_uplink = */ false);
911         if (r < 0)
912                 return r;
913 
914         return dhcp_pd_finalize(link);
915 }
916 
dhcp4_pd_6rd_tunnel_create_handler(sd_netlink * rtnl,sd_netlink_message * m,Link * link)917 static int dhcp4_pd_6rd_tunnel_create_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
918         int r;
919 
920         assert(m);
921         assert(link);
922         assert(link->manager);
923         assert(link->dhcp4_6rd_tunnel_name);
924 
925         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
926                 return 0;
927 
928         r = sd_netlink_message_get_errno(m);
929         if (r < 0) {
930                 log_link_message_warning_errno(link, m, r, "Failed to create tunnel device for DHCPv4 6rd");
931                 link_enter_failed(link);
932                 return 0;
933         }
934 
935         return 0;
936 }
937 
dhcp4_pd_prefix_acquired(Link * uplink)938 int dhcp4_pd_prefix_acquired(Link *uplink) {
939         _cleanup_free_ char *tunnel_name = NULL;
940         uint8_t ipv4masklen, sixrd_prefixlen, pd_prefixlen;
941         struct in6_addr sixrd_prefix, pd_prefix;
942         struct in_addr ipv4address;
943         union in_addr_union server_address;
944         const struct in_addr *br_addresses;
945         uint32_t lifetime_sec;
946         usec_t lifetime_usec;
947         Link *link;
948         int r;
949 
950         assert(uplink);
951         assert(uplink->dhcp_lease);
952 
953         r = sd_dhcp_lease_get_address(uplink->dhcp_lease, &ipv4address);
954         if (r < 0)
955                 return log_link_warning_errno(uplink, r, "Failed to get DHCPv4 address: %m");
956 
957         r = sd_dhcp_lease_get_lifetime(uplink->dhcp_lease, &lifetime_sec);
958         if (r < 0)
959                 return log_link_warning_errno(uplink, r, "Failed to get lifetime of DHCPv4 lease: %m");
960 
961         lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(CLOCK_BOOTTIME));
962 
963         r = sd_dhcp_lease_get_server_identifier(uplink->dhcp_lease, &server_address.in);
964         if (r < 0)
965                 return log_link_warning_errno(uplink, r, "Failed to get server address of DHCPv4 lease: %m");
966 
967         r = sd_dhcp_lease_get_6rd(uplink->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, &br_addresses, NULL);
968         if (r < 0)
969                 return log_link_warning_errno(uplink, r, "Failed to get DHCPv4 6rd option: %m");
970 
971         if (DEBUG_LOGGING) {
972                 _cleanup_free_ char *buf = NULL;
973 
974                 (void) in6_addr_prefix_to_string(&sixrd_prefix, sixrd_prefixlen, &buf);
975                 log_link_debug(uplink, "DHCPv4: 6rd option is acquired: IPv4_masklen=%u, 6rd_prefix=%s, br_address="IPV4_ADDRESS_FMT_STR,
976                                ipv4masklen, strna(buf), IPV4_ADDRESS_FMT_VAL(*br_addresses));
977         }
978 
979         /* Calculate PD prefix */
980         dhcp4_calculate_pd_prefix(&ipv4address, ipv4masklen, &sixrd_prefix, sixrd_prefixlen, &pd_prefix, &pd_prefixlen);
981 
982         /* Register and log PD prefix */
983         r = dhcp_pd_prefix_add(uplink, &pd_prefix, pd_prefixlen);
984         if (r < 0)
985                 return r;
986 
987         /* Request unreachable route */
988         r = dhcp4_request_unreachable_route(uplink, &pd_prefix, pd_prefixlen, lifetime_usec, &server_address);
989         if (r < 0)
990                 return r;
991 
992         /* Generate 6rd SIT tunnel device name. */
993         r = dhcp4_pd_create_6rd_tunnel_name(uplink, &tunnel_name);
994         if (r < 0)
995                 return r;
996 
997         /* Remove old tunnel device if exists. */
998         if (!streq_ptr(uplink->dhcp4_6rd_tunnel_name, tunnel_name)) {
999                 Link *old_tunnel;
1000 
1001                 if (uplink->dhcp4_6rd_tunnel_name &&
1002                     link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &old_tunnel) >= 0)
1003                         (void) link_remove(old_tunnel);
1004 
1005                 free_and_replace(uplink->dhcp4_6rd_tunnel_name, tunnel_name);
1006         }
1007 
1008         /* Create 6rd SIT tunnel device if it does not exist yet. */
1009         if (link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, NULL) < 0) {
1010                 r = dhcp4_pd_create_6rd_tunnel(uplink, dhcp4_pd_6rd_tunnel_create_handler);
1011                 if (r < 0)
1012                         return r;
1013         }
1014 
1015         /* Then, assign subnet prefixes to downstream interfaces. */
1016         HASHMAP_FOREACH(link, uplink->manager->links_by_index) {
1017                 if (!dhcp_pd_is_uplink(link, uplink, /* accept_auto = */ true))
1018                         continue;
1019 
1020                 r = dhcp4_pd_assign_subnet_prefix(link, uplink);
1021                 if (r < 0) {
1022                         /* When failed on the upstream interface (i.e., the case link == uplink),
1023                          * immediately abort the assignment of the prefixes. As, the all assigned
1024                          * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
1025                          * to continue the assignment. */
1026                         if (link == uplink)
1027                                 return r;
1028 
1029                         link_enter_failed(link);
1030                 }
1031         }
1032 
1033         return 0;
1034 }
1035 
dhcp6_pd_assign_subnet_prefixes(Link * link,Link * uplink)1036 static int dhcp6_pd_assign_subnet_prefixes(Link *link, Link *uplink) {
1037         usec_t timestamp_usec;
1038         int r;
1039 
1040         assert(link);
1041         assert(uplink);
1042         assert(uplink->dhcp6_lease);
1043 
1044         r = dhcp_pd_prepare(link);
1045         if (r <= 0)
1046                 return r;
1047 
1048         r = sd_dhcp6_lease_get_timestamp(uplink->dhcp6_lease, CLOCK_BOOTTIME, &timestamp_usec);
1049         if (r < 0)
1050                 return r;
1051 
1052         for (sd_dhcp6_lease_reset_pd_prefix_iter(uplink->dhcp6_lease);;) {
1053                 uint32_t lifetime_preferred_sec, lifetime_valid_sec;
1054                 usec_t lifetime_preferred_usec, lifetime_valid_usec;
1055                 struct in6_addr pd_prefix;
1056                 uint8_t pd_prefix_len;
1057 
1058                 r = sd_dhcp6_lease_get_pd(uplink->dhcp6_lease, &pd_prefix, &pd_prefix_len,
1059                                           &lifetime_preferred_sec, &lifetime_valid_sec);
1060                 if (r < 0)
1061                         break;
1062 
1063                 if (pd_prefix_len > 64)
1064                         continue;
1065 
1066                 /* Mask prefix for safety. */
1067                 r = in6_addr_mask(&pd_prefix, pd_prefix_len);
1068                 if (r < 0)
1069                         return r;
1070 
1071                 lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec);
1072                 lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
1073 
1074                 r = dhcp_pd_assign_subnet_prefix(link, &pd_prefix, pd_prefix_len,
1075                                                  lifetime_preferred_usec, lifetime_valid_usec,
1076                                                  /* is_uplink = */ link == uplink);
1077                 if (r < 0)
1078                         return r;
1079         }
1080 
1081         return dhcp_pd_finalize(link);
1082 }
1083 
dhcp6_pd_prefix_acquired(Link * uplink)1084 int dhcp6_pd_prefix_acquired(Link *uplink) {
1085         union in_addr_union server_address;
1086         usec_t timestamp_usec;
1087         Link *link;
1088         int r;
1089 
1090         assert(uplink);
1091         assert(uplink->dhcp6_lease);
1092 
1093         r = sd_dhcp6_lease_get_server_address(uplink->dhcp6_lease, &server_address.in6);
1094         if (r < 0)
1095                 return log_link_warning_errno(uplink, r, "Failed to get server address of DHCPv6 lease: %m");
1096 
1097         r = sd_dhcp6_lease_get_timestamp(uplink->dhcp6_lease, CLOCK_BOOTTIME, &timestamp_usec);
1098         if (r < 0)
1099                 return log_link_warning_errno(uplink, r, "Failed to get timestamp of DHCPv6 lease: %m");
1100 
1101         /* First, logs acquired prefixes and request unreachable routes. */
1102         for (sd_dhcp6_lease_reset_pd_prefix_iter(uplink->dhcp6_lease);;) {
1103                 uint32_t lifetime_preferred_sec, lifetime_valid_sec;
1104                 usec_t lifetime_valid_usec;
1105                 struct in6_addr pd_prefix;
1106                 uint8_t pd_prefix_len;
1107 
1108                 r = sd_dhcp6_lease_get_pd(uplink->dhcp6_lease, &pd_prefix, &pd_prefix_len,
1109                                           &lifetime_preferred_sec, &lifetime_valid_sec);
1110                 if (r < 0)
1111                         break;
1112 
1113                 /* Mask prefix for safety. */
1114                 r = in6_addr_mask(&pd_prefix, pd_prefix_len);
1115                 if (r < 0)
1116                         return log_link_error_errno(uplink, r, "Failed to mask DHCPv6 delegated prefix: %m");
1117 
1118                 lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
1119 
1120                 r = dhcp_pd_prefix_add(uplink, &pd_prefix, pd_prefix_len);
1121                 if (r < 0)
1122                         return r;
1123 
1124                 r = dhcp6_request_unreachable_route(uplink, &pd_prefix, pd_prefix_len, lifetime_valid_usec, &server_address);
1125                 if (r < 0)
1126                         return r;
1127         }
1128 
1129         /* Then, assign subnet prefixes. */
1130         HASHMAP_FOREACH(link, uplink->manager->links_by_index) {
1131                 if (!dhcp_pd_is_uplink(link, uplink, /* accept_auto = */ true))
1132                         continue;
1133 
1134                 r = dhcp6_pd_assign_subnet_prefixes(link, uplink);
1135                 if (r < 0) {
1136                         /* When failed on the upstream interface (i.e., the case link == uplink),
1137                          * immediately abort the assignment of the prefixes. As, the all assigned
1138                          * prefixes will be dropped soon in link_enter_failed(), and it is meaningless
1139                          * to continue the assignment. */
1140                         if (link == uplink)
1141                                 return r;
1142 
1143                         link_enter_failed(link);
1144                 }
1145         }
1146 
1147         return 0;
1148 }
1149 
dhcp4_pd_uplink_is_ready(Link * link)1150 static bool dhcp4_pd_uplink_is_ready(Link *link) {
1151         assert(link);
1152 
1153         if (!link->network)
1154                 return false;
1155 
1156         if (!link->network->dhcp_use_6rd)
1157                 return false;
1158 
1159         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1160                 return false;
1161 
1162         if (!link->dhcp_client)
1163                 return false;
1164 
1165         if (sd_dhcp_client_is_running(link->dhcp_client) <= 0)
1166                 return false;
1167 
1168         if (!link->dhcp_lease)
1169                 return false;
1170 
1171         return dhcp4_lease_has_pd_prefix(link->dhcp_lease);
1172 }
1173 
dhcp6_pd_uplink_is_ready(Link * link)1174 static bool dhcp6_pd_uplink_is_ready(Link *link) {
1175         assert(link);
1176 
1177         if (!link->network)
1178                 return false;
1179 
1180         if (!link->network->dhcp6_use_pd_prefix)
1181                 return false;
1182 
1183         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1184                 return false;
1185 
1186         if (!link->dhcp6_client)
1187                 return false;
1188 
1189         if (sd_dhcp6_client_is_running(link->dhcp6_client) <= 0)
1190                 return false;
1191 
1192         if (!link->dhcp6_lease)
1193                 return false;
1194 
1195         return dhcp6_lease_has_pd_prefix(link->dhcp6_lease);
1196 }
1197 
dhcp_pd_find_uplink(Link * link,Link ** ret)1198 int dhcp_pd_find_uplink(Link *link, Link **ret) {
1199         Link *uplink = NULL;
1200         int r = 0;
1201 
1202         assert(link);
1203         assert(link->manager);
1204         assert(link_dhcp_pd_is_enabled(link));
1205         assert(ret);
1206 
1207         if (link->network->dhcp_pd_uplink_name)
1208                 r = link_get_by_name(link->manager, link->network->dhcp_pd_uplink_name, &uplink);
1209         else if (link->network->dhcp_pd_uplink_index > 0)
1210                 r = link_get_by_index(link->manager, link->network->dhcp_pd_uplink_index, &uplink);
1211         else if (link->network->dhcp_pd_uplink_index == UPLINK_INDEX_SELF)
1212                 uplink = link;
1213         if (r < 0)
1214                 return r;
1215 
1216         if (uplink) {
1217                 if (dhcp4_pd_uplink_is_ready(uplink)) {
1218                         *ret = uplink;
1219                         return AF_INET;
1220                 }
1221 
1222                 if (dhcp6_pd_uplink_is_ready(uplink)) {
1223                         *ret = uplink;
1224                         return AF_INET6;
1225                 }
1226 
1227                 return -EBUSY;
1228         }
1229 
1230         HASHMAP_FOREACH(uplink, link->manager->links_by_index) {
1231                 /* Assume that there exists at most one link which acquired delegated prefixes. */
1232                 if (dhcp4_pd_uplink_is_ready(uplink)) {
1233                         *ret = uplink;
1234                         return AF_INET;
1235                 }
1236 
1237                 if (dhcp6_pd_uplink_is_ready(uplink)) {
1238                         *ret = uplink;
1239                         return AF_INET6;
1240                 }
1241         }
1242 
1243         return -ENODEV;
1244 }
1245 
dhcp_request_prefix_delegation(Link * link)1246 int dhcp_request_prefix_delegation(Link *link) {
1247         Link *uplink;
1248         int r;
1249 
1250         assert(link);
1251 
1252         if (!link_dhcp_pd_is_enabled(link))
1253                 return 0;
1254 
1255         r = dhcp_pd_find_uplink(link, &uplink);
1256         if (r < 0)
1257                 return 0;
1258 
1259         log_link_debug(link, "Requesting subnets of delegated prefixes acquired by DHCPv%c client on %s",
1260                        r == AF_INET ? '4' : '6', uplink->ifname);
1261 
1262         return r == AF_INET ?
1263                 dhcp4_pd_assign_subnet_prefix(link, uplink) :
1264                 dhcp6_pd_assign_subnet_prefixes(link, uplink);
1265 }
1266 
config_parse_dhcp_pd_subnet_id(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1267 int config_parse_dhcp_pd_subnet_id(
1268                 const char *unit,
1269                 const char *filename,
1270                 unsigned line,
1271                 const char *section,
1272                 unsigned section_line,
1273                 const char *lvalue,
1274                 int ltype,
1275                 const char *rvalue,
1276                 void *data,
1277                 void *userdata) {
1278 
1279         int64_t *p = data;
1280         uint64_t t;
1281         int r;
1282 
1283         assert(filename);
1284         assert(lvalue);
1285         assert(rvalue);
1286         assert(data);
1287 
1288         if (isempty(rvalue) || streq(rvalue, "auto")) {
1289                 *p = -1;
1290                 return 0;
1291         }
1292 
1293         r = safe_atoux64(rvalue, &t);
1294         if (r < 0) {
1295                 log_syntax(unit, LOG_WARNING, filename, line, r,
1296                            "Failed to parse %s=, ignoring assignment: %s",
1297                            lvalue, rvalue);
1298                 return 0;
1299         }
1300         if (t > INT64_MAX) {
1301                 log_syntax(unit, LOG_WARNING, filename, line, 0,
1302                            "Invalid subnet id '%s', ignoring assignment.",
1303                            rvalue);
1304                 return 0;
1305         }
1306 
1307         *p = (int64_t) t;
1308 
1309         return 0;
1310 }
1311