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