LCOV - code coverage report
Current view: top level - libsystemd-network - sd-radv.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 278 396 70.2 %
Date: 2019-08-23 13:36:53 Functions: 31 34 91.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 211 371 56.9 %

           Branch data     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                 :          8 : _public_ int sd_radv_new(sd_radv **ret) {
      29                 :          8 :         _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
      30                 :            : 
      31   [ -  +  -  + ]:          8 :         assert_return(ret, -EINVAL);
      32                 :            : 
      33                 :          8 :         ra = new(sd_radv, 1);
      34         [ -  + ]:          8 :         if (!ra)
      35                 :          0 :                 return -ENOMEM;
      36                 :            : 
      37                 :          8 :         *ra = (sd_radv) {
      38                 :            :                 .n_ref = 1,
      39                 :            :                 .fd = -1,
      40                 :            :         };
      41                 :            : 
      42                 :          8 :         *ret = TAKE_PTR(ra);
      43                 :            : 
      44                 :          8 :         return 0;
      45                 :            : }
      46                 :            : 
      47                 :          4 : _public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
      48                 :            :         int r;
      49                 :            : 
      50   [ -  +  -  + ]:          4 :         assert_return(ra, -EINVAL);
      51   [ -  +  -  + ]:          4 :         assert_return(!ra->event, -EBUSY);
      52                 :            : 
      53         [ +  - ]:          4 :         if (event)
      54                 :          4 :                 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                 :          4 :         ra->event_priority = priority;
      62                 :            : 
      63                 :          4 :         return 0;
      64                 :            : }
      65                 :            : 
      66                 :          8 : _public_ int sd_radv_detach_event(sd_radv *ra) {
      67                 :            : 
      68   [ -  +  -  + ]:          8 :         assert_return(ra, -EINVAL);
      69                 :            : 
      70                 :          8 :         ra->event = sd_event_unref(ra->event);
      71                 :          8 :         return 0;
      72                 :            : }
      73                 :            : 
      74                 :          4 : _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
      75   [ -  +  -  + ]:          4 :         assert_return(ra, NULL);
      76                 :            : 
      77                 :          4 :         return ra->event;
      78                 :            : }
      79                 :            : 
      80                 :         12 : static void radv_reset(sd_radv *ra) {
      81         [ -  + ]:         12 :         assert(ra);
      82                 :            : 
      83                 :         12 :         (void) event_source_disable(ra->timeout_event_source);
      84                 :            : 
      85                 :         12 :         ra->recv_event_source =
      86                 :         12 :                 sd_event_source_unref(ra->recv_event_source);
      87                 :            : 
      88                 :         12 :         ra->ra_sent = 0;
      89                 :         12 : }
      90                 :            : 
      91                 :          8 : static sd_radv *radv_free(sd_radv *ra) {
      92         [ -  + ]:          8 :         if (!ra)
      93                 :          0 :                 return NULL;
      94                 :            : 
      95         [ +  + ]:         20 :         while (ra->prefixes) {
      96                 :         12 :                 sd_radv_prefix *p = ra->prefixes;
      97                 :            : 
      98   [ -  +  +  +  :         12 :                 LIST_REMOVE(prefix, ra->prefixes, p);
             -  +  -  + ]
      99                 :         12 :                 sd_radv_prefix_unref(p);
     100                 :            :         }
     101                 :            : 
     102                 :          8 :         free(ra->rdnss);
     103                 :          8 :         free(ra->dnssl);
     104                 :            : 
     105                 :          8 :         ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
     106                 :            : 
     107                 :          8 :         radv_reset(ra);
     108                 :            : 
     109                 :          8 :         sd_radv_detach_event(ra);
     110                 :            : 
     111                 :          8 :         ra->fd = safe_close(ra->fd);
     112                 :            : 
     113                 :          8 :         return mfree(ra);
     114                 :            : }
     115                 :            : 
     116   [ +  +  -  +  :         36 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
                   -  + ]
     117                 :            : 
     118                 :          8 : static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_lifetime) {
     119                 :            :         sd_radv_prefix *p;
     120                 :          8 :         struct sockaddr_in6 dst_addr = {
     121                 :            :                 .sin6_family = AF_INET6,
     122                 :            :                 .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
     123                 :            :         };
     124                 :          8 :         struct nd_router_advert adv = {};
     125                 :            :         struct {
     126                 :            :                 struct nd_opt_hdr opthdr;
     127                 :            :                 struct ether_addr slladdr;
     128                 :          8 :         } _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                 :          8 :         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                 :          8 :         struct iovec iov[5 + ra->n_prefixes];
     142                 :          8 :         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         [ -  + ]:          8 :         assert(ra);
     151                 :            : 
     152                 :          8 :         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
     153         [ -  + ]:          8 :         if (r < 0)
     154                 :          0 :                 return r;
     155                 :            : 
     156   [ -  +  #  #  :          8 :         if (dst && !IN6_IS_ADDR_UNSPECIFIED(dst))
          #  #  #  #  #  
                #  #  # ]
     157                 :          0 :                 dst_addr.sin6_addr = *dst;
     158                 :            : 
     159                 :          8 :         adv.nd_ra_type = ND_ROUTER_ADVERT;
     160                 :          8 :         adv.nd_ra_curhoplimit = ra->hop_limit;
     161                 :          8 :         adv.nd_ra_flags_reserved = ra->flags;
     162                 :          8 :         adv.nd_ra_router_lifetime = htobe16(router_lifetime);
     163                 :          8 :         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         [ +  - ]:          8 :         if (!ether_addr_is_null(&ra->mac_addr)) {
     168                 :          8 :                 opt_mac.slladdr = ra->mac_addr;
     169                 :          8 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
     170                 :            :         }
     171                 :            : 
     172         [ -  + ]:          8 :         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         [ +  + ]:         32 :         LIST_FOREACH(prefix, p, ra->prefixes) {
     178         [ -  + ]:         24 :                 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                 :         24 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
     191                 :            :         }
     192                 :            : 
     193         [ +  - ]:          8 :         if (ra->rdnss)
     194                 :          8 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
     195                 :            : 
     196         [ +  - ]:          8 :         if (ra->dnssl)
     197                 :          8 :                 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
     198                 :            : 
     199         [ -  + ]:          8 :         if (sendmsg(ra->fd, &msg, 0) < 0)
     200                 :          0 :                 return -errno;
     201                 :            : 
     202                 :          8 :         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                 :          4 : static usec_t radv_compute_timeout(usec_t min, usec_t max) {
     270   [ -  +  -  + ]:          4 :         assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
     271                 :            : 
     272                 :          4 :         return min + (random_u32() % (max - min));
     273                 :            : }
     274                 :            : 
     275                 :          4 : static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
     276                 :            :         int r;
     277                 :          4 :         sd_radv *ra = userdata;
     278                 :          4 :         usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
     279                 :          4 :         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         [ -  + ]:          4 :         assert(s);
     284         [ -  + ]:          4 :         assert(ra);
     285         [ -  + ]:          4 :         assert(ra->event);
     286                 :            : 
     287                 :          4 :         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
     288         [ -  + ]:          4 :         if (r < 0)
     289                 :          0 :                 goto fail;
     290                 :            : 
     291                 :          4 :         r = radv_send(ra, NULL, ra->lifetime);
     292         [ -  + ]:          4 :         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         [ +  - ]:          4 :         if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
     297                 :          4 :                 max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
     298                 :          4 :                 min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
     299                 :            :         }
     300                 :            : 
     301                 :          4 :         timeout = radv_compute_timeout(min_timeout, max_timeout);
     302                 :            : 
     303                 :          4 :         log_radv("Next Router Advertisement in %s",
     304                 :            :                  format_timespan(time_string, FORMAT_TIMESPAN_MAX,
     305                 :            :                                  timeout, USEC_PER_SEC));
     306                 :            : 
     307                 :          4 :         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                 :          4 :                              ra->event_priority, "radv-timeout", true);
     312         [ -  + ]:          4 :         if (r < 0)
     313                 :          0 :                 goto fail;
     314                 :            : 
     315                 :          4 :         ra->ra_sent++;
     316                 :            : 
     317                 :          4 :         return 0;
     318                 :            : 
     319                 :          0 : fail:
     320                 :          0 :         sd_radv_stop(ra);
     321                 :            : 
     322                 :          0 :         return 0;
     323                 :            : }
     324                 :            : 
     325                 :          4 : _public_ int sd_radv_stop(sd_radv *ra) {
     326                 :            :         int r;
     327                 :            : 
     328   [ -  +  -  + ]:          4 :         assert_return(ra, -EINVAL);
     329                 :            : 
     330         [ -  + ]:          4 :         if (ra->state == SD_RADV_STATE_IDLE)
     331                 :          0 :                 return 0;
     332                 :            : 
     333                 :          4 :         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                 :          4 :         r = radv_send(ra, NULL, 0);
     338         [ -  + ]:          4 :         if (r < 0)
     339                 :          0 :                 log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
     340                 :            : 
     341                 :          4 :         radv_reset(ra);
     342                 :          4 :         ra->fd = safe_close(ra->fd);
     343                 :          4 :         ra->state = SD_RADV_STATE_IDLE;
     344                 :            : 
     345                 :          4 :         return 0;
     346                 :            : }
     347                 :            : 
     348                 :          4 : _public_ int sd_radv_start(sd_radv *ra) {
     349                 :            :         int r;
     350                 :            : 
     351   [ -  +  -  + ]:          4 :         assert_return(ra, -EINVAL);
     352   [ -  +  -  + ]:          4 :         assert_return(ra->event, -EINVAL);
     353   [ -  +  -  + ]:          4 :         assert_return(ra->ifindex > 0, -EINVAL);
     354                 :            : 
     355         [ -  + ]:          4 :         if (ra->state != SD_RADV_STATE_IDLE)
     356                 :          0 :                 return 0;
     357                 :            : 
     358                 :          4 :         r = event_reset_time(ra->event, &ra->timeout_event_source,
     359                 :            :                              clock_boottime_or_monotonic(),
     360                 :            :                              0, 0,
     361                 :            :                              radv_timeout, ra,
     362                 :          4 :                              ra->event_priority, "radv-timeout", true);
     363         [ -  + ]:          4 :         if (r < 0)
     364                 :          0 :                 goto fail;
     365                 :            : 
     366                 :          4 :         r = icmp6_bind_router_advertisement(ra->ifindex);
     367         [ -  + ]:          4 :         if (r < 0)
     368                 :          0 :                 goto fail;
     369                 :            : 
     370                 :          4 :         ra->fd = r;
     371                 :            : 
     372                 :          4 :         r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
     373         [ -  + ]:          4 :         if (r < 0)
     374                 :          0 :                 goto fail;
     375                 :            : 
     376                 :          4 :         r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
     377         [ -  + ]:          4 :         if (r < 0)
     378                 :          0 :                 goto fail;
     379                 :            : 
     380                 :          4 :         (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
     381                 :            : 
     382                 :          4 :         ra->state = SD_RADV_STATE_ADVERTISING;
     383                 :            : 
     384                 :          4 :         log_radv("Started IPv6 Router Advertisement daemon");
     385                 :            : 
     386                 :          4 :         return 0;
     387                 :            : 
     388                 :          0 :  fail:
     389                 :          0 :         radv_reset(ra);
     390                 :            : 
     391                 :          0 :         return r;
     392                 :            : }
     393                 :            : 
     394                 :         24 : _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
     395   [ +  +  +  + ]:         24 :         assert_return(ra, -EINVAL);
     396   [ +  +  +  + ]:         20 :         assert_return(ifindex >= -1, -EINVAL);
     397                 :            : 
     398         [ -  + ]:         16 :         if (ra->state != SD_RADV_STATE_IDLE)
     399                 :          0 :                 return -EBUSY;
     400                 :            : 
     401                 :         16 :         ra->ifindex = ifindex;
     402                 :            : 
     403                 :         16 :         return 0;
     404                 :            : }
     405                 :            : 
     406                 :         16 : _public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
     407   [ +  +  +  + ]:         16 :         assert_return(ra, -EINVAL);
     408                 :            : 
     409         [ -  + ]:         12 :         if (ra->state != SD_RADV_STATE_IDLE)
     410                 :          0 :                 return -EBUSY;
     411                 :            : 
     412         [ +  + ]:         12 :         if (mac_addr)
     413                 :          8 :                 ra->mac_addr = *mac_addr;
     414                 :            :         else
     415         [ +  - ]:          4 :                 zero(ra->mac_addr);
     416                 :            : 
     417                 :         12 :         return 0;
     418                 :            : }
     419                 :            : 
     420                 :         20 : _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
     421   [ +  +  +  + ]:         20 :         assert_return(ra, -EINVAL);
     422   [ +  +  +  + ]:         16 :         assert_return(mtu >= 1280, -EINVAL);
     423                 :            : 
     424                 :          8 :         ra->mtu = mtu;
     425                 :            : 
     426                 :          8 :         return 0;
     427                 :            : }
     428                 :            : 
     429                 :         16 : _public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
     430   [ +  +  +  + ]:         16 :         assert_return(ra, -EINVAL);
     431                 :            : 
     432         [ -  + ]:         12 :         if (ra->state != SD_RADV_STATE_IDLE)
     433                 :          0 :                 return -EBUSY;
     434                 :            : 
     435                 :         12 :         ra->hop_limit = hop_limit;
     436                 :            : 
     437                 :         12 :         return 0;
     438                 :            : }
     439                 :            : 
     440                 :         28 : _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
     441   [ +  +  +  + ]:         28 :         assert_return(ra, -EINVAL);
     442                 :            : 
     443         [ -  + ]:         24 :         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         [ +  + ]:         24 :         if (router_lifetime == 0 &&
     449         [ +  + ]:         12 :             (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
     450                 :          4 :                 return -ETIME;
     451                 :            : 
     452                 :         20 :         ra->lifetime = router_lifetime;
     453                 :            : 
     454                 :         20 :         return 0;
     455                 :            : }
     456                 :            : 
     457                 :         16 : _public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
     458   [ +  +  +  + ]:         16 :         assert_return(ra, -EINVAL);
     459                 :            : 
     460         [ -  + ]:         12 :         if (ra->state != SD_RADV_STATE_IDLE)
     461                 :          0 :                 return -EBUSY;
     462                 :            : 
     463         [ +  + ]:         12 :         SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
     464                 :            : 
     465                 :         12 :         return 0;
     466                 :            : }
     467                 :            : 
     468                 :         16 : _public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
     469   [ +  +  +  + ]:         16 :         assert_return(ra, -EINVAL);
     470                 :            : 
     471         [ -  + ]:         12 :         if (ra->state != SD_RADV_STATE_IDLE)
     472                 :          0 :                 return -EBUSY;
     473                 :            : 
     474         [ +  + ]:         12 :         SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
     475                 :            : 
     476                 :         12 :         return 0;
     477                 :            : }
     478                 :            : 
     479                 :         28 : _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
     480                 :         28 :         int r = 0;
     481                 :            : 
     482   [ +  +  +  + ]:         28 :         assert_return(ra, -EINVAL);
     483   [ +  +  +  +  :         24 :         assert_return(IN_SET(preference,
                   +  + ]
     484                 :            :                              SD_NDISC_PREFERENCE_LOW,
     485                 :            :                              SD_NDISC_PREFERENCE_MEDIUM,
     486                 :            :                              SD_NDISC_PREFERENCE_HIGH), -EINVAL);
     487                 :            : 
     488                 :         20 :         ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
     489                 :            : 
     490                 :         20 :         return r;
     491                 :            : }
     492                 :            : 
     493                 :         56 : _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
     494                 :            :         sd_radv_prefix *cur;
     495                 :            :         int r;
     496                 :         56 :         _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   [ -  +  -  + ]:         56 :         assert_return(ra, -EINVAL);
     502                 :            : 
     503         [ -  + ]:         56 :         if (!p)
     504                 :          0 :                 return -EINVAL;
     505                 :            : 
     506                 :            :         /* Refuse prefixes that don't have a prefix set */
     507   [ -  +  #  #  :         56 :         if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr))
          #  #  #  #  -  
                      + ]
     508                 :          0 :                 return -ENOEXEC;
     509                 :            : 
     510         [ +  + ]:        112 :         LIST_FOREACH(prefix, cur, ra->prefixes) {
     511                 :            : 
     512                 :        300 :                 r = in_addr_prefix_intersect(AF_INET6,
     513                 :        100 :                                              (union in_addr_union*) &cur->opt.in6_addr,
     514                 :        100 :                                              cur->opt.prefixlen,
     515                 :        100 :                                              (union in_addr_union*) &p->opt.in6_addr,
     516                 :        100 :                                              p->opt.prefixlen);
     517         [ +  + ]:        100 :                 if (r > 0) {
     518         [ -  + ]:         44 :                         _cleanup_free_ char *addr_cur = NULL;
     519                 :            : 
     520                 :         44 :                         (void) in_addr_to_string(AF_INET6,
     521                 :         44 :                                                  (union in_addr_union*) &p->opt.in6_addr,
     522                 :            :                                                  &addr_p);
     523                 :            : 
     524   [ -  +  #  # ]:         44 :                         if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
     525                 :          0 :                                 goto update;
     526                 :            : 
     527                 :         44 :                         (void) in_addr_to_string(AF_INET6,
     528                 :         44 :                                                  (union in_addr_union*) &cur->opt.in6_addr,
     529                 :            :                                                  &addr_cur);
     530                 :         44 :                         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                 :         44 :                         return -EEXIST;
     535                 :            :                 }
     536                 :            :         }
     537                 :            : 
     538                 :         12 :         p = sd_radv_prefix_ref(p);
     539                 :            : 
     540   [ +  +  +  +  :         16 :         LIST_APPEND(prefix, ra->prefixes, p);
          -  +  +  +  -  
                +  -  + ]
     541                 :            : 
     542                 :         12 :         ra->n_prefixes++;
     543                 :            : 
     544                 :         12 :         (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
     545                 :            : 
     546         [ +  - ]:         12 :         if (!dynamic) {
     547                 :         12 :                 log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
     548                 :         12 :                 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                 :         32 : _public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
     610                 :            :                                const struct in6_addr *dns, size_t n_dns) {
     611                 :         32 :         _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
     612                 :            :         size_t len;
     613                 :            : 
     614   [ +  +  +  + ]:         32 :         assert_return(ra, -EINVAL);
     615   [ +  +  +  + ]:         28 :         assert_return(n_dns < 128, -EINVAL);
     616                 :            : 
     617   [ +  +  +  + ]:         24 :         if (!dns || n_dns == 0) {
     618                 :         12 :                 ra->rdnss = mfree(ra->rdnss);
     619                 :         12 :                 ra->n_rdnss = 0;
     620                 :            : 
     621                 :         12 :                 return 0;
     622                 :            :         }
     623                 :            : 
     624                 :         12 :         len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
     625                 :            : 
     626                 :         12 :         opt_rdnss = malloc0(len);
     627         [ -  + ]:         12 :         if (!opt_rdnss)
     628                 :          0 :                 return -ENOMEM;
     629                 :            : 
     630                 :         12 :         opt_rdnss->type = SD_RADV_OPT_RDNSS;
     631                 :         12 :         opt_rdnss->length = len / 8;
     632                 :         12 :         opt_rdnss->lifetime = htobe32(lifetime);
     633                 :            : 
     634                 :         12 :         memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
     635                 :            : 
     636                 :         12 :         free_and_replace(ra->rdnss, opt_rdnss);
     637                 :            : 
     638                 :         12 :         ra->n_rdnss = n_dns;
     639                 :            : 
     640                 :         12 :         return 0;
     641                 :            : }
     642                 :            : 
     643                 :         20 : _public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
     644                 :            :                                char **search_list) {
     645                 :         20 :         _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
     646                 :         20 :         size_t len = 0;
     647                 :            :         char **s;
     648                 :            :         uint8_t *p;
     649                 :            : 
     650   [ -  +  -  + ]:         20 :         assert_return(ra, -EINVAL);
     651                 :            : 
     652         [ +  + ]:         20 :         if (strv_isempty(search_list)) {
     653                 :          8 :                 ra->dnssl = mfree(ra->dnssl);
     654                 :          8 :                 return 0;
     655                 :            :         }
     656                 :            : 
     657   [ +  -  +  + ]:         24 :         STRV_FOREACH(s, search_list)
     658                 :         12 :                 len += strlen(*s) + 2;
     659                 :            : 
     660                 :         12 :         len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
     661                 :            : 
     662                 :         12 :         opt_dnssl = malloc0(len);
     663         [ -  + ]:         12 :         if (!opt_dnssl)
     664                 :          0 :                 return -ENOMEM;
     665                 :            : 
     666                 :         12 :         opt_dnssl->type = SD_RADV_OPT_DNSSL;
     667                 :         12 :         opt_dnssl->length = len / 8;
     668                 :         12 :         opt_dnssl->lifetime = htobe32(lifetime);
     669                 :            : 
     670                 :         12 :         p = (uint8_t *)(opt_dnssl + 1);
     671                 :         12 :         len -= sizeof(struct sd_radv_opt_dns);
     672                 :            : 
     673   [ +  -  +  + ]:         24 :         STRV_FOREACH(s, search_list) {
     674                 :            :                 int r;
     675                 :            : 
     676                 :         12 :                 r = dns_name_to_wire_format(*s, p, len, false);
     677         [ -  + ]:         12 :                 if (r < 0)
     678                 :          0 :                         return r;
     679                 :            : 
     680         [ -  + ]:         12 :                 if (len < (size_t)r)
     681                 :          0 :                         return -ENOBUFS;
     682                 :            : 
     683                 :         12 :                 p += r;
     684                 :         12 :                 len -= r;
     685                 :            :         }
     686                 :            : 
     687                 :         12 :         free_and_replace(ra->dnssl, opt_dnssl);
     688                 :            : 
     689                 :         12 :         return 0;
     690                 :            : }
     691                 :            : 
     692                 :         32 : _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
     693                 :            :         sd_radv_prefix *p;
     694                 :            : 
     695   [ -  +  -  + ]:         32 :         assert_return(ret, -EINVAL);
     696                 :            : 
     697                 :         32 :         p = new(sd_radv_prefix, 1);
     698         [ -  + ]:         32 :         if (!p)
     699                 :          0 :                 return -ENOMEM;
     700                 :            : 
     701                 :         32 :         *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                 :         32 :                 .opt.preferred_lifetime = htobe32(604800),
     712                 :         32 :                 .opt.valid_lifetime = htobe32(2592000),
     713                 :            :         };
     714                 :            : 
     715                 :         32 :         *ret = p;
     716                 :         32 :         return 0;
     717                 :            : }
     718                 :            : 
     719   [ -  +  -  +  :         56 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
                   +  + ]
     720                 :            : 
     721                 :         72 : _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
     722                 :            :                                        unsigned char prefixlen) {
     723   [ +  +  +  + ]:         72 :         assert_return(p, -EINVAL);
     724   [ +  +  +  + ]:         68 :         assert_return(in6_addr, -EINVAL);
     725                 :            : 
     726   [ +  +  +  + ]:         64 :         if (prefixlen < 3 || prefixlen > 128)
     727                 :         20 :                 return -EINVAL;
     728                 :            : 
     729         [ +  + ]:         44 :         if (prefixlen > 64)
     730                 :            :                 /* unusual but allowed, log it */
     731                 :         12 :                 log_radv("Unusual prefix length %d greater than 64", prefixlen);
     732                 :            : 
     733                 :         44 :         p->opt.in6_addr = *in6_addr;
     734                 :         44 :         p->opt.prefixlen = prefixlen;
     735                 :            : 
     736                 :         44 :         return 0;
     737                 :            : }
     738                 :            : 
     739                 :         12 : _public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
     740   [ +  +  +  + ]:         12 :         assert_return(p, -EINVAL);
     741                 :            : 
     742         [ +  + ]:          8 :         SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
     743                 :            : 
     744                 :          8 :         return 0;
     745                 :            : }
     746                 :            : 
     747                 :         12 : _public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
     748                 :            :                                                           int address_autoconfiguration) {
     749   [ +  +  +  + ]:         12 :         assert_return(p, -EINVAL);
     750                 :            : 
     751         [ +  + ]:          8 :         SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
     752                 :            : 
     753                 :          8 :         return 0;
     754                 :            : }
     755                 :            : 
     756                 :         20 : _public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
     757                 :            :                                                uint32_t valid_lifetime) {
     758   [ +  +  +  + ]:         20 :         assert_return(p, -EINVAL);
     759                 :            : 
     760                 :         16 :         p->opt.valid_lifetime = htobe32(valid_lifetime);
     761                 :            : 
     762                 :         16 :         return 0;
     763                 :            : }
     764                 :            : 
     765                 :         20 : _public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
     766                 :            :                                                    uint32_t preferred_lifetime) {
     767   [ +  +  +  + ]:         20 :         assert_return(p, -EINVAL);
     768                 :            : 
     769                 :         16 :         p->opt.preferred_lifetime = htobe32(preferred_lifetime);
     770                 :            : 
     771                 :         16 :         return 0;
     772                 :            : }

Generated by: LCOV version 1.14