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