]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
65f568bb 2
65f568bb 3#include <poll.h>
65f568bb 4
1c4baffc 5#include "sd-netlink.h"
07630cea 6
b5efdb8a 7#include "alloc-util.h"
3ffd4af2 8#include "fd-util.h"
07630cea 9#include "hashmap.h"
0f2d351f 10#include "io-util.h"
07630cea 11#include "macro.h"
1c4baffc 12#include "netlink-internal.h"
ee38400b 13#include "netlink-slot.h"
1c4baffc 14#include "netlink-util.h"
dccca82b 15#include "process-util.h"
2583fbea 16#include "socket-util.h"
8190a388 17#include "string-util.h"
07630cea 18#include "util.h"
65f568bb 19
b522c4b9
LP
20/* Some really high limit, to catch programming errors */
21#define REPLY_CALLBACKS_MAX UINT16_MAX
22
1c4baffc 23static int sd_netlink_new(sd_netlink **ret) {
4afd3348 24 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
65f568bb
TG
25
26 assert_return(ret, -EINVAL);
27
2fea6090 28 rtnl = new(sd_netlink, 1);
65f568bb
TG
29 if (!rtnl)
30 return -ENOMEM;
31
2fea6090 32 *rtnl = (sd_netlink) {
f23ab4dc 33 .n_ref = 1,
2fea6090
YW
34 .fd = -1,
35 .sockaddr.nl.nl_family = AF_NETLINK,
36 .original_pid = getpid_cached(),
37 .protocol = -1,
adf412b9 38
ac3bc1b8
LP
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,
2fea6090 62 };
8cec01b9 63
a88f77c4
TG
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
1cc6c93a 70 *ret = TAKE_PTR(rtnl);
689703f6 71
65f568bb
TG
72 return 0;
73}
74
1c4baffc 75int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
4afd3348 76 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
a9944163
TG
77 socklen_t addrlen;
78 int r;
79
80 assert_return(ret, -EINVAL);
81
1c4baffc 82 r = sd_netlink_new(&rtnl);
a9944163
TG
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
d6c16624
LP
92 if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
93 return -EINVAL;
94
a9944163
TG
95 rtnl->fd = fd;
96
1cc6c93a 97 *ret = TAKE_PTR(rtnl);
a9944163
TG
98
99 return 0;
100}
101
de157fe2 102static bool rtnl_pid_changed(const sd_netlink *rtnl) {
adf412b9
TG
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
df0ff127 108 return rtnl->original_pid != getpid_cached();
adf412b9
TG
109}
110
1c4baffc 111int sd_netlink_open_fd(sd_netlink **ret, int fd) {
4afd3348 112 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
13ec9f10 113 int r, protocol;
65f568bb 114
9d0db178 115 assert_return(ret, -EINVAL);
8ac43fee 116 assert_return(fd >= 0, -EBADF);
9d0db178 117
1c4baffc 118 r = sd_netlink_new(&rtnl);
65f568bb
TG
119 if (r < 0)
120 return r;
121
13ec9f10 122 r = getsockopt_int(fd, SOL_SOCKET, SO_PROTOCOL, &protocol);
05d0c2e3
JT
123 if (r < 0)
124 return r;
125
b95cc756 126 rtnl->fd = fd;
05d0c2e3 127 rtnl->protocol = protocol;
65f568bb 128
e4a1e68d
YW
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
b95cc756 133 r = socket_bind(rtnl);
5c60db87
LP
134 if (r < 0) {
135 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
05d0c2e3 136 rtnl->protocol = -1;
b95cc756 137 return r;
5c60db87 138 }
6d0b55c2 139
1cc6c93a 140 *ret = TAKE_PTR(rtnl);
65f568bb
TG
141
142 return 0;
143}
144
05d0c2e3 145int netlink_open_family(sd_netlink **ret, int family) {
31710be5 146 _cleanup_close_ int fd = -1;
6d0b55c2
LP
147 int r;
148
05d0c2e3 149 fd = socket_open(family);
6d0b55c2 150 if (fd < 0)
b95cc756 151 return fd;
6d0b55c2 152
1c4baffc 153 r = sd_netlink_open_fd(ret, fd);
31710be5 154 if (r < 0)
6d0b55c2 155 return r;
d52e1c42 156 TAKE_FD(fd);
31710be5
TG
157
158 return 0;
159}
160
05d0c2e3
JT
161int sd_netlink_open(sd_netlink **ret) {
162 return netlink_open_family(ret, NETLINK_ROUTE);
163}
164
75f8a779
LP
165int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
166 assert_return(rtnl, -EINVAL);
167 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
168
be660c37
AR
169 return fd_inc_rcvbuf(rtnl->fd, size);
170}
171
1c71f7f3 172static sd_netlink *netlink_free(sd_netlink *rtnl) {
ee38400b 173 sd_netlink_slot *s;
1c71f7f3 174 unsigned i;
8c578303 175
1c71f7f3 176 assert(rtnl);
4555ec72 177
1c71f7f3
YW
178 for (i = 0; i < rtnl->rqueue_size; i++)
179 sd_netlink_message_unref(rtnl->rqueue[i]);
180 free(rtnl->rqueue);
8cec01b9 181
1c71f7f3
YW
182 for (i = 0; i < rtnl->rqueue_partial_size; i++)
183 sd_netlink_message_unref(rtnl->rqueue_partial[i]);
184 free(rtnl->rqueue_partial);
4e996881 185
1c71f7f3 186 free(rtnl->rbuffer);
a88f77c4 187
ee38400b
YW
188 while ((s = rtnl->slots)) {
189 assert(s->floating);
190 netlink_slot_disconnect(s, true);
545bab1f
YW
191 }
192 hashmap_free(rtnl->reply_callbacks);
1c71f7f3 193 prioq_free(rtnl->reply_callbacks_prioq);
22fdeadc 194
1c71f7f3
YW
195 sd_event_source_unref(rtnl->io_event_source);
196 sd_event_source_unref(rtnl->time_event_source);
197 sd_event_unref(rtnl->event);
22fdeadc 198
1c71f7f3 199 hashmap_free(rtnl->broadcast_group_refs);
9c5a882b 200
4e8f0ef9
YW
201 hashmap_free(rtnl->genl_family_to_nlmsg_type);
202 hashmap_free(rtnl->nlmsg_type_to_genl_family);
203
1c71f7f3
YW
204 safe_close(rtnl->fd);
205 return mfree(rtnl);
65f568bb
TG
206}
207
f23ab4dc 208DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free);
1c71f7f3 209
1c4baffc 210static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) {
b522c4b9
LP
211 uint32_t picked;
212
3dd215e0
TG
213 assert(rtnl);
214 assert(!rtnl_pid_changed(rtnl));
215 assert(m);
216 assert(m->hdr);
217
b522c4b9
LP
218 /* Avoid collisions with outstanding requests */
219 do {
220 picked = rtnl->serial;
3dd215e0 221
b522c4b9
LP
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)));
3dd215e0 227
b522c4b9
LP
228 m->hdr->nlmsg_seq = picked;
229 rtnl_message_seal(m);
3dd215e0
TG
230}
231
1c4baffc 232int sd_netlink_send(sd_netlink *nl,
6b6e0741
YW
233 sd_netlink_message *message,
234 uint32_t *serial) {
4555ec72 235 int r;
65f568bb
TG
236
237 assert_return(nl, -EINVAL);
adf412b9 238 assert_return(!rtnl_pid_changed(nl), -ECHILD);
65f568bb 239 assert_return(message, -EINVAL);
3dd215e0 240 assert_return(!message->sealed, -EPERM);
65f568bb 241
3dd215e0 242 rtnl_seal_message(nl, message);
65f568bb 243
bbe181b4
TG
244 r = socket_write_message(nl, message);
245 if (r < 0)
246 return r;
65f568bb 247
4555ec72 248 if (serial)
3815f36f 249 *serial = rtnl_message_get_serial(message);
65f568bb 250
4555ec72
TG
251 return 1;
252}
65f568bb 253
99c41c0d 254int sd_netlink_sendv(sd_netlink *nl,
2d1ad724 255 sd_netlink_message **messages,
99c41c0d
FW
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);
f6dab748 265 assert_return(msgcount > 0, -EINVAL);
99c41c0d
FW
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
1c4baffc 290int rtnl_rqueue_make_room(sd_netlink *rtnl) {
1b89cf56
TG
291 assert(rtnl);
292
baaa35ad
ZJS
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);
1b89cf56
TG
297
298 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
299 return -ENOMEM;
300
301 return 0;
302}
303
1c4baffc 304int rtnl_rqueue_partial_make_room(sd_netlink *rtnl) {
4e996881
TG
305 assert(rtnl);
306
baaa35ad
ZJS
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);
4e996881
TG
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
1c4baffc 319static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
4555ec72 320 int r;
65f568bb 321
4555ec72
TG
322 assert(rtnl);
323 assert(message);
324
1b89cf56
TG
325 if (rtnl->rqueue_size <= 0) {
326 /* Try to read a new message */
327 r = socket_read_message(rtnl);
71994cff
LP
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 }
1b89cf56
TG
332 if (r <= 0)
333 return r;
4555ec72
TG
334 }
335
1b89cf56
TG
336 /* Dispatch a queued message */
337 *message = rtnl->rqueue[0];
313cefa1 338 rtnl->rqueue_size--;
1c4baffc 339 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
4555ec72
TG
340
341 return 1;
342}
343
1c4baffc 344static int process_timeout(sd_netlink *rtnl) {
4afd3348 345 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
e16bcf98 346 struct reply_callback *c;
ee38400b 347 sd_netlink_slot *slot;
e16bcf98
TG
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
05d0c2e3 361 r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m);
e16bcf98
TG
362 if (r < 0)
363 return r;
364
365 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
ee38400b 366 c->timeout = 0;
b522c4b9 367 hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(c->serial));
e16bcf98 368
ee38400b
YW
369 slot = container_of(c, sd_netlink_slot, reply_callback);
370
371 r = c->callback(rtnl, m, slot->userdata);
233ba5c3 372 if (r < 0)
8190a388
YW
373 log_debug_errno(r, "sd-netlink: timedout callback %s%s%sfailed: %m",
374 slot->description ? "'" : "",
375 strempty(slot->description),
376 slot->description ? "' " : "");
233ba5c3 377
ee38400b
YW
378 if (slot->floating)
379 netlink_slot_disconnect(slot, true);
e16bcf98 380
233ba5c3 381 return 1;
e16bcf98
TG
382}
383
1c4baffc 384static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) {
ee38400b
YW
385 struct reply_callback *c;
386 sd_netlink_slot *slot;
b522c4b9 387 uint32_t serial;
ea342a99 388 uint16_t type;
e16bcf98
TG
389 int r;
390
391 assert(rtnl);
392 assert(m);
393
3815f36f 394 serial = rtnl_message_get_serial(m);
b522c4b9 395 c = hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(serial));
e16bcf98
TG
396 if (!c)
397 return 0;
398
ee38400b 399 if (c->timeout != 0) {
e16bcf98 400 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
ee38400b
YW
401 c->timeout = 0;
402 }
e16bcf98 403
1c4baffc 404 r = sd_netlink_message_get_type(m, &type);
ea342a99 405 if (r < 0)
ee38400b 406 return r;
ea342a99
AR
407
408 if (type == NLMSG_DONE)
409 m = NULL;
410
ee38400b
YW
411 slot = container_of(c, sd_netlink_slot, reply_callback);
412
413 r = c->callback(rtnl, m, slot->userdata);
233ba5c3 414 if (r < 0)
8190a388
YW
415 log_debug_errno(r, "sd-netlink: reply callback %s%s%sfailed: %m",
416 slot->description ? "'" : "",
417 strempty(slot->description),
418 slot->description ? "' " : "");
233ba5c3 419
ee38400b
YW
420 if (slot->floating)
421 netlink_slot_disconnect(slot, true);
545bab1f 422
233ba5c3 423 return 1;
e16bcf98
TG
424}
425
1c4baffc 426static int process_match(sd_netlink *rtnl, sd_netlink_message *m) {
8cec01b9 427 struct match_callback *c;
ee38400b 428 sd_netlink_slot *slot;
8cec01b9
TG
429 uint16_t type;
430 int r;
431
432 assert(rtnl);
433 assert(m);
434
1c4baffc 435 r = sd_netlink_message_get_type(m, &type);
8cec01b9
TG
436 if (r < 0)
437 return r;
438
439 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
baf78f1a
LP
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;
8cec01b9
TG
453 }
454
233ba5c3 455 return 1;
8cec01b9
TG
456}
457
1c4baffc 458static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) {
4afd3348 459 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
4555ec72
TG
460 int r;
461
9d0db178
TG
462 assert(rtnl);
463
e16bcf98
TG
464 r = process_timeout(rtnl);
465 if (r != 0)
466 goto null_message;
467
4555ec72
TG
468 r = dispatch_rqueue(rtnl, &m);
469 if (r < 0)
470 return r;
471 if (!m)
472 goto null_message;
473
1c4baffc 474 if (sd_netlink_message_is_broadcast(m)) {
f436aa11
TG
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 }
8cec01b9 483
4555ec72 484 if (ret) {
1cc6c93a 485 *ret = TAKE_PTR(m);
4555ec72
TG
486
487 return 1;
488 }
489
490 return 1;
491
492null_message:
493 if (r >= 0 && ret)
494 *ret = NULL;
495
496 return r;
497}
e16bcf98 498
1c4baffc 499int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) {
4afd3348 500 NETLINK_DONT_DESTROY(rtnl);
4555ec72
TG
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
514static 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
1c4baffc 524static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
3a43da28 525 usec_t m = USEC_INFINITY;
b4f2a5b1
TG
526 int r, e;
527
528 assert(rtnl);
4555ec72 529
1c4baffc 530 e = sd_netlink_get_events(rtnl);
b4f2a5b1
TG
531 if (e < 0)
532 return e;
4555ec72 533
b4f2a5b1
TG
534 if (need_more)
535 /* Caller wants more data, and doesn't care about
536 * what's been read or any other timeouts. */
f55dc7c9 537 e |= POLLIN;
b4f2a5b1
TG
538 else {
539 usec_t until;
540 /* Caller wants to process if there is something to
541 * process, but doesn't care otherwise */
542
1c4baffc 543 r = sd_netlink_get_timeout(rtnl, &until);
b4f2a5b1
TG
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 }
65f568bb 552
0f2d351f 553 if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m))
b4f2a5b1
TG
554 m = timeout_usec;
555
0f2d351f 556 r = fd_wait_for_event(rtnl->fd, e, m);
8d16f29b 557 if (r <= 0)
0f2d351f 558 return r;
4555ec72 559
dad28bff 560 return 1;
4555ec72
TG
561}
562
1c4baffc 563int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
4555ec72
TG
564 assert_return(nl, -EINVAL);
565 assert_return(!rtnl_pid_changed(nl), -ECHILD);
566
567 if (nl->rqueue_size > 0)
568 return 0;
569
b4f2a5b1 570 return rtnl_poll(nl, false, timeout_usec);
4555ec72
TG
571}
572
e16bcf98
TG
573static 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
9c57a73b 582 return CMP(x->timeout, y->timeout);
e16bcf98
TG
583}
584
545bab1f
YW
585int sd_netlink_call_async(
586 sd_netlink *nl,
ee38400b 587 sd_netlink_slot **ret_slot,
545bab1f
YW
588 sd_netlink_message *m,
589 sd_netlink_message_handler_t callback,
590 sd_netlink_destroy_t destroy_callback,
591 void *userdata,
8190a388
YW
592 uint64_t usec,
593 const char *description) {
ee38400b 594 _cleanup_free_ sd_netlink_slot *slot = NULL;
e16bcf98
TG
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
b522c4b9
LP
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);
e16bcf98
TG
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
5cd67116 615 r = netlink_slot_allocate(nl, !ret_slot, NETLINK_REPLY_CALLBACK, sizeof(struct reply_callback), userdata, description, &slot);
8190a388
YW
616 if (r < 0)
617 return r;
e16bcf98 618
ee38400b
YW
619 slot->reply_callback.callback = callback;
620 slot->reply_callback.timeout = calc_elapse(usec);
e16bcf98 621
b522c4b9 622 k = sd_netlink_send(nl, m, &slot->reply_callback.serial);
545bab1f 623 if (k < 0)
e16bcf98 624 return k;
e16bcf98 625
b522c4b9 626 r = hashmap_put(nl->reply_callbacks, UINT32_TO_PTR(slot->reply_callback.serial), &slot->reply_callback);
545bab1f 627 if (r < 0)
e16bcf98 628 return r;
e16bcf98 629
ee38400b
YW
630 if (slot->reply_callback.timeout != 0) {
631 r = prioq_put(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
f6bdbd9e 632 if (r < 0) {
b522c4b9 633 (void) hashmap_remove(nl->reply_callbacks, UINT32_TO_PTR(slot->reply_callback.serial));
e16bcf98
TG
634 return r;
635 }
636 }
637
5cd67116
YW
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
ee38400b
YW
641 if (ret_slot)
642 *ret_slot = slot;
e16bcf98 643
ee38400b 644 TAKE_PTR(slot);
545bab1f 645
e16bcf98
TG
646 return k;
647}
648
4df42cd9
FW
649int sd_netlink_read(sd_netlink *rtnl,
650 uint32_t serial,
651 uint64_t usec,
652 sd_netlink_message **ret) {
4555ec72 653 usec_t timeout;
4555ec72
TG
654 int r;
655
1b89cf56
TG
656 assert_return(rtnl, -EINVAL);
657 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
4555ec72
TG
658
659 timeout = calc_elapse(usec);
660
65f568bb 661 for (;;) {
4555ec72 662 usec_t left;
ea342a99 663 unsigned i;
65f568bb 664
ea342a99 665 for (i = 0; i < rtnl->rqueue_size; i++) {
1b89cf56 666 uint32_t received_serial;
65f568bb 667
ea342a99 668 received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
65f568bb
TG
669
670 if (received_serial == serial) {
4afd3348 671 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL;
ea342a99
AR
672 uint16_t type;
673
674 incoming = rtnl->rqueue[i];
675
1b89cf56
TG
676 /* found a match, remove from rqueue and return it */
677 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
1c4baffc 678 sizeof(sd_netlink_message*) * (rtnl->rqueue_size - i - 1));
1b89cf56
TG
679 rtnl->rqueue_size--;
680
1c4baffc 681 r = sd_netlink_message_get_errno(incoming);
ea342a99
AR
682 if (r < 0)
683 return r;
684
1c4baffc 685 r = sd_netlink_message_get_type(incoming, &type);
ea342a99 686 if (r < 0)
65f568bb 687 return r;
ea342a99
AR
688
689 if (type == NLMSG_DONE) {
690 *ret = NULL;
691 return 0;
1b89cf56 692 }
65f568bb 693
1cc6c93a
YW
694 if (ret)
695 *ret = TAKE_PTR(incoming);
65f568bb 696
4555ec72 697 return 1;
65f568bb 698 }
65f568bb 699 }
1b89cf56
TG
700
701 r = socket_read_message(rtnl);
702 if (r < 0)
703 return r;
704 if (r > 0)
6ff8806e 705 /* received message, so try to process straight away */
4555ec72 706 continue;
65f568bb 707
4555ec72
TG
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
1b89cf56 719 r = rtnl_poll(rtnl, true, left);
4555ec72
TG
720 if (r < 0)
721 return r;
b551ddd3
TG
722 else if (r == 0)
723 return -ETIMEDOUT;
b4f2a5b1
TG
724 }
725}
726
4df42cd9
FW
727int 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
de157fe2 745int sd_netlink_get_events(const sd_netlink *rtnl) {
b4f2a5b1
TG
746 assert_return(rtnl, -EINVAL);
747 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
748
bbe181b4
TG
749 if (rtnl->rqueue_size == 0)
750 return POLLIN;
751 else
752 return 0;
b4f2a5b1
TG
753}
754
de157fe2 755int sd_netlink_get_timeout(const sd_netlink *rtnl, uint64_t *timeout_usec) {
b4f2a5b1
TG
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
778static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1c4baffc 779 sd_netlink *rtnl = userdata;
b4f2a5b1
TG
780 int r;
781
782 assert(rtnl);
783
1c4baffc 784 r = sd_netlink_process(rtnl, NULL);
b4f2a5b1
TG
785 if (r < 0)
786 return r;
787
788 return 1;
789}
790
791static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
1c4baffc 792 sd_netlink *rtnl = userdata;
b4f2a5b1
TG
793 int r;
794
795 assert(rtnl);
796
1c4baffc 797 r = sd_netlink_process(rtnl, NULL);
b4f2a5b1
TG
798 if (r < 0)
799 return r;
800
801 return 1;
802}
803
804static int prepare_callback(sd_event_source *s, void *userdata) {
1c4baffc 805 sd_netlink *rtnl = userdata;
b4f2a5b1
TG
806 int r, e;
807 usec_t until;
808
809 assert(s);
810 assert(rtnl);
811
1c4baffc 812 e = sd_netlink_get_events(rtnl);
b4f2a5b1
TG
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
1c4baffc 820 r = sd_netlink_get_timeout(rtnl, &until);
b4f2a5b1
TG
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
32d20645 838int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
b4f2a5b1
TG
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
151b9b96 855 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
b4f2a5b1
TG
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
356779df 863 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
9021bb9f
TG
864 if (r < 0)
865 goto fail;
866
b4f2a5b1
TG
867 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
868 if (r < 0)
869 goto fail;
870
6a0f1f6d 871 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
b4f2a5b1
TG
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
356779df 879 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
9021bb9f
TG
880 if (r < 0)
881 goto fail;
882
b4f2a5b1
TG
883 return 0;
884
885fail:
1c4baffc 886 sd_netlink_detach_event(rtnl);
b4f2a5b1
TG
887 return r;
888}
889
1c4baffc 890int sd_netlink_detach_event(sd_netlink *rtnl) {
b4f2a5b1
TG
891 assert_return(rtnl, -EINVAL);
892 assert_return(rtnl->event, -ENXIO);
893
bbe181b4 894 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
b4f2a5b1 895
bbe181b4 896 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
b4f2a5b1 897
bbe181b4 898 rtnl->event = sd_event_unref(rtnl->event);
b4f2a5b1
TG
899
900 return 0;
901}
8cec01b9 902
ee38400b
YW
903int 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,
8190a388
YW
909 void *userdata,
910 const char *description) {
ee38400b 911 _cleanup_free_ sd_netlink_slot *slot = NULL;
31710be5 912 int r;
8cec01b9
TG
913
914 assert_return(rtnl, -EINVAL);
915 assert_return(callback, -EINVAL);
8cec01b9
TG
916 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
917
5cd67116 918 r = netlink_slot_allocate(rtnl, !ret_slot, NETLINK_MATCH_CALLBACK, sizeof(struct match_callback), userdata, description, &slot);
8190a388
YW
919 if (r < 0)
920 return r;
8cec01b9 921
ee38400b
YW
922 slot->match_callback.callback = callback;
923 slot->match_callback.type = type;
8cec01b9 924
31710be5
TG
925 switch (type) {
926 case RTM_NEWLINK:
31710be5 927 case RTM_DELLINK:
9c5a882b 928 r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
31710be5
TG
929 if (r < 0)
930 return r;
931
932 break;
933 case RTM_NEWADDR:
31710be5 934 case RTM_DELADDR:
9c5a882b 935 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
31710be5
TG
936 if (r < 0)
937 return r;
938
9c5a882b 939 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
31710be5
TG
940 if (r < 0)
941 return r;
942
d1bdafd2
WKI
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
31710be5 950 break;
87e4c847
TG
951 case RTM_NEWROUTE:
952 case RTM_DELROUTE:
9c5a882b 953 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
87e4c847
TG
954 if (r < 0)
955 return r;
956
9c5a882b 957 r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
87e4c847
TG
958 if (r < 0)
959 return r;
960 break;
bce67bbe
SS
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;
c16c7808
SS
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
31710be5
TG
978 default:
979 return -EOPNOTSUPP;
980 }
981
ee38400b 982 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, &slot->match_callback);
8cec01b9 983
5cd67116
YW
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
ee38400b
YW
987 if (ret_slot)
988 *ret_slot = slot;
8cec01b9 989
ee38400b 990 TAKE_PTR(slot);
8cec01b9
TG
991
992 return 0;
993}