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