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