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