File: | build-scan/../src/libsystemd-network/sd-lldp.c |
Warning: | line 380, column 25 Potential leak of memory pointed to by 'lldp' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <arpa/inet.h> | |||
4 | #include <linux1/sockios.h> | |||
5 | ||||
6 | #include "sd-lldp.h" | |||
7 | ||||
8 | #include "alloc-util.h" | |||
9 | #include "fd-util.h" | |||
10 | #include "lldp-internal.h" | |||
11 | #include "lldp-neighbor.h" | |||
12 | #include "lldp-network.h" | |||
13 | #include "socket-util.h" | |||
14 | #include "ether-addr-util.h" | |||
15 | ||||
16 | #define LLDP_DEFAULT_NEIGHBORS_MAX128U 128U | |||
17 | ||||
18 | static void lldp_flush_neighbors(sd_lldp *lldp) { | |||
19 | sd_lldp_neighbor *n; | |||
20 | ||||
21 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 21, __PRETTY_FUNCTION__); } while (0); | |||
22 | ||||
23 | while ((n = hashmap_first(lldp->neighbor_by_id))) | |||
24 | lldp_neighbor_unlink(n); | |||
25 | } | |||
26 | ||||
27 | static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { | |||
28 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 28, __PRETTY_FUNCTION__); } while (0); | |||
29 | ||||
30 | log_lldp("Invoking callback for '%c'.", event)log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-lldp.c", 30, __func__, "LLDP: " "Invoking callback for '%c'.", event); | |||
31 | ||||
32 | if (!lldp->callback) | |||
33 | return; | |||
34 | ||||
35 | lldp->callback(lldp, event, n, lldp->userdata); | |||
36 | } | |||
37 | ||||
38 | static int lldp_make_space(sd_lldp *lldp, size_t extra) { | |||
39 | usec_t t = USEC_INFINITY((usec_t) -1); | |||
40 | bool_Bool changed = false0; | |||
41 | ||||
42 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 42, __PRETTY_FUNCTION__); } while (0); | |||
43 | ||||
44 | /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries | |||
45 | * are free. */ | |||
46 | ||||
47 | for (;;) { | |||
48 | _cleanup_(sd_lldp_neighbor_unrefp)__attribute__((cleanup(sd_lldp_neighbor_unrefp))) sd_lldp_neighbor *n = NULL((void*)0); | |||
49 | ||||
50 | n = prioq_peek(lldp->neighbor_by_expiry); | |||
51 | if (!n) | |||
52 | break; | |||
53 | ||||
54 | sd_lldp_neighbor_ref(n); | |||
55 | ||||
56 | if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)__extension__ ({ const typeof((lldp->neighbors_max)) __unique_prefix_A2 = ((lldp->neighbors_max)); const typeof((extra)) __unique_prefix_B3 = ((extra)); __unique_prefix_A2 > __unique_prefix_B3 ? __unique_prefix_A2 - __unique_prefix_B3 : 0; })) | |||
57 | goto remove_one; | |||
58 | ||||
59 | if (t == USEC_INFINITY((usec_t) -1)) | |||
60 | t = now(clock_boottime_or_monotonic()); | |||
61 | ||||
62 | if (n->until > t) | |||
63 | break; | |||
64 | ||||
65 | remove_one: | |||
66 | lldp_neighbor_unlink(n); | |||
67 | lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); | |||
68 | changed = true1; | |||
69 | } | |||
70 | ||||
71 | return changed; | |||
72 | } | |||
73 | ||||
74 | static bool_Bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { | |||
75 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 75, __PRETTY_FUNCTION__); } while (0); | |||
76 | assert(n)do { if ((__builtin_expect(!!(!(n)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n"), "../src/libsystemd-network/sd-lldp.c" , 76, __PRETTY_FUNCTION__); } while (0); | |||
77 | ||||
78 | /* Don't keep data with a zero TTL */ | |||
79 | if (n->ttl <= 0) | |||
80 | return false0; | |||
81 | ||||
82 | /* Filter out data from the filter address */ | |||
83 | if (!ether_addr_is_null(&lldp->filter_address) && | |||
84 | ether_addr_equal(&lldp->filter_address, &n->source_address)) | |||
85 | return false0; | |||
86 | ||||
87 | /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with | |||
88 | * no caps field set. */ | |||
89 | if (n->has_capabilities && | |||
90 | (n->enabled_capabilities & lldp->capability_mask) == 0) | |||
91 | return false0; | |||
92 | ||||
93 | /* Keep everything else */ | |||
94 | return true1; | |||
95 | } | |||
96 | ||||
97 | static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor); | |||
98 | ||||
99 | static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { | |||
100 | _cleanup_(sd_lldp_neighbor_unrefp)__attribute__((cleanup(sd_lldp_neighbor_unrefp))) sd_lldp_neighbor *old = NULL((void*)0); | |||
101 | bool_Bool keep; | |||
102 | int r; | |||
103 | ||||
104 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 104, __PRETTY_FUNCTION__); } while (0); | |||
105 | assert(n)do { if ((__builtin_expect(!!(!(n)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n"), "../src/libsystemd-network/sd-lldp.c" , 105, __PRETTY_FUNCTION__); } while (0); | |||
106 | assert(!n->lldp)do { if ((__builtin_expect(!!(!(!n->lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!n->lldp"), "../src/libsystemd-network/sd-lldp.c" , 106, __PRETTY_FUNCTION__); } while (0); | |||
107 | ||||
108 | keep = lldp_keep_neighbor(lldp, n); | |||
109 | ||||
110 | /* First retrieve the old entry for this MSAP */ | |||
111 | old = hashmap_get(lldp->neighbor_by_id, &n->id); | |||
112 | if (old) { | |||
113 | sd_lldp_neighbor_ref(old); | |||
114 | ||||
115 | if (!keep) { | |||
116 | lldp_neighbor_unlink(old); | |||
117 | lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); | |||
118 | return 0; | |||
119 | } | |||
120 | ||||
121 | if (lldp_neighbor_equal(n, old)) { | |||
122 | /* Is this equal, then restart the TTL counter, but don't do anyting else. */ | |||
123 | old->timestamp = n->timestamp; | |||
124 | lldp_start_timer(lldp, old); | |||
125 | lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); | |||
126 | return 0; | |||
127 | } | |||
128 | ||||
129 | /* Data changed, remove the old entry, and add a new one */ | |||
130 | lldp_neighbor_unlink(old); | |||
131 | ||||
132 | } else if (!keep) | |||
133 | return 0; | |||
134 | ||||
135 | /* Then, make room for at least one new neighbor */ | |||
136 | lldp_make_space(lldp, 1); | |||
137 | ||||
138 | r = hashmap_put(lldp->neighbor_by_id, &n->id, n); | |||
139 | if (r < 0) | |||
140 | goto finish; | |||
141 | ||||
142 | r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx); | |||
143 | if (r < 0) { | |||
144 | assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n)do { if ((__builtin_expect(!!(!(hashmap_remove(lldp->neighbor_by_id , &n->id) == n)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("hashmap_remove(lldp->neighbor_by_id, &n->id) == n" ), "../src/libsystemd-network/sd-lldp.c", 144, __PRETTY_FUNCTION__ ); } while (0); | |||
145 | goto finish; | |||
146 | } | |||
147 | ||||
148 | n->lldp = lldp; | |||
149 | ||||
150 | lldp_start_timer(lldp, n); | |||
151 | lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); | |||
152 | ||||
153 | return 1; | |||
154 | ||||
155 | finish: | |||
156 | if (old) | |||
157 | lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); | |||
158 | ||||
159 | return r; | |||
160 | } | |||
161 | ||||
162 | static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { | |||
163 | int r; | |||
164 | ||||
165 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 165, __PRETTY_FUNCTION__); } while (0); | |||
166 | assert(n)do { if ((__builtin_expect(!!(!(n)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n"), "../src/libsystemd-network/sd-lldp.c" , 166, __PRETTY_FUNCTION__); } while (0); | |||
167 | ||||
168 | r = lldp_neighbor_parse(n); | |||
169 | if (r == -EBADMSG74) /* Ignore bad messages */ | |||
170 | return 0; | |||
171 | if (r < 0) | |||
172 | return r; | |||
173 | ||||
174 | r = lldp_add_neighbor(lldp, n); | |||
175 | if (r < 0) { | |||
176 | log_lldp_errno(r, "Failed to add datagram. Ignoring.")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/libsystemd-network/sd-lldp.c", 176, __func__, "LLDP: " "Failed to add datagram. Ignoring."); | |||
177 | return 0; | |||
178 | } | |||
179 | ||||
180 | log_lldp("Successfully processed LLDP datagram.")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-lldp.c", 180, __func__, "LLDP: " "Successfully processed LLDP datagram."); | |||
181 | return 0; | |||
182 | } | |||
183 | ||||
184 | static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { | |||
185 | _cleanup_(sd_lldp_neighbor_unrefp)__attribute__((cleanup(sd_lldp_neighbor_unrefp))) sd_lldp_neighbor *n = NULL((void*)0); | |||
186 | ssize_t space, length; | |||
187 | sd_lldp *lldp = userdata; | |||
188 | struct timespec ts; | |||
189 | ||||
190 | assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/libsystemd-network/sd-lldp.c" , 190, __PRETTY_FUNCTION__); } while (0); | |||
191 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 191, __PRETTY_FUNCTION__); } while (0); | |||
192 | ||||
193 | space = next_datagram_size_fd(fd); | |||
194 | if (space < 0) | |||
195 | return log_lldp_errno(space, "Failed to determine datagram size to read: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), space, "../src/libsystemd-network/sd-lldp.c", 195, __func__, "LLDP: " "Failed to determine datagram size to read: %m"); | |||
196 | ||||
197 | n = lldp_neighbor_new(space); | |||
198 | if (!n) | |||
199 | return -ENOMEM12; | |||
200 | ||||
201 | length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAITMSG_DONTWAIT); | |||
202 | if (length < 0) { | |||
203 | if (IN_SET(errno, EAGAIN, EINTR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){11, 4})/sizeof(int)]; switch((*__errno_location ())) { case 11: case 4: _found = 1; break; default: break; } _found; })) | |||
204 | return 0; | |||
205 | ||||
206 | return log_lldp_errno(errno, "Failed to read LLDP datagram: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), (*__errno_location ()), "../src/libsystemd-network/sd-lldp.c" , 206, __func__, "LLDP: " "Failed to read LLDP datagram: %m"); | |||
207 | } | |||
208 | ||||
209 | if ((size_t) length != n->raw_size) { | |||
210 | log_lldp("Packet size mismatch.")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-lldp.c", 210, __func__, "LLDP: " "Packet size mismatch."); | |||
211 | return -EINVAL22; | |||
212 | } | |||
213 | ||||
214 | /* Try to get the timestamp of this packet if it is known */ | |||
215 | if (ioctl(fd, SIOCGSTAMPNS0x8907, &ts) >= 0) | |||
216 | triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts)); | |||
217 | else | |||
218 | triple_timestamp_get(&n->timestamp); | |||
219 | ||||
220 | return lldp_handle_datagram(lldp, n); | |||
221 | } | |||
222 | ||||
223 | static void lldp_reset(sd_lldp *lldp) { | |||
224 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 224, __PRETTY_FUNCTION__); } while (0); | |||
225 | ||||
226 | lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); | |||
227 | lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); | |||
228 | lldp->fd = safe_close(lldp->fd); | |||
229 | } | |||
230 | ||||
231 | _public___attribute__ ((visibility("default"))) int sd_lldp_start(sd_lldp *lldp) { | |||
232 | int r; | |||
233 | ||||
234 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 234, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
235 | assert_return(lldp->event, -EINVAL)do { if (!(((__builtin_expect(!!(lldp->event),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("lldp->event" ), "../src/libsystemd-network/sd-lldp.c", 235, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
236 | assert_return(lldp->ifindex > 0, -EINVAL)do { if (!(((__builtin_expect(!!(lldp->ifindex > 0),1)) ) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ( "lldp->ifindex > 0"), "../src/libsystemd-network/sd-lldp.c" , 236, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
237 | ||||
238 | if (lldp->fd >= 0) | |||
239 | return 0; | |||
240 | ||||
241 | assert(!lldp->io_event_source)do { if ((__builtin_expect(!!(!(!lldp->io_event_source)),0 ))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!lldp->io_event_source" ), "../src/libsystemd-network/sd-lldp.c", 241, __PRETTY_FUNCTION__ ); } while (0); | |||
242 | ||||
243 | lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); | |||
244 | if (lldp->fd < 0) | |||
245 | return lldp->fd; | |||
246 | ||||
247 | r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLINEPOLLIN, lldp_receive_datagram, lldp); | |||
248 | if (r < 0) | |||
249 | goto fail; | |||
250 | ||||
251 | r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); | |||
252 | if (r < 0) | |||
253 | goto fail; | |||
254 | ||||
255 | (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); | |||
256 | ||||
257 | log_lldp("Started LLDP client")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-lldp.c", 257, __func__, "LLDP: " "Started LLDP client"); | |||
258 | return 1; | |||
259 | ||||
260 | fail: | |||
261 | lldp_reset(lldp); | |||
262 | return r; | |||
263 | } | |||
264 | ||||
265 | _public___attribute__ ((visibility("default"))) int sd_lldp_stop(sd_lldp *lldp) { | |||
266 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 266, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
267 | ||||
268 | if (lldp->fd < 0) | |||
269 | return 0; | |||
270 | ||||
271 | log_lldp("Stopping LLDP client")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-lldp.c", 271, __func__, "LLDP: " "Stopping LLDP client"); | |||
272 | ||||
273 | lldp_reset(lldp); | |||
274 | lldp_flush_neighbors(lldp); | |||
275 | ||||
276 | return 1; | |||
277 | } | |||
278 | ||||
279 | _public___attribute__ ((visibility("default"))) int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { | |||
280 | int r; | |||
281 | ||||
282 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 282, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
283 | assert_return(lldp->fd < 0, -EBUSY)do { if (!(((__builtin_expect(!!(lldp->fd < 0),1))) ? ( 1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("lldp->fd < 0" ), "../src/libsystemd-network/sd-lldp.c", 283, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
284 | assert_return(!lldp->event, -EBUSY)do { if (!(((__builtin_expect(!!(!lldp->event),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("!lldp->event" ), "../src/libsystemd-network/sd-lldp.c", 284, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
285 | ||||
286 | if (event) | |||
287 | lldp->event = sd_event_ref(event); | |||
288 | else { | |||
289 | r = sd_event_default(&lldp->event); | |||
290 | if (r < 0) | |||
291 | return r; | |||
292 | } | |||
293 | ||||
294 | lldp->event_priority = priority; | |||
295 | ||||
296 | return 0; | |||
297 | } | |||
298 | ||||
299 | _public___attribute__ ((visibility("default"))) int sd_lldp_detach_event(sd_lldp *lldp) { | |||
300 | ||||
301 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 301, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
302 | assert_return(lldp->fd < 0, -EBUSY)do { if (!(((__builtin_expect(!!(lldp->fd < 0),1))) ? ( 1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("lldp->fd < 0" ), "../src/libsystemd-network/sd-lldp.c", 302, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
303 | ||||
304 | lldp->event = sd_event_unref(lldp->event); | |||
305 | return 0; | |||
306 | } | |||
307 | ||||
308 | _public___attribute__ ((visibility("default"))) sd_event* sd_lldp_get_event(sd_lldp *lldp) { | |||
309 | assert_return(lldp, NULL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 309, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
310 | ||||
311 | return lldp->event; | |||
312 | } | |||
313 | ||||
314 | _public___attribute__ ((visibility("default"))) int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { | |||
315 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 315, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
316 | ||||
317 | lldp->callback = cb; | |||
318 | lldp->userdata = userdata; | |||
319 | ||||
320 | return 0; | |||
321 | } | |||
322 | ||||
323 | _public___attribute__ ((visibility("default"))) int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) { | |||
324 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 324, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
325 | assert_return(ifindex > 0, -EINVAL)do { if (!(((__builtin_expect(!!(ifindex > 0),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("ifindex > 0" ), "../src/libsystemd-network/sd-lldp.c", 325, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
326 | assert_return(lldp->fd < 0, -EBUSY)do { if (!(((__builtin_expect(!!(lldp->fd < 0),1))) ? ( 1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("lldp->fd < 0" ), "../src/libsystemd-network/sd-lldp.c", 326, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
327 | ||||
328 | lldp->ifindex = ifindex; | |||
329 | return 0; | |||
330 | } | |||
331 | ||||
332 | _public___attribute__ ((visibility("default"))) sd_lldp* sd_lldp_ref(sd_lldp *lldp) { | |||
333 | ||||
334 | if (!lldp) | |||
335 | return NULL((void*)0); | |||
336 | ||||
337 | assert(lldp->n_ref > 0)do { if ((__builtin_expect(!!(!(lldp->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp->n_ref > 0"), "../src/libsystemd-network/sd-lldp.c" , 337, __PRETTY_FUNCTION__); } while (0); | |||
338 | lldp->n_ref++; | |||
339 | ||||
340 | return lldp; | |||
341 | } | |||
342 | ||||
343 | _public___attribute__ ((visibility("default"))) sd_lldp* sd_lldp_unref(sd_lldp *lldp) { | |||
344 | ||||
345 | if (!lldp) | |||
346 | return NULL((void*)0); | |||
347 | ||||
348 | assert(lldp->n_ref > 0)do { if ((__builtin_expect(!!(!(lldp->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp->n_ref > 0"), "../src/libsystemd-network/sd-lldp.c" , 348, __PRETTY_FUNCTION__); } while (0); | |||
349 | lldp->n_ref --; | |||
350 | ||||
351 | if (lldp->n_ref > 0) | |||
352 | return NULL((void*)0); | |||
353 | ||||
354 | lldp_reset(lldp); | |||
355 | sd_lldp_detach_event(lldp); | |||
356 | lldp_flush_neighbors(lldp); | |||
357 | ||||
358 | hashmap_free(lldp->neighbor_by_id); | |||
359 | prioq_free(lldp->neighbor_by_expiry); | |||
360 | return mfree(lldp); | |||
361 | } | |||
362 | ||||
363 | _public___attribute__ ((visibility("default"))) int sd_lldp_new(sd_lldp **ret) { | |||
364 | _cleanup_(sd_lldp_unrefp)__attribute__((cleanup(sd_lldp_unrefp))) sd_lldp *lldp = NULL((void*)0); | |||
365 | int r; | |||
366 | ||||
367 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd-network/sd-lldp.c" , 367, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| ||||
368 | ||||
369 | lldp = new0(sd_lldp, 1)((sd_lldp*) calloc((1), sizeof(sd_lldp))); | |||
370 | if (!lldp) | |||
371 | return -ENOMEM12; | |||
372 | ||||
373 | lldp->n_ref = 1; | |||
374 | lldp->fd = -1; | |||
375 | lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX128U; | |||
376 | lldp->capability_mask = (uint16_t) -1; | |||
377 | ||||
378 | lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops)internal_hashmap_new(&lldp_neighbor_id_hash_ops ); | |||
379 | if (!lldp->neighbor_by_id) | |||
380 | return -ENOMEM12; | |||
| ||||
381 | ||||
382 | r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func); | |||
383 | if (r < 0) | |||
384 | return r; | |||
385 | ||||
386 | *ret = TAKE_PTR(lldp)({ typeof(lldp) _ptr_ = (lldp); (lldp) = ((void*)0); _ptr_; } ); | |||
387 | ||||
388 | return 0; | |||
389 | } | |||
390 | ||||
391 | static int neighbor_compare_func(const void *a, const void *b) { | |||
392 | const sd_lldp_neighbor * const*x = a, * const *y = b; | |||
393 | ||||
394 | return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); | |||
395 | } | |||
396 | ||||
397 | static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { | |||
398 | sd_lldp *lldp = userdata; | |||
399 | int r; | |||
400 | ||||
401 | r = lldp_make_space(lldp, 0); | |||
402 | if (r < 0) | |||
403 | return log_lldp_errno(r, "Failed to make space: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/libsystemd-network/sd-lldp.c", 403, __func__, "LLDP: " "Failed to make space: %m"); | |||
404 | ||||
405 | r = lldp_start_timer(lldp, NULL((void*)0)); | |||
406 | if (r < 0) | |||
407 | return log_lldp_errno(r, "Failed to restart timer: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/libsystemd-network/sd-lldp.c", 407, __func__, "LLDP: " "Failed to restart timer: %m"); | |||
408 | ||||
409 | return 0; | |||
410 | } | |||
411 | ||||
412 | static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { | |||
413 | sd_lldp_neighbor *n; | |||
414 | int r; | |||
415 | ||||
416 | assert(lldp)do { if ((__builtin_expect(!!(!(lldp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 416, __PRETTY_FUNCTION__); } while (0); | |||
417 | ||||
418 | if (neighbor) | |||
419 | lldp_neighbor_start_ttl(neighbor); | |||
420 | ||||
421 | n = prioq_peek(lldp->neighbor_by_expiry); | |||
422 | if (!n) { | |||
423 | ||||
424 | if (lldp->timer_event_source) | |||
425 | return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF); | |||
426 | ||||
427 | return 0; | |||
428 | } | |||
429 | ||||
430 | if (lldp->timer_event_source) { | |||
431 | r = sd_event_source_set_time(lldp->timer_event_source, n->until); | |||
432 | if (r < 0) | |||
433 | return r; | |||
434 | ||||
435 | return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT); | |||
436 | } | |||
437 | ||||
438 | if (!lldp->event) | |||
439 | return 0; | |||
440 | ||||
441 | r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp); | |||
442 | if (r < 0) | |||
443 | return r; | |||
444 | ||||
445 | r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority); | |||
446 | if (r < 0) | |||
447 | return r; | |||
448 | ||||
449 | (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer"); | |||
450 | return 0; | |||
451 | } | |||
452 | ||||
453 | _public___attribute__ ((visibility("default"))) int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { | |||
454 | sd_lldp_neighbor **l = NULL((void*)0), *n; | |||
455 | Iterator i; | |||
456 | int k = 0, r; | |||
457 | ||||
458 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 458, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
459 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd-network/sd-lldp.c" , 459, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
460 | ||||
461 | if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */ | |||
462 | *ret = NULL((void*)0); | |||
463 | return 0; | |||
464 | } | |||
465 | ||||
466 | l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id))((sd_lldp_neighbor**) calloc((hashmap_size(lldp->neighbor_by_id )), sizeof(sd_lldp_neighbor*))); | |||
467 | if (!l) | |||
468 | return -ENOMEM12; | |||
469 | ||||
470 | r = lldp_start_timer(lldp, NULL((void*)0)); | |||
471 | if (r < 0) { | |||
472 | free(l); | |||
473 | return r; | |||
474 | } | |||
475 | ||||
476 | HASHMAP_FOREACH(n, lldp->neighbor_by_id, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((lldp->neighbor_by_id ), &(i), (void**)&(n), ((void*)0)); ) | |||
477 | l[k++] = sd_lldp_neighbor_ref(n); | |||
478 | ||||
479 | assert((size_t) k == hashmap_size(lldp->neighbor_by_id))do { if ((__builtin_expect(!!(!((size_t) k == hashmap_size(lldp ->neighbor_by_id))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("(size_t) k == hashmap_size(lldp->neighbor_by_id)"), "../src/libsystemd-network/sd-lldp.c" , 479, __PRETTY_FUNCTION__); } while (0); | |||
480 | ||||
481 | /* Return things in a stable order */ | |||
482 | qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func); | |||
483 | *ret = l; | |||
484 | ||||
485 | return k; | |||
486 | } | |||
487 | ||||
488 | _public___attribute__ ((visibility("default"))) int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) { | |||
489 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 489, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
490 | assert_return(m <= 0, -EINVAL)do { if (!(((__builtin_expect(!!(m <= 0),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("m <= 0"), "../src/libsystemd-network/sd-lldp.c" , 490, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
491 | ||||
492 | lldp->neighbors_max = m; | |||
493 | lldp_make_space(lldp, 0); | |||
494 | ||||
495 | return 0; | |||
496 | } | |||
497 | ||||
498 | _public___attribute__ ((visibility("default"))) int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) { | |||
499 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 499, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
500 | assert_return(mask != 0, -EINVAL)do { if (!(((__builtin_expect(!!(mask != 0),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("mask != 0"), "../src/libsystemd-network/sd-lldp.c" , 500, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
501 | ||||
502 | lldp->capability_mask = mask; | |||
503 | ||||
504 | return 0; | |||
505 | } | |||
506 | ||||
507 | _public___attribute__ ((visibility("default"))) int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) { | |||
508 | assert_return(lldp, -EINVAL)do { if (!(((__builtin_expect(!!(lldp),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("lldp"), "../src/libsystemd-network/sd-lldp.c" , 508, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
509 | ||||
510 | /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so | |||
511 | * that our own can be filtered out here. */ | |||
512 | ||||
513 | if (addr) | |||
514 | lldp->filter_address = *addr; | |||
515 | else | |||
516 | zero(lldp->filter_address)(({ size_t _l_ = (sizeof(lldp->filter_address)); void *_x_ = (&(lldp->filter_address)); _l_ == 0 ? _x_ : memset( _x_, 0, _l_); })); | |||
517 | ||||
518 | return 0; | |||
519 | } |