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