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