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