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