]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd-network/sd-radv.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / libsystemd-network / sd-radv.c
index 4f5dbf0090b9f4a090950dcefa9d499e81202c85..6611746a589546db97eee8910afd03a7002f0c2d 100644 (file)
@@ -148,8 +148,6 @@ static be32_t usec_to_be32_sec(usec_t 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;
         struct sockaddr_in6 dst_addr = {
                 .sin6_family = AF_INET6,
                 .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
@@ -183,7 +181,7 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
         assert(ra);
         assert(router_lifetime_is_valid(lifetime_usec));
 
-        r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
+        r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
         if (r < 0)
                 return r;
 
@@ -245,32 +243,36 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
 }
 
 static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_radv *ra = userdata;
-        _cleanup_free_ char *addr = NULL;
+        sd_radv *ra = ASSERT_PTR(userdata);
         struct in6_addr src;
         triple_timestamp timestamp;
         int r;
-        ssize_t buflen;
-        _cleanup_free_ char *buf = NULL;
 
         assert(s);
-        assert(ra);
         assert(ra->event);
 
-        buflen = next_datagram_size_fd(fd);
-        if (buflen < 0)
-                return (int) buflen;
+        ssize_t buflen = next_datagram_size_fd(fd);
+        if (buflen < 0) {
+                if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
+                        return 0;
+
+                log_radv_errno(ra, buflen, "Failed to determine datagram size to read, ignoring: %m");
+                return 0;
+        }
 
-        buf = new0(char, buflen);
+        _cleanup_free_ char *buf = new0(char, buflen);
         if (!buf)
                 return -ENOMEM;
 
         r = icmp6_receive(fd, buf, buflen, &src, &timestamp);
         if (r < 0) {
+                if (ERRNO_IS_TRANSIENT(r) || ERRNO_IS_DISCONNECT(r))
+                        return 0;
+
                 switch (r) {
                 case -EADDRNOTAVAIL:
-                        (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr);
-                        log_radv(ra, "Received RS from non-link-local address %s. Ignoring", addr);
+                        log_radv(ra, "Received RS from non-link-local address %s. Ignoring",
+                                 IN6_ADDR_TO_STRING(&src));
                         break;
 
                 case -EMULTIHOP:
@@ -281,11 +283,8 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
                         log_radv(ra, "Received invalid source address from ICMPv6 socket. Ignoring.");
                         break;
 
-                case -EAGAIN: /* ignore spurious wakeups */
-                        break;
-
                 default:
-                        log_radv_errno(ra, r, "Unexpected error receiving from ICMPv6 socket, Ignoring: %m");
+                        log_radv_errno(ra, r, "Unexpected error receiving from ICMPv6 socket, ignoring: %m");
                         break;
                 }
 
@@ -297,28 +296,27 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
                 return 0;
         }
 
-        (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr);
+        const char *addr = IN6_ADDR_TO_STRING(&src);
 
         r = radv_send(ra, &src, ra->lifetime_usec);
         if (r < 0)
-                log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", strnull(addr));
+                log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", addr);
         else
-                log_radv(ra, "Sent solicited Router Advertisement to %s", strnull(addr));
+                log_radv(ra, "Sent solicited Router Advertisement to %s", addr);
 
         return 0;
 }
 
 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 = userdata;
+        sd_radv *ra = ASSERT_PTR(userdata);
         int r;
 
         assert(s);
-        assert(ra);
         assert(ra->event);
         assert(router_lifetime_is_valid(ra->lifetime_usec));
 
-        r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
+        r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
         if (r < 0)
                 goto fail;
 
@@ -354,7 +352,7 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         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_or_monotonic(),
+                             CLOCK_BOOTTIME,
                              usec_add(time_now, timeout), MSEC_PER_SEC,
                              radv_timeout, ra,
                              ra->event_priority, "radv-timeout", true);
