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