Coverage Report

Created: 2019-06-19 13:33

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