@@ -406,7 +404,7 @@ int sd_radv_start(sd_radv *ra) {
                 return 0;
 
         r = event_reset_time(ra->event, &ra->timeout_event_source,
-                             clock_boottime_or_monotonic(),
+                             CLOCK_BOOTTIME,
                              0, 0,
                              radv_timeout, ra,
                              ra->event_priority, "radv-timeout", true);
@@ -572,8 +570,7 @@ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
 }
 
 int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
-        _cleanup_free_ char *addr_p = NULL;
-        sd_radv_prefix *cur;
+        sd_radv_prefix *found = NULL;
         int r;
 
         assert_return(ra, -EINVAL);
@@ -583,10 +580,9 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
         if (in6_addr_is_null(&p->opt.in6_addr))
                 return -ENOEXEC;
 
-        (void) in6_addr_prefix_to_string(&p->opt.in6_addr, p->opt.prefixlen, &addr_p);
+        const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen);
 
         LIST_FOREACH(prefix, cur, ra->prefixes) {
-
                 r = in_addr_prefix_intersect(AF_INET6,
                                              (const union in_addr_union*) &cur->opt.in6_addr,
                                              cur->opt.prefixlen,
@@ -598,60 +594,69 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
                         continue;
 
                 if (cur->opt.prefixlen == p->opt.prefixlen) {
-                        /* p and cur may be equivalent. First increment the counter. */
-                        sd_radv_prefix_ref(p);
-
-                        /* Then, remove the old entry. */
-                        LIST_REMOVE(prefix, ra->prefixes, cur);
-                        sd_radv_prefix_unref(cur);
-
-                        /* Finally, add the new entry. */
-                        LIST_APPEND(prefix, ra->prefixes, p);
-
-                        log_radv(ra, "Updated/replaced IPv6 prefix %s (preferred: %s, valid: %s)",
-                                 strna(addr_p),
-                                 FORMAT_TIMESPAN(p->lifetime_preferred_usec, USEC_PER_SEC),
-                                 FORMAT_TIMESPAN(p->lifetime_valid_usec, USEC_PER_SEC));
-                        return 0;
+                        found = cur;
+                        break;
                 }
 
-                _cleanup_free_ char *addr_cur = NULL;
-                (void) in6_addr_prefix_to_string(&cur->opt.in6_addr, cur->opt.prefixlen, &addr_cur);
                 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
                                       "IPv6 prefix %s conflicts with %s, ignoring.",
-                                      strna(addr_p), strna(addr_cur));
+                                      addr_p,
+                                      IN6_ADDR_PREFIX_TO_STRING(&cur->opt.in6_addr, cur->opt.prefixlen));
         }
 
