mirror of
https://github.com/systemd/systemd.git
synced 2026-08-05 07:30:30 +00:00
Merge pull request #2685 from poettering/lldp-fixes2
lldp fixes, second iteration
This commit is contained in:
15
Makefile.am
15
Makefile.am
@@ -3299,14 +3299,10 @@ libsystemd_network_la_SOURCES = \
|
||||
src/libsystemd-network/dhcp-identifier.h \
|
||||
src/libsystemd-network/dhcp-identifier.c \
|
||||
src/libsystemd-network/lldp.h \
|
||||
src/libsystemd-network/lldp-tlv.h \
|
||||
src/libsystemd-network/lldp-tlv.c \
|
||||
src/libsystemd-network/lldp-network.h \
|
||||
src/libsystemd-network/lldp-network.c \
|
||||
src/libsystemd-network/lldp-port.h \
|
||||
src/libsystemd-network/lldp-port.c \
|
||||
src/libsystemd-network/lldp-internal.h \
|
||||
src/libsystemd-network/lldp-internal.c \
|
||||
src/libsystemd-network/lldp-neighbor.h \
|
||||
src/libsystemd-network/lldp-neighbor.c \
|
||||
src/libsystemd-network/sd-lldp.c
|
||||
|
||||
libsystemd_network_la_LIBADD = \
|
||||
@@ -3389,9 +3385,6 @@ test_dhcp6_client_LDADD = \
|
||||
libshared.la
|
||||
|
||||
test_lldp_SOURCES = \
|
||||
src/libsystemd-network/lldp.h \
|
||||
src/libsystemd-network/lldp-tlv.h \
|
||||
src/libsystemd-network/lldp-tlv.c \
|
||||
src/libsystemd-network/test-lldp.c
|
||||
|
||||
test_lldp_LDADD = \
|
||||
@@ -5348,7 +5341,9 @@ libnetworkd_core_la_SOURCES = \
|
||||
src/network/networkd-address-pool.h \
|
||||
src/network/networkd-address-pool.c \
|
||||
src/network/networkd-util.h \
|
||||
src/network/networkd-util.c
|
||||
src/network/networkd-util.c \
|
||||
src/network/networkd-lldp-tx.h \
|
||||
src/network/networkd-lldp-tx.c
|
||||
|
||||
nodist_libnetworkd_core_la_SOURCES = \
|
||||
src/network/networkd-network-gperf.c \
|
||||
|
||||
9
TODO
9
TODO
@@ -33,6 +33,14 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
|
||||
|
||||
* machinectl remove --hidden + machinectl remove --all
|
||||
|
||||
* move specifier expansion from service_spawn() into load-fragment.c
|
||||
|
||||
* optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
|
||||
|
||||
* resolved: maybe, after all, implement local listening for DNS packets on port
|
||||
53.
|
||||
|
||||
@@ -773,7 +781,6 @@ Features:
|
||||
- work with non-Ethernet devices
|
||||
- add support for more bond options
|
||||
- dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from?
|
||||
- add LLDP client side support
|
||||
- the DHCP lease data (such as NTP/DNS) is still made available when
|
||||
a carrier is lost on a link. It should be removed instantly.
|
||||
- expose in the API the following bits:
|
||||
|
||||
@@ -933,12 +933,12 @@
|
||||
<title>Download a Fedora image, set a root password in it, start
|
||||
it as service</title>
|
||||
|
||||
<programlisting># machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz
|
||||
# systemd-nspawn -M Fedora-Cloud-Base-20141203-21
|
||||
<programlisting># machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/23/Cloud/x86_64/Images/Fedora-Cloud-Base-23-20151030.x86_64.raw.xz
|
||||
# systemd-nspawn -M Fedora-Cloud-Base-23-20151030
|
||||
# passwd
|
||||
# exit
|
||||
# machinectl start Fedora-Cloud-Base-20141203-21
|
||||
# machinectl login Fedora-Cloud-Base-20141203-21</programlisting>
|
||||
# machinectl start Fedora-Cloud-Base-23-20151030
|
||||
# machinectl login Fedora-Cloud-Base-23-20151030</programlisting>
|
||||
|
||||
<para>This downloads the specified <filename>.raw</filename>
|
||||
image with verification disabled. Then, a shell is opened in it
|
||||
|
||||
@@ -102,12 +102,14 @@
|
||||
<varlistentry>
|
||||
<term>
|
||||
<command>list</command>
|
||||
<optional><replaceable>LINK...</replaceable></optional>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>Show a list of existing links and their
|
||||
status. Produces output similar to <programlisting>
|
||||
IDX LINK TYPE OPERATIONAL SETUP
|
||||
<para>Show a list of existing links and their status. If no further arguments are specified shows all links,
|
||||
otherwise just the specified links. Produces output similar to:
|
||||
|
||||
<programlisting>IDX LINK TYPE OPERATIONAL SETUP
|
||||
1 lo loopback carrier unmanaged
|
||||
2 eth0 ether routable configured
|
||||
3 virbr0 ether no-carrier unmanaged
|
||||
@@ -128,10 +130,10 @@ IDX LINK TYPE OPERATIONAL SETUP
|
||||
state, kernel module driver, hardware and IP address,
|
||||
configured DNS servers, etc.</para>
|
||||
|
||||
<para>When no links are specified, routable links are
|
||||
shown. Also see the option <option>--all</option>.</para>
|
||||
<para>When no links are specified, an overall network status is shown. Also see the option
|
||||
<option>--all</option>.</para>
|
||||
|
||||
<para>Produces output similar to
|
||||
<para>Produces output similar to:
|
||||
<programlisting>
|
||||
● State: routable
|
||||
Address: 10.193.76.5 on eth0
|
||||
@@ -148,11 +150,26 @@ IDX LINK TYPE OPERATIONAL SETUP
|
||||
<varlistentry>
|
||||
<term>
|
||||
<command>lldp</command>
|
||||
<optional><replaceable>LINK...</replaceable></optional>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>Show LLDP (Link Layer Discovery Protocol)
|
||||
status.</para>
|
||||
<para>Show discovered LLDP (Link Layer Discovery Protocol) neighbors. If one or more link names are specified
|
||||
only neighbors on those interfaces are shown. Otherwise shows discovered neighbors on all interfaces. Note
|
||||
that for this feature to work, <varname>LLDP=</varname> must be turned on on the specific interface, see
|
||||
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
|
||||
<para>Produces output similar to:
|
||||
<programlisting>LINK CHASSIS ID SYSTEM NAME CAPS PORT ID PORT DESCRIPTION
|
||||
enp0s25 00:e0:4c:00:00:00 GS1900 ..b........ 2 Port #2
|
||||
|
||||
Capability Flags:
|
||||
o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;
|
||||
t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;
|
||||
s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
||||
|
||||
1 neighbors listed.</programlisting></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
@@ -335,10 +335,36 @@
|
||||
<varlistentry>
|
||||
<term><varname>LLDP=</varname></term>
|
||||
<listitem>
|
||||
<para>A boolean. When true, enables LLDP link receive support.
|
||||
<para>Controls support for Ethernet LLDP packet reception. LLDP is a link-layer protocol commonly
|
||||
implemented on professional routers and bridges which announces which physical port a system is connected
|
||||
to, as well as other related data. Accepts a boolean or the special value
|
||||
<literal>routers-only</literal>. When true, incoming LLDP packets are accepted and a database of all LLDP
|
||||
neighbors maintained. If <literal>routers-only</literal> is set only LLDP data of various types of routers
|
||||
is collected and LLDP data about other types of devices ignored (such as stations, telephones and
|
||||
others). If false, LLDP reception is disabled. Defaults to <literal>routers-only</literal>. Use
|
||||
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to query the
|
||||
collected neighbor data. LLDP is only available on Ethernet links. See <varname>EmitLLDP=</varname> below
|
||||
for enabling LLDP packet emission from the local system.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>EmitLLDP=</varname></term>
|
||||
<listitem>
|
||||
<para>Controls support for Ethernet LLDP packet emission. Accepts a boolean parameter and defaults to
|
||||
false. If enabled a short LLDP packet with information about the local system is sent out in regular
|
||||
intervals on the link. The LLDP packet will contain information about the local host name, the local
|
||||
machine ID (as stored in
|
||||
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>) and the
|
||||
local interface name, as well as the pretty hostname of the system (as set in
|
||||
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>). LLDP
|
||||
emission is only available on Ethernet links. Note that this setting passed data suitable for
|
||||
identification of host to the network and should thus not be used on untrusted networks, where such
|
||||
identification data should not be made available. Use this option to enable other systems to identify on
|
||||
which interface they are connected to this system. See <varname>LLDP=</varname> above for an option to
|
||||
enable LLDP reception.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>BindCarrier=</varname></term>
|
||||
<listitem>
|
||||
|
||||
@@ -12,6 +12,8 @@ Name=host0
|
||||
[Network]
|
||||
DHCP=yes
|
||||
LinkLocalAddressing=yes
|
||||
LLDP=yes
|
||||
EmitLLDP=yes
|
||||
|
||||
[DHCP]
|
||||
UseTimezone=yes
|
||||
|
||||
@@ -15,3 +15,5 @@ Address=0.0.0.0/28
|
||||
LinkLocalAddressing=yes
|
||||
DHCPServer=yes
|
||||
IPMasquerade=yes
|
||||
LLDP=yes
|
||||
EmitLLDP=yes
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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') ||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
struct ether_addr filter_address;
|
||||
};
|
||||
|
||||
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 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__)
|
||||
|
||||
792
src/libsystemd-network/lldp-neighbor.c
Normal file
792
src/libsystemd-network/lldp-neighbor.c
Normal file
@@ -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;
|
||||
}
|
||||
106
src/libsystemd-network/lldp-neighbor.h
Normal file
106
src/libsystemd-network/lldp-neighbor.h
Normal file
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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(§ion);
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
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 ((uint16_t) -1)
|
||||
|
||||
#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,
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
@@ -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(ðer.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
|
||||
memcpy(ðer.ether_shost, &mac_addr, ETHER_ADDR_LEN);
|
||||
|
||||
assert_se(tlv_packet_new(&m) >= 0);
|
||||
|
||||
assert_se(tlv_packet_append_bytes(m, ðer, 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_get_neighbors(lldp, &neighbors) == 1);
|
||||
|
||||
assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
|
||||
assert_se(id16 == 0x1234);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_by(int ifindex, char ***ret) {
|
||||
return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret);
|
||||
_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, int **ret) {
|
||||
return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
|
||||
}
|
||||
|
||||
static inline int MONITOR_TO_FD(sd_network_monitor *m) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
(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.");
|
||||
|
||||
r = link_lldp_tx_start(link);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not save LLDP: %m");
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
347
src/network/networkd-lldp-tx.c
Normal file
347
src/network/networkd-lldp-tx.c
Normal file
@@ -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(), ¤t) >= 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);
|
||||
}
|
||||
25
src/network/networkd-lldp-tx.h
Normal file
25
src/network/networkd-lldp-tx.h
Normal file
@@ -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);
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata);
|
||||
|
||||
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);
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors);
|
||||
|
||||
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_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);
|
||||
|
||||
int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
|
||||
/* 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);
|
||||
|
||||
int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
|
||||
/* 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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
/*
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user