summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2016-02-22 17:38:34 +0100
committerTom Gundersen <teg@jklm.no>2016-02-22 17:38:34 +0100
commit7c7c0cbe640e33e5f57b24d0281564724b3eaeeb (patch)
tree478c558c880ef1082eda62b6ee3208b29fe98832 /src
parenta4ae7f1d739cc011b5312a8bfba99971bce0e7c3 (diff)
parentda6c766d539dc38dbabf401be31180ca4691215f (diff)
Merge pull request #2685 from poettering/lldp-fixes2
lldp fixes, second iteration
Diffstat (limited to 'src')
-rw-r--r--src/analyze/analyze-verify.h4
-rw-r--r--src/basic/btrfs-util.h4
-rw-r--r--src/basic/ether-addr-util.c23
-rw-r--r--src/basic/ether-addr-util.h5
-rw-r--r--src/basic/gunicode.h4
-rw-r--r--src/basic/hostname-util.c28
-rw-r--r--src/basic/hostname-util.h1
-rw-r--r--src/basic/login-util.h4
-rw-r--r--src/basic/missing.h5
-rw-r--r--src/basic/sigbus.h4
-rw-r--r--src/core/scope.c3
-rw-r--r--src/core/slice.c8
-rw-r--r--src/import/pull-raw.c6
-rw-r--r--src/import/pull-tar.c6
-rw-r--r--src/journal-remote/journal-remote-parse.h4
-rw-r--r--src/journal-remote/journal-remote-write.h5
-rw-r--r--src/journal-remote/journal-remote.h5
-rw-r--r--src/journal-remote/microhttpd-util.h4
-rw-r--r--src/libsystemd-network/dhcp-internal.h4
-rw-r--r--src/libsystemd-network/dhcp-option.c4
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h4
-rw-r--r--src/libsystemd-network/lldp-internal.c360
-rw-r--r--src/libsystemd-network/lldp-internal.h78
-rw-r--r--src/libsystemd-network/lldp-neighbor.c792
-rw-r--r--src/libsystemd-network/lldp-neighbor.h106
-rw-r--r--src/libsystemd-network/lldp-network.c33
-rw-r--r--src/libsystemd-network/lldp-network.h4
-rw-r--r--src/libsystemd-network/lldp-port.c116
-rw-r--r--src/libsystemd-network/lldp-port.h69
-rw-r--r--src/libsystemd-network/lldp-tlv.c638
-rw-r--r--src/libsystemd-network/lldp-tlv.h94
-rw-r--r--src/libsystemd-network/lldp.h84
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c7
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c3
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c6
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c6
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c6
-rw-r--r--src/libsystemd-network/sd-lldp.c899
-rw-r--r--src/libsystemd-network/sd-ndisc.c2
-rw-r--r--src/libsystemd-network/test-lldp.c334
-rw-r--r--src/libsystemd/sd-device/device-internal.h4
-rw-r--r--src/libsystemd/sd-hwdb/hwdb-internal.h3
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c2
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c2
-rw-r--r--src/libsystemd/sd-network/sd-network.c106
-rw-r--r--src/libsystemd/sd-resolve/sd-resolve.c2
-rw-r--r--src/libudev/libudev-device-internal.h4
-rw-r--r--src/network/networkctl.c918
-rw-r--r--src/network/networkd-link.c310
-rw-r--r--src/network/networkd-link.h14
-rw-r--r--src/network/networkd-lldp-tx.c347
-rw-r--r--src/network/networkd-lldp-tx.h25
-rw-r--r--src/network/networkd-netdev-bridge.h4
-rw-r--r--src/network/networkd-netdev-dummy.h4
-rw-r--r--src/network/networkd-netdev-ipvlan.h4
-rw-r--r--src/network/networkd-netdev-macvlan.h4
-rw-r--r--src/network/networkd-netdev-tunnel.h4
-rw-r--r--src/network/networkd-netdev-tuntap.h4
-rw-r--r--src/network/networkd-netdev-veth.h4
-rw-r--r--src/network/networkd-netdev-vlan.h4
-rw-r--r--src/network/networkd-netdev-vxlan.h4
-rw-r--r--src/network/networkd-netdev.h4
-rw-r--r--src/network/networkd-network-gperf.gperf3
-rw-r--r--src/network/networkd-network.c12
-rw-r--r--src/network/networkd-network.h15
-rw-r--r--src/network/networkd-wait-online.h4
-rw-r--r--src/network/networkd.h4
-rw-r--r--src/resolve/dns-type.h4
-rw-r--r--src/shared/dns-domain.h5
-rw-r--r--src/shared/gpt.h4
-rw-r--r--src/shared/install-printf.h4
-rw-r--r--src/shared/sleep-config.h4
-rw-r--r--src/systemd/sd-dhcp-client.h6
-rw-r--r--src/systemd/sd-dhcp-server.h2
-rw-r--r--src/systemd/sd-dhcp6-client.h7
-rw-r--r--src/systemd/sd-ipv4acd.h6
-rw-r--r--src/systemd/sd-ipv4ll.h6
-rw-r--r--src/systemd/sd-lldp.h90
-rw-r--r--src/systemd/sd-ndisc.h2
-rw-r--r--src/systemd/sd-netlink.h4
-rw-r--r--src/systemd/sd-network.h12
-rw-r--r--src/systemd/sd-resolve.h2
-rw-r--r--src/udev/mtd_probe/mtd_probe.h4
-rw-r--r--src/udev/net/ethtool-util.h4
-rw-r--r--src/udev/net/link-config.h4
-rw-r--r--src/udev/scsi_id/scsi.h4
-rw-r--r--src/udev/scsi_id/scsi_id.h4
-rw-r--r--src/udev/udev.h4
-rw-r--r--src/udev/udevadm-util.h4
89 files changed, 2743 insertions, 3030 deletions
diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h
index 54adad93e1..27c253a562 100644
--- a/src/analyze/analyze-verify.h
+++ b/src/analyze/analyze-verify.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <stdbool.h>
#include "path-lookup.h"
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index 37802c2565..1d852d502c 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c
index ded6d31f4b..d2c030903b 100644
--- a/src/basic/ether-addr-util.c
+++ b/src/basic/ether-addr-util.c
@@ -42,3 +42,26 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
return buffer;
}
+
+bool ether_addr_is_null(const struct ether_addr *addr) {
+ assert(addr);
+
+ return addr->ether_addr_octet[0] == 0 &&
+ addr->ether_addr_octet[1] == 0 &&
+ addr->ether_addr_octet[2] == 0 &&
+ addr->ether_addr_octet[3] == 0 &&
+ addr->ether_addr_octet[4] == 0 &&
+ addr->ether_addr_octet[5] == 0;
+}
+
+bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
+ assert(a);
+ assert(b);
+
+ return a->ether_addr_octet[0] == b->ether_addr_octet[0] &&
+ a->ether_addr_octet[1] == b->ether_addr_octet[1] &&
+ a->ether_addr_octet[2] == b->ether_addr_octet[2] &&
+ a->ether_addr_octet[3] == b->ether_addr_octet[3] &&
+ a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
+ a->ether_addr_octet[5] == b->ether_addr_octet[5];
+}
diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h
index 4487149efd..00c5159fe8 100644
--- a/src/basic/ether-addr-util.h
+++ b/src/basic/ether-addr-util.h
@@ -20,10 +20,13 @@
***/
#include <net/ethernet.h>
+#include <stdbool.h>
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
#define ETHER_ADDR_TO_STRING_MAX (3*6)
-
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
+
+bool ether_addr_is_null(const struct ether_addr *addr);
+bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b);
diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h
index b03aa43160..5975bc8fc9 100644
--- a/src/basic/gunicode.h
+++ b/src/basic/gunicode.h
@@ -1,11 +1,11 @@
+#pragma once
+
/* gunicode.h - Unicode manipulation functions
*
* Copyright (C) 1999, 2000 Tom Tromey
* Copyright 2000, 2005 Red Hat, Inc.
*/
-#pragma once
-
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index 57031b645c..f900c509a3 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -48,6 +48,9 @@ bool hostname_is_set(void) {
char* gethostname_malloc(void) {
struct utsname u;
+ /* This call tries to return something useful, either the actual hostname or it makes something up. The only
+ * reason it might mail is OOM. It might even return "localhost" if that's set. */
+
assert_se(uname(&u) >= 0);
if (isempty(u.nodename) || streq(u.nodename, "(none)"))
@@ -56,6 +59,31 @@ char* gethostname_malloc(void) {
return strdup(u.nodename);
}
+int gethostname_strict(char **ret) {
+ struct utsname u;
+ char *k;
+
+ /* This call will rather fail than make up a name. It will not return "localhost" either. */
+
+ assert_se(uname(&u) >= 0);
+
+ if (isempty(u.nodename))
+ return -ENXIO;
+
+ if (streq(u.nodename, "(none)"))
+ return -ENXIO;
+
+ if (is_localhost(u.nodename))
+ return -ENXIO;
+
+ k = strdup(u.nodename);
+ if (!k)
+ return -ENOMEM;
+
+ *ret = k;
+ return 0;
+}
+
static bool hostname_valid_char(char c) {
return
(c >= 'a' && c <= 'z') ||
diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h
index d062eddea1..7af4e6c7ec 100644
--- a/src/basic/hostname-util.h
+++ b/src/basic/hostname-util.h
@@ -26,6 +26,7 @@
bool hostname_is_set(void);
char* gethostname_malloc(void);
+int gethostname_strict(char **ret);
bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
char* hostname_cleanup(char *s);
diff --git a/src/basic/login-util.h b/src/basic/login-util.h
index 89a337d7c1..b01ee25c88 100644
--- a/src/basic/login-util.h
+++ b/src/basic/login-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <stdbool.h>
#include <unistd.h>
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 88ecb4ac01..417604aa64 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -31,6 +31,7 @@
#include <linux/neighbour.h>
#include <linux/oom.h>
#include <linux/rtnetlink.h>
+#include <net/ethernet.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h>
@@ -1171,4 +1172,8 @@ static inline key_serial_t request_key(const char *type, const char *description
#define char16_t uint16_t
#endif
+#ifndef ETHERTYPE_LLDP
+#define ETHERTYPE_LLDP 0x88cc
+#endif
+
#endif
diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h
index cce9eb201b..980243d9ce 100644
--- a/src/basic/sigbus.h
+++ b/src/basic/sigbus.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
void sigbus_install(void);
void sigbus_reset(void);
diff --git a/src/core/scope.c b/src/core/scope.c
index c5d0ecef04..361695c3f9 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -50,8 +50,7 @@ static void scope_init(Unit *u) {
assert(u->load_state == UNIT_STUB);
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
-
- UNIT(s)->ignore_on_isolate = true;
+ u->ignore_on_isolate = true;
}
static void scope_done(Unit *u) {
diff --git a/src/core/slice.c b/src/core/slice.c
index d65364c6f4..667f61bde5 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -34,6 +34,13 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_ACTIVE] = UNIT_ACTIVE
};
+static void slice_init(Unit *u) {
+ assert(u);
+ assert(u->load_state == UNIT_STUB);
+
+ u->ignore_on_isolate = true;
+}
+
static void slice_set_state(Slice *t, SliceState state) {
SliceState old_state;
assert(t);
@@ -305,6 +312,7 @@ const UnitVTable slice_vtable = {
.no_instances = true,
.can_transient = true,
+ .init = slice_init,
.load = slice_load,
.coldplug = slice_coldplug,
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index 8a16602c3e..8993402821 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -355,10 +355,12 @@ static int raw_pull_make_local_copy(RawPull *i) {
r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0);
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
- else if (r < 0 && r != -ENOENT)
+ else if (r == -ENOENT)
+ log_debug_errno(r, "Skipping creation of settings file, since none was found.");
+ else if (r < 0)
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
else
- log_info("Created new settings file '%s.nspawn'", i->local);
+ log_info("Created new settings file %s.", local_settings);
}
return 0;
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index afb13366f0..8c61c46f73 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -251,10 +251,12 @@ static int tar_pull_make_local_copy(TarPull *i) {
r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0);
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
- else if (r < 0 && r != -ENOENT)
+ else if (r == -ENOENT)
+ log_debug_errno(r, "Skipping creation of settings file, since none was found.");
+ else if (r < 0)
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
else
- log_info("Created new settings file '%s.nspawn'", i->local);
+ log_info("Created new settings file %s.", local_settings);
}
return 0;
diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h
index 0b8b6af736..1740a21f92 100644
--- a/src/journal-remote/journal-remote-parse.h
+++ b/src/journal-remote/journal-remote-parse.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "sd-event.h"
#include "journal-remote-write.h"
diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h
index 6b645a353c..53ba45fc04 100644
--- a/src/journal-remote/journal-remote-write.h
+++ b/src/journal-remote/journal-remote-write.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-
#include "journal-file.h"
typedef struct RemoteServer RemoteServer;
diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h
index 6466a1c101..30ad7df996 100644
--- a/src/journal-remote/journal-remote.h
+++ b/src/journal-remote/journal-remote.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-
#include "sd-event.h"
#include "hashmap.h"
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index 70c4d29c0f..ea160f212b 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <microhttpd.h>
#include <stdarg.h>
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index a3b842cda3..4662b0d847 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -42,10 +42,10 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
uint8_t code, size_t optlen, const void *optval);
-typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
+typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
const void *option, void *userdata);
-int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message);
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
uint8_t type, uint16_t arp_type, size_t optlen,
diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c
index b0ea7576bf..531b80eb08 100644
--- a/src/libsystemd-network/dhcp-option.c
+++ b/src/libsystemd-network/dhcp-option.c
@@ -135,7 +135,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
- uint8_t *message_type, char **error_message, dhcp_option_cb_t cb,
+ uint8_t *message_type, char **error_message, dhcp_option_callback_t cb,
void *userdata) {
uint8_t code, len;
const uint8_t *option;
@@ -221,7 +221,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
return 0;
}
-int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) {
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) {
_cleanup_free_ char *error_message = NULL;
uint8_t overload = 0;
uint8_t message_type = 0;
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index bf123f1439..adb557167a 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "sd-dhcp-server.h"
#include "sd-event.h"
diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c
deleted file mode 100644
index c8740ce5f0..0000000000
--- a/src/libsystemd-network/lldp-internal.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-lldp.h"
-
-#include "alloc-util.h"
-#include "lldp-internal.h"
-
-/* We store maximum 1K chassis entries */
-#define LLDP_MIB_MAX_CHASSIS 1024
-
-/* Maximum Ports can be attached to any chassis */
-#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32
-
-/* 10.5.5.2.2 mibUpdateObjects ()
- * The mibUpdateObjects () procedure updates the MIB objects corresponding to
- * the TLVs contained in the received LLDPDU for the LLDP remote system
- * indicated by the LLDP remote systems update process defined in 10.3.5 */
-
-int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
- lldp_neighbour_port *p;
- uint16_t length, ttl;
- uint8_t *data;
- uint8_t type;
- int r;
-
- assert_return(c, -EINVAL);
- assert_return(tlv, -EINVAL);
-
- r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- /* Update the packet if we already have */
- LIST_FOREACH(port, p, c->ports) {
-
- if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) {
-
- r = sd_lldp_packet_read_ttl(tlv, &ttl);
- if (r < 0)
- return r;
-
- p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
-
- sd_lldp_packet_unref(p->packet);
- p->packet = tlv;
-
- prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx);
-
- return 0;
- }
- }
-
- return -1;
-}
-
-int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) {
- lldp_neighbour_port *p, *q;
- uint8_t *data;
- uint16_t length;
- uint8_t type;
- int r;
-
- assert_return(c, -EINVAL);
- assert_return(tlv, -EINVAL);
-
- r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- LIST_FOREACH_SAFE(port, p, q, c->ports) {
-
- /* Find the port */
- if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) {
- lldp_neighbour_port_remove_and_free(p);
- break;
- }
- }
-
- return 0;
-}
-
-int lldp_mib_add_objects(Prioq *by_expiry,
- Hashmap *neighbour_mib,
- tlv_packet *tlv) {
- _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
- _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
- lldp_chassis_id chassis_id;
- bool new_chassis = false;
- uint8_t subtype, *data;
- uint16_t ttl, length;
- int r;
-
- assert_return(by_expiry, -EINVAL);
- assert_return(neighbour_mib, -EINVAL);
- assert_return(tlv, -EINVAL);
-
- r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length);
- if (r < 0)
- goto drop;
-
- r = sd_lldp_packet_read_ttl(tlv, &ttl);
- if (r < 0)
- goto drop;
-
- /* Make hash key */
- chassis_id.type = subtype;
- chassis_id.length = length;
- chassis_id.data = data;
-
- /* Try to find the Chassis */
- c = hashmap_get(neighbour_mib, &chassis_id);
- if (!c) {
-
- /* Don't create chassis if ttl 0 is received . Silently drop it */
- if (ttl == 0) {
- log_lldp("TTL value 0 received. Skiping Chassis creation.");
- goto drop;
- }
-
- /* Admission Control: Can we store this packet ? */
- if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) {
-
- log_lldp("Exceeding number of chassie: %d. Dropping ...",
- hashmap_size(neighbour_mib));
- goto drop;
- }
-
- r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c);
- if (r < 0)
- goto drop;
-
- new_chassis = true;
-
- r = hashmap_put(neighbour_mib, &c->chassis_id, c);
- if (r < 0)
- goto drop;
-
- } else {
-
- /* When the TTL field is set to zero, the receiving LLDP agent is notified all
- * system information associated with the LLDP agent/port is to be deleted */
- if (ttl == 0) {
- log_lldp("TTL value 0 received . Deleting associated Port ...");
-
- lldp_mib_remove_objects(c, tlv);
-
- c = NULL;
- goto drop;
- }
-
- /* if we already have this port just update it */
- r = lldp_mib_update_objects(c, tlv);
- if (r >= 0) {
- c = NULL;
- return r;
- }
-
- /* Admission Control: Can this port attached to the existing chassis ? */
- if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) {
- log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref);
-
- c = NULL;
- goto drop;
- }
- }
-
- /* This is a new port */
- r = lldp_neighbour_port_new(c, tlv, &p);
- if (r < 0)
- goto drop;
-
- r = prioq_put(c->by_expiry, p, &p->prioq_idx);
- if (r < 0)
- goto drop;
-
- /* Attach new port to chassis */
- LIST_PREPEND(port, c->ports, p);
- c->n_ref ++;
-
- p = NULL;
- c = NULL;
-
- return 0;
-
- drop:
- sd_lldp_packet_unref(tlv);
-
- if (new_chassis)
- hashmap_remove(neighbour_mib, &c->chassis_id);
-
- return r;
-}
-
-void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) {
- lldp_chassis *c;
-
- assert(p);
- assert(p->c);
-
- c = p->c;
-
- prioq_remove(c->by_expiry, p, &p->prioq_idx);
-
- LIST_REMOVE(port, c->ports, p);
- lldp_neighbour_port_free(p);
-
- /* Drop the Chassis if no port is attached */
- c->n_ref --;
- if (c->n_ref <= 1) {
- hashmap_remove(c->neighbour_mib, &c->chassis_id);
- lldp_chassis_free(c);
- }
-}
-
-void lldp_neighbour_port_free(lldp_neighbour_port *p) {
-
- if(!p)
- return;
-
- sd_lldp_packet_unref(p->packet);
-
- free(p->data);
- free(p);
-}
-
-int lldp_neighbour_port_new(lldp_chassis *c,
- tlv_packet *tlv,
- lldp_neighbour_port **ret) {
- _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
- uint16_t length, ttl;
- uint8_t *data;
- uint8_t type;
- int r;
-
- assert(tlv);
-
- r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- r = sd_lldp_packet_read_ttl(tlv, &ttl);
- if (r < 0)
- return r;
-
- p = new0(lldp_neighbour_port, 1);
- if (!p)
- return -ENOMEM;
-
- p->c = c;
- p->type = type;
- p->length = length;
- p->packet = tlv;
- p->prioq_idx = PRIOQ_IDX_NULL;
- p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
-
- p->data = memdup(data, length);
- if (!p->data)
- return -ENOMEM;
-
- *ret = p;
- p = NULL;
-
- return 0;
-}
-
-void lldp_chassis_free(lldp_chassis *c) {
-
- if (!c)
- return;
-
- if (c->n_ref > 1)
- return;
-
- free(c->chassis_id.data);
- free(c);
-}
-
-int lldp_chassis_new(tlv_packet *tlv,
- Prioq *by_expiry,
- Hashmap *neighbour_mib,
- lldp_chassis **ret) {
- _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
- uint16_t length;
- uint8_t *data;
- uint8_t type;
- int r;
-
- assert(tlv);
-
- r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- c = new0(lldp_chassis, 1);
- if (!c)
- return -ENOMEM;
-
- c->n_ref = 1;
- c->chassis_id.type = type;
- c->chassis_id.length = length;
-
- c->chassis_id.data = memdup(data, length);
- if (!c->chassis_id.data)
- return -ENOMEM;
-
- LIST_HEAD_INIT(c->ports);
-
- c->by_expiry = by_expiry;
- c->neighbour_mib = neighbour_mib;
-
- *ret = c;
- c = NULL;
-
- return 0;
-}
-
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL;
- tlv_packet *p;
- uint16_t length;
- int r;
-
- assert(fd);
- assert(userdata);
-
- r = tlv_packet_new(&packet);
- if (r < 0)
- return r;
-
- length = read(fd, &packet->pdu, sizeof(packet->pdu));
-
- /* Silently drop the packet */
- if ((size_t) length > ETHER_MAX_LEN)
- return 0;
-
- packet->userdata = userdata;
-
- p = packet;
- packet = NULL;
-
- return lldp_handle_packet(p, (uint16_t) length);
-}
diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h
index 15b4a11b15..7592bc4305 100644
--- a/src/libsystemd-network/lldp-internal.h
+++ b/src/libsystemd-network/lldp-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,74 +20,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "sd-event.h"
+#include "sd-lldp.h"
-#include "list.h"
-#include "lldp-tlv.h"
+#include "hashmap.h"
#include "log.h"
#include "prioq.h"
-typedef struct lldp_neighbour_port lldp_neighbour_port;
-typedef struct lldp_chassis lldp_chassis;
-typedef struct lldp_chassis_id lldp_chassis_id;
-typedef struct lldp_agent_statistics lldp_agent_statistics;
+struct sd_lldp {
+ int ifindex;
+ int fd;
-struct lldp_neighbour_port {
- uint8_t type;
- uint8_t *data;
+ sd_event *event;
+ int64_t event_priority;
+ sd_event_source *io_event_source;
+ sd_event_source *timer_event_source;
- uint16_t length;
- usec_t until;
+ Prioq *neighbor_by_expiry;
+ Hashmap *neighbor_by_id;
- unsigned prioq_idx;
+ uint64_t neighbors_max;
- lldp_chassis *c;
- tlv_packet *packet;
+ sd_lldp_callback_t callback;
+ void *userdata;
- LIST_FIELDS(lldp_neighbour_port, port);
-};
+ uint16_t capability_mask;
-int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret);
-void lldp_neighbour_port_free(lldp_neighbour_port *p);
-void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free);
-#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep)
-
-struct lldp_chassis_id {
- uint8_t type;
- uint16_t length;
-
- uint8_t *data;
+ struct ether_addr filter_address;
};
-struct lldp_chassis {
- unsigned n_ref;
-
- lldp_chassis_id chassis_id;
-
- Prioq *by_expiry;
- Hashmap *neighbour_mib;
-
- LIST_HEAD(lldp_neighbour_port, ports);
-};
-
-int lldp_chassis_new(tlv_packet *tlv,
- Prioq *by_expiry,
- Hashmap *neighbour_mib,
- lldp_chassis **ret);
-
-void lldp_chassis_free(lldp_chassis *c);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free);
-#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep)
-
-int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv);
-int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv);
-int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv);
-
-int lldp_handle_packet(tlv_packet *m, uint16_t length);
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata);
-#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
+#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
+#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c
new file mode 100644
index 0000000000..c61941cd70
--- /dev/null
+++ b/src/libsystemd-network/lldp-neighbor.c
@@ -0,0 +1,792 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "ether-addr-util.h"
+#include "hexdecoct.h"
+#include "in-addr-util.h"
+#include "lldp-internal.h"
+#include "lldp-neighbor.h"
+#include "lldp.h"
+#include "unaligned.h"
+
+static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
+ const LLDPNeighborID *id = p;
+
+ 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);
+}
+
+static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
+ const LLDPNeighborID *x = a, *y = b;
+ int r;
+
+ r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
+ if (r != 0)
+ return r;
+
+ if (x->chassis_id_size < y->chassis_id_size)
+ return -1;
+
+ if (x->chassis_id_size > y->chassis_id_size)
+ return 1;
+
+ r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size));
+ if (r != 0)
+ return r;
+
+ if (x->port_id_size < y->port_id_size)
+ return -1;
+ if (x->port_id_size > y->port_id_size)
+ return 1;
+
+ return 0;
+}
+
+const struct hash_ops lldp_neighbor_id_hash_ops = {
+ .hash = lldp_neighbor_id_hash_func,
+ .compare = lldp_neighbor_id_compare_func
+};
+
+int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
+ const sd_lldp_neighbor *x = a, *y = b;
+
+ if (x->until < y->until)
+ return -1;
+
+ if (x->until > y->until)
+ return 1;
+
+ return 0;
+}
+
+_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
+ if (!n)
+ return NULL;
+
+ assert(n->n_ref > 0 || n->lldp);
+ n->n_ref++;
+
+ return n;
+}
+
+static void lldp_neighbor_free(sd_lldp_neighbor *n) {
+ assert(n);
+
+ free(n->id.port_id);
+ free(n->id.chassis_id);
+ free(n->port_description);
+ free(n->system_name);
+ free(n->system_description);
+ free(n->chassis_id_as_string);
+ free(n->port_id_as_string);
+ free(n);
+}
+
+_public_ 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)
+ 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)
+ return NULL;
+
+ assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n);
+ assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
+
+ n->lldp = 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;
+
+ 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(char **s, const void *q, size_t n) {
+ const char *p = q;
+ char *k;
+
+ assert(s);
+ assert(p || n == 0);
+
+ if (*s) {
+ log_lldp("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("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 -ENOMEM;
+
+ 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)) {
+ log_lldp("Recieved truncated packet, ignoring.");
+ return -EBADMSG;
+ }
+
+ memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
+
+ if (h.ether_type != htobe16(ETHERTYPE_LLDP)) {
+ log_lldp("Received packet with wrong type, ignoring.");
+ return -EBADMSG;
+ }
+
+ 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)) {
+ log_lldp("Received packet with wrong destination address, ignoring.");
+ return -EBADMSG;
+ }
+
+ 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) {
+ log_lldp("TLV lacks header, ignoring.");
+ return -EBADMSG;
+ }
+
+ type = p[0] >> 1;
+ length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
+ p += 2, left -= 2;
+
+ if (left < length) {
+ log_lldp("TLV truncated, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ switch (type) {
+
+ case LLDP_TYPE_END:
+ if (length != 0) {
+ log_lldp("End marker TLV not zero-sized, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (left != 0) {
+ log_lldp("Trailing garbage in datagram, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ goto end_marker;
+
+ case LLDP_TYPE_CHASSIS_ID:
+ if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */
+ log_lldp("Chassis ID field size out of range, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (n->id.chassis_id) {
+ log_lldp("Duplicate chassis ID field, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ n->id.chassis_id = memdup(p, length);
+ if (!n->id.chassis_id)
+ return -ENOMEM;
+
+ n->id.chassis_id_size = length;
+ break;
+
+ case LLDP_TYPE_PORT_ID:
+ if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */
+ log_lldp("Port ID field size out of range, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (n->id.port_id) {
+ log_lldp("Duplicate port ID field, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ n->id.port_id = memdup(p, length);
+ if (!n->id.port_id)
+ return -ENOMEM;
+
+ n->id.port_id_size = length;
+ break;
+
+ case LLDP_TYPE_TTL:
+ if (length != 2) {
+ log_lldp("TTL field has wrong size, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ if (n->has_ttl) {
+ log_lldp("Duplicate TTL field, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ n->ttl = unaligned_read_be16(p);
+ n->has_ttl = true;
+ break;
+
+ case LLDP_TYPE_PORT_DESCRIPTION:
+ r = parse_string(&n->port_description, p, length);
+ if (r < 0)
+ return r;
+ break;
+
+ case LLDP_TYPE_SYSTEM_NAME:
+ r = parse_string(&n->system_name, p, length);
+ if (r < 0)
+ return r;
+ break;
+
+ case LLDP_TYPE_SYSTEM_DESCRIPTION:
+ r = parse_string(&n->system_description, p, length);
+ if (r < 0)
+ return r;
+ break;
+
+ case LLDP_TYPE_SYSTEM_CAPABILITIES:
+ if (length != 4)
+ log_lldp("System capabilities field has wrong size, ignoring.");
+ else {
+ n->system_capabilities = unaligned_read_be16(p);
+ n->enabled_capabilities = unaligned_read_be16(p + 2);
+ n->has_capabilities = true;
+ }
+
+ break;
+
+ case LLDP_TYPE_PRIVATE:
+ if (length < 4)
+ log_lldp("Found private TLV that is too short, ignoring.");
+
+ break;
+ }
+
+
+ p += length, left -= length;
+ }
+
+end_marker:
+ if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) {
+ log_lldp("One or more mandatory TLV missing in datagram. Ignoring.");
+ return -EBADMSG;
+
+ }
+
+ n->rindex = sizeof(struct ether_header);
+
+ return 0;
+}
+
+void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
+ assert(n);
+
+ if (n->ttl > 0)
+ n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC);
+ else
+ n->until = 0;
+
+ if (n->lldp)
+ prioq_reshuffle(n->lldp->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;
+}
+
+_public_ 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;
+}
+
+_public_ 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;
+}
+
+_public_ 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;
+}
+
+_public_ 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;
+
+ 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;
+
+ return in_addr_to_string(family, &a, ret);
+}
+
+_public_ 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 LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
+ case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
+ case LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT:
+ case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
+ case 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 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 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;
+}
+
+_public_ 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;
+}
+
+_public_ 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 LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
+ case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
+ case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
+ case 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 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 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;
+}
+
+_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = n->ttl;
+ return 0;
+}
+
+_public_ 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;
+}
+
+_public_ 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;
+}
+
+_public_ 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;
+}
+
+_public_ 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;
+}
+
+_public_ 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(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
+ r = lldp_neighbor_parse(n);
+ if (r < 0)
+ return r;
+
+ *ret = n;
+ n = 0;
+
+ return r;
+}
+
+_public_ 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 0;
+}
+
+_public_ 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_LENGTH(n);
+ if (n->rindex + 2 + length > n->raw_size)
+ return -EBADMSG;
+
+ n->rindex += 2 + length;
+ return n->rindex < n->raw_size;
+}
+
+_public_ 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_TYPE(n);
+ return 0;
+}
+
+_public_ 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;
+}
+
+_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[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, LLDP_TYPE_PRIVATE);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENXIO;
+
+ length = LLDP_NEIGHBOR_LENGTH(n);
+ if (length < 4)
+ return -EBADMSG;
+
+ if (n->rindex + 2 + length > n->raw_size)
+ return -EBADMSG;
+
+ d = LLDP_NEIGHBOR_DATA(n);
+ memcpy(oui, d, 3);
+ *subtype = d[3];
+
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[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;
+}
+
+_public_ 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_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;
+}
diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h
new file mode 100644
index 0000000000..f203bfa604
--- /dev/null
+++ b/src/libsystemd-network/lldp-neighbor.h
@@ -0,0 +1,106 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "sd-lldp.h"
+
+#include "hash-funcs.h"
+#include "lldp-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" object or n_ref > 0. */
+ sd_lldp *lldp;
+ unsigned n_ref;
+
+ 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;
+
+ 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_TYPE(const sd_lldp_neighbor *n) {
+ return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1;
+}
+
+static inline size_t LLDP_NEIGHBOR_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_DATA(const sd_lldp_neighbor *n) {
+ return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
+}
+
+extern const struct hash_ops lldp_neighbor_id_hash_ops;
+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);
diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c
index 7c865b46cb..f031760351 100644
--- a/src/libsystemd-network/lldp-network.c
+++ b/src/libsystemd-network/lldp-network.c
@@ -22,62 +22,55 @@
#include <netinet/if_ether.h>
#include "fd-util.h"
-#include "lldp-internal.h"
#include "lldp-network.h"
-#include "lldp-tlv.h"
#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) {
- typedef struct LLDPFrame {
- struct ethhdr hdr;
- uint8_t tlvs[0];
- } LLDPFrame;
- struct sock_filter filter[] = {
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */
+ 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(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
+ 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(LLDPFrame, hdr.h_proto)), /* A <- protocol */
+ 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_t) -1), /* accept packet */
};
- struct sock_fprog fprog = {
+ static const struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
- .filter = filter
+ .filter = (struct sock_filter*) filter,
};
- _cleanup_close_ int s = -1;
-
union sockaddr_union saddrll = {
.ll.sll_family = AF_PACKET,
.ll.sll_ifindex = ifindex,
};
+ _cleanup_close_ int fd = -1;
int r;
assert(ifindex > 0);
- s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (s < 0)
+ fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP));
+ if (fd < 0)
return -errno;
- r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
+ r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
if (r < 0)
return -errno;
- r = bind(s, &saddrll.sa, sizeof(saddrll.ll));
+ r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
if (r < 0)
return -errno;
- r = s;
- s = -1;
+ r = fd;
+ fd = -1;
return r;
}
diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h
index dcf31faa95..c4cf8c79f1 100644
--- a/src/libsystemd-network/lldp-network.h
+++ b/src/libsystemd-network/lldp-network.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "sd-event.h"
int lldp_network_bind_raw_socket(int ifindex);
diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c
deleted file mode 100644
index c86f62a6c2..0000000000
--- a/src/libsystemd-network/lldp-port.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "async.h"
-#include "lldp-internal.h"
-#include "lldp-network.h"
-#include "lldp-port.h"
-
-int lldp_port_start(lldp_port *p) {
- int r;
-
- assert_return(p, -EINVAL);
-
- r = lldp_network_bind_raw_socket(p->ifindex);
- if (r < 0)
- return r;
-
- p->rawfd = r;
-
- r = sd_event_add_io(p->event, &p->lldp_port_rx,
- p->rawfd, EPOLLIN, lldp_receive_packet, p);
- if (r < 0) {
- log_debug_errno(r, "Failed to allocate event source: %m");
- goto fail;
- }
-
- r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority);
- if (r < 0) {
- log_debug_errno(r, "Failed to set event priority: %m");
- goto fail;
- }
-
- r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx");
- if (r < 0) {
- log_debug_errno(r, "Failed to set event name: %m");
- goto fail;
- }
-
- return 0;
-
-fail:
- lldp_port_stop(p);
-
- return r;
-}
-
-int lldp_port_stop(lldp_port *p) {
-
- assert_return(p, -EINVAL);
-
- p->rawfd = asynchronous_close(p->rawfd);
- p->lldp_port_rx = sd_event_source_unref(p->lldp_port_rx);
-
- return 0;
-}
-
-void lldp_port_free(lldp_port *p) {
- if (!p)
- return;
-
- lldp_port_stop(p);
-
- free(p->ifname);
- free(p);
-}
-
-int lldp_port_new(int ifindex,
- const char *ifname,
- const struct ether_addr *addr,
- void *userdata,
- lldp_port **ret) {
- _cleanup_free_ lldp_port *p = NULL;
-
- assert_return(ifindex, -EINVAL);
- assert_return(ifname, -EINVAL);
- assert_return(addr, -EINVAL);
-
- p = new0(lldp_port, 1);
- if (!p)
- return -ENOMEM;
-
- p->rawfd = -1;
- p->ifindex = ifindex;
-
- p->ifname = strdup(ifname);
- if (!p->ifname)
- return -ENOMEM;
-
- memcpy(&p->mac, addr, ETH_ALEN);
-
- p->userdata = userdata;
-
- *ret = p;
-
- p = NULL;
-
- return 0;
-}
diff --git a/src/libsystemd-network/lldp-port.h b/src/libsystemd-network/lldp-port.h
deleted file mode 100644
index 96092f8df9..0000000000
--- a/src/libsystemd-network/lldp-port.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <http://www.gnu.org/licenses/>.
-***/
-
-#pragma once
-
-#include <net/ethernet.h>
-
-#include "sd-event.h"
-#include "sd-lldp.h"
-
-#include "util.h"
-
-typedef struct lldp_port lldp_port;
-
-typedef enum LLDPPortStatus {
- LLDP_PORT_STATUS_NONE,
- LLDP_PORT_STATUS_ENABLED,
- LLDP_PORT_STATUS_DISABLED,
- _LLDP_PORT_STATUS_MAX,
- _LLDP_PORT_STATUS_INVALID = -1,
-} LLDPPortStatus;
-
-struct lldp_port {
- LLDPPortStatus status;
-
- int ifindex;
- char *ifname;
-
- struct ether_addr mac;
-
- int rawfd;
-
- sd_event *event;
- sd_event_source *lldp_port_rx;
-
- int event_priority;
-
- void *userdata;
-};
-
-int lldp_port_new(int ifindex,
- const char *ifname,
- const struct ether_addr *addr,
- void *userdata,
- lldp_port **ret);
-void lldp_port_free(lldp_port *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_port*, lldp_port_free);
-#define _cleanup_lldp_port_free_ _cleanup_(lldp_port_freep)
-
-int lldp_port_start(lldp_port *p);
-int lldp_port_stop(lldp_port *p);
diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c
deleted file mode 100644
index 9170b50691..0000000000
--- a/src/libsystemd-network/lldp-tlv.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <http://www.gnu.org/licenses/>.
-***/
-
-#include <arpa/inet.h>
-#include <net/ethernet.h>
-
-#include "alloc-util.h"
-#include "lldp-tlv.h"
-#include "macro.h"
-
-int tlv_section_new(tlv_section **ret) {
- tlv_section *s;
-
- s = new0(tlv_section, 1);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
-
- return 0;
-}
-
-void tlv_section_free(tlv_section *m) {
-
- if (!m)
- return;
-
- free(m);
-}
-
-int tlv_packet_new(tlv_packet **ret) {
- tlv_packet *m;
-
- m = new0(tlv_packet, 1);
- if (!m)
- return -ENOMEM;
-
- LIST_HEAD_INIT(m->sections);
- m->n_ref = 1;
-
- *ret = m;
-
- return 0;
-}
-
-tlv_packet *sd_lldp_packet_ref(tlv_packet *m) {
-
- if (!m)
- return NULL;
-
- assert(m->n_ref > 0);
- m->n_ref++;
-
- return m;
-}
-
-tlv_packet *sd_lldp_packet_unref(tlv_packet *m) {
- tlv_section *s, *n;
-
- if (!m)
- return NULL;
-
- assert(m->n_ref > 0);
- m->n_ref--;
-
- if (m->n_ref > 0)
- return m;
-
- LIST_FOREACH_SAFE(section, s, n, m->sections)
- tlv_section_free(s);
-
- free(m);
- return NULL;
-}
-
-int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) {
- uint8_t *p;
-
- assert_return(m, -EINVAL);
- assert_return(data, -EINVAL);
- assert_return(data_length, -EINVAL);
-
- if (m->length + data_length > ETHER_MAX_LEN)
- return -ENOMEM;
-
- p = m->pdu + m->length;
- memcpy(p, data, data_length);
- m->length += data_length;
-
- return 0;
-}
-
-int tlv_packet_append_u8(tlv_packet *m, uint8_t data) {
-
- assert_return(m, -EINVAL);
-
- return tlv_packet_append_bytes(m, &data, sizeof(uint8_t));
-}
-
-int tlv_packet_append_u16(tlv_packet *m, uint16_t data) {
- uint16_t type;
-
- assert_return(m, -EINVAL);
-
- type = htons(data);
-
- return tlv_packet_append_bytes(m, &type, sizeof(uint16_t));
-}
-
-int tlv_packet_append_u32(tlv_packet *m, uint32_t data) {
- uint32_t type;
-
- assert_return(m, -EINVAL);
-
- type = htonl(data);
-
- return tlv_packet_append_bytes(m, &type, sizeof(uint32_t));
-}
-
-int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) {
-
- assert_return(m, -EINVAL);
-
- return tlv_packet_append_bytes(m, data, size);
-}
-
-int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) {
-
- assert_return(m, -EINVAL);
-
- m->container_pos = m->pdu + m->length;
-
- return tlv_packet_append_u16(m, type << 9);
-}
-
-int lldp_tlv_packet_close_container(tlv_packet *m) {
- uint16_t type;
-
- assert_return(m, -EINVAL);
- assert_return(m->container_pos, -EINVAL);
-
- memcpy(&type, m->container_pos, sizeof(uint16_t));
-
- type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff);
- memcpy(m->container_pos, &type, sizeof(uint16_t));
-
- return 0;
-}
-
-static inline int tlv_packet_read_internal(tlv_section *m, void **data) {
-
- assert_return(m->read_pos, -EINVAL);
-
- *data = m->read_pos;
-
- return 0;
-}
-
-int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) {
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- memcpy(data, val, sizeof(uint8_t));
-
- m->container->read_pos ++;
-
- return 0;
-}
-
-int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) {
- uint16_t t;
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- memcpy(&t, val, sizeof(uint16_t));
- *data = ntohs(t);
-
- m->container->read_pos += 2;
-
- return 0;
-}
-
-int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) {
- uint32_t t;
- void *val;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- memcpy(&t, val, sizeof(uint32_t));
- *data = ntohl(t);
-
- m->container->read_pos += 4;
-
- return r;
-}
-
-int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- *data = (char *) val;
- *data_length = m->container->data + m->container->length - m->container->read_pos;
-
- m->container->read_pos += *data_length;
-
- return 0;
-}
-
-int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) {
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- *data = (uint8_t *) val;
- *data_length = m->container->data + m->container->length - m->container->read_pos;
-
- m->container->read_pos += *data_length;
-
- return 0;
-}
-
-/* parse raw TLV packet */
-int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
- tlv_section *section, *tail;
- uint16_t t, l;
- uint8_t *p;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(size, -EINVAL);
-
- p = m->pdu;
-
- /* extract Ethernet header */
- memcpy(&m->mac, p, ETH_ALEN);
- p += sizeof(struct ether_header);
-
- for (l = 0; l <= size; ) {
- r = tlv_section_new(&section);
- if (r < 0)
- return r;
-
- memcpy(&t, p, sizeof(uint16_t));
-
- section->type = ntohs(t) >> 9;
- section->length = ntohs(t) & 0x01ff;
-
- if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) {
- tlv_section_free(section);
- break;
- }
-
- p += 2;
-
- if (section->type == LLDP_TYPE_PRIVATE &&
- section->length >= LLDP_OUI_LEN + 1) {
- section->oui = p;
- p += LLDP_OUI_LEN;
- section->subtype = *p++;
-
- section->length -= LLDP_OUI_LEN + 1;
- l += LLDP_OUI_LEN + 1;
- }
-
- section->data = p;
-
- LIST_FIND_TAIL(section, m->sections, tail);
- LIST_INSERT_AFTER(section, m->sections, tail, section);
-
- p += section->length;
- l += (section->length + 2);
- }
-
- return 0;
-}
-
-int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
- tlv_section *s;
-
- assert_return(m, -EINVAL);
- assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL);
-
- LIST_FOREACH(section, s, m->sections)
- if (s->type == type)
- break;
- if (!s)
- return -1;
-
- m->container = s;
-
- m->container->read_pos = s->data;
- if (!m->container->read_pos) {
- m->container = NULL;
- return -1;
- }
-
- return 0;
-}
-
-int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) {
- tlv_section *s;
-
- assert_return(m, -EINVAL);
- assert_return(oui, -EINVAL);
-
- LIST_FOREACH(section, s, m->sections) {
- if (s->type == LLDP_TYPE_PRIVATE &&
- s->oui &&
- s->subtype == subtype &&
- !memcmp(s->oui, oui, LLDP_OUI_LEN))
- break;
- }
-
- if (!s)
- return -1;
-
- m->container = s;
-
- m->container->read_pos = s->data;
- if (!m->container->read_pos) {
- m->container = NULL;
- return -1;
- }
-
- return 0;
-}
-
-int lldp_tlv_packet_exit_container(tlv_packet *m) {
- assert_return(m, -EINVAL);
-
- m->container = 0;
-
- return 0;
-}
-
-static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) {
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, type);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u16(tlv, value);
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) {
- char *s;
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, type);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
- uint8_t *type,
- uint8_t **data,
- uint16_t *length) {
- uint8_t subtype;
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out;
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out:
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_port_id(tlv_packet *tlv,
- uint8_t *type,
- uint8_t **data,
- uint16_t *length) {
- uint8_t subtype;
- char *s;
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out;
-
- switch (subtype) {
- case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
- case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
- case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
- case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (uint8_t *) s;
-
- break;
- case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out:
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
- return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl);
-}
-
-int sd_lldp_packet_read_system_name(tlv_packet *tlv,
- char **data,
- uint16_t *length) {
- return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length);
-}
-
-int sd_lldp_packet_read_system_description(tlv_packet *tlv,
- char **data,
- uint16_t *length) {
- return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length);
-}
-
-int sd_lldp_packet_read_port_description(tlv_packet *tlv,
- char **data,
- uint16_t *length) {
- return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length);
-}
-
-int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) {
- return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data);
-}
-
-int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) {
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u16(tlv, id);
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) {
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u8(tlv, flags);
- if (r >= 0)
- r = tlv_packet_read_u16(tlv, id);
-
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) {
- int r, r2;
- uint8_t len = 0;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u16(tlv, vlan_id);
- if (r >= 0)
- r = tlv_packet_read_u8(tlv, &len);
- if (r >= 0)
- r = tlv_packet_read_string(tlv, name, length);
-
- if (r >= 0 && len < *length)
- *length = len;
-
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) {
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u16(tlv, id);
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) {
- int r, r2;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u8(tlv, status);
- if (r >= 0)
- r = tlv_packet_read_u32(tlv, id);
-
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- return r < 0 ? r : r2;
-}
-
-int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) {
- assert_return(tlv, -EINVAL);
- assert_return(dest, -EINVAL);
-
- /* 802.1AB-2009, Table 7-1 */
- if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN))
- *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE;
- else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN))
- *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE;
- else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN))
- *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE;
- else
- return -EINVAL;
-
- return 0;
-}
diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h
deleted file mode 100644
index 8e7706c612..0000000000
--- a/src/libsystemd-network/lldp-tlv.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <http://www.gnu.org/licenses/>.
-***/
-
-#pragma once
-
-#include <net/ethernet.h>
-
-#include "sd-lldp.h"
-
-#include "list.h"
-#include "lldp.h"
-#include "util.h"
-
-typedef struct sd_lldp_packet tlv_packet;
-typedef struct sd_lldp_section tlv_section;
-
-#define LLDP_OUI_LEN 3
-
-struct sd_lldp_section {
- uint16_t type;
- uint16_t length;
- uint8_t *oui;
- uint8_t subtype;
-
- uint8_t *read_pos;
- uint8_t *data;
-
- LIST_FIELDS(tlv_section, section);
-};
-
-#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
-#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }
-#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }
-
-int tlv_section_new(tlv_section **ret);
-void tlv_section_free(tlv_section *ret);
-
-struct sd_lldp_packet {
- unsigned n_ref;
-
- uint16_t type;
- uint16_t length;
- usec_t ts;
-
- uint8_t *container_pos;
- uint8_t pdu[ETHER_MAX_LEN];
-
- void *userdata;
-
- struct ether_addr mac;
- tlv_section *container;
-
- LIST_HEAD(tlv_section, sections);
-};
-
-int tlv_packet_new(tlv_packet **ret);
-
-int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type);
-int lldp_tlv_packet_close_container(tlv_packet *m);
-
-int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length);
-int tlv_packet_append_u8(tlv_packet *m, uint8_t data);
-int tlv_packet_append_u16(tlv_packet *m, uint16_t data);
-int tlv_packet_append_u32(tlv_packet *m, uint32_t data);
-int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size);
-
-int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type);
-int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype);
-int lldp_tlv_packet_exit_container(tlv_packet *m);
-
-int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length);
-int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length);
-int tlv_packet_read_u8(tlv_packet *m, uint8_t *data);
-int tlv_packet_read_u16(tlv_packet *m, uint16_t *data);
-int tlv_packet_read_u32(tlv_packet *m, uint32_t *data);
-
-int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size);
diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h
index d2c7164633..d61ecabcfc 100644
--- a/src/libsystemd-network/lldp.h
+++ b/src/libsystemd-network/lldp.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,14 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
-#define ETHERTYPE_LLDP 0x88cc
-
/* IEEE 802.3AB Clause 9: TLV Types */
-typedef enum LLDPTypes {
+enum {
LLDP_TYPE_END = 0,
LLDP_TYPE_CHASSIS_ID = 1,
LLDP_TYPE_PORT_ID = 2,
@@ -36,12 +34,10 @@ typedef enum LLDPTypes {
LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
LLDP_TYPE_MGMT_ADDRESS = 8,
LLDP_TYPE_PRIVATE = 127,
- _LLDP_TYPE_MAX,
- _LLDP_TYPE_INVALID = -1,
-} LLDPTypes;
+};
/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */
-typedef enum LLDPChassisSubtypes {
+enum {
LLDP_CHASSIS_SUBTYPE_RESERVED = 0,
LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1,
LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2,
@@ -50,25 +46,21 @@ typedef enum LLDPChassisSubtypes {
LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
- _LLDP_CHASSIS_SUBTYPE_MAX,
- _LLDP_CHASSIS_SUBTYPE_INVALID = -1,
-} LLDPChassisSubtypes;
+};
/* IEEE 802.3AB Clause 9.5.3: Port subtype */
-typedef enum LLDPPortSubtypes {
+enum {
LLDP_PORT_SUBTYPE_RESERVED = 0,
LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
- LLDP_PORT_SUBTYPE_NETWORK = 4,
+ LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
- _LLDP_PORT_SUBTYPE_MAX,
- _LLDP_PORT_SUBTYPE_INVALID = -1
-} LLDPPortSubtypes;
+};
-typedef enum LLDPSystemCapabilities {
+enum {
LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
@@ -80,47 +72,31 @@ typedef enum LLDPSystemCapabilities {
LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
- _LLDP_SYSTEM_CAPABILITIES_MAX,
- _LLDP_SYSTEM_CAPABILITIES_INVALID = -1,
-} LLDPSystemCapabilities;
+};
+
+#define _LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1)
-typedef enum LLDPMedSubtype {
- LLDP_MED_SUBTYPE_RESERVED = 0,
- LLDP_MED_SUBTYPE_CAPABILITIES = 1,
- LLDP_MED_SUBTYPE_NETWORK_POLICY = 2,
- LLDP_MED_SUBTYPE_LOCATION_ID = 3,
- LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4,
- LLDP_MED_SUBTYPE_INV_HWREV = 5,
- LLDP_MED_SUBTYPE_INV_FWREV = 6,
- LLDP_MED_SUBTYPE_INV_SWREV = 7,
- LLDP_MED_SUBTYPE_INV_SERIAL = 8,
- LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9,
- LLDP_MED_SUBTYPE_INV_MODELNAME = 10,
- LLDP_MED_SUBTYPE_INV_ASSETID = 11,
- _LLDP_MED_SUBTYPE_MAX,
- _LLDP_MED_SUBTYPE_INVALID = -1,
-} LLDPMedSubtype;
+#define _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \
+ ((uint16_t) \
+ (LLDP_SYSTEM_CAPABILITIES_REPEATER| \
+ LLDP_SYSTEM_CAPABILITIES_BRIDGE| \
+ LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \
+ LLDP_SYSTEM_CAPABILITIES_ROUTER| \
+ LLDP_SYSTEM_CAPABILITIES_DOCSIS| \
+ LLDP_SYSTEM_CAPABILITIES_CVLAN| \
+ LLDP_SYSTEM_CAPABILITIES_SVLAN| \
+ LLDP_SYSTEM_CAPABILITIES_TPMR))
-typedef enum LLDPMedCapability {
- LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0,
- LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1,
- LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2,
- LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3,
- LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4,
- LLDP_MED_CAPABILITY_INVENTORY = 1 << 5,
- LLDP_MED_CAPABILITY_MAX,
- LLDP_MED_CAPABILITY_INVALID = -1,
-} LLDPMedCapability;
#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
enum {
- LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1,
- LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2,
- LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3,
- LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4,
- LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5,
- LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6,
- LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7,
+ LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
+ LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
+ LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3,
+ LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
+ LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
+ LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
+ LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
};
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 62099dd3f4..d484c37a73 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -101,7 +101,7 @@ struct sd_dhcp_client {
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
sd_event_source *timeout_expire;
- sd_dhcp_client_cb_t cb;
+ sd_dhcp_client_callback_t cb;
void *userdata;
sd_dhcp_lease *lease;
usec_t start_delay;
@@ -121,7 +121,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
uint32_t revents, void *userdata);
static void client_stop(sd_dhcp_client *client, int error);
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
+int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb,
void *userdata) {
assert_return(client, -EINVAL);
@@ -1691,8 +1691,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) {
return 0;
}
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
- int priority) {
+int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
int r;
assert_return(client, -EINVAL);
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 54ff1a3f28..1c408aaaac 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -208,8 +208,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
return 0;
}
-int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
- int priority) {
+int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
int r;
assert_return(server, -EINVAL);
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 7d56d4cc60..af4709d788 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -64,7 +64,7 @@ struct sd_dhcp6_client {
uint8_t retransmit_count;
sd_event_source *timeout_resend;
sd_event_source *timeout_resend_expire;
- sd_dhcp6_client_cb_t cb;
+ sd_dhcp6_client_callback_t cb;
void *userdata;
struct duid duid;
size_t duid_len;
@@ -111,7 +111,7 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
-int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) {
+int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) {
assert_return(client, -EINVAL);
client->cb = cb;
@@ -1204,7 +1204,7 @@ error:
return r;
}
-int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) {
+int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) {
int r;
assert_return(client, -EINVAL);
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index f7880a891c..8a26cb8770 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -92,7 +92,7 @@ struct sd_ipv4acd {
struct ether_addr mac_addr;
sd_event *event;
int event_priority;
- sd_ipv4acd_cb_t cb;
+ sd_ipv4acd_callback_t cb;
void* userdata;
};
@@ -428,7 +428,7 @@ int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
return 0;
}
-int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) {
int r;
assert_return(ll, -EINVAL);
@@ -447,7 +447,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
return 0;
}
-int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) {
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->cb = cb;
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index db6cf22aaa..aca393aa5e 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -52,7 +52,7 @@ struct sd_ipv4ll {
/* External */
be32_t claimed_address;
- sd_ipv4ll_cb_t cb;
+ sd_ipv4ll_callback_t cb;
void* userdata;
};
@@ -160,7 +160,7 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
return sd_ipv4acd_detach_event(ll->acd);
}
-int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
+int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) {
int r;
assert_return(ll, -EINVAL);
@@ -172,7 +172,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
return 0;
}
-int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
+int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->cb = cb;
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 885ca62425..d0743cf3e2 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -1,21 +1,21 @@
/***
- This file is part of systemd.
+ This file is part of systemd.
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
+ Copyright (C) 2014 Tom Gundersen
+ Copyright (C) 2014 Susant Sahani
- 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 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.
+ 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 <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <arpa/inet.h>
@@ -24,733 +24,470 @@
#include "alloc-util.h"
#include "fd-util.h"
-#include "fileio.h"
-#include "hashmap.h"
#include "lldp-internal.h"
-#include "lldp-port.h"
-#include "lldp-tlv.h"
-#include "prioq.h"
-#include "siphash24.h"
-#include "string-util.h"
-
-typedef enum LLDPAgentRXState {
- LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
- LLDP_AGENT_RX_DELETE_AGED_INFO,
- LLDP_AGENT_RX_LLDP_INITIALIZE,
- LLDP_AGENT_RX_WAIT_FOR_FRAME,
- LLDP_AGENT_RX_RX_FRAME,
- LLDP_AGENT_RX_DELETE_INFO,
- LLDP_AGENT_RX_UPDATE_INFO,
- _LLDP_AGENT_RX_STATE_MAX,
- _LLDP_AGENT_RX_INVALID = -1,
-} LLDPAgentRXState;
-
-/* Section 10.5.2.2 Reception counters */
-struct lldp_agent_statistics {
- uint64_t stats_ageouts_total;
- uint64_t stats_frames_discarded_total;
- uint64_t stats_frames_in_errors_total;
- uint64_t stats_frames_in_total;
- uint64_t stats_tlvs_discarded_total;
- uint64_t stats_tlvs_unrecognized_total;
-};
-
-struct sd_lldp {
- lldp_port *port;
-
- Prioq *by_expiry;
- Hashmap *neighbour_mib;
-
- sd_lldp_cb_t cb;
-
- void *userdata;
-
- LLDPAgentRXState rx_state;
- lldp_agent_statistics statistics;
-};
-
-static void chassis_id_hash_func(const void *p, struct siphash *state) {
- const lldp_chassis_id *id = p;
-
- assert(id);
- assert(id->data);
-
- siphash24_compress(&id->length, sizeof(id->length), state);
- siphash24_compress(id->data, id->length, state);
-}
-
-static int chassis_id_compare_func(const void *_a, const void *_b) {
- const lldp_chassis_id *a, *b;
+#include "lldp-neighbor.h"
+#include "lldp-network.h"
+#include "socket-util.h"
+#include "ether-addr-util.h"
- a = _a;
- b = _b;
+#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
- assert(!a->length || a->data);
- assert(!b->length || b->data);
+static void lldp_flush_neighbors(sd_lldp *lldp) {
+ sd_lldp_neighbor *n;
- if (a->type != b->type)
- return -1;
-
- if (a->length != b->length)
- return a->length < b->length ? -1 : 1;
+ assert(lldp);
- return memcmp(a->data, b->data, a->length);
+ while ((n = hashmap_first(lldp->neighbor_by_id)))
+ lldp_neighbor_unlink(n);
}
-static const struct hash_ops chassis_id_hash_ops = {
- .hash = chassis_id_hash_func,
- .compare = chassis_id_compare_func
-};
-
-static void lldp_mib_delete_objects(sd_lldp *lldp);
-static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state);
-static void lldp_run_state_machine(sd_lldp *ll);
-
-static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) {
- int r;
-
+static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
assert(lldp);
- assert(tlv);
-
- /* Remove expired packets */
- if (prioq_size(lldp->by_expiry) > 0) {
+ assert(n);
- lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO);
+ log_lldp("Invoking callback for '%c'.", event);
- lldp_mib_delete_objects(lldp);
- }
+ if (!lldp->callback)
+ return;
- r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv);
- if (r < 0)
- goto out;
+ lldp->callback(lldp, event, n, lldp->userdata);
+}
- lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO);
+static int lldp_make_space(sd_lldp *lldp, size_t extra) {
+ usec_t t = USEC_INFINITY;
+ bool changed = false;
- log_lldp("Packet added. MIB size: %d , PQ size: %d",
- hashmap_size(lldp->neighbour_mib),
- prioq_size(lldp->by_expiry));
+ assert(lldp);
- lldp->statistics.stats_frames_in_total ++;
+ /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries
+ * are free. */
- out:
- if (r < 0)
- log_lldp("Receive frame failed: %s", strerror(-r));
+ for (;;) {
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
+ n = prioq_peek(lldp->neighbor_by_expiry);
+ if (!n)
+ break;
- return 0;
-}
+ sd_lldp_neighbor_ref(n);
-/* 10.3.2 LLDPDU validation: rxProcessFrame() */
-int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
- bool system_description = false, system_name = false, chassis_id = false;
- bool malformed = false, port_id = false, ttl = false, end = false;
- uint16_t type, len, i, l, t;
- lldp_port *port;
- uint8_t *p, *q;
- sd_lldp *lldp;
- int r;
+ if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra))
+ goto remove_one;
- assert(tlv);
- assert(length > 0);
+ if (t == USEC_INFINITY)
+ t = now(clock_boottime_or_monotonic());
- port = (lldp_port *) tlv->userdata;
- lldp = (sd_lldp *) port->userdata;
+ if (n->until > t)
+ break;
- if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) {
- log_lldp("Port: %s is disabled. Dropping.", lldp->port->ifname);
- goto out;
+ remove_one:
+ lldp_neighbor_unlink(n);
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n);
+ changed = true;
}
- lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME);
+ return changed;
+}
- p = tlv->pdu;
- p += sizeof(struct ether_header);
+static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
+ assert(lldp);
+ assert(n);
- for (i = 1, l = 0; l <= length; i++) {
+ /* Don't keep data with a zero TTL */
+ if (n->ttl <= 0)
+ return false;
- memcpy(&t, p, sizeof(uint16_t));
+ /* Filter out data from the filter address */
+ if (!ether_addr_is_null(&lldp->filter_address) &&
+ ether_addr_equal(&lldp->filter_address, &n->source_address))
+ return false;
- type = ntohs(t) >> 9;
- len = ntohs(t) & 0x01ff;
+ /* 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->capability_mask) == 0)
+ return false;
- if (type == LLDP_TYPE_END) {
- if (len != 0) {
- log_lldp("TLV type end must be length 0 (not %d). Dropping.", len);
+ /* Keep everything else */
+ return true;
+}
- malformed = true;
- goto out;
- }
+static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL;
+ bool keep;
+ int r;
- end = true;
+ assert(lldp);
+ assert(n);
+ assert(!n->lldp);
- break;
- } else if (type >=_LLDP_TYPE_MAX) {
- log_lldp("TLV type: %d not recognized. Dropping.", type);
+ keep = lldp_keep_neighbor(lldp, n);
- malformed = true;
- goto out;
- }
+ /* First retrieve the old entry for this MSAP */
+ old = hashmap_get(lldp->neighbor_by_id, &n->id);
+ if (old) {
+ sd_lldp_neighbor_ref(old);
- /* skip type and length encoding */
- p += 2;
- q = p;
+ if (!keep) {
+ lldp_neighbor_unlink(old);
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old);
+ return 0;
+ }
- p += len;
- l += (len + 2);
+ if (lldp_neighbor_equal(n, old)) {
+ /* Is this equal, then restart the TTL counter, but don't do anyting else. */
+ lldp_neighbor_start_ttl(old);
+ lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old);
+ return 0;
+ }
- if (i <= 3) {
- if (i != type) {
- log_lldp("TLV missing or out of order. Dropping.");
+ /* Data changed, remove the old entry, and add a new one */
+ lldp_neighbor_unlink(old);
- malformed = true;
- goto out;
- }
- }
+ } else if (!keep)
+ return 0;
- switch(type) {
- case LLDP_TYPE_CHASSIS_ID:
+ /* Then, make room for at least one new neighbor */
+ lldp_make_space(lldp, 1);
- if (len < 2) {
- log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len);
+ r = hashmap_put(lldp->neighbor_by_id, &n->id, n);
+ if (r < 0)
+ goto finish;
- malformed = true;
- goto out;
- }
+ r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx);
+ if (r < 0) {
+ assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n);
+ goto finish;
+ }
- if (chassis_id) {
- log_lldp("Duplicate Chassis ID TLV found. Dropping.");
+ n->lldp = lldp;
- malformed = true;
- goto out;
- }
+ lldp_neighbor_start_ttl(n);
+ lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n);
- /* Look what subtype it has */
- if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) {
- log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q);
+ return 1;
- malformed = true;
- goto out;
+finish:
+ if (old)
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n);
- }
+ return r;
+}
- chassis_id = true;
+static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) {
+ int r;
- break;
- case LLDP_TYPE_PORT_ID:
+ assert(lldp);
+ assert(n);
- if (len < 2) {
- log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len);
+ r = lldp_neighbor_parse(n);
+ if (r == -EBADMSG) /* Ignore bad messages */
+ return 0;
+ if (r < 0)
+ return r;
- malformed = true;
- goto out;
- }
+ r = lldp_add_neighbor(lldp, n);
+ if (r < 0) {
+ log_lldp_errno(r, "Failed to add datagram. Ignoring.");
+ return 0;
+ }
- if (port_id) {
- log_lldp("Duplicate Port ID TLV found. Dropping.");
+ log_lldp("Successfully processed LLDP datagram.");
+ return 0;
+}
- malformed = true;
- goto out;
- }
+static int lldp_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 *lldp = userdata;
- /* Look what subtype it has */
- if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) {
- log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q);
+ assert(fd >= 0);
+ assert(lldp);
- malformed = true;
- goto out;
+ space = next_datagram_size_fd(fd);
+ if (space < 0)
+ return log_lldp_errno(space, "Failed to determine datagram size to read: %m");
- }
+ n = lldp_neighbor_new(space);
+ if (!n)
+ return -ENOMEM;
- port_id = true;
+ length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
+ if (length < 0)
+ return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
- break;
- case LLDP_TYPE_TTL:
+ if ((size_t) length != n->raw_size) {
+ log_lldp("Packet size mismatch.");
+ return -EINVAL;
+ }
- if(len != 2) {
- log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len);
+ return lldp_handle_datagram(lldp, n);
+}
- malformed = true;
- goto out;
- }
+_public_ int sd_lldp_start(sd_lldp *lldp) {
+ int r;
- if (ttl) {
- log_lldp("Duplicate TTL TLV found. Dropping.");
+ assert_return(lldp, -EINVAL);
- malformed = true;
- goto out;
- }
+ if (lldp->fd >= 0)
+ return 0;
- ttl = true;
+ assert(!lldp->io_event_source);
- break;
- case LLDP_TYPE_SYSTEM_NAME:
+ lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex);
+ if (lldp->fd < 0)
+ return lldp->fd;
- /* According to RFC 1035 the length of a FQDN is limited to 255 characters */
- if (len > 255) {
- log_lldp("Received invalid system name length: %d. Dropping.", len);
- malformed = true;
- goto out;
- }
+ if (lldp->event) {
+ r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp);
+ if (r < 0)
+ goto fail;
- if (system_name) {
- log_lldp("Duplicate system name found. Dropping.");
- malformed = true;
- goto out;
- }
+ r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority);
+ if (r < 0)
+ goto fail;
- system_name = true;
+ (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io");
+ }
- break;
- case LLDP_TYPE_SYSTEM_DESCRIPTION:
-
- /* 0 <= n <= 255 octets */
- if (len > 255) {
- log_lldp("Received invalid system description length: %d. Dropping.", len);
- malformed = true;
- goto out;
- }
-
- if (system_description) {
- log_lldp("Duplicate system description found. Dropping.");
- malformed = true;
- goto out;
- }
-
- system_description = true;
- break;
- default:
+ return 1;
- if (len == 0) {
- log_lldp("TLV type: %d length 0 received. Dropping.", type);
+fail:
+ lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
+ lldp->fd = safe_close(lldp->fd);
- malformed = true;
- goto out;
- }
- break;
- }
- }
+ return r;
+}
- if(!chassis_id || !port_id || !ttl || !end) {
- log_lldp("One or more mandatory TLV missing. Dropping.");
+_public_ int sd_lldp_stop(sd_lldp *lldp) {
+ assert_return(lldp, -EINVAL);
- malformed = true;
- goto out;
+ if (lldp->fd < 0)
+ return 0;
- }
+ lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
+ lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
+ lldp->fd = safe_close(lldp->fd);
- r = tlv_packet_parse_pdu(tlv, length);
- if (r < 0) {
- log_lldp("Failed to parse the TLV. Dropping.");
+ lldp_flush_neighbors(lldp);
- malformed = true;
- goto out;
- }
+ return 1;
+}
- return lldp_receive_frame(lldp, tlv);
+_public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) {
+ int r;
- out:
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
+ assert_return(lldp, -EINVAL);
+ assert_return(lldp->fd < 0, -EBUSY);
+ assert_return(!lldp->event, -EBUSY);
- if (malformed) {
- lldp->statistics.stats_frames_discarded_total ++;
- lldp->statistics.stats_frames_in_errors_total ++;
+ if (event)
+ lldp->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&lldp->event);
+ if (r < 0)
+ return r;
}
- sd_lldp_packet_unref(tlv);
+ lldp->event_priority = priority;
return 0;
}
-static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) {
- const lldp_neighbour_port *p = a, *q = b;
-
- if (p->until < q->until)
- return -1;
+_public_ int sd_lldp_detach_event(sd_lldp *lldp) {
- if (p->until > q->until)
- return 1;
+ assert_return(lldp, -EINVAL);
+ assert_return(lldp->fd < 0, -EBUSY);
+ lldp->event = sd_event_unref(lldp->event);
return 0;
}
-static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) {
-
- assert(lldp);
- assert(state < _LLDP_AGENT_RX_STATE_MAX);
+_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) {
+ assert_return(lldp, -EINVAL);
- lldp->rx_state = state;
+ lldp->callback = cb;
+ lldp->userdata = userdata;
- lldp_run_state_machine(lldp);
+ return 0;
}
-static void lldp_run_state_machine(sd_lldp *lldp) {
- if (!lldp->cb)
- return;
-
- switch (lldp->rx_state) {
- case LLDP_AGENT_RX_UPDATE_INFO:
- lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata);
- break;
- default:
- break;
- }
-}
+_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
-/* 10.5.5.2.1 mibDeleteObjects ()
- * The mibDeleteObjects () procedure deletes all information in the LLDP remote
- * systems MIB associated with the MSAP identifier if an LLDPDU is received with
- * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */
+ if (!lldp)
+ return NULL;
-static void lldp_mib_delete_objects(sd_lldp *lldp) {
- lldp_neighbour_port *p;
- usec_t t = 0;
+ lldp_flush_neighbors(lldp);
- /* Remove all entries that are past their TTL */
- for (;;) {
+ hashmap_free(lldp->neighbor_by_id);
+ prioq_free(lldp->neighbor_by_expiry);
- if (prioq_size(lldp->by_expiry) <= 0)
- break;
+ sd_event_source_unref(lldp->io_event_source);
+ sd_event_source_unref(lldp->timer_event_source);
+ sd_event_unref(lldp->event);
+ safe_close(lldp->fd);
- p = prioq_peek(lldp->by_expiry);
- if (!p)
- break;
+ free(lldp);
- if (t <= 0)
- t = now(clock_boottime_or_monotonic());
+ return NULL;
+}
- if (p->until > t)
- break;
+_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) {
+ _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
+ int r;
- lldp_neighbour_port_remove_and_free(p);
+ assert_return(ret, -EINVAL);
+ assert_return(ifindex > 0, -EINVAL);
- lldp->statistics.stats_ageouts_total ++;
- }
-}
+ lldp = new0(sd_lldp, 1);
+ if (!lldp)
+ return -ENOMEM;
-static void lldp_mib_objects_flush(sd_lldp *lldp) {
- lldp_neighbour_port *p, *q;
- lldp_chassis *c;
+ lldp->fd = -1;
+ lldp->ifindex = ifindex;
+ lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX;
+ lldp->capability_mask = (uint16_t) -1;
- assert(lldp);
- assert(lldp->neighbour_mib);
- assert(lldp->by_expiry);
+ lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
+ if (!lldp->neighbor_by_id)
+ return -ENOMEM;
- /* Drop all packets */
- while ((c = hashmap_steal_first(lldp->neighbour_mib))) {
+ r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func);
+ if (r < 0)
+ return r;
- LIST_FOREACH_SAFE(port, p, q, c->ports) {
- lldp_neighbour_port_remove_and_free(p);
- }
- }
+ *ret = lldp;
+ lldp = NULL;
- assert(hashmap_size(lldp->neighbour_mib) == 0);
- assert(prioq_size(lldp->by_expiry) == 0);
+ return 0;
}
-int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
- _cleanup_free_ char *temp_path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- uint8_t *mac, *port_id, type;
- lldp_neighbour_port *p;
- uint16_t data = 0, length = 0;
- char buf[LINE_MAX];
- lldp_chassis *c;
- usec_t time;
- Iterator i;
- int r;
+static int neighbor_compare_func(const void *a, const void *b) {
+ const sd_lldp_neighbor * const*x = a, * const *y = b;
- assert(lldp);
- assert(lldp_file);
+ return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id);
+}
- r = fopen_temporary(lldp_file, &f, &temp_path);
- if (r < 0)
- goto fail;
-
- fchmod(fileno(f), 0644);
-
- HASHMAP_FOREACH(c, lldp->neighbour_mib, i) {
- LIST_FOREACH(port, p, c->ports) {
- _cleanup_free_ char *s = NULL;
- char *k, *t;
-
- r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length);
- if (r < 0)
- continue;
-
- sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
-
- s = strdup(buf);
- if (!s) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length);
- if (r < 0)
- continue;
-
- if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) {
- k = strndup((char *) port_id, length -1);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type);
- free(k);
- } else {
- mac = port_id;
- sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
- }
-
- k = strappend(s, buf);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- time = now(clock_boottime_or_monotonic());
-
- /* Don't write expired packets */
- if (time - p->until <= 0)
- continue;
-
- sprintf(buf, "'_TTL="USEC_FMT"' ", p->until);
-
- k = strappend(s, buf);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- r = sd_lldp_packet_read_system_name(p->packet, &k, &length);
- if (r < 0)
- k = strappend(s, "'_NAME=N/A' ");
- else {
- t = strndup(k, length);
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
-
- k = strjoin(s, "'_NAME=", t, "' ", NULL);
- free(t);
- }
-
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- (void) sd_lldp_packet_read_system_capability(p->packet, &data);
-
- sprintf(buf, "'_CAP=%x'", data);
-
- k = strappend(s, buf);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- fprintf(f, "%s\n", s);
- }
- }
+static int lldp_start_timer(sd_lldp *lldp);
+
+static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
+ sd_lldp *lldp = userdata;
+ int r, q;
- r = fflush_and_check(f);
+ r = lldp_make_space(lldp, 0);
if (r < 0)
- goto fail;
+ return log_lldp_errno(r, "Failed to make space: %m");
- if (rename(temp_path, lldp_file) < 0) {
- r = -errno;
- goto fail;
- }
+ q = lldp_start_timer(lldp);
+ if (q < 0)
+ return log_lldp_errno(q, "Failed to restart timer: %m");
return 0;
-
- fail:
- if (temp_path)
- (void) unlink(temp_path);
-
- return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file);
}
-int sd_lldp_start(sd_lldp *lldp) {
+static int lldp_start_timer(sd_lldp *lldp) {
+ sd_lldp_neighbor *n;
int r;
- assert_return(lldp, -EINVAL);
- assert_return(lldp->port, -EINVAL);
-
- lldp->port->status = LLDP_PORT_STATUS_ENABLED;
+ assert(lldp);
- lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE);
+ n = prioq_peek(lldp->neighbor_by_expiry);
+ if (!n) {
- r = lldp_port_start(lldp->port);
- if (r < 0) {
- log_lldp("Failed to start Port : %s , %s",
- lldp->port->ifname,
- strerror(-r));
+ if (lldp->timer_event_source)
+ return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF);
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL);
-
- return r;
+ return 0;
}
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
-
- return 0;
-}
-
-int sd_lldp_stop(sd_lldp *lldp) {
- int r;
+ if (lldp->timer_event_source) {
+ r = sd_event_source_set_time(lldp->timer_event_source, n->until);
+ if (r < 0)
+ return r;
- assert_return(lldp, -EINVAL);
- assert_return(lldp->port, -EINVAL);
+ return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT);
+ }
- lldp->port->status = LLDP_PORT_STATUS_DISABLED;
+ if (!lldp->event)
+ return 0;
- r = lldp_port_stop(lldp->port);
+ r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp);
if (r < 0)
return r;
- lldp_mib_objects_flush(lldp);
+ r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority);
+ if (r < 0)
+ return r;
+ (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer");
return 0;
}
-int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) {
- int r;
+_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
+ sd_lldp_neighbor **l = NULL, *n;
+ Iterator i;
+ int k = 0, r;
assert_return(lldp, -EINVAL);
- assert_return(!lldp->port->event, -EBUSY);
+ assert_return(ret, -EINVAL);
- if (event)
- lldp->port->event = sd_event_ref(event);
- else {
- r = sd_event_default(&lldp->port->event);
- if (r < 0)
- return r;
+ if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */
+ *ret = NULL;
+ return 0;
}
- lldp->port->event_priority = priority;
+ l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id));
+ if (!l)
+ return -ENOMEM;
- return 0;
-}
+ r = lldp_start_timer(lldp);
+ if (r < 0) {
+ free(l);
+ return r;
+ }
-int sd_lldp_detach_event(sd_lldp *lldp) {
+ HASHMAP_FOREACH(n, lldp->neighbor_by_id, i)
+ l[k++] = sd_lldp_neighbor_ref(n);
- assert_return(lldp, -EINVAL);
+ assert((size_t) k == hashmap_size(lldp->neighbor_by_id));
- lldp->port->event = sd_event_unref(lldp->port->event);
+ /* Return things in a stable order */
+ qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func);
+ *ret = l;
- return 0;
+ return k;
}
-int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) {
+_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) {
assert_return(lldp, -EINVAL);
+ assert_return(m <= 0, -EINVAL);
- lldp->cb = cb;
- lldp->userdata = userdata;
+ lldp->neighbors_max = m;
+ lldp_make_space(lldp, 0);
return 0;
}
-sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
-
- if (!lldp)
- return NULL;
-
- /* Drop all packets */
- lldp_mib_objects_flush(lldp);
-
- lldp_port_free(lldp->port);
-
- hashmap_free(lldp->neighbour_mib);
- prioq_free(lldp->by_expiry);
-
- free(lldp);
- return NULL;
-}
-
-int sd_lldp_new(int ifindex,
- const char *ifname,
- const struct ether_addr *mac,
- sd_lldp **ret) {
- _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
- int r;
-
- assert_return(ret, -EINVAL);
- assert_return(ifindex > 0, -EINVAL);
- assert_return(ifname, -EINVAL);
- assert_return(mac, -EINVAL);
-
- lldp = new0(sd_lldp, 1);
- if (!lldp)
- return -ENOMEM;
-
- r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port);
- if (r < 0)
- return r;
-
- lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops);
- if (!lldp->neighbour_mib)
- return -ENOMEM;
-
- r = prioq_ensure_allocated(&lldp->by_expiry,
- ttl_expiry_item_prioq_compare_func);
- if (r < 0)
- return r;
-
- lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL;
+_public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) {
+ assert_return(lldp, -EINVAL);
+ assert_return(mask != 0, -EINVAL);
- *ret = lldp;
- lldp = NULL;
+ lldp->capability_mask = mask;
return 0;
}
-int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) {
- lldp_neighbour_port *p;
- lldp_chassis *c;
- Iterator iter;
- unsigned count = 0, i;
-
+_public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) {
assert_return(lldp, -EINVAL);
- assert_return(tlvs, -EINVAL);
- HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
- LIST_FOREACH(port, p, c->ports)
- count++;
- }
+ /* 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 (!count) {
- *tlvs = NULL;
+ if (!addr) {
+ zero(lldp->filter_address);
return 0;
}
- *tlvs = new(sd_lldp_packet *, count);
- if (!*tlvs)
- return -ENOMEM;
-
- i = 0;
- HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
- LIST_FOREACH(port, p, c->ports)
- (*tlvs)[i++] = sd_lldp_packet_ref(p->packet);
- }
-
- return count;
+ lldp->filter_address = *addr;
+ return 0;
}
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index bae6a49fe6..fb4ef55673 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -166,7 +166,7 @@ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
}
-int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) {
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
int r;
assert_return(nd, -EINVAL);
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index b8490073dd..da4ce293bc 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -22,6 +22,7 @@
#include <net/ethernet.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "sd-event.h"
#include "sd-lldp.h"
@@ -29,7 +30,6 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "lldp-network.h"
-#include "lldp-tlv.h"
#include "lldp.h"
#include "macro.h"
#include "string-util.h"
@@ -38,211 +38,8 @@
#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
-static int test_fd[2];
-
-static struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
-};
-
-static int lldp_build_tlv_packet(tlv_packet **ret) {
- _cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL;
- const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
- struct ether_header ether = {
- .ether_type = htons(ETHERTYPE_LLDP),
- };
-
- /* Append Ethernet header */
- memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
- memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
-
- assert_se(tlv_packet_new(&m) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
-
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
-
- assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
- assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* port name */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
-
- assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* ttl */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
-
- assert_se(tlv_packet_append_u16(m, 170) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* system name */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
- strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* system descrition */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
- strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* Mark end of packet */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- *ret = m;
-
- m = NULL;
-
- return 0;
-}
-
-static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
- uint8_t *p, subtype;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
- assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
- assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
-
- assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
-
- break;
- default:
- assert_not_reached("Unhandled option");
- }
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_port_id_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
- uint8_t subtype;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
-
- assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
-
- switch (subtype) {
- case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length-1);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_PORT) == 1);
- break;
- default:
- assert_not_reached("Unhandled option");
- }
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_system_name_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 1;
-}
-
-static int lldp_parse_system_desc_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_ttl_tlv(tlv_packet *m) {
- uint16_t ttl;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
- assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
-
- assert_se(ttl == 170);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_get_destination_type(tlv_packet *m) {
- int dest;
-
- assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
- assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
-
- return 0;
-}
-
-static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
- uint8_t subtype;
-
- assert_se(tlv_packet_parse_pdu(m, len) >= 0);
- assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
- assert_se(lldp_parse_port_id_tlv(m) >= 0);
- assert_se(lldp_parse_system_name_tlv(m) >= 0);
- assert_se(lldp_parse_ttl_tlv(m) >= 0);
- assert_se(lldp_parse_system_desc_tlv(m) >= 0);
-
- assert_se(lldp_get_destination_type(m) >= 0);
-
- return 0;
-}
-
-static void test_parser(void) {
- _cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL;
-
- /* form a packet */
- lldp_build_tlv_packet(&tlv);
- /* parse the packet */
- tlv_packet_parse_pdu(tlv, tlv->length);
- /* verify */
- lldp_parse_tlv_packet(tlv, tlv->length);
-}
+static int test_fd[2] = { -1, -1 };
+static int lldp_handler_calls;
int lldp_network_bind_raw_socket(int ifindex) {
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
@@ -251,28 +48,27 @@ int lldp_network_bind_raw_socket(int ifindex) {
return test_fd[0];
}
-static int lldp_handler_calls;
-static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
+static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
lldp_handler_calls++;
}
-static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
+static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
int r;
- r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
- if (r)
+ r = sd_lldp_new(lldp, 42);
+ if (r < 0)
return r;
r = sd_lldp_attach_event(*lldp, e, 0);
- if (r)
+ if (r < 0)
return r;
r = sd_lldp_set_callback(*lldp, cb, cb_data);
- if (r)
+ if (r < 0)
return r;
r = sd_lldp_start(*lldp);
- if (r)
+ if (r < 0)
return r;
return 0;
@@ -282,11 +78,11 @@ static int stop_lldp(sd_lldp *lldp) {
int r;
r = sd_lldp_stop(lldp);
- if (r)
+ if (r < 0)
return r;
r = sd_lldp_detach_event(lldp);
- if (r)
+ if (r < 0)
return r;
sd_lldp_unref(lldp);
@@ -296,13 +92,8 @@ static int stop_lldp(sd_lldp *lldp) {
}
static void test_receive_basic_packet(sd_event *e) {
- sd_lldp *lldp;
- sd_lldp_packet **packets;
- uint8_t type, *data;
- uint16_t length, ttl;
- int dest_type;
- char *str;
- uint8_t frame[] = {
+
+ static const uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
@@ -319,51 +110,53 @@ static void test_receive_basic_packet(sd_event *e) {
0x00, 0x00 /* End Of LLDPDU */
};
+ sd_lldp *lldp;
+ sd_lldp_neighbor **neighbors;
+ uint8_t type;
+ const void *data;
+ uint16_t ttl;
+ size_t length;
+ const char *str;
+
lldp_handler_calls = 0;
assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 1);
- assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
+ assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
- assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
+ assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0);
assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
assert_se(length == ETH_ALEN);
assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
- assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
+ assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0);
assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
assert_se(length == 3);
assert_se(strneq((char *) data, "1/3", 3));
- assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
- assert_se(length == 4);
- assert_se(strneq(str, "Port", 4));
+ assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0);
+ assert_se(streq(str, "Port"));
- assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
- assert_se(length == 3);
- assert_se(strneq(str, "SYS", 3));
+ assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0);
+ assert_se(streq(str, "SYS"));
- assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
- assert_se(length == 4); /* This is the real length in the TLV packet */
- assert_se(strneq(str, "foo", 3));
+ assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0);
+ assert_se(streq(str, "foo"));
- assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
+ assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0);
assert_se(ttl == 120);
- assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
- assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
-
- sd_lldp_packet_unref(packets[0]);
- free(packets);
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_incomplete_packet(sd_event *e) {
sd_lldp *lldp;
- sd_lldp_packet **packets;
+ sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -383,18 +176,14 @@ static void test_receive_incomplete_packet(sd_event *e) {
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 0);
- assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
+ assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_oui_packet(sd_event *e) {
sd_lldp *lldp;
- sd_lldp_packet **packets;
- uint32_t id32;
- uint16_t id16, len;
- uint8_t flags;
- char *str;
+ sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -426,29 +215,30 @@ static void test_receive_oui_packet(sd_event *e) {
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 1);
- assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
-
- assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
- assert_se(id16 == 0x1234);
-
- assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
- assert_se(flags == 1);
- assert_se(id16 == 0x7788);
-
- assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
- assert_se(id16 == 0x1234);
- assert_se(len == 6);
- assert_se(strneq(str, "Vlan51", 6));
-
- assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
- assert_se(id16 == 0x0102);
-
- assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
- assert_se(flags == 1);
- assert_se(id32 == 0x00140012);
-
- sd_lldp_packet_unref(packets[0]);
- free(packets);
+ assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
+
+ assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_CHASSIS_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_PORT_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_TTL) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_END) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0);
+
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
@@ -456,7 +246,7 @@ static void test_receive_oui_packet(sd_event *e) {
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
- test_parser();
+ log_set_max_level(LOG_DEBUG);
/* LLDP reception tests */
assert_se(sd_event_new(&e) == 0);
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h
index b96441de56..ab222e27de 100644
--- a/src/libsystemd/sd-device/device-internal.h
+++ b/src/libsystemd/sd-device/device-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "hashmap.h"
#include "set.h"
diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h
index 13fddfc8ad..8ffb5e5c74 100644
--- a/src/libsystemd/sd-hwdb/hwdb-internal.h
+++ b/src/libsystemd/sd-hwdb/hwdb-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -16,7 +18,6 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
#include "sparse-endian.h"
#include "util.h"
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index 090552f576..255526bf32 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -616,7 +616,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
return 0;
}
-int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index 4833815b43..f5c2b33f46 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -774,7 +774,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
return 1;
}
-int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
+int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
int r;
assert_return(rtnl, -EINVAL);
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index 62051992ef..580047d3ab 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -31,6 +31,7 @@
#include "fs-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -102,16 +103,16 @@ _public_ int sd_network_get_route_domains(char ***ret) {
}
static int network_link_get_string(int ifindex, const char *field, char **ret) {
- _cleanup_free_ char *s = NULL, *p = NULL;
+ char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
+ _cleanup_free_ char *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
- if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0)
- return -ENOMEM;
+ xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
- r = parse_env_file(p, NEWLINE, field, &s, NULL);
+ r = parse_env_file(path, NEWLINE, field, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@@ -126,17 +127,16 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) {
}
static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
- _cleanup_free_ char *p = NULL, *s = NULL;
+ char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
_cleanup_strv_free_ char **a = NULL;
+ _cleanup_free_ char *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
- if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
- return -ENOMEM;
-
- r = parse_env_file(p, NEWLINE, key, &s, NULL);
+ xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
+ r = parse_env_file(path, NEWLINE, key, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@@ -187,32 +187,7 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char
return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
}
-_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
- _cleanup_free_ char *s = NULL, *p = NULL;
- size_t size;
- int r;
-
- assert_return(ifindex > 0, -EINVAL);
- assert_return(lldp, -EINVAL);
-
- if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
- return -ENOMEM;
-
- r = read_full_file(p, &s, &size);
- if (r == -ENOENT)
- return -ENODATA;
- if (r < 0)
- return r;
- if (size <= 0)
- return -ENODATA;
-
- *lldp = s;
- s = NULL;
-
- return 0;
-}
-
-int sd_network_link_get_timezone(int ifindex, char **ret) {
+_public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
return network_link_get_string(ifindex, "TIMEZONE", ret);
}
@@ -232,12 +207,65 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
}
-_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
- return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret);
+static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
+ char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
+ _cleanup_strv_free_ char **a = NULL;
+ _cleanup_free_ int *ifis = NULL;
+ _cleanup_free_ char *s = NULL;
+ size_t allocated = 0, c = 0;
+ const char *x;
+ int r;
+
+ assert_return(ifindex > 0, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
+ r = parse_env_file(path, NEWLINE, key, &s, NULL);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+ if (isempty(s)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ x = s;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&x, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = parse_ifindex(word, &ifindex);
+ if (r < 0)
+ return r;
+
+ if (!GREEDY_REALLOC(ifis, allocated, c + 1))
+ return -ENOMEM;
+
+ ifis[c++] = ifindex;
+ }
+
+ if (!GREEDY_REALLOC(ifis, allocated, c + 1))
+ return -ENOMEM;
+ ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/
+
+ *ret = ifis;
+ ifis = NULL;
+
+ return c;
+}
+
+_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
+ return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
}
-_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
- return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret);
+_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
+ return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
}
static inline int MONITOR_TO_FD(sd_network_monitor *m) {
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index d693b2c2b0..910e75441f 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -1191,7 +1191,7 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd
return 1;
}
-_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
+_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) {
int r;
assert_return(resolve, -EINVAL);
diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h
index 40d59201cf..0e9af8ec09 100644
--- a/src/libudev/libudev-device-internal.h
+++ b/src/libudev/libudev-device-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "libudev.h"
#include "sd-device.h"
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 60724fce80..d1aec9a7dc 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -23,6 +23,7 @@
#include "sd-device.h"
#include "sd-hwdb.h"
+#include "sd-lldp.h"
#include "sd-netlink.h"
#include "sd-network.h"
@@ -30,6 +31,7 @@
#include "arphrd-list.h"
#include "device-util.h"
#include "ether-addr-util.h"
+#include "fd-util.h"
#include "hwdb-util.h"
#include "lldp.h"
#include "local-addresses.h"
@@ -38,6 +40,7 @@
#include "pager.h"
#include "parse-util.h"
#include "socket-util.h"
+#include "sparse-endian.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
@@ -58,7 +61,7 @@ static void pager_open_if_enabled(void) {
pager_open(false);
}
-static int link_get_type_string(int iftype, sd_device *d, char **ret) {
+static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) {
const char *t;
char *p;
@@ -70,7 +73,7 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) {
* to show a more useful type string for
* them */
- (void)sd_device_get_devtype(d, &devtype);
+ (void) sd_device_get_devtype(d, &devtype);
if (streq_ptr(devtype, "wlan"))
id = "wlan";
@@ -103,10 +106,46 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) {
return 0;
}
+static void operational_state_to_color(const char *state, const char **on, const char **off) {
+ assert(on);
+ assert(off);
+
+ if (streq_ptr(state, "routable")) {
+ *on = ansi_highlight_green();
+ *off = ansi_normal();
+ } else if (streq_ptr(state, "degraded")) {
+ *on = ansi_highlight_yellow();
+ *off = ansi_normal();
+ } else
+ *on = *off = "";
+}
+
+static void setup_state_to_color(const char *state, const char **on, const char **off) {
+ assert(on);
+ assert(off);
+
+ if (streq_ptr(state, "configured")) {
+ *on = ansi_highlight_green();
+ *off = ansi_normal();
+ } else if (streq_ptr(state, "configuring")) {
+ *on = ansi_highlight_yellow();
+ *off = ansi_normal();
+ } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
+ *on = ansi_highlight_red();
+ *off = ansi_normal();
+ } else
+ *on = *off = "";
+}
+
typedef struct LinkInfo {
- const char *name;
+ char name[IFNAMSIZ+1];
int ifindex;
- unsigned iftype;
+ unsigned short iftype;
+ struct ether_addr mac_address;
+ uint32_t mtu;
+
+ bool has_mac_address:1;
+ bool has_mtu:1;
} LinkInfo;
static int link_info_compare(const void *a, const void *b) {
@@ -115,44 +154,85 @@ static int link_info_compare(const void *a, const void *b) {
return x->ifindex - y->ifindex;
}
-static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) {
+static int decode_link(sd_netlink_message *m, LinkInfo *info) {
+ static const struct ether_addr null_address = {};
+ const char *name;
+ uint16_t type;
+ int r;
+
+ assert(m);
+ assert(info);
+
+ r = sd_netlink_message_get_type(m, &type);
+ if (r < 0)
+ return r;
+
+ if (type != RTM_NEWLINK)
+ return 0;
+
+ r = sd_rtnl_message_link_get_ifindex(m, &info->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_link_get_type(m, &info->iftype);
+ if (r < 0)
+ return r;
+
+ strncpy(info->name, name, sizeof(info->name));
+
+ info->has_mac_address =
+ sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
+ memcmp(&info->mac_address, &null_address, sizeof(struct ether_addr)) != 0;
+
+ info->has_mtu =
+ sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) &&
+ info->mtu > 0;
+
+ return 1;
+}
+
+static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) {
_cleanup_free_ LinkInfo *links = NULL;
- size_t size = 0, c = 0;
- sd_netlink_message *i;
+ char **i;
+ size_t c = 0;
int r;
- for (i = m; i; i = sd_netlink_message_next(i)) {
- const char *name;
- unsigned iftype;
- uint16_t type;
- int ifindex;
+ assert(rtnl);
+ assert(ret);
- r = sd_netlink_message_get_type(i, &type);
- if (r < 0)
- return r;
+ links = new(LinkInfo, strv_length(l));
+ if (!links)
+ return log_oom();
- if (type != RTM_NEWLINK)
- continue;
+ STRV_FOREACH(i, l) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ int ifindex;
- r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
+ if (parse_ifindex(*i, &ifindex) >= 0)
+ r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
+ else {
+ r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
+ if (r < 0)
+ return rtnl_log_create_error(r);
+
+ r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i);
+ }
if (r < 0)
- return r;
+ return rtnl_log_create_error(r);
- r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
+ r = sd_netlink_call(rtnl, req, 0, &reply);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to request link: %m");
- r = sd_rtnl_message_link_get_type(i, &iftype);
+ r = decode_link(reply, links + c);
if (r < 0)
return r;
-
- if (!GREEDY_REALLOC(links, size, c+1))
- return -ENOMEM;
-
- links[c].name = name;
- links[c].ifindex = ifindex;
- links[c].iftype = iftype;
- c++;
+ if (r > 0)
+ c++;
}
qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
@@ -163,48 +243,15 @@ static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) {
return (int) c;
}
-static void operational_state_to_color(const char *state, const char **on, const char **off) {
- assert(on);
- assert(off);
-
- if (streq_ptr(state, "routable")) {
- *on = ansi_highlight_green();
- *off = ansi_normal();
- } else if (streq_ptr(state, "degraded")) {
- *on = ansi_highlight_yellow();
- *off = ansi_normal();
- } else
- *on = *off = "";
-}
-
-static void setup_state_to_color(const char *state, const char **on, const char **off) {
- assert(on);
- assert(off);
-
- if (streq_ptr(state, "configured")) {
- *on = ansi_highlight_green();
- *off = ansi_normal();
- } else if (streq_ptr(state, "configuring")) {
- *on = ansi_highlight_yellow();
- *off = ansi_normal();
- } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
- *on = ansi_highlight_red();
- *off = ansi_normal();
- } else
- *on = *off = "";
-}
-
-static int list_links(int argc, char *argv[], void *userdata) {
+static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
- int r, c, i;
-
- pager_open_if_enabled();
+ size_t allocated = 0, c = 0;
+ sd_netlink_message *i;
+ int r;
- r = sd_netlink_open(&rtnl);
- if (r < 0)
- return log_error_errno(r, "Failed to connect to netlink: %m");
+ assert(rtnl);
+ assert(ret);
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
@@ -218,12 +265,50 @@ static int list_links(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
- if (arg_legend)
- printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
+ for (i = reply; i; i = sd_netlink_message_next(i)) {
+ if (!GREEDY_REALLOC(links, allocated, c+1))
+ return -ENOMEM;
+
+ r = decode_link(i, links + c);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ c++;
+ }
+
+ qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
+
+ *ret = links;
+ links = NULL;
+
+ return (int) c;
+}
+
+static int list_links(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_free_ LinkInfo *links = NULL;
+ int c, i, r;
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
- c = decode_and_sort_links(reply, &links);
+ if (argc > 1)
+ c = acquire_link_info_strv(rtnl, argv + 1, &links);
+ else
+ c = acquire_link_info_all(rtnl, &links);
if (c < 0)
- return rtnl_log_parse_error(c);
+ return c;
+
+ pager_open_if_enabled();
+
+ if (arg_legend)
+ printf("%3s %-16s %-18s %-11s %-10s\n",
+ "IDX",
+ "LINK",
+ "TYPE",
+ "OPERATIONAL",
+ "SETUP");
for (i = 0; i < c; i++) {
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
@@ -233,16 +318,18 @@ static int list_links(int argc, char *argv[], void *userdata) {
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL;
- sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
+ (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
+ r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
+ if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
+ setup_state = strdup("unmanaged");
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
- sprintf(devid, "n%i", links[i].ifindex);
- (void)sd_device_new_from_device_id(&d, devid);
+ xsprintf(devid, "n%i", links[i].ifindex);
+ (void) sd_device_new_from_device_id(&d, devid);
- link_get_type_string(links[i].iftype, d, &t);
+ (void) link_get_type_string(links[i].iftype, d, &t);
printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
links[i].ifindex, links[i].name, strna(t),
@@ -257,7 +344,7 @@ static int list_links(int argc, char *argv[], void *userdata) {
}
/* IEEE Organizationally Unique Identifier vendor string */
-static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
+static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
const char *description;
char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
int r;
@@ -404,6 +491,9 @@ static int dump_gateways(
_cleanup_free_ struct local_address *local = NULL;
int r, n, i;
+ assert(rtnl);
+ assert(prefix);
+
n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
if (n < 0)
return n;
@@ -453,6 +543,9 @@ static int dump_addresses(
_cleanup_free_ struct local_address *local = NULL;
int r, n, i;
+ assert(rtnl);
+ assert(prefix);
+
n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
if (n < 0)
return n;
@@ -485,6 +578,116 @@ static int dump_addresses(
return 0;
}
+static int open_lldp_neighbors(int ifindex, FILE **ret) {
+ _cleanup_free_ char *p = NULL;
+ FILE *f;
+
+ if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0)
+ return -ENOMEM;
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ *ret = f;
+ return 0;
+}
+
+static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
+ _cleanup_free_ void *raw = NULL;
+ size_t l;
+ le64_t u;
+ int r;
+
+ assert(f);
+ assert(ret);
+
+ l = fread(&u, 1, sizeof(u), f);
+ if (l == 0 && feof(f))
+ return 0;
+ if (l != sizeof(u))
+ return -EBADMSG;
+
+ raw = new(uint8_t, le64toh(u));
+ if (!raw)
+ return -ENOMEM;
+
+ if (fread(raw, 1, le64toh(u), f) != le64toh(u))
+ return -EBADMSG;
+
+ r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int dump_lldp_neighbors(const char *prefix, int ifindex) {
+ _cleanup_fclose_ FILE *f = NULL;
+ int r, c = 0;
+
+ assert(prefix);
+ assert(ifindex > 0);
+
+ r = open_lldp_neighbors(ifindex, &f);
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
+
+ r = next_lldp_neighbor(f, &n);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ printf("%*s",
+ (int) strlen(prefix),
+ c == 0 ? prefix : "");
+
+ (void) sd_lldp_neighbor_get_system_name(n, &system_name);
+ (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
+ (void) sd_lldp_neighbor_get_port_description(n, &port_description);
+
+ printf("%s on port %s", strna(system_name), strna(port_id));
+
+ if (!isempty(port_description))
+ printf(" (%s)", port_description);
+
+ putchar('\n');
+
+ c++;
+ }
+
+ return c;
+}
+
+static void dump_ifindexes(const char *prefix, const int *ifindexes) {
+ unsigned c;
+
+ assert(prefix);
+
+ if (!ifindexes || ifindexes[0] <= 0)
+ return;
+
+ for (c = 0; ifindexes[c] > 0; c++) {
+ char name[IF_NAMESIZE+1];
+
+ printf("%*s",
+ (int) strlen(prefix),
+ c == 0 ? prefix : "");
+
+ if (if_indextoname(ifindexes[c], name))
+ fputs(name, stdout);
+ else
+ printf("%i", ifindexes[c]);
+
+ fputc('\n', stdout);
+ }
+}
+
static void dump_list(const char *prefix, char **l) {
char **i;
@@ -502,85 +705,36 @@ static void dump_list(const char *prefix, char **l) {
static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
- const char *name) {
+ const LinkInfo *info) {
+
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL, *network = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
- _cleanup_strv_free_ char **carrier_bound_to = NULL;
- _cleanup_strv_free_ char **carrier_bound_by = NULL;
- struct ether_addr e;
- unsigned iftype;
- int r, ifindex;
- bool have_mac;
- uint32_t mtu;
+ _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
+ int r;
assert(rtnl);
- assert(name);
-
- if (parse_ifindex(name, &ifindex) >= 0)
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
- else {
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_message_append_string(req, IFLA_IFNAME, name);
- }
-
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_call(rtnl, req, 0, &reply);
- if (r < 0)
- return log_error_errno(r, "Failed to query link: %m");
-
- r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
- if (r < 0)
- return rtnl_log_parse_error(r);
-
- r = sd_netlink_message_read_string(reply, IFLA_IFNAME, &name);
- if (r < 0)
- return rtnl_log_parse_error(r);
-
- r = sd_rtnl_message_link_get_type(reply, &iftype);
- if (r < 0)
- return rtnl_log_parse_error(r);
+ assert(info);
- have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
- if (have_mac) {
- const uint8_t *p;
- bool all_zeroes = true;
-
- for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
- if (*p != 0) {
- all_zeroes = false;
- break;
- }
-
- if (all_zeroes)
- have_mac = false;
- }
-
- (void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
-
- (void) sd_network_link_get_operational_state(ifindex, &operational_state);
+ (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- (void) sd_network_link_get_setup_state(ifindex, &setup_state);
+ r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
+ if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
+ setup_state = strdup("unmanaged");
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
- (void) sd_network_link_get_dns(ifindex, &dns);
- (void) sd_network_link_get_search_domains(ifindex, &search_domains);
- (void) sd_network_link_get_route_domains(ifindex, &route_domains);
- (void) sd_network_link_get_ntp(ifindex, &ntp);
+ (void) sd_network_link_get_dns(info->ifindex, &dns);
+ (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
+ (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
+ (void) sd_network_link_get_ntp(info->ifindex, &ntp);
- sprintf(devid, "n%i", ifindex);
+ xsprintf(devid, "n%i", info->ifindex);
(void) sd_device_new_from_device_id(&d, devid);
@@ -598,14 +752,14 @@ static int link_status_one(
(void) sd_device_get_property_value(d, "ID_MODEL", &model);
}
- link_get_type_string(iftype, d, &t);
+ (void) link_get_type_string(info->iftype, d, &t);
- sd_network_link_get_network_file(ifindex, &network);
+ (void) sd_network_link_get_network_file(info->ifindex, &network);
- sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
- sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
+ (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
+ (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
- printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
+ printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name);
printf(" Link File: %s\n"
" Network File: %s\n"
@@ -626,23 +780,23 @@ static int link_status_one(
if (model)
printf(" Model: %s\n", model);
- if (have_mac) {
+ if (info->has_mac_address) {
_cleanup_free_ char *description = NULL;
char ea[ETHER_ADDR_TO_STRING_MAX];
- ieee_oui(hwdb, &e, &description);
+ (void) ieee_oui(hwdb, &info->mac_address, &description);
if (description)
- printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
+ printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info->mac_address, ea), description);
else
- printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
+ printf(" HW Address: %s\n", ether_addr_to_string(&info->mac_address, ea));
}
- if (mtu > 0)
- printf(" MTU: %u\n", mtu);
+ if (info->has_mtu)
+ printf(" MTU: %u\n", info->mtu);
- dump_addresses(rtnl, " Address: ", ifindex);
- dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
+ (void) dump_addresses(rtnl, " Address: ", info->ifindex);
+ (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex);
dump_list(" DNS: ", dns);
dump_list(" Search Domains: ", search_domains);
@@ -650,363 +804,205 @@ static int link_status_one(
dump_list(" NTP: ", ntp);
- dump_list("Carrier Bound To: ", carrier_bound_to);
- dump_list("Carrier Bound By: ", carrier_bound_by);
+ dump_ifindexes("Carrier Bound To: ", carrier_bound_to);
+ dump_ifindexes("Carrier Bound By: ", carrier_bound_by);
- (void) sd_network_link_get_timezone(ifindex, &tz);
+ (void) sd_network_link_get_timezone(info->ifindex, &tz);
if (tz)
- printf(" Time Zone: %s", tz);
+ printf(" Time Zone: %s\n", tz);
+
+ (void) dump_lldp_neighbors(" Connected To: ", info->ifindex);
return 0;
}
-static int link_status(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- char **name;
- int r;
-
- r = sd_netlink_open(&rtnl);
- if (r < 0)
- return log_error_errno(r, "Failed to connect to netlink: %m");
+static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
+ _cleanup_free_ char *operational_state = NULL;
+ _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
+ const char *on_color_operational, *off_color_operational;
- r = sd_hwdb_new(&hwdb);
- if (r < 0)
- log_debug_errno(r, "Failed to open hardware database: %m");
+ assert(rtnl);
- if (argc <= 1 && !arg_all) {
- _cleanup_free_ char *operational_state = NULL;
- _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains;
- const char *on_color_operational, *off_color_operational;
+ (void) sd_network_get_operational_state(&operational_state);
+ operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- sd_network_get_operational_state(&operational_state);
- operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
+ printf("%s%s%s State: %s%s%s\n",
+ on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
+ on_color_operational, strna(operational_state), off_color_operational);
- printf("%s%s%s State: %s%s%s\n",
- on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
- on_color_operational, strna(operational_state), off_color_operational);
+ (void) dump_addresses(rtnl, " Address: ", 0);
+ (void) dump_gateways(rtnl, hwdb, " Gateway: ", 0);
- dump_addresses(rtnl, " Address: ", 0);
- dump_gateways(rtnl, hwdb, " Gateway: ", 0);
+ (void) sd_network_get_dns(&dns);
+ dump_list(" DNS: ", dns);
- sd_network_get_dns(&dns);
- dump_list(" DNS: ", dns);
+ (void) sd_network_get_search_domains(&search_domains);
+ dump_list("Search Domains: ", search_domains);
- sd_network_get_search_domains(&search_domains);
- dump_list("Search Domains: ", search_domains);
+ (void) sd_network_get_route_domains(&route_domains);
+ dump_list(" Route Domains: ", route_domains);
- sd_network_get_route_domains(&route_domains);
- dump_list(" Route Domains: ", route_domains);
+ (void) sd_network_get_ntp(&ntp);
+ dump_list(" NTP: ", ntp);
- sd_network_get_ntp(&ntp);
- dump_list(" NTP: ", ntp);
+ return 0;
+}
- return 0;
- }
+static int link_status(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
+ _cleanup_free_ LinkInfo *links = NULL;
+ int r, c, i;
pager_open_if_enabled();
- if (arg_all) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_free_ LinkInfo *links = NULL;
- int c, i;
-
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_message_request_dump(req, true);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_call(rtnl, req, 0, &reply);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate links: %m");
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
- c = decode_and_sort_links(reply, &links);
- if (c < 0)
- return rtnl_log_parse_error(c);
+ r = sd_hwdb_new(&hwdb);
+ if (r < 0)
+ log_debug_errno(r, "Failed to open hardware database: %m");
- for (i = 0; i < c; i++) {
- if (i > 0)
- fputc('\n', stdout);
+ if (arg_all)
+ c = acquire_link_info_all(rtnl, &links);
+ else if (argc <= 1)
+ return system_status(rtnl, hwdb);
+ else
+ c = acquire_link_info_strv(rtnl, argv + 1, &links);
+ if (c < 0)
+ return c;
- link_status_one(rtnl, hwdb, links[i].name);
- }
- } else {
- STRV_FOREACH(name, argv + 1) {
- if (name != argv + 1)
- fputc('\n', stdout);
+ for (i = 0; i < c; i++) {
+ if (i > 0)
+ fputc('\n', stdout);
- link_status_one(rtnl, hwdb, *name);
- }
+ link_status_one(rtnl, hwdb, links + i);
}
return 0;
}
-const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
-LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
-
-static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
- [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
- [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
- [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
- [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
- [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
- [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
- [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
- [LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
- [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
- [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
- [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
- [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
-
-static char *lldp_system_caps(uint16_t cap) {
- _cleanup_free_ char *s = NULL, *t = NULL;
- char *capability;
-
- t = strdup("[ ");
- if (!t)
- return NULL;
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
- s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
- if (!s)
- return NULL;
-
- free(t);
- }
-
- if (!s) {
- s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
- if (!s)
- return NULL;
-
- free(t);
- }
+static char *lldp_capabilities_to_string(uint16_t x) {
+ static const char characters[] = {
+ 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
+ };
+ char *ret;
+ unsigned i;
- t = strappend(s, "]");
- if (!t)
+ ret = new(char, ELEMENTSOF(characters) + 1);
+ if (!ret)
return NULL;
- free(s);
- capability = t;
+ for (i = 0; i < ELEMENTSOF(characters); i++)
+ ret[i] = (x & (1U << i)) ? characters[i] : '.';
- s = NULL;
- t = NULL;
-
- return capability;
+ ret[i] = 0;
+ return ret;
}
static int link_lldp_status(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
- double ttl = -1;
- uint32_t capability;
- int i, r, c, j;
- const char *p;
- char **s;
-
- pager_open_if_enabled();
+ int i, r, c, m = 0;
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_message_request_dump(req, true);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_call(rtnl, req, 0, &reply);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate links: %m");
-
- c = decode_and_sort_links(reply, &links);
+ if (argc > 1)
+ c = acquire_link_info_strv(rtnl, argv + 1, &links);
+ else
+ c = acquire_link_info_all(rtnl, &links);
if (c < 0)
- return rtnl_log_parse_error(c);
+ return c;
+
+ pager_open_if_enabled();
if (arg_legend)
- printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
+ printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
+ "LINK",
+ "CHASSIS ID",
+ "SYSTEM NAME",
+ "CAPS",
+ "PORT ID",
+ "PORT DESCRIPTION");
- for (i = j = 0; i < c; i++) {
- _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
- _cleanup_strv_free_ char **l = NULL;
+ for (i = 0; i < c; i++) {
+ _cleanup_fclose_ FILE *f = NULL;
- r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
- if (r < 0)
+ r = open_lldp_neighbors(links[i].ifindex, &f);
+ if (r == -ENOENT)
continue;
+ if (r < 0) {
+ log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
+ continue;
+ }
- l = strv_split_newlines(lldp);
- if (!l)
- return -ENOMEM;
-
- STRV_FOREACH(s, l) {
-
- p = *s;
- for (;;) {
- _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r < 0)
- return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s);
-
- if (r == 0)
- break;
-
- r = split_pair(word, "=", &a, &b);
- if (r < 0)
- continue;
+ for (;;) {
+ _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL;
+ const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL;
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
+ uint16_t cc;
- if (streq(a, "_Chassis")) {
- r = free_and_strdup(&chassis, b);
- if (r < 0)
- return r;
+ r = next_lldp_neighbor(f, &n);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read neighbor data: %m");
+ break;
+ }
+ if (r == 0)
+ break;
- } else if (streq(a, "_Port")) {
- r = free_and_strdup(&port, b);
- if (r < 0)
- return r;
+ (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
+ (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
+ (void) sd_lldp_neighbor_get_system_name(n, &system_name);
+ (void) sd_lldp_neighbor_get_port_description(n, &port_description);
- } else if (streq(a, "_TTL")) {
- long long unsigned x = 0;
- usec_t time;
+ if (chassis_id) {
+ cid = ellipsize(chassis_id, 17, 100);
+ if (cid)
+ chassis_id = cid;
+ }
- r = safe_atollu(b, &x);
- if (r < 0 || (usec_t) x != x)
- return log_warning_errno(r < 0 ? r : ERANGE,
- "Failed to parse TTL \"%s\": %m", b);
+ if (port_id) {
+ pid = ellipsize(port_id, 17, 100);
+ if (pid)
+ port_id = pid;
+ }
- time = now(clock_boottime_or_monotonic());
- if (x < time)
- continue;
+ if (system_name) {
+ sname = ellipsize(system_name, 16, 100);
+ if (sname)
+ system_name = sname;
+ }
- ttl = (double) (x - time) / USEC_PER_SEC;
+ if (port_description) {
+ pdesc = ellipsize(port_description, 16, 100);
+ if (pdesc)
+ port_description = pdesc;
+ }
- } else if (streq(a, "_CAP")) {
- sscanf(b, "%x", &capability);
+ if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0)
+ capabilities = lldp_capabilities_to_string(cc);
- cap = lldp_system_caps(capability);
- }
+ printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
+ links[i].name,
+ strna(chassis_id),
+ strna(system_name),
+ strna(capabilities),
+ strna(port_id),
+ strna(port_description));
- }
-
- if (ttl >= 0) {
- printf("%10s %24s %16s %16f %16s\n",
- links[i].name,
- strna(chassis), strna(port),
- ttl, cap);
- j++;
- }
+ m++;
}
}
- if (arg_legend) {
- printf("\nCapability Codes:\n"
- "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
- "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
- "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
-
- printf("Total entries displayed: %d\n", j);
- }
+ if (arg_legend)
+ printf("\nCapability Flags:\n"
+ "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n"
+ "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n"
+ "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n"
+ "%i neighbors listed.\n", m);
return 0;
}
@@ -1020,9 +1016,9 @@ static void help(void) {
" --no-legend Do not show the headers and footers\n"
" -a --all Show status for all links\n\n"
"Commands:\n"
- " list List links\n"
+ " list [LINK...] List links\n"
" status [LINK...] Show link status\n"
- " lldp Show lldp information\n"
+ " lldp [LINK...] Show LLDP neighbors\n"
, program_invocation_short_name);
}
@@ -1084,15 +1080,23 @@ static int parse_argv(int argc, char *argv[]) {
static int networkctl_main(int argc, char *argv[]) {
const Verb verbs[] = {
- { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
- { "status", 1, VERB_ANY, 0, link_status },
- { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
+ { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
+ { "status", VERB_ANY, VERB_ANY, 0, link_status },
+ { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
{}
};
return dispatch_verb(argc, argv, verbs, NULL);
}
+static void warn_networkd_missing(void) {
+
+ if (access("/run/systemd/netif/state", F_OK) >= 0)
+ return;
+
+ fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
+}
+
int main(int argc, char* argv[]) {
int r;
@@ -1103,6 +1107,8 @@ int main(int argc, char* argv[]) {
if (r <= 0)
goto finish;
+ warn_networkd_missing();
+
r = networkctl_main(argc, argv);
finish:
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 692c0bf63d..85a439b2a5 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -26,9 +26,11 @@
#include "dhcp-lease-internal.h"
#include "fd-util.h"
#include "fileio.h"
+#include "lldp.h"
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-link.h"
+#include "networkd-lldp-tx.h"
#include "networkd-netdev.h"
#include "set.h"
#include "socket-util.h"
@@ -38,7 +40,9 @@
#include "util.h"
#include "virt.h"
-bool link_dhcp6_enabled(Link *link) {
+static bool link_dhcp6_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -48,7 +52,9 @@ bool link_dhcp6_enabled(Link *link) {
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
}
-bool link_dhcp4_enabled(Link *link) {
+static bool link_dhcp4_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -58,7 +64,9 @@ bool link_dhcp4_enabled(Link *link) {
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
}
-bool link_dhcp4_server_enabled(Link *link) {
+static bool link_dhcp4_server_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -68,7 +76,9 @@ bool link_dhcp4_server_enabled(Link *link) {
return link->network->dhcp_server;
}
-bool link_ipv4ll_enabled(Link *link) {
+static bool link_ipv4ll_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -78,7 +88,9 @@ bool link_ipv4ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV4;
}
-bool link_ipv6ll_enabled(Link *link) {
+static bool link_ipv6ll_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -88,20 +100,42 @@ bool link_ipv6ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV6;
}
-bool link_lldp_enabled(Link *link) {
+static bool link_lldp_rx_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
+ if (link->iftype != ARPHRD_ETHER)
+ return false;
+
if (!link->network)
return false;
if (link->network->bridge)
return false;
- return link->network->lldp;
+ return link->network->lldp_mode != LLDP_MODE_NO;
+}
+
+static bool link_lldp_tx_enabled(Link *link) {
+ assert(link);
+
+ if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (link->iftype != ARPHRD_ETHER)
+ return false;
+
+ if (!link->network)
+ return false;
+
+ return link->network->lldp_emit;
}
static bool link_ipv4_forward_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -115,6 +149,7 @@ static bool link_ipv4_forward_enabled(Link *link) {
}
static bool link_ipv6_forward_enabled(Link *link) {
+ assert(link);
if (!socket_ipv6_is_supported())
return false;
@@ -131,7 +166,9 @@ static bool link_ipv6_forward_enabled(Link *link) {
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
}
-bool link_ipv6_accept_ra_enabled(Link *link) {
+static bool link_ipv6_accept_ra_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -300,6 +337,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
uint16_t type;
const char *ifname;
int r, ifindex;
+ unsigned short iftype;
assert(manager);
assert(message);
@@ -317,6 +355,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
else if (ifindex <= 0)
return -EINVAL;
+ r = sd_rtnl_message_link_get_type(message, &iftype);
+ if (r < 0)
+ return r;
+
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
if (r < 0)
return r;
@@ -330,30 +372,24 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
link->state = LINK_STATE_PENDING;
link->rtnl_extended_attrs = true;
link->ifindex = ifindex;
+ link->iftype = iftype;
link->ifname = strdup(ifname);
if (!link->ifname)
return -ENOMEM;
r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
if (r < 0)
- log_link_debug(link, "MAC address not found for new device, continuing without");
+ log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
- r = asprintf(&link->state_file, "/run/systemd/netif/links/%d",
- link->ifindex);
- if (r < 0)
+ if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
return -ENOMEM;
- r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d",
- link->ifindex);
- if (r < 0)
+ if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
return -ENOMEM;
- r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d",
- link->ifindex);
- if (r < 0)
+ if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
return -ENOMEM;
-
r = hashmap_ensure_allocated(&manager->links, NULL);
if (r < 0)
return r;
@@ -399,10 +435,11 @@ static void link_free(Link *link) {
sd_dhcp_client_unref(link->dhcp_client);
sd_dhcp_lease_unref(link->dhcp_lease);
+ link_lldp_tx_stop(link);
+
free(link->lease_file);
sd_lldp_unref(link->lldp);
-
free(link->lldp_file);
sd_ipv4ll_unref(link->ipv4ll);
@@ -506,33 +543,28 @@ static int link_stop_clients(Link *link) {
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m");
+ r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
}
if (link->ipv4ll) {
k = sd_ipv4ll_stop(link->ipv4ll);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
+ r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
}
if (link->dhcp6_client) {
k = sd_dhcp6_client_stop(link->dhcp6_client);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
+ r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
}
if (link->ndisc_router_discovery) {
k = sd_ndisc_stop(link->ndisc_router_discovery);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
- }
-
- if (link->lldp) {
- k = sd_lldp_stop(link->lldp);
- if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop LLDP: %m");
+ r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
}
+ link_lldp_tx_stop(link);
return r;
}
@@ -1211,7 +1243,7 @@ static int link_set_bridge(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
- if(link->network->cost != 0) {
+ if (link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
@@ -1230,23 +1262,93 @@ static int link_set_bridge(Link *link) {
return r;
}
-static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
+static int link_lldp_save(Link *link) {
+ _cleanup_free_ char *temp_path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ sd_lldp_neighbor **l = NULL;
+ int n = 0, r, i;
+
+ assert(link);
+ assert(link->lldp_file);
+
+ if (!link->lldp) {
+ (void) unlink(link->lldp_file);
+ return 0;
+ }
+
+ r = sd_lldp_get_neighbors(link->lldp, &l);
+ if (r < 0)
+ goto finish;
+ if (r == 0) {
+ (void) unlink(link->lldp_file);
+ goto finish;
+ }
+
+ n = r;
+
+ r = fopen_temporary(link->lldp_file, &f, &temp_path);
+ if (r < 0)
+ goto finish;
+
+ fchmod(fileno(f), 0644);
+
+ for (i = 0; i < n; i++) {
+ const void *p;
+ le64_t u;
+ size_t sz;
+
+ r = sd_lldp_neighbor_get_raw(l[i], &p, &sz);
+ if (r < 0)
+ goto finish;
+
+ u = htole64(sz);
+ (void) fwrite(&u, 1, sizeof(u), f);
+ (void) fwrite(p, 1, sz, f);
+ }
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ goto finish;
+
+ if (rename(temp_path, link->lldp_file) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+finish:
+ if (r < 0) {
+ (void) unlink(link->lldp_file);
+ if (temp_path)
+ (void) unlink(temp_path);
+
+ log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
+ }
+
+ if (l) {
+ for (i = 0; i < n; i++)
+ sd_lldp_neighbor_unref(l[i]);
+ free(l);
+ }
+
+ return r;
+}
+
+static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
Link *link = userdata;
int r;
assert(link);
- assert(link->network);
- assert(link->manager);
- switch (event) {
- case SD_LLDP_EVENT_UPDATE_INFO:
- r = sd_lldp_save(link->lldp, link->lldp_file);
- if (r < 0)
- log_link_warning_errno(link, r, "Could not save LLDP: %m");
+ (void) link_lldp_save(link);
+
+ if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
+ /* If we received information about a new neighbor, restart the LLDP "fast" logic */
+
+ log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission.");
- break;
- default:
- break;
+ r = link_lldp_tx_start(link);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
}
}
@@ -1311,14 +1413,10 @@ static int link_acquire_conf(Link *link) {
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
}
- if (link_lldp_enabled(link)) {
- assert(link->lldp);
-
- log_link_debug(link, "Starting LLDP");
-
- r = sd_lldp_start(link->lldp);
+ if (link_lldp_tx_enabled(link)) {
+ r = link_lldp_tx_start(link);
if (r < 0)
- return log_link_warning_errno(link, r, "Could not start LLDP: %m");
+ return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
}
return 0;
@@ -1559,7 +1657,7 @@ static int link_new_bound_by_list(Link *link) {
m = link->manager;
- HASHMAP_FOREACH (carrier, m->links, i) {
+ HASHMAP_FOREACH(carrier, m->links, i) {
if (!carrier->network)
continue;
@@ -1578,7 +1676,7 @@ static int link_new_bound_by_list(Link *link) {
if (list_updated)
link_dirty(link);
- HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
+ HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
if (r < 0)
return r;
@@ -2030,6 +2128,27 @@ static int link_drop_foreign_config(Link *link) {
return 0;
}
+static int link_update_lldp(Link *link) {
+ int r;
+
+ assert(link);
+
+ if (!link->lldp)
+ return 0;
+
+ if (link->flags & IFF_UP) {
+ r = sd_lldp_start(link->lldp);
+ if (r > 0)
+ log_link_debug(link, "Started LLDP.");
+ } else {
+ r = sd_lldp_stop(link->lldp);
+ if (r > 0)
+ log_link_debug(link, "Stopped LLDP.");
+ }
+
+ return r;
+}
+
static int link_configure(Link *link) {
int r;
@@ -2108,8 +2227,19 @@ static int link_configure(Link *link) {
return r;
}
- if (link_lldp_enabled(link)) {
- r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp);
+ if (link_lldp_rx_enabled(link)) {
+ r = sd_lldp_new(&link->lldp, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_lldp_match_capabilities(link->lldp,
+ link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ?
+ _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS :
+ _LLDP_SYSTEM_CAPABILITIES_ALL);
+ if (r < 0)
+ return r;
+
+ r = sd_lldp_set_filter_address(link->lldp, &link->mac);
if (r < 0)
return r;
@@ -2117,8 +2247,11 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
- r = sd_lldp_set_callback(link->lldp,
- lldp_handler, link);
+ r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
+ if (r < 0)
+ return r;
+
+ r = link_update_lldp(link);
if (r < 0)
return r;
}
@@ -2562,7 +2695,6 @@ int link_carrier_reset(Link *link) {
return 0;
}
-
int link_update(Link *link, sd_netlink_message *m) {
struct ether_addr mac;
const char *ifname;
@@ -2668,6 +2800,10 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return r;
+ r = link_update_lldp(link);
+ if (r < 0)
+ return r;
+
carrier_gained = !had_carrier && link_has_carrier(link);
carrier_lost = had_carrier && !link_has_carrier(link);
@@ -2683,12 +2819,34 @@ int link_update(Link *link, sd_netlink_message *m) {
r = link_carrier_lost(link);
if (r < 0)
return r;
-
}
return 0;
}
+static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
+ bool space = false;
+ Iterator i;
+ Link *link;
+
+ assert(f);
+ assert(prefix);
+
+ if (hashmap_isempty(h))
+ return;
+
+ fputs(prefix, f);
+ HASHMAP_FOREACH(link, h, i) {
+ if (space)
+ fputc(' ', f);
+
+ fprintf(f, "%i", link->ifindex);
+ space = true;
+ }
+
+ fputc('\n', f);
+}
+
int link_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -2708,6 +2866,8 @@ int link_save(Link *link) {
return 0;
}
+ link_lldp_save(link);
+
admin_state = link_state_to_string(link->state);
assert(admin_state);
@@ -2887,27 +3047,8 @@ int link_save(Link *link) {
fputc('\n', f);
}
- if (!hashmap_isempty(link->bound_to_links)) {
- Link *carrier;
- bool space = false;
-
- fputs("CARRIER_BOUND_TO=", f);
- HASHMAP_FOREACH(carrier, link->bound_to_links, i)
- fputs_with_space(f, carrier->ifname, NULL, &space);
-
- fputc('\n', f);
- }
-
- if (!hashmap_isempty(link->bound_by_links)) {
- Link *carrier;
- bool space = false;
-
- fputs("CARRIER_BOUND_BY=", f);
- HASHMAP_FOREACH(carrier, link->bound_by_links, i)
- fputs_with_space(f, carrier->ifname, NULL, &space);
-
- fputc('\n', f);
- }
+ print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
+ print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
if (link->dhcp_lease) {
struct in_addr address;
@@ -2947,19 +3088,6 @@ int link_save(Link *link) {
}
}
- if (link->lldp) {
- assert(link->network);
-
- r = sd_lldp_save(link->lldp, link->lldp_file);
- if (r < 0)
- goto fail;
-
- fprintf(f,
- "LLDP_FILE=%s\n",
- link->lldp_file);
- } else
- unlink(link->lldp_file);
-
r = fflush_and_check(f);
if (r < 0)
goto fail;
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 0e6a7b6f21..f2a64ca9b5 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -65,6 +65,7 @@ struct Link {
int ifindex;
char *ifname;
+ unsigned short iftype;
char *state_file;
struct ether_addr mac;
struct in6_addr ipv6ll_address;
@@ -111,9 +112,14 @@ struct Link {
sd_dhcp6_client *dhcp6_client;
bool rtnl_extended_attrs;
+ /* This is about LLDP reception */
sd_lldp *lldp;
char *lldp_file;
+ /* This is about LLDP transmission */
+ unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */
+ sd_event_source *lldp_tx_event_source;
+
Hashmap *bound_by_links;
Hashmap *bound_to_links;
};
@@ -154,14 +160,6 @@ int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link);
int ndisc_configure(Link *link);
-bool link_lldp_enabled(Link *link);
-bool link_ipv4ll_enabled(Link *link);
-bool link_ipv6ll_enabled(Link *link);
-bool link_dhcp4_server_enabled(Link *link);
-bool link_dhcp4_enabled(Link *link);
-bool link_dhcp6_enabled(Link *link);
-bool link_ipv6_accept_ra_enabled(Link *link);
-
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
new file mode 100644
index 0000000000..ae8367a60e
--- /dev/null
+++ b/src/network/networkd-lldp-tx.c
@@ -0,0 +1,347 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <endian.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include "fd-util.h"
+#include "fileio.h"
+#include "hostname-util.h"
+#include "lldp.h"
+#include "networkd-lldp-tx.h"
+#include "random-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "unaligned.h"
+
+/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
+#define LLDP_TX_FAST_INIT 4U
+
+/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
+#define LLDP_TX_HOLD 4U
+
+/* The jitter range to add, see 9.2.2. */
+#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC)
+
+/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
+#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
+
+/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
+#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
+
+static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
+ assert(p);
+
+ if (id > 127)
+ return -EBADMSG;
+ if (sz > 511)
+ return -ENOBUFS;
+
+ (*p)[0] = (id << 1) | !!(sz & 256);
+ (*p)[1] = sz & 255;
+
+ *p = *p + 2;
+ return 0;
+}
+
+static int lldp_make_packet(
+ const struct ether_addr *hwaddr,
+ const char *machine_id,
+ const char *ifname,
+ uint16_t ttl,
+ const char *port_description,
+ const char *hostname,
+ const char *pretty_hostname,
+ uint16_t system_capabilities,
+ uint16_t enabled_capabilities,
+ void **ret, size_t *sz) {
+
+ size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
+ _cleanup_free_ void *packet = NULL;
+ struct ether_header *h;
+ uint8_t *p;
+ size_t l;
+ int r;
+
+ assert(hwaddr);
+ assert(machine_id);
+ assert(ifname);
+ assert(ret);
+ assert(sz);
+
+ machine_id_length = strlen(machine_id);
+ ifname_length = strlen(ifname);
+
+ if (port_description)
+ port_description_length = strlen(port_description);
+
+ if (hostname)
+ hostname_length = strlen(hostname);
+
+ if (pretty_hostname)
+ pretty_hostname_length = strlen(pretty_hostname);
+
+ l = sizeof(struct ether_header) +
+ /* Chassis ID */
+ 2 + 1 + machine_id_length +
+ /* Port ID */
+ 2 + 1 + ifname_length +
+ /* TTL */
+ 2 + 2 +
+ /* System Capabilities */
+ 2 + 4 +
+ /* End */
+ 2;
+
+ /* Port Description */
+ if (port_description)
+ l += 2 + port_description_length;
+
+ /* System Name */
+ if (hostname)
+ l += 2 + hostname_length;
+
+ /* System Description */
+ if (pretty_hostname)
+ l += 2 + pretty_hostname_length;
+
+ packet = malloc(l);
+ if (!packet)
+ return -ENOMEM;
+
+ h = (struct ether_header*) packet;
+ h->ether_type = htobe16(ETHERTYPE_LLDP);
+ memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN);
+ memcpy(h->ether_shost, hwaddr, ETH_ALEN);
+
+ p = (uint8_t*) packet + sizeof(struct ether_header);
+
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length);
+ if (r < 0)
+ return r;
+ *(p++) = LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED;
+ p = mempcpy(p, machine_id, machine_id_length);
+
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_ID, 1 + ifname_length);
+ if (r < 0)
+ return r;
+ *(p++) = LLDP_PORT_SUBTYPE_INTERFACE_NAME;
+ p = mempcpy(p, ifname, ifname_length);
+
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_TTL, 2);
+ if (r < 0)
+ return r;
+ unaligned_write_be16(p, ttl);
+ p += 2;
+
+ if (port_description) {
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_DESCRIPTION, port_description_length);
+ if (r < 0)
+ return r;
+ p = mempcpy(p, port_description, port_description_length);
+ }
+
+ if (hostname) {
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_NAME, hostname_length);
+ if (r < 0)
+ return r;
+ p = mempcpy(p, hostname, hostname_length);
+ }
+
+ if (pretty_hostname) {
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length);
+ if (r < 0)
+ return r;
+ p = mempcpy(p, pretty_hostname, pretty_hostname_length);
+ }
+
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
+ if (r < 0)
+ return r;
+ unaligned_write_be16(p, system_capabilities);
+ p += 2;
+ unaligned_write_be16(p, enabled_capabilities);
+ p += 2;
+
+ r = lldp_write_tlv_header(&p, LLDP_TYPE_END, 0);
+ if (r < 0)
+ return r;
+
+ assert(p == (uint8_t*) packet + l);
+
+ *ret = packet;
+ *sz = l;
+
+ packet = NULL;
+ return 0;
+}
+
+static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) {
+
+ union sockaddr_union sa = {
+ .ll.sll_family = AF_PACKET,
+ .ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
+ .ll.sll_ifindex = ifindex,
+ .ll.sll_halen = ETH_ALEN,
+ .ll.sll_addr = LLDP_MULTICAST_ADDR,
+ };
+
+ _cleanup_close_ int fd = -1;
+ ssize_t l;
+
+ assert(ifindex > 0);
+ assert(packet || packet_size <= 0);
+
+ fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
+ if (fd < 0)
+ return -errno;
+
+ l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
+ if (l < 0)
+ return -errno;
+
+ if ((size_t) l != packet_size)
+ return -EIO;
+
+ return 0;
+}
+
+static int link_send_lldp(Link *link) {
+ char machine_id_string[SD_ID128_STRING_MAX];
+ _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL;
+ _cleanup_free_ void *packet = NULL;
+ size_t packet_size = 0;
+ sd_id128_t machine_id;
+ uint16_t caps;
+ usec_t ttl;
+ int r;
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return r;
+
+ (void) gethostname_strict(&hostname);
+ (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL);
+
+ ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
+ if (ttl > (usec_t) UINT16_MAX)
+ ttl = (usec_t) UINT16_MAX;
+
+ caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
+ LLDP_SYSTEM_CAPABILITIES_ROUTER :
+ LLDP_SYSTEM_CAPABILITIES_STATION;
+
+ r = lldp_make_packet(&link->mac,
+ sd_id128_to_string(machine_id, machine_id_string),
+ link->ifname,
+ (uint16_t) ttl,
+ link->network ? link->network->description : NULL,
+ hostname,
+ pretty_hostname,
+ LLDP_SYSTEM_CAPABILITIES_STATION|LLDP_SYSTEM_CAPABILITIES_BRIDGE|LLDP_SYSTEM_CAPABILITIES_ROUTER,
+ caps,
+ &packet, &packet_size);
+ if (r < 0)
+ return r;
+
+ return lldp_send_packet(link->ifindex, packet, packet_size);
+}
+
+static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
+ Link *link = userdata;
+ usec_t current, delay, next;
+ int r;
+
+ assert(s);
+ assert(userdata);
+
+ log_link_debug(link, "Sending LLDP packet...");
+
+ r = link_send_lldp(link);
+ if (r < 0)
+ log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m");
+
+ if (link->lldp_tx_fast > 0)
+ link->lldp_tx_fast--;
+
+ assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), &current) >= 0);
+
+ delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC;
+ next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC);
+
+ r = sd_event_source_set_time(s, next);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m");
+
+ r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m");
+
+ return 0;
+}
+
+int link_lldp_tx_start(Link *link) {
+ usec_t next;
+ int r;
+
+ assert(link);
+
+ /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
+
+ link->lldp_tx_fast = LLDP_TX_FAST_INIT;
+
+ next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
+ (usec_t) random_u64() % LLDP_JITTER_USEC);
+
+ if (link->lldp_tx_event_source) {
+ usec_t old;
+
+ /* Lower the timeout, maybe */
+ r = sd_event_source_get_time(link->lldp_tx_event_source, &old);
+ if (r < 0)
+ return r;
+
+ if (old <= next)
+ return 0;
+
+ return sd_event_source_set_time(link->lldp_tx_event_source, next);
+ } else {
+ r = sd_event_add_time(
+ link->manager->event,
+ &link->lldp_tx_event_source,
+ clock_boottime_or_monotonic(),
+ next,
+ 0,
+ on_lldp_timer,
+ link);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx");
+ }
+
+ return 0;
+}
+
+void link_lldp_tx_stop(Link *link) {
+ assert(link);
+
+ link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source);
+}
diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h
new file mode 100644
index 0000000000..8c7f403005
--- /dev/null
+++ b/src/network/networkd-lldp-tx.h
@@ -0,0 +1,25 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include "networkd-link.h"
+
+int link_lldp_tx_start(Link *link);
+void link_lldp_tx_stop(Link *link);
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index b2bf7e15f1..27f26f7870 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct Bridge Bridge;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h
index 29f75a149b..42da62ebe4 100644
--- a/src/network/networkd-netdev-dummy.h
+++ b/src/network/networkd-netdev-dummy.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct Dummy Dummy;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h
index 5b85ef2150..4bd0b67866 100644
--- a/src/network/networkd-netdev-ipvlan.h
+++ b/src/network/networkd-netdev-ipvlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct IPVlan IPVlan;
#include "missing.h"
diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h
index 8b42684de6..622ef9ef53 100644
--- a/src/network/networkd-netdev-macvlan.h
+++ b/src/network/networkd-netdev-macvlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct MacVlan MacVlan;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index ea1d9a79e7..0d41f80a3c 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct Tunnel Tunnel;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h
index b970b0ce3b..cbb7ee05a6 100644
--- a/src/network/networkd-netdev-tuntap.h
+++ b/src/network/networkd-netdev-tuntap.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct TunTap TunTap;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h
index f7fdf906ab..ae5785783c 100644
--- a/src/network/networkd-netdev-veth.h
+++ b/src/network/networkd-netdev-veth.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct Veth Veth;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h
index 8701c4b785..1de6a1cc36 100644
--- a/src/network/networkd-netdev-vlan.h
+++ b/src/network/networkd-netdev-vlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct VLan VLan;
#include "networkd-netdev.h"
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index 459ce53f5e..a4bb44635a 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct VxLan VxLan;
#include "in-addr-util.h"
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 3eacee824b..7ea825fcb4 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "list.h"
typedef struct NetDev NetDev;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 409df1709f..a5d1714293 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -40,7 +40,8 @@ Network.DHCPServer, config_parse_bool,
Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
-Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
+Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
+Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
Network.Domains, config_parse_domains, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 54f76fe206..f175788977 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -119,6 +119,8 @@ static int network_load_one(Manager *manager, const char *filename) {
network->allow_port_to_be_root = true;
network->unicast_flood = true;
+ network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
+
network->llmnr = RESOLVE_SUPPORT_YES;
network->mdns = RESOLVE_SUPPORT_NO;
network->dnssec_mode = _DNSSEC_MODE_INVALID;
@@ -1017,3 +1019,13 @@ static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
+
+static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
+ [LLDP_MODE_NO] = "no",
+ [LLDP_MODE_YES] = "yes",
+ [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 03c3f206c3..4a13e2b574 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -58,6 +58,14 @@ typedef enum DHCPUseDomains {
_DHCP_USE_DOMAINS_INVALID = -1,
} DHCPUseDomains;
+typedef enum LLDPMode {
+ LLDP_MODE_NO = 0,
+ LLDP_MODE_YES = 1,
+ LLDP_MODE_ROUTERS_ONLY = 2,
+ _LLDP_MODE_MAX,
+ _LLDP_MODE_INVALID = -1,
+} LLDPMode;
+
struct Network {
Manager *manager;
@@ -137,7 +145,8 @@ struct Network {
struct ether_addr *mac;
unsigned mtu;
- bool lldp;
+ LLDPMode lldp_mode; /* LLDP reception */
+ bool lldp_emit; /* LLDP transmission */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
@@ -181,6 +190,7 @@ int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigne
int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -197,3 +207,6 @@ IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;
+
+const char* lldp_mode_to_string(LLDPMode m) _const_;
+LLDPMode lldp_mode_from_string(const char *s) _pure_;
diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h
index 421c2bdf44..f91995c306 100644
--- a/src/network/networkd-wait-online.h
+++ b/src/network/networkd-wait-online.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-network.h"
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 7ee922621a..6bdd8302a0 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <arpa/inet.h>
#include "sd-bus.h"
diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h
index db9666b970..7b79d29d7e 100644
--- a/src/resolve/dns-type.h
+++ b/src/resolve/dns-type.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "macro.h"
/* DNS record types, taken from
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 2de3642cb3..af780f0b8b 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
diff --git a/src/shared/gpt.h b/src/shared/gpt.h
index 52ab29ed5f..55b41bbcd8 100644
--- a/src/shared/gpt.h
+++ b/src/shared/gpt.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <endian.h>
#include "sd-id128.h"
diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h
index acf519f4f7..8a570fc265 100644
--- a/src/shared/install-printf.h
+++ b/src/shared/install-printf.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "install.h"
int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret);
diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h
index 51f4621844..ad10039ff4 100644
--- a/src/shared/sleep-config.h
+++ b/src/shared/sleep-config.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
int parse_sleep_config(const char *verb, char ***modes, char ***states);
int can_sleep(const char *verb);
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 2b865a80e1..ef45370505 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -84,9 +84,9 @@ enum {
typedef struct sd_dhcp_client sd_dhcp_client;
-typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event,
+typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event,
void *userdata);
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
+int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb,
void *userdata);
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
@@ -113,7 +113,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
int sd_dhcp_client_new(sd_dhcp_client **ret);
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority);
+int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority);
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h
index 8658197e80..fcef083ce6 100644
--- a/src/systemd/sd-dhcp-server.h
+++ b/src/systemd/sd-dhcp-server.h
@@ -37,7 +37,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex);
sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server);
sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server);
-int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority);
+int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int64_t priority);
int sd_dhcp_server_detach_event(sd_dhcp_server *client);
sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index 9608060830..1bedc941aa 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -76,10 +76,10 @@ enum {
typedef struct sd_dhcp6_client sd_dhcp6_client;
-typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event,
+typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event,
void *userdata);
int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
- sd_dhcp6_client_cb_t cb, void *userdata);
+ sd_dhcp6_client_callback_t cb, void *userdata);
int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
@@ -97,8 +97,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
-int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
- int priority);
+int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority);
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h
index 3a2219c82c..9e3e14a30c 100644
--- a/src/systemd/sd-ipv4acd.h
+++ b/src/systemd/sd-ipv4acd.h
@@ -37,12 +37,12 @@ enum {
};
typedef struct sd_ipv4acd sd_ipv4acd;
-typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata);
+typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata);
int sd_ipv4acd_detach_event(sd_ipv4acd *ll);
-int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority);
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority);
int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address);
-int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata);
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index 67c566fe0d..6fa38a2243 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -36,12 +36,12 @@ enum {
};
typedef struct sd_ipv4ll sd_ipv4ll;
-typedef void (*sd_ipv4ll_cb_t)(sd_ipv4ll *ll, int event, void *userdata);
+typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata);
int sd_ipv4ll_detach_event(sd_ipv4ll *ll);
-int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority);
+int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority);
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
-int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
+int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h
index ea952ef187..f7eff58769 100644
--- a/src/systemd/sd-lldp.h
+++ b/src/systemd/sd-lldp.h
@@ -30,57 +30,69 @@
_SD_BEGIN_DECLARATIONS;
-enum {
- SD_LLDP_EVENT_UPDATE_INFO = 0,
-};
-
-enum {
- SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE,
- SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE,
- SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE,
-};
-
typedef struct sd_lldp sd_lldp;
-typedef struct sd_lldp_packet sd_lldp_packet;
+typedef struct sd_lldp_neighbor sd_lldp_neighbor;
-typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
+typedef enum sd_lldp_event {
+ SD_LLDP_EVENT_ADDED = 'a',
+ SD_LLDP_EVENT_REMOVED = 'r',
+ SD_LLDP_EVENT_UPDATED = 'u',
+ SD_LLDP_EVENT_REFRESHED = 'f',
+} sd_lldp_event;
-int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret);
+typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
+
+int sd_lldp_new(sd_lldp **ret, int ifindex);
sd_lldp* sd_lldp_unref(sd_lldp *lldp);
int sd_lldp_start(sd_lldp *lldp);
int sd_lldp_stop(sd_lldp *lldp);
-int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority);
+int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority);
int sd_lldp_detach_event(sd_lldp *lldp);
-int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata);
-int sd_lldp_save(sd_lldp *lldp, const char *file);
-
-int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
-int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
-int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl);
-int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length);
-int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
-int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data);
-int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
-
-/* IEEE 802.1 organizationally specific TLVs */
-int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id);
-int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id);
-int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length);
-int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id);
-int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id);
-
-sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv);
-sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
-
-int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
-
-int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
+int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata);
+
+/* Controls how much and what to store in the neighbors database */
+int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n);
+int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask);
+int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *address);
+
+int sd_lldp_get_neighbors(sd_lldp *lldp, 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_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);
+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_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 evertyhing 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[3], uint8_t *subtype);
+int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[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, sd_lldp_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref);
_SD_END_DECLARATIONS;
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
index 762947531d..29bcbe8e3e 100644
--- a/src/systemd/sd-ndisc.h
+++ b/src/systemd/sd-ndisc.h
@@ -52,7 +52,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd,
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
-int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority);
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
sd_event *sd_ndisc_get_event(sd_ndisc *nd);
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index b4798d2476..af7a797567 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -64,7 +64,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout);
int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
-int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int priority);
+int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority);
int sd_netlink_detach_event(sd_netlink *nl);
int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data);
@@ -131,7 +131,7 @@ int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type);
int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family);
int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags);
-int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type);
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type);
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index e20d12c44d..0f13e2bae7 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -99,11 +99,11 @@ int sd_network_link_get_network_file(int ifindex, char **filename);
/* Get DNS entries for a given link. These are string representations of
* IP addresses */
-int sd_network_link_get_dns(int ifindex, char ***addr);
+int sd_network_link_get_dns(int ifindex, char ***ret);
/* Get NTP entries for a given link. These are domain names or string
* representations of IP addresses */
-int sd_network_link_get_ntp(int ifindex, char ***addr);
+int sd_network_link_get_ntp(int ifindex, char ***ret);
/* Indicates whether or not LLMNR should be enabled for the link
* Possible levels of support: yes, no, resolve
@@ -133,19 +133,17 @@ int sd_network_link_get_dnssec(int ifindex, char **dnssec);
*/
int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta);
-int sd_network_link_get_lldp(int ifindex, char **lldp);
-
/* Get the search DNS domain names for a given link. */
int sd_network_link_get_search_domains(int ifindex, char ***domains);
/* Get the route DNS domain names for a given link. */
int sd_network_link_get_route_domains(int ifindex, char ***domains);
-/* Get the CARRIERS to which current link is bound to. */
-int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers);
+/* Get the carrier interface indexes to which current link is bound to. */
+int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes);
/* Get the CARRIERS that are bound to current link. */
-int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers);
+int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
/* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone);
diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h
index 903b917f70..1c792dab39 100644
--- a/src/systemd/sd-resolve.h
+++ b/src/systemd/sd-resolve.h
@@ -79,7 +79,7 @@ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec);
int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid);
-int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int priority);
+int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int64_t priority);
int sd_resolve_detach_event(sd_resolve *resolve);
sd_event *sd_resolve_get_event(sd_resolve *resolve);
diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h
index caea5c2693..68e4954537 100644
--- a/src/udev/mtd_probe/mtd_probe.h
+++ b/src/udev/mtd_probe/mtd_probe.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) 2010 - Maxim Levitsky
*
@@ -17,8 +19,6 @@
* Boston, MA 02110-1301 USA
*/
-#pragma once
-
#include <mtd/mtd-user.h>
#include "macro.h"
diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h
index 2e6e1d7150..7716516e76 100644
--- a/src/udev/net/ethtool-util.h
+++ b/src/udev/net/ethtool-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <macro.h>
/* we can't use DUPLEX_ prefix, as it
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index f525fe2116..9df5529d05 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "libudev.h"
#include "condition.h"
diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h
index 3bf1a94200..a27a84a40a 100644
--- a/src/udev/scsi_id/scsi.h
+++ b/src/udev/scsi_id/scsi.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* scsi.h
*
@@ -10,8 +12,6 @@
* Free Software Foundation version 2 of the License.
*/
-#pragma once
-
#include <scsi/scsi.h>
struct scsi_ioctl_command {
diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h
index 141b116a88..5c2e1c28ee 100644
--- a/src/udev/scsi_id/scsi_id.h
+++ b/src/udev/scsi_id/scsi_id.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) IBM Corp. 2003
*
@@ -15,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-
#define MAX_PATH_LEN 512
/*
diff --git a/src/udev/udev.h b/src/udev/udev.h
index 655880346b..56590517ef 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2003-2010 Kay Sievers <kay@vrfy.org>
@@ -16,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-
#include <sys/param.h>
#include <sys/types.h>
diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h
index 37e4fe8369..dc712b0d93 100644
--- a/src/udev/udevadm-util.h
+++ b/src/udev/udevadm-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
*
@@ -15,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-
#include "udev.h"
struct udev_device *find_device(struct udev *udev,