]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/sd-netlink.c
Merge pull request #8417 from brauner/2018-03-09/add_bind_mount_fallback_to_private_d...
[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
8 #include <poll.h>
9 #include <sys/socket.h>
10
11 #include "sd-netlink.h"
12
13 #include "alloc-util.h"
14 #include "fd-util.h"
15 #include "hashmap.h"
16 #include "macro.h"
17 #include "missing.h"
18 #include "netlink-internal.h"
19 #include "netlink-util.h"
20 #include "process-util.h"
21 #include "socket-util.h"
22 #include "util.h"
23
24 static int sd_netlink_new(sd_netlink **ret) {
25 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
26
27 assert_return(ret, -EINVAL);
28
29 rtnl = new0(sd_netlink, 1);
30 if (!rtnl)
31 return -ENOMEM;
32
33 rtnl->n_ref = REFCNT_INIT;
34 rtnl->fd = -1;
35 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
36 rtnl->original_pid = getpid_cached();
37 rtnl->protocol = -1;
38
39 LIST_HEAD_INIT(rtnl->match_callbacks);
40
41 /* We guarantee that the read buffer has at least space for
42 * a message header */
43 if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
44 sizeof(struct nlmsghdr), sizeof(uint8_t)))
45 return -ENOMEM;
46
47 /* Change notification responses have sequence 0, so we must
48 * start our request sequence numbers at 1, or we may confuse our
49 * responses with notifications from the kernel */
50 rtnl->serial = 1;
51
52 *ret = TAKE_PTR(rtnl);
53
54 return 0;
55 }
56
57 int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
58 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
59 socklen_t addrlen;
60 int r;
61
62 assert_return(ret, -EINVAL);
63
64 r = sd_netlink_new(&rtnl);
65 if (r < 0)
66 return r;
67
68 addrlen = sizeof(rtnl->sockaddr);
69
70 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
71 if (r < 0)
72 return -errno;
73
74 if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
75 return -EINVAL;
76
77 rtnl->fd = fd;
78
79 *ret = TAKE_PTR(rtnl);
80
81 return 0;
82 }
83
84 static bool rtnl_pid_changed(sd_netlink *rtnl) {
85 assert(rtnl);
86
87 /* We don't support people creating an rtnl connection and
88 * keeping it around over a fork(). Let's complain. */
89
90 return rtnl->original_pid != getpid_cached();
91 }
92
93 int sd_netlink_open_fd(sd_netlink **ret, int fd) {
94 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
95 int r;
96 int protocol;
97 socklen_t l;
98
99 assert_return(ret, -EINVAL);
100 assert_return(fd >= 0, -EBADF);
101
102 r = sd_netlink_new(&rtnl);
103 if (r < 0)
104 return r;
105
106 l = sizeof(protocol);
107 r = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &l);
108 if (r < 0)
109 return r;
110
111 rtnl->fd = fd;
112 rtnl->protocol = protocol;
113
114 r = socket_bind(rtnl);
115 if (r < 0) {
116 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
117 rtnl->protocol = -1;
118 return r;
119 }
120
121 *ret = TAKE_PTR(rtnl);
122
123 return 0;
124 }
125
126 int netlink_open_family(sd_netlink **ret, int family) {
127 _cleanup_close_ int fd = -1;
128 int r;
129
130 fd = socket_open(family);
131 if (fd < 0)
132 return fd;
133
134 r = sd_netlink_open_fd(ret, fd);
135 if (r < 0)
136 return r;
137
138 fd = -1;
139
140 return 0;
141 }
142
143 int sd_netlink_open(sd_netlink **ret) {
144 return netlink_open_family(ret, NETLINK_ROUTE);
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(rtnl, -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 = TAKE_PTR(m);
413
414 return 1;
415 }
416
417 return 1;
418
419 null_message:
420 if (r >= 0 && ret)
421 *ret = NULL;
422
423 return r;
424 }
425
426 int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
427 NETLINK_DONT_DESTROY(rtnl);
428 int r;
429
430 assert_return(rtnl, -EINVAL);
431 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
432 assert_return(!rtnl->processing, -EBUSY);
433
434 rtnl->processing = true;
435 r = process_running(rtnl, ret);
436 rtnl->processing = false;
437
438 return r;
439 }
440
441 static usec_t calc_elapse(uint64_t usec) {
442 if (usec == (uint64_t) -1)
443 return 0;
444
445 if (usec == 0)
446 usec = RTNL_DEFAULT_TIMEOUT;
447
448 return now(CLOCK_MONOTONIC) + usec;
449 }
450
451 static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
452 struct pollfd p[1] = {};
453 struct timespec ts;
454 usec_t m = USEC_INFINITY;
455 int r, e;
456
457 assert(rtnl);
458
459 e = sd_netlink_get_events(rtnl);
460 if (e < 0)
461 return e;
462
463 if (need_more)
464 /* Caller wants more data, and doesn't care about
465 * what's been read or any other timeouts. */
466 e |= POLLIN;
467 else {
468 usec_t until;
469 /* Caller wants to process if there is something to
470 * process, but doesn't care otherwise */
471
472 r = sd_netlink_get_timeout(rtnl, &until);
473 if (r < 0)
474 return r;
475 if (r > 0) {
476 usec_t nw;
477 nw = now(CLOCK_MONOTONIC);
478 m = until > nw ? until - nw : 0;
479 }
480 }
481
482 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
483 m = timeout_usec;
484
485 p[0].fd = rtnl->fd;
486 p[0].events = e;
487
488 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
489 if (r < 0)
490 return -errno;
491
492 return r > 0 ? 1 : 0;
493 }
494
495 int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
496 assert_return(nl, -EINVAL);
497 assert_return(!rtnl_pid_changed(nl), -ECHILD);
498
499 if (nl->rqueue_size > 0)
500 return 0;
501
502 return rtnl_poll(nl, false, timeout_usec);
503 }
504
505 static int timeout_compare(const void *a, const void *b) {
506 const struct reply_callback *x = a, *y = b;
507
508 if (x->timeout != 0 && y->timeout == 0)
509 return -1;
510
511 if (x->timeout == 0 && y->timeout != 0)
512 return 1;
513
514 if (x->timeout < y->timeout)
515 return -1;
516
517 if (x->timeout > y->timeout)
518 return 1;
519
520 return 0;
521 }
522
523 int sd_netlink_call_async(sd_netlink *nl,
524 sd_netlink_message *m,
525 sd_netlink_message_handler_t callback,
526 void *userdata,
527 uint64_t usec,
528 uint32_t *serial) {
529 struct reply_callback *c;
530 uint32_t s;
531 int r, k;
532
533 assert_return(nl, -EINVAL);
534 assert_return(m, -EINVAL);
535 assert_return(callback, -EINVAL);
536 assert_return(!rtnl_pid_changed(nl), -ECHILD);
537
538 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
539 if (r < 0)
540 return r;
541
542 if (usec != (uint64_t) -1) {
543 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
544 if (r < 0)
545 return r;
546 }
547
548 c = new0(struct reply_callback, 1);
549 if (!c)
550 return -ENOMEM;
551
552 c->callback = callback;
553 c->userdata = userdata;
554 c->timeout = calc_elapse(usec);
555
556 k = sd_netlink_send(nl, m, &s);
557 if (k < 0) {
558 free(c);
559 return k;
560 }
561
562 c->serial = s;
563
564 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
565 if (r < 0) {
566 free(c);
567 return r;
568 }
569
570 if (c->timeout != 0) {
571 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
572 if (r > 0) {
573 c->timeout = 0;
574 sd_netlink_call_async_cancel(nl, c->serial);
575 return r;
576 }
577 }
578
579 if (serial)
580 *serial = s;
581
582 return k;
583 }
584
585 int sd_netlink_call_async_cancel(sd_netlink *nl, uint32_t serial) {
586 struct reply_callback *c;
587 uint64_t s = serial;
588
589 assert_return(nl, -EINVAL);
590 assert_return(serial != 0, -EINVAL);
591 assert_return(!rtnl_pid_changed(nl), -ECHILD);
592
593 c = hashmap_remove(nl->reply_callbacks, &s);
594 if (!c)
595 return 0;
596
597 if (c->timeout != 0)
598 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
599
600 free(c);
601 return 1;
602 }
603
604 int sd_netlink_call(sd_netlink *rtnl,
605 sd_netlink_message *message,
606 uint64_t usec,
607 sd_netlink_message **ret) {
608 usec_t timeout;
609 uint32_t serial;
610 int r;
611
612 assert_return(rtnl, -EINVAL);
613 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
614 assert_return(message, -EINVAL);
615
616 r = sd_netlink_send(rtnl, message, &serial);
617 if (r < 0)
618 return r;
619
620 timeout = calc_elapse(usec);
621
622 for (;;) {
623 usec_t left;
624 unsigned i;
625
626 for (i = 0; i < rtnl->rqueue_size; i++) {
627 uint32_t received_serial;
628
629 received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
630
631 if (received_serial == serial) {
632 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
633 uint16_t type;
634
635 incoming = rtnl->rqueue[i];
636
637 /* found a match, remove from rqueue and return it */
638 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
639 sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1));
640 rtnl->rqueue_size--;
641
642 r = sd_netlink_message_get_errno(incoming);
643 if (r < 0)
644 return r;
645
646 r = sd_netlink_message_get_type(incoming, &type);
647 if (r < 0)
648 return r;
649
650 if (type == NLMSG_DONE) {
651 *ret = NULL;
652 return 0;
653 }
654
655 if (ret)
656 *ret = TAKE_PTR(incoming);
657
658 return 1;
659 }
660 }
661
662 r = socket_read_message(rtnl);
663 if (r < 0)
664 return r;
665 if (r > 0)
666 /* received message, so try to process straight away */
667 continue;
668
669 if (timeout > 0) {
670 usec_t n;
671
672 n = now(CLOCK_MONOTONIC);
673 if (n >= timeout)
674 return -ETIMEDOUT;
675
676 left = timeout - n;
677 } else
678 left = (uint64_t) -1;
679
680 r = rtnl_poll(rtnl, true, left);
681 if (r < 0)
682 return r;
683 else if (r == 0)
684 return -ETIMEDOUT;
685 }
686 }
687
688 int sd_netlink_get_events(sd_netlink *rtnl) {
689 assert_return(rtnl, -EINVAL);
690 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
691
692 if (rtnl->rqueue_size == 0)
693 return POLLIN;
694 else
695 return 0;
696 }
697
698 int sd_netlink_get_timeout(sd_netlink *rtnl, uint64_t *timeout_usec) {
699 struct reply_callback *c;
700
701 assert_return(rtnl, -EINVAL);
702 assert_return(timeout_usec, -EINVAL);
703 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
704
705 if (rtnl->rqueue_size > 0) {
706 *timeout_usec = 0;
707 return 1;
708 }
709
710 c = prioq_peek(rtnl->reply_callbacks_prioq);
711 if (!c) {
712 *timeout_usec = (uint64_t) -1;
713 return 0;
714 }
715
716 *timeout_usec = c->timeout;
717
718 return 1;
719 }
720
721 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
722 sd_netlink *rtnl = userdata;
723 int r;
724
725 assert(rtnl);
726
727 r = sd_netlink_process(rtnl, NULL);
728 if (r < 0)
729 return r;
730
731 return 1;
732 }
733
734 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
735 sd_netlink *rtnl = userdata;
736 int r;
737
738 assert(rtnl);
739
740 r = sd_netlink_process(rtnl, NULL);
741 if (r < 0)
742 return r;
743
744 return 1;
745 }
746
747 static int prepare_callback(sd_event_source *s, void *userdata) {
748 sd_netlink *rtnl = userdata;
749 int r, e;
750 usec_t until;
751
752 assert(s);
753 assert(rtnl);
754
755 e = sd_netlink_get_events(rtnl);
756 if (e < 0)
757 return e;
758
759 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
760 if (r < 0)
761 return r;
762
763 r = sd_netlink_get_timeout(rtnl, &until);
764 if (r < 0)
765 return r;
766 if (r > 0) {
767 int j;
768
769 j = sd_event_source_set_time(rtnl->time_event_source, until);
770 if (j < 0)
771 return j;
772 }
773
774 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
775 if (r < 0)
776 return r;
777
778 return 1;
779 }
780
781 int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
782 int r;
783
784 assert_return(rtnl, -EINVAL);
785 assert_return(!rtnl->event, -EBUSY);
786
787 assert(!rtnl->io_event_source);
788 assert(!rtnl->time_event_source);
789
790 if (event)
791 rtnl->event = sd_event_ref(event);
792 else {
793 r = sd_event_default(&rtnl->event);
794 if (r < 0)
795 return r;
796 }
797
798 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
799 if (r < 0)
800 goto fail;
801
802 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
803 if (r < 0)
804 goto fail;
805
806 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
807 if (r < 0)
808 goto fail;
809
810 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
811 if (r < 0)
812 goto fail;
813
814 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
815 if (r < 0)
816 goto fail;
817
818 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
819 if (r < 0)
820 goto fail;
821
822 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
823 if (r < 0)
824 goto fail;
825
826 return 0;
827
828 fail:
829 sd_netlink_detach_event(rtnl);
830 return r;
831 }
832
833 int sd_netlink_detach_event(sd_netlink *rtnl) {
834 assert_return(rtnl, -EINVAL);
835 assert_return(rtnl->event, -ENXIO);
836
837 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
838
839 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
840
841 rtnl->event = sd_event_unref(rtnl->event);
842
843 return 0;
844 }
845
846 int sd_netlink_add_match(sd_netlink *rtnl,
847 uint16_t type,
848 sd_netlink_message_handler_t callback,
849 void *userdata) {
850 _cleanup_free_ struct match_callback *c = NULL;
851 int r;
852
853 assert_return(rtnl, -EINVAL);
854 assert_return(callback, -EINVAL);
855 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
856
857 c = new0(struct match_callback, 1);
858 if (!c)
859 return -ENOMEM;
860
861 c->callback = callback;
862 c->type = type;
863 c->userdata = userdata;
864
865 switch (type) {
866 case RTM_NEWLINK:
867 case RTM_DELLINK:
868 r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
869 if (r < 0)
870 return r;
871
872 break;
873 case RTM_NEWADDR:
874 case RTM_DELADDR:
875 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
876 if (r < 0)
877 return r;
878
879 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
880 if (r < 0)
881 return r;
882
883 break;
884 case RTM_NEWROUTE:
885 case RTM_DELROUTE:
886 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
887 if (r < 0)
888 return r;
889
890 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
891 if (r < 0)
892 return r;
893 break;
894 case RTM_NEWRULE:
895 case RTM_DELRULE:
896 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE);
897 if (r < 0)
898 return r;
899
900 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE);
901 if (r < 0)
902 return r;
903 break;
904 default:
905 return -EOPNOTSUPP;
906 }
907
908 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
909
910 c = NULL;
911
912 return 0;
913 }
914
915 int sd_netlink_remove_match(sd_netlink *rtnl,
916 uint16_t type,
917 sd_netlink_message_handler_t callback,
918 void *userdata) {
919 struct match_callback *c;
920 int r;
921
922 assert_return(rtnl, -EINVAL);
923 assert_return(callback, -EINVAL);
924 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
925
926 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
927 if (c->callback == callback && c->type == type && c->userdata == userdata) {
928 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
929 free(c);
930
931 switch (type) {
932 case RTM_NEWLINK:
933 case RTM_DELLINK:
934 r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK);
935 if (r < 0)
936 return r;
937
938 break;
939 case RTM_NEWADDR:
940 case RTM_DELADDR:
941 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR);
942 if (r < 0)
943 return r;
944
945 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR);
946 if (r < 0)
947 return r;
948
949 break;
950 case RTM_NEWROUTE:
951 case RTM_DELROUTE:
952 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE);
953 if (r < 0)
954 return r;
955
956 r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE);
957 if (r < 0)
958 return r;
959 break;
960 default:
961 return -EOPNOTSUPP;
962 }
963
964 return 1;
965 }
966
967 return 0;
968 }