]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/sd-netlink.c
Merge pull request #18481 from keszybz/rpm-restart-post-trans
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / sd-netlink.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <poll.h>
4
5 #include "sd-netlink.h"
6
7 #include "alloc-util.h"
8 #include "fd-util.h"
9 #include "hashmap.h"
10 #include "io-util.h"
11 #include "macro.h"
12 #include "netlink-internal.h"
13 #include "netlink-slot.h"
14 #include "netlink-util.h"
15 #include "process-util.h"
16 #include "socket-util.h"
17 #include "string-util.h"
18 #include "util.h"
19
20 /* Some really high limit, to catch programming errors */
21 #define REPLY_CALLBACKS_MAX UINT16_MAX
22
23 static int sd_netlink_new(sd_netlink **ret) {
24 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
25
26 assert_return(ret, -EINVAL);
27
28 rtnl = new(sd_netlink, 1);
29 if (!rtnl)
30 return -ENOMEM;
31
32 *rtnl = (sd_netlink) {
33 .n_ref = 1,
34 .fd = -1,
35 .sockaddr.nl.nl_family = AF_NETLINK,
36 .original_pid = getpid_cached(),
37 .protocol = -1,
38
39 /* Kernel change notification messages have sequence number 0. We want to avoid that with our
40 * own serials, in order not to get confused when matching up kernel replies to our earlier
41 * requests.
42 *
43 * Moreover, when using netlink socket activation (i.e. where PID 1 binds an AF_NETLINK
44 * socket for us and passes it to us across execve()) and we get restarted multiple times
45 * while the socket sticks around we might get confused by replies from earlier runs coming
46 * in late — which is pretty likely if we'd start our sequence numbers always from 1. Hence,
47 * let's start with a value based on the system clock. This should make collisions much less
48 * likely (though still theoretically possible). We use a 32 bit µs counter starting at boot
49 * for this (and explicitly exclude the zero, see above). This counter will wrap around after
50 * a bit more than 1h, but that's hopefully OK as the kernel shouldn't take that long to
51 * reply to our requests.
52 *
53 * We only pick the initial start value this way. For each message we simply increase the
54 * sequence number by 1. This means we could enqueue 1 netlink message per µs without risking
55 * collisions, which should be OK.
56 *
57 * Note this means the serials will be in the range 1…UINT32_MAX here.
58 *
59 * (In an ideal world we'd attach the current serial counter to the netlink socket itself
60 * somehow, to avoid all this, but I couldn't come up with a nice way to do this) */
61 .serial = (uint32_t) (now(CLOCK_MONOTONIC) % UINT32_MAX) + 1,
62 };
63
64 /* We guarantee that the read buffer has at least space for
65 * a message header */
66 if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
67 sizeof(struct nlmsghdr), sizeof(uint8_t)))
68 return -ENOMEM;
69
70 *ret = TAKE_PTR(rtnl);
71
72 return 0;
73 }
74
75 int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
76 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
77 socklen_t addrlen;
78 int r;
79
80 assert_return(ret, -EINVAL);
81
82 r = sd_netlink_new(&rtnl);
83 if (r < 0)
84 return r;
85
86 addrlen = sizeof(rtnl->sockaddr);
87
88 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
89 if (r < 0)
90 return -errno;
91
92 if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
93 return -EINVAL;
94
95 rtnl->fd = fd;
96
97 *ret = TAKE_PTR(rtnl);
98
99 return 0;
100 }
101
102 static bool rtnl_pid_changed(const sd_netlink *rtnl) {
103 assert(rtnl);
104
105 /* We don't support people creating an rtnl connection and
106 * keeping it around over a fork(). Let's complain. */
107
108 return rtnl->original_pid != getpid_cached();
109 }
110
111 int sd_netlink_open_fd(sd_netlink **ret, int fd) {
112 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
113 int r, protocol;
114
115 assert_return(ret, -EINVAL);
116 assert_return(fd >= 0, -EBADF);
117
118 r = sd_netlink_new(&rtnl);
119 if (r < 0)
120 return r;
121
122 r = getsockopt_int(fd, SOL_SOCKET, SO_PROTOCOL, &protocol);
123 if (r < 0)
124 return r;
125
126 rtnl->fd = fd;
127 rtnl->protocol = protocol;
128
129 r = setsockopt_int(fd, SOL_NETLINK, NETLINK_EXT_ACK, 1);
130 if (r < 0)
131 log_debug_errno(r, "sd-netlink: Failed to enable NETLINK_EXT_ACK option, ignoring: %m");
132
133 r = socket_bind(rtnl);
134 if (r < 0) {
135 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
136 rtnl->protocol = -1;
137 return r;
138 }
139
140 *ret = TAKE_PTR(rtnl);
141
142 return 0;
143 }
144
145 int netlink_open_family(sd_netlink **ret, int family) {
146 _cleanup_close_ int fd = -1;
147 int r;
148
149 fd = socket_open(family);
150 if (fd < 0)
151 return fd;
152
153 r = sd_netlink_open_fd(ret, fd);
154 if (r < 0)
155 return r;
156 TAKE_FD(fd);
157
158 return 0;
159 }
160
161 int sd_netlink_open(sd_netlink **ret) {
162 return netlink_open_family(ret, NETLINK_ROUTE);
163 }
164
165 int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
166 assert_return(rtnl, -EINVAL);
167 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
168
169 return fd_inc_rcvbuf(rtnl->fd, size);
170 }
171
172 static sd_netlink *netlink_free(sd_netlink *rtnl) {
173 sd_netlink_slot *s;
174 unsigned i;
175
176 assert(rtnl);
177
178 for (i = 0; i < rtnl->rqueue_size; i++)
179 sd_netlink_message_unref(rtnl->rqueue[i]);
180 free(rtnl->rqueue);
181
182 for (i = 0; i < rtnl->rqueue_partial_size; i++)
183 sd_netlink_message_unref(rtnl->rqueue_partial[i]);
184 free(rtnl->rqueue_partial);
185
186 free(rtnl->rbuffer);
187
188 while ((s = rtnl->slots)) {
189 assert(s->floating);
190 netlink_slot_disconnect(s, true);
191 }
192 hashmap_free(rtnl->reply_callbacks);
193 prioq_free(rtnl->reply_callbacks_prioq);
194
195 sd_event_source_unref(rtnl->io_event_source);
196 sd_event_source_unref(rtnl->time_event_source);
197 sd_event_unref(rtnl->event);
198
199 hashmap_free(rtnl->broadcast_group_refs);
200
201 hashmap_free(rtnl->genl_family_to_nlmsg_type);
202 hashmap_free(rtnl->nlmsg_type_to_genl_family);
203
204 safe_close(rtnl->fd);
205 return mfree(rtnl);
206 }
207
208 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free);
209
210 static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) {
211 uint32_t picked;
212
213 assert(rtnl);
214 assert(!rtnl_pid_changed(rtnl));
215 assert(m);
216 assert(m->hdr);
217
218 /* Avoid collisions with outstanding requests */
219 do {
220 picked = rtnl->serial;
221
222 /* Don't use seq == 0, as that is used for broadcasts, so we would get confused by replies to
223 such messages */
224 rtnl->serial = rtnl->serial == UINT32_MAX ? 1 : rtnl->serial + 1;
225
226 } while (hashmap_contains(rtnl->reply_callbacks, UINT32_TO_PTR(picked)));
227
228 m->hdr->nlmsg_seq = picked;
229 rtnl_message_seal(m);
230 }
231
232 int sd_netlink_send(sd_netlink *nl,
233 sd_netlink_message *message,
234 uint32_t *serial) {
235 int r;
236
237 assert_return(nl, -EINVAL);
238 assert_return(!rtnl_pid_changed(nl), -ECHILD);
239 assert_return(message, -EINVAL);
240 assert_return(!message->sealed, -EPERM);
241
242 rtnl_seal_message(nl, message);
243
244 r = socket_write_message(nl, message);
245 if (r < 0)
246 return r;
247
248 if (serial)
249 *serial = rtnl_message_get_serial(message);
250
251 return 1;
252 }
253
254 int sd_netlink_sendv(sd_netlink *nl,
255 sd_netlink_message **messages,
256 size_t msgcount,
257 uint32_t **ret_serial) {
258 _cleanup_free_ uint32_t *serials = NULL;
259 unsigned i;
260 int r;
261
262 assert_return(nl, -EINVAL);
263 assert_return(!rtnl_pid_changed(nl), -ECHILD);
264 assert_return(messages, -EINVAL);
265 assert_return(msgcount > 0, -EINVAL);
266
267 if (ret_serial) {
268 serials = new0(uint32_t, msgcount);
269 if (!serials)
270 return -ENOMEM;
271 }
272
273 for (i = 0; i < msgcount; i++) {
274 assert_return(!messages[i]->sealed, -EPERM);
275 rtnl_seal_message(nl, messages[i]);
276 if (serials)
277 serials[i] = rtnl_message_get_serial(messages[i]);
278 }
279
280 r = socket_writev_message(nl, messages, msgcount);
281 if (r < 0)
282 return r;
283
284 if (ret_serial)
285 *ret_serial = TAKE_PTR(serials);
286
287 return r;
288 }
289
290 int rtnl_rqueue_make_room(sd_netlink *rtnl) {
291 assert(rtnl);
292
293 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX)
294 return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
295 "rtnl: exhausted the read queue size (%d)",
296 RTNL_RQUEUE_MAX);
297
298 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
299 return -ENOMEM;
300
301 return 0;
302 }
303
304 int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) {
305 assert(rtnl);
306
307 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX)
308 return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
309 "rtnl: exhausted the partial read queue size (%d)",
310 RTNL_RQUEUE_MAX);
311
312 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
313 rtnl->rqueue_partial_size + 1))
314 return -ENOMEM;
315
316 return 0;
317 }
318
319 static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
320 int r;
321
322 assert(rtnl);
323 assert(message);
324
325 if (rtnl->rqueue_size <= 0) {
326 /* Try to read a new message */
327 r = socket_read_message(rtnl);
328 if (r == -ENOBUFS) { /* FIXME: ignore buffer overruns for now */
329 log_debug_errno(r, "Got ENOBUFS from netlink socket, ignoring.");
330 return 1;
331 }
332 if (r <= 0)
333 return r;
334 }
335
336 /* Dispatch a queued message */
337 *message = rtnl->rqueue[0];
338 rtnl->rqueue_size--;
339 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
340
341 return 1;
342 }
343
344 static int process_timeout(sd_netlink *rtnl) {
345 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
346 struct reply_callback *c;
347 sd_netlink_slot *slot;
348 usec_t n;
349 int r;
350
351 assert(rtnl);
352
353 c = prioq_peek(rtnl->reply_callbacks_prioq);
354 if (!c)
355 return 0;
356
357 n = now(CLOCK_MONOTONIC);
358 if (c->timeout > n)
359 return 0;
360
361 r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m);
362 if (r < 0)
363 return r;
364
365 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
366 c->timeout = 0;
367 hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(c->serial));
368
369 slot = container_of(c, sd_netlink_slot, reply_callback);
370
371 r = c->callback(rtnl, m, slot->userdata);
372 if (r < 0)
373 log_debug_errno(r, "sd-netlink: timedout callback %s%s%sfailed: %m",
374 slot->description ? "'" : "",
375 strempty(slot->description),
376 slot->description ? "' " : "");
377
378 if (slot->floating)
379 netlink_slot_disconnect(slot, true);
380
381 return 1;
382 }
383
384 static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
385 struct reply_callback *c;
386 sd_netlink_slot *slot;
387 uint32_t serial;
388 uint16_t type;
389 int r;
390
391 assert(rtnl);
392 assert(m);
393
394 serial = rtnl_message_get_serial(m);
395 c = hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(serial));
396 if (!c)
397 return 0;
398
399 if (c->timeout != 0) {
400 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
401 c->timeout = 0;
402 }
403
404 r = sd_netlink_message_get_type(m, &type);
405 if (r < 0)
406 return r;
407
408 if (type == NLMSG_DONE)
409 m = NULL;
410
411 slot = container_of(c, sd_netlink_slot, reply_callback);
412
413 r = c->callback(rtnl, m, slot->userdata);
414 if (r < 0)
415 log_debug_errno(r, "sd-netlink: reply callback %s%s%sfailed: %m",
416 slot->description ? "'" : "",
417 strempty(slot->description),
418 slot->description ? "' " : "");
419
420 if (slot->floating)
421 netlink_slot_disconnect(slot, true);
422
423 return 1;
424 }
425
426 static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
427 struct match_callback *c;
428 sd_netlink_slot *slot;
429 uint16_t type;
430 int r;
431
432 assert(rtnl);
433 assert(m);
434
435 r = sd_netlink_message_get_type(m, &type);
436 if (r < 0)
437 return r;
438
439 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
440 if (type != c->type)
441 continue;
442
443 slot = container_of(c, sd_netlink_slot, match_callback);
444
445 r = c->callback(rtnl, m, slot->userdata);
446 if (r < 0)
447 log_debug_errno(r, "sd-netlink: match callback %s%s%sfailed: %m",
448 slot->description ? "'" : "",
449 strempty(slot->description),
450 slot->description ? "' " : "");
451 if (r != 0)
452 break;
453 }
454
455 return 1;
456 }
457
458 static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
459 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
460 int r;
461
462 assert(rtnl);
463
464 r = process_timeout(rtnl);
465 if (r != 0)
466 goto null_message;
467
468 r = dispatch_rqueue(rtnl, &m);
469 if (r < 0)
470 return r;
471 if (!m)
472 goto null_message;
473
474 if (sd_netlink_message_is_broadcast(m)) {
475 r = process_match(rtnl, m);
476 if (r != 0)
477 goto null_message;
478 } else {
479 r = process_reply(rtnl, m);
480 if (r != 0)
481 goto null_message;
482 }
483
484 if (ret) {
485 *ret = TAKE_PTR(m);
486
487 return 1;
488 }
489
490 return 1;
491
492 null_message:
493 if (r >= 0 && ret)
494 *ret = NULL;
495
496 return r;
497 }
498
499 int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
500 NETLINK_DONT_DESTROY(rtnl);
501 int r;
502
503 assert_return(rtnl, -EINVAL);
504 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
505 assert_return(!rtnl->processing, -EBUSY);
506
507 rtnl->processing = true;
508 r = process_running(rtnl, ret);
509 rtnl->processing = false;
510
511 return r;
512 }
513
514 static usec_t calc_elapse(uint64_t usec) {
515 if (usec == (uint64_t) -1)
516 return 0;
517
518 if (usec == 0)
519 usec = RTNL_DEFAULT_TIMEOUT;
520
521 return now(CLOCK_MONOTONIC) + usec;
522 }
523
524 static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
525 usec_t m = USEC_INFINITY;
526 int r, e;
527
528 assert(rtnl);
529
530 e = sd_netlink_get_events(rtnl);
531 if (e < 0)
532 return e;
533
534 if (need_more)
535 /* Caller wants more data, and doesn't care about
536 * what's been read or any other timeouts. */
537 e |= POLLIN;
538 else {
539 usec_t until;
540 /* Caller wants to process if there is something to
541 * process, but doesn't care otherwise */
542
543 r = sd_netlink_get_timeout(rtnl, &until);
544 if (r < 0)
545 return r;
546 if (r > 0) {
547 usec_t nw;
548 nw = now(CLOCK_MONOTONIC);
549 m = until > nw ? until - nw : 0;
550 }
551 }
552
553 if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m))
554 m = timeout_usec;
555
556 r = fd_wait_for_event(rtnl->fd, e, m);
557 if (r <= 0)
558 return r;
559
560 return 1;
561 }
562
563 int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
564 assert_return(nl, -EINVAL);
565 assert_return(!rtnl_pid_changed(nl), -ECHILD);
566
567 if (nl->rqueue_size > 0)
568 return 0;
569
570 return rtnl_poll(nl, false, timeout_usec);
571 }
572
573 static int timeout_compare(const void *a, const void *b) {
574 const struct reply_callback *x = a, *y = b;
575
576 if (x->timeout != 0 && y->timeout == 0)
577 return -1;
578
579 if (x->timeout == 0 && y->timeout != 0)
580 return 1;
581
582 return CMP(x->timeout, y->timeout);
583 }
584
585 int sd_netlink_call_async(
586 sd_netlink *nl,
587 sd_netlink_slot **ret_slot,
588 sd_netlink_message *m,
589 sd_netlink_message_handler_t callback,
590 sd_netlink_destroy_t destroy_callback,
591 void *userdata,
592 uint64_t usec,
593 const char *description) {
594 _cleanup_free_ sd_netlink_slot *slot = NULL;
595 int r, k;
596
597 assert_return(nl, -EINVAL);
598 assert_return(m, -EINVAL);
599 assert_return(callback, -EINVAL);
600 assert_return(!rtnl_pid_changed(nl), -ECHILD);
601
602 if (hashmap_size(nl->reply_callbacks) >= REPLY_CALLBACKS_MAX)
603 return -ERANGE;
604
605 r = hashmap_ensure_allocated(&nl->reply_callbacks, &trivial_hash_ops);
606 if (r < 0)
607 return r;
608
609 if (usec != (uint64_t) -1) {
610 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
611 if (r < 0)
612 return r;
613 }
614
615 r = netlink_slot_allocate(nl, !ret_slot, NETLINK_REPLY_CALLBACK, sizeof(struct reply_callback), userdata, description, &slot);
616 if (r < 0)
617 return r;
618
619 slot->reply_callback.callback = callback;
620 slot->reply_callback.timeout = calc_elapse(usec);
621
622 k = sd_netlink_send(nl, m, &slot->reply_callback.serial);
623 if (k < 0)
624 return k;
625
626 r = hashmap_put(nl->reply_callbacks, UINT32_TO_PTR(slot->reply_callback.serial), &slot->reply_callback);
627 if (r < 0)
628 return r;
629
630 if (slot->reply_callback.timeout != 0) {
631 r = prioq_put(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
632 if (r < 0) {
633 (void) hashmap_remove(nl->reply_callbacks, UINT32_TO_PTR(slot->reply_callback.serial));
634 return r;
635 }
636 }
637
638 /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */
639 slot->destroy_callback = destroy_callback;
640
641 if (ret_slot)
642 *ret_slot = slot;
643
644 TAKE_PTR(slot);
645
646 return k;
647 }
648
649 int sd_netlink_read(sd_netlink *rtnl,
650 uint32_t serial,
651 uint64_t usec,
652 sd_netlink_message **ret) {
653 usec_t timeout;
654 int r;
655
656 assert_return(rtnl, -EINVAL);
657 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
658
659 timeout = calc_elapse(usec);
660
661 for (;;) {
662 usec_t left;
663 unsigned i;
664
665 for (i = 0; i < rtnl->rqueue_size; i++) {
666 uint32_t received_serial;
667
668 received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
669
670 if (received_serial == serial) {
671 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
672 uint16_t type;
673
674 incoming = rtnl->rqueue[i];
675
676 /* found a match, remove from rqueue and return it */
677 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
678 sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1));
679 rtnl->rqueue_size--;
680
681 r = sd_netlink_message_get_errno(incoming);
682 if (r < 0)
683 return r;
684
685 r = sd_netlink_message_get_type(incoming, &type);
686 if (r < 0)
687 return r;
688
689 if (type == NLMSG_DONE) {
690 *ret = NULL;
691 return 0;
692 }
693
694 if (ret)
695 *ret = TAKE_PTR(incoming);
696
697 return 1;
698 }
699 }
700
701 r = socket_read_message(rtnl);
702 if (r < 0)
703 return r;
704 if (r > 0)
705 /* received message, so try to process straight away */
706 continue;
707
708 if (timeout > 0) {
709 usec_t n;
710
711 n = now(CLOCK_MONOTONIC);
712 if (n >= timeout)
713 return -ETIMEDOUT;
714
715 left = timeout - n;
716 } else
717 left = (uint64_t) -1;
718
719 r = rtnl_poll(rtnl, true, left);
720 if (r < 0)
721 return r;
722 else if (r == 0)
723 return -ETIMEDOUT;
724 }
725 }
726
727 int sd_netlink_call(sd_netlink *rtnl,
728 sd_netlink_message *message,
729 uint64_t usec,
730 sd_netlink_message **ret) {
731 uint32_t serial;
732 int r;
733
734 assert_return(rtnl, -EINVAL);
735 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
736 assert_return(message, -EINVAL);
737
738 r = sd_netlink_send(rtnl, message, &serial);
739 if (r < 0)
740 return r;
741
742 return sd_netlink_read(rtnl, serial, usec, ret);
743 }
744
745 int sd_netlink_get_events(const sd_netlink *rtnl) {
746 assert_return(rtnl, -EINVAL);
747 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
748
749 if (rtnl->rqueue_size == 0)
750 return POLLIN;
751 else
752 return 0;
753 }
754
755 int sd_netlink_get_timeout(const sd_netlink *rtnl, uint64_t *timeout_usec) {
756 struct reply_callback *c;
757
758 assert_return(rtnl, -EINVAL);
759 assert_return(timeout_usec, -EINVAL);
760 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
761
762 if (rtnl->rqueue_size > 0) {
763 *timeout_usec = 0;
764 return 1;
765 }
766
767 c = prioq_peek(rtnl->reply_callbacks_prioq);
768 if (!c) {
769 *timeout_usec = (uint64_t) -1;
770 return 0;
771 }
772
773 *timeout_usec = c->timeout;
774
775 return 1;
776 }
777
778 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
779 sd_netlink *rtnl = userdata;
780 int r;
781
782 assert(rtnl);
783
784 r = sd_netlink_process(rtnl, NULL);
785 if (r < 0)
786 return r;
787
788 return 1;
789 }
790
791 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
792 sd_netlink *rtnl = userdata;
793 int r;
794
795 assert(rtnl);
796
797 r = sd_netlink_process(rtnl, NULL);
798 if (r < 0)
799 return r;
800
801 return 1;
802 }
803
804 static int prepare_callback(sd_event_source *s, void *userdata) {
805 sd_netlink *rtnl = userdata;
806 int r, e;
807 usec_t until;
808
809 assert(s);
810 assert(rtnl);
811
812 e = sd_netlink_get_events(rtnl);
813 if (e < 0)
814 return e;
815
816 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
817 if (r < 0)
818 return r;
819
820 r = sd_netlink_get_timeout(rtnl, &until);
821 if (r < 0)
822 return r;
823 if (r > 0) {
824 int j;
825
826 j = sd_event_source_set_time(rtnl->time_event_source, until);
827 if (j < 0)
828 return j;
829 }
830
831 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
832 if (r < 0)
833 return r;
834
835 return 1;
836 }
837
838 int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
839 int r;
840
841 assert_return(rtnl, -EINVAL);
842 assert_return(!rtnl->event, -EBUSY);
843
844 assert(!rtnl->io_event_source);
845 assert(!rtnl->time_event_source);
846
847 if (event)
848 rtnl->event = sd_event_ref(event);
849 else {
850 r = sd_event_default(&rtnl->event);
851 if (r < 0)
852 return r;
853 }
854
855 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
856 if (r < 0)
857 goto fail;
858
859 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
860 if (r < 0)
861 goto fail;
862
863 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
864 if (r < 0)
865 goto fail;
866
867 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
868 if (r < 0)
869 goto fail;
870
871 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
872 if (r < 0)
873 goto fail;
874
875 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
876 if (r < 0)
877 goto fail;
878
879 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
880 if (r < 0)
881 goto fail;
882
883 return 0;
884
885 fail:
886 sd_netlink_detach_event(rtnl);
887 return r;
888 }
889
890 int sd_netlink_detach_event(sd_netlink *rtnl) {
891 assert_return(rtnl, -EINVAL);
892 assert_return(rtnl->event, -ENXIO);
893
894 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
895
896 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
897
898 rtnl->event = sd_event_unref(rtnl->event);
899
900 return 0;
901 }
902
903 int sd_netlink_add_match(
904 sd_netlink *rtnl,
905 sd_netlink_slot **ret_slot,
906 uint16_t type,
907 sd_netlink_message_handler_t callback,
908 sd_netlink_destroy_t destroy_callback,
909 void *userdata,
910 const char *description) {
911 _cleanup_free_ sd_netlink_slot *slot = NULL;
912 int r;
913
914 assert_return(rtnl, -EINVAL);
915 assert_return(callback, -EINVAL);
916 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
917
918 r = netlink_slot_allocate(rtnl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), userdata, description, &slot);
919 if (r < 0)
920 return r;
921
922 slot->match_callback.callback = callback;
923 slot->match_callback.type = type;
924
925 switch (type) {
926 case RTM_NEWLINK:
927 case RTM_DELLINK:
928 r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
929 if (r < 0)
930 return r;
931
932 break;
933 case RTM_NEWADDR:
934 case RTM_DELADDR:
935 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
936 if (r < 0)
937 return r;
938
939 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
940 if (r < 0)
941 return r;
942
943 break;
944 case RTM_NEWNEIGH:
945 case RTM_DELNEIGH:
946 r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEIGH);
947 if (r < 0)
948 return r;
949
950 break;
951 case RTM_NEWROUTE:
952 case RTM_DELROUTE:
953 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
954 if (r < 0)
955 return r;
956
957 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
958 if (r < 0)
959 return r;
960 break;
961 case RTM_NEWRULE:
962 case RTM_DELRULE:
963 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE);
964 if (r < 0)
965 return r;
966
967 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE);
968 if (r < 0)
969 return r;
970 break;
971 case RTM_NEWNEXTHOP:
972 case RTM_DELNEXTHOP:
973 r = socket_broadcast_group_ref(rtnl, RTNLGRP_NEXTHOP);
974 if (r < 0)
975 return r;
976 break;
977
978 default:
979 return -EOPNOTSUPP;
980 }
981
982 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, &slot->match_callback);
983
984 /* Set this at last. Otherwise, some failures in above call the destroy callback but some do not. */
985 slot->destroy_callback = destroy_callback;
986
987 if (ret_slot)
988 *ret_slot = slot;
989
990 TAKE_PTR(slot);
991
992 return 0;
993 }