LCOV - code coverage report
Current view: top level - libsystemd/sd-netlink - sd-netlink.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 365 500 73.0 %
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             : #include <poll.h>
       4             : #include <sys/socket.h>
       5             : 
       6             : #include "sd-netlink.h"
       7             : 
       8             : #include "alloc-util.h"
       9             : #include "fd-util.h"
      10             : #include "hashmap.h"
      11             : #include "macro.h"
      12             : #include "missing.h"
      13             : #include "netlink-internal.h"
      14             : #include "netlink-slot.h"
      15             : #include "netlink-util.h"
      16             : #include "process-util.h"
      17             : #include "socket-util.h"
      18             : #include "string-util.h"
      19             : #include "util.h"
      20             : 
      21          15 : static int sd_netlink_new(sd_netlink **ret) {
      22          15 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
      23             : 
      24          15 :         assert_return(ret, -EINVAL);
      25             : 
      26          15 :         rtnl = new(sd_netlink, 1);
      27          15 :         if (!rtnl)
      28           0 :                 return -ENOMEM;
      29             : 
      30          30 :         *rtnl = (sd_netlink) {
      31             :                 .n_ref = 1,
      32             :                 .fd = -1,
      33             :                 .sockaddr.nl.nl_family = AF_NETLINK,
      34          15 :                 .original_pid = getpid_cached(),
      35             :                 .protocol = -1,
      36             : 
      37             :                 /* Change notification responses have sequence 0, so we must
      38             :                  * start our request sequence numbers at 1, or we may confuse our
      39             :                  * responses with notifications from the kernel */
      40             :                 .serial = 1,
      41             : 
      42             :         };
      43             : 
      44             :         /* We guarantee that the read buffer has at least space for
      45             :          * a message header */
      46          15 :         if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
      47             :                             sizeof(struct nlmsghdr), sizeof(uint8_t)))
      48           0 :                 return -ENOMEM;
      49             : 
      50          15 :         *ret = TAKE_PTR(rtnl);
      51             : 
      52          15 :         return 0;
      53             : }
      54             : 
      55           0 : int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
      56           0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
      57             :         socklen_t addrlen;
      58             :         int r;
      59             : 
      60           0 :         assert_return(ret, -EINVAL);
      61             : 
      62           0 :         r = sd_netlink_new(&rtnl);
      63           0 :         if (r < 0)
      64           0 :                 return r;
      65             : 
      66           0 :         addrlen = sizeof(rtnl->sockaddr);
      67             : 
      68           0 :         r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
      69           0 :         if (r < 0)
      70           0 :                 return -errno;
      71             : 
      72           0 :         if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
      73           0 :                 return -EINVAL;
      74             : 
      75           0 :         rtnl->fd = fd;
      76             : 
      77           0 :         *ret = TAKE_PTR(rtnl);
      78             : 
      79           0 :         return 0;
      80             : }
      81             : 
      82         144 : static bool rtnl_pid_changed(sd_netlink *rtnl) {
      83         144 :         assert(rtnl);
      84             : 
      85             :         /* We don't support people creating an rtnl connection and
      86             :          * keeping it around over a fork(). Let's complain. */
      87             : 
      88         144 :         return rtnl->original_pid != getpid_cached();
      89             : }
      90             : 
      91          15 : int sd_netlink_open_fd(sd_netlink **ret, int fd) {
      92          15 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
      93             :         int r;
      94             :         int protocol;
      95             :         socklen_t l;
      96             : 
      97          15 :         assert_return(ret, -EINVAL);
      98          15 :         assert_return(fd >= 0, -EBADF);
      99             : 
     100          15 :         r = sd_netlink_new(&rtnl);
     101          15 :         if (r < 0)
     102           0 :                 return r;
     103             : 
     104          15 :         l = sizeof(protocol);
     105          15 :         r = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &l);
     106          15 :         if (r < 0)
     107           0 :                 return r;
     108             : 
     109          15 :         rtnl->fd = fd;
     110          15 :         rtnl->protocol = protocol;
     111             : 
     112          15 :         r = socket_bind(rtnl);
     113          15 :         if (r < 0) {
     114           0 :                 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
     115           0 :                 rtnl->protocol = -1;
     116           0 :                 return r;
     117             :         }
     118             : 
     119          15 :         *ret = TAKE_PTR(rtnl);
     120             : 
     121          15 :         return 0;
     122             : }
     123             : 
     124          15 : int netlink_open_family(sd_netlink **ret, int family) {
     125          15 :         _cleanup_close_ int fd = -1;
     126             :         int r;
     127             : 
     128          15 :         fd = socket_open(family);
     129          15 :         if (fd < 0)
     130           0 :                 return fd;
     131             : 
     132          15 :         r = sd_netlink_open_fd(ret, fd);
     133          15 :         if (r < 0)
     134           0 :                 return r;
     135             : 
     136          15 :         fd = -1;
     137             : 
     138          15 :         return 0;
     139             : }
     140             : 
     141          13 : int sd_netlink_open(sd_netlink **ret) {
     142          13 :         return netlink_open_family(ret, NETLINK_ROUTE);
     143             : }
     144             : 
     145           2 : int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
     146           2 :         assert_return(rtnl, -EINVAL);
     147           2 :         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
     148             : 
     149           2 :         return fd_inc_rcvbuf(rtnl->fd, size);
     150             : }
     151             : 
     152          15 : static sd_netlink *netlink_free(sd_netlink *rtnl) {
     153             :         sd_netlink_slot *s;
     154             :         unsigned i;
     155             : 
     156          15 :         assert(rtnl);
     157             : 
     158          18 :         for (i = 0; i < rtnl->rqueue_size; i++)
     159           3 :                 sd_netlink_message_unref(rtnl->rqueue[i]);
     160          15 :         free(rtnl->rqueue);
     161             : 
     162          15 :         for (i = 0; i < rtnl->rqueue_partial_size; i++)
     163           0 :                 sd_netlink_message_unref(rtnl->rqueue_partial[i]);
     164          15 :         free(rtnl->rqueue_partial);
     165             : 
     166          15 :         free(rtnl->rbuffer);
     167             : 
     168          33 :         while ((s = rtnl->slots)) {
     169          18 :                 assert(s->floating);
     170          18 :                 netlink_slot_disconnect(s, true);
     171             :         }
     172          15 :         hashmap_free(rtnl->reply_callbacks);
     173          15 :         prioq_free(rtnl->reply_callbacks_prioq);
     174             : 
     175          15 :         sd_event_source_unref(rtnl->io_event_source);
     176          15 :         sd_event_source_unref(rtnl->time_event_source);
     177          15 :         sd_event_unref(rtnl->event);
     178             : 
     179          15 :         hashmap_free(rtnl->broadcast_group_refs);
     180             : 
     181          15 :         safe_close(rtnl->fd);
     182          15 :         return mfree(rtnl);
     183             : }
     184             : 
     185          45 : DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free);
     186             : 
     187          26 : static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) {
     188          26 :         assert(rtnl);
     189          26 :         assert(!rtnl_pid_changed(rtnl));
     190          26 :         assert(m);
     191          26 :         assert(m->hdr);
     192             : 
     193             :         /* don't use seq == 0, as that is used for broadcasts, so we
     194             :            would get confused by replies to such messages */
     195          26 :         m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
     196             : 
     197          26 :         rtnl_message_seal(m);
     198             : 
     199          26 :         return;
     200             : }
     201             : 
     202          27 : int sd_netlink_send(sd_netlink *nl,
     203             :                     sd_netlink_message *message,
     204             :                     uint32_t *serial) {
     205             :         int r;
     206             : 
     207          27 :         assert_return(nl, -EINVAL);
     208          27 :         assert_return(!rtnl_pid_changed(nl), -ECHILD);
     209          27 :         assert_return(message, -EINVAL);
     210          27 :         assert_return(!message->sealed, -EPERM);
     211             : 
     212          26 :         rtnl_seal_message(nl, message);
     213             : 
     214          26 :         r = socket_write_message(nl, message);
     215          26 :         if (r < 0)
     216           0 :                 return r;
     217             : 
     218          26 :         if (serial)
     219          26 :                 *serial = rtnl_message_get_serial(message);
     220             : 
     221          26 :         return 1;
     222             : }
     223             : 
     224          22 : int rtnl_rqueue_make_room(sd_netlink *rtnl) {
     225          22 :         assert(rtnl);
     226             : 
     227          22 :         if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX)
     228           0 :                 return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
     229             :                                        "rtnl: exhausted the read queue size (%d)",
     230             :                                        RTNL_RQUEUE_MAX);
     231             : 
     232          22 :         if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
     233           0 :                 return -ENOMEM;
     234             : 
     235          22 :         return 0;
     236             : }
     237             : 
     238           5 : int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) {
     239           5 :         assert(rtnl);
     240             : 
     241           5 :         if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX)
     242           0 :                 return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
     243             :                                        "rtnl: exhausted the partial read queue size (%d)",
     244             :                                        RTNL_RQUEUE_MAX);
     245             : 
     246           5 :         if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
     247             :                             rtnl->rqueue_partial_size + 1))
     248           0 :                 return -ENOMEM;
     249             : 
     250           5 :         return 0;
     251             : }
     252             : 
     253          10 : static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
     254             :         int r;
     255             : 
     256          10 :         assert(rtnl);
     257          10 :         assert(message);
     258             : 
     259          10 :         if (rtnl->rqueue_size <= 0) {
     260             :                 /* Try to read a new message */
     261          10 :                 r = socket_read_message(rtnl);
     262          10 :                 if (r == -ENOBUFS) { /* FIXME: ignore buffer overruns for now */
     263           0 :                         log_debug_errno(r, "Got ENOBUFS from netlink socket, ignoring.");
     264           0 :                         return 1;
     265             :                 }
     266          10 :                 if (r <= 0)
     267           0 :                         return r;
     268             :         }
     269             : 
     270             :         /* Dispatch a queued message */
     271          10 :         *message = rtnl->rqueue[0];
     272          10 :         rtnl->rqueue_size--;
     273          10 :         memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
     274             : 
     275          10 :         return 1;
     276             : }
     277             : 
     278          10 : static int process_timeout(sd_netlink *rtnl) {
     279          10 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     280             :         struct reply_callback *c;
     281             :         sd_netlink_slot *slot;
     282             :         usec_t n;
     283             :         int r;
     284             : 
     285          10 :         assert(rtnl);
     286             : 
     287          10 :         c = prioq_peek(rtnl->reply_callbacks_prioq);
     288          10 :         if (!c)
     289           0 :                 return 0;
     290             : 
     291          10 :         n = now(CLOCK_MONOTONIC);
     292          10 :         if (c->timeout > n)
     293          10 :                 return 0;
     294             : 
     295           0 :         r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m);
     296           0 :         if (r < 0)
     297           0 :                 return r;
     298             : 
     299           0 :         assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
     300           0 :         c->timeout = 0;
     301           0 :         hashmap_remove(rtnl->reply_callbacks, &c->serial);
     302             : 
     303           0 :         slot = container_of(c, sd_netlink_slot, reply_callback);
     304             : 
     305           0 :         r = c->callback(rtnl, m, slot->userdata);
     306           0 :         if (r < 0)
     307           0 :                 log_debug_errno(r, "sd-netlink: timedout callback %s%s%sfailed: %m",
     308             :                                 slot->description ? "'" : "",
     309             :                                 strempty(slot->description),
     310             :                                 slot->description ? "' " : "");
     311             : 
     312           0 :         if (slot->floating)
     313           0 :                 netlink_slot_disconnect(slot, true);
     314             : 
     315           0 :         return 1;
     316             : }
     317             : 
     318          10 : static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
     319             :         struct reply_callback *c;
     320             :         sd_netlink_slot *slot;
     321             :         uint64_t serial;
     322             :         uint16_t type;
     323             :         int r;
     324             : 
     325          10 :         assert(rtnl);
     326          10 :         assert(m);
     327             : 
     328          10 :         serial = rtnl_message_get_serial(m);
     329          10 :         c = hashmap_remove(rtnl->reply_callbacks, &serial);
     330          10 :         if (!c)
     331           1 :                 return 0;
     332             : 
     333           9 :         if (c->timeout != 0) {
     334           7 :                 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
     335           7 :                 c->timeout = 0;
     336             :         }
     337             : 
     338           9 :         r = sd_netlink_message_get_type(m, &type);
     339           9 :         if (r < 0)
     340           0 :                 return r;
     341             : 
     342           9 :         if (type == NLMSG_DONE)
     343           0 :                 m = NULL;
     344             : 
     345           9 :         slot = container_of(c, sd_netlink_slot, reply_callback);
     346             : 
     347           9 :         r = c->callback(rtnl, m, slot->userdata);
     348           9 :         if (r < 0)
     349           0 :                 log_debug_errno(r, "sd-netlink: reply callback %s%s%sfailed: %m",
     350             :                                 slot->description ? "'" : "",
     351             :                                 strempty(slot->description),
     352             :                                 slot->description ? "' " : "");
     353             : 
     354           9 :         if (slot->floating)
     355           8 :                 netlink_slot_disconnect(slot, true);
     356             : 
     357           9 :         return 1;
     358             : }
     359             : 
     360           0 : static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
     361             :         struct match_callback *c;
     362             :         sd_netlink_slot *slot;
     363             :         uint16_t type;
     364             :         int r;
     365             : 
     366           0 :         assert(rtnl);
     367           0 :         assert(m);
     368             : 
     369           0 :         r = sd_netlink_message_get_type(m, &type);
     370           0 :         if (r < 0)
     371           0 :                 return r;
     372             : 
     373           0 :         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
     374           0 :                 if (type == c->type) {
     375           0 :                         slot = container_of(c, sd_netlink_slot, match_callback);
     376             : 
     377           0 :                         r = c->callback(rtnl, m, slot->userdata);
     378           0 :                         if (r != 0) {
     379           0 :                                 if (r < 0)
     380           0 :                                         log_debug_errno(r, "sd-netlink: match callback %s%s%sfailed: %m",
     381             :                                                         slot->description ? "'" : "",
     382             :                                                         strempty(slot->description),
     383             :                                                         slot->description ? "' " : "");
     384             : 
     385           0 :                                 break;
     386             :                         }
     387             :                 }
     388             :         }
     389             : 
     390           0 :         return 1;
     391             : }
     392             : 
     393          10 : static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
     394          10 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     395             :         int r;
     396             : 
     397          10 :         assert(rtnl);
     398             : 
     399          10 :         r = process_timeout(rtnl);
     400          10 :         if (r != 0)
     401           0 :                 goto null_message;
     402             : 
     403          10 :         r = dispatch_rqueue(rtnl, &m);
     404          10 :         if (r < 0)
     405           0 :                 return r;
     406          10 :         if (!m)
     407           0 :                 goto null_message;
     408             : 
     409          10 :         if (sd_netlink_message_is_broadcast(m)) {
     410           0 :                 r = process_match(rtnl, m);
     411           0 :                 if (r != 0)
     412           0 :                         goto null_message;
     413             :         } else {
     414          10 :                 r = process_reply(rtnl, m);
     415          10 :                 if (r != 0)
     416           9 :                         goto null_message;
     417             :         }
     418             : 
     419           1 :         if (ret) {
     420           0 :                 *ret = TAKE_PTR(m);
     421             : 
     422           0 :                 return 1;
     423             :         }
     424             : 
     425           1 :         return 1;
     426             : 
     427           9 : null_message:
     428           9 :         if (r >= 0 && ret)
     429           3 :                 *ret = NULL;
     430             : 
     431           9 :         return r;
     432             : }
     433             : 
     434          10 : int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
     435          20 :         NETLINK_DONT_DESTROY(rtnl);
     436             :         int r;
     437             : 
     438          10 :         assert_return(rtnl, -EINVAL);
     439          10 :         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
     440          10 :         assert_return(!rtnl->processing, -EBUSY);
     441             : 
     442          10 :         rtnl->processing = true;
     443          10 :         r = process_running(rtnl, ret);
     444          10 :         rtnl->processing = false;
     445             : 
     446          10 :         return r;
     447             : }
     448             : 
     449          26 : static usec_t calc_elapse(uint64_t usec) {
     450          26 :         if (usec == (uint64_t) -1)
     451           5 :                 return 0;
     452             : 
     453          21 :         if (usec == 0)
     454          20 :                 usec = RTNL_DEFAULT_TIMEOUT;
     455             : 
     456          21 :         return now(CLOCK_MONOTONIC) + usec;
     457             : }
     458             : 
     459          19 : static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
     460          19 :         struct pollfd p[1] = {};
     461             :         struct timespec ts;
     462          19 :         usec_t m = USEC_INFINITY;
     463             :         int r, e;
     464             : 
     465          19 :         assert(rtnl);
     466             : 
     467          19 :         e = sd_netlink_get_events(rtnl);
     468          19 :         if (e < 0)
     469           0 :                 return e;
     470             : 
     471          19 :         if (need_more)
     472             :                 /* Caller wants more data, and doesn't care about
     473             :                  * what's been read or any other timeouts. */
     474          10 :                 e |= POLLIN;
     475             :         else {
     476             :                 usec_t until;
     477             :                 /* Caller wants to process if there is something to
     478             :                  * process, but doesn't care otherwise */
     479             : 
     480           9 :                 r = sd_netlink_get_timeout(rtnl, &until);
     481           9 :                 if (r < 0)
     482           0 :                         return r;
     483           9 :                 if (r > 0) {
     484             :                         usec_t nw;
     485           9 :                         nw = now(CLOCK_MONOTONIC);
     486           9 :                         m = until > nw ? until - nw : 0;
     487             :                 }
     488             :         }
     489             : 
     490          19 :         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
     491          15 :                 m = timeout_usec;
     492             : 
     493          19 :         p[0].fd = rtnl->fd;
     494          19 :         p[0].events = e;
     495             : 
     496          19 :         r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
     497          19 :         if (r < 0)
     498           0 :                 return -errno;
     499             : 
     500          19 :         return r > 0 ? 1 : 0;
     501             : }
     502             : 
     503           9 : int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
     504           9 :         assert_return(nl, -EINVAL);
     505           9 :         assert_return(!rtnl_pid_changed(nl), -ECHILD);
     506             : 
     507           9 :         if (nl->rqueue_size > 0)
     508           0 :                 return 0;
     509             : 
     510           9 :         return rtnl_poll(nl, false, timeout_usec);
     511             : }
     512             : 
     513           6 : static int timeout_compare(const void *a, const void *b) {
     514           6 :         const struct reply_callback *x = a, *y = b;
     515             : 
     516           6 :         if (x->timeout != 0 && y->timeout == 0)
     517           0 :                 return -1;
     518             : 
     519           6 :         if (x->timeout == 0 && y->timeout != 0)
     520           0 :                 return 1;
     521             : 
     522           6 :         return CMP(x->timeout, y->timeout);
     523             : }
     524             : 
     525          17 : int sd_netlink_call_async(
     526             :                 sd_netlink *nl,
     527             :                 sd_netlink_slot **ret_slot,
     528             :                 sd_netlink_message *m,
     529             :                 sd_netlink_message_handler_t callback,
     530             :                 sd_netlink_destroy_t destroy_callback,
     531             :                 void *userdata,
     532             :                 uint64_t usec,
     533             :                 const char *description) {
     534          17 :         _cleanup_free_ sd_netlink_slot *slot = NULL;
     535             :         uint32_t s;
     536             :         int r, k;
     537             : 
     538          17 :         assert_return(nl, -EINVAL);
     539          17 :         assert_return(m, -EINVAL);
     540          17 :         assert_return(callback, -EINVAL);
     541          17 :         assert_return(!rtnl_pid_changed(nl), -ECHILD);
     542             : 
     543          17 :         r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
     544          17 :         if (r < 0)
     545           0 :                 return r;
     546             : 
     547          17 :         if (usec != (uint64_t) -1) {
     548          15 :                 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
     549          15 :                 if (r < 0)
     550           0 :                         return r;
     551             :         }
     552             : 
     553          17 :         r = netlink_slot_allocate(nl, !ret_slot, NETLINK_REPLY_CALLBACK, sizeof(struct reply_callback), userdata, description, &slot);
     554          17 :         if (r < 0)
     555           0 :                 return r;
     556             : 
     557          17 :         slot->reply_callback.callback = callback;
     558          17 :         slot->reply_callback.timeout = calc_elapse(usec);
     559             : 
     560          17 :         k = sd_netlink_send(nl, m, &s);
     561          17 :         if (k < 0)
     562           0 :                 return k;
     563             : 
     564          17 :         slot->reply_callback.serial = s;
     565             : 
     566          17 :         r = hashmap_put(nl->reply_callbacks, &slot->reply_callback.serial, &slot->reply_callback);
     567          17 :         if (r < 0)
     568           0 :                 return r;
     569             : 
     570          17 :         if (slot->reply_callback.timeout != 0) {
     571          15 :                 r = prioq_put(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
     572          15 :                 if (r < 0) {
     573           0 :                         (void) hashmap_remove(nl->reply_callbacks, &slot->reply_callback.serial);
     574           0 :                         return r;
     575             :                 }
     576             :         }
     577             : 
     578             :         /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */
     579          17 :         slot->destroy_callback = destroy_callback;
     580             : 
     581          17 :         if (ret_slot)
     582           3 :                 *ret_slot = slot;
     583             : 
     584          17 :         TAKE_PTR(slot);
     585             : 
     586          17 :         return k;
     587             : }
     588             : 
     589          10 : int sd_netlink_call(sd_netlink *rtnl,
     590             :                 sd_netlink_message *message,
     591             :                 uint64_t usec,
     592             :                 sd_netlink_message **ret) {
     593             :         usec_t timeout;
     594             :         uint32_t serial;
     595             :         int r;
     596             : 
     597          10 :         assert_return(rtnl, -EINVAL);
     598          10 :         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
     599          10 :         assert_return(message, -EINVAL);
     600             : 
     601          10 :         r = sd_netlink_send(rtnl, message, &serial);
     602          10 :         if (r < 0)
     603           1 :                 return r;
     604             : 
     605           9 :         timeout = calc_elapse(usec);
     606             : 
     607          22 :         for (;;) {
     608             :                 usec_t left;
     609             :                 unsigned i;
     610             : 
     611          53 :                 for (i = 0; i < rtnl->rqueue_size; i++) {
     612             :                         uint32_t received_serial;
     613             : 
     614          31 :                         received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
     615             : 
     616          31 :                         if (received_serial == serial) {
     617           9 :                                 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
     618             :                                 uint16_t type;
     619             : 
     620           9 :                                 incoming = rtnl->rqueue[i];
     621             : 
     622             :                                 /* found a match, remove from rqueue and return it */
     623           9 :                                 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
     624           9 :                                         sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1));
     625           9 :                                 rtnl->rqueue_size--;
     626             : 
     627           9 :                                 r = sd_netlink_message_get_errno(incoming);
     628           9 :                                 if (r < 0)
     629           0 :                                         return r;
     630             : 
     631           9 :                                 r = sd_netlink_message_get_type(incoming, &type);
     632           9 :                                 if (r < 0)
     633           0 :                                         return r;
     634             : 
     635           9 :                                 if (type == NLMSG_DONE) {
     636           0 :                                         *ret = NULL;
     637           0 :                                         return 0;
     638             :                                 }
     639             : 
     640           9 :                                 if (ret)
     641           8 :                                         *ret = TAKE_PTR(incoming);
     642             : 
     643           9 :                                 return 1;
     644             :                         }
     645             :                 }
     646             : 
     647          22 :                 r = socket_read_message(rtnl);
     648          22 :                 if (r < 0)
     649           0 :                         return r;
     650          22 :                 if (r > 0)
     651             :                         /* received message, so try to process straight away */
     652          12 :                         continue;
     653             : 
     654          10 :                 if (timeout > 0) {
     655             :                         usec_t n;
     656             : 
     657           9 :                         n = now(CLOCK_MONOTONIC);
     658           9 :                         if (n >= timeout)
     659           0 :                                 return -ETIMEDOUT;
     660             : 
     661           9 :                         left = timeout - n;
     662             :                 } else
     663           1 :                         left = (uint64_t) -1;
     664             : 
     665          10 :                 r = rtnl_poll(rtnl, true, left);
     666          10 :                 if (r < 0)
     667           0 :                         return r;
     668          10 :                 else if (r == 0)
     669           0 :                         return -ETIMEDOUT;
     670             :         }
     671             : }
     672             : 
     673          20 : int sd_netlink_get_events(sd_netlink *rtnl) {
     674          20 :         assert_return(rtnl, -EINVAL);
     675          20 :         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
     676             : 
     677          20 :         if (rtnl->rqueue_size == 0)
     678          17 :                 return POLLIN;
     679             :         else
     680           3 :                 return 0;
     681             : }
     682             : 
     683          10 : int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) {
     684             :         struct reply_callback *c;
     685             : 
     686          10 :         assert_return(rtnl, -EINVAL);
     687          10 :         assert_return(timeout_usec, -EINVAL);
     688          10 :         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
     689             : 
     690          10 :         if (rtnl->rqueue_size > 0) {
     691           0 :                 *timeout_usec = 0;
     692           0 :                 return 1;
     693             :         }
     694             : 
     695          10 :         c = prioq_peek(rtnl->reply_callbacks_prioq);
     696          10 :         if (!c) {
     697           0 :                 *timeout_usec = (uint64_t) -1;
     698           0 :                 return 0;
     699             :         }
     700             : 
     701          10 :         *timeout_usec = c->timeout;
     702             : 
     703          10 :         return 1;
     704             : }
     705             : 
     706           1 : static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     707           1 :         sd_netlink *rtnl = userdata;
     708             :         int r;
     709             : 
     710           1 :         assert(rtnl);
     711             : 
     712           1 :         r = sd_netlink_process(rtnl, NULL);
     713           1 :         if (r < 0)
     714           0 :                 return r;
     715             : 
     716           1 :         return 1;
     717             : }
     718             : 
     719           0 : static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
     720           0 :         sd_netlink *rtnl = userdata;
     721             :         int r;
     722             : 
     723           0 :         assert(rtnl);
     724             : 
     725           0 :         r = sd_netlink_process(rtnl, NULL);
     726           0 :         if (r < 0)
     727           0 :                 return r;
     728             : 
     729           0 :         return 1;
     730             : }
     731             : 
     732           1 : static int prepare_callback(sd_event_source *s, void *userdata) {
     733           1 :         sd_netlink *rtnl = userdata;
     734             :         int r, e;
     735             :         usec_t until;
     736             : 
     737           1 :         assert(s);
     738           1 :         assert(rtnl);
     739             : 
     740           1 :         e = sd_netlink_get_events(rtnl);
     741           1 :         if (e < 0)
     742           0 :                 return e;
     743             : 
     744           1 :         r = sd_event_source_set_io_events(rtnl->io_event_source, e);
     745           1 :         if (r < 0)
     746           0 :                 return r;
     747             : 
     748           1 :         r = sd_netlink_get_timeout(rtnl, &until);
     749           1 :         if (r < 0)
     750           0 :                 return r;
     751           1 :         if (r > 0) {
     752             :                 int j;
     753             : 
     754           1 :                 j = sd_event_source_set_time(rtnl->time_event_source, until);
     755           1 :                 if (j < 0)
     756           0 :                         return j;
     757             :         }
     758             : 
     759           1 :         r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
     760           1 :         if (r < 0)
     761           0 :                 return r;
     762             : 
     763           1 :         return 1;
     764             : }
     765             : 
     766           3 : int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
     767             :         int r;
     768             : 
     769           3 :         assert_return(rtnl, -EINVAL);
     770           3 :         assert_return(!rtnl->event, -EBUSY);
     771             : 
     772           3 :         assert(!rtnl->io_event_source);
     773           3 :         assert(!rtnl->time_event_source);
     774             : 
     775           3 :         if (event)
     776           3 :                 rtnl->event = sd_event_ref(event);
     777             :         else {
     778           0 :                 r = sd_event_default(&rtnl->event);
     779           0 :                 if (r < 0)
     780           0 :                         return r;
     781             :         }
     782             : 
     783           3 :         r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
     784           3 :         if (r < 0)
     785           0 :                 goto fail;
     786             : 
     787           3 :         r = sd_event_source_set_priority(rtnl->io_event_source, priority);
     788           3 :         if (r < 0)
     789           0 :                 goto fail;
     790             : 
     791           3 :         r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
     792           3 :         if (r < 0)
     793           0 :                 goto fail;
     794             : 
     795           3 :         r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
     796           3 :         if (r < 0)
     797           0 :                 goto fail;
     798             : 
     799           3 :         r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
     800           3 :         if (r < 0)
     801           0 :                 goto fail;
     802             : 
     803           3 :         r = sd_event_source_set_priority(rtnl->time_event_source, priority);
     804           3 :         if (r < 0)
     805           0 :                 goto fail;
     806             : 
     807           3 :         r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
     808           3 :         if (r < 0)
     809           0 :                 goto fail;
     810             : 
     811           3 :         return 0;
     812             : 
     813           0 : fail:
     814           0 :         sd_netlink_detach_event(rtnl);
     815           0 :         return r;
     816             : }
     817             : 
     818           1 : int sd_netlink_detach_event(sd_netlink *rtnl) {
     819           1 :         assert_return(rtnl, -EINVAL);
     820           1 :         assert_return(rtnl->event, -ENXIO);
     821             : 
     822           1 :         rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
     823             : 
     824           1 :         rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
     825             : 
     826           1 :         rtnl->event = sd_event_unref(rtnl->event);
     827             : 
     828           1 :         return 0;
     829             : }
     830             : 
     831          13 : int sd_netlink_add_match(
     832             :                 sd_netlink *rtnl,
     833             :                 sd_netlink_slot **ret_slot,
     834             :                 uint16_t type,
     835             :                 sd_netlink_message_handler_t callback,
     836             :                 sd_netlink_destroy_t destroy_callback,
     837             :                 void *userdata,
     838             :                 const char *description) {
     839          13 :         _cleanup_free_ sd_netlink_slot *slot = NULL;
     840             :         int r;
     841             : 
     842          13 :         assert_return(rtnl, -EINVAL);
     843          13 :         assert_return(callback, -EINVAL);
     844          13 :         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
     845             : 
     846          13 :         r = netlink_slot_allocate(rtnl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), userdata, description, &slot);
     847          13 :         if (r < 0)
     848           0 :                 return r;
     849             : 
     850          13 :         slot->match_callback.callback = callback;
     851          13 :         slot->match_callback.type = type;
     852             : 
     853          13 :         switch (type) {
     854           5 :                 case RTM_NEWLINK:
     855             :                 case RTM_DELLINK:
     856           5 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
     857           5 :                         if (r < 0)
     858           0 :                                 return r;
     859             : 
     860           5 :                         break;
     861           2 :                 case RTM_NEWADDR:
     862             :                 case RTM_DELADDR:
     863           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
     864           2 :                         if (r < 0)
     865           0 :                                 return r;
     866             : 
     867           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
     868           2 :                         if (r < 0)
     869           0 :                                 return r;
     870             : 
     871           2 :                         break;
     872           2 :                 case RTM_NEWNEIGH:
     873             :                 case RTM_DELNEIGH:
     874           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEIGH);
     875           2 :                         if (r < 0)
     876           0 :                                 return r;
     877             : 
     878           2 :                         break;
     879           2 :                 case RTM_NEWROUTE:
     880             :                 case RTM_DELROUTE:
     881           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
     882           2 :                         if (r < 0)
     883           0 :                                 return r;
     884             : 
     885           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
     886           2 :                         if (r < 0)
     887           0 :                                 return r;
     888           2 :                         break;
     889           2 :                 case RTM_NEWRULE:
     890             :                 case RTM_DELRULE:
     891           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE);
     892           2 :                         if (r < 0)
     893           0 :                                 return r;
     894             : 
     895           2 :                         r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE);
     896           2 :                         if (r < 0)
     897           0 :                                 return r;
     898           2 :                         break;
     899           0 :                 default:
     900           0 :                         return -EOPNOTSUPP;
     901             :         }
     902             : 
     903          13 :         LIST_PREPEND(match_callbacks, rtnl->match_callbacks, &slot->match_callback);
     904             : 
     905             :         /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */
     906          13 :         slot->destroy_callback = destroy_callback;
     907             : 
     908          13 :         if (ret_slot)
     909           2 :                 *ret_slot = slot;
     910             : 
     911          13 :         TAKE_PTR(slot);
     912             : 
     913          13 :         return 0;
     914             : }

Generated by: LCOV version 1.14