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