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