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