-        sd_radv_prefix_ref(p);
-        LIST_APPEND(prefix, ra->prefixes, p);
-        ra->n_prefixes++;
+        if (found) {
+                /* p and cur may be equivalent. First increment the reference counter. */
+                sd_radv_prefix_ref(p);
 
-        if (ra->state == RADV_STATE_IDLE) {
-                log_radv(ra, "Added prefix %s", strna(addr_p));
-                return 0;
+                /* Then, remove the old entry. */
+                LIST_REMOVE(prefix, ra->prefixes, found);
+                sd_radv_prefix_unref(found);
+
+                /* Finally, add the new entry. */
+                LIST_APPEND(prefix, ra->prefixes, p);
+
+                log_radv(ra, "Updated/replaced IPv6 prefix %s (preferred: %s, valid: %s)",
+                         addr_p,
+                         FORMAT_TIMESPAN(p->lifetime_preferred_usec, USEC_PER_SEC),
+                         FORMAT_TIMESPAN(p->lifetime_valid_usec, USEC_PER_SEC));
+        } else {
+                /* The prefix is new. Let's simply add it. */
+
+                sd_radv_prefix_ref(p);
+                LIST_APPEND(prefix, ra->prefixes, p);
+                ra->n_prefixes++;
+
+                log_radv(ra, "Added prefix %s", addr_p);
         }
 
+        if (ra->state == RADV_STATE_IDLE)
+                return 0;
+
+        if (ra->ra_sent == 0)
+                return 0;
+
         /* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
-        if (ra->ra_sent > 0) {
-                r = radv_send(ra, NULL, ra->lifetime_usec);
-                if (r < 0)
-                        log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix: %m");
-                else
-                        log_radv(ra, "Sent Router Advertisement for added prefix");
-        }
+        r = radv_send(ra, NULL, ra->lifetime_usec);
+        if (r < 0)
+                log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix %s: %m", addr_p);
+        else
+                log_radv(ra, "Sent Router Advertisement for added/updated prefix %s.", addr_p);
 
         return 0;
 }
 
-sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra,
-                                               const struct in6_addr *prefix,
-                                               unsigned char prefixlen) {
-        sd_radv_prefix *cur, *next;
+void sd_radv_remove_prefix(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                unsigned char prefixlen) {
 
-        assert_return(ra, NULL);
-        assert_return(prefix, NULL);
+        if (!ra)
+                return;
 
-        LIST_FOREACH_SAFE(prefix, cur, next, ra->prefixes) {
+        if (!prefix)
+                return;
+
+        LIST_FOREACH(prefix, cur, ra->prefixes) {
                 if (prefixlen != cur->opt.prefixlen)
                         continue;
 
@@ -661,25 +666,20 @@ sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra,
                 LIST_REMOVE(prefix, ra->prefixes, cur);
                 ra->n_prefixes--;
                 sd_radv_prefix_unref(cur);
-
-                break;
+                return;
         }
-
-        return cur;
 }
 
 int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
-        _cleanup_free_ char *addr_p = NULL;
-        sd_radv_route_prefix *cur;
+        sd_radv_route_prefix *found = NULL;
         int r;
 
         assert_return(ra, -EINVAL);
         assert_return(p, -EINVAL);
 
-        (void) in6_addr_prefix_to_string(&p->opt.in6_addr, p->opt.prefixlen, &addr_p);
+        const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen);
 
         LIST_FOREACH(prefix, cur, ra->route_prefixes) {
-
                 r = in_addr_prefix_intersect(AF_INET6,
                                              (const union in_addr_union*) &cur->opt.in6_addr,
                                              cur->opt.prefixlen,
@@ -691,52 +691,63 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
                         continue;
 
                 if (cur->opt.prefixlen == p->opt.prefixlen) {
-                        /* p and cur may be equivalent. First increment the counter. */
-                        sd_radv_route_prefix_ref(p);
-
-                        /* Then, remove the old entry. */
-                        LIST_REMOVE(prefix, ra->route_prefixes, cur);
-                        sd_radv_route_prefix_unref(cur);
-
-                        /* Finally, add the new entry. */
-                        LIST_APPEND(prefix, ra->route_prefixes, p);
-
-                        log_radv(ra, "Updated/replaced IPv6 route prefix %s (lifetime: %s)",
-                                 strna(addr_p),
-                                 FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
-                        return 0;
+                        found = cur;
+                        break;
                 }
 
-                _cleanup_free_ char *addr_cur = NULL;
-                (void) in6_addr_prefix_to_string(&cur->opt.in6_addr, cur->opt.prefixlen, &addr_cur);
                 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
                                       "IPv6 route prefix %s conflicts with %s, ignoring.",
-                                      strna(addr_p), strna(addr_cur));
+                                      addr_p,
+                                      IN6_ADDR_PREFIX_TO_STRING(&cur->opt.in6_addr, cur->opt.prefixlen));
         }
 
