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