LCOV - code coverage report
Current view: top level - libsystemd-network - sd-radv.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 278 396 70.2 %
Date: 2019-08-22 15:41:25 Functions: 31 34 91.2 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : /***
       3             :   Copyright © 2017 Intel Corporation. All rights reserved.
       4             : ***/
       5             : 
       6             : #include <netinet/icmp6.h>
       7             : #include <netinet/in.h>
       8             : #include <arpa/inet.h>
       9             : 
      10             : #include "sd-radv.h"
      11             : 
      12             : #include "alloc-util.h"
      13             : #include "dns-domain.h"
      14             : #include "ether-addr-util.h"
      15             : #include "event-util.h"
      16             : #include "fd-util.h"
      17             : #include "icmp6-util.h"
      18             : #include "in-addr-util.h"
      19             : #include "io-util.h"
      20             : #include "macro.h"
      21             : #include "memory-util.h"
      22             : #include "radv-internal.h"
      23             : #include "random-util.h"
      24             : #include "socket-util.h"
      25             : #include "string-util.h"
      26             : #include "strv.h"
      27             : 
      28           2 : _public_ int sd_radv_new(sd_radv **ret) {
      29           2 :         _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
      30             : 
      31           2 :         assert_return(ret, -EINVAL);
      32             : 
      33           2 :         ra = new(sd_radv, 1);
      34           2 :         if (!ra)
      35           0 :                 return -ENOMEM;
      36             : 
      37           2 :         *ra = (sd_radv) {
      38             :                 .n_ref = 1,
      39             :                 .fd = -1,
      40             :         };
      41             : 
      42           2 :         *ret = TAKE_PTR(ra);
      43             : 
      44           2 :         return 0;
      45             : }
      46             : 
      47           1 : _public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
      48             :         int r;
      49             : 
      50           1 :         assert_return(ra, -EINVAL);
      51           1 :         assert_return(!ra->event, -EBUSY);
      52             : 
      53           1 :         if (event)
      54           1 :                 ra->event = sd_event_ref(event);
      55             :         else {
      56           0 :                 r = sd_event_default(&ra->event);
      57           0 :                 if (r < 0)
      58           0 :                         return 0;
      59             :         }
      60             : 
      61           1 :         ra->event_priority = priority;
      62             : 
      63           1 :         return 0;
      64             : }
      65             : 
      66           2 : _public_ int sd_radv_detach_event(sd_radv *ra) {
      67             : 
      68           2 :         assert_return(ra, -EINVAL);
      69             : 
      70           2 :         ra->event = sd_event_unref(ra->event);
      71           2 :         return 0;
      72             : }
      73             : 
      74           1 : _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
      75           1 :         assert_return(ra, NULL);
      76             : 
      77           1 :         return ra->event;
      78             : }
      79             : 
      80           3 : static void radv_reset(sd_radv *ra) {
      81           3 :         assert(ra);
      82             : 
      83           3 :         (void) event_source_disable(ra->timeout_event_source);
      84             : 
      85           3 :         ra->recv_event_source =
      86           3 :                 sd_event_source_unref(ra->recv_event_source);
      87             : 
      88           3 :         ra->ra_sent = 0;
      89           3 : }
      90             : 
      91           2 : static sd_radv *radv_free(sd_radv *ra) {
      92           2 :         if (!ra)
      93           0 :                 return NULL;
      94             : 
      95           5 :         while (ra->prefixes) {
      96           3 :                 sd_radv_prefix *p = ra->prefixes;
      97             : 
      98           3 :                 LIST_REMOVE(prefix, ra->prefixes, p);
      99           3 :                 sd_radv_prefix_unref(p);
     100             :         }
     101             : 
     102           2 :         free(ra->rdnss);
     103           2 :         free(ra->dnssl);
     104             : 
     105           2 :         ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
     106             : 
     107           2 :         radv_reset(ra);
     108             : 
     109           2 :         sd_radv_detach_event(ra);
     110             : 
     111           2 :         ra->fd = safe_close(ra->fd);
     112             : 
     113           2 :         return mfree(ra);
     114             : }
     115             : 
     116           8 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
     117             : 
     118           2 : static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_lifetime) {
     119             :         sd_radv_prefix *p;
     120           2 :         struct sockaddr_in6 dst_addr = {
     121             :                 .sin6_family = AF_INET6,
     122             :                 .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
     123             :         };
     124           2 :         struct nd_router_advert adv = {};
     125             :         struct {
     126             :                 struct nd_opt_hdr opthdr;
     127             :                 struct ether_addr slladdr;
     128           2 :         } _packed_ opt_mac = {
     129             :                 .opthdr = {
     130             :                         .nd_opt_type = ND_OPT_SOURCE_LINKADDR,
     131             :                         .nd_opt_len = (sizeof(struct nd_opt_hdr) +
     132             :                                        sizeof(struct ether_addr) - 1) /8 + 1,
     133             :                 },
     134             :         };
     135           2 :         struct nd_opt_mtu opt_mtu =  {
     136             :                 .nd_opt_mtu_type = ND_OPT_MTU,
     137             :                 .nd_opt_mtu_len = 1,
     138             :         };
     139             :         /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, RDNSS
     140             :            and DNSSL */
     141           2 :         struct iovec iov[5 + ra->n_prefixes];
     142           2 :         struct msghdr msg = {
     143             :                 .msg_name = &dst_addr,
     144             :                 .msg_namelen = sizeof(dst_addr),
     145             :                 .msg_iov = iov,
     146             :         };
     147             :         usec_t time_now;
     148             :         int r;
     149             : 
     150           2 :         assert(ra);
     151             : 
     152           2 :         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
     153           2 :         if (r < 0)
     154           0 :                 return r;
     155             : 
     156           2 :         if (dst && !IN6_IS_ADDR_UNSPECIFIED(dst))
     157           0 :                 dst_addr.sin6_addr = *dst;
     158             : 
     159           2 :         adv.nd_ra_type = ND_ROUTER_ADVERT;
     160           2 :         adv.nd_ra_curhoplimit = ra->hop_limit;
     161           2 :         adv.nd_ra_flags_reserved = ra->flags;
     162           2 :         adv.nd_ra_router_lifetime = htobe16(router_lifetime);
     163           2 :         iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
     164             : 
     165             :         /* MAC address is optional, either because the link does not use L2
     166             :            addresses or load sharing is desired. See RFC 4861, Section 4.2 */
     167           2 :         if (!ether_addr_is_null(&ra->mac_addr)) {
     168           2 :                 opt_mac.slladdr = ra->mac_addr;
     169           2 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
     170             :         }
     171             : 
     172           2 :         if (ra->mtu) {
     173           0 :                 opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu);
     174           0 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu));
     175             :         }
     176             : 
     177           8 :         LIST_FOREACH(prefix, p, ra->prefixes) {
     178           6 :                 if (p->valid_until) {
     179             : 
     180           0 :                         if (time_now > p->valid_until)
     181           0 :                                 p->opt.valid_lifetime = 0;
     182             :                         else
     183           0 :                                 p->opt.valid_lifetime = htobe32((p->valid_until - time_now) / USEC_PER_SEC);
     184             : 
     185           0 :                         if (time_now > p->preferred_until)
     186           0 :                                 p->opt.preferred_lifetime = 0;
     187             :                         else
     188           0 :                                 p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC);
     189             :                 }
     190           6 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
     191             :         }
     192             : 
     193           2 :         if (ra->rdnss)
     194           2 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
     195             : 
     196           2 :         if (ra->dnssl)
     197           2 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
     198             : 
     199           2 :         if (sendmsg(ra->fd, &msg, 0) < 0)
     200           0 :                 return -errno;
     201             : 
     202           2 :         return 0;
     203             : }
     204             : 
     205           0 : static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     206           0 :         sd_radv *ra = userdata;
     207           0 :         _cleanup_free_ char *addr = NULL;
     208             :         struct in6_addr src;
     209             :         triple_timestamp timestamp;
     210             :         int r;
     211             :         ssize_t buflen;
     212           0 :         _cleanup_free_ char *buf = NULL;
     213             : 
     214           0 :         assert(s);
     215           0 :         assert(ra);
     216           0 :         assert(ra->event);
     217             : 
     218           0 :         buflen = next_datagram_size_fd(fd);
     219           0 :         if (buflen < 0)
     220           0 :                 return (int) buflen;
     221             : 
     222           0 :         buf = new0(char, buflen);
     223           0 :         if (!buf)
     224           0 :                 return -ENOMEM;
     225             : 
     226           0 :         r = icmp6_receive(fd, buf, buflen, &src, &timestamp);
     227           0 :         if (r < 0) {
     228           0 :                 switch (r) {
     229           0 :                 case -EADDRNOTAVAIL:
     230           0 :                         (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr);
     231           0 :                         log_radv("Received RS from non-link-local address %s. Ignoring", addr);
     232           0 :                         break;
     233             : 
     234           0 :                 case -EMULTIHOP:
     235           0 :                         log_radv("Received RS with invalid hop limit. Ignoring.");
     236           0 :                         break;
     237             : 
     238           0 :                 case -EPFNOSUPPORT:
     239           0 :                         log_radv("Received invalid source address from ICMPv6 socket. Ignoring.");
     240           0 :                         break;
     241             : 
     242           0 :                 case -EAGAIN: /* ignore spurious wakeups */
     243           0 :                         break;
     244             : 
     245           0 :                 default:
     246           0 :                         log_radv_errno(r, "Unexpected error receiving from ICMPv6 socket: %m");
     247           0 :                         break;
     248             :                 }
     249             : 
     250           0 :                 return 0;
     251             :         }
     252             : 
     253           0 :         if ((size_t) buflen < sizeof(struct nd_router_solicit)) {
     254           0 :                 log_radv("Too short packet received");
     255           0 :                 return 0;
     256             :         }
     257             : 
     258           0 :         (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr);
     259             : 
     260           0 :         r = radv_send(ra, &src, ra->lifetime);
     261           0 :         if (r < 0)
     262           0 :                 log_radv_errno(r, "Unable to send solicited Router Advertisement to %s: %m", strnull(addr));
     263             :         else
     264           0 :                 log_radv("Sent solicited Router Advertisement to %s", strnull(addr));
     265             : 
     266           0 :         return 0;
     267             : }
     268             : 
     269           1 : static usec_t radv_compute_timeout(usec_t min, usec_t max) {
     270           1 :         assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
     271             : 
     272           1 :         return min + (random_u32() % (max - min));
     273             : }
     274             : 
     275           1 : static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
     276             :         int r;
     277           1 :         sd_radv *ra = userdata;
     278           1 :         usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
     279           1 :         usec_t max_timeout = SD_RADV_DEFAULT_MAX_TIMEOUT_USEC;
     280             :         usec_t time_now, timeout;
     281             :         char time_string[FORMAT_TIMESPAN_MAX];
     282             : 
     283           1 :         assert(s);
     284           1 :         assert(ra);
     285           1 :         assert(ra->event);
     286             : 
     287           1 :         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
     288           1 :         if (r < 0)
     289           0 :                 goto fail;
     290             : 
     291           1 :         r = radv_send(ra, NULL, ra->lifetime);
     292           1 :         if (r < 0)
     293           0 :                 log_radv_errno(r, "Unable to send Router Advertisement: %m");
     294             : 
     295             :         /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
     296           1 :         if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
     297           1 :                 max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
     298           1 :                 min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
     299             :         }
     300             : 
     301           1 :         timeout = radv_compute_timeout(min_timeout, max_timeout);
     302             : 
     303           1 :         log_radv("Next Router Advertisement in %s",
     304             :                  format_timespan(time_string, FORMAT_TIMESPAN_MAX,
     305             :                                  timeout, USEC_PER_SEC));
     306             : 
     307           1 :         r = event_reset_time(ra->event, &ra->timeout_event_source,
     308             :                              clock_boottime_or_monotonic(),
     309             :                              time_now + timeout, MSEC_PER_SEC,
     310             :                              radv_timeout, ra,
     311           1 :                              ra->event_priority, "radv-timeout", true);
     312           1 :         if (r < 0)
     313           0 :                 goto fail;
     314             : 
     315           1 :         ra->ra_sent++;
     316             : 
     317           1 :         return 0;
     318             : 
     319           0 : fail:
     320           0 :         sd_radv_stop(ra);
     321             : 
     322           0 :         return 0;
     323             : }
     324             : 
     325           1 : _public_ int sd_radv_stop(sd_radv *ra) {
     326             :         int r;
     327             : 
     328           1 :         assert_return(ra, -EINVAL);
     329             : 
     330           1 :         if (ra->state == SD_RADV_STATE_IDLE)
     331           0 :                 return 0;
     332             : 
     333           1 :         log_radv("Stopping IPv6 Router Advertisement daemon");
     334             : 
     335             :         /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
     336             :            with zero lifetime  */
     337           1 :         r = radv_send(ra, NULL, 0);
     338           1 :         if (r < 0)
     339           0 :                 log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
     340             : 
     341           1 :         radv_reset(ra);
     342           1 :         ra->fd = safe_close(ra->fd);
     343           1 :         ra->state = SD_RADV_STATE_IDLE;
     344             : 
     345           1 :         return 0;
     346             : }
     347             : 
     348           1 : _public_ int sd_radv_start(sd_radv *ra) {
     349             :         int r;
     350             : 
     351           1 :         assert_return(ra, -EINVAL);
     352           1 :         assert_return(ra->event, -EINVAL);
     353           1 :         assert_return(ra->ifindex > 0, -EINVAL);
     354             : 
     355           1 :         if (ra->state != SD_RADV_STATE_IDLE)
     356           0 :                 return 0;
     357             : 
     358           1 :         r = event_reset_time(ra->event, &ra->timeout_event_source,
     359             :                              clock_boottime_or_monotonic(),
     360             :                              0, 0,
     361             :                              radv_timeout, ra,
     362           1 :                              ra->event_priority, "radv-timeout", true);
     363           1 :         if (r < 0)
     364           0 :                 goto fail;
     365             : 
     366           1 :         r = icmp6_bind_router_advertisement(ra->ifindex);
     367           1 :         if (r < 0)
     368           0 :                 goto fail;
     369             : 
     370           1 :         ra->fd = r;
     371             : 
     372           1 :         r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
     373           1 :         if (r < 0)
     374           0 :                 goto fail;
     375             : 
     376           1 :         r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
     377           1 :         if (r < 0)
     378           0 :                 goto fail;
     379             : 
     380           1 :         (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
     381             : 
     382           1 :         ra->state = SD_RADV_STATE_ADVERTISING;
     383             : 
     384           1 :         log_radv("Started IPv6 Router Advertisement daemon");
     385             : 
     386           1 :         return 0;
     387             : 
     388           0 :  fail:
     389           0 :         radv_reset(ra);
     390             : 
     391           0 :         return r;
     392             : }
     393             : 
     394           6 : _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
     395           6 :         assert_return(ra, -EINVAL);
     396           5 :         assert_return(ifindex >= -1, -EINVAL);
     397             : 
     398           4 :         if (ra->state != SD_RADV_STATE_IDLE)
     399           0 :                 return -EBUSY;
     400             : 
     401           4 :         ra->ifindex = ifindex;
     402             : 
     403           4 :         return 0;
     404             : }
     405             : 
     406           4 : _public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
     407           4 :         assert_return(ra, -EINVAL);
     408             : 
     409           3 :         if (ra->state != SD_RADV_STATE_IDLE)
     410           0 :                 return -EBUSY;
     411             : 
     412           3 :         if (mac_addr)
     413           2 :                 ra->mac_addr = *mac_addr;
     414             :         else
     415           1 :                 zero(ra->mac_addr);
     416             : 
     417           3 :         return 0;
     418             : }
     419             : 
     420           5 : _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
     421           5 :         assert_return(ra, -EINVAL);
     422           4 :         assert_return(mtu >= 1280, -EINVAL);
     423             : 
     424           2 :         ra->mtu = mtu;
     425             : 
     426           2 :         return 0;
     427             : }
     428             : 
     429           4 : _public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
     430           4 :         assert_return(ra, -EINVAL);
     431             : 
     432           3 :         if (ra->state != SD_RADV_STATE_IDLE)
     433           0 :                 return -EBUSY;
     434             : 
     435           3 :         ra->hop_limit = hop_limit;
     436             : 
     437           3 :         return 0;
     438             : }
     439             : 
     440           7 : _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
     441           7 :         assert_return(ra, -EINVAL);
     442             : 
     443           6 :         if (ra->state != SD_RADV_STATE_IDLE)
     444           0 :                 return -EBUSY;
     445             : 
     446             :         /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the
     447             :            preference value MUST be set to (00) by the sender..." */
     448           6 :         if (router_lifetime == 0 &&
     449           3 :             (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
     450           1 :                 return -ETIME;
     451             : 
     452           5 :         ra->lifetime = router_lifetime;
     453             : 
     454           5 :         return 0;
     455             : }
     456             : 
     457           4 : _public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
     458           4 :         assert_return(ra, -EINVAL);
     459             : 
     460           3 :         if (ra->state != SD_RADV_STATE_IDLE)
     461           0 :                 return -EBUSY;
     462             : 
     463           3 :         SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
     464             : 
     465           3 :         return 0;
     466             : }
     467             : 
     468           4 : _public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
     469           4 :         assert_return(ra, -EINVAL);
     470             : 
     471           3 :         if (ra->state != SD_RADV_STATE_IDLE)
     472           0 :                 return -EBUSY;
     473             : 
     474           3 :         SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
     475             : 
     476           3 :         return 0;
     477             : }
     478             : 
     479           7 : _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
     480           7 :         int r = 0;
     481             : 
     482           7 :         assert_return(ra, -EINVAL);
     483           6 :         assert_return(IN_SET(preference,
     484             :                              SD_NDISC_PREFERENCE_LOW,
     485             :                              SD_NDISC_PREFERENCE_MEDIUM,
     486             :                              SD_NDISC_PREFERENCE_HIGH), -EINVAL);
     487             : 
     488           5 :         ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
     489             : 
     490           5 :         return r;
     491             : }
     492             : 
     493          14 : _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
     494             :         sd_radv_prefix *cur;
     495             :         int r;
     496          14 :         _cleanup_free_ char *addr_p = NULL;
     497             :         char time_string_preferred[FORMAT_TIMESPAN_MAX];
     498             :         char time_string_valid[FORMAT_TIMESPAN_MAX];
     499             :         usec_t time_now, valid, preferred, valid_until, preferred_until;
     500             : 
     501          14 :         assert_return(ra, -EINVAL);
     502             : 
     503          14 :         if (!p)
     504           0 :                 return -EINVAL;
     505             : 
     506             :         /* Refuse prefixes that don't have a prefix set */
     507          14 :         if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr))
     508           0 :                 return -ENOEXEC;
     509             : 
     510          28 :         LIST_FOREACH(prefix, cur, ra->prefixes) {
     511             : 
     512          75 :                 r = in_addr_prefix_intersect(AF_INET6,
     513          25 :                                              (union in_addr_union*) &cur->opt.in6_addr,
     514          25 :                                              cur->opt.prefixlen,
     515          25 :                                              (union in_addr_union*) &p->opt.in6_addr,
     516          25 :                                              p->opt.prefixlen);
     517          25 :                 if (r > 0) {
     518          11 :                         _cleanup_free_ char *addr_cur = NULL;
     519             : 
     520          11 :                         (void) in_addr_to_string(AF_INET6,
     521          11 :                                                  (union in_addr_union*) &p->opt.in6_addr,
     522             :                                                  &addr_p);
     523             : 
     524          11 :                         if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
     525           0 :                                 goto update;
     526             : 
     527          11 :                         (void) in_addr_to_string(AF_INET6,
     528          11 :                                                  (union in_addr_union*) &cur->opt.in6_addr,
     529             :                                                  &addr_cur);
     530          11 :                         log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
     531             :                                  addr_cur, cur->opt.prefixlen,
     532             :                                  addr_p, p->opt.prefixlen);
     533             : 
     534          11 :                         return -EEXIST;
     535             :                 }
     536             :         }
     537             : 
     538           3 :         p = sd_radv_prefix_ref(p);
     539             : 
     540           4 :         LIST_APPEND(prefix, ra->prefixes, p);
     541             : 
     542           3 :         ra->n_prefixes++;
     543             : 
     544           3 :         (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
     545             : 
     546           3 :         if (!dynamic) {
     547           3 :                 log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
     548           3 :                 return 0;
     549             :         }
     550             : 
     551           0 :         cur = p;
     552             : 
     553           0 :  update:
     554           0 :         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
     555           0 :         if (r < 0)
     556           0 :                 return r;
     557             : 
     558           0 :         valid = be32toh(p->opt.valid_lifetime) * USEC_PER_SEC;
     559           0 :         valid_until = usec_add(valid, time_now);
     560           0 :         if (valid_until == USEC_INFINITY)
     561           0 :                 return -EOVERFLOW;
     562             : 
     563           0 :         preferred = be32toh(p->opt.preferred_lifetime) * USEC_PER_SEC;
     564           0 :         preferred_until = usec_add(preferred, time_now);
     565           0 :         if (preferred_until == USEC_INFINITY)
     566           0 :                 return -EOVERFLOW;
     567             : 
     568           0 :         cur->valid_until = valid_until;
     569           0 :         cur->preferred_until = preferred_until;
     570             : 
     571           0 :         log_radv("%s prefix %s/%u preferred %s valid %s",
     572             :                  cur? "Updated": "Added",
     573             :                  addr_p, p->opt.prefixlen,
     574             :                  format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
     575             :                                  preferred, USEC_PER_SEC),
     576             :                  format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX,
     577             :                                  valid, USEC_PER_SEC));
     578             : 
     579           0 :         return 0;
     580             : }
     581             : 
     582           0 : _public_ sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra,
     583             :                                                const struct in6_addr *prefix,
     584             :                                                unsigned char prefixlen) {
     585             :         sd_radv_prefix *cur, *next;
     586             : 
     587           0 :         assert_return(ra, NULL);
     588           0 :         assert_return(prefix, NULL);
     589             : 
     590           0 :         LIST_FOREACH_SAFE(prefix, cur, next, ra->prefixes) {
     591           0 :                 if (prefixlen != cur->opt.prefixlen)
     592           0 :                         continue;
     593             : 
     594           0 :                 if (!in_addr_equal(AF_INET6,
     595             :                                    (union in_addr_union *)prefix,
     596           0 :                                    (union in_addr_union *)&cur->opt.in6_addr))
     597           0 :                         continue;
     598             : 
     599           0 :                 LIST_REMOVE(prefix, ra->prefixes, cur);
     600           0 :                 ra->n_prefixes--;
     601           0 :                 sd_radv_prefix_unref(cur);
     602             : 
     603           0 :                 break;
     604             :         }
     605             : 
     606           0 :         return cur;
     607             : }
     608             : 
     609           8 : _public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
     610             :                                const struct in6_addr *dns, size_t n_dns) {
     611           8 :         _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
     612             :         size_t len;
     613             : 
     614           8 :         assert_return(ra, -EINVAL);
     615           7 :         assert_return(n_dns < 128, -EINVAL);
     616             : 
     617           6 :         if (!dns || n_dns == 0) {
     618           3 :                 ra->rdnss = mfree(ra->rdnss);
     619           3 :                 ra->n_rdnss = 0;
     620             : 
     621           3 :                 return 0;
     622             :         }
     623             : 
     624           3 :         len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
     625             : 
     626           3 :         opt_rdnss = malloc0(len);
     627           3 :         if (!opt_rdnss)
     628           0 :                 return -ENOMEM;
     629             : 
     630           3 :         opt_rdnss->type = SD_RADV_OPT_RDNSS;
     631           3 :         opt_rdnss->length = len / 8;
     632           3 :         opt_rdnss->lifetime = htobe32(lifetime);
     633             : 
     634           3 :         memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
     635             : 
     636           3 :         free_and_replace(ra->rdnss, opt_rdnss);
     637             : 
     638           3 :         ra->n_rdnss = n_dns;
     639             : 
     640           3 :         return 0;
     641             : }
     642             : 
     643           5 : _public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
     644             :                                char **search_list) {
     645           5 :         _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
     646           5 :         size_t len = 0;
     647             :         char **s;
     648             :         uint8_t *p;
     649             : 
     650           5 :         assert_return(ra, -EINVAL);
     651             : 
     652           5 :         if (strv_isempty(search_list)) {
     653           2 :                 ra->dnssl = mfree(ra->dnssl);
     654           2 :                 return 0;
     655             :         }
     656             : 
     657           6 :         STRV_FOREACH(s, search_list)
     658           3 :                 len += strlen(*s) + 2;
     659             : 
     660           3 :         len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
     661             : 
     662           3 :         opt_dnssl = malloc0(len);
     663           3 :         if (!opt_dnssl)
     664           0 :                 return -ENOMEM;
     665             : 
     666           3 :         opt_dnssl->type = SD_RADV_OPT_DNSSL;
     667           3 :         opt_dnssl->length = len / 8;
     668           3 :         opt_dnssl->lifetime = htobe32(lifetime);
     669             : 
     670           3 :         p = (uint8_t *)(opt_dnssl + 1);
     671           3 :         len -= sizeof(struct sd_radv_opt_dns);
     672             : 
     673           6 :         STRV_FOREACH(s, search_list) {
     674             :                 int r;
     675             : 
     676           3 :                 r = dns_name_to_wire_format(*s, p, len, false);
     677           3 :                 if (r < 0)
     678           0 :                         return r;
     679             : 
     680           3 :                 if (len < (size_t)r)
     681           0 :                         return -ENOBUFS;
     682             : 
     683           3 :                 p += r;
     684           3 :                 len -= r;
     685             :         }
     686             : 
     687           3 :         free_and_replace(ra->dnssl, opt_dnssl);
     688             : 
     689           3 :         return 0;
     690             : }
     691             : 
     692           8 : _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
     693             :         sd_radv_prefix *p;
     694             : 
     695           8 :         assert_return(ret, -EINVAL);
     696             : 
     697           8 :         p = new(sd_radv_prefix, 1);
     698           8 :         if (!p)
     699           0 :                 return -ENOMEM;
     700             : 
     701           8 :         *p = (sd_radv_prefix) {
     702             :                 .n_ref = 1,
     703             : 
     704             :                 .opt.type = ND_OPT_PREFIX_INFORMATION,
     705             :                 .opt.length = (sizeof(p->opt) - 1)/8 + 1,
     706             :                 .opt.prefixlen = 64,
     707             : 
     708             :                 /* RFC 4861, Section 6.2.1 */
     709             :                 .opt.flags = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO,
     710             : 
     711           8 :                 .opt.preferred_lifetime = htobe32(604800),
     712           8 :                 .opt.valid_lifetime = htobe32(2592000),
     713             :         };
     714             : 
     715           8 :         *ret = p;
     716           8 :         return 0;
     717             : }
     718             : 
     719          14 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
     720             : 
     721          18 : _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
     722             :                                        unsigned char prefixlen) {
     723          18 :         assert_return(p, -EINVAL);
     724          17 :         assert_return(in6_addr, -EINVAL);
     725             : 
     726          16 :         if (prefixlen < 3 || prefixlen > 128)
     727           5 :                 return -EINVAL;
     728             : 
     729          11 :         if (prefixlen > 64)
     730             :                 /* unusual but allowed, log it */
     731           3 :                 log_radv("Unusual prefix length %d greater than 64", prefixlen);
     732             : 
     733          11 :         p->opt.in6_addr = *in6_addr;
     734          11 :         p->opt.prefixlen = prefixlen;
     735             : 
     736          11 :         return 0;
     737             : }
     738             : 
     739           3 : _public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
     740           3 :         assert_return(p, -EINVAL);
     741             : 
     742           2 :         SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
     743             : 
     744           2 :         return 0;
     745             : }
     746             : 
     747           3 : _public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
     748             :                                                           int address_autoconfiguration) {
     749           3 :         assert_return(p, -EINVAL);
     750             : 
     751           2 :         SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
     752             : 
     753           2 :         return 0;
     754             : }
     755             : 
     756           5 : _public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
     757             :                                                uint32_t valid_lifetime) {
     758           5 :         assert_return(p, -EINVAL);
     759             : 
     760           4 :         p->opt.valid_lifetime = htobe32(valid_lifetime);
     761             : 
     762           4 :         return 0;
     763             : }
     764             : 
     765           5 : _public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
     766             :                                                    uint32_t preferred_lifetime) {
     767           5 :         assert_return(p, -EINVAL);
     768             : 
     769           4 :         p->opt.preferred_lifetime = htobe32(preferred_lifetime);
     770             : 
     771           4 :         return 0;
     772             : }

Generated by: LCOV version 1.14