]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #32345 from yuwata/sd-radv-send
authorLuca Boccassi <bluca@debian.org>
Fri, 19 Apr 2024 09:59:08 +0000 (11:59 +0200)
committerGitHub <noreply@github.com>
Fri, 19 Apr 2024 09:59:08 +0000 (11:59 +0200)
sd-radv: introduce sd_radv_send(), and reset timer on sending unsplicited RA

src/libsystemd-network/sd-radv.c
src/systemd/sd-radv.h

index 053dd0653b1ad6c33ae23db67230b6ce78a6e8e1..cc8d144e6dd4189b81a71268e15ffce915b15db9 100644 (file)
@@ -279,11 +279,13 @@ static int radv_process_packet(sd_radv *ra, ICMP6Packet *packet) {
         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.");
@@ -314,24 +316,35 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
 }
 
 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;
@@ -355,24 +368,15 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         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) {
index 6d17dcc7f6d82dd81d29032e15d874209c71e8eb..32ea3bd4ede36eebe516535b7737fef358497380 100644 (file)
@@ -48,6 +48,7 @@ sd_event *sd_radv_get_event(sd_radv *ra);
 int sd_radv_start(sd_radv *ra);
 int sd_radv_stop(sd_radv *ra);
 int sd_radv_is_running(sd_radv *ra);
+int sd_radv_send(sd_radv *ra);
 
 int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
 int sd_radv_set_ifname(sd_radv *ra, const char *interface_name);