chiark / gitweb /
sd-rtnl: allow sd_rtnl_open_fd() to be used on bound sockets
[elogind.git] / src / libsystemd / sd-rtnl / sd-rtnl.c
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-rtnl.h"
31 #include "rtnl-internal.h"
32 #include "rtnl-util.h"
33
34 static int sd_rtnl_new(sd_rtnl **ret) {
35         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
36
37         assert_return(ret, -EINVAL);
38
39         rtnl = new0(sd_rtnl, 1);
40         if (!rtnl)
41                 return -ENOMEM;
42
43         rtnl->n_ref = REFCNT_INIT;
44
45         rtnl->fd = -1;
46
47         rtnl->sockaddr.nl.nl_family = AF_NETLINK;
48
49         rtnl->original_pid = getpid();
50
51         LIST_HEAD_INIT(rtnl->match_callbacks);
52
53         /* We guarantee that wqueue always has space for at least
54          * one entry */
55         if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
56                 return -ENOMEM;
57
58         /* We guarantee that the read buffer has at least space for
59          * a message header */
60         if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
61                             sizeof(struct nlmsghdr), sizeof(uint8_t)))
62                 return -ENOMEM;
63
64         *ret = rtnl;
65         rtnl = NULL;
66
67         return 0;
68 }
69
70 int sd_rtnl_new_from_netlink(sd_rtnl **ret, int fd) {
71         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
72         socklen_t addrlen;
73         int r;
74
75         assert_return(ret, -EINVAL);
76
77         r = sd_rtnl_new(&rtnl);
78         if (r < 0)
79                 return r;
80
81         addrlen = sizeof(rtnl->sockaddr);
82
83         r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
84         if (r < 0)
85                 return -errno;
86
87         rtnl->fd = fd;
88
89         *ret = rtnl;
90         rtnl = NULL;
91
92         return 0;
93 }
94
95 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
96         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         return rtnl->original_pid != getpid();
102 }
103
104 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
105         uint32_t groups = 0;
106         unsigned i;
107
108         for (i = 0; i < n_groups; i++) {
109                 unsigned group;
110
111                 group = va_arg(ap, unsigned);
112                 assert_return(group < 32, -EINVAL);
113
114                 groups |= group ? (1 << (group - 1)) : 0;
115         }
116
117         *_groups = groups;
118
119         return 0;
120 }
121
122 static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
123         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
124         socklen_t addrlen;
125         int r, one = 1;
126
127         assert_return(ret, -EINVAL);
128         assert_return(fd >= 0, -EINVAL);
129
130         r = sd_rtnl_new(&rtnl);
131         if (r < 0)
132                 return r;
133
134         r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
135         if (r < 0)
136                 return -errno;
137
138         r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
139         if (r < 0)
140                 return -errno;
141
142         r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
143         if (r < 0)
144                 return r;
145
146         addrlen = sizeof(rtnl->sockaddr);
147
148         r = bind(fd, &rtnl->sockaddr.sa, addrlen);
149         /* ignore EINVAL to allow opening an already bound socket */
150         if (r < 0 && errno != EINVAL)
151                 return -errno;
152
153         r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
154         if (r < 0)
155                 return -errno;
156
157         rtnl->fd = fd;
158
159         *ret = rtnl;
160         rtnl = NULL;
161
162         return 0;
163 }
164
165 int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
166         va_list ap;
167         int r;
168
169         va_start(ap, n_groups);
170         r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
171         va_end(ap);
172
173         return r;
174 }
175
176 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
177         va_list ap;
178         int fd, r;
179
180         fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
181         if (fd < 0)
182                 return -errno;
183
184         va_start(ap, n_groups);
185         r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
186         va_end(ap);
187
188         if (r < 0) {
189                 safe_close(fd);
190                 return r;
191         }
192
193         return 0;
194 }
195
196 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
197         return fd_inc_rcvbuf(rtnl->fd, size);
198 }
199
200 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
201         assert_return(rtnl, NULL);
202         assert_return(!rtnl_pid_changed(rtnl), NULL);
203
204         if (rtnl)
205                 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
206
207         return rtnl;
208 }
209
210 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
211         if (!rtnl)
212                 return NULL;
213
214         assert_return(!rtnl_pid_changed(rtnl), NULL);
215
216         if (REFCNT_DEC(rtnl->n_ref) == 0) {
217                 struct match_callback *f;
218                 unsigned i;
219
220                 for (i = 0; i < rtnl->rqueue_size; i++)
221                         sd_rtnl_message_unref(rtnl->rqueue[i]);
222                 free(rtnl->rqueue);
223
224                 for (i = 0; i < rtnl->rqueue_partial_size; i++)
225                         sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
226                 free(rtnl->rqueue_partial);
227
228                 for (i = 0; i < rtnl->wqueue_size; i++)
229                         sd_rtnl_message_unref(rtnl->wqueue[i]);
230                 free(rtnl->wqueue);
231
232                 free(rtnl->rbuffer);
233
234                 hashmap_free_free(rtnl->reply_callbacks);
235                 prioq_free(rtnl->reply_callbacks_prioq);
236
237                 sd_event_source_unref(rtnl->io_event_source);
238                 sd_event_source_unref(rtnl->time_event_source);
239                 sd_event_source_unref(rtnl->exit_event_source);
240                 sd_event_unref(rtnl->event);
241
242                 while ((f = rtnl->match_callbacks)) {
243                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
244                         free(f);
245                 }
246
247                 safe_close(rtnl->fd);
248                 free(rtnl);
249         }
250
251         return NULL;
252 }
253
254 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
255         assert(rtnl);
256         assert(!rtnl_pid_changed(rtnl));
257         assert(m);
258         assert(m->hdr);
259
260         m->hdr->nlmsg_seq = rtnl->serial++;
261
262         rtnl_message_seal(m);
263
264         return;
265 }
266
267 int sd_rtnl_send(sd_rtnl *nl,
268                  sd_rtnl_message *message,
269                  uint32_t *serial) {
270         int r;
271
272         assert_return(nl, -EINVAL);
273         assert_return(!rtnl_pid_changed(nl), -ECHILD);
274         assert_return(message, -EINVAL);
275         assert_return(!message->sealed, -EPERM);
276
277         rtnl_seal_message(nl, message);
278
279         if (nl->wqueue_size <= 0) {
280                 /* send directly */
281                 r = socket_write_message(nl, message);
282                 if (r < 0)
283                         return r;
284                 else if (r == 0) {
285                         /* nothing was sent, so let's put it on
286                          * the queue */
287                         nl->wqueue[0] = sd_rtnl_message_ref(message);
288                         nl->wqueue_size = 1;
289                 }
290         } else {
291                 /* append to queue */
292                 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
293                         log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
294                         return -ENOBUFS;
295                 }
296
297                 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
298                         return -ENOMEM;
299
300                 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
301         }
302
303         if (serial)
304                 *serial = rtnl_message_get_serial(message);
305
306         return 1;
307 }
308
309 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
310         assert(rtnl);
311
312         if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
313                 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
314                 return -ENOBUFS;
315         }
316
317         if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
318                 return -ENOMEM;
319
320         return 0;
321 }
322
323 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
324         assert(rtnl);
325
326         if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
327                 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
328                 return -ENOBUFS;
329         }
330
331         if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
332                             rtnl->rqueue_partial_size + 1))
333                 return -ENOMEM;
334
335         return 0;
336 }
337
338 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
339         int r;
340
341         assert(rtnl);
342         assert(message);
343
344         if (rtnl->rqueue_size <= 0) {
345                 /* Try to read a new message */
346                 r = socket_read_message(rtnl);
347                 if (r <= 0)
348                         return r;
349         }
350
351         /* Dispatch a queued message */
352         *message = rtnl->rqueue[0];
353         rtnl->rqueue_size --;
354         memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
355
356         return 1;
357 }
358
359 static int dispatch_wqueue(sd_rtnl *rtnl) {
360         int r, ret = 0;
361
362         assert(rtnl);
363
364         while (rtnl->wqueue_size > 0) {
365                 r = socket_write_message(rtnl, rtnl->wqueue[0]);
366                 if (r < 0)
367                         return r;
368                 else if (r == 0)
369                         /* Didn't do anything this time */
370                         return ret;
371                 else {
372                         /* see equivalent in sd-bus.c */
373                         sd_rtnl_message_unref(rtnl->wqueue[0]);
374                         rtnl->wqueue_size --;
375                         memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
376
377                         ret = 1;
378                 }
379         }
380
381         return ret;
382 }
383
384 static int process_timeout(sd_rtnl *rtnl) {
385         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
386         struct reply_callback *c;
387         usec_t n;
388         int r;
389
390         assert(rtnl);
391
392         c = prioq_peek(rtnl->reply_callbacks_prioq);
393         if (!c)
394                 return 0;
395
396         n = now(CLOCK_MONOTONIC);
397         if (c->timeout > n)
398                 return 0;
399
400         r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
401         if (r < 0)
402                 return r;
403
404         assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
405         hashmap_remove(rtnl->reply_callbacks, &c->serial);
406
407         r = c->callback(rtnl, m, c->userdata);
408         if (r < 0)
409                 log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
410
411         free(c);
412
413         return 1;
414 }
415
416 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
417         struct reply_callback *c;
418         uint64_t serial;
419         int r;
420
421         assert(rtnl);
422         assert(m);
423
424         if (sd_rtnl_message_is_broadcast(m))
425                 return 0;
426
427         serial = rtnl_message_get_serial(m);
428         c = hashmap_remove(rtnl->reply_callbacks, &serial);
429         if (!c)
430                 return 0;
431
432         if (c->timeout != 0)
433                 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
434
435         r = c->callback(rtnl, m, c->userdata);
436         if (r < 0)
437                 log_debug_errno(r, "sd-rtnl: callback failed: %m");
438
439         free(c);
440
441         return 1;
442 }
443
444 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
445         struct match_callback *c;
446         uint16_t type;
447         int r;
448
449         assert(rtnl);
450         assert(m);
451
452         r = sd_rtnl_message_get_type(m, &type);
453         if (r < 0)
454                 return r;
455
456         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
457                 if (type == c->type) {
458                         r = c->callback(rtnl, m, c->userdata);
459                         if (r != 0) {
460                                 if (r < 0)
461                                         log_debug_errno(r, "sd-rtnl: match callback failed: %m");
462
463                                 break;
464                         }
465                 }
466         }
467
468         return 1;
469 }
470
471 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
472         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
473         int r;
474
475         assert(rtnl);
476
477         r = process_timeout(rtnl);
478         if (r != 0)
479                 goto null_message;
480
481         r = dispatch_wqueue(rtnl);
482         if (r != 0)
483                 goto null_message;
484
485         r = dispatch_rqueue(rtnl, &m);
486         if (r < 0)
487                 return r;
488         if (!m)
489                 goto null_message;
490
491         r = process_reply(rtnl, m);
492         if (r != 0)
493                 goto null_message;
494
495         r = process_match(rtnl, m);
496         if (r != 0)
497                 goto null_message;
498
499         if (ret) {
500                 *ret = m;
501                 m = NULL;
502
503                 return 1;
504         }
505
506         return 1;
507
508 null_message:
509         if (r >= 0 && ret)
510                 *ret = NULL;
511
512         return r;
513 }
514
515 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
516         RTNL_DONT_DESTROY(rtnl);
517         int r;
518
519         assert_return(rtnl, -EINVAL);
520         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
521         assert_return(!rtnl->processing, -EBUSY);
522
523         rtnl->processing = true;
524         r = process_running(rtnl, ret);
525         rtnl->processing = false;
526
527         return r;
528 }
529
530 static usec_t calc_elapse(uint64_t usec) {
531         if (usec == (uint64_t) -1)
532                 return 0;
533
534         if (usec == 0)
535                 usec = RTNL_DEFAULT_TIMEOUT;
536
537         return now(CLOCK_MONOTONIC) + usec;
538 }
539
540 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
541         struct pollfd p[1] = {};
542         struct timespec ts;
543         usec_t m = USEC_INFINITY;
544         int r, e;
545
546         assert(rtnl);
547
548         e = sd_rtnl_get_events(rtnl);
549         if (e < 0)
550                 return e;
551
552         if (need_more)
553                 /* Caller wants more data, and doesn't care about
554                  * what's been read or any other timeouts. */
555                 e |= POLLIN;
556         else {
557                 usec_t until;
558                 /* Caller wants to process if there is something to
559                  * process, but doesn't care otherwise */
560
561                 r = sd_rtnl_get_timeout(rtnl, &until);
562                 if (r < 0)
563                         return r;
564                 if (r > 0) {
565                         usec_t nw;
566                         nw = now(CLOCK_MONOTONIC);
567                         m = until > nw ? until - nw : 0;
568                 }
569         }
570
571         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
572                 m = timeout_usec;
573
574         p[0].fd = rtnl->fd;
575         p[0].events = e;
576
577         r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
578         if (r < 0)
579                 return -errno;
580
581         return r > 0 ? 1 : 0;
582 }
583
584 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
585         assert_return(nl, -EINVAL);
586         assert_return(!rtnl_pid_changed(nl), -ECHILD);
587
588         if (nl->rqueue_size > 0)
589                 return 0;
590
591         return rtnl_poll(nl, false, timeout_usec);
592 }
593
594 static int timeout_compare(const void *a, const void *b) {
595         const struct reply_callback *x = a, *y = b;
596
597         if (x->timeout != 0 && y->timeout == 0)
598                 return -1;
599
600         if (x->timeout == 0 && y->timeout != 0)
601                 return 1;
602
603         if (x->timeout < y->timeout)
604                 return -1;
605
606         if (x->timeout > y->timeout)
607                 return 1;
608
609         return 0;
610 }
611
612 int sd_rtnl_call_async(sd_rtnl *nl,
613                        sd_rtnl_message *m,
614                        sd_rtnl_message_handler_t callback,
615                        void *userdata,
616                        uint64_t usec,
617                        uint32_t *serial) {
618         struct reply_callback *c;
619         uint32_t s;
620         int r, k;
621
622         assert_return(nl, -EINVAL);
623         assert_return(m, -EINVAL);
624         assert_return(callback, -EINVAL);
625         assert_return(!rtnl_pid_changed(nl), -ECHILD);
626
627         r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
628         if (r < 0)
629                 return r;
630
631         if (usec != (uint64_t) -1) {
632                 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
633                 if (r < 0)
634                         return r;
635         }
636
637         c = new0(struct reply_callback, 1);
638         if (!c)
639                 return -ENOMEM;
640
641         c->callback = callback;
642         c->userdata = userdata;
643         c->timeout = calc_elapse(usec);
644
645         k = sd_rtnl_send(nl, m, &s);
646         if (k < 0) {
647                 free(c);
648                 return k;
649         }
650
651         c->serial = s;
652
653         r = hashmap_put(nl->reply_callbacks, &c->serial, c);
654         if (r < 0) {
655                 free(c);
656                 return r;
657         }
658
659         if (c->timeout != 0) {
660                 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
661                 if (r > 0) {
662                         c->timeout = 0;
663                         sd_rtnl_call_async_cancel(nl, c->serial);
664                         return r;
665                 }
666         }
667
668         if (serial)
669                 *serial = s;
670
671         return k;
672 }
673
674 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
675         struct reply_callback *c;
676         uint64_t s = serial;
677
678         assert_return(nl, -EINVAL);
679         assert_return(serial != 0, -EINVAL);
680         assert_return(!rtnl_pid_changed(nl), -ECHILD);
681
682         c = hashmap_remove(nl->reply_callbacks, &s);
683         if (!c)
684                 return 0;
685
686         if (c->timeout != 0)
687                 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
688
689         free(c);
690         return 1;
691 }
692
693 int sd_rtnl_call(sd_rtnl *rtnl,
694                 sd_rtnl_message *message,
695                 uint64_t usec,
696                 sd_rtnl_message **ret) {
697         usec_t timeout;
698         uint32_t serial;
699         unsigned i = 0;
700         int r;
701
702         assert_return(rtnl, -EINVAL);
703         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
704         assert_return(message, -EINVAL);
705
706         r = sd_rtnl_send(rtnl, message, &serial);
707         if (r < 0)
708                 return r;
709
710         timeout = calc_elapse(usec);
711
712         for (;;) {
713                 usec_t left;
714
715                 while (i < rtnl->rqueue_size) {
716                         sd_rtnl_message *incoming;
717                         uint32_t received_serial;
718
719                         incoming = rtnl->rqueue[i];
720                         received_serial = rtnl_message_get_serial(incoming);
721
722                         if (received_serial == serial) {
723                                 /* found a match, remove from rqueue and return it */
724                                 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
725                                         sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
726                                 rtnl->rqueue_size--;
727
728                                 r = sd_rtnl_message_get_errno(incoming);
729                                 if (r < 0) {
730                                         sd_rtnl_message_unref(incoming);
731                                         return r;
732                                 }
733
734                                 if (ret) {
735                                         *ret = incoming;
736                                 } else
737                                         sd_rtnl_message_unref(incoming);
738
739                                 return 1;
740                         }
741
742                         /* Try to read more, right away */
743                         i ++;
744                 }
745
746                 r = socket_read_message(rtnl);
747                 if (r < 0)
748                         return r;
749                 if (r > 0)
750                         /* received message, so try to process straight away */
751                         continue;
752
753                 if (timeout > 0) {
754                         usec_t n;
755
756                         n = now(CLOCK_MONOTONIC);
757                         if (n >= timeout)
758                                 return -ETIMEDOUT;
759
760                         left = timeout - n;
761                 } else
762                         left = (uint64_t) -1;
763
764                 r = rtnl_poll(rtnl, true, left);
765                 if (r < 0)
766                         return r;
767                 else if (r == 0)
768                         return -ETIMEDOUT;
769
770                 r = dispatch_wqueue(rtnl);
771                 if (r < 0)
772                         return r;
773         }
774 }
775
776 int sd_rtnl_flush(sd_rtnl *rtnl) {
777         int r;
778
779         assert_return(rtnl, -EINVAL);
780         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
781
782         if (rtnl->wqueue_size <= 0)
783                 return 0;
784
785         for (;;) {
786                 r = dispatch_wqueue(rtnl);
787                 if (r < 0)
788                         return r;
789
790                 if (rtnl->wqueue_size <= 0)
791                         return 0;
792
793                 r = rtnl_poll(rtnl, false, (uint64_t) -1);
794                 if (r < 0)
795                         return r;
796         }
797 }
798
799 int sd_rtnl_get_events(sd_rtnl *rtnl) {
800         int flags = 0;
801
802         assert_return(rtnl, -EINVAL);
803         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
804
805         if (rtnl->rqueue_size <= 0)
806                 flags |= POLLIN;
807         if (rtnl->wqueue_size > 0)
808                 flags |= POLLOUT;
809
810         return flags;
811 }
812
813 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
814         struct reply_callback *c;
815
816         assert_return(rtnl, -EINVAL);
817         assert_return(timeout_usec, -EINVAL);
818         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
819
820         if (rtnl->rqueue_size > 0) {
821                 *timeout_usec = 0;
822                 return 1;
823         }
824
825         c = prioq_peek(rtnl->reply_callbacks_prioq);
826         if (!c) {
827                 *timeout_usec = (uint64_t) -1;
828                 return 0;
829         }
830
831         *timeout_usec = c->timeout;
832
833         return 1;
834 }
835
836 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
837         sd_rtnl *rtnl = userdata;
838         int r;
839
840         assert(rtnl);
841
842         r = sd_rtnl_process(rtnl, NULL);
843         if (r < 0)
844                 return r;
845
846         return 1;
847 }
848
849 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
850         sd_rtnl *rtnl = userdata;
851         int r;
852
853         assert(rtnl);
854
855         r = sd_rtnl_process(rtnl, NULL);
856         if (r < 0)
857                 return r;
858
859         return 1;
860 }
861
862 static int prepare_callback(sd_event_source *s, void *userdata) {
863         sd_rtnl *rtnl = userdata;
864         int r, e;
865         usec_t until;
866
867         assert(s);
868         assert(rtnl);
869
870         e = sd_rtnl_get_events(rtnl);
871         if (e < 0)
872                 return e;
873
874         r = sd_event_source_set_io_events(rtnl->io_event_source, e);
875         if (r < 0)
876                 return r;
877
878         r = sd_rtnl_get_timeout(rtnl, &until);
879         if (r < 0)
880                 return r;
881         if (r > 0) {
882                 int j;
883
884                 j = sd_event_source_set_time(rtnl->time_event_source, until);
885                 if (j < 0)
886                         return j;
887         }
888
889         r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
890         if (r < 0)
891                 return r;
892
893         return 1;
894 }
895
896 static int exit_callback(sd_event_source *event, void *userdata) {
897         sd_rtnl *rtnl = userdata;
898
899         assert(event);
900
901         sd_rtnl_flush(rtnl);
902
903         return 1;
904 }
905
906 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
907         int r;
908
909         assert_return(rtnl, -EINVAL);
910         assert_return(!rtnl->event, -EBUSY);
911
912         assert(!rtnl->io_event_source);
913         assert(!rtnl->time_event_source);
914
915         if (event)
916                 rtnl->event = sd_event_ref(event);
917         else {
918                 r = sd_event_default(&rtnl->event);
919                 if (r < 0)
920                         return r;
921         }
922
923         r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
924         if (r < 0)
925                 goto fail;
926
927         r = sd_event_source_set_priority(rtnl->io_event_source, priority);
928         if (r < 0)
929                 goto fail;
930
931         r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
932         if (r < 0)
933                 goto fail;
934
935         r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
936         if (r < 0)
937                 goto fail;
938
939         r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
940         if (r < 0)
941                 goto fail;
942
943         r = sd_event_source_set_priority(rtnl->time_event_source, priority);
944         if (r < 0)
945                 goto fail;
946
947         r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
948         if (r < 0)
949                 goto fail;
950
951         r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
952         if (r < 0)
953                 goto fail;
954
955         r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
956         if (r < 0)
957                 goto fail;
958
959         return 0;
960
961 fail:
962         sd_rtnl_detach_event(rtnl);
963         return r;
964 }
965
966 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
967         assert_return(rtnl, -EINVAL);
968         assert_return(rtnl->event, -ENXIO);
969
970         if (rtnl->io_event_source)
971                 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
972
973         if (rtnl->time_event_source)
974                 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
975
976         if (rtnl->exit_event_source)
977                 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
978
979         if (rtnl->event)
980                 rtnl->event = sd_event_unref(rtnl->event);
981
982         return 0;
983 }
984
985 int sd_rtnl_add_match(sd_rtnl *rtnl,
986                       uint16_t type,
987                       sd_rtnl_message_handler_t callback,
988                       void *userdata) {
989         struct match_callback *c;
990
991         assert_return(rtnl, -EINVAL);
992         assert_return(callback, -EINVAL);
993         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
994         assert_return(rtnl_message_type_is_link(type) ||
995                       rtnl_message_type_is_addr(type) ||
996                       rtnl_message_type_is_route(type), -ENOTSUP);
997
998         c = new0(struct match_callback, 1);
999         if (!c)
1000                 return -ENOMEM;
1001
1002         c->callback = callback;
1003         c->type = type;
1004         c->userdata = userdata;
1005
1006         LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
1007
1008         return 0;
1009 }
1010
1011 int sd_rtnl_remove_match(sd_rtnl *rtnl,
1012                          uint16_t type,
1013                          sd_rtnl_message_handler_t callback,
1014                          void *userdata) {
1015         struct match_callback *c;
1016
1017         assert_return(rtnl, -EINVAL);
1018         assert_return(callback, -EINVAL);
1019         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
1020
1021         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
1022                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
1023                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
1024                         free(c);
1025
1026                         return 1;
1027                 }
1028
1029         return 0;
1030 }