]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-lldp-rx.c
Add systemd-analyze verb to list runtime unit properties (#37665)
[thirdparty/systemd.git] / src / libsystemd-network / sd-lldp-rx.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
ad1ad5c8 2
284d1cd0 3#include <linux/sockios.h>
ef118d00 4#include <sys/ioctl.h>
ad1ad5c8 5
309a747f 6#include "sd-json.h"
3a2ee855 7#include "sd-lldp-rx.h"
07630cea 8
b5efdb8a 9#include "alloc-util.h"
5cdf13c7 10#include "errno-util.h"
4f0e4d29 11#include "ether-addr-util.h"
6ec11d46 12#include "event-util.h"
3ffd4af2 13#include "fd-util.h"
5cdf13c7 14#include "hashmap.h"
34437b4f 15#include "lldp-neighbor.h"
032b27f5 16#include "lldp-network.h"
3a2ee855 17#include "lldp-rx-internal.h"
0a970718 18#include "memory-util.h"
61a9fa8f 19#include "network-common.h"
5cdf13c7 20#include "prioq.h"
34437b4f 21#include "socket-util.h"
760877e9 22#include "sort-util.h"
4f0e4d29 23#include "string-table.h"
5cdf13c7 24#include "string-util.h"
49699bac 25
34437b4f 26#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
032b27f5 27
35778343
YW
28static const char * const lldp_rx_event_table[_SD_LLDP_RX_EVENT_MAX] = {
29 [SD_LLDP_RX_EVENT_ADDED] = "added",
30 [SD_LLDP_RX_EVENT_REMOVED] = "removed",
31 [SD_LLDP_RX_EVENT_UPDATED] = "updated",
32 [SD_LLDP_RX_EVENT_REFRESHED] = "refreshed",
4f0e4d29
YW
33};
34
35778343 35DEFINE_STRING_TABLE_LOOKUP(lldp_rx_event, sd_lldp_rx_event_t);
4f0e4d29 36
35778343
YW
37static void lldp_rx_flush_neighbors(sd_lldp_rx *lldp_rx) {
38 assert(lldp_rx);
ad1ad5c8 39
35778343 40 hashmap_clear(lldp_rx->neighbor_by_id);
ad1ad5c8
SS
41}
42
35778343
YW
43static void lldp_rx_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n) {
44 assert(lldp_rx);
45 assert(event >= 0 && event < _SD_LLDP_RX_EVENT_MAX);
90dffb22 46
35778343
YW
47 if (!lldp_rx->callback)
48 return (void) log_lldp_rx(lldp_rx, "Received '%s' event.", lldp_rx_event_to_string(event));
90dffb22 49
35778343
YW
50 log_lldp_rx(lldp_rx, "Invoking callback for '%s' event.", lldp_rx_event_to_string(event));
51 lldp_rx->callback(lldp_rx, event, n, lldp_rx->userdata);
90dffb22
LP
52}
53
35778343 54static int lldp_rx_make_space(sd_lldp_rx *lldp_rx, size_t extra) {
34437b4f
LP
55 usec_t t = USEC_INFINITY;
56 bool changed = false;
ad1ad5c8 57
35778343 58 assert(lldp_rx);
ad1ad5c8 59
34437b4f
LP
60 /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries
61 * are free. */
ad1ad5c8 62
34437b4f 63 for (;;) {
90dffb22
LP
64 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
65
35778343 66 n = prioq_peek(lldp_rx->neighbor_by_expiry);
34437b4f 67 if (!n)
859c37b1 68 break;
859c37b1 69
90dffb22
LP
70 sd_lldp_neighbor_ref(n);
71
35778343 72 if (hashmap_size(lldp_rx->neighbor_by_id) > LESS_BY(lldp_rx->neighbors_max, extra))
34437b4f 73 goto remove_one;
859c37b1 74
34437b4f 75 if (t == USEC_INFINITY)
ba4e0427 76 t = now(CLOCK_BOOTTIME);
859c37b1 77
34437b4f 78 if (n->until > t)
859c37b1 79 break;
859c37b1 80
34437b4f
LP
81 remove_one:
82 lldp_neighbor_unlink(n);
35778343 83 lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, n);
34437b4f
LP
84 changed = true;
85 }
859c37b1 86
34437b4f
LP
87 return changed;
88}
ad1ad5c8 89
35778343
YW
90static bool lldp_rx_keep_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
91 assert(lldp_rx);
90dffb22
LP
92 assert(n);
93
94 /* Don't keep data with a zero TTL */
95 if (n->ttl <= 0)
96 return false;
97
98 /* Filter out data from the filter address */
35778343
YW
99 if (!ether_addr_is_null(&lldp_rx->filter_address) &&
100 ether_addr_equal(&lldp_rx->filter_address, &n->source_address))
90dffb22
LP
101 return false;
102
103 /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with
104 * no caps field set. */
105 if (n->has_capabilities &&
35778343 106 (n->enabled_capabilities & lldp_rx->capability_mask) == 0)
90dffb22
LP
107 return false;
108
109 /* Keep everything else */
110 return true;
111}
112
35778343 113static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor);
0513ea4e 114
35778343 115static int lldp_rx_add_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
90dffb22
LP
116 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL;
117 bool keep;
34437b4f 118 int r;
ad1ad5c8 119
35778343 120 assert(lldp_rx);
34437b4f 121 assert(n);
35778343 122 assert(!n->lldp_rx);
34437b4f 123
35778343 124 keep = lldp_rx_keep_neighbor(lldp_rx, n);
90dffb22 125
34437b4f 126 /* First retrieve the old entry for this MSAP */
35778343 127 old = hashmap_get(lldp_rx->neighbor_by_id, &n->id);
34437b4f 128 if (old) {
90dffb22
LP
129 sd_lldp_neighbor_ref(old);
130
131 if (!keep) {
132 lldp_neighbor_unlink(old);
35778343 133 lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, old);
90dffb22
LP
134 return 0;
135 }
136
34437b4f 137 if (lldp_neighbor_equal(n, old)) {
f21f31b2 138 /* Is this equal, then restart the TTL counter, but don't do anything else. */
16fed825 139 old->timestamp = n->timestamp;
35778343
YW
140 lldp_rx_start_timer(lldp_rx, old);
141 lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REFRESHED, old);
34437b4f 142 return 0;
ad1ad5c8 143 }
34437b4f
LP
144
145 /* Data changed, remove the old entry, and add a new one */
146 lldp_neighbor_unlink(old);
ad1ad5c8 147
90dffb22
LP
148 } else if (!keep)
149 return 0;
ad1ad5c8 150
34437b4f 151 /* Then, make room for at least one new neighbor */
35778343 152 lldp_rx_make_space(lldp_rx, 1);
ad1ad5c8 153
b0a67b20 154 r = hashmap_ensure_put(&lldp_rx->neighbor_by_id, &lldp_neighbor_hash_ops, &n->id, n);
34437b4f 155 if (r < 0)
90dffb22 156 goto finish;
ad1ad5c8 157
b0a67b20 158 r = prioq_ensure_put(&lldp_rx->neighbor_by_expiry, lldp_neighbor_prioq_compare_func, n, &n->prioq_idx);
34437b4f 159 if (r < 0) {
35778343 160 assert_se(hashmap_remove(lldp_rx->neighbor_by_id, &n->id) == n);
90dffb22 161 goto finish;
ad1ad5c8
SS
162 }
163
35778343 164 n->lldp_rx = lldp_rx;
ad1ad5c8 165
35778343
YW
166 lldp_rx_start_timer(lldp_rx, n);
167 lldp_rx_callback(lldp_rx, old ? SD_LLDP_RX_EVENT_UPDATED : SD_LLDP_RX_EVENT_ADDED, n);
90dffb22
LP
168
169 return 1;
170
171finish:
172 if (old)
35778343 173 lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, old);
90dffb22
LP
174
175 return r;
ad1ad5c8
SS
176}
177
35778343 178static int lldp_rx_handle_datagram(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
34437b4f 179 int r;
ad1ad5c8 180
35778343 181 assert(lldp_rx);
34437b4f 182 assert(n);
ad1ad5c8 183
34437b4f 184 r = lldp_neighbor_parse(n);
34437b4f
LP
185 if (r < 0)
186 return r;
ad1ad5c8 187
35778343 188 r = lldp_rx_add_neighbor(lldp_rx, n);
4be699a8
YW
189 if (r < 0)
190 return log_lldp_rx_errno(lldp_rx, r, "Failed to add datagram. Ignoring.");
ad1ad5c8 191
35778343 192 log_lldp_rx(lldp_rx, "Successfully processed LLDP datagram.");
34437b4f 193 return 0;
ad1ad5c8
SS
194}
195
35778343 196static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
34437b4f
LP
197 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
198 ssize_t space, length;
99534007 199 sd_lldp_rx *lldp_rx = ASSERT_PTR(userdata);
16fed825 200 struct timespec ts;
49699bac 201
34437b4f 202 assert(fd >= 0);
49699bac 203
34437b4f 204 space = next_datagram_size_fd(fd);
1f2db2e3
ZJS
205 if (ERRNO_IS_NEG_TRANSIENT(space) || ERRNO_IS_NEG_DISCONNECT(space))
206 return 0;
35388783 207 if (space < 0) {
35778343 208 log_lldp_rx_errno(lldp_rx, space, "Failed to determine datagram size to read, ignoring: %m");
35388783
YW
209 return 0;
210 }
49699bac 211
34437b4f 212 n = lldp_neighbor_new(space);
4be699a8
YW
213 if (!n) {
214 log_oom_debug();
215 return 0;
216 }
49699bac 217
34437b4f 218 length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
f3315c58 219 if (length < 0) {
ab8a8a4e 220 if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
f3315c58
LP
221 return 0;
222
35778343 223 log_lldp_rx_errno(lldp_rx, errno, "Failed to read LLDP datagram, ignoring: %m");
35388783 224 return 0;
f3315c58 225 }
dacd6cee 226
34437b4f 227 if ((size_t) length != n->raw_size) {
35778343 228 log_lldp_rx(lldp_rx, "Packet size mismatch, ignoring");
35388783 229 return 0;
34437b4f 230 }
49699bac 231
16fed825
LP
232 /* Try to get the timestamp of this packet if it is known */
233 if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0)
234 triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts));
235 else
fa5a0251 236 triple_timestamp_now(&n->timestamp);
16fed825 237
4be699a8
YW
238 (void) lldp_rx_handle_datagram(lldp_rx, n);
239 return 0;
49699bac
SS
240}
241
35778343
YW
242static void lldp_rx_reset(sd_lldp_rx *lldp_rx) {
243 assert(lldp_rx);
fc6a313b 244
35778343
YW
245 (void) event_source_disable(lldp_rx->timer_event_source);
246 lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
247 lldp_rx->fd = safe_close(lldp_rx->fd);
fc6a313b
LP
248}
249
b5dce07a
YW
250int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx) {
251 if (!lldp_rx)
252 return false;
253
254 return lldp_rx->fd >= 0;
255}
256
17347053 257int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
ad1ad5c8
SS
258 int r;
259
35778343
YW
260 assert_return(lldp_rx, -EINVAL);
261 assert_return(lldp_rx->event, -EINVAL);
262 assert_return(lldp_rx->ifindex > 0, -EINVAL);
ad1ad5c8 263
b5dce07a 264 if (sd_lldp_rx_is_running(lldp_rx))
032b27f5 265 return 0;
ad1ad5c8 266
35778343 267 assert(!lldp_rx->io_event_source);
49699bac 268
35778343
YW
269 lldp_rx->fd = lldp_network_bind_raw_socket(lldp_rx->ifindex);
270 if (lldp_rx->fd < 0)
271 return lldp_rx->fd;
032b27f5 272
35778343 273 r = sd_event_add_io(lldp_rx->event, &lldp_rx->io_event_source, lldp_rx->fd, EPOLLIN, lldp_rx_receive_datagram, lldp_rx);
fc6a313b
LP
274 if (r < 0)
275 goto fail;
032b27f5 276
35778343 277 r = sd_event_source_set_priority(lldp_rx->io_event_source, lldp_rx->event_priority);
fc6a313b
LP
278 if (r < 0)
279 goto fail;
032b27f5 280
35778343 281 (void) sd_event_source_set_description(lldp_rx->io_event_source, "lldp-rx-io");
ad1ad5c8 282
35778343 283 log_lldp_rx(lldp_rx, "Started LLDP client");
032b27f5
LP
284 return 1;
285
286fail:
35778343 287 lldp_rx_reset(lldp_rx);
032b27f5 288 return r;
ad1ad5c8
SS
289}
290
17347053 291int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
b5dce07a 292 if (!sd_lldp_rx_is_running(lldp_rx))
032b27f5 293 return 0;
ad1ad5c8 294
35778343 295 log_lldp_rx(lldp_rx, "Stopping LLDP client");
ad1ad5c8 296
35778343
YW
297 lldp_rx_reset(lldp_rx);
298 lldp_rx_flush_neighbors(lldp_rx);
ad1ad5c8 299
032b27f5 300 return 1;
ad1ad5c8
SS
301}
302
17347053 303int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
ad1ad5c8
SS
304 int r;
305
35778343 306 assert_return(lldp_rx, -EINVAL);
b5dce07a 307 assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
35778343 308 assert_return(!lldp_rx->event, -EBUSY);
ad1ad5c8
SS
309
310 if (event)
35778343 311 lldp_rx->event = sd_event_ref(event);
ad1ad5c8 312 else {
35778343 313 r = sd_event_default(&lldp_rx->event);
ad1ad5c8
SS
314 if (r < 0)
315 return r;
316 }
317
35778343 318 lldp_rx->event_priority = priority;
ad1ad5c8
SS
319
320 return 0;
321}
322
17347053 323int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
35778343 324 assert_return(lldp_rx, -EINVAL);
b5dce07a 325 assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
ad1ad5c8 326
aa3f8d4c
YW
327 lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
328 lldp_rx->timer_event_source = sd_event_source_disable_unref(lldp_rx->timer_event_source);
35778343 329 lldp_rx->event = sd_event_unref(lldp_rx->event);
ad1ad5c8
SS
330 return 0;
331}
332
17347053 333sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
35778343 334 assert_return(lldp_rx, NULL);
3db2ec56 335
35778343 336 return lldp_rx->event;
3db2ec56
LP
337}
338
17347053 339int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
35778343 340 assert_return(lldp_rx, -EINVAL);
49699bac 341
35778343
YW
342 lldp_rx->callback = cb;
343 lldp_rx->userdata = userdata;
49699bac
SS
344
345 return 0;
346}
347
17347053 348int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
35778343 349 assert_return(lldp_rx, -EINVAL);
fc6a313b 350 assert_return(ifindex > 0, -EINVAL);
b5dce07a 351 assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
fc6a313b 352
35778343 353 lldp_rx->ifindex = ifindex;
fc6a313b
LP
354 return 0;
355}
356
35778343
YW
357int sd_lldp_rx_set_ifname(sd_lldp_rx *lldp_rx, const char *ifname) {
358 assert_return(lldp_rx, -EINVAL);
61a9fa8f
YW
359 assert_return(ifname, -EINVAL);
360
361 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
362 return -EINVAL;
363
35778343 364 return free_and_strdup(&lldp_rx->ifname, ifname);
61a9fa8f
YW
365}
366
5977b71f
YW
367int sd_lldp_rx_get_ifname(sd_lldp_rx *lldp_rx, const char **ret) {
368 int r;
369
370 assert_return(lldp_rx, -EINVAL);
61a9fa8f 371
5977b71f
YW
372 r = get_ifname(lldp_rx->ifindex, &lldp_rx->ifname);
373 if (r < 0)
374 return r;
375
376 if (ret)
377 *ret = lldp_rx->ifname;
378
379 return 0;
61a9fa8f
YW
380}
381
35778343 382static sd_lldp_rx *lldp_rx_free(sd_lldp_rx *lldp_rx) {
35777f51
YW
383 if (!lldp_rx)
384 return NULL;
fc6a313b 385
35778343 386 lldp_rx_reset(lldp_rx);
eb2f7502 387
35778343 388 sd_lldp_rx_detach_event(lldp_rx);
eb2f7502 389
35778343 390 lldp_rx_flush_neighbors(lldp_rx);
ad1ad5c8 391
35778343
YW
392 hashmap_free(lldp_rx->neighbor_by_id);
393 prioq_free(lldp_rx->neighbor_by_expiry);
394 free(lldp_rx->ifname);
395 return mfree(lldp_rx);
ad1ad5c8
SS
396}
397
35778343 398DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_rx, sd_lldp_rx, lldp_rx_free);
8301aa0b 399
17347053 400int sd_lldp_rx_new(sd_lldp_rx **ret) {
35778343 401 _cleanup_(sd_lldp_rx_unrefp) sd_lldp_rx *lldp_rx = NULL;
ad1ad5c8
SS
402
403 assert_return(ret, -EINVAL);
ad1ad5c8 404
35778343
YW
405 lldp_rx = new(sd_lldp_rx, 1);
406 if (!lldp_rx)
ad1ad5c8
SS
407 return -ENOMEM;
408
35778343 409 *lldp_rx = (sd_lldp_rx) {
8158b90d 410 .n_ref = 1,
254d1313 411 .fd = -EBADF,
8158b90d 412 .neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
f5fbe71d 413 .capability_mask = UINT16_MAX,
8158b90d 414 };
ad1ad5c8 415
35778343 416 *ret = TAKE_PTR(lldp_rx);
ad1ad5c8
SS
417 return 0;
418}
7434883c 419
34437b4f 420static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
35778343 421 sd_lldp_rx *lldp_rx = userdata;
bb1d9534 422 int r;
34437b4f 423
35778343 424 r = lldp_rx_make_space(lldp_rx, 0);
35388783 425 if (r < 0) {
35778343 426 log_lldp_rx_errno(lldp_rx, r, "Failed to make space, ignoring: %m");
35388783
YW
427 return 0;
428 }
34437b4f 429
35778343 430 r = lldp_rx_start_timer(lldp_rx, NULL);
35388783 431 if (r < 0) {
35778343 432 log_lldp_rx_errno(lldp_rx, r, "Failed to restart timer, ignoring: %m");
35388783
YW
433 return 0;
434 }
34437b4f 435
34437b4f
LP
436 return 0;
437}
7434883c 438
35778343 439static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor) {
34437b4f 440 sd_lldp_neighbor *n;
34437b4f 441
35778343 442 assert(lldp_rx);
92466b8d 443 assert(lldp_rx->event);
34437b4f 444
0513ea4e
TH
445 if (neighbor)
446 lldp_neighbor_start_ttl(neighbor);
447
35778343 448 n = prioq_peek(lldp_rx->neighbor_by_expiry);
6ec11d46 449 if (!n)
35778343 450 return event_source_disable(lldp_rx->timer_event_source);
7434883c 451
35778343 452 return event_reset_time(lldp_rx->event, &lldp_rx->timer_event_source,
ba4e0427 453 CLOCK_BOOTTIME,
6ec11d46 454 n->until, 0,
35778343
YW
455 on_timer_event, lldp_rx,
456 lldp_rx->event_priority, "lldp-rx-timer", true);
34437b4f
LP
457}
458
cf1ab844 459static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
90496cc6
YW
460 assert(a);
461 assert(b);
462 assert(*a);
463 assert(*b);
464
465 return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
466}
467
17347053 468int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
0cd7e072
YW
469 _cleanup_free_ sd_lldp_neighbor **l = NULL;
470 sd_lldp_neighbor *n;
3e4a2025 471 int k = 0;
34437b4f 472
35778343 473 assert_return(lldp_rx, -EINVAL);
34437b4f
LP
474 assert_return(ret, -EINVAL);
475
35778343 476 if (hashmap_isempty(lldp_rx->neighbor_by_id)) { /* Special shortcut */
34437b4f 477 *ret = NULL;
7434883c
BG
478 return 0;
479 }
480
35778343 481 l = new0(sd_lldp_neighbor*, hashmap_size(lldp_rx->neighbor_by_id));
34437b4f 482 if (!l)
7434883c
BG
483 return -ENOMEM;
484
35778343 485 HASHMAP_FOREACH(n, lldp_rx->neighbor_by_id)
34437b4f
LP
486 l[k++] = sd_lldp_neighbor_ref(n);
487
35778343 488 assert((size_t) k == hashmap_size(lldp_rx->neighbor_by_id));
34437b4f
LP
489
490 /* Return things in a stable order */
93bab288 491 typesafe_qsort(l, k, neighbor_compare_func);
0cd7e072 492 *ret = TAKE_PTR(l);
34437b4f
LP
493
494 return k;
495}
496
309a747f
LP
497int lldp_rx_build_neighbors_json(sd_lldp_rx *lldp_rx, sd_json_variant **ret) {
498 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
329146a9
TP
499 int r;
500
501 assert(lldp_rx);
502 assert(ret);
503
504 sd_lldp_neighbor *n;
505 HASHMAP_FOREACH(n, lldp_rx->neighbor_by_id) {
309a747f 506 _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
329146a9
TP
507
508 r = lldp_neighbor_build_json(n, &w);
509 if (r < 0)
510 return r;
511
309a747f 512 r = sd_json_variant_append_array(&v, w);
329146a9
TP
513 if (r < 0)
514 return r;
515 }
516
517 *ret = TAKE_PTR(v);
518 return 0;
519}
520
17347053 521int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
35778343 522 assert_return(lldp_rx, -EINVAL);
9141594c 523 assert_return(m > 0, -EINVAL);
34437b4f 524
35778343
YW
525 lldp_rx->neighbors_max = m;
526 lldp_rx_make_space(lldp_rx, 0);
34437b4f
LP
527
528 return 0;
529}
530
17347053 531int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
35778343 532 assert_return(lldp_rx, -EINVAL);
34437b4f
LP
533 assert_return(mask != 0, -EINVAL);
534
35778343 535 lldp_rx->capability_mask = mask;
34437b4f
LP
536
537 return 0;
7434883c 538}
b553a6b1 539
17347053 540int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
35778343 541 assert_return(lldp_rx, -EINVAL);
b553a6b1
LP
542
543 /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
544 * that our own can be filtered out here. */
545
a1fb61b0 546 if (addr)
35778343 547 lldp_rx->filter_address = *addr;
a1fb61b0 548 else
35778343 549 zero(lldp_rx->filter_address);
b553a6b1 550
b553a6b1
LP
551 return 0;
552}