File: | build-scan/../src/libsystemd/sd-netlink/sd-netlink.c |
Warning: | line 900, column 33 Potential leak of memory pointed to by 'c' |
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 && c->type == type && c->userdata == userdata) { | |||
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 | } |