| 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 | } |