mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-04-22 04:40:47 +02:00
lldp/systemd: remove systemd LLDP sources
They are no longer used. We use now libnm-llpd instead.
This commit is contained in:
parent
04e72b6b4d
commit
c416c066cf
11 changed files with 0 additions and 1803 deletions
|
|
@ -2421,16 +2421,10 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/lldp-network.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/lldp-network.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/network-common.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/network-common.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h \
|
||||
|
|
@ -2444,8 +2438,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-event.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-id128.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-lldp-rx.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-lldp.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-ndisc.h \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,28 +6,12 @@
|
|||
#include "libnm-systemd-core/nm-default-systemd-core.h"
|
||||
|
||||
#include "libnm-systemd-core/nm-sd.h"
|
||||
#include "libnm-systemd-core/src/systemd/sd-lldp-rx.h"
|
||||
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
|
||||
|
||||
#include "libnm-glib-aux/nm-test-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_lldp_create(void)
|
||||
{
|
||||
sd_lldp_rx *lldp = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_lldp_rx_new(&lldp);
|
||||
g_assert(r == 0);
|
||||
g_assert(lldp);
|
||||
|
||||
sd_lldp_rx_unref(lldp);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
GMainLoop *mainloop;
|
||||
sd_event_source *event_source;
|
||||
|
|
@ -106,7 +90,6 @@ main(int argc, char **argv)
|
|||
{
|
||||
nmtst_init(&argc, &argv, TRUE);
|
||||
|
||||
g_test_add_func("/systemd/lldp/create", test_lldp_create);
|
||||
g_test_add_func("/systemd/sd-event", test_sd_event);
|
||||
|
||||
return g_test_run();
|
||||
|
|
|
|||
|
|
@ -7,12 +7,9 @@ libnm_systemd_core = static_library(
|
|||
'src/libsystemd-network/dhcp6-network.c',
|
||||
'src/libsystemd-network/dhcp6-option.c',
|
||||
'src/libsystemd-network/dhcp6-protocol.c',
|
||||
'src/libsystemd-network/lldp-neighbor.c',
|
||||
'src/libsystemd-network/lldp-network.c',
|
||||
'src/libsystemd-network/network-common.c',
|
||||
'src/libsystemd-network/sd-dhcp6-client.c',
|
||||
'src/libsystemd-network/sd-dhcp6-lease.c',
|
||||
'src/libsystemd-network/sd-lldp-rx.c',
|
||||
'src/libsystemd/sd-event/event-util.c',
|
||||
'src/libsystemd/sd-event/sd-event.c',
|
||||
'src/libsystemd/sd-id128/id128-util.c',
|
||||
|
|
|
|||
|
|
@ -1,798 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "escape.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "lldp-neighbor.h"
|
||||
#include "memory-util.h"
|
||||
#include "missing_network.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
|
||||
assert(id);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(id->chassis_id, id->chassis_id_size, state);
|
||||
siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
|
||||
siphash24_compress(id->port_id, id->port_id_size, state);
|
||||
siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
|
||||
}
|
||||
|
||||
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
|
||||
assert(x);
|
||||
assert(y);
|
||||
|
||||
return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size)
|
||||
?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
lldp_neighbor_hash_ops,
|
||||
LLDPNeighborID,
|
||||
lldp_neighbor_id_hash_func,
|
||||
lldp_neighbor_id_compare_func,
|
||||
sd_lldp_neighbor,
|
||||
lldp_neighbor_unlink);
|
||||
|
||||
int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
|
||||
const sd_lldp_neighbor *x = a, *y = b;
|
||||
|
||||
assert(x);
|
||||
assert(y);
|
||||
|
||||
return CMP(x->until, y->until);
|
||||
}
|
||||
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
assert(n->n_ref > 0 || n->lldp_rx);
|
||||
n->n_ref++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static sd_lldp_neighbor *lldp_neighbor_free(sd_lldp_neighbor *n) {
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
free(n->id.port_id);
|
||||
free(n->id.chassis_id);
|
||||
free(n->port_description);
|
||||
free(n->system_name);
|
||||
free(n->system_description);
|
||||
free(n->mud_url);
|
||||
free(n->chassis_id_as_string);
|
||||
free(n->port_id_as_string);
|
||||
return mfree(n);
|
||||
}
|
||||
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
|
||||
|
||||
/* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
|
||||
* the sd_lldp object. */
|
||||
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
assert(n->n_ref > 0);
|
||||
n->n_ref--;
|
||||
|
||||
if (n->n_ref <= 0 && !n->lldp_rx)
|
||||
lldp_neighbor_free(n);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
|
||||
|
||||
/* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */
|
||||
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
if (!n->lldp_rx)
|
||||
return NULL;
|
||||
|
||||
/* Only remove the neighbor object from the hash table if it's in there, don't complain if it isn't. This is
|
||||
* because we are used as destructor call for hashmap_clear() and thus sometimes are called to de-register
|
||||
* ourselves from the hashtable and sometimes are called after we already are de-registered. */
|
||||
|
||||
(void) hashmap_remove_value(n->lldp_rx->neighbor_by_id, &n->id, n);
|
||||
|
||||
assert_se(prioq_remove(n->lldp_rx->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
|
||||
|
||||
n->lldp_rx = NULL;
|
||||
|
||||
if (n->n_ref <= 0)
|
||||
lldp_neighbor_free(n);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
|
||||
sd_lldp_neighbor *n;
|
||||
|
||||
if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_lldp_neighbor)))
|
||||
return NULL;
|
||||
|
||||
n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
n->raw_size = raw_size;
|
||||
n->n_ref = 1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int parse_string(sd_lldp_rx *lldp_rx, char **s, const void *q, size_t n) {
|
||||
const char *p = q;
|
||||
char *k;
|
||||
|
||||
assert(s);
|
||||
assert(p || n == 0);
|
||||
|
||||
if (*s) {
|
||||
log_lldp_rx(lldp_rx, "Found duplicate string, ignoring field.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Strip trailing NULs, just to be nice */
|
||||
while (n > 0 && p[n-1] == 0)
|
||||
n--;
|
||||
|
||||
if (n <= 0) /* Ignore empty strings */
|
||||
return 0;
|
||||
|
||||
/* Look for inner NULs */
|
||||
if (memchr(p, 0, n)) {
|
||||
log_lldp_rx(lldp_rx, "Found inner NUL in string, ignoring field.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Let's escape weird chars, for security reasons */
|
||||
k = cescape_length(p, n);
|
||||
if (!k)
|
||||
return log_oom_debug();
|
||||
|
||||
free(*s);
|
||||
*s = k;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lldp_neighbor_parse(sd_lldp_neighbor *n) {
|
||||
struct ether_header h;
|
||||
const uint8_t *p;
|
||||
size_t left;
|
||||
int r;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (n->raw_size < sizeof(struct ether_header))
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received truncated packet, ignoring.");
|
||||
|
||||
memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
|
||||
|
||||
if (h.ether_type != htobe16(ETHERTYPE_LLDP))
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received packet with wrong type, ignoring.");
|
||||
|
||||
if (h.ether_dhost[0] != 0x01 ||
|
||||
h.ether_dhost[1] != 0x80 ||
|
||||
h.ether_dhost[2] != 0xc2 ||
|
||||
h.ether_dhost[3] != 0x00 ||
|
||||
h.ether_dhost[4] != 0x00 ||
|
||||
!IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e))
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received packet with wrong destination address, ignoring.");
|
||||
|
||||
memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr));
|
||||
memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr));
|
||||
|
||||
p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header);
|
||||
left = n->raw_size - sizeof(struct ether_header);
|
||||
|
||||
for (;;) {
|
||||
uint8_t type;
|
||||
uint16_t length;
|
||||
|
||||
if (left < 2)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"TLV lacks header, ignoring.");
|
||||
|
||||
type = p[0] >> 1;
|
||||
length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
|
||||
p += 2, left -= 2;
|
||||
|
||||
if (left < length)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"TLV truncated, ignoring datagram.");
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SD_LLDP_TYPE_END:
|
||||
if (length != 0)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"End marker TLV not zero-sized, ignoring datagram.");
|
||||
|
||||
/* Note that after processing the SD_LLDP_TYPE_END left could still be > 0
|
||||
* as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */
|
||||
|
||||
goto end_marker;
|
||||
|
||||
case SD_LLDP_TYPE_CHASSIS_ID:
|
||||
if (length < 2 || length > 256)
|
||||
/* includes the chassis subtype, hence one extra byte */
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Chassis ID field size out of range, ignoring datagram.");
|
||||
|
||||
if (n->id.chassis_id)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Duplicate chassis ID field, ignoring datagram.");
|
||||
|
||||
n->id.chassis_id = memdup(p, length);
|
||||
if (!n->id.chassis_id)
|
||||
return log_oom_debug();
|
||||
|
||||
n->id.chassis_id_size = length;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_PORT_ID:
|
||||
if (length < 2 || length > 256)
|
||||
/* includes the port subtype, hence one extra byte */
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Port ID field size out of range, ignoring datagram.");
|
||||
|
||||
if (n->id.port_id)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Duplicate port ID field, ignoring datagram.");
|
||||
|
||||
n->id.port_id = memdup(p, length);
|
||||
if (!n->id.port_id)
|
||||
return log_oom_debug();
|
||||
|
||||
n->id.port_id_size = length;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_TTL:
|
||||
if (length != 2)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"TTL field has wrong size, ignoring datagram.");
|
||||
|
||||
if (n->has_ttl)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Duplicate TTL field, ignoring datagram.");
|
||||
|
||||
n->ttl = unaligned_read_be16(p);
|
||||
n->has_ttl = true;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_PORT_DESCRIPTION:
|
||||
r = parse_string(n->lldp_rx, &n->port_description, p, length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_SYSTEM_NAME:
|
||||
r = parse_string(n->lldp_rx, &n->system_name, p, length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_SYSTEM_DESCRIPTION:
|
||||
r = parse_string(n->lldp_rx, &n->system_description, p, length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_SYSTEM_CAPABILITIES:
|
||||
if (length != 4)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"System capabilities field has wrong size.");
|
||||
|
||||
n->system_capabilities = unaligned_read_be16(p);
|
||||
n->enabled_capabilities = unaligned_read_be16(p + 2);
|
||||
n->has_capabilities = true;
|
||||
break;
|
||||
|
||||
case SD_LLDP_TYPE_PRIVATE:
|
||||
if (length < 4)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Found private TLV that is too short, ignoring.");
|
||||
|
||||
/* RFC 8520: MUD URL */
|
||||
if (memcmp(p, SD_LLDP_OUI_IANA_MUD, sizeof(SD_LLDP_OUI_IANA_MUD)) == 0) {
|
||||
r = parse_string(n->lldp_rx, &n->mud_url, p + sizeof(SD_LLDP_OUI_IANA_MUD),
|
||||
length - sizeof(SD_LLDP_OUI_IANA_MUD));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
p += length, left -= length;
|
||||
}
|
||||
|
||||
end_marker:
|
||||
if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl)
|
||||
return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"One or more mandatory TLV missing in datagram. Ignoring.");
|
||||
|
||||
n->rindex = sizeof(struct ether_header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
|
||||
assert(n);
|
||||
|
||||
if (n->ttl > 0) {
|
||||
usec_t base;
|
||||
|
||||
/* Use the packet's timestamp if there is one known */
|
||||
base = triple_timestamp_by_clock(&n->timestamp, CLOCK_BOOTTIME);
|
||||
if (!timestamp_is_set(base))
|
||||
base = now(CLOCK_BOOTTIME); /* Otherwise, take the current time */
|
||||
|
||||
n->until = usec_add(base, n->ttl * USEC_PER_SEC);
|
||||
} else
|
||||
n->until = 0;
|
||||
|
||||
if (n->lldp_rx)
|
||||
prioq_reshuffle(n->lldp_rx->neighbor_by_expiry, n, &n->prioq_idx);
|
||||
}
|
||||
|
||||
bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
|
||||
if (a->raw_size != b->raw_size)
|
||||
return false;
|
||||
|
||||
return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
|
||||
*address = n->source_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
|
||||
*address = n->destination_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(size, -EINVAL);
|
||||
|
||||
*ret = LLDP_NEIGHBOR_RAW(n);
|
||||
*size = n->raw_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(size, -EINVAL);
|
||||
|
||||
assert(n->id.chassis_id_size > 0);
|
||||
|
||||
*type = *(uint8_t*) n->id.chassis_id;
|
||||
*ret = (uint8_t*) n->id.chassis_id + 1;
|
||||
*size = n->id.chassis_id_size - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int format_mac_address(const void *data, size_t sz, char **ret) {
|
||||
struct ether_addr a;
|
||||
char *k;
|
||||
|
||||
assert(data || sz <= 0);
|
||||
|
||||
if (sz != 7)
|
||||
return 0;
|
||||
|
||||
memcpy(&a, (uint8_t*) data + 1, sizeof(a));
|
||||
|
||||
k = new(char, ETHER_ADDR_TO_STRING_MAX);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = ether_addr_to_string(&a, k);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int format_network_address(const void *data, size_t sz, char **ret) {
|
||||
union in_addr_union a;
|
||||
int family, r;
|
||||
|
||||
if (sz == 6 && ((uint8_t*) data)[1] == 1) {
|
||||
memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in));
|
||||
family = AF_INET;
|
||||
} else if (sz == 18 && ((uint8_t*) data)[1] == 2) {
|
||||
memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6));
|
||||
family = AF_INET6;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
r = in_addr_to_string(family, &a, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (n->chassis_id_as_string) {
|
||||
*ret = n->chassis_id_as_string;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(n->id.chassis_id_size > 0);
|
||||
|
||||
switch (*(uint8_t*) n->id.chassis_id) {
|
||||
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT:
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED:
|
||||
k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
goto done;
|
||||
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
|
||||
r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
|
||||
case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS:
|
||||
r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Generic fallback */
|
||||
k = hexmem(n->id.chassis_id, n->id.chassis_id_size);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
done:
|
||||
*ret = n->chassis_id_as_string = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(size, -EINVAL);
|
||||
|
||||
assert(n->id.port_id_size > 0);
|
||||
|
||||
*type = *(uint8_t*) n->id.port_id;
|
||||
*ret = (uint8_t*) n->id.port_id + 1;
|
||||
*size = n->id.port_id_size - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (n->port_id_as_string) {
|
||||
*ret = n->port_id_as_string;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(n->id.port_id_size > 0);
|
||||
|
||||
switch (*(uint8_t*) n->id.port_id) {
|
||||
|
||||
case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
|
||||
case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT:
|
||||
case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME:
|
||||
case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
|
||||
k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
goto done;
|
||||
|
||||
case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS:
|
||||
r = format_mac_address(n->id.port_id, n->id.port_id_size, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
|
||||
case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS:
|
||||
r = format_network_address(n->id.port_id, n->id.port_id_size, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Generic fallback */
|
||||
k = hexmem(n->id.port_id, n->id.port_id_size);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
done:
|
||||
*ret = n->port_id_as_string = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret_sec, -EINVAL);
|
||||
|
||||
*ret_sec = n->ttl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->system_name)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->system_name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->system_description)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->system_description;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->port_description)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->port_description;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->mud_url)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->mud_url;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->has_capabilities)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->system_capabilities;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!n->has_capabilities)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = n->enabled_capabilities;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(raw || raw_size <= 0, -EINVAL);
|
||||
|
||||
n = lldp_neighbor_new(raw_size);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_safe(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
|
||||
|
||||
r = lldp_neighbor_parse(n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(n);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
|
||||
assert_return(n, -EINVAL);
|
||||
|
||||
assert(n->raw_size >= sizeof(struct ether_header));
|
||||
n->rindex = sizeof(struct ether_header);
|
||||
|
||||
return n->rindex < n->raw_size;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
|
||||
size_t length;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
|
||||
if (n->rindex == n->raw_size) /* EOF */
|
||||
return -ESPIPE;
|
||||
|
||||
if (n->rindex + 2 > n->raw_size) /* Truncated message */
|
||||
return -EBADMSG;
|
||||
|
||||
length = LLDP_NEIGHBOR_TLV_LENGTH(n);
|
||||
if (n->rindex + 2 + length > n->raw_size)
|
||||
return -EBADMSG;
|
||||
|
||||
n->rindex += 2 + length;
|
||||
return n->rindex < n->raw_size;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
|
||||
if (n->rindex == n->raw_size) /* EOF */
|
||||
return -ESPIPE;
|
||||
|
||||
if (n->rindex + 2 > n->raw_size)
|
||||
return -EBADMSG;
|
||||
|
||||
*type = LLDP_NEIGHBOR_TLV_TYPE(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
|
||||
uint8_t k;
|
||||
int r;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
|
||||
r = sd_lldp_neighbor_tlv_get_type(n, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return type == k;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
|
||||
const uint8_t *d;
|
||||
size_t length;
|
||||
int r;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(oui, -EINVAL);
|
||||
assert_return(subtype, -EINVAL);
|
||||
|
||||
r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -ENXIO;
|
||||
|
||||
length = LLDP_NEIGHBOR_TLV_LENGTH(n);
|
||||
if (length < 4)
|
||||
return -EBADMSG;
|
||||
|
||||
if (n->rindex + 2 + length > n->raw_size)
|
||||
return -EBADMSG;
|
||||
|
||||
d = LLDP_NEIGHBOR_TLV_DATA(n);
|
||||
memcpy(oui, d, 3);
|
||||
*subtype = d[3];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
|
||||
uint8_t k[3], st;
|
||||
int r;
|
||||
|
||||
r = sd_lldp_neighbor_tlv_get_oui(n, k, &st);
|
||||
if (r == -ENXIO)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return memcmp(k, oui, 3) == 0 && st == subtype;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
size_t length;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(size, -EINVAL);
|
||||
|
||||
/* Note that this returns the full TLV, including the TLV header */
|
||||
|
||||
if (n->rindex + 2 > n->raw_size)
|
||||
return -EBADMSG;
|
||||
|
||||
length = LLDP_NEIGHBOR_TLV_LENGTH(n);
|
||||
if (n->rindex + 2 + length > n->raw_size)
|
||||
return -EBADMSG;
|
||||
|
||||
*ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
|
||||
*size = length + 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
|
||||
assert_return(clock_supported(clock), -EOPNOTSUPP);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!triple_timestamp_is_set(&n->timestamp))
|
||||
return -ENODATA;
|
||||
|
||||
*ret = triple_timestamp_by_clock(&n->timestamp, clock);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-lldp-rx.h"
|
||||
|
||||
#include "hash-funcs.h"
|
||||
#include "lldp-rx-internal.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct LLDPNeighborID {
|
||||
/* The spec calls this an "MSAP identifier" */
|
||||
void *chassis_id;
|
||||
size_t chassis_id_size;
|
||||
|
||||
void *port_id;
|
||||
size_t port_id_size;
|
||||
} LLDPNeighborID;
|
||||
|
||||
struct sd_lldp_neighbor {
|
||||
/* Neighbor objects stay around as long as they are linked into an "sd_lldp_rx" object or n_ref > 0. */
|
||||
sd_lldp_rx *lldp_rx;
|
||||
unsigned n_ref;
|
||||
|
||||
triple_timestamp timestamp;
|
||||
|
||||
usec_t until;
|
||||
unsigned prioq_idx;
|
||||
|
||||
struct ether_addr source_address;
|
||||
struct ether_addr destination_address;
|
||||
|
||||
LLDPNeighborID id;
|
||||
|
||||
/* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */
|
||||
size_t raw_size;
|
||||
|
||||
/* The current read index for the iterative TLV interface */
|
||||
size_t rindex;
|
||||
|
||||
/* And a couple of fields parsed out. */
|
||||
bool has_ttl:1;
|
||||
bool has_capabilities:1;
|
||||
bool has_port_vlan_id:1;
|
||||
|
||||
uint16_t ttl;
|
||||
|
||||
uint16_t system_capabilities;
|
||||
uint16_t enabled_capabilities;
|
||||
|
||||
char *port_description;
|
||||
char *system_name;
|
||||
char *system_description;
|
||||
char *mud_url;
|
||||
|
||||
uint16_t port_vlan_id;
|
||||
|
||||
char *chassis_id_as_string;
|
||||
char *port_id_as_string;
|
||||
};
|
||||
|
||||
static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) {
|
||||
return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor));
|
||||
}
|
||||
|
||||
static inline uint8_t LLDP_NEIGHBOR_TLV_TYPE(const sd_lldp_neighbor *n) {
|
||||
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1;
|
||||
}
|
||||
|
||||
static inline size_t LLDP_NEIGHBOR_TLV_LENGTH(const sd_lldp_neighbor *n) {
|
||||
uint8_t *p;
|
||||
|
||||
p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
|
||||
return p[1] + (((size_t) (p[0] & 1)) << 8);
|
||||
}
|
||||
|
||||
static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
|
||||
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
|
||||
}
|
||||
|
||||
extern const struct hash_ops lldp_neighbor_hash_ops;
|
||||
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
|
||||
int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
|
||||
|
||||
sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
|
||||
sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size);
|
||||
int lldp_neighbor_parse(sd_lldp_neighbor *n);
|
||||
void lldp_neighbor_start_ttl(sd_lldp_neighbor *n);
|
||||
bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b);
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <linux/filter.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "lldp-network.h"
|
||||
#include "missing_network.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
int lldp_network_bind_raw_socket(int ifindex) {
|
||||
static const struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept packet */
|
||||
};
|
||||
static const struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = (struct sock_filter*) filter,
|
||||
};
|
||||
struct packet_mreq mreq = {
|
||||
.mr_ifindex = ifindex,
|
||||
.mr_type = PACKET_MR_MULTICAST,
|
||||
.mr_alen = ETH_ALEN,
|
||||
.mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
union sockaddr_union saddrll = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_ifindex = ifindex,
|
||||
};
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(ifindex > 0);
|
||||
|
||||
fd = socket(AF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK,
|
||||
htobe16(ETHERTYPE_LLDP));
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
|
||||
return -errno;
|
||||
|
||||
/* customer bridge */
|
||||
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
return -errno;
|
||||
|
||||
/* non TPMR bridge */
|
||||
mreq.mr_address[ETH_ALEN - 1] = 0x03;
|
||||
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
return -errno;
|
||||
|
||||
/* nearest bridge */
|
||||
mreq.mr_address[ETH_ALEN - 1] = 0x0E;
|
||||
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
return -errno;
|
||||
|
||||
if (bind(fd, &saddrll.sa, sizeof(saddrll.ll)) < 0)
|
||||
return -errno;
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
int lldp_network_bind_raw_socket(int ifindex);
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "sd-lldp-rx.h"
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "network-common.h"
|
||||
#include "prioq.h"
|
||||
|
||||
struct sd_lldp_rx {
|
||||
unsigned n_ref;
|
||||
|
||||
int ifindex;
|
||||
char *ifname;
|
||||
int fd;
|
||||
|
||||
sd_event *event;
|
||||
int64_t event_priority;
|
||||
sd_event_source *io_event_source;
|
||||
sd_event_source *timer_event_source;
|
||||
|
||||
Prioq *neighbor_by_expiry;
|
||||
Hashmap *neighbor_by_id;
|
||||
|
||||
uint64_t neighbors_max;
|
||||
|
||||
sd_lldp_rx_callback_t callback;
|
||||
void *userdata;
|
||||
|
||||
uint16_t capability_mask;
|
||||
|
||||
struct ether_addr filter_address;
|
||||
};
|
||||
|
||||
const char* lldp_rx_event_to_string(sd_lldp_rx_event_t e) _const_;
|
||||
sd_lldp_rx_event_t lldp_rx_event_from_string(const char *s) _pure_;
|
||||
|
||||
#define log_lldp_rx_errno(lldp_rx, error, fmt, ...) \
|
||||
log_interface_prefix_full_errno( \
|
||||
"LLDP Rx: ", \
|
||||
sd_lldp_rx, lldp_rx, \
|
||||
error, fmt, ##__VA_ARGS__)
|
||||
#define log_lldp_rx(lldp_rx, fmt, ...) \
|
||||
log_interface_prefix_full_errno_zerook( \
|
||||
"LLDP Rx: ", \
|
||||
sd_lldp_rx, lldp_rx, \
|
||||
0, fmt, ##__VA_ARGS__)
|
||||
|
|
@ -1,527 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "sd-lldp-rx.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "lldp-neighbor.h"
|
||||
#include "lldp-network.h"
|
||||
#include "lldp-rx-internal.h"
|
||||
#include "memory-util.h"
|
||||
#include "network-common.h"
|
||||
#include "socket-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-table.h"
|
||||
|
||||
#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
|
||||
|
||||
static const char * const lldp_rx_event_table[_SD_LLDP_RX_EVENT_MAX] = {
|
||||
[SD_LLDP_RX_EVENT_ADDED] = "added",
|
||||
[SD_LLDP_RX_EVENT_REMOVED] = "removed",
|
||||
[SD_LLDP_RX_EVENT_UPDATED] = "updated",
|
||||
[SD_LLDP_RX_EVENT_REFRESHED] = "refreshed",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(lldp_rx_event, sd_lldp_rx_event_t);
|
||||
|
||||
static void lldp_rx_flush_neighbors(sd_lldp_rx *lldp_rx) {
|
||||
assert(lldp_rx);
|
||||
|
||||
hashmap_clear(lldp_rx->neighbor_by_id);
|
||||
}
|
||||
|
||||
static void lldp_rx_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n) {
|
||||
assert(lldp_rx);
|
||||
assert(event >= 0 && event < _SD_LLDP_RX_EVENT_MAX);
|
||||
|
||||
if (!lldp_rx->callback)
|
||||
return (void) log_lldp_rx(lldp_rx, "Received '%s' event.", lldp_rx_event_to_string(event));
|
||||
|
||||
log_lldp_rx(lldp_rx, "Invoking callback for '%s' event.", lldp_rx_event_to_string(event));
|
||||
lldp_rx->callback(lldp_rx, event, n, lldp_rx->userdata);
|
||||
}
|
||||
|
||||
static int lldp_rx_make_space(sd_lldp_rx *lldp_rx, size_t extra) {
|
||||
usec_t t = USEC_INFINITY;
|
||||
bool changed = false;
|
||||
|
||||
assert(lldp_rx);
|
||||
|
||||
/* Remove all entries that are past their TTL, and more until at least the specified number of extra entries
|
||||
* are free. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||
|
||||
n = prioq_peek(lldp_rx->neighbor_by_expiry);
|
||||
if (!n)
|
||||
break;
|
||||
|
||||
sd_lldp_neighbor_ref(n);
|
||||
|
||||
if (hashmap_size(lldp_rx->neighbor_by_id) > LESS_BY(lldp_rx->neighbors_max, extra))
|
||||
goto remove_one;
|
||||
|
||||
if (t == USEC_INFINITY)
|
||||
t = now(CLOCK_BOOTTIME);
|
||||
|
||||
if (n->until > t)
|
||||
break;
|
||||
|
||||
remove_one:
|
||||
lldp_neighbor_unlink(n);
|
||||
lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, n);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool lldp_rx_keep_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
|
||||
assert(lldp_rx);
|
||||
assert(n);
|
||||
|
||||
/* Don't keep data with a zero TTL */
|
||||
if (n->ttl <= 0)
|
||||
return false;
|
||||
|
||||
/* Filter out data from the filter address */
|
||||
if (!ether_addr_is_null(&lldp_rx->filter_address) &&
|
||||
ether_addr_equal(&lldp_rx->filter_address, &n->source_address))
|
||||
return false;
|
||||
|
||||
/* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with
|
||||
* no caps field set. */
|
||||
if (n->has_capabilities &&
|
||||
(n->enabled_capabilities & lldp_rx->capability_mask) == 0)
|
||||
return false;
|
||||
|
||||
/* Keep everything else */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor);
|
||||
|
||||
static int lldp_rx_add_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL;
|
||||
bool keep;
|
||||
int r;
|
||||
|
||||
assert(lldp_rx);
|
||||
assert(n);
|
||||
assert(!n->lldp_rx);
|
||||
|
||||
keep = lldp_rx_keep_neighbor(lldp_rx, n);
|
||||
|
||||
/* First retrieve the old entry for this MSAP */
|
||||
old = hashmap_get(lldp_rx->neighbor_by_id, &n->id);
|
||||
if (old) {
|
||||
sd_lldp_neighbor_ref(old);
|
||||
|
||||
if (!keep) {
|
||||
lldp_neighbor_unlink(old);
|
||||
lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lldp_neighbor_equal(n, old)) {
|
||||
/* Is this equal, then restart the TTL counter, but don't do anything else. */
|
||||
old->timestamp = n->timestamp;
|
||||
lldp_rx_start_timer(lldp_rx, old);
|
||||
lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REFRESHED, old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Data changed, remove the old entry, and add a new one */
|
||||
lldp_neighbor_unlink(old);
|
||||
|
||||
} else if (!keep)
|
||||
return 0;
|
||||
|
||||
/* Then, make room for at least one new neighbor */
|
||||
lldp_rx_make_space(lldp_rx, 1);
|
||||
|
||||
r = hashmap_ensure_put(&lldp_rx->neighbor_by_id, &lldp_neighbor_hash_ops, &n->id, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = prioq_ensure_put(&lldp_rx->neighbor_by_expiry, lldp_neighbor_prioq_compare_func, n, &n->prioq_idx);
|
||||
if (r < 0) {
|
||||
assert_se(hashmap_remove(lldp_rx->neighbor_by_id, &n->id) == n);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n->lldp_rx = lldp_rx;
|
||||
|
||||
lldp_rx_start_timer(lldp_rx, n);
|
||||
lldp_rx_callback(lldp_rx, old ? SD_LLDP_RX_EVENT_UPDATED : SD_LLDP_RX_EVENT_ADDED, n);
|
||||
|
||||
return 1;
|
||||
|
||||
finish:
|
||||
if (old)
|
||||
lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, old);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int lldp_rx_handle_datagram(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
|
||||
int r;
|
||||
|
||||
assert(lldp_rx);
|
||||
assert(n);
|
||||
|
||||
r = lldp_neighbor_parse(n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = lldp_rx_add_neighbor(lldp_rx, n);
|
||||
if (r < 0)
|
||||
return log_lldp_rx_errno(lldp_rx, r, "Failed to add datagram. Ignoring.");
|
||||
|
||||
log_lldp_rx(lldp_rx, "Successfully processed LLDP datagram.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||
ssize_t space, length;
|
||||
sd_lldp_rx *lldp_rx = ASSERT_PTR(userdata);
|
||||
struct timespec ts;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
space = next_datagram_size_fd(fd);
|
||||
if (space < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(space) || ERRNO_IS_DISCONNECT(space))
|
||||
return 0;
|
||||
|
||||
log_lldp_rx_errno(lldp_rx, space, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = lldp_neighbor_new(space);
|
||||
if (!n) {
|
||||
log_oom_debug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
|
||||
if (length < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
|
||||
return 0;
|
||||
|
||||
log_lldp_rx_errno(lldp_rx, errno, "Failed to read LLDP datagram, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((size_t) length != n->raw_size) {
|
||||
log_lldp_rx(lldp_rx, "Packet size mismatch, ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to get the timestamp of this packet if it is known */
|
||||
if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0)
|
||||
triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts));
|
||||
else
|
||||
triple_timestamp_get(&n->timestamp);
|
||||
|
||||
(void) lldp_rx_handle_datagram(lldp_rx, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lldp_rx_reset(sd_lldp_rx *lldp_rx) {
|
||||
assert(lldp_rx);
|
||||
|
||||
(void) event_source_disable(lldp_rx->timer_event_source);
|
||||
lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
|
||||
lldp_rx->fd = safe_close(lldp_rx->fd);
|
||||
}
|
||||
|
||||
int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx) {
|
||||
if (!lldp_rx)
|
||||
return false;
|
||||
|
||||
return lldp_rx->fd >= 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(lldp_rx->event, -EINVAL);
|
||||
assert_return(lldp_rx->ifindex > 0, -EINVAL);
|
||||
|
||||
if (sd_lldp_rx_is_running(lldp_rx))
|
||||
return 0;
|
||||
|
||||
assert(!lldp_rx->io_event_source);
|
||||
|
||||
lldp_rx->fd = lldp_network_bind_raw_socket(lldp_rx->ifindex);
|
||||
if (lldp_rx->fd < 0)
|
||||
return lldp_rx->fd;
|
||||
|
||||
r = sd_event_add_io(lldp_rx->event, &lldp_rx->io_event_source, lldp_rx->fd, EPOLLIN, lldp_rx_receive_datagram, lldp_rx);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_event_source_set_priority(lldp_rx->io_event_source, lldp_rx->event_priority);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
(void) sd_event_source_set_description(lldp_rx->io_event_source, "lldp-rx-io");
|
||||
|
||||
log_lldp_rx(lldp_rx, "Started LLDP client");
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
lldp_rx_reset(lldp_rx);
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
|
||||
if (!sd_lldp_rx_is_running(lldp_rx))
|
||||
return 0;
|
||||
|
||||
log_lldp_rx(lldp_rx, "Stopping LLDP client");
|
||||
|
||||
lldp_rx_reset(lldp_rx);
|
||||
lldp_rx_flush_neighbors(lldp_rx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
assert_return(!lldp_rx->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
lldp_rx->event = sd_event_ref(event);
|
||||
else {
|
||||
r = sd_event_default(&lldp_rx->event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
lldp_rx->event_priority = priority;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
|
||||
lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
|
||||
lldp_rx->timer_event_source = sd_event_source_disable_unref(lldp_rx->timer_event_source);
|
||||
lldp_rx->event = sd_event_unref(lldp_rx->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
|
||||
assert_return(lldp_rx, NULL);
|
||||
|
||||
return lldp_rx->event;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
||||
lldp_rx->callback = cb;
|
||||
lldp_rx->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
|
||||
lldp_rx->ifindex = ifindex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_set_ifname(sd_lldp_rx *lldp_rx, const char *ifname) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(ifname, -EINVAL);
|
||||
|
||||
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
|
||||
return -EINVAL;
|
||||
|
||||
return free_and_strdup(&lldp_rx->ifname, ifname);
|
||||
}
|
||||
|
||||
int sd_lldp_rx_get_ifname(sd_lldp_rx *lldp_rx, const char **ret) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
||||
r = get_ifname(lldp_rx->ifindex, &lldp_rx->ifname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = lldp_rx->ifname;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sd_lldp_rx *lldp_rx_free(sd_lldp_rx *lldp_rx) {
|
||||
if (!lldp_rx)
|
||||
return NULL;
|
||||
|
||||
lldp_rx_reset(lldp_rx);
|
||||
|
||||
sd_lldp_rx_detach_event(lldp_rx);
|
||||
|
||||
lldp_rx_flush_neighbors(lldp_rx);
|
||||
|
||||
hashmap_free(lldp_rx->neighbor_by_id);
|
||||
prioq_free(lldp_rx->neighbor_by_expiry);
|
||||
free(lldp_rx->ifname);
|
||||
return mfree(lldp_rx);
|
||||
}
|
||||
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_rx, sd_lldp_rx, lldp_rx_free);
|
||||
|
||||
int sd_lldp_rx_new(sd_lldp_rx **ret) {
|
||||
_cleanup_(sd_lldp_rx_unrefp) sd_lldp_rx *lldp_rx = NULL;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
lldp_rx = new(sd_lldp_rx, 1);
|
||||
if (!lldp_rx)
|
||||
return -ENOMEM;
|
||||
|
||||
*lldp_rx = (sd_lldp_rx) {
|
||||
.n_ref = 1,
|
||||
.fd = -1,
|
||||
.neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
|
||||
.capability_mask = UINT16_MAX,
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(lldp_rx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_lldp_rx *lldp_rx = userdata;
|
||||
int r;
|
||||
|
||||
r = lldp_rx_make_space(lldp_rx, 0);
|
||||
if (r < 0) {
|
||||
log_lldp_rx_errno(lldp_rx, r, "Failed to make space, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = lldp_rx_start_timer(lldp_rx, NULL);
|
||||
if (r < 0) {
|
||||
log_lldp_rx_errno(lldp_rx, r, "Failed to restart timer, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor) {
|
||||
sd_lldp_neighbor *n;
|
||||
|
||||
assert(lldp_rx);
|
||||
assert(lldp_rx->event);
|
||||
|
||||
if (neighbor)
|
||||
lldp_neighbor_start_ttl(neighbor);
|
||||
|
||||
n = prioq_peek(lldp_rx->neighbor_by_expiry);
|
||||
if (!n)
|
||||
return event_source_disable(lldp_rx->timer_event_source);
|
||||
|
||||
return event_reset_time(lldp_rx->event, &lldp_rx->timer_event_source,
|
||||
CLOCK_BOOTTIME,
|
||||
n->until, 0,
|
||||
on_timer_event, lldp_rx,
|
||||
lldp_rx->event_priority, "lldp-rx-timer", true);
|
||||
}
|
||||
|
||||
static inline int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(*a);
|
||||
assert(*b);
|
||||
|
||||
return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
|
||||
}
|
||||
|
||||
int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
|
||||
_cleanup_free_ sd_lldp_neighbor **l = NULL;
|
||||
sd_lldp_neighbor *n;
|
||||
int k = 0;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (hashmap_isempty(lldp_rx->neighbor_by_id)) { /* Special shortcut */
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
l = new0(sd_lldp_neighbor*, hashmap_size(lldp_rx->neighbor_by_id));
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH(n, lldp_rx->neighbor_by_id)
|
||||
l[k++] = sd_lldp_neighbor_ref(n);
|
||||
|
||||
assert((size_t) k == hashmap_size(lldp_rx->neighbor_by_id));
|
||||
|
||||
/* Return things in a stable order */
|
||||
typesafe_qsort(l, k, neighbor_compare_func);
|
||||
*ret = TAKE_PTR(l);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(m > 0, -EINVAL);
|
||||
|
||||
lldp_rx->neighbors_max = m;
|
||||
lldp_rx_make_space(lldp_rx, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(mask != 0, -EINVAL);
|
||||
|
||||
lldp_rx->capability_mask = mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
||||
/* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
|
||||
* that our own can be filtered out here. */
|
||||
|
||||
if (addr)
|
||||
lldp_rx->filter_address = *addr;
|
||||
else
|
||||
zero(lldp_rx->filter_address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosdlldprxhfoo
|
||||
#define foosdlldprxhfoo
|
||||
|
||||
/***
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "sd-lldp.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_lldp_rx sd_lldp_rx;
|
||||
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
|
||||
|
||||
__extension__ typedef enum sd_lldp_rx_event_t {
|
||||
SD_LLDP_RX_EVENT_ADDED,
|
||||
SD_LLDP_RX_EVENT_REMOVED,
|
||||
SD_LLDP_RX_EVENT_UPDATED,
|
||||
SD_LLDP_RX_EVENT_REFRESHED,
|
||||
_SD_LLDP_RX_EVENT_MAX,
|
||||
_SD_LLDP_RX_EVENT_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT)
|
||||
} sd_lldp_rx_event_t;
|
||||
|
||||
typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata);
|
||||
|
||||
int sd_lldp_rx_new(sd_lldp_rx **ret);
|
||||
sd_lldp_rx *sd_lldp_rx_ref(sd_lldp_rx *lldp_rx);
|
||||
sd_lldp_rx *sd_lldp_rx_unref(sd_lldp_rx *lldp_rx);
|
||||
|
||||
int sd_lldp_rx_start(sd_lldp_rx *lldp_rx);
|
||||
int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx);
|
||||
int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx);
|
||||
|
||||
int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority);
|
||||
int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx);
|
||||
sd_event *sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx);
|
||||
|
||||
int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata);
|
||||
int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex);
|
||||
int sd_lldp_rx_set_ifname(sd_lldp_rx *lldp_rx, const char *ifname);
|
||||
int sd_lldp_rx_get_ifname(sd_lldp_rx *lldp_rx, const char **ret);
|
||||
|
||||
/* Controls how much and what to store in the neighbors database */
|
||||
int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t n);
|
||||
int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask);
|
||||
int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *address);
|
||||
|
||||
int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***neighbors);
|
||||
|
||||
int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size);
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n);
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
|
||||
|
||||
/* Access to LLDP frame metadata */
|
||||
int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address);
|
||||
int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address);
|
||||
int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret);
|
||||
int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
|
||||
|
||||
/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */
|
||||
int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
|
||||
int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
|
||||
int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec);
|
||||
int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret);
|
||||
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
|
||||
|
||||
/* Low-level, iterative TLV access. This is for everything else, it iteratively goes through all available TLVs
|
||||
* (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */
|
||||
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n);
|
||||
int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n);
|
||||
int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type);
|
||||
int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type);
|
||||
int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype);
|
||||
int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype);
|
||||
int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_rx, sd_lldp_rx_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosdlldphfoo
|
||||
#define foosdlldphfoo
|
||||
|
||||
/***
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8: TLV Types */
|
||||
enum {
|
||||
SD_LLDP_TYPE_END = 0,
|
||||
SD_LLDP_TYPE_CHASSIS_ID = 1,
|
||||
SD_LLDP_TYPE_PORT_ID = 2,
|
||||
SD_LLDP_TYPE_TTL = 3,
|
||||
SD_LLDP_TYPE_PORT_DESCRIPTION = 4,
|
||||
SD_LLDP_TYPE_SYSTEM_NAME = 5,
|
||||
SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
|
||||
SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
|
||||
SD_LLDP_TYPE_MGMT_ADDRESS = 8,
|
||||
SD_LLDP_TYPE_PRIVATE = 127
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */
|
||||
enum {
|
||||
SD_LLDP_CHASSIS_SUBTYPE_RESERVED = 0,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */
|
||||
enum {
|
||||
SD_LLDP_PORT_SUBTYPE_RESERVED = 0,
|
||||
SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
|
||||
SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
|
||||
SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
|
||||
SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
|
||||
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
|
||||
SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
|
||||
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */
|
||||
enum {
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10
|
||||
};
|
||||
|
||||
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX
|
||||
|
||||
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \
|
||||
((uint16_t) \
|
||||
(SD_LLDP_SYSTEM_CAPABILITIES_REPEATER | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN | \
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR))
|
||||
|
||||
#define SD_LLDP_OUI_802_1 (const uint8_t[]) { 0x00, 0x80, 0xc2 }
|
||||
#define SD_LLDP_OUI_802_3 (const uint8_t[]) { 0x00, 0x12, 0x0f }
|
||||
|
||||
#define _SD_LLDP_OUI_IANA 0x00, 0x00, 0x5E
|
||||
#define SD_LLDP_OUI_IANA (const uint8_t[]) { _SD_LLDP_OUI_IANA }
|
||||
|
||||
#define SD_LLDP_OUI_IANA_SUBTYPE_MUD 0x01
|
||||
#define SD_LLDP_OUI_IANA_MUD \
|
||||
(const uint8_t[]) { _SD_LLDP_OUI_IANA, SD_LLDP_OUI_IANA_SUBTYPE_MUD }
|
||||
|
||||
/* IEEE 802.1AB-2009 Annex E */
|
||||
enum {
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Annex F */
|
||||
enum {
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4
|
||||
};
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue