]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-radv.c
Merge pull request #32447 from keszybz/test-taint
[thirdparty/systemd.git] / src / network / networkd-radv.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2017 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <arpa/inet.h>
8
9 #include "dns-domain.h"
10 #include "ndisc-router-internal.h"
11 #include "networkd-address-generation.h"
12 #include "networkd-address.h"
13 #include "networkd-dhcp-prefix-delegation.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-network.h"
17 #include "networkd-queue.h"
18 #include "networkd-radv.h"
19 #include "networkd-route-util.h"
20 #include "parse-util.h"
21 #include "radv-internal.h"
22 #include "string-util.h"
23 #include "string-table.h"
24 #include "strv.h"
25
26 bool link_radv_enabled(Link *link) {
27 assert(link);
28
29 if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
30 return false;
31
32 if (link->hw_addr.length != ETH_ALEN)
33 return false;
34
35 return link->network->router_prefix_delegation;
36 }
37
38 Prefix *prefix_free(Prefix *prefix) {
39 if (!prefix)
40 return NULL;
41
42 if (prefix->network) {
43 assert(prefix->section);
44 hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
45 }
46
47 config_section_free(prefix->section);
48 set_free(prefix->tokens);
49
50 return mfree(prefix);
51 }
52
53 DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix, prefix_free);
54
55 static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
56 _cleanup_(config_section_freep) ConfigSection *n = NULL;
57 _cleanup_(prefix_freep) Prefix *prefix = NULL;
58 int r;
59
60 assert(network);
61 assert(ret);
62 assert(filename);
63 assert(section_line > 0);
64
65 r = config_section_new(filename, section_line, &n);
66 if (r < 0)
67 return r;
68
69 prefix = hashmap_get(network->prefixes_by_section, n);
70 if (prefix) {
71 *ret = TAKE_PTR(prefix);
72 return 0;
73 }
74
75 prefix = new(Prefix, 1);
76 if (!prefix)
77 return -ENOMEM;
78
79 *prefix = (Prefix) {
80 .network = network,
81 .section = TAKE_PTR(n),
82
83 .flags = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO,
84 .preferred_lifetime = RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
85 .valid_lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
86 };
87
88 r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
89 if (r < 0)
90 return r;
91
92 *ret = TAKE_PTR(prefix);
93 return 0;
94 }
95
96 RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
97 if (!prefix)
98 return NULL;
99
100 if (prefix->network) {
101 assert(prefix->section);
102 hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
103 }
104
105 config_section_free(prefix->section);
106
107 return mfree(prefix);
108 }
109
110 DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutePrefix, route_prefix_free);
111
112 static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
113 _cleanup_(config_section_freep) ConfigSection *n = NULL;
114 _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
115 int r;
116
117 assert(network);
118 assert(ret);
119 assert(filename);
120 assert(section_line > 0);
121
122 r = config_section_new(filename, section_line, &n);
123 if (r < 0)
124 return r;
125
126 prefix = hashmap_get(network->route_prefixes_by_section, n);
127 if (prefix) {
128 *ret = TAKE_PTR(prefix);
129 return 0;
130 }
131
132 prefix = new(RoutePrefix, 1);
133 if (!prefix)
134 return -ENOMEM;
135
136 *prefix = (RoutePrefix) {
137 .network = network,
138 .section = TAKE_PTR(n),
139
140 .lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
141 };
142
143 r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
144 if (r < 0)
145 return r;
146
147 *ret = TAKE_PTR(prefix);
148 return 0;
149 }
150
151 pref64Prefix *pref64_prefix_free(pref64Prefix *prefix) {
152 if (!prefix)
153 return NULL;
154
155 if (prefix->network) {
156 assert(prefix->section);
157 hashmap_remove(prefix->network->pref64_prefixes_by_section, prefix->section);
158 }
159
160 config_section_free(prefix->section);
161
162 return mfree(prefix);
163 }
164
165 DEFINE_SECTION_CLEANUP_FUNCTIONS(pref64Prefix, pref64_prefix_free);
166
167 static int pref64_prefix_new_static(Network *network, const char *filename, unsigned section_line, pref64Prefix **ret) {
168 _cleanup_(config_section_freep) ConfigSection *n = NULL;
169 _cleanup_(pref64_prefix_freep) pref64Prefix *prefix = NULL;
170 int r;
171
172 assert(network);
173 assert(ret);
174 assert(filename);
175 assert(section_line > 0);
176
177 r = config_section_new(filename, section_line, &n);
178 if (r < 0)
179 return r;
180
181 prefix = hashmap_get(network->pref64_prefixes_by_section, n);
182 if (prefix) {
183 *ret = TAKE_PTR(prefix);
184 return 0;
185 }
186
187 prefix = new(pref64Prefix, 1);
188 if (!prefix)
189 return -ENOMEM;
190
191 *prefix = (pref64Prefix) {
192 .network = network,
193 .section = TAKE_PTR(n),
194
195 .lifetime = RADV_PREF64_DEFAULT_LIFETIME_USEC,
196 };
197
198 r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
199 if (r < 0)
200 return r;
201
202 *ret = TAKE_PTR(prefix);
203 return 0;
204 }
205
206 int link_request_radv_addresses(Link *link) {
207 Prefix *p;
208 int r;
209
210 assert(link);
211
212 if (!link_radv_enabled(link))
213 return 0;
214
215 HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
216 if (!p->assign)
217 continue;
218
219 /* radv_generate_addresses() below requires the prefix length <= 64. */
220 if (p->prefixlen > 64)
221 continue;
222
223 _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
224 r = radv_generate_addresses(link, p->tokens, &p->prefix, p->prefixlen, &tokens_by_address);
225 if (r < 0)
226 return r;
227
228 IPv6Token *token;
229 struct in6_addr *a;
230 HASHMAP_FOREACH_KEY(token, a, tokens_by_address) {
231 _cleanup_(address_unrefp) Address *address = NULL;
232
233 r = address_new(&address);
234 if (r < 0)
235 return -ENOMEM;
236
237 address->source = NETWORK_CONFIG_SOURCE_STATIC;
238 address->family = AF_INET6;
239 address->in_addr.in6 = *a;
240 address->prefixlen = p->prefixlen;
241 address->route_metric = p->route_metric;
242 address->token = ipv6_token_ref(token);
243
244 r = link_request_static_address(link, address);
245 if (r < 0)
246 return r;
247 }
248 }
249
250 return 0;
251 }
252
253 int link_reconfigure_radv_address(Address *address, Link *link) {
254 int r;
255
256 assert(address);
257 assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
258 assert(link);
259
260 r = regenerate_address(address, link);
261 if (r <= 0)
262 return r;
263
264 r = link_request_static_address(link, address);
265 if (r < 0)
266 return r;
267
268 if (link->static_address_messages != 0) {
269 link->static_addresses_configured = false;
270 link_set_state(link, LINK_STATE_CONFIGURING);
271 }
272
273 return 0;
274 }
275
276 static int radv_set_prefix(Link *link, Prefix *prefix) {
277 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
278 int r;
279
280 assert(link);
281 assert(link->radv);
282 assert(prefix);
283
284 r = sd_radv_prefix_new(&p);
285 if (r < 0)
286 return r;
287
288 r = sd_radv_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen);
289 if (r < 0)
290 return r;
291
292 r = sd_radv_prefix_set_preferred_lifetime(p, prefix->preferred_lifetime, USEC_INFINITY);
293 if (r < 0)
294 return r;
295
296 r = sd_radv_prefix_set_valid_lifetime(p, prefix->valid_lifetime, USEC_INFINITY);
297 if (r < 0)
298 return r;
299
300 r = sd_radv_prefix_set_onlink(p, FLAGS_SET(prefix->flags, ND_OPT_PI_FLAG_ONLINK));
301 if (r < 0)
302 return r;
303
304 r = sd_radv_prefix_set_address_autoconfiguration(p, FLAGS_SET(prefix->flags, ND_OPT_PI_FLAG_AUTO));
305 if (r < 0)
306 return r;
307
308 return sd_radv_add_prefix(link->radv, p);
309 }
310
311 static int radv_set_route_prefix(Link *link, RoutePrefix *prefix) {
312 _cleanup_(sd_radv_route_prefix_unrefp) sd_radv_route_prefix *p = NULL;
313 int r;
314
315 assert(link);
316 assert(link->radv);
317 assert(prefix);
318
319 r = sd_radv_route_prefix_new(&p);
320 if (r < 0)
321 return r;
322
323 r = sd_radv_route_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen);
324 if (r < 0)
325 return r;
326
327 r = sd_radv_route_prefix_set_lifetime(p, prefix->lifetime, USEC_INFINITY);
328 if (r < 0)
329 return r;
330
331 return sd_radv_add_route_prefix(link->radv, p);
332 }
333
334 static int radv_set_pref64_prefix(Link *link, pref64Prefix *prefix) {
335 _cleanup_(sd_radv_pref64_prefix_unrefp) sd_radv_pref64_prefix *p = NULL;
336 int r;
337
338 assert(link);
339 assert(link->radv);
340 assert(prefix);
341
342 r = sd_radv_pref64_prefix_new(&p);
343 if (r < 0)
344 return r;
345
346 r = sd_radv_pref64_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen, prefix->lifetime);
347 if (r < 0)
348 return r;
349
350 return sd_radv_add_pref64_prefix(link->radv, p);
351 }
352
353 static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
354 _cleanup_free_ struct in6_addr *addresses = NULL;
355 size_t n_addresses = 0;
356
357 assert(network);
358 assert(ret_addresses);
359 assert(ret_size);
360
361 for (size_t i = 0; i < network->n_dns; i++) {
362 union in_addr_union *addr;
363
364 if (network->dns[i]->family != AF_INET6)
365 continue;
366
367 addr = &network->dns[i]->address;
368
369 if (in_addr_is_null(AF_INET6, addr) ||
370 in_addr_is_link_local(AF_INET6, addr) ||
371 in_addr_is_localhost(AF_INET6, addr))
372 continue;
373
374 if (!GREEDY_REALLOC(addresses, n_addresses + 1))
375 return -ENOMEM;
376
377 addresses[n_addresses++] = addr->in6;
378 }
379
380 *ret_addresses = TAKE_PTR(addresses);
381 *ret_size = n_addresses;
382
383 return n_addresses;
384 }
385
386 static int radv_set_dns(Link *link, Link *uplink) {
387 _cleanup_free_ struct in6_addr *dns = NULL;
388 size_t n_dns;
389 int r;
390
391 if (!link->network->router_emit_dns)
392 return 0;
393
394 if (link->network->router_dns) {
395 struct in6_addr *p;
396
397 dns = new(struct in6_addr, link->network->n_router_dns);
398 if (!dns)
399 return -ENOMEM;
400
401 p = dns;
402 for (size_t i = 0; i < link->network->n_router_dns; i++)
403 if (in6_addr_is_null(&link->network->router_dns[i])) {
404 if (in6_addr_is_set(&link->ipv6ll_address))
405 *(p++) = link->ipv6ll_address;
406 } else
407 *(p++) = link->network->router_dns[i];
408
409 n_dns = p - dns;
410
411 goto set_dns;
412 }
413
414 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
415 if (r > 0)
416 goto set_dns;
417
418 if (uplink) {
419 assert(uplink->network);
420
421 r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
422 if (r > 0)
423 goto set_dns;
424 }
425
426 return 0;
427
428 set_dns:
429 return sd_radv_set_rdnss(link->radv,
430 link->network->router_dns_lifetime_usec,
431 dns, n_dns);
432 }
433
434 static int radv_set_domains(Link *link, Link *uplink) {
435 _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
436 OrderedSet *search_domains;
437
438 if (!link->network->router_emit_domains)
439 return 0;
440
441 search_domains = link->network->router_search_domains;
442
443 if (search_domains)
444 goto set_domains;
445
446 search_domains = link->network->search_domains;
447 if (search_domains)
448 goto set_domains;
449
450 if (uplink) {
451 assert(uplink->network);
452
453 search_domains = uplink->network->search_domains;
454 if (search_domains)
455 goto set_domains;
456 }
457
458 return 0;
459
460 set_domains:
461 s = ordered_set_get_strv(search_domains);
462 if (!s)
463 return log_oom();
464
465 return sd_radv_set_dnssl(link->radv,
466 link->network->router_dns_lifetime_usec,
467 s);
468
469 }
470
471 static int radv_find_uplink(Link *link, Link **ret) {
472 int r;
473
474 assert(link);
475
476 if (link->network->router_uplink_name)
477 return link_get_by_name(link->manager, link->network->router_uplink_name, ret);
478
479 if (link->network->router_uplink_index > 0)
480 return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
481
482 if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
483 if (link_dhcp_pd_is_enabled(link))
484 r = dhcp_pd_find_uplink(link, ret); /* When DHCP-PD is enabled, use its uplink. */
485 else
486 r = manager_find_uplink(link->manager, AF_INET6, link, ret);
487 if (r < 0)
488 /* It is not necessary to propagate error in automatic selection. */
489 *ret = NULL;
490 return 0;
491 }
492
493 *ret = NULL;
494 return 0;
495 }
496
497 static int radv_configure(Link *link) {
498 Link *uplink = NULL;
499 RoutePrefix *q;
500 pref64Prefix *n;
501 Prefix *p;
502 int r;
503
504 assert(link);
505 assert(link->network);
506
507 if (link->radv)
508 return -EBUSY;
509
510 r = sd_radv_new(&link->radv);
511 if (r < 0)
512 return r;
513
514 r = sd_radv_attach_event(link->radv, link->manager->event, 0);
515 if (r < 0)
516 return r;
517
518 if (link->hw_addr.length == ETH_ALEN) {
519 r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
520 if (r < 0)
521 return r;
522 }
523
524 r = sd_radv_set_ifindex(link->radv, link->ifindex);
525 if (r < 0)
526 return r;
527
528 r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
529 if (r < 0)
530 return r;
531
532 r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
533 if (r < 0)
534 return r;
535
536 r = sd_radv_set_router_lifetime(link->radv, link->network->router_lifetime_usec);
537 if (r < 0)
538 return r;
539
540 r = sd_radv_set_hop_limit(link->radv, link->network->router_hop_limit);
541 if (r < 0)
542 return r;
543
544 r = sd_radv_set_preference(link->radv, link->network->router_preference);
545 if (r < 0)
546 return r;
547
548 r = sd_radv_set_reachable_time(link->radv, link->network->router_reachable_usec);
549 if (r < 0)
550 return r;
551
552 r = sd_radv_set_retransmit(link->radv, link->network->router_retransmit_usec);
553 if (r < 0)
554 return r;
555
556 HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
557 r = radv_set_prefix(link, p);
558 if (r < 0 && r != -EEXIST)
559 return r;
560 }
561
562 HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
563 r = radv_set_route_prefix(link, q);
564 if (r < 0 && r != -EEXIST)
565 return r;
566 }
567
568 HASHMAP_FOREACH(n, link->network->pref64_prefixes_by_section) {
569 r = radv_set_pref64_prefix(link, n);
570 if (r < 0 && r != -EEXIST)
571 return r;
572 }
573
574 (void) radv_find_uplink(link, &uplink);
575
576 r = radv_set_dns(link, uplink);
577 if (r < 0)
578 return log_link_debug_errno(link, r, "Could not set RA DNS: %m");
579
580 r = radv_set_domains(link, uplink);
581 if (r < 0)
582 return log_link_debug_errno(link, r, "Could not set RA Domains: %m");
583
584 r = sd_radv_set_home_agent_information(link->radv, link->network->router_home_agent_information);
585 if (r < 0)
586 return r;
587
588 r = sd_radv_set_home_agent_preference(link->radv, link->network->router_home_agent_preference);
589 if (r < 0)
590 return r;
591
592 r = sd_radv_set_home_agent_lifetime(link->radv, link->network->home_agent_lifetime_usec);
593 if (r < 0)
594 return r;
595
596 return 0;
597 }
598
599 int radv_update_mac(Link *link) {
600 assert(link);
601
602 if (!link->radv)
603 return 0;
604
605 if (link->hw_addr.length != ETH_ALEN)
606 return 0;
607
608 return sd_radv_set_mac(link->radv, &link->hw_addr.ether);
609 }
610
611 static int radv_is_ready_to_configure(Link *link) {
612 bool needs_uplink = false;
613 int r;
614
615 assert(link);
616 assert(link->network);
617
618 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
619 return false;
620
621 if (in6_addr_is_null(&link->ipv6ll_address))
622 return false;
623
624 if (link->hw_addr.length != ETH_ALEN || hw_addr_is_null(&link->hw_addr))
625 return false;
626
627 if (link->network->router_emit_dns && !link->network->router_dns) {
628 _cleanup_free_ struct in6_addr *dns = NULL;
629 size_t n_dns;
630
631 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
632 if (r < 0)
633 return r;
634
635 needs_uplink = r == 0;
636 }
637
638 if (link->network->router_emit_domains &&
639 !link->network->router_search_domains &&
640 !link->network->search_domains)
641 needs_uplink = true;
642
643 if (needs_uplink) {
644 Link *uplink = NULL;
645
646 if (radv_find_uplink(link, &uplink) < 0)
647 return false;
648
649 if (uplink && !uplink->network)
650 return false;
651 }
652
653 return true;
654 }
655
656 static int radv_process_request(Request *req, Link *link, void *userdata) {
657 int r;
658
659 assert(link);
660
661 r = radv_is_ready_to_configure(link);
662 if (r <= 0)
663 return r;
664
665 r = radv_configure(link);
666 if (r < 0)
667 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m");
668
669 if (link_has_carrier(link)) {
670 r = radv_start(link);
671 if (r < 0)
672 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m");
673 }
674
675 log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.",
676 link_has_carrier(link) ? " and started" : "");
677 return 1;
678 }
679
680 int link_request_radv(Link *link) {
681 int r;
682
683 assert(link);
684
685 if (!link_radv_enabled(link))
686 return 0;
687
688 if (link->radv)
689 return 0;
690
691 r = link_queue_request(link, REQUEST_TYPE_RADV, radv_process_request, NULL);
692 if (r < 0)
693 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
694
695 log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
696 return 0;
697 }
698
699 int radv_start(Link *link) {
700 int r;
701
702 assert(link);
703 assert(link->network);
704
705 if (!link->radv)
706 return 0;
707
708 if (!link_has_carrier(link))
709 return 0;
710
711 if (in6_addr_is_null(&link->ipv6ll_address))
712 return 0;
713
714 if (sd_radv_is_running(link->radv))
715 return 0;
716
717 if (link->network->dhcp_pd_announce) {
718 r = dhcp_request_prefix_delegation(link);
719 if (r < 0)
720 return log_link_debug_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m");
721 }
722
723 r = sd_radv_set_link_local_address(link->radv, &link->ipv6ll_address);
724 if (r < 0)
725 return r;
726
727 log_link_debug(link, "Starting IPv6 Router Advertisements");
728 return sd_radv_start(link->radv);
729 }
730
731 int radv_add_prefix(
732 Link *link,
733 const struct in6_addr *prefix,
734 uint8_t prefix_len,
735 usec_t lifetime_preferred_usec,
736 usec_t lifetime_valid_usec) {
737
738 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
739 int r;
740
741 assert(link);
742
743 if (!link->radv)
744 return 0;
745
746 r = sd_radv_prefix_new(&p);
747 if (r < 0)
748 return r;
749
750 r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
751 if (r < 0)
752 return r;
753
754 r = sd_radv_prefix_set_preferred_lifetime(p, RADV_DEFAULT_PREFERRED_LIFETIME_USEC, lifetime_preferred_usec);
755 if (r < 0)
756 return r;
757
758 r = sd_radv_prefix_set_valid_lifetime(p, RADV_DEFAULT_VALID_LIFETIME_USEC, lifetime_valid_usec);
759 if (r < 0)
760 return r;
761
762 r = sd_radv_add_prefix(link->radv, p);
763 if (r == -EEXIST)
764 return 0;
765 if (r < 0)
766 return r;
767
768 if (sd_radv_is_running(link->radv)) {
769 /* Announce updated prefixe now. */
770 r = sd_radv_send(link->radv);
771 if (r < 0)
772 return r;
773 }
774
775 return 0;
776 }
777
778 static int prefix_section_verify(Prefix *p) {
779 assert(p);
780
781 if (section_is_invalid(p->section))
782 return -EINVAL;
783
784 if (in6_addr_is_null(&p->prefix))
785 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
786 "%s: [IPv6Prefix] section without Prefix= field configured, "
787 "or specified prefix is the null address. "
788 "Ignoring [IPv6Prefix] section from line %u.",
789 p->section->filename, p->section->line);
790
791 if (p->prefixlen < 3 || p->prefixlen > 128)
792 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
793 "%s: Invalid prefix length %u is specified in [IPv6Prefix] section. "
794 "Valid range is 3…128. Ignoring [IPv6Prefix] section from line %u.",
795 p->section->filename, p->prefixlen, p->section->line);
796
797 if (p->prefixlen > 64) {
798 log_info("%s:%u: Unusual prefix length %u (> 64) is specified in [IPv6Prefix] section from line %s%s.",
799 p->section->filename, p->section->line,
800 p->prefixlen,
801 p->assign ? ", refusing to assign an address in " : "",
802 p->assign ? IN6_ADDR_PREFIX_TO_STRING(&p->prefix, p->prefixlen) : "");
803
804 p->assign = false;
805 }
806
807 if (p->preferred_lifetime > p->valid_lifetime)
808 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
809 "%s: The preferred lifetime %s is longer than the valid lifetime %s. "
810 "Ignoring [IPv6Prefix] section from line %u.",
811 p->section->filename,
812 FORMAT_TIMESPAN(p->preferred_lifetime, USEC_PER_SEC),
813 FORMAT_TIMESPAN(p->valid_lifetime, USEC_PER_SEC),
814 p->section->line);
815
816 return 0;
817 }
818
819 static int route_prefix_section_verify(RoutePrefix *p) {
820 if (section_is_invalid(p->section))
821 return -EINVAL;
822
823 if (p->prefixlen > 128)
824 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
825 "%s: Invalid prefix length %u is specified in [IPv6RoutePrefix] section. "
826 "Valid range is 0…128. Ignoring [IPv6RoutePrefix] section from line %u.",
827 p->section->filename, p->prefixlen, p->section->line);
828
829 return 0;
830 }
831
832 void network_adjust_radv(Network *network) {
833 assert(network);
834
835 /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
836
837 if (network->dhcp_pd < 0)
838 /* For backward compatibility. */
839 network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
840
841 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
842 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
843 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. "
844 "Disabling IPv6PrefixDelegation=.", network->filename);
845
846 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
847 }
848
849 if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
850 network->n_router_dns = 0;
851 network->router_dns = mfree(network->router_dns);
852 network->router_search_domains = ordered_set_free(network->router_search_domains);
853 }
854
855 if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
856 network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
857 network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
858 network->pref64_prefixes_by_section = hashmap_free_with_destructor(network->pref64_prefixes_by_section, pref64_prefix_free);
859 }
860
861 if (!network->router_prefix_delegation)
862 return;
863
864 /* Below, let's verify router settings, if enabled. */
865
866 if (network->router_lifetime_usec == 0 && network->router_preference != SD_NDISC_PREFERENCE_MEDIUM)
867 /* RFC 4191, Section 2.2,
868 * If the Router Lifetime is zero, the preference value MUST be set to (00) by the sender.
869 *
870 * Note, radv_send_router() gracefully handle that. So, it is not necessary to refuse, but
871 * let's warn about that. */
872 log_notice("%s: RouterPreference=%s specified with RouterLifetimeSec=0, ignoring RouterPreference= setting.",
873 network->filename, ndisc_router_preference_to_string(network->router_preference));
874
875 Prefix *prefix;
876 HASHMAP_FOREACH(prefix, network->prefixes_by_section)
877 if (prefix_section_verify(prefix) < 0)
878 prefix_free(prefix);
879
880
881 RoutePrefix *route;
882 HASHMAP_FOREACH(route, network->route_prefixes_by_section)
883 if (route_prefix_section_verify(route) < 0)
884 route_prefix_free(route);
885
886 pref64Prefix *pref64;
887 HASHMAP_FOREACH(pref64, network->pref64_prefixes_by_section)
888 if (section_is_invalid(pref64->section))
889 pref64_prefix_free(pref64);
890 }
891
892 int config_parse_prefix(
893 const char *unit,
894 const char *filename,
895 unsigned line,
896 const char *section,
897 unsigned section_line,
898 const char *lvalue,
899 int ltype,
900 const char *rvalue,
901 void *data,
902 void *userdata) {
903
904 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
905 Network *network = ASSERT_PTR(userdata);
906 union in_addr_union a;
907 int r;
908
909 assert(filename);
910 assert(section);
911 assert(lvalue);
912 assert(rvalue);
913
914 r = prefix_new_static(network, filename, section_line, &p);
915 if (r < 0)
916 return log_oom();
917
918 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
919 if (r < 0) {
920 log_syntax(unit, LOG_WARNING, filename, line, r,
921 "Prefix is invalid, ignoring assignment: %s", rvalue);
922 return 0;
923 }
924
925 (void) in6_addr_mask(&a.in6, p->prefixlen);
926 p->prefix = a.in6;
927
928 TAKE_PTR(p);
929 return 0;
930 }
931
932 int config_parse_prefix_boolean(
933 const char *unit,
934 const char *filename,
935 unsigned line,
936 const char *section,
937 unsigned section_line,
938 const char *lvalue,
939 int ltype,
940 const char *rvalue,
941 void *data,
942 void *userdata) {
943
944 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
945 Network *network = ASSERT_PTR(userdata);
946 int r;
947
948 assert(filename);
949 assert(section);
950 assert(lvalue);
951 assert(rvalue);
952
953 r = prefix_new_static(network, filename, section_line, &p);
954 if (r < 0)
955 return log_oom();
956
957 r = parse_boolean(rvalue);
958 if (r < 0) {
959 log_syntax(unit, LOG_WARNING, filename, line, r,
960 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
961 return 0;
962 }
963
964 if (ltype != 0)
965 SET_FLAG(p->flags, ltype, r);
966 else {
967 assert(streq(lvalue, "Assign"));
968 p->assign = r;
969 }
970
971 TAKE_PTR(p);
972 return 0;
973 }
974
975 int config_parse_prefix_lifetime(
976 const char *unit,
977 const char *filename,
978 unsigned line,
979 const char *section,
980 unsigned section_line,
981 const char *lvalue,
982 int ltype,
983 const char *rvalue,
984 void *data,
985 void *userdata) {
986
987 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
988 Network *network = ASSERT_PTR(userdata);
989 usec_t usec;
990 int r;
991
992 assert(filename);
993 assert(section);
994 assert(lvalue);
995 assert(rvalue);
996
997 r = prefix_new_static(network, filename, section_line, &p);
998 if (r < 0)
999 return log_oom();
1000
1001 r = parse_sec(rvalue, &usec);
1002 if (r < 0) {
1003 log_syntax(unit, LOG_WARNING, filename, line, r,
1004 "Lifetime is invalid, ignoring assignment: %s", rvalue);
1005 return 0;
1006 }
1007
1008 if (usec != USEC_INFINITY && DIV_ROUND_UP(usec, USEC_PER_SEC) >= UINT32_MAX) {
1009 log_syntax(unit, LOG_WARNING, filename, line, 0,
1010 "Lifetime is too long, ignoring assignment: %s", rvalue);
1011 return 0;
1012 }
1013
1014 if (streq(lvalue, "PreferredLifetimeSec"))
1015 p->preferred_lifetime = usec;
1016 else if (streq(lvalue, "ValidLifetimeSec"))
1017 p->valid_lifetime = usec;
1018 else
1019 assert_not_reached();
1020
1021 TAKE_PTR(p);
1022 return 0;
1023 }
1024
1025 int config_parse_prefix_metric(
1026 const char *unit,
1027 const char *filename,
1028 unsigned line,
1029 const char *section,
1030 unsigned section_line,
1031 const char *lvalue,
1032 int ltype,
1033 const char *rvalue,
1034 void *data,
1035 void *userdata) {
1036
1037 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
1038 Network *network = ASSERT_PTR(userdata);
1039 int r;
1040
1041 assert(filename);
1042 assert(section);
1043 assert(lvalue);
1044 assert(rvalue);
1045
1046 r = prefix_new_static(network, filename, section_line, &p);
1047 if (r < 0)
1048 return log_oom();
1049
1050 r = safe_atou32(rvalue, &p->route_metric);
1051 if (r < 0) {
1052 log_syntax(unit, LOG_WARNING, filename, line, r,
1053 "Failed to parse %s=, ignoring assignment: %s",
1054 lvalue, rvalue);
1055 return 0;
1056 }
1057
1058 TAKE_PTR(p);
1059 return 0;
1060 }
1061
1062 int config_parse_prefix_token(
1063 const char *unit,
1064 const char *filename,
1065 unsigned line,
1066 const char *section,
1067 unsigned section_line,
1068 const char *lvalue,
1069 int ltype,
1070 const char *rvalue,
1071 void *data,
1072 void *userdata) {
1073
1074 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
1075 Network *network = ASSERT_PTR(userdata);
1076 int r;
1077
1078 assert(filename);
1079 assert(section);
1080 assert(lvalue);
1081 assert(rvalue);
1082
1083 r = prefix_new_static(network, filename, section_line, &p);
1084 if (r < 0)
1085 return log_oom();
1086
1087 r = config_parse_address_generation_type(unit, filename, line, section, section_line,
1088 lvalue, ltype, rvalue, &p->tokens, userdata);
1089 if (r < 0)
1090 return r;
1091
1092 TAKE_PTR(p);
1093 return 0;
1094 }
1095
1096 int config_parse_route_prefix(
1097 const char *unit,
1098 const char *filename,
1099 unsigned line,
1100 const char *section,
1101 unsigned section_line,
1102 const char *lvalue,
1103 int ltype,
1104 const char *rvalue,
1105 void *data,
1106 void *userdata) {
1107
1108 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
1109 Network *network = ASSERT_PTR(userdata);
1110 union in_addr_union a;
1111 int r;
1112
1113 assert(filename);
1114 assert(section);
1115 assert(lvalue);
1116 assert(rvalue);
1117
1118 r = route_prefix_new_static(network, filename, section_line, &p);
1119 if (r < 0)
1120 return log_oom();
1121
1122 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
1123 if (r < 0) {
1124 log_syntax(unit, LOG_WARNING, filename, line, r,
1125 "Route prefix is invalid, ignoring assignment: %s", rvalue);
1126 return 0;
1127 }
1128
1129 (void) in6_addr_mask(&a.in6, p->prefixlen);
1130 p->prefix = a.in6;
1131
1132 TAKE_PTR(p);
1133 return 0;
1134 }
1135
1136 int config_parse_route_prefix_lifetime(
1137 const char *unit,
1138 const char *filename,
1139 unsigned line,
1140 const char *section,
1141 unsigned section_line,
1142 const char *lvalue,
1143 int ltype,
1144 const char *rvalue,
1145 void *data,
1146 void *userdata) {
1147
1148 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
1149 Network *network = ASSERT_PTR(userdata);
1150 usec_t usec;
1151 int r;
1152
1153 assert(filename);
1154 assert(section);
1155 assert(lvalue);
1156 assert(rvalue);
1157
1158 r = route_prefix_new_static(network, filename, section_line, &p);
1159 if (r < 0)
1160 return log_oom();
1161
1162 r = parse_sec(rvalue, &usec);
1163 if (r < 0) {
1164 log_syntax(unit, LOG_WARNING, filename, line, r,
1165 "Route lifetime is invalid, ignoring assignment: %s", rvalue);
1166 return 0;
1167 }
1168
1169 if (usec != USEC_INFINITY && DIV_ROUND_UP(usec, USEC_PER_SEC) >= UINT32_MAX) {
1170 log_syntax(unit, LOG_WARNING, filename, line, 0,
1171 "Lifetime is too long, ignoring assignment: %s", rvalue);
1172 return 0;
1173 }
1174
1175 p->lifetime = usec;
1176
1177 TAKE_PTR(p);
1178 return 0;
1179 }
1180
1181 int config_parse_pref64_prefix(
1182 const char *unit,
1183 const char *filename,
1184 unsigned line,
1185 const char *section,
1186 unsigned section_line,
1187 const char *lvalue,
1188 int ltype,
1189 const char *rvalue,
1190 void *data,
1191 void *userdata) {
1192
1193 _cleanup_(pref64_prefix_free_or_set_invalidp) pref64Prefix *p = NULL;
1194 Network *network = ASSERT_PTR(userdata);
1195 union in_addr_union a;
1196 uint8_t prefixlen;
1197 int r;
1198
1199 assert(filename);
1200 assert(section);
1201 assert(lvalue);
1202 assert(rvalue);
1203
1204 r = pref64_prefix_new_static(network, filename, section_line, &p);
1205 if (r < 0)
1206 return log_oom();
1207
1208 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
1209 if (r < 0) {
1210 log_syntax(unit, LOG_WARNING, filename, line, r,
1211 "PREF64 prefix is invalid, ignoring assignment: %s", rvalue);
1212 return 0;
1213 }
1214
1215 if (!IN_SET(prefixlen, 96, 64, 56, 48, 40, 32)) {
1216 log_syntax(unit, LOG_WARNING, filename, line, 0,
1217 "PREF64 prefixlen is invalid, ignoring assignment: %s", rvalue);
1218 return 0;
1219 }
1220
1221 (void) in6_addr_mask(&a.in6, prefixlen);
1222 p->prefix = a.in6;
1223 p->prefixlen = prefixlen;
1224
1225 TAKE_PTR(p);
1226 return 0;
1227 }
1228
1229 int config_parse_pref64_prefix_lifetime(
1230 const char *unit,
1231 const char *filename,
1232 unsigned line,
1233 const char *section,
1234 unsigned section_line,
1235 const char *lvalue,
1236 int ltype,
1237 const char *rvalue,
1238 void *data,
1239 void *userdata) {
1240
1241 _cleanup_(pref64_prefix_free_or_set_invalidp) pref64Prefix *p = NULL;
1242 Network *network = ASSERT_PTR(userdata);
1243 usec_t usec;
1244 int r;
1245
1246 assert(filename);
1247 assert(section);
1248 assert(lvalue);
1249 assert(rvalue);
1250
1251 r = pref64_prefix_new_static(network, filename, section_line, &p);
1252 if (r < 0)
1253 return log_oom();
1254
1255 r = parse_sec(rvalue, &usec);
1256 if (r < 0) {
1257 log_syntax(unit, LOG_WARNING, filename, line, r,
1258 "PREF64 lifetime is invalid, ignoring assignment: %s", rvalue);
1259 return 0;
1260 }
1261
1262 if (usec == USEC_INFINITY || DIV_ROUND_UP(usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13) {
1263 log_syntax(unit, LOG_WARNING, filename, line, 0,
1264 "PREF64 lifetime is too long, ignoring assignment: %s", rvalue);
1265 return 0;
1266 }
1267
1268 p->lifetime = usec;
1269
1270 TAKE_PTR(p);
1271 return 0;
1272 }
1273
1274 int config_parse_radv_dns(
1275 const char *unit,
1276 const char *filename,
1277 unsigned line,
1278 const char *section,
1279 unsigned section_line,
1280 const char *lvalue,
1281 int ltype,
1282 const char *rvalue,
1283 void *data,
1284 void *userdata) {
1285
1286 Network *n = data;
1287 int r;
1288
1289 assert(filename);
1290 assert(lvalue);
1291 assert(rvalue);
1292
1293 if (isempty(rvalue)) {
1294 n->n_router_dns = 0;
1295 n->router_dns = mfree(n->router_dns);
1296 return 0;
1297 }
1298
1299 for (const char *p = rvalue;;) {
1300 _cleanup_free_ char *w = NULL;
1301 union in_addr_union a;
1302
1303 r = extract_first_word(&p, &w, NULL, 0);
1304 if (r == -ENOMEM)
1305 return log_oom();
1306 if (r < 0) {
1307 log_syntax(unit, LOG_WARNING, filename, line, r,
1308 "Failed to extract word, ignoring: %s", rvalue);
1309 return 0;
1310 }
1311 if (r == 0)
1312 return 0;
1313
1314 if (streq(w, "_link_local"))
1315 a = IN_ADDR_NULL;
1316 else {
1317 r = in_addr_from_string(AF_INET6, w, &a);
1318 if (r < 0) {
1319 log_syntax(unit, LOG_WARNING, filename, line, r,
1320 "Failed to parse DNS server address, ignoring: %s", w);
1321 continue;
1322 }
1323
1324 if (in_addr_is_null(AF_INET6, &a)) {
1325 log_syntax(unit, LOG_WARNING, filename, line, 0,
1326 "DNS server address is null, ignoring: %s", w);
1327 continue;
1328 }
1329 }
1330
1331 struct in6_addr *m;
1332 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1333 if (!m)
1334 return log_oom();
1335
1336 m[n->n_router_dns++] = a.in6;
1337 n->router_dns = m;
1338 }
1339 }
1340
1341 int config_parse_radv_search_domains(
1342 const char *unit,
1343 const char *filename,
1344 unsigned line,
1345 const char *section,
1346 unsigned section_line,
1347 const char *lvalue,
1348 int ltype,
1349 const char *rvalue,
1350 void *data,
1351 void *userdata) {
1352
1353 Network *n = data;
1354 int r;
1355
1356 assert(filename);
1357 assert(lvalue);
1358 assert(rvalue);
1359
1360 if (isempty(rvalue)) {
1361 n->router_search_domains = ordered_set_free(n->router_search_domains);
1362 return 0;
1363 }
1364
1365 for (const char *p = rvalue;;) {
1366 _cleanup_free_ char *w = NULL, *idna = NULL;
1367
1368 r = extract_first_word(&p, &w, NULL, 0);
1369 if (r == -ENOMEM)
1370 return log_oom();
1371 if (r < 0) {
1372 log_syntax(unit, LOG_WARNING, filename, line, r,
1373 "Failed to extract word, ignoring: %s", rvalue);
1374 return 0;
1375 }
1376 if (r == 0)
1377 return 0;
1378
1379 r = dns_name_apply_idna(w, &idna);
1380 if (r < 0) {
1381 log_syntax(unit, LOG_WARNING, filename, line, r,
1382 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1383 continue;
1384 } else if (r == 0)
1385 /* transfer ownership to simplify subsequent operations */
1386 idna = TAKE_PTR(w);
1387
1388 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
1389 if (r < 0)
1390 return log_oom();
1391
1392 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1393 if (r < 0)
1394 return log_oom();
1395 }
1396 }
1397
1398 static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
1399 [RADV_PREFIX_DELEGATION_NONE] = "no",
1400 [RADV_PREFIX_DELEGATION_STATIC] = "static",
1401 [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
1402 [RADV_PREFIX_DELEGATION_BOTH] = "yes",
1403 };
1404
1405 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
1406 radv_prefix_delegation,
1407 RADVPrefixDelegation,
1408 RADV_PREFIX_DELEGATION_BOTH);
1409
1410 int config_parse_router_prefix_delegation(
1411 const char *unit,
1412 const char *filename,
1413 unsigned line,
1414 const char *section,
1415 unsigned section_line,
1416 const char *lvalue,
1417 int ltype,
1418 const char *rvalue,
1419 void *data,
1420 void *userdata) {
1421
1422 RADVPrefixDelegation val, *ra = ASSERT_PTR(data);
1423 int r;
1424
1425 assert(filename);
1426 assert(lvalue);
1427 assert(rvalue);
1428
1429 if (streq(lvalue, "IPv6SendRA")) {
1430 r = parse_boolean(rvalue);
1431 if (r < 0) {
1432 log_syntax(unit, LOG_WARNING, filename, line, r,
1433 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1434 return 0;
1435 }
1436
1437 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
1438 * need to explicitly enable DHCPv6PrefixDelegation=. */
1439 *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
1440 return 0;
1441 }
1442
1443 /* For backward compatibility */
1444 val = radv_prefix_delegation_from_string(rvalue);
1445 if (val < 0) {
1446 log_syntax(unit, LOG_WARNING, filename, line, val,
1447 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1448 return 0;
1449 }
1450
1451 *ra = val;
1452 return 0;
1453 }
1454
1455 int config_parse_router_lifetime(
1456 const char *unit,
1457 const char *filename,
1458 unsigned line,
1459 const char *section,
1460 unsigned section_line,
1461 const char *lvalue,
1462 int ltype,
1463 const char *rvalue,
1464 void *data,
1465 void *userdata) {
1466
1467 usec_t usec, *lifetime = ASSERT_PTR(data);
1468 int r;
1469
1470 assert(filename);
1471 assert(section);
1472 assert(lvalue);
1473 assert(rvalue);
1474
1475 if (isempty(rvalue)) {
1476 *lifetime = RADV_DEFAULT_ROUTER_LIFETIME_USEC;
1477 return 0;
1478 }
1479
1480 r = parse_sec(rvalue, &usec);
1481 if (r < 0) {
1482 log_syntax(unit, LOG_WARNING, filename, line, r,
1483 "Failed to parse router lifetime, ignoring assignment: %s", rvalue);
1484 return 0;
1485 }
1486 if (usec > 0) {
1487 if (usec < RADV_MIN_ROUTER_LIFETIME_USEC) {
1488 log_syntax(unit, LOG_WARNING, filename, line, 0,
1489 "Router lifetime %s is too short, using %s.",
1490 FORMAT_TIMESPAN(usec, USEC_PER_SEC),
1491 FORMAT_TIMESPAN(RADV_MIN_ROUTER_LIFETIME_USEC, USEC_PER_SEC));
1492 usec = RADV_MIN_ROUTER_LIFETIME_USEC;
1493 } else if (usec > RADV_MAX_ROUTER_LIFETIME_USEC) {
1494 log_syntax(unit, LOG_WARNING, filename, line, 0,
1495 "Router lifetime %s is too large, using %s.",
1496 FORMAT_TIMESPAN(usec, USEC_PER_SEC),
1497 FORMAT_TIMESPAN(RADV_MAX_ROUTER_LIFETIME_USEC, USEC_PER_SEC));
1498 usec = RADV_MAX_ROUTER_LIFETIME_USEC;
1499 }
1500 }
1501
1502 *lifetime = usec;
1503 return 0;
1504 }
1505
1506 int config_parse_router_uint32_msec_usec(
1507 const char *unit,
1508 const char *filename,
1509 unsigned line,
1510 const char *section,
1511 unsigned section_line,
1512 const char *lvalue,
1513 int ltype,
1514 const char *rvalue,
1515 void *data,
1516 void *userdata) {
1517
1518 usec_t usec, *router_usec = ASSERT_PTR(data);
1519 int r;
1520
1521 assert(filename);
1522 assert(section);
1523 assert(lvalue);
1524 assert(rvalue);
1525
1526 if (isempty(rvalue)) {
1527 *router_usec = 0;
1528 return 0;
1529 }
1530
1531 r = parse_sec(rvalue, &usec);
1532 if (r < 0) {
1533 log_syntax(unit, LOG_WARNING, filename, line, r,
1534 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1535 return 0;
1536 }
1537
1538 if (usec != USEC_INFINITY &&
1539 usec > RADV_MAX_UINT32_MSEC_USEC) {
1540 log_syntax(unit, LOG_WARNING, filename, line, 0,
1541 "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
1542 return 0;
1543 }
1544
1545 *router_usec = usec;
1546 return 0;
1547 }
1548
1549 int config_parse_router_preference(
1550 const char *unit,
1551 const char *filename,
1552 unsigned line,
1553 const char *section,
1554 unsigned section_line,
1555 const char *lvalue,
1556 int ltype,
1557 const char *rvalue,
1558 void *data,
1559 void *userdata) {
1560
1561 Network *network = userdata;
1562
1563 assert(filename);
1564 assert(section);
1565 assert(lvalue);
1566 assert(rvalue);
1567 assert(data);
1568
1569 if (streq(rvalue, "high"))
1570 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1571 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1572 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1573 else if (streq(rvalue, "low"))
1574 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1575 else
1576 log_syntax(unit, LOG_WARNING, filename, line, 0,
1577 "Invalid router preference, ignoring assignment: %s", rvalue);
1578
1579 return 0;
1580 }
1581
1582 int config_parse_router_home_agent_lifetime(
1583 const char *unit,
1584 const char *filename,
1585 unsigned line,
1586 const char *section,
1587 unsigned section_line,
1588 const char *lvalue,
1589 int ltype,
1590 const char *rvalue,
1591 void *data,
1592 void *userdata) {
1593
1594 usec_t usec, *home_agent_lifetime_usec = ASSERT_PTR(data);
1595 int r;
1596
1597 assert(filename);
1598 assert(section);
1599 assert(lvalue);
1600 assert(rvalue);
1601
1602 if (isempty(rvalue)) {
1603 *home_agent_lifetime_usec = 0;
1604 return 0;
1605 }
1606
1607 r = parse_sec(rvalue, &usec);
1608 if (r < 0) {
1609 log_syntax(unit, LOG_WARNING, filename, line, r,
1610 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1611 return 0;
1612 }
1613
1614 if (!timestamp_is_set(usec) ||
1615 usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) {
1616 log_syntax(unit, LOG_WARNING, filename, line, 0,
1617 "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
1618 return 0;
1619 }
1620
1621 *home_agent_lifetime_usec = usec;
1622 return 0;
1623 }