]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd-network/sd-radv.c
Merge pull request #32299 from yuwata/network-radv-ignore-rs-from-the-same-interface
[thirdparty/systemd.git] / src / libsystemd-network / sd-radv.c
index 62b69e633ff608570d530bea3a4fbf12c88f4e7d..053dd0653b1ad6c33ae23db67230b6ce78a6e8e1 100644 (file)
@@ -129,9 +129,32 @@ static bool router_lifetime_is_valid(usec_t lifetime_usec) {
                  lifetime_usec <= RADV_MAX_ROUTER_LIFETIME_USEC);
 }
 
-static int radv_send_router(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_usec) {
+static int radv_send_router_on_stop(sd_radv *ra) {
+        static const struct nd_router_advert adv = {
+                .nd_ra_type = ND_ROUTER_ADVERT,
+        };
+
+        _cleanup_set_free_ Set *options = NULL;
+        usec_t time_now;
+        int r;
+
+        assert(ra);
+
+        r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
+        if (r < 0)
+                return r;
+
+        if (!ether_addr_is_null(&ra->mac_addr)) {
+                r = ndisc_option_set_link_layer_address(&options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, &ra->mac_addr);
+                if (r < 0)
+                        return r;
+        }
+
+        return ndisc_send(ra->fd, &IN6_ADDR_ALL_NODES_MULTICAST, &adv.nd_ra_hdr, options, time_now);
+}
+
+static int radv_send_router(sd_radv *ra, const struct in6_addr *dst) {
         assert(ra);
-        assert(router_lifetime_is_valid(lifetime_usec));
 
         struct sockaddr_in6 dst_addr = {
                 .sin6_family = AF_INET6,
@@ -139,7 +162,7 @@ static int radv_send_router(sd_radv *ra, const struct in6_addr *dst, usec_t life
         };
         struct nd_router_advert adv = {
                 .nd_ra_type = ND_ROUTER_ADVERT,
-                .nd_ra_router_lifetime = usec_to_be16_sec(lifetime_usec),
+                .nd_ra_router_lifetime = usec_to_be16_sec(ra->lifetime_usec),
                 .nd_ra_retransmit = usec_to_be32_msec(ra->retransmit_usec),
         };
         struct {
@@ -265,7 +288,7 @@ static int radv_process_packet(sd_radv *ra, ICMP6Packet *packet) {
                  * kernel complains about that. Let's ignore the packet. */
                 return log_radv_errno(ra, SYNTHETIC_ERRNO(EADDRINUSE), "Received RS from the same interface, ignoring.");
 
-        r = radv_send_router(ra, &src, ra->lifetime_usec);
+        r = radv_send_router(ra, &src);
         if (r < 0)
                 return log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", IN6_ADDR_TO_STRING(&src));
 
@@ -303,7 +326,7 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         if (r < 0)
                 goto fail;
 
-        r = radv_send_router(ra, NULL, ra->lifetime_usec);
+        r = radv_send_router(ra, NULL);
         if (r < 0)
                 log_radv_errno(ra, r, "Unable to send Router Advertisement, ignoring: %m");
 
@@ -366,7 +389,7 @@ int sd_radv_stop(sd_radv *ra) {
         /* RFC 4861, Section 6.2.5:
          * the router SHOULD transmit one or more (but not more than MAX_FINAL_RTR_ADVERTISEMENTS) final
          * multicast Router Advertisements on the interface with a Router Lifetime field of zero. */
-        r = radv_send_router(ra, NULL, 0);
+        r = radv_send_router_on_stop(ra);
         if (r < 0)
                 log_radv_errno(ra, r, "Unable to send last Router Advertisement with router lifetime set to zero, ignoring: %m");
 
@@ -695,7 +718,7 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
                 return 0;
 
         /* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
-        r = radv_send_router(ra, NULL, ra->lifetime_usec);
+        r = radv_send_router(ra, NULL);
         if (r < 0)
                 log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix %s, ignoring: %m", addr_p);
         else
@@ -791,7 +814,7 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
                 return 0;
 
         /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
-        r = radv_send_router(ra, NULL, ra->lifetime_usec);
+        r = radv_send_router(ra, NULL);
         if (r < 0)
                 log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix %s, ignoring: %m",
                                strna(addr_p));
@@ -863,7 +886,7 @@ int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
                 return 0;
 
         /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
-        r = radv_send_router(ra, NULL, ra->lifetime_usec);
+        r = radv_send_router(ra, NULL);
         if (r < 0)
                 log_radv_errno(ra, r, "Unable to send Router Advertisement for added PREF64 prefix %s, ignoring: %m",
                                strna(addr_p));