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