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