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