-        sd_radv_route_prefix_ref(p);
-        LIST_APPEND(prefix, ra->route_prefixes, p);
-        ra->n_route_prefixes++;
+        if (found) {
+                /* p and cur may be equivalent. First increment the reference counter. */
+                sd_radv_route_prefix_ref(p);
+
+                /* Then, remove the old entry. */
+                LIST_REMOVE(prefix, ra->route_prefixes, found);
+                sd_radv_route_prefix_unref(found);
+
+                /* Finally, add the new entry. */
+                LIST_APPEND(prefix, ra->route_prefixes, p);
+
+                log_radv(ra, "Updated/replaced IPv6 route prefix %s (lifetime: %s)",
+                         strna(addr_p),
+                         FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
+        } else {
+                /* The route prefix is new. Let's simply add it. */
+
+                sd_radv_route_prefix_ref(p);
+                LIST_APPEND(prefix, ra->route_prefixes, p);
+                ra->n_route_prefixes++;
 
-        if (ra->state == RADV_STATE_IDLE) {
                 log_radv(ra, "Added route prefix %s", strna(addr_p));
-                return 0;
         }
 
+        if (ra->state == RADV_STATE_IDLE)
+                return 0;
+
+        if (ra->ra_sent == 0)
+                return 0;
+
         /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
-        if (ra->ra_sent > 0) {
-                r = radv_send(ra, NULL, ra->lifetime_usec);
-                if (r < 0)
-                        log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix: %m");
-                else
-                        log_radv(ra, "Sent Router Advertisement for added route prefix");
-        }
+        r = radv_send(ra, NULL, ra->lifetime_usec);
+        if (r < 0)
+                log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix %s: %m",
+                               strna(addr_p));
+        else
+                log_radv(ra, "Sent Router Advertisement for added route prefix %s.", strna(addr_p));
 
         return 0;
 }
 
-int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
-                               const struct in6_addr *dns, size_t n_dns) {
+int sd_radv_set_rdnss(
+                sd_radv *ra,
+                uint32_t lifetime,
+                const struct in6_addr *dns,
+                size_t n_dns) {
+
         _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
         size_t len;
 
@@ -769,11 +780,13 @@ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
         return 0;
 }
 
-int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
-                               char **search_list) {
+int sd_radv_set_dnssl(
+                sd_radv *ra,
+                uint32_t lifetime,
+                char **search_list) {
+
         _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
         size_t len = 0;
-        char **s;
         uint8_t *p;
 
         assert_return(ra, -EINVAL);
@@ -849,8 +862,11 @@ int sd_radv_prefix_new(sd_radv_prefix **ret) {
 
 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
 
-int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
-                                       unsigned char prefixlen) {
+int sd_radv_prefix_set_prefix(
+                sd_radv_prefix *p,
+                const struct in6_addr *in6_addr,
+                unsigned char prefixlen) {
+
         assert_return(p, -EINVAL);
         assert_return(in6_addr, -EINVAL);
 
@@ -867,8 +883,11 @@ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr
         return 0;
 }
 
-int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
-                                       unsigned char *ret_prefixlen) {
+int sd_radv_prefix_get_prefix(
+                sd_radv_prefix *p,
+                struct in6_addr *ret_in6_addr,
+                unsigned char *ret_prefixlen) {
+
         assert_return(p, -EINVAL);
         assert_return(ret_in6_addr, -EINVAL);
         assert_return(ret_prefixlen, -EINVAL);
@@ -887,8 +906,7 @@ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
         return 0;
 }
 
-int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
-                                                          int address_autoconfiguration) {
+int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p, int address_autoconfiguration) {
         assert_return(p, -EINVAL);
 
         SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
@@ -940,8 +958,11 @@ int sd_radv_route_prefix_new(sd_radv_route_prefix **ret) {
 
 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_route_prefix, sd_radv_route_prefix, mfree);
 
-int sd_radv_route_prefix_set_prefix(sd_radv_route_prefix *p, const struct in6_addr *in6_addr,
-                                             unsigned char prefixlen) {
+int sd_radv_route_prefix_set_prefix(
+                sd_radv_route_prefix *p,
+                const struct in6_addr *in6_addr,
+                unsigned char prefixlen) {
+
         assert_return(p, -EINVAL);
         assert_return(in6_addr, -EINVAL);