]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/sd-netlink.c
sd-netlink: don't give up on netlink on ENOBUFS
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / sd-netlink.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <poll.h>
21 #include <sys/socket.h>
22
23 #include "sd-netlink.h"
24
25 #include "alloc-util.h"
26 #include "fd-util.h"
27 #include "hashmap.h"
28 #include "macro.h"
29 #include "missing.h"
30 #include "netlink-internal.h"
31 #include "netlink-util.h"
32 #include "socket-util.h"
33 #include "util.h"
34
35 static int sd_netlink_new(sd_netlink **ret) {
36 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
37
38 assert_return(ret, -EINVAL);
39
40 rtnl = new0(sd_netlink, 1);
41 if (!rtnl)
42 return -ENOMEM;
43
44 rtnl->n_ref = REFCNT_INIT;
45 rtnl->fd = -1;
46 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
47 rtnl->original_pid = getpid();
48
49 LIST_HEAD_INIT(rtnl->match_callbacks);
50
51 /* We guarantee that the read buffer has at least space for
52 * a message header */
53 if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
54 sizeof(struct nlmsghdr), sizeof(uint8_t)))
55 return -ENOMEM;
56
57 /* Change notification responses have sequence 0, so we must
58 * start our request sequence numbers at 1, or we may confuse our
59 * responses with notifications from the kernel */
60 rtnl->serial = 1;
61
62 *ret = rtnl;
63 rtnl = NULL;
64
65 return 0;
66 }
67
68 int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
69 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
70 socklen_t addrlen;
71 int r;
72
73 assert_return(ret, -EINVAL);
74
75 r = sd_netlink_new(&rtnl);
76 if (r < 0)
77 return r;
78
79 addrlen = sizeof(rtnl->sockaddr);
80
81 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
82 if (r < 0)
83 return -errno;
84
85 if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
86 return -EINVAL;
87
88 rtnl->fd = fd;
89
90 *ret = rtnl;
91 rtnl = NULL;
92
93 return 0;
94 }
95
96 static bool rtnl_pid_changed(sd_netlink *rtnl) {
97 assert(rtnl);
98
99 /* We don't support people creating an rtnl connection and
100 * keeping it around over a fork(). Let's complain. */
101
102 return rtnl->original_pid != getpid();
103 }
104
105 int sd_netlink_open_fd(sd_netlink **ret, int fd) {
106 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
107 int r;
108
109 assert_return(ret, -EINVAL);
110 assert_return(fd >= 0, -EBADF);
111
112 r = sd_netlink_new(&rtnl);
113 if (r < 0)
114 return r;
115
116 rtnl->fd = fd;
117
118 r = socket_bind(rtnl);
119 if (r < 0) {
120 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
121 return r;
122 }
123
124 *ret = rtnl;
125 rtnl = NULL;
126
127 return 0;
128 }
129
130 int sd_netlink_open(sd_netlink **ret) {
131 _cleanup_close_ int fd = -1;
132 int r;
133
134 fd = socket_open(NETLINK_ROUTE);
135 if (fd < 0)
136 return fd;
137
138 r = sd_netlink_open_fd(ret, fd);
139 if (r < 0)
140 return r;
141
142 fd = -1;
143
144 return 0;
145 }
146
147 int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
148 assert_return(rtnl, -EINVAL);
149 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
150
151 return fd_inc_rcvbuf(rtnl->fd, size);
152 }
153
154 sd_netlink *sd_netlink_ref(sd_netlink *rtnl) {
155 assert_return(rtnl, NULL);
156 assert_return(!rtnl_pid_changed(rtnl), NULL);
157
158 if (rtnl)
159 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
160
161 return rtnl;
162 }
163
164 sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
165 if (!rtnl)
166 return NULL;
167
168 assert_return(!rtnl_pid_changed(rtnl), NULL);
169
170 if (REFCNT_DEC(rtnl->n_ref) == 0) {
171 struct match_callback *f;
172 unsigned i;
173
174 for (i = 0; i < rtnl->rqueue_size; i++)
175 sd_netlink_message_unref(rtnl->rqueue[i]);
176 free(rtnl->rqueue);
177
178 for (i = 0; i < rtnl->rqueue_partial_size; i++)
179 sd_netlink_message_unref(rtnl->rqueue_partial[i]);
180 free(rtnl->rqueue_partial);
181
182 free(rtnl->rbuffer);
183
184 hashmap_free_free(rtnl->reply_callbacks);
185 prioq_free(rtnl->reply_callbacks_prioq);
186
187 sd_event_source_unref(rtnl->io_event_source);
188 sd_event_source_unref(rtnl->time_event_source);
189 sd_event_unref(rtnl->event);
190
191 while ((f = rtnl->match_callbacks)) {
192 sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata);
193 }
194
195 hashmap_free(rtnl->broadcast_group_refs);
196
197 safe_close(rtnl->fd);
198 free(rtnl);
199 }
200
201 return NULL;
202 }
203
204 static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) {
205 assert(rtnl);
206 assert(!rtnl_pid_changed(rtnl));
207 assert(m);
208 assert(m->hdr);
209
210 /* don't use seq == 0, as that is used for broadcasts, so we
211 would get confused by replies to such messages */
212 m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
213
214 rtnl_message_seal(m);
215
216 return;
217 }
218
219 int sd_netlink_send(sd_netlink *nl,
220 sd_netlink_message *message,
221 uint32_t *serial) {
222 int r;
223
224 assert_return(nl, -EINVAL);
225 assert_return(!rtnl_pid_changed(nl), -ECHILD);
226 assert_return(message, -EINVAL);
227 assert_return(!message->sealed, -EPERM);
228
229 rtnl_seal_message(nl, message);
230
231 r = socket_write_message(nl, message);
232 if (r < 0)
233 return r;
234
235 if (serial)
236 *serial = rtnl_message_get_serial(message);
237
238 return 1;
239 }
240
241 int rtnl_rqueue_make_room(sd_netlink *rtnl) {
242 assert(rtnl);
243
244 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
245 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
246 return -ENOBUFS;
247 }
248
249 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
250 return -ENOMEM;
251
252 return 0;
253 }
254
255 int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) {
256 assert(rtnl);
257
258 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
259 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
260 return -ENOBUFS;
261 }
262
263 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
264 rtnl->rqueue_partial_size + 1))
265 return -ENOMEM;
266
267 return 0;
268 }
269
270 static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
271 int r;
272
273 assert(rtnl);
274 assert(message);
275
276 if (rtnl->rqueue_size <= 0) {
277 /* Try to read a new message */
278 r = socket_read_message(rtnl);
279 if (r == -ENOBUFS) { /* FIXME: ignore buffer overruns for now */
280 log_debug_errno(r, "Got ENOBUFS from netlink socket, ignoring.");
281 return 1;
282 }
283 if (r <= 0)
284 return r;
285 }
286
287 /* Dispatch a queued message */
288 *message = rtnl->rqueue[0];
289 rtnl->rqueue_size--;
290 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
291
292 return 1;
293 }
294
295 static int process_timeout(sd_netlink *rtnl) {
296 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
297 struct reply_callback *c;
298 usec_t n;
299 int r;
300
301 assert(rtnl);
302
303 c = prioq_peek(rtnl->reply_callbacks_prioq);
304 if (!c)
305 return 0;
306
307 n = now(CLOCK_MONOTONIC);
308 if (c->timeout > n)
309 return 0;
310
311 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
312 if (r < 0)
313 return r;
314
315 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
316 hashmap_remove(rtnl->reply_callbacks, &c->serial);
317
318 r = c->callback(rtnl, m, c->userdata);
319 if (r < 0)
320 log_debug_errno(r, "sd-netlink: timedout callback failed: %m");
321
322 free(c);
323
324 return 1;
325 }
326
327 static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
328 _cleanup_free_ struct reply_callback *c = NULL;
329 uint64_t serial;
330 uint16_t type;
331 int r;
332
333 assert(rtnl);
334 assert(m);
335
336 serial = rtnl_message_get_serial(m);
337 c = hashmap_remove(rtnl->reply_callbacks, &serial);
338 if (!c)
339 return 0;
340
341 if (c->timeout != 0)
342 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
343
344 r = sd_netlink_message_get_type(m, &type);
345 if (r < 0)
346 return 0;
347
348 if (type == NLMSG_DONE)
349 m = NULL;
350
351 r = c->callback(rtnl, m, c->userdata);
352 if (r < 0)
353 log_debug_errno(r, "sd-netlink: callback failed: %m");
354
355 return 1;
356 }
357
358 static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
359 struct match_callback *c;
360 uint16_t type;
361 int r;
362
363 assert(rtnl);
364 assert(m);
365
366 r = sd_netlink_message_get_type(m, &type);
367 if (r < 0)
368 return r;
369
370 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
371 if (type == c->type) {
372 r = c->callback(rtnl, m, c->userdata);
373 if (r != 0) {
374 if (r < 0)
375 log_debug_errno(r, "sd-netlink: match callback failed: %m");
376
377 break;
378 }
379 }
380 }
381
382 return 1;
383 }
384
385 static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
386 _cleanup_(sd_netlink_message_unrefp) sd_netlink_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_rqueue(rtnl, &m);
396 if (r < 0)
397 return r;
398 if (!m)
399 goto null_message;
400
401 if (sd_netlink_message_is_broadcast(m)) {
402 r = process_match(rtnl, m);
403 if (r != 0)
404 goto null_message;
405 } else {
406 r = process_reply(rtnl, m);
407 if (r != 0)
408 goto null_message;
409 }
410
411 if (ret) {
412 *ret = m;
413 m = NULL;
414
415 return 1;
416 }
417
418 return 1;
419
420 null_message:
421 if (r >= 0 && ret)
422 *ret = NULL;
423
424 return r;
425 }
426
427 int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
428 NETLINK_DONT_DESTROY(rtnl);
429 int r;
430
431 assert_return(rtnl, -EINVAL);
432 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
433 assert_return(!rtnl->processing, -EBUSY);
434
435 rtnl->processing = true;
436 r = process_running(rtnl, ret);
437 rtnl->processing = false;
438
439 return r;
440 }
441
442 static usec_t calc_elapse(uint64_t usec) {
443 if (usec == (uint64_t) -1)
444 return 0;
445
446 if (usec == 0)
447 usec = RTNL_DEFAULT_TIMEOUT;
448
449 return now(CLOCK_MONOTONIC) + usec;
450 }
451
452 static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
453 struct pollfd p[1] = {};
454 struct timespec ts;
455 usec_t m = USEC_INFINITY;
456 int r, e;
457
458 assert(rtnl);
459
460 e = sd_netlink_get_events(rtnl);
461 if (e < 0)
462 return e;
463
464 if (need_more)
465 /* Caller wants more data, and doesn't care about
466 * what's been read or any other timeouts. */
467 e |= POLLIN;
468 else {
469 usec_t until;
470 /* Caller wants to process if there is something to
471 * process, but doesn't care otherwise */
472
473 r = sd_netlink_get_timeout(rtnl, &until);
474 if (r < 0)
475 return r;
476 if (r > 0) {
477 usec_t nw;
478 nw = now(CLOCK_MONOTONIC);
479 m = until > nw ? until - nw : 0;
480 }
481 }
482
483 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
484 m = timeout_usec;
485
486 p[0].fd = rtnl->fd;
487 p[0].events = e;
488
489 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
490 if (r < 0)
491 return -errno;
492
493 return r > 0 ? 1 : 0;
494 }
495
496 int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
497 assert_return(nl, -EINVAL);
498 assert_return(!rtnl_pid_changed(nl), -ECHILD);
499
500 if (nl->rqueue_size > 0)
501 return 0;
502
503 return rtnl_poll(nl, false, timeout_usec);
504 }
505
506 static int timeout_compare(const void *a, const void *b) {
507 const struct reply_callback *x = a, *y = b;
508
509 if (x->timeout != 0 && y->timeout == 0)
510 return -1;
511
512 if (x->timeout == 0 && y->timeout != 0)
513 return 1;
514
515 if (x->timeout < y->timeout)
516 return -1;
517
518 if (x->timeout > y->timeout)
519 return 1;
520
521 return 0;
522 }
523
524 int sd_netlink_call_async(sd_netlink *nl,
525 sd_netlink_message *m,
526 sd_netlink_message_handler_t callback,
527 void *userdata,
528 uint64_t usec,
529 uint32_t *serial) {
530 struct reply_callback *c;
531 uint32_t s;
532 int r, k;
533
534 assert_return(nl, -EINVAL);
535 assert_return(m, -EINVAL);
536 assert_return(callback, -EINVAL);
537 assert_return(!rtnl_pid_changed(nl), -ECHILD);
538
539 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
540 if (r < 0)
541 return r;
542
543 if (usec != (uint64_t) -1) {
544 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
545 if (r < 0)
546 return r;
547 }
548
549 c = new0(struct reply_callback, 1);
550 if (!c)
551 return -ENOMEM;
552
553 c->callback = callback;
554 c->userdata = userdata;
555 c->timeout = calc_elapse(usec);
556
557 k = sd_netlink_send(nl, m, &s);
558 if (k < 0) {
559 free(c);
560 return k;
561 }
562
563 c->serial = s;
564
565 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
566 if (r < 0) {
567 free(c);
568 return r;
569 }
570
571 if (c->timeout != 0) {
572 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
573 if (r > 0) {
574 c->timeout = 0;
575 sd_netlink_call_async_cancel(nl, c->serial);
576 return r;
577 }
578 }
579
580 if (serial)
581 *serial = s;
582
583 return k;
584 }
585
586 int sd_netlink_call_async_cancel(sd_netlink *nl, uint32_t serial) {
587 struct reply_callback *c;
588 uint64_t s = serial;
589
590 assert_return(nl, -EINVAL);
591 assert_return(serial != 0, -EINVAL);
592 assert_return(!rtnl_pid_changed(nl), -ECHILD);
593
594 c = hashmap_remove(nl->reply_callbacks, &s);
595 if (!c)
596 return 0;
597
598 if (c->timeout != 0)
599 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
600
601 free(c);
602 return 1;
603 }
604
605 int sd_netlink_call(sd_netlink *rtnl,
606 sd_netlink_message *message,
607 uint64_t usec,
608 sd_netlink_message **ret) {
609 usec_t timeout;
610 uint32_t serial;
611 int r;
612
613 assert_return(rtnl, -EINVAL);
614 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
615 assert_return(message, -EINVAL);
616
617 r = sd_netlink_send(rtnl, message, &serial);
618 if (r < 0)
619 return r;
620
621 timeout = calc_elapse(usec);
622
623 for (;;) {
624 usec_t left;
625 unsigned i;
626
627 for (i = 0; i < rtnl->rqueue_size; i++) {
628 uint32_t received_serial;
629
630 received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
631
632 if (received_serial == serial) {
633 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
634 uint16_t type;
635
636 incoming = rtnl->rqueue[i];
637
638 /* found a match, remove from rqueue and return it */
639 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
640 sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1));
641 rtnl->rqueue_size--;
642
643 r = sd_netlink_message_get_errno(incoming);
644 if (r < 0)
645 return r;
646
647 r = sd_netlink_message_get_type(incoming, &type);
648 if (r < 0)
649 return r;
650
651 if (type == NLMSG_DONE) {
652 *ret = NULL;
653 return 0;
654 }
655
656 if (ret) {
657 *ret = incoming;
658 incoming = NULL;
659 }
660
661 return 1;
662 }
663 }
664
665 r = socket_read_message(rtnl);
666 if (r < 0)
667 return r;
668 if (r > 0)
669 /* received message, so try to process straight away */
670 continue;
671
672 if (timeout > 0) {
673 usec_t n;
674
675 n = now(CLOCK_MONOTONIC);
676 if (n >= timeout)
677 return -ETIMEDOUT;
678
679 left = timeout - n;
680 } else
681 left = (uint64_t) -1;
682
683 r = rtnl_poll(rtnl, true, left);
684 if (r < 0)
685 return r;
686 else if (r == 0)
687 return -ETIMEDOUT;
688 }
689 }
690
691 int sd_netlink_get_events(sd_netlink *rtnl) {
692 assert_return(rtnl, -EINVAL);
693 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
694
695 if (rtnl->rqueue_size == 0)
696 return POLLIN;
697 else
698 return 0;
699 }
700
701 int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) {
702 struct reply_callback *c;
703
704 assert_return(rtnl, -EINVAL);
705 assert_return(timeout_usec, -EINVAL);
706 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
707
708 if (rtnl->rqueue_size > 0) {
709 *timeout_usec = 0;
710 return 1;
711 }
712
713 c = prioq_peek(rtnl->reply_callbacks_prioq);
714 if (!c) {
715 *timeout_usec = (uint64_t) -1;
716 return 0;
717 }
718
719 *timeout_usec = c->timeout;
720
721 return 1;
722 }
723
724 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
725 sd_netlink *rtnl = userdata;
726 int r;
727
728 assert(rtnl);
729
730 r = sd_netlink_process(rtnl, NULL);
731 if (r < 0)
732 return r;
733
734 return 1;
735 }
736
737 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
738 sd_netlink *rtnl = userdata;
739 int r;
740
741 assert(rtnl);
742
743 r = sd_netlink_process(rtnl, NULL);
744 if (r < 0)
745 return r;
746
747 return 1;
748 }
749
750 static int prepare_callback(sd_event_source *s, void *userdata) {
751 sd_netlink *rtnl = userdata;
752 int r, e;
753 usec_t until;
754
755 assert(s);
756 assert(rtnl);
757
758 e = sd_netlink_get_events(rtnl);
759 if (e < 0)
760 return e;
761
762 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
763 if (r < 0)
764 return r;
765
766 r = sd_netlink_get_timeout(rtnl, &until);
767 if (r < 0)
768 return r;
769 if (r > 0) {
770 int j;
771
772 j = sd_event_source_set_time(rtnl->time_event_source, until);
773 if (j < 0)
774 return j;
775 }
776
777 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
778 if (r < 0)
779 return r;
780
781 return 1;
782 }
783
784 int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
785 int r;
786
787 assert_return(rtnl, -EINVAL);
788 assert_return(!rtnl->event, -EBUSY);
789
790 assert(!rtnl->io_event_source);
791 assert(!rtnl->time_event_source);
792
793 if (event)
794 rtnl->event = sd_event_ref(event);
795 else {
796 r = sd_event_default(&rtnl->event);
797 if (r < 0)
798 return r;
799 }
800
801 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
802 if (r < 0)
803 goto fail;
804
805 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
806 if (r < 0)
807 goto fail;
808
809 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
810 if (r < 0)
811 goto fail;
812
813 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
814 if (r < 0)
815 goto fail;
816
817 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
818 if (r < 0)
819 goto fail;
820
821 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
822 if (r < 0)
823 goto fail;
824
825 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
826 if (r < 0)
827 goto fail;
828
829 return 0;
830
831 fail:
832 sd_netlink_detach_event(rtnl);
833 return r;
834 }
835
836 int sd_netlink_detach_event(sd_netlink *rtnl) {
837 assert_return(rtnl, -EINVAL);
838 assert_return(rtnl->event, -ENXIO);
839
840 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
841
842 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
843
844 rtnl->event = sd_event_unref(rtnl->event);
845
846 return 0;
847 }
848
849 int sd_netlink_add_match(sd_netlink *rtnl,
850 uint16_t type,
851 sd_netlink_message_handler_t callback,
852 void *userdata) {
853 _cleanup_free_ struct match_callback *c = NULL;
854 int r;
855
856 assert_return(rtnl, -EINVAL);
857 assert_return(callback, -EINVAL);
858 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
859
860 c = new0(struct match_callback, 1);
861 if (!c)
862 return -ENOMEM;
863
864 c->callback = callback;
865 c->type = type;
866 c->userdata = userdata;
867
868 switch (type) {
869 case RTM_NEWLINK:
870 case RTM_DELLINK:
871 r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
872 if (r < 0)
873 return r;
874
875 break;
876 case RTM_NEWADDR:
877 case RTM_DELADDR:
878 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
879 if (r < 0)
880 return r;
881
882 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
883 if (r < 0)
884 return r;
885
886 break;
887 case RTM_NEWROUTE:
888 case RTM_DELROUTE:
889 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
890 if (r < 0)
891 return r;
892
893 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
894 if (r < 0)
895 return r;
896 break;
897 default:
898 return -EOPNOTSUPP;
899 }
900
901 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
902
903 c = NULL;
904
905 return 0;
906 }
907
908 int sd_netlink_remove_match(sd_netlink *rtnl,
909 uint16_t type,
910 sd_netlink_message_handler_t callback,
911 void *userdata) {
912 struct match_callback *c;
913 int r;
914
915 assert_return(rtnl, -EINVAL);
916 assert_return(callback, -EINVAL);
917 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
918
919 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
920 if (c->callback == callback && c->type == type && c->userdata == userdata) {
921 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
922 free(c);
923
924 switch (type) {
925 case RTM_NEWLINK:
926 case RTM_DELLINK:
927 r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK);
928 if (r < 0)
929 return r;
930
931 break;
932 case RTM_NEWADDR:
933 case RTM_DELADDR:
934 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR);
935 if (r < 0)
936 return r;
937
938 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR);
939 if (r < 0)
940 return r;
941
942 break;
943 case RTM_NEWROUTE:
944 case RTM_DELROUTE:
945 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE);
946 if (r < 0)
947 return r;
948
949 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE);
950 if (r < 0)
951 return r;
952 break;
953 default:
954 return -EOPNOTSUPP;
955 }
956
957 return 1;
958 }
959
960 return 0;
961 }