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