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