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