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