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