]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-radv.c
Merge pull request #32166 from yuwata/network-rfc7217-dad
[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 bool restart;
631 int r;
632
633 assert(link);
634
635 if (!link->radv)
636 return 0;
637
638 if (link->hw_addr.length != ETH_ALEN)
639 return 0;
640
641 restart = sd_radv_is_running(link->radv);
642
643 r = sd_radv_stop(link->radv);
644 if (r < 0)
645 return r;
646
647 r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
648 if (r < 0)
649 return r;
650
651 if (restart) {
652 r = sd_radv_start(link->radv);
653 if (r < 0)
654 return r;
655 }
656
657 return 0;
658 }
659
660 static int radv_is_ready_to_configure(Link *link) {
661 bool needs_uplink = false;
662 int r;
663
664 assert(link);
665 assert(link->network);
666
667 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
668 return false;
669
670 if (in6_addr_is_null(&link->ipv6ll_address))
671 return false;
672
673 if (link->hw_addr.length != ETH_ALEN || hw_addr_is_null(&link->hw_addr))
674 return false;
675
676 if (link->network->router_emit_dns && !link->network->router_dns) {
677 _cleanup_free_ struct in6_addr *dns = NULL;
678 size_t n_dns;
679
680 r = network_get_ipv6_dns(link->network, &dns, &n_dns);
681 if (r < 0)
682 return r;
683
684 needs_uplink = r == 0;
685 }
686
687 if (link->network->router_emit_domains &&
688 !link->network->router_search_domains &&
689 !link->network->search_domains)
690 needs_uplink = true;
691
692 if (needs_uplink) {
693 Link *uplink = NULL;
694
695 if (radv_find_uplink(link, &uplink) < 0)
696 return false;
697
698 if (uplink && !uplink->network)
699 return false;
700 }
701
702 return true;
703 }
704
705 static int radv_process_request(Request *req, Link *link, void *userdata) {
706 int r;
707
708 assert(link);
709
710 r = radv_is_ready_to_configure(link);
711 if (r <= 0)
712 return r;
713
714 r = radv_configure(link);
715 if (r < 0)
716 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Advertisement engine: %m");
717
718 if (link_has_carrier(link)) {
719 r = radv_start(link);
720 if (r < 0)
721 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Advertisement engine: %m");
722 }
723
724 log_link_debug(link, "IPv6 Router Advertisement engine is configured%s.",
725 link_has_carrier(link) ? " and started" : "");
726 return 1;
727 }
728
729 int link_request_radv(Link *link) {
730 int r;
731
732 assert(link);
733
734 if (!link_radv_enabled(link))
735 return 0;
736
737 if (link->radv)
738 return 0;
739
740 r = link_queue_request(link, REQUEST_TYPE_RADV, radv_process_request, NULL);
741 if (r < 0)
742 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m");
743
744 log_link_debug(link, "Requested configuring of the IPv6 Router Advertisement engine.");
745 return 0;
746 }
747
748 int radv_start(Link *link) {
749 int r;
750
751 assert(link);
752 assert(link->network);
753
754 if (!link->radv)
755 return 0;
756
757 if (!link_has_carrier(link))
758 return 0;
759
760 if (in6_addr_is_null(&link->ipv6ll_address))
761 return 0;
762
763 if (sd_radv_is_running(link->radv))
764 return 0;
765
766 if (link->network->dhcp_pd_announce) {
767 r = dhcp_request_prefix_delegation(link);
768 if (r < 0)
769 return log_link_debug_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m");
770 }
771
772 log_link_debug(link, "Starting IPv6 Router Advertisements");
773 return sd_radv_start(link->radv);
774 }
775
776 int radv_add_prefix(
777 Link *link,
778 const struct in6_addr *prefix,
779 uint8_t prefix_len,
780 usec_t lifetime_preferred_usec,
781 usec_t lifetime_valid_usec) {
782
783 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
784 int r;
785
786 assert(link);
787
788 if (!link->radv)
789 return 0;
790
791 r = sd_radv_prefix_new(&p);
792 if (r < 0)
793 return r;
794
795 r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
796 if (r < 0)
797 return r;
798
799 r = sd_radv_prefix_set_preferred_lifetime(p, RADV_DEFAULT_PREFERRED_LIFETIME_USEC, lifetime_preferred_usec);
800 if (r < 0)
801 return r;
802
803 r = sd_radv_prefix_set_valid_lifetime(p, RADV_DEFAULT_VALID_LIFETIME_USEC, lifetime_valid_usec);
804 if (r < 0)
805 return r;
806
807 r = sd_radv_add_prefix(link->radv, p);
808 if (r < 0 && r != -EEXIST)
809 return r;
810
811 return 0;
812 }
813
814 static int prefix_section_verify(Prefix *p) {
815 assert(p);
816
817 if (section_is_invalid(p->section))
818 return -EINVAL;
819
820 if (in6_addr_is_null(&p->prefix))
821 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
822 "%s: [IPv6Prefix] section without Prefix= field configured, "
823 "or specified prefix is the null address. "
824 "Ignoring [IPv6Prefix] section from line %u.",
825 p->section->filename, p->section->line);
826
827 if (p->prefixlen < 3 || p->prefixlen > 128)
828 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
829 "%s: Invalid prefix length %u is specified in [IPv6Prefix] section. "
830 "Valid range is 3…128. Ignoring [IPv6Prefix] section from line %u.",
831 p->section->filename, p->prefixlen, p->section->line);
832
833 if (p->prefixlen > 64) {
834 log_info("%s:%u: Unusual prefix length %u (> 64) is specified in [IPv6Prefix] section from line %s%s.",
835 p->section->filename, p->section->line,
836 p->prefixlen,
837 p->assign ? ", refusing to assign an address in " : "",
838 p->assign ? IN6_ADDR_PREFIX_TO_STRING(&p->prefix, p->prefixlen) : "");
839
840 p->assign = false;
841 }
842
843 if (p->preferred_lifetime > p->valid_lifetime)
844 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
845 "%s: The preferred lifetime %s is longer than the valid lifetime %s. "
846 "Ignoring [IPv6Prefix] section from line %u.",
847 p->section->filename,
848 FORMAT_TIMESPAN(p->preferred_lifetime, USEC_PER_SEC),
849 FORMAT_TIMESPAN(p->valid_lifetime, USEC_PER_SEC),
850 p->section->line);
851
852 return 0;
853 }
854
855 void network_drop_invalid_prefixes(Network *network) {
856 Prefix *p;
857
858 assert(network);
859
860 HASHMAP_FOREACH(p, network->prefixes_by_section)
861 if (prefix_section_verify(p) < 0)
862 prefix_free(p);
863 }
864
865 static int route_prefix_section_verify(RoutePrefix *p) {
866 if (section_is_invalid(p->section))
867 return -EINVAL;
868
869 if (p->prefixlen > 128)
870 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
871 "%s: Invalid prefix length %u is specified in [IPv6RoutePrefix] section. "
872 "Valid range is 0…128. Ignoring [IPv6RoutePrefix] section from line %u.",
873 p->section->filename, p->prefixlen, p->section->line);
874
875 return 0;
876 }
877
878 void network_drop_invalid_route_prefixes(Network *network) {
879 RoutePrefix *p;
880
881 assert(network);
882
883 HASHMAP_FOREACH(p, network->route_prefixes_by_section)
884 if (route_prefix_section_verify(p) < 0)
885 route_prefix_free(p);
886 }
887
888 void network_drop_invalid_pref64_prefixes(Network *network) {
889 pref64Prefix *p;
890
891 assert(network);
892
893 HASHMAP_FOREACH(p, network->pref64_prefixes_by_section)
894 if (section_is_invalid(p->section))
895 pref64_prefix_free(p);
896 }
897
898 int config_parse_prefix(
899 const char *unit,
900 const char *filename,
901 unsigned line,
902 const char *section,
903 unsigned section_line,
904 const char *lvalue,
905 int ltype,
906 const char *rvalue,
907 void *data,
908 void *userdata) {
909
910 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
911 Network *network = ASSERT_PTR(userdata);
912 union in_addr_union a;
913 int r;
914
915 assert(filename);
916 assert(section);
917 assert(lvalue);
918 assert(rvalue);
919
920 r = prefix_new_static(network, filename, section_line, &p);
921 if (r < 0)
922 return log_oom();
923
924 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
925 if (r < 0) {
926 log_syntax(unit, LOG_WARNING, filename, line, r,
927 "Prefix is invalid, ignoring assignment: %s", rvalue);
928 return 0;
929 }
930
931 (void) in6_addr_mask(&a.in6, p->prefixlen);
932 p->prefix = a.in6;
933
934 TAKE_PTR(p);
935 return 0;
936 }
937
938 int config_parse_prefix_boolean(
939 const char *unit,
940 const char *filename,
941 unsigned line,
942 const char *section,
943 unsigned section_line,
944 const char *lvalue,
945 int ltype,
946 const char *rvalue,
947 void *data,
948 void *userdata) {
949
950 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
951 Network *network = ASSERT_PTR(userdata);
952 int r;
953
954 assert(filename);
955 assert(section);
956 assert(lvalue);
957 assert(rvalue);
958
959 r = prefix_new_static(network, filename, section_line, &p);
960 if (r < 0)
961 return log_oom();
962
963 r = parse_boolean(rvalue);
964 if (r < 0) {
965 log_syntax(unit, LOG_WARNING, filename, line, r,
966 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
967 return 0;
968 }
969
970 if (streq(lvalue, "OnLink"))
971 p->onlink = r;
972 else if (streq(lvalue, "AddressAutoconfiguration"))
973 p->address_auto_configuration = r;
974 else if (streq(lvalue, "Assign"))
975 p->assign = r;
976 else
977 assert_not_reached();
978
979 TAKE_PTR(p);
980 return 0;
981 }
982
983 int config_parse_prefix_lifetime(
984 const char *unit,
985 const char *filename,
986 unsigned line,
987 const char *section,
988 unsigned section_line,
989 const char *lvalue,
990 int ltype,
991 const char *rvalue,
992 void *data,
993 void *userdata) {
994
995 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
996 Network *network = ASSERT_PTR(userdata);
997 usec_t usec;
998 int r;
999
1000 assert(filename);
1001 assert(section);
1002 assert(lvalue);
1003 assert(rvalue);
1004
1005 r = prefix_new_static(network, filename, section_line, &p);
1006 if (r < 0)
1007 return log_oom();
1008
1009 r = parse_sec(rvalue, &usec);
1010 if (r < 0) {
1011 log_syntax(unit, LOG_WARNING, filename, line, r,
1012 "Lifetime is invalid, ignoring assignment: %s", rvalue);
1013 return 0;
1014 }
1015
1016 if (usec != USEC_INFINITY && DIV_ROUND_UP(usec, USEC_PER_SEC) >= UINT32_MAX) {
1017 log_syntax(unit, LOG_WARNING, filename, line, 0,
1018 "Lifetime is too long, ignoring assignment: %s", rvalue);
1019 return 0;
1020 }
1021
1022 if (streq(lvalue, "PreferredLifetimeSec"))
1023 p->preferred_lifetime = usec;
1024 else if (streq(lvalue, "ValidLifetimeSec"))
1025 p->valid_lifetime = usec;
1026 else
1027 assert_not_reached();
1028
1029 TAKE_PTR(p);
1030 return 0;
1031 }
1032
1033 int config_parse_prefix_metric(
1034 const char *unit,
1035 const char *filename,
1036 unsigned line,
1037 const char *section,
1038 unsigned section_line,
1039 const char *lvalue,
1040 int ltype,
1041 const char *rvalue,
1042 void *data,
1043 void *userdata) {
1044
1045 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
1046 Network *network = ASSERT_PTR(userdata);
1047 int r;
1048
1049 assert(filename);
1050 assert(section);
1051 assert(lvalue);
1052 assert(rvalue);
1053
1054 r = prefix_new_static(network, filename, section_line, &p);
1055 if (r < 0)
1056 return log_oom();
1057
1058 r = safe_atou32(rvalue, &p->route_metric);
1059 if (r < 0) {
1060 log_syntax(unit, LOG_WARNING, filename, line, r,
1061 "Failed to parse %s=, ignoring assignment: %s",
1062 lvalue, rvalue);
1063 return 0;
1064 }
1065
1066 TAKE_PTR(p);
1067 return 0;
1068 }
1069
1070 int config_parse_prefix_token(
1071 const char *unit,
1072 const char *filename,
1073 unsigned line,
1074 const char *section,
1075 unsigned section_line,
1076 const char *lvalue,
1077 int ltype,
1078 const char *rvalue,
1079 void *data,
1080 void *userdata) {
1081
1082 _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
1083 Network *network = ASSERT_PTR(userdata);
1084 int r;
1085
1086 assert(filename);
1087 assert(section);
1088 assert(lvalue);
1089 assert(rvalue);
1090
1091 r = prefix_new_static(network, filename, section_line, &p);
1092 if (r < 0)
1093 return log_oom();
1094
1095 r = config_parse_address_generation_type(unit, filename, line, section, section_line,
1096 lvalue, ltype, rvalue, &p->tokens, userdata);
1097 if (r < 0)
1098 return r;
1099
1100 TAKE_PTR(p);
1101 return 0;
1102 }
1103
1104 int config_parse_route_prefix(
1105 const char *unit,
1106 const char *filename,
1107 unsigned line,
1108 const char *section,
1109 unsigned section_line,
1110 const char *lvalue,
1111 int ltype,
1112 const char *rvalue,
1113 void *data,
1114 void *userdata) {
1115
1116 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
1117 Network *network = ASSERT_PTR(userdata);
1118 union in_addr_union a;
1119 int r;
1120
1121 assert(filename);
1122 assert(section);
1123 assert(lvalue);
1124 assert(rvalue);
1125
1126 r = route_prefix_new_static(network, filename, section_line, &p);
1127 if (r < 0)
1128 return log_oom();
1129
1130 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
1131 if (r < 0) {
1132 log_syntax(unit, LOG_WARNING, filename, line, r,
1133 "Route prefix is invalid, ignoring assignment: %s", rvalue);
1134 return 0;
1135 }
1136
1137 (void) in6_addr_mask(&a.in6, p->prefixlen);
1138 p->prefix = a.in6;
1139
1140 TAKE_PTR(p);
1141 return 0;
1142 }
1143
1144 int config_parse_route_prefix_lifetime(
1145 const char *unit,
1146 const char *filename,
1147 unsigned line,
1148 const char *section,
1149 unsigned section_line,
1150 const char *lvalue,
1151 int ltype,
1152 const char *rvalue,
1153 void *data,
1154 void *userdata) {
1155
1156 _cleanup_(route_prefix_free_or_set_invalidp) RoutePrefix *p = NULL;
1157 Network *network = ASSERT_PTR(userdata);
1158 usec_t usec;
1159 int r;
1160
1161 assert(filename);
1162 assert(section);
1163 assert(lvalue);
1164 assert(rvalue);
1165
1166 r = route_prefix_new_static(network, filename, section_line, &p);
1167 if (r < 0)
1168 return log_oom();
1169
1170 r = parse_sec(rvalue, &usec);
1171 if (r < 0) {
1172 log_syntax(unit, LOG_WARNING, filename, line, r,
1173 "Route lifetime is invalid, ignoring assignment: %s", rvalue);
1174 return 0;
1175 }
1176
1177 if (usec != USEC_INFINITY && DIV_ROUND_UP(usec, USEC_PER_SEC) >= UINT32_MAX) {
1178 log_syntax(unit, LOG_WARNING, filename, line, 0,
1179 "Lifetime is too long, ignoring assignment: %s", rvalue);
1180 return 0;
1181 }
1182
1183 p->lifetime = usec;
1184
1185 TAKE_PTR(p);
1186 return 0;
1187 }
1188
1189 int config_parse_pref64_prefix(
1190 const char *unit,
1191 const char *filename,
1192 unsigned line,
1193 const char *section,
1194 unsigned section_line,
1195 const char *lvalue,
1196 int ltype,
1197 const char *rvalue,
1198 void *data,
1199 void *userdata) {
1200
1201 _cleanup_(pref64_prefix_free_or_set_invalidp) pref64Prefix *p = NULL;
1202 Network *network = ASSERT_PTR(userdata);
1203 union in_addr_union a;
1204 uint8_t prefixlen;
1205 int r;
1206
1207 assert(filename);
1208 assert(section);
1209 assert(lvalue);
1210 assert(rvalue);
1211
1212 r = pref64_prefix_new_static(network, filename, section_line, &p);
1213 if (r < 0)
1214 return log_oom();
1215
1216 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
1217 if (r < 0) {
1218 log_syntax(unit, LOG_WARNING, filename, line, r,
1219 "PREF64 prefix is invalid, ignoring assignment: %s", rvalue);
1220 return 0;
1221 }
1222
1223 if (!IN_SET(prefixlen, 96, 64, 56, 48, 40, 32)) {
1224 log_syntax(unit, LOG_WARNING, filename, line, 0,
1225 "PREF64 prefixlen is invalid, ignoring assignment: %s", rvalue);
1226 return 0;
1227 }
1228
1229 (void) in6_addr_mask(&a.in6,prefixlen);
1230 p->prefix = a.in6;
1231 p->prefixlen = prefixlen;
1232
1233 TAKE_PTR(p);
1234 return 0;
1235 }
1236
1237 int config_parse_pref64_prefix_lifetime(
1238 const char *unit,
1239 const char *filename,
1240 unsigned line,
1241 const char *section,
1242 unsigned section_line,
1243 const char *lvalue,
1244 int ltype,
1245 const char *rvalue,
1246 void *data,
1247 void *userdata) {
1248
1249 _cleanup_(pref64_prefix_free_or_set_invalidp) pref64Prefix *p = NULL;
1250 Network *network = ASSERT_PTR(userdata);
1251 usec_t usec;
1252 int r;
1253
1254 assert(filename);
1255 assert(section);
1256 assert(lvalue);
1257 assert(rvalue);
1258
1259 r = pref64_prefix_new_static(network, filename, section_line, &p);
1260 if (r < 0)
1261 return log_oom();
1262
1263 r = parse_sec(rvalue, &usec);
1264 if (r < 0) {
1265 log_syntax(unit, LOG_WARNING, filename, line, r,
1266 "PREF64 lifetime is invalid, ignoring assignment: %s", rvalue);
1267 return 0;
1268 }
1269
1270 if (usec == USEC_INFINITY || DIV_ROUND_UP(usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13) {
1271 log_syntax(unit, LOG_WARNING, filename, line, 0,
1272 "PREF64 lifetime is too long, ignoring assignment: %s", rvalue);
1273 return 0;
1274 }
1275
1276 p->lifetime = usec;
1277
1278 TAKE_PTR(p);
1279 return 0;
1280 }
1281
1282 int config_parse_radv_dns(
1283 const char *unit,
1284 const char *filename,
1285 unsigned line,
1286 const char *section,
1287 unsigned section_line,
1288 const char *lvalue,
1289 int ltype,
1290 const char *rvalue,
1291 void *data,
1292 void *userdata) {
1293
1294 Network *n = data;
1295 int r;
1296
1297 assert(filename);
1298 assert(lvalue);
1299 assert(rvalue);
1300
1301 if (isempty(rvalue)) {
1302 n->n_router_dns = 0;
1303 n->router_dns = mfree(n->router_dns);
1304 return 0;
1305 }
1306
1307 for (const char *p = rvalue;;) {
1308 _cleanup_free_ char *w = NULL;
1309 union in_addr_union a;
1310
1311 r = extract_first_word(&p, &w, NULL, 0);
1312 if (r == -ENOMEM)
1313 return log_oom();
1314 if (r < 0) {
1315 log_syntax(unit, LOG_WARNING, filename, line, r,
1316 "Failed to extract word, ignoring: %s", rvalue);
1317 return 0;
1318 }
1319 if (r == 0)
1320 return 0;
1321
1322 if (streq(w, "_link_local"))
1323 a = IN_ADDR_NULL;
1324 else {
1325 r = in_addr_from_string(AF_INET6, w, &a);
1326 if (r < 0) {
1327 log_syntax(unit, LOG_WARNING, filename, line, r,
1328 "Failed to parse DNS server address, ignoring: %s", w);
1329 continue;
1330 }
1331
1332 if (in_addr_is_null(AF_INET6, &a)) {
1333 log_syntax(unit, LOG_WARNING, filename, line, 0,
1334 "DNS server address is null, ignoring: %s", w);
1335 continue;
1336 }
1337 }
1338
1339 struct in6_addr *m;
1340 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1341 if (!m)
1342 return log_oom();
1343
1344 m[n->n_router_dns++] = a.in6;
1345 n->router_dns = m;
1346 }
1347 }
1348
1349 int config_parse_radv_search_domains(
1350 const char *unit,
1351 const char *filename,
1352 unsigned line,
1353 const char *section,
1354 unsigned section_line,
1355 const char *lvalue,
1356 int ltype,
1357 const char *rvalue,
1358 void *data,
1359 void *userdata) {
1360
1361 Network *n = data;
1362 int r;
1363
1364 assert(filename);
1365 assert(lvalue);
1366 assert(rvalue);
1367
1368 if (isempty(rvalue)) {
1369 n->router_search_domains = ordered_set_free(n->router_search_domains);
1370 return 0;
1371 }
1372
1373 for (const char *p = rvalue;;) {
1374 _cleanup_free_ char *w = NULL, *idna = NULL;
1375
1376 r = extract_first_word(&p, &w, NULL, 0);
1377 if (r == -ENOMEM)
1378 return log_oom();
1379 if (r < 0) {
1380 log_syntax(unit, LOG_WARNING, filename, line, r,
1381 "Failed to extract word, ignoring: %s", rvalue);
1382 return 0;
1383 }
1384 if (r == 0)
1385 return 0;
1386
1387 r = dns_name_apply_idna(w, &idna);
1388 if (r < 0) {
1389 log_syntax(unit, LOG_WARNING, filename, line, r,
1390 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1391 continue;
1392 } else if (r == 0)
1393 /* transfer ownership to simplify subsequent operations */
1394 idna = TAKE_PTR(w);
1395
1396 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops_free);
1397 if (r < 0)
1398 return log_oom();
1399
1400 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1401 if (r < 0)
1402 return log_oom();
1403 }
1404 }
1405
1406 static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
1407 [RADV_PREFIX_DELEGATION_NONE] = "no",
1408 [RADV_PREFIX_DELEGATION_STATIC] = "static",
1409 [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
1410 [RADV_PREFIX_DELEGATION_BOTH] = "yes",
1411 };
1412
1413 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
1414 radv_prefix_delegation,
1415 RADVPrefixDelegation,
1416 RADV_PREFIX_DELEGATION_BOTH);
1417
1418 int config_parse_router_prefix_delegation(
1419 const char *unit,
1420 const char *filename,
1421 unsigned line,
1422 const char *section,
1423 unsigned section_line,
1424 const char *lvalue,
1425 int ltype,
1426 const char *rvalue,
1427 void *data,
1428 void *userdata) {
1429
1430 RADVPrefixDelegation val, *ra = ASSERT_PTR(data);
1431 int r;
1432
1433 assert(filename);
1434 assert(lvalue);
1435 assert(rvalue);
1436
1437 if (streq(lvalue, "IPv6SendRA")) {
1438 r = parse_boolean(rvalue);
1439 if (r < 0) {
1440 log_syntax(unit, LOG_WARNING, filename, line, r,
1441 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1442 return 0;
1443 }
1444
1445 /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users
1446 * need to explicitly enable DHCPv6PrefixDelegation=. */
1447 *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE;
1448 return 0;
1449 }
1450
1451 /* For backward compatibility */
1452 val = radv_prefix_delegation_from_string(rvalue);
1453 if (val < 0) {
1454 log_syntax(unit, LOG_WARNING, filename, line, val,
1455 "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue);
1456 return 0;
1457 }
1458
1459 *ra = val;
1460 return 0;
1461 }
1462
1463 int config_parse_router_lifetime(
1464 const char *unit,
1465 const char *filename,
1466 unsigned line,
1467 const char *section,
1468 unsigned section_line,
1469 const char *lvalue,
1470 int ltype,
1471 const char *rvalue,
1472 void *data,
1473 void *userdata) {
1474
1475 usec_t usec, *lifetime = ASSERT_PTR(data);
1476 int r;
1477
1478 assert(filename);
1479 assert(section);
1480 assert(lvalue);
1481 assert(rvalue);
1482
1483 if (isempty(rvalue)) {
1484 *lifetime = RADV_DEFAULT_ROUTER_LIFETIME_USEC;
1485 return 0;
1486 }
1487
1488 r = parse_sec(rvalue, &usec);
1489 if (r < 0) {
1490 log_syntax(unit, LOG_WARNING, filename, line, r,
1491 "Failed to parse router lifetime, ignoring assignment: %s", rvalue);
1492 return 0;
1493 }
1494 if (usec > 0) {
1495 if (usec < RADV_MIN_ROUTER_LIFETIME_USEC) {
1496 log_syntax(unit, LOG_WARNING, filename, line, 0,
1497 "Router lifetime %s is too short, using %s.",
1498 FORMAT_TIMESPAN(usec, USEC_PER_SEC),
1499 FORMAT_TIMESPAN(RADV_MIN_ROUTER_LIFETIME_USEC, USEC_PER_SEC));
1500 usec = RADV_MIN_ROUTER_LIFETIME_USEC;
1501 } else if (usec > RADV_MAX_ROUTER_LIFETIME_USEC) {
1502 log_syntax(unit, LOG_WARNING, filename, line, 0,
1503 "Router lifetime %s is too large, using %s.",
1504 FORMAT_TIMESPAN(usec, USEC_PER_SEC),
1505 FORMAT_TIMESPAN(RADV_MAX_ROUTER_LIFETIME_USEC, USEC_PER_SEC));
1506 usec = RADV_MAX_ROUTER_LIFETIME_USEC;
1507 }
1508 }
1509
1510 *lifetime = usec;
1511 return 0;
1512 }
1513
1514 int config_parse_router_retransmit(
1515 const char *unit,
1516 const char *filename,
1517 unsigned line,
1518 const char *section,
1519 unsigned section_line,
1520 const char *lvalue,
1521 int ltype,
1522 const char *rvalue,
1523 void *data,
1524 void *userdata) {
1525
1526 usec_t usec, *router_retransmit_usec = ASSERT_PTR(data);
1527 int r;
1528
1529 assert(filename);
1530 assert(section);
1531 assert(lvalue);
1532 assert(rvalue);
1533
1534 if (isempty(rvalue)) {
1535 *router_retransmit_usec = 0;
1536 return 0;
1537 }
1538
1539 r = parse_sec(rvalue, &usec);
1540 if (r < 0) {
1541 log_syntax(unit, LOG_WARNING, filename, line, r,
1542 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1543 return 0;
1544 }
1545
1546 if (usec != USEC_INFINITY &&
1547 usec > RADV_MAX_RETRANSMIT_USEC) {
1548 log_syntax(unit, LOG_WARNING, filename, line, 0,
1549 "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
1550 return 0;
1551 }
1552
1553 *router_retransmit_usec = usec;
1554 return 0;
1555 }
1556
1557 int config_parse_router_preference(
1558 const char *unit,
1559 const char *filename,
1560 unsigned line,
1561 const char *section,
1562 unsigned section_line,
1563 const char *lvalue,
1564 int ltype,
1565 const char *rvalue,
1566 void *data,
1567 void *userdata) {
1568
1569 Network *network = userdata;
1570
1571 assert(filename);
1572 assert(section);
1573 assert(lvalue);
1574 assert(rvalue);
1575 assert(data);
1576
1577 if (streq(rvalue, "high"))
1578 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
1579 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
1580 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
1581 else if (streq(rvalue, "low"))
1582 network->router_preference = SD_NDISC_PREFERENCE_LOW;
1583 else
1584 log_syntax(unit, LOG_WARNING, filename, line, 0,
1585 "Invalid router preference, ignoring assignment: %s", rvalue);
1586
1587 return 0;
1588 }
1589
1590 int config_parse_router_home_agent_lifetime(
1591 const char *unit,
1592 const char *filename,
1593 unsigned line,
1594 const char *section,
1595 unsigned section_line,
1596 const char *lvalue,
1597 int ltype,
1598 const char *rvalue,
1599 void *data,
1600 void *userdata) {
1601
1602 usec_t usec, *home_agent_lifetime_usec = ASSERT_PTR(data);
1603 int r;
1604
1605 assert(filename);
1606 assert(section);
1607 assert(lvalue);
1608 assert(rvalue);
1609
1610 if (isempty(rvalue)) {
1611 *home_agent_lifetime_usec = 0;
1612 return 0;
1613 }
1614
1615 r = parse_sec(rvalue, &usec);
1616 if (r < 0) {
1617 log_syntax(unit, LOG_WARNING, filename, line, r,
1618 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1619 return 0;
1620 }
1621
1622 if (!timestamp_is_set(usec) ||
1623 usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) {
1624 log_syntax(unit, LOG_WARNING, filename, line, 0,
1625 "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
1626 return 0;
1627 }
1628
1629 *home_agent_lifetime_usec = usec;
1630 return 0;
1631 }