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