#define RADV_MIN_ROUTER_LIFETIME_USEC RADV_MIN_MAX_TIMEOUT_USEC
#define RADV_MAX_ROUTER_LIFETIME_USEC (9000 * USEC_PER_SEC)
#define RADV_DEFAULT_ROUTER_LIFETIME_USEC (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
+/* RFC 4861 section 4.2.
+ * Retrans Timer
+ * 32-bit unsigned integer. The time, in milliseconds. */
+#define RADV_MAX_RETRANSMIT_USEC (UINT32_MAX * USEC_PER_MSEC)
/* draft-ietf-6man-slaac-renum-02 section 4.1.1.
* AdvPreferredLifetime: max(AdvDefaultLifetime, 3 * MaxRtrAdvInterval)
* AdvValidLifetime: 2 * AdvPreferredLifetime */
#define RADV_MAX_RA_DELAY_TIME_USEC (500 * USEC_PER_MSEC)
/* From RFC 8781 section 4.1
* By default, the value of the Scaled Lifetime field SHOULD be set to the lesser of 3 x MaxRtrAdvInterval */
-#define RADV_DEFAULT_PRE64_LIFETIME_USEC (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
+#define RADV_PREF64_DEFAULT_LIFETIME_USEC (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
+
+#define RADV_RDNSS_MAX_LIFETIME_USEC (UINT32_MAX * USEC_PER_SEC)
+#define RADV_DNSSL_MAX_LIFETIME_USEC (UINT32_MAX * USEC_PER_SEC)
+/* rfc6275 7.4 Neighbor Discovery Home Agent Lifetime.
+ * The default value is the same as the Router Lifetime.
+ * The maximum value corresponds to 18.2 hours. 0 MUST NOT be used. */
+#define RADV_HOME_AGENT_MAX_LIFETIME_USEC (UINT16_MAX * USEC_PER_SEC)
#define RADV_OPT_ROUTE_INFORMATION 24
#define RADV_OPT_RDNSS 25
/* Pref64 option type (RFC8781, section 4) */
#define RADV_OPT_PREF64 38
-/* rfc6275 7.4 Neighbor Discovery Home Agent Lifetime.
- * The default value is the same as the Router Lifetime
- * The maximum value corresponds to 18.2 hours. value of 0 MUST NOT be used.*/
-#define RADV_MAX_HOME_AGENT_LIFETIME_USEC (65535 * USEC_PER_SEC)
-
enum RAdvState {
RADV_STATE_IDLE = 0,
RADV_STATE_ADVERTISING = 1,
uint8_t hop_limit;
uint8_t flags;
uint32_t mtu;
- uint32_t retransmit_msec;
+ usec_t retransmit_usec;
usec_t lifetime_usec; /* timespan */
int fd;
adv.nd_ra_type = ND_ROUTER_ADVERT;
adv.nd_ra_curhoplimit = ra->hop_limit;
- adv.nd_ra_retransmit = htobe32(ra->retransmit_msec);
+ adv.nd_ra_retransmit = usec_to_be32_msec(ra->retransmit_usec);
adv.nd_ra_flags_reserved = ra->flags;
assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC);
- adv.nd_ra_router_lifetime = htobe16(DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC));
+ adv.nd_ra_router_lifetime = usec_to_be16_sec(lifetime_usec);
iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
/* MAC address is optional, either because the link does not use L2
return 0;
}
-int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec) {
+int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec) {
assert_return(ra, -EINVAL);
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
- ra->retransmit_msec = retransmit_msec;
+ if (usec > RADV_MAX_RETRANSMIT_USEC)
+ return -EINVAL;
+ ra->retransmit_usec = usec;
return 0;
}
-int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
+int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec) {
assert_return(ra, -EINVAL);
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
- if (!router_lifetime_is_valid(lifetime_usec))
+ if (!router_lifetime_is_valid(usec))
return -EINVAL;
/* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
* to (00) by the sender..." */
- if (lifetime_usec == 0 &&
+ if (usec == 0 &&
(ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
return -EINVAL;
- ra->lifetime_usec = lifetime_usec;
-
+ ra->lifetime_usec = usec;
return 0;
}
return 0;
}
-int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint16_t lifetime) {
+int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
assert_return(ra, -EINVAL);
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
- ra->home_agent.nd_opt_home_agent_info_lifetime = htobe16(lifetime);
+ if (lifetime_usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC)
+ return -EINVAL;
+ ra->home_agent.nd_opt_home_agent_info_lifetime = usec_to_be16_sec(lifetime_usec);
return 0;
}
int sd_radv_set_rdnss(
sd_radv *ra,
- uint32_t lifetime,
+ uint64_t lifetime_usec,
const struct in6_addr *dns,
size_t n_dns) {
assert_return(ra, -EINVAL);
assert_return(n_dns < 128, -EINVAL);
+ if (lifetime_usec > RADV_RDNSS_MAX_LIFETIME_USEC)
+ return -EINVAL;
+
if (!dns || n_dns == 0) {
ra->rdnss = mfree(ra->rdnss);
ra->n_rdnss = 0;
opt_rdnss->type = RADV_OPT_RDNSS;
opt_rdnss->length = len / 8;
- opt_rdnss->lifetime = htobe32(lifetime);
+ opt_rdnss->lifetime = usec_to_be32_sec(lifetime_usec);
memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
int sd_radv_set_dnssl(
sd_radv *ra,
- uint32_t lifetime,
+ uint64_t lifetime_usec,
char **search_list) {
_cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
assert_return(ra, -EINVAL);
+ if (lifetime_usec > RADV_DNSSL_MAX_LIFETIME_USEC)
+ return -EINVAL;
+
if (strv_isempty(search_list)) {
ra->dnssl = mfree(ra->dnssl);
return 0;
opt_dnssl->type = RADV_OPT_DNSSL;
opt_dnssl->length = len / 8;
- opt_dnssl->lifetime = htobe32(lifetime);
+ opt_dnssl->lifetime = usec_to_be32_sec(lifetime_usec);
p = (uint8_t *)(opt_dnssl + 1);
len -= sizeof(struct sd_radv_opt_dns);
if (r < 0)
return log_radv_errno(NULL, r, "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
- if (lifetime_usec == USEC_INFINITY || DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13)
+ if (lifetime_usec > PREF64_MAX_LIFETIME_USEC)
return -EINVAL;
/* RFC 8781 - 4.1 rounding up lifetime to multiply of 8 */
assert_se(sd_radv_set_rdnss(NULL, 0, NULL, 0) < 0);
assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
assert_se(sd_radv_set_rdnss(ra, 0, NULL, 128) < 0);
- assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 0) >= 0);
- assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 1) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 600 * USEC_PER_SEC, &test_rdnss, 0) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 600 * USEC_PER_SEC, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_rdnss(ra, 0, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
assert_se(sd_radv_set_dnssl(ra, 0, NULL) >= 0);
- assert_se(sd_radv_set_dnssl(ra, 600, NULL) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, NULL) >= 0);
assert_se(sd_radv_set_dnssl(ra, 0, (char **)test_dnssl) >= 0);
- assert_se(sd_radv_set_dnssl(ra, 600, (char **)test_dnssl) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
ra = sd_radv_unref(ra);
assert_se(!ra);
assert_se(sd_radv_set_hop_limit(ra, 64) >= 0);
assert_se(sd_radv_set_managed_information(ra, true) >= 0);
assert_se(sd_radv_set_other_information(ra, true) >= 0);
- assert_se(sd_radv_set_rdnss(ra, 60, &test_rdnss, 1) >= 0);
- assert_se(sd_radv_set_dnssl(ra, 60, (char **)test_dnssl) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 60 * USEC_PER_SEC, &test_rdnss, 1) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 60 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
for (unsigned i = 0; i < ELEMENTSOF(prefix); i++) {
sd_radv_prefix *p;
.network = network,
.section = TAKE_PTR(n),
- .lifetime = RADV_DEFAULT_PRE64_LIFETIME_USEC,
+ .lifetime = RADV_PREF64_DEFAULT_LIFETIME_USEC,
};
r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
return 0;
}
-static uint32_t usec_to_lifetime(usec_t usec) {
- uint64_t t;
-
- if (usec == USEC_INFINITY)
- return UINT32_MAX;
-
- t = DIV_ROUND_UP(usec, USEC_PER_SEC);
- if (t >= UINT32_MAX)
- return UINT32_MAX;
-
- return (uint32_t) t;
-}
-
static int radv_set_prefix(Link *link, Prefix *prefix) {
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
int r;
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);
}
}
if (link->network->router_retransmit_usec > 0) {
- r = sd_radv_set_retransmit(link->radv, DIV_ROUND_UP(link->network->router_retransmit_usec, USEC_PER_MSEC));
+ r = sd_radv_set_retransmit(link->radv, link->network->router_retransmit_usec);
if (r < 0)
return r;
}
if (r < 0)
return r;
- r = sd_radv_set_home_agent_lifetime(link->radv, DIV_ROUND_UP(link->network->home_agent_lifetime_usec, USEC_PER_SEC));
+ r = sd_radv_set_home_agent_lifetime(link->radv, link->network->home_agent_lifetime_usec);
if (r < 0)
return r;
}
if (usec != USEC_INFINITY &&
- DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) {
+ usec > RADV_MAX_RETRANSMIT_USEC) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Invalid %s= must be in the range 0...%"PRIu32"Sec, ignoring: %s", lvalue, UINT32_MAX, rvalue);
+ "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
return 0;
}
}
if (usec == USEC_INFINITY || usec == 0 ||
- DIV_ROUND_UP(usec, USEC_PER_SEC) > RADV_MAX_HOME_AGENT_LIFETIME_USEC) {
+ usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Invalid %s= must be in the range 1…%s, ignoring: %s", lvalue,
- FORMAT_TIMESPAN(RADV_MAX_HOME_AGENT_LIFETIME_USEC, USEC_PER_SEC), rvalue);
+ "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
return 0;
}
int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);
int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu);
int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit);
-int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec);
-int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec);
+int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec);
+int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec);
int sd_radv_set_managed_information(sd_radv *ra, int managed);
int sd_radv_set_other_information(sd_radv *ra, int other);
int sd_radv_set_preference(sd_radv *ra, unsigned preference);
int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p);
int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p);
void sd_radv_remove_prefix(sd_radv *ra, const struct in6_addr *prefix, unsigned char prefixlen);
-int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
+int sd_radv_set_rdnss(sd_radv *ra, uint64_t lifetime_usec,
const struct in6_addr *dns, size_t n_dns);
-int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list);
+int sd_radv_set_dnssl(sd_radv *ra, uint64_t lifetime_usec, char **search_list);
/* Advertised prefixes */
int sd_radv_prefix_new(sd_radv_prefix **ret);
/* Mobile IPv6 extension: Home Agent Info. */
int sd_radv_set_home_agent_information(sd_radv *ra, int home_agent);
int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference);
-int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint16_t lifetime);
+int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t usec);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv, sd_radv_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_prefix, sd_radv_prefix_unref);