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