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