sd-radv: router lifetime must be 0 or between 4 seconds and 9000 seconds

See RFC 4861 section 6.2.1.
This commit is contained in:
Yu Watanabe
2021-10-27 19:27:07 +09:00
parent 72db0a714b
commit 0945767012
3 changed files with 20 additions and 14 deletions
+2
View File
@@ -34,6 +34,8 @@
* point-to-point link the peers may have enough information about the number and status of devices at
* the other end so that advertisements are needed less frequently.
* Default: 3 * MaxRtrAdvInterval */
#define RADV_MIN_ROUTER_LIFETIME_USEC (4 * USEC_PER_SEC)
#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 10.
* MAX_INITIAL_RTR_ADVERT_INTERVAL 16 seconds
+13 -11
View File
@@ -129,6 +129,12 @@ static sd_radv *radv_free(sd_radv *ra) {
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
static bool router_lifetime_is_valid(usec_t lifetime_usec) {
return lifetime_usec == 0 ||
(lifetime_usec >= RADV_MIN_ROUTER_LIFETIME_USEC &&
lifetime_usec <= RADV_MAX_ROUTER_LIFETIME_USEC);
}
static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_usec) {
sd_radv_route_prefix *rt;
sd_radv_prefix *p;
@@ -159,31 +165,24 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
.msg_namelen = sizeof(dst_addr),
.msg_iov = iov,
};
uint16_t lifetime_sec;
usec_t time_now;
int r;
assert(ra);
assert(router_lifetime_is_valid(lifetime_usec));
r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return r;
/* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */
if (lifetime_usec == USEC_INFINITY)
lifetime_sec = UINT16_MAX;
else if (lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC)
lifetime_sec = UINT16_MAX - 1;
else
lifetime_sec = DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC);
if (dst && in6_addr_is_set(dst))
dst_addr.sin6_addr = *dst;
adv.nd_ra_type = ND_ROUTER_ADVERT;
adv.nd_ra_curhoplimit = ra->hop_limit;
adv.nd_ra_flags_reserved = ra->flags;
adv.nd_ra_router_lifetime = htobe16(lifetime_sec);
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));
iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
/* MAC address is optional, either because the link does not use L2
@@ -504,11 +503,14 @@ _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
if (!router_lifetime_is_valid(lifetime_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 &&
(ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
return -ETIME;
return -EINVAL;
ra->lifetime_usec = lifetime_usec;
+5 -3
View File
@@ -180,7 +180,9 @@ static void test_radv(void) {
assert_se(sd_radv_set_router_lifetime(NULL, 0) < 0);
assert_se(sd_radv_set_router_lifetime(ra, 0) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, ~0) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, USEC_INFINITY) < 0);
assert_se(sd_radv_set_router_lifetime(ra, USEC_PER_YEAR) < 0);
assert_se(sd_radv_set_router_lifetime(ra, 300 * USEC_PER_SEC) >= 0);
assert_se(sd_radv_set_preference(NULL, 0) < 0);
assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_LOW) >= 0);
@@ -189,7 +191,7 @@ static void test_radv(void) {
assert_se(sd_radv_set_preference(ra, ~0) < 0);
assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_HIGH) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, 42000) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, 300 * USEC_PER_SEC) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, 0) < 0);
assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_MEDIUM) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, 0) >= 0);
@@ -308,7 +310,7 @@ static void test_ra(void) {
assert_se(sd_radv_set_ifindex(ra, 42) >= 0);
assert_se(sd_radv_set_mac(ra, &mac_addr) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, 180) >= 0);
assert_se(sd_radv_set_router_lifetime(ra, 180 * USEC_PER_SEC) >= 0);
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);