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