#include <arpa/inet.h>
#include "dns-domain.h"
+#include "ndisc-router-internal.h"
#include "networkd-address-generation.h"
#include "networkd-address.h"
#include "networkd-dhcp-prefix-delegation.h"
#include "string-table.h"
#include "strv.h"
-void network_adjust_radv(Network *network) {
- assert(network);
-
- /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
-
- if (network->dhcp_pd < 0)
- /* For backward compatibility. */
- network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
-
- if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
- if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
- log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. "
- "Disabling IPv6PrefixDelegation=.", network->filename);
-
- network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
- }
-
- if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
- network->n_router_dns = 0;
- network->router_dns = mfree(network->router_dns);
- network->router_search_domains = ordered_set_free(network->router_search_domains);
- }
-
- if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
- network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
- network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
- }
-}
-
bool link_radv_enabled(Link *link) {
assert(link);
return link->network->router_prefix_delegation;
}
-Prefix *prefix_free(Prefix *prefix) {
+Prefix* prefix_free(Prefix *prefix) {
if (!prefix)
return NULL;
.network = network,
.section = TAKE_PTR(n),
- .preferred_lifetime = RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
- .valid_lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
- .onlink = true,
- .address_auto_configuration = true,
+ .prefix.flags = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO,
+ .prefix.valid_lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
+ .prefix.preferred_lifetime = RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
+ .prefix.valid_until = USEC_INFINITY,
+ .prefix.preferred_until = USEC_INFINITY,
};
r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
return 0;
}
-RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
+RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
if (!prefix)
return NULL;
.network = network,
.section = TAKE_PTR(n),
- .lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
+ .route.lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
+ .route.valid_until = USEC_INFINITY,
};
r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
return 0;
}
+Prefix64* prefix64_free(Prefix64 *prefix) {
+ if (!prefix)
+ return NULL;
+
+ if (prefix->network) {
+ assert(prefix->section);
+ hashmap_remove(prefix->network->pref64_prefixes_by_section, prefix->section);
+ }
+
+ config_section_free(prefix->section);
+
+ return mfree(prefix);
+}
+
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix64, prefix64_free);
+
+static int prefix64_new_static(Network *network, const char *filename, unsigned section_line, Prefix64 **ret) {
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
+ _cleanup_(prefix64_freep) Prefix64 *prefix = NULL;
+ int r;
+
+ assert(network);
+ assert(ret);
+ assert(filename);
+ assert(section_line > 0);
+
+ r = config_section_new(filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ prefix = hashmap_get(network->pref64_prefixes_by_section, n);
+ if (prefix) {
+ *ret = TAKE_PTR(prefix);
+ return 0;
+ }
+
+ prefix = new(Prefix64, 1);
+ if (!prefix)
+ return -ENOMEM;
+
+ *prefix = (Prefix64) {
+ .network = network,
+ .section = TAKE_PTR(n),
+
+ .prefix64.lifetime = RADV_PREF64_DEFAULT_LIFETIME_USEC,
+ .prefix64.valid_until = USEC_INFINITY,
+ };
+
+ r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(prefix);
+ return 0;
+}
+
int link_request_radv_addresses(Link *link) {
Prefix *p;
int r;
return 0;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
- _cleanup_set_free_ Set *addresses = NULL;
- struct in6_addr *a;
-
if (!p->assign)
continue;
/* radv_generate_addresses() below requires the prefix length <= 64. */
- if (p->prefixlen > 64)
+ if (p->prefix.prefixlen > 64)
continue;
- r = radv_generate_addresses(link, p->tokens, &p->prefix, p->prefixlen, &addresses);
+ _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
+ r = radv_generate_addresses(link, p->tokens, &p->prefix.address, p->prefix.prefixlen, &tokens_by_address);
if (r < 0)
return r;
- SET_FOREACH(a, addresses) {
- _cleanup_(address_freep) Address *address = NULL;
+ IPv6Token *token;
+ struct in6_addr *a;
+ HASHMAP_FOREACH_KEY(token, a, tokens_by_address) {
+ _cleanup_(address_unrefp) Address *address = NULL;
r = address_new(&address);
if (r < 0)
address->source = NETWORK_CONFIG_SOURCE_STATIC;
address->family = AF_INET6;
address->in_addr.in6 = *a;
- address->prefixlen = p->prefixlen;
+ address->prefixlen = p->prefix.prefixlen;
address->route_metric = p->route_metric;
+ address->token = ipv6_token_ref(token);
- r = link_request_static_address(link, TAKE_PTR(address), true);
+ r = link_request_static_address(link, address);
if (r < 0)
return r;
}
return 0;
}
-static uint32_t usec_to_lifetime(usec_t usec) {
- uint64_t t;
+int link_reconfigure_radv_address(Address *address, Link *link) {
+ int r;
- if (usec == USEC_INFINITY)
- return UINT32_MAX;
+ assert(address);
+ assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
+ assert(link);
- t = DIV_ROUND_UP(usec, USEC_PER_SEC);
- if (t >= UINT32_MAX)
- return UINT32_MAX;
+ r = regenerate_address(address, link);
+ if (r <= 0)
+ return r;
- return (uint32_t) t;
+ r = link_request_static_address(link, address);
+ if (r < 0)
+ return r;
+
+ if (link->static_address_messages != 0) {
+ link->static_addresses_configured = false;
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
+
+ return 0;
}
static int radv_set_prefix(Link *link, Prefix *prefix) {
if (r < 0)
return r;
- r = sd_radv_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen);
+ r = sd_radv_prefix_set_prefix(p, &prefix->prefix.address, prefix->prefix.prefixlen);
if (r < 0)
return r;
- r = sd_radv_prefix_set_preferred_lifetime(p, prefix->preferred_lifetime, USEC_INFINITY);
+ r = sd_radv_prefix_set_preferred_lifetime(p, prefix->prefix.preferred_lifetime, prefix->prefix.preferred_until);
if (r < 0)
return r;
- r = sd_radv_prefix_set_valid_lifetime(p, prefix->valid_lifetime, USEC_INFINITY);
+ r = sd_radv_prefix_set_valid_lifetime(p, prefix->prefix.valid_lifetime, prefix->prefix.valid_until);
if (r < 0)
return r;
- r = sd_radv_prefix_set_onlink(p, prefix->onlink);
+ r = sd_radv_prefix_set_onlink(p, FLAGS_SET(prefix->prefix.flags, ND_OPT_PI_FLAG_ONLINK));
if (r < 0)
return r;
- r = sd_radv_prefix_set_address_autoconfiguration(p, prefix->address_auto_configuration);
+ r = sd_radv_prefix_set_address_autoconfiguration(p, FLAGS_SET(prefix->prefix.flags, ND_OPT_PI_FLAG_AUTO));
if (r < 0)
return r;
if (r < 0)
return r;
- r = sd_radv_route_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen);
+ r = sd_radv_route_prefix_set_prefix(p, &prefix->route.address, prefix->route.prefixlen);
if (r < 0)
return r;
- r = sd_radv_route_prefix_set_lifetime(p, prefix->lifetime, USEC_INFINITY);
+ r = sd_radv_route_prefix_set_lifetime(p, prefix->route.lifetime, prefix->route.valid_until);
if (r < 0)
return r;
return sd_radv_add_route_prefix(link->radv, p);
}
+static int radv_set_pref64_prefix(Link *link, Prefix64 *prefix) {
+ _cleanup_(sd_radv_pref64_prefix_unrefp) sd_radv_pref64_prefix *p = NULL;
+ int r;
+
+ assert(link);
+ assert(link->radv);
+ assert(prefix);
+
+ r = sd_radv_pref64_prefix_new(&p);
+ if (r < 0)
+ return r;
+
+ r = sd_radv_pref64_prefix_set_prefix(p, &prefix->prefix64.prefix, prefix->prefix64.prefixlen, prefix->prefix64.lifetime);
+ if (r < 0)
+ return r;
+
+ return sd_radv_add_pref64_prefix(link->radv, p);
+}
+
static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) {
_cleanup_free_ struct in6_addr *addresses = NULL;
size_t n_addresses = 0;
set_dns:
return sd_radv_set_rdnss(link->radv,
- usec_to_lifetime(link->network->router_dns_lifetime_usec),
+ link->network->router_dns_lifetime_usec,
dns, n_dns);
}
return log_oom();
return sd_radv_set_dnssl(link->radv,
- usec_to_lifetime(link->network->router_dns_lifetime_usec),
+ link->network->router_dns_lifetime_usec,
s);
}
static int radv_configure(Link *link) {
Link *uplink = NULL;
- RoutePrefix *q;
- Prefix *p;
int r;
assert(link);
if (r < 0)
return r;
- if (link->network->router_lifetime_usec > 0) {
- r = sd_radv_set_preference(link->radv, link->network->router_preference);
- if (r < 0)
- return r;
- }
+ r = sd_radv_set_hop_limit(link->radv, link->network->router_hop_limit);
+ if (r < 0)
+ return r;
+
+ r = sd_radv_set_preference(link->radv, link->network->router_preference);
+ if (r < 0)
+ return r;
+
+ r = sd_radv_set_reachable_time(link->radv, link->network->router_reachable_usec);
+ if (r < 0)
+ return r;
+ r = sd_radv_set_retransmit(link->radv, link->network->router_retransmit_usec);
+ if (r < 0)
+ return r;
+
+ Prefix *p;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
r = radv_set_prefix(link, p);
if (r < 0 && r != -EEXIST)
return r;
}
+ RoutePrefix *q;
HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) {
r = radv_set_route_prefix(link, q);
if (r < 0 && r != -EEXIST)
return r;
}
+ Prefix64 *n;
+ HASHMAP_FOREACH(n, link->network->pref64_prefixes_by_section) {
+ r = radv_set_pref64_prefix(link, n);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ }
+
(void) radv_find_uplink(link, &uplink);
r = radv_set_dns(link, uplink);
if (r < 0)
return log_link_debug_errno(link, r, "Could not set RA Domains: %m");
+ r = sd_radv_set_home_agent_information(link->radv, link->network->router_home_agent_information);
+ if (r < 0)
+ return r;
+
+ r = sd_radv_set_home_agent_preference(link->radv, link->network->router_home_agent_preference);
+ if (r < 0)
+ return r;
+
+ r = sd_radv_set_home_agent_lifetime(link->radv, link->network->home_agent_lifetime_usec);
+ if (r < 0)
+ return r;
+
return 0;
}
int radv_update_mac(Link *link) {
- bool restart;
- int r;
-
assert(link);
if (!link->radv)
if (link->hw_addr.length != ETH_ALEN)
return 0;
- restart = sd_radv_is_running(link->radv);
-
- r = sd_radv_stop(link->radv);
- if (r < 0)
- return r;
-
- r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
- if (r < 0)
- return r;
-
- if (restart) {
- r = sd_radv_start(link->radv);
- if (r < 0)
- return r;
- }
-
- return 0;
+ return sd_radv_set_mac(link->radv, &link->hw_addr.ether);
}
static int radv_is_ready_to_configure(Link *link) {
return log_link_debug_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m");
}
+ r = sd_radv_set_link_local_address(link->radv, &link->ipv6ll_address);
+ if (r < 0)
+ return r;
+
log_link_debug(link, "Starting IPv6 Router Advertisements");
return sd_radv_start(link->radv);
}
return r;
r = sd_radv_add_prefix(link->radv, p);
- if (r < 0 && r != -EEXIST)
+ if (r == -EEXIST)
+ return 0;
+ if (r < 0)
return r;
+ if (sd_radv_is_running(link->radv)) {
+ /* Announce updated prefixe now. */
+ r = sd_radv_send(link->radv);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
if (section_is_invalid(p->section))
return -EINVAL;
- if (in6_addr_is_null(&p->prefix))
+ if (in6_addr_is_null(&p->prefix.address))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: [IPv6Prefix] section without Prefix= field configured, "
"or specified prefix is the null address. "
"Ignoring [IPv6Prefix] section from line %u.",
p->section->filename, p->section->line);
- if (p->prefixlen < 3 || p->prefixlen > 128)
+ if (p->prefix.prefixlen < 3 || p->prefix.prefixlen > 128)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Invalid prefix length %u is specified in [IPv6Prefix] section. "
"Valid range is 3…128. Ignoring [IPv6Prefix] section from line %u.",
- p->section->filename, p->prefixlen, p->section->line);
+ p->section->filename, p->prefix.prefixlen, p->section->line);
- if (p->prefixlen > 64) {
+ if (p->prefix.prefixlen > 64) {
log_info("%s:%u: Unusual prefix length %u (> 64) is specified in [IPv6Prefix] section from line %s%s.",
p->section->filename, p->section->line,
- p->prefixlen,
+ p->prefix.prefixlen,
p->assign ? ", refusing to assign an address in " : "",
- p->assign ? IN6_ADDR_PREFIX_TO_STRING(&p->prefix, p->prefixlen) : "");
+ p->assign ? IN6_ADDR_PREFIX_TO_STRING(&p->prefix.address, p->prefix.prefixlen) : "");
p->assign = false;
}
- if (p->valid_lifetime == 0)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: The valid lifetime of prefix cannot be zero. "
- "Ignoring [IPv6Prefix] section from line %u.",
- p->section->filename, p->section->line);
-
- if (p->preferred_lifetime > p->valid_lifetime)
+ if (p->prefix.preferred_lifetime > p->prefix.valid_lifetime)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: The preferred lifetime %s is longer than the valid lifetime %s. "
"Ignoring [IPv6Prefix] section from line %u.",
p->section->filename,
- FORMAT_TIMESPAN(p->preferred_lifetime, USEC_PER_SEC),
- FORMAT_TIMESPAN(p->valid_lifetime, USEC_PER_SEC),
+ FORMAT_TIMESPAN(p->prefix.preferred_lifetime, USEC_PER_SEC),
+ FORMAT_TIMESPAN(p->prefix.valid_lifetime, USEC_PER_SEC),
p->section->line);
return 0;
}
-void network_drop_invalid_prefixes(Network *network) {
- Prefix *p;
-
- assert(network);
-
- HASHMAP_FOREACH(p, network->prefixes_by_section)
- if (prefix_section_verify(p) < 0)
- prefix_free(p);
-}
-
static int route_prefix_section_verify(RoutePrefix *p) {
if (section_is_invalid(p->section))
return -EINVAL;
- if (p->prefixlen > 128)
+ if (p->route.prefixlen > 128)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Invalid prefix length %u is specified in [IPv6RoutePrefix] section. "
"Valid range is 0…128. Ignoring [IPv6RoutePrefix] section from line %u.",
- p->section->filename, p->prefixlen, p->section->line);
-
- if (p->lifetime == 0)
- return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: The lifetime of route cannot be zero. "
- "Ignoring [IPv6RoutePrefix] section from line %u.",
- p->section->filename, p->section->line);
+ p->section->filename, p->route.prefixlen, p->section->line);
return 0;
}
-void network_drop_invalid_route_prefixes(Network *network) {
- RoutePrefix *p;
-
+void network_adjust_radv(Network *network) {
assert(network);
- HASHMAP_FOREACH(p, network->route_prefixes_by_section)
- if (route_prefix_section_verify(p) < 0)
- route_prefix_free(p);
+ /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */
+
+ if (network->dhcp_pd < 0)
+ /* For backward compatibility. */
+ network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6);
+
+ if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
+ if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE)
+ log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. "
+ "Disabling IPv6PrefixDelegation=.", network->filename);
+
+ network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
+ }
+
+ if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) {
+ network->n_router_dns = 0;
+ network->router_dns = mfree(network->router_dns);
+ network->router_search_domains = ordered_set_free(network->router_search_domains);
+ }
+
+ if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
+ network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
+ network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
+ network->pref64_prefixes_by_section = hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free);
+ }
+
+ if (!network->router_prefix_delegation)
+ return;
+
+ /* Below, let's verify router settings, if enabled. */
+
+ if (network->router_lifetime_usec == 0 && network->router_preference != SD_NDISC_PREFERENCE_MEDIUM)
+ /* RFC 4191, Section 2.2,
+ * If the Router Lifetime is zero, the preference value MUST be set to (00) by the sender.
+ *
+ * Note, radv_send_router() gracefully handle that. So, it is not necessary to refuse, but
+ * let's warn about that. */
+ log_notice("%s: RouterPreference=%s specified with RouterLifetimeSec=0, ignoring RouterPreference= setting.",
+ network->filename, ndisc_router_preference_to_string(network->router_preference));
+
+ Prefix *prefix;
+ HASHMAP_FOREACH(prefix, network->prefixes_by_section)
+ if (prefix_section_verify(prefix) < 0)
+ prefix_free(prefix);
+
+
+ RoutePrefix *route;
+ HASHMAP_FOREACH(route, network->route_prefixes_by_section)
+ if (route_prefix_section_verify(route) < 0)
+ route_prefix_free(route);
+
+ Prefix64 *pref64;
+ HASHMAP_FOREACH(pref64, network->pref64_prefixes_by_section)
+ if (section_is_invalid(pref64->section))
+ prefix64_free(pref64);
}
int config_parse_prefix(
if (r < 0)
return log_oom();
- r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
+ r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefix.prefixlen);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Prefix is invalid, ignoring assignment: %s", rvalue);
return 0;
}
- (void) in6_addr_mask(&a.in6, p->prefixlen);
- p->prefix = a.in6;
+ (void) in6_addr_mask(&a.in6, p->prefix.prefixlen);
+ p->prefix.address = a.in6;
TAKE_PTR(p);
return 0;
return 0;
}
- if (streq(lvalue, "OnLink"))
- p->onlink = r;
- else if (streq(lvalue, "AddressAutoconfiguration"))
- p->address_auto_configuration = r;
- else if (streq(lvalue, "Assign"))
+ if (ltype != 0)
+ SET_FLAG(p->prefix.flags, ltype, r);
+ else {
+ assert(streq(lvalue, "Assign"));
p->assign = r;
- else
- assert_not_reached();
+ }
TAKE_PTR(p);
return 0;
}
if (streq(lvalue, "PreferredLifetimeSec"))
- p->preferred_lifetime = usec;
+ p->prefix.preferred_lifetime = usec;
else if (streq(lvalue, "ValidLifetimeSec"))
- p->valid_lifetime = usec;
+ p->prefix.valid_lifetime = usec;
else
assert_not_reached();
if (r < 0)
return log_oom();
- r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen);
+ r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->route.prefixlen);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Route prefix is invalid, ignoring assignment: %s", rvalue);
return 0;
}
- (void) in6_addr_mask(&a.in6, p->prefixlen);
- p->prefix = a.in6;
+ (void) in6_addr_mask(&a.in6, p->route.prefixlen);
+ p->route.address = a.in6;
TAKE_PTR(p);
return 0;
return 0;
}
- p->lifetime = usec;
+ p->route.lifetime = usec;
+
+ TAKE_PTR(p);
+ return 0;
+}
+
+int config_parse_pref64_prefix(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(prefix64_free_or_set_invalidp) Prefix64 *p = NULL;
+ Network *network = ASSERT_PTR(userdata);
+ union in_addr_union a;
+ uint8_t prefixlen;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = prefix64_new_static(network, filename, section_line, &p);
+ if (r < 0)
+ return log_oom();
+
+ r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "PREF64 prefix is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (!IN_SET(prefixlen, 96, 64, 56, 48, 40, 32)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "PREF64 prefixlen is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ (void) in6_addr_mask(&a.in6, prefixlen);
+ p->prefix64.prefix = a.in6;
+ p->prefix64.prefixlen = prefixlen;
+
+ TAKE_PTR(p);
+ return 0;
+}
+
+int config_parse_pref64_prefix_lifetime(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(prefix64_free_or_set_invalidp) Prefix64 *p = NULL;
+ Network *network = ASSERT_PTR(userdata);
+ usec_t usec;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = prefix64_new_static(network, filename, section_line, &p);
+ if (r < 0)
+ return log_oom();
+
+ r = parse_sec(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "PREF64 lifetime is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (usec == USEC_INFINITY || DIV_ROUND_UP(usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "PREF64 lifetime is too long, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ p->prefix64.lifetime = usec;
TAKE_PTR(p);
return 0;
return 0;
}
+int config_parse_router_uint32_msec_usec(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ usec_t usec, *router_usec = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *router_usec = 0;
+ return 0;
+ }
+
+ r = parse_sec(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ if (usec != USEC_INFINITY &&
+ usec > RADV_MAX_UINT32_MSEC_USEC) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
+ return 0;
+ }
+
+ *router_usec = usec;
+ return 0;
+}
+
int config_parse_router_preference(
const char *unit,
const char *filename,
return 0;
}
+
+int config_parse_router_home_agent_lifetime(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ usec_t usec, *home_agent_lifetime_usec = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *home_agent_lifetime_usec = 0;
+ return 0;
+ }
+
+ r = parse_sec(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ if (!timestamp_is_set(usec) ||
+ usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
+ return 0;
+ }
+
+ *home_agent_lifetime_usec = usec;
+ return 0;
+}