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