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