LCOV - code coverage report
Current view: top level - libsystemd/sd-netlink - sd-netlink.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 355 495 71.7 %
Date: 2015-07-29 18:47:03 Functions: 30 34 88.2 %

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

Generated by: LCOV version 1.11