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