if (r < 0)
return r;
- struct in6_addr src = {};
+ struct in6_addr src;
r = sd_ndisc_router_solicit_get_sender_address(rs, &src);
- if (r < 0 && r != -ENODATA) /* null address is allowed */
+ if (r == -ENODATA) /* null address is allowed */
+ return sd_radv_send(ra); /* When an unsolicited RA, we need to also update timer. */
+ if (r < 0)
return log_radv_errno(ra, r, "Failed to get sender address of RS, ignoring: %m");
- if (r >= 0 && in6_addr_equal(&src, &ra->ipv6ll))
+ if (in6_addr_equal(&src, &ra->ipv6ll))
/* This should be definitely caused by a misconfiguration. If we send RA to ourself, the
* kernel complains about that. Let's ignore the packet. */
return log_radv_errno(ra, SYNTHETIC_ERRNO(EADDRINUSE), "Received RS from the same interface, ignoring.");
}
static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- usec_t min_timeout, max_timeout, time_now, timeout;
sd_radv *ra = ASSERT_PTR(userdata);
+
+ if (sd_radv_send(ra) < 0)
+ (void) sd_radv_stop(ra);
+
+ return 0;
+}
+
+int sd_radv_send(sd_radv *ra) {
+ usec_t min_timeout, max_timeout, time_now, timeout;
int r;
- assert(s);
- assert(ra->event);
+ assert_return(ra, -EINVAL);
+ assert_return(ra->event, -EINVAL);
+ assert_return(sd_radv_is_running(ra), -EINVAL);
assert(router_lifetime_is_valid(ra->lifetime_usec));
r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
if (r < 0)
- goto fail;
+ return r;
r = radv_send_router(ra, NULL);
if (r < 0)
- log_radv_errno(ra, r, "Unable to send Router Advertisement, ignoring: %m");
+ return log_radv_errno(ra, r, "Unable to send Router Advertisement: %m");
+
+ ra->ra_sent++;
/* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
- if (ra->ra_sent < RADV_MAX_INITIAL_RTR_ADVERTISEMENTS)
+ if (ra->ra_sent <= RADV_MAX_INITIAL_RTR_ADVERTISEMENTS)
max_timeout = RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
else
max_timeout = RADV_DEFAULT_MAX_TIMEOUT_USEC;
assert(min_timeout <= max_timeout * 3 / 4);
timeout = min_timeout + random_u64_range(max_timeout - min_timeout);
- log_radv(ra, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
-
- r = event_reset_time(ra->event, &ra->timeout_event_source,
- CLOCK_BOOTTIME,
- usec_add(time_now, timeout), MSEC_PER_SEC,
- radv_timeout, ra,
- ra->event_priority, "radv-timeout", true);
- if (r < 0)
- goto fail;
-
- ra->ra_sent++;
-
- return 0;
-
-fail:
- sd_radv_stop(ra);
-
- return 0;
+ log_radv(ra, "Sent unsolicited Router Advertisement. Next advertisement will be in %s.",
+ FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
+
+ return event_reset_time(
+ ra->event, &ra->timeout_event_source,
+ CLOCK_BOOTTIME,
+ usec_add(time_now, timeout), MSEC_PER_SEC,
+ radv_timeout, ra,
+ ra->event_priority, "radv-timeout", true);
}
int sd_radv_stop(sd_radv *ra) {