mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-08 16:30:23 +01:00
systemd: merge branch 'th/systemd-lldp-bgo763384' into master
https://bugzilla.gnome.org/show_bug.cgi?id=763384
This commit is contained in:
commit
e1e428b21e
72 changed files with 6029 additions and 2546 deletions
|
|
@ -86,6 +86,9 @@ AC_SUBST(nmdatadir, '${datadir}'/$PACKAGE, [NetworkManager shared data directory
|
|||
AC_SUBST(nmstatedir, '${localstatedir}'/lib/$PACKAGE, [NetworkManager persistent state directory])
|
||||
AC_SUBST(nmrundir, '${runstatedir}'/$PACKAGE, [NetworkManager runtime state directory])
|
||||
|
||||
AC_GNU_SOURCE
|
||||
AC_CHECK_FUNCS([__secure_getenv secure_getenv])
|
||||
|
||||
# Alternative configuration plugins
|
||||
AC_ARG_ENABLE(config-plugin-ibft, AS_HELP_STRING([--enable-config-plugin-ibft], [enable ibft configuration plugin]))
|
||||
AC_ARG_ENABLE(ifcfg-rh, AS_HELP_STRING([--enable-ifcfg-rh], [enable ifcfg-rh configuration plugin (Fedora/RHEL)]))
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/basic/async.h \
|
||||
systemd/src/basic/escape.c \
|
||||
systemd/src/basic/escape.h \
|
||||
systemd/src/basic/ether-addr-util.c \
|
||||
systemd/src/basic/ether-addr-util.h \
|
||||
systemd/src/basic/fd-util.c \
|
||||
systemd/src/basic/fd-util.h \
|
||||
systemd/src/basic/fileio.c \
|
||||
|
|
@ -106,6 +108,7 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/basic/set.h \
|
||||
systemd/src/basic/siphash24.c \
|
||||
systemd/src/basic/siphash24.h \
|
||||
systemd/src/basic/socket-util.c \
|
||||
systemd/src/basic/socket-util.h \
|
||||
systemd/src/basic/sparse-endian.h \
|
||||
systemd/src/basic/stdio-util.h \
|
||||
|
|
@ -138,14 +141,11 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/libsystemd-network/dhcp6-network.c \
|
||||
systemd/src/libsystemd-network/dhcp6-option.c \
|
||||
systemd/src/libsystemd-network/dhcp6-protocol.h \
|
||||
systemd/src/libsystemd-network/lldp-internal.c \
|
||||
systemd/src/libsystemd-network/lldp-internal.h \
|
||||
systemd/src/libsystemd-network/lldp-neighbor.c \
|
||||
systemd/src/libsystemd-network/lldp-neighbor.h \
|
||||
systemd/src/libsystemd-network/lldp-network.c \
|
||||
systemd/src/libsystemd-network/lldp-network.h \
|
||||
systemd/src/libsystemd-network/lldp-port.c \
|
||||
systemd/src/libsystemd-network/lldp-port.h \
|
||||
systemd/src/libsystemd-network/lldp-tlv.c \
|
||||
systemd/src/libsystemd-network/lldp-tlv.h \
|
||||
systemd/src/libsystemd-network/lldp.h \
|
||||
systemd/src/libsystemd-network/network-internal.c \
|
||||
systemd/src/libsystemd-network/network-internal.h \
|
||||
|
|
@ -156,6 +156,7 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/libsystemd-network/sd-ipv4acd.c \
|
||||
systemd/src/libsystemd-network/sd-ipv4ll.c \
|
||||
systemd/src/libsystemd-network/sd-lldp.c \
|
||||
systemd/src/libsystemd/sd-event/sd-event.c \
|
||||
systemd/src/libsystemd/sd-id128/sd-id128.c \
|
||||
systemd/src/shared/dns-domain.c \
|
||||
systemd/src/shared/dns-domain.h \
|
||||
|
|
|
|||
|
|
@ -1235,8 +1235,7 @@ update_dynamic_ip_setup (NMDevice *self)
|
|||
nm_lldp_listener_stop (priv->lldp_listener);
|
||||
addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length);
|
||||
|
||||
if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self),
|
||||
nm_device_get_iface (self), addr, addr_length, &error)) {
|
||||
if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) {
|
||||
_LOGD (LOGD_DEVICE, "LLDP listener %p could not be restarted: %s",
|
||||
priv->lldp_listener, error->message);
|
||||
g_clear_error (&error);
|
||||
|
|
@ -3564,8 +3563,7 @@ activate_stage2_device_config (NMDevice *self)
|
|||
|
||||
addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length);
|
||||
|
||||
if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self),
|
||||
nm_device_get_iface (self), addr, addr_length, &error))
|
||||
if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error))
|
||||
_LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener);
|
||||
else {
|
||||
_LOGD (LOGD_DEVICE, "LLDP listener %p could not be started: %s",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "nm-default.h"
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sd-lldp.h"
|
||||
#include "lldp.h"
|
||||
|
|
@ -31,6 +32,10 @@
|
|||
#define MAX_NEIGHBORS 4096
|
||||
#define MIN_UPDATE_INTERVAL 2
|
||||
|
||||
#define LLDP_MAC_NEAREST_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }))
|
||||
#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }))
|
||||
#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }))
|
||||
|
||||
typedef struct {
|
||||
char *iface;
|
||||
int ifindex;
|
||||
|
|
@ -58,7 +63,7 @@ typedef struct {
|
|||
char *chassis_id;
|
||||
char *port_id;
|
||||
|
||||
int dest;
|
||||
struct ether_addr destination_address;
|
||||
|
||||
GHashTable *tlvs;
|
||||
} LLDPNeighbor;
|
||||
|
|
@ -91,6 +96,16 @@ static void process_lldp_neighbors (NMLldpListener *self);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
ether_addr_equal (const struct ether_addr *a1, const struct ether_addr *a2)
|
||||
{
|
||||
nm_assert (a1);
|
||||
nm_assert (a2);
|
||||
|
||||
G_STATIC_ASSERT_EXPR (sizeof (*a1) == ETH_ALEN);
|
||||
return memcmp (a1, a2, ETH_ALEN) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gvalue_destroy (gpointer data)
|
||||
{
|
||||
|
|
@ -101,16 +116,42 @@ gvalue_destroy (gpointer data)
|
|||
}
|
||||
|
||||
static GValue *
|
||||
gvalue_new_nstr (const char *str, guint16 len)
|
||||
gvalue_new_str (const char *str)
|
||||
{
|
||||
GValue *value;
|
||||
|
||||
value = g_slice_new0 (GValue);
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_take_string (value, strndup (str, len));
|
||||
g_value_set_string (value, str ?: "");
|
||||
return value;
|
||||
}
|
||||
|
||||
static GValue *
|
||||
gvalue_new_str_ptr (const void *str, gsize len)
|
||||
{
|
||||
const char *s = str;
|
||||
const char *tmp;
|
||||
gsize len0 = len;
|
||||
gs_free char *str_free = NULL;
|
||||
gs_free char *str_escaped = NULL;
|
||||
|
||||
/* truncate at first NUL, including removing trailing NULs*/
|
||||
tmp = memchr (s, '\0', len);
|
||||
if (tmp)
|
||||
len = tmp - s;
|
||||
|
||||
if (!len)
|
||||
return gvalue_new_str ("");
|
||||
|
||||
if (len0 <= len || s[len] != '\0') {
|
||||
/* hmpf, g_strescape needs a trailing NUL. Need to clone */
|
||||
s = str_free = g_strndup (s, len);
|
||||
}
|
||||
|
||||
str_escaped = g_strescape (s, NULL);
|
||||
return gvalue_new_str (str_escaped);
|
||||
}
|
||||
|
||||
static GValue *
|
||||
gvalue_new_uint (guint val)
|
||||
{
|
||||
|
|
@ -122,6 +163,21 @@ gvalue_new_uint (guint val)
|
|||
return value;
|
||||
}
|
||||
|
||||
static GValue *
|
||||
gvalue_new_uint_u8 (const void *data)
|
||||
{
|
||||
return gvalue_new_uint (*((const guint8 *) data));
|
||||
}
|
||||
|
||||
static GValue *
|
||||
gvalue_new_uint_u16 (const void *data)
|
||||
{
|
||||
guint16 v;
|
||||
|
||||
memcpy (&v, data, sizeof (v));
|
||||
return gvalue_new_uint (ntohs (v));
|
||||
}
|
||||
|
||||
static guint
|
||||
lldp_neighbor_id_hash (gconstpointer ptr)
|
||||
{
|
||||
|
|
@ -174,7 +230,7 @@ lldp_neighbor_equal (LLDPNeighbor *a, LLDPNeighbor *b)
|
|||
|
||||
if ( a->chassis_id_type != b->chassis_id_type
|
||||
|| a->port_id_type != b->port_id_type
|
||||
|| a->dest != b->dest
|
||||
|| ether_addr_equal (&a->destination_address, &b->destination_address)
|
||||
|| g_strcmp0 (a->chassis_id, b->chassis_id)
|
||||
|| g_strcmp0 (a->port_id, b->port_id))
|
||||
return FALSE;
|
||||
|
|
@ -258,13 +314,13 @@ static void
|
|||
process_lldp_neighbors (NMLldpListener *self)
|
||||
{
|
||||
NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
|
||||
nm_auto_free sd_lldp_packet **packets = NULL;
|
||||
nm_auto_free sd_lldp_neighbor **neighbors = NULL;
|
||||
GHashTable *hash;
|
||||
int num, i;
|
||||
int num, i, r;
|
||||
|
||||
g_return_if_fail (priv->lldp_handle);
|
||||
|
||||
num = sd_lldp_get_packets (priv->lldp_handle, &packets);
|
||||
num = sd_lldp_get_neighbors (priv->lldp_handle, &neighbors);
|
||||
if (num < 0) {
|
||||
_LOGD ("process: error %d retrieving neighbor packets for %s",
|
||||
num, priv->iface);
|
||||
|
|
@ -274,35 +330,40 @@ process_lldp_neighbors (NMLldpListener *self)
|
|||
hash = g_hash_table_new_full (lldp_neighbor_id_hash, lldp_neighbor_id_equal,
|
||||
(GDestroyNotify) lldp_neighbor_free, NULL);
|
||||
|
||||
for (i = 0; packets && i < num; i++) {
|
||||
for (i = 0; neighbors && i < num; i++) {
|
||||
nm_auto (lldp_neighbor_freep) LLDPNeighbor *neigh = NULL;
|
||||
uint8_t chassis_id_type, port_id_type, *chassis_id, *port_id, data8;
|
||||
uint16_t chassis_id_len, port_id_len, len, data16;
|
||||
uint8_t chassis_id_type, port_id_type;
|
||||
uint16_t data16;
|
||||
uint8_t *data8;
|
||||
const void *chassis_id, *port_id;
|
||||
gsize chassis_id_len, port_id_len, len;
|
||||
GValue *value;
|
||||
char *str;
|
||||
int r;
|
||||
const char *str;
|
||||
|
||||
if (i >= MAX_NEIGHBORS)
|
||||
goto next_packet;
|
||||
break;
|
||||
|
||||
r = sd_lldp_packet_read_chassis_id (packets[i], &chassis_id_type,
|
||||
&chassis_id, &chassis_id_len);
|
||||
r = sd_lldp_neighbor_get_chassis_id (neighbors[i], &chassis_id_type,
|
||||
&chassis_id, &chassis_id_len);
|
||||
if (r < 0)
|
||||
goto next_packet;
|
||||
goto next_neighbor;
|
||||
if (chassis_id_len < 1)
|
||||
goto next_neighbor;
|
||||
|
||||
r = sd_lldp_packet_read_port_id (packets[i], &port_id_type,
|
||||
&port_id, &port_id_len);
|
||||
r = sd_lldp_neighbor_get_port_id (neighbors[i], &port_id_type,
|
||||
&port_id, &port_id_len);
|
||||
if (r < 0)
|
||||
goto next_packet;
|
||||
goto next_neighbor;
|
||||
if (port_id_len < 1)
|
||||
goto next_neighbor;
|
||||
|
||||
neigh = g_slice_new0 (LLDPNeighbor);
|
||||
neigh->tlvs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy);
|
||||
neigh->chassis_id_type = chassis_id_type;
|
||||
neigh->port_id_type = port_id_type;
|
||||
sd_lldp_packet_get_destination_type (packets[i], &neigh->dest);
|
||||
|
||||
if (chassis_id_len < 1)
|
||||
goto next_packet;
|
||||
if (sd_lldp_neighbor_get_destination_address (neighbors[i], &neigh->destination_address) < 0)
|
||||
goto next_neighbor;
|
||||
|
||||
switch (chassis_id_type) {
|
||||
case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
|
||||
|
|
@ -316,12 +377,9 @@ process_lldp_neighbors (NMLldpListener *self)
|
|||
break;
|
||||
default:
|
||||
_LOGD ("process: unsupported chassis ID type %d", chassis_id_type);
|
||||
goto next_packet;
|
||||
goto next_neighbor;
|
||||
}
|
||||
|
||||
if (port_id_len < 1)
|
||||
goto next_packet;
|
||||
|
||||
switch (port_id_type) {
|
||||
case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
|
||||
case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
|
||||
|
|
@ -334,59 +392,121 @@ process_lldp_neighbors (NMLldpListener *self)
|
|||
break;
|
||||
default:
|
||||
_LOGD ("process: unsupported port ID type %d", port_id_type);
|
||||
goto next_packet;
|
||||
goto next_neighbor;
|
||||
}
|
||||
|
||||
if (sd_lldp_packet_read_port_description (packets[i], &str, &len) == 0) {
|
||||
value = gvalue_new_nstr (str, len);
|
||||
if (sd_lldp_neighbor_get_port_description (neighbors[i], &str) == 0) {
|
||||
value = gvalue_new_str (str);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_PORT_DESCRIPTION, value);
|
||||
}
|
||||
|
||||
if (sd_lldp_packet_read_system_name (packets[i], &str, &len) == 0) {
|
||||
value = gvalue_new_nstr (str, len);
|
||||
if (sd_lldp_neighbor_get_system_name (neighbors[i], &str) == 0) {
|
||||
value = gvalue_new_str (str);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_NAME, value);
|
||||
}
|
||||
|
||||
if (sd_lldp_packet_read_system_description (packets[i], &str, &len) == 0) {
|
||||
value = gvalue_new_nstr (str, len);
|
||||
if (sd_lldp_neighbor_get_system_description (neighbors[i], &str) == 0) {
|
||||
value = gvalue_new_str (str);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, value);
|
||||
}
|
||||
|
||||
if (sd_lldp_packet_read_system_capability (packets[i], &data16) == 0) {
|
||||
if (sd_lldp_neighbor_get_system_capabilities (neighbors[i], &data16) == 0) {
|
||||
value = gvalue_new_uint (data16);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, value);
|
||||
}
|
||||
|
||||
if (sd_lldp_packet_read_port_vlan_id (packets[i], &data16) == 0) {
|
||||
value = gvalue_new_uint (data16);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PVID, value);
|
||||
}
|
||||
if (sd_lldp_neighbor_tlv_rewind (neighbors[i]) < 0)
|
||||
goto next_neighbor;
|
||||
do {
|
||||
guint8 oui[3];
|
||||
guint8 subtype;
|
||||
|
||||
if (sd_lldp_packet_read_port_protocol_vlan_id (packets[i], &data8, &data16) == 0) {
|
||||
value = gvalue_new_uint (data16);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID, value);
|
||||
r = sd_lldp_neighbor_tlv_get_oui (neighbors[i], oui, &subtype);
|
||||
if (r < 0) {
|
||||
if (r == -ENXIO)
|
||||
continue;
|
||||
goto next_neighbor;
|
||||
}
|
||||
|
||||
value = gvalue_new_uint (data8);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, value);
|
||||
}
|
||||
if (!( memcmp (oui, LLDP_OUI_802_1, sizeof (oui)) == 0
|
||||
&& NM_IN_SET (subtype,
|
||||
LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID,
|
||||
LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID,
|
||||
LLDP_OUI_802_1_SUBTYPE_VLAN_NAME)))
|
||||
continue;
|
||||
|
||||
if (sd_lldp_packet_read_vlan_name (packets[i], &data16, &str, &len) == 0) {
|
||||
value = gvalue_new_uint (data16);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VID, value);
|
||||
if (sd_lldp_neighbor_tlv_get_raw (neighbors[i], (void *) &data8, &len) < 0)
|
||||
continue;
|
||||
|
||||
value = gvalue_new_nstr (str, len);
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, value);
|
||||
}
|
||||
/* skip over leading TLV, OUI and subtype */
|
||||
#ifdef WITH_MORE_ASSERTS
|
||||
{
|
||||
guint8 check_hdr[] = {
|
||||
0xfe | (((len - 2) >> 8) & 0x01), ((len - 2) & 0xFF),
|
||||
oui[0], oui[1], oui[2],
|
||||
subtype
|
||||
};
|
||||
|
||||
nm_assert (len > 2 + 3 +1);
|
||||
nm_assert (memcmp (data8, check_hdr, sizeof check_hdr) == 0);
|
||||
}
|
||||
#endif
|
||||
if (len <= 6)
|
||||
goto next_neighbor;
|
||||
data8 += 6;
|
||||
len -= 6;
|
||||
|
||||
/*if (memcmp (oui, LLDP_OUI_802_1, sizeof (oui)) == 0)*/
|
||||
{
|
||||
switch (subtype) {
|
||||
case LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID:
|
||||
if (len != 2)
|
||||
goto next_neighbor;
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PVID,
|
||||
gvalue_new_uint_u16 (data8));
|
||||
break;
|
||||
case LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID:
|
||||
if (len != 3)
|
||||
goto next_neighbor;
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS,
|
||||
gvalue_new_uint_u8 (&data8[0]));
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID,
|
||||
gvalue_new_uint_u16 (&data8[1]));
|
||||
break;
|
||||
case LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: {
|
||||
int l;
|
||||
|
||||
if (len <= 3)
|
||||
goto next_neighbor;
|
||||
|
||||
l = data8[2];
|
||||
if (len != 3 + l)
|
||||
goto next_neighbor;
|
||||
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VID,
|
||||
gvalue_new_uint_u16 (&data8[0]));
|
||||
g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME,
|
||||
gvalue_new_str_ptr (&data8[3], len));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
} while (sd_lldp_neighbor_tlv_next (neighbors[i]) > 0);
|
||||
|
||||
_LOGD ("process: new neigh: CHASSIS='%s' PORT='%s'",
|
||||
neigh->chassis_id, neigh->port_id);
|
||||
|
||||
g_hash_table_add (hash, neigh);
|
||||
neigh = NULL;
|
||||
next_packet:
|
||||
sd_lldp_packet_unref (packets[i]);
|
||||
next_neighbor:
|
||||
;
|
||||
}
|
||||
|
||||
for (i = 0; neighbors && i < num; i++)
|
||||
sd_lldp_neighbor_unref (neighbors[i]);
|
||||
|
||||
if (lldp_hash_table_equal (priv->lldp_neighbors, hash)) {
|
||||
g_hash_table_destroy (hash);
|
||||
} else {
|
||||
|
|
@ -405,7 +525,7 @@ next_packet:
|
|||
}
|
||||
|
||||
static void
|
||||
lldp_event_handler (sd_lldp *lldp, int event, void *userdata)
|
||||
lldp_event_handler (sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata)
|
||||
{
|
||||
NMLldpListener *self = userdata;
|
||||
NMLldpListenerPrivate *priv;
|
||||
|
|
@ -423,15 +543,13 @@ lldp_event_handler (sd_lldp *lldp, int event, void *userdata)
|
|||
}
|
||||
|
||||
gboolean
|
||||
nm_lldp_listener_start (NMLldpListener *self, int ifindex, const char *iface,
|
||||
const guint8 *mac, guint mac_len, GError **error)
|
||||
nm_lldp_listener_start (NMLldpListener *self, int ifindex, GError **error)
|
||||
{
|
||||
NMLldpListenerPrivate *priv;
|
||||
int ret;
|
||||
|
||||
g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), FALSE);
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (iface, FALSE);
|
||||
g_return_val_if_fail (!error || !*error, FALSE);
|
||||
|
||||
priv = NM_LLDP_LISTENER_GET_PRIVATE (self);
|
||||
|
|
@ -442,42 +560,35 @@ nm_lldp_listener_start (NMLldpListener *self, int ifindex, const char *iface,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (!mac || mac_len != ETH_ALEN) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
|
||||
"unsupported device");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = sd_lldp_new (ifindex, iface, (struct ether_addr *) mac, &priv->lldp_handle);
|
||||
if (ret) {
|
||||
ret = sd_lldp_new (&priv->lldp_handle, ifindex);
|
||||
if (ret < 0) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
|
||||
"initialization failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = sd_lldp_attach_event (priv->lldp_handle, NULL, 0);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
|
||||
"attach event failed");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ret = sd_lldp_set_callback (priv->lldp_handle, lldp_event_handler, self);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
|
||||
"set callback failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = sd_lldp_start (priv->lldp_handle);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
|
||||
"start failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
priv->ifindex = ifindex;
|
||||
priv->iface = strdup (iface);
|
||||
_LOGD ("start");
|
||||
return TRUE;
|
||||
|
||||
|
|
@ -503,7 +614,6 @@ nm_lldp_listener_stop (NMLldpListener *self)
|
|||
sd_lldp_stop (priv->lldp_handle);
|
||||
sd_lldp_detach_event (priv->lldp_handle);
|
||||
sd_lldp_unref (priv->lldp_handle);
|
||||
g_clear_pointer (&priv->iface, g_free);
|
||||
priv->lldp_handle = NULL;
|
||||
|
||||
size = g_hash_table_size (priv->lldp_neighbors);
|
||||
|
|
@ -536,7 +646,6 @@ nm_lldp_listener_get_neighbors (NMLldpListener *self)
|
|||
GHashTableIter iter;
|
||||
NMLldpListenerPrivate *priv;
|
||||
LLDPNeighbor *neigh;
|
||||
char *dest_str = NULL;
|
||||
|
||||
g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), FALSE);
|
||||
|
||||
|
|
@ -551,6 +660,7 @@ nm_lldp_listener_get_neighbors (NMLldpListener *self)
|
|||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &neigh)) {
|
||||
GHashTableIter val_iter;
|
||||
gpointer key, val;
|
||||
const char *dest_str;
|
||||
|
||||
g_variant_builder_init (&neigh_builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
|
|
@ -567,18 +677,14 @@ nm_lldp_listener_get_neighbors (NMLldpListener *self)
|
|||
NM_LLDP_ATTR_PORT_ID,
|
||||
g_variant_new_string (neigh->port_id));
|
||||
|
||||
switch (neigh->dest) {
|
||||
case SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE:
|
||||
if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_BRIDGE))
|
||||
dest_str = NM_LLDP_DEST_NEAREST_BRIDGE;
|
||||
break;
|
||||
case SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE:
|
||||
else if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE))
|
||||
dest_str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE;
|
||||
break;
|
||||
case SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE:
|
||||
else if (ether_addr_equal (&neigh->destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE))
|
||||
dest_str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE;
|
||||
break;
|
||||
}
|
||||
|
||||
else
|
||||
dest_str = NULL;
|
||||
if (dest_str) {
|
||||
g_variant_builder_add (&neigh_builder, "{sv}",
|
||||
NM_LLDP_ATTR_DESTINATION,
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@ typedef struct {
|
|||
|
||||
GType nm_lldp_listener_get_type (void);
|
||||
NMLldpListener *nm_lldp_listener_new (void);
|
||||
gboolean nm_lldp_listener_start (NMLldpListener *self, int ifindex, const char *iface,
|
||||
const guint8 *mac, guint mac_len, GError **error);
|
||||
gboolean nm_lldp_listener_start (NMLldpListener *self, int ifindex, GError **error);
|
||||
void nm_lldp_listener_stop (NMLldpListener *self);
|
||||
gboolean nm_lldp_listener_is_running (NMLldpListener *self);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "nm-lldp-listener.h"
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "lldp.h"
|
||||
|
||||
|
|
@ -330,9 +331,6 @@ _test_recv_data2_ttl1_check (GMainLoop *loop, NMLldpListener *listener)
|
|||
|
||||
_test_recv_data0_check (loop, listener);
|
||||
|
||||
g_test_skip ("the test is known to fail");
|
||||
return;
|
||||
|
||||
/* wait for signal. */
|
||||
notify_id = g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS,
|
||||
nmtst_main_loop_quit_on_notify, loop);
|
||||
|
|
@ -396,14 +394,18 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data)
|
|||
TestRecvCallbackInfo info = { };
|
||||
gsize i_frames;
|
||||
gulong notify_id;
|
||||
GError *error = NULL;
|
||||
guint sd_id;
|
||||
|
||||
listener = nm_lldp_listener_new ();
|
||||
g_assert (listener != NULL);
|
||||
g_assert (nm_lldp_listener_start (listener, fixture->ifindex, TEST_IFNAME, fixture->mac, ETH_ALEN, NULL));
|
||||
g_assert (nm_lldp_listener_start (listener, fixture->ifindex, &error));
|
||||
g_assert_no_error (error);
|
||||
|
||||
notify_id = g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS,
|
||||
(GCallback) lldp_neighbors_changed, &info);
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
sd_id = nm_sd_event_attach_default ();
|
||||
|
||||
for (i_frames = 0; i_frames < data->frames_len; i_frames++) {
|
||||
const TestRecvFrame *f = data->frames[i_frames];
|
||||
|
|
@ -420,6 +422,7 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data)
|
|||
|
||||
data->check (loop, listener);
|
||||
|
||||
nm_clear_g_source (&sd_id);
|
||||
g_clear_pointer (&loop, g_main_loop_unref);
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/main.c
10
src/main.c
|
|
@ -50,6 +50,7 @@
|
|||
#include "nm-auth-manager.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "nm-exported-object.h"
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#if !defined(NM_DIST_VERSION)
|
||||
# define NM_DIST_VERSION VERSION
|
||||
|
|
@ -271,6 +272,7 @@ main (int argc, char *argv[])
|
|||
gboolean wrote_pidfile = FALSE;
|
||||
char *bad_domains = NULL;
|
||||
NMConfigCmdLineOptions *config_cli;
|
||||
guint sd_id = 0;
|
||||
|
||||
nm_g_type_init ();
|
||||
|
||||
|
|
@ -474,8 +476,11 @@ main (int argc, char *argv[])
|
|||
|
||||
success = TRUE;
|
||||
|
||||
if (configure_and_quit == FALSE)
|
||||
if (configure_and_quit == FALSE) {
|
||||
sd_id = nm_sd_event_attach_default ();
|
||||
|
||||
g_main_loop_run (main_loop);
|
||||
}
|
||||
|
||||
done:
|
||||
nm_exported_object_class_set_quitting ();
|
||||
|
|
@ -486,5 +491,8 @@ done:
|
|||
unlink (global_opt.pidfile);
|
||||
|
||||
nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
|
||||
|
||||
nm_clear_g_source (&sd_id);
|
||||
|
||||
exit (success ? 0 : 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ extern unsigned int if_nametoindex (const char *__ifname);
|
|||
#include "nm-lndp-rdisc.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-setting-ip6-config.h"
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#if !defined(NM_DIST_VERSION)
|
||||
# define NM_DIST_VERSION VERSION
|
||||
|
|
@ -345,6 +346,7 @@ main (int argc, char *argv[])
|
|||
size_t hwaddr_len = 0;
|
||||
gconstpointer tmp;
|
||||
gs_free NMUtilsIPv6IfaceId *iid = NULL;
|
||||
guint sd_id;
|
||||
|
||||
nm_g_type_init ();
|
||||
|
||||
|
|
@ -494,6 +496,8 @@ main (int argc, char *argv[])
|
|||
nm_rdisc_start (rdisc);
|
||||
}
|
||||
|
||||
sd_id = nm_sd_event_attach_default ();
|
||||
|
||||
g_main_loop_run (main_loop);
|
||||
|
||||
g_clear_pointer (&hwaddr, g_byte_array_unref);
|
||||
|
|
@ -502,6 +506,8 @@ main (int argc, char *argv[])
|
|||
unlink (pidfile);
|
||||
|
||||
nm_log_info (LOGD_CORE, "exiting");
|
||||
|
||||
nm_clear_g_source (&sd_id);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,219 +20,126 @@
|
|||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "fd-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
struct sd_event_source {
|
||||
guint refcount;
|
||||
guint id;
|
||||
gpointer user_data;
|
||||
|
||||
GIOChannel *channel;
|
||||
|
||||
union {
|
||||
struct {
|
||||
sd_event_io_handler_t cb;
|
||||
} io;
|
||||
struct {
|
||||
sd_event_time_handler_t cb;
|
||||
uint64_t usec;
|
||||
} time;
|
||||
};
|
||||
};
|
||||
|
||||
static struct sd_event_source *
|
||||
source_new (void)
|
||||
{
|
||||
struct sd_event_source *source;
|
||||
|
||||
source = g_slice_new0 (struct sd_event_source);
|
||||
source->refcount = 1;
|
||||
return source;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
sd_event_source_set_priority (sd_event_source *s, int64_t priority)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event_source*
|
||||
sd_event_source_unref (sd_event_source *s)
|
||||
{
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
g_return_val_if_fail (s->refcount, NULL);
|
||||
|
||||
s->refcount--;
|
||||
if (s->refcount == 0) {
|
||||
if (s->id)
|
||||
g_source_remove (s->id);
|
||||
if (s->channel) {
|
||||
/* Don't shut down the channel since systemd will soon close
|
||||
* the file descriptor itself, which would cause -EBADF.
|
||||
*/
|
||||
g_io_channel_unref (s->channel);
|
||||
}
|
||||
g_slice_free (struct sd_event_source, s);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_source_set_description(sd_event_source *s, const char *description)
|
||||
{
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
g_source_set_name_by_id (s->id, description);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source)
|
||||
{
|
||||
int r, revents = 0;
|
||||
gboolean result;
|
||||
|
||||
if (condition & G_IO_IN)
|
||||
revents |= EPOLLIN;
|
||||
if (condition & G_IO_OUT)
|
||||
revents |= EPOLLOUT;
|
||||
if (condition & G_IO_PRI)
|
||||
revents |= EPOLLPRI;
|
||||
if (condition & G_IO_ERR)
|
||||
revents |= EPOLLERR;
|
||||
if (condition & G_IO_HUP)
|
||||
revents |= EPOLLHUP;
|
||||
|
||||
source->refcount++;
|
||||
|
||||
r = source->io.cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data);
|
||||
if (r < 0 || source->refcount <= 1) {
|
||||
source->id = 0;
|
||||
result = G_SOURCE_REMOVE;
|
||||
} else
|
||||
result = G_SOURCE_CONTINUE;
|
||||
|
||||
sd_event_source_unref (source);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata)
|
||||
{
|
||||
struct sd_event_source *source;
|
||||
GIOChannel *channel;
|
||||
GIOCondition condition = 0;
|
||||
|
||||
/* systemd supports floating sd_event_source by omitting the @s argument.
|
||||
* We don't have such users and don't implement floating references. */
|
||||
g_return_val_if_fail (s, -EINVAL);
|
||||
|
||||
channel = g_io_channel_unix_new (fd);
|
||||
if (!channel)
|
||||
return -EINVAL;
|
||||
|
||||
source = source_new ();
|
||||
source->io.cb = callback;
|
||||
source->user_data = userdata;
|
||||
source->channel = channel;
|
||||
|
||||
if (events & EPOLLIN)
|
||||
condition |= G_IO_IN;
|
||||
if (events & EPOLLOUT)
|
||||
condition |= G_IO_OUT;
|
||||
if (events & EPOLLPRI)
|
||||
condition |= G_IO_PRI;
|
||||
if (events & EPOLLERR)
|
||||
condition |= G_IO_ERR;
|
||||
if (events & EPOLLHUP)
|
||||
condition |= G_IO_HUP;
|
||||
|
||||
g_io_channel_set_encoding (source->channel, NULL, NULL);
|
||||
g_io_channel_set_buffered (source->channel, FALSE);
|
||||
source->id = g_io_add_watch (source->channel, condition, (GIOFunc) io_ready, source);
|
||||
|
||||
*s = source;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
time_ready (struct sd_event_source *source)
|
||||
{
|
||||
source->refcount++;
|
||||
|
||||
source->time.cb (source, source->time.usec, source->user_data);
|
||||
source->id = 0;
|
||||
|
||||
sd_event_source_unref (source);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata)
|
||||
{
|
||||
struct sd_event_source *source;
|
||||
uint64_t n = now (clock);
|
||||
|
||||
/* systemd supports floating sd_event_source by omitting the @s argument.
|
||||
* We don't have such users and don't implement floating references. */
|
||||
g_return_val_if_fail (s, -EINVAL);
|
||||
|
||||
source = source_new ();
|
||||
source->time.cb = callback;
|
||||
source->user_data = userdata;
|
||||
source->time.usec = usec;
|
||||
|
||||
if (usec > 1000)
|
||||
usec = n < usec - 1000 ? usec - n : 1000;
|
||||
source->id = g_timeout_add (usec / 1000, (GSourceFunc) time_ready, source);
|
||||
|
||||
*s = source;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sd_event is basically a GMainContext; but since we only
|
||||
* ever use the default context, nothing to do here.
|
||||
*/
|
||||
|
||||
int
|
||||
sd_event_default (sd_event **e)
|
||||
{
|
||||
*e = GUINT_TO_POINTER (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_event*
|
||||
sd_event_ref (sd_event *e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
sd_event*
|
||||
sd_event_unref (sd_event *e)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
sd_event_now (sd_event *e, clockid_t clock, uint64_t *usec)
|
||||
{
|
||||
*usec = now (clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asynchronous_close(int fd) {
|
||||
safe_close(fd);
|
||||
asynchronous_close (int fd) {
|
||||
safe_close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Integrating sd_event into glib. Taken and adjusted from
|
||||
* https://www.freedesktop.org/software/systemd/man/sd_event_get_fd.html
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct SDEventSource {
|
||||
GSource source;
|
||||
GPollFD pollfd;
|
||||
sd_event *event;
|
||||
guint *default_source_id;
|
||||
} SDEventSource;
|
||||
|
||||
static gboolean
|
||||
event_prepare (GSource *source, gint *timeout_)
|
||||
{
|
||||
return sd_event_prepare (((SDEventSource *) source)->event) > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_check (GSource *source)
|
||||
{
|
||||
return sd_event_wait (((SDEventSource *) source)->event, 0) > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
return sd_event_dispatch (((SDEventSource *)source)->event) > 0;
|
||||
}
|
||||
|
||||
static void
|
||||
event_finalize (GSource *source)
|
||||
{
|
||||
SDEventSource *s;
|
||||
|
||||
s = (SDEventSource *) source;
|
||||
sd_event_unref (s->event);
|
||||
if (s->default_source_id)
|
||||
*s->default_source_id = 0;
|
||||
}
|
||||
|
||||
static SDEventSource *
|
||||
event_create_source (sd_event *event, guint *default_source_id)
|
||||
{
|
||||
static GSourceFuncs event_funcs = {
|
||||
.prepare = event_prepare,
|
||||
.check = event_check,
|
||||
.dispatch = event_dispatch,
|
||||
.finalize = event_finalize,
|
||||
};
|
||||
SDEventSource *source;
|
||||
|
||||
g_return_val_if_fail (event, NULL);
|
||||
|
||||
source = (SDEventSource *) g_source_new (&event_funcs, sizeof (SDEventSource));
|
||||
|
||||
source->event = sd_event_ref (event);
|
||||
source->pollfd.fd = sd_event_get_fd (event);
|
||||
source->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
|
||||
source->default_source_id = default_source_id;
|
||||
|
||||
g_source_add_poll ((GSource *) source, &source->pollfd);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
static guint
|
||||
event_attach (sd_event *event, GMainContext *context)
|
||||
{
|
||||
SDEventSource *source;
|
||||
guint id;
|
||||
int r;
|
||||
sd_event *e = event;
|
||||
guint *p_default_source_id = NULL;
|
||||
|
||||
if (!e) {
|
||||
static guint default_source_id = 0;
|
||||
|
||||
if (default_source_id) {
|
||||
/* The default event cannot be registered multiple times. */
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
|
||||
r = sd_event_default (&e);
|
||||
if (r < 0)
|
||||
g_return_val_if_reached (0);
|
||||
|
||||
p_default_source_id = &default_source_id;
|
||||
}
|
||||
|
||||
source = event_create_source (e, p_default_source_id);
|
||||
id = g_source_attach ((GSource *) source, context);
|
||||
g_source_unref ((GSource *) source);
|
||||
|
||||
|
||||
if (!event) {
|
||||
*p_default_source_id = id;
|
||||
sd_event_unref (e);
|
||||
}
|
||||
|
||||
g_return_val_if_fail (id, 0);
|
||||
return id;
|
||||
}
|
||||
|
||||
guint
|
||||
nm_sd_event_attach_default (void)
|
||||
{
|
||||
return event_attach (NULL, NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include <sys/resource.h>
|
||||
#include <time.h>
|
||||
|
||||
guint nm_sd_event_attach_default (void);
|
||||
|
||||
#define noreturn G_GNUC_NORETURN
|
||||
|
||||
#ifndef CLOCK_BOOTTIME
|
||||
|
|
@ -102,6 +104,7 @@ G_STMT_START { \
|
|||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <net/if_arp.h>
|
||||
|
||||
|
|
@ -110,6 +113,18 @@ G_STMT_START { \
|
|||
#define BPF_XOR 0xa0
|
||||
#endif
|
||||
|
||||
#ifndef ETHERTYPE_LLDP
|
||||
#define ETHERTYPE_LLDP 0x88cc
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SECURE_GETENV
|
||||
# ifdef HAVE___SECURE_GETENV
|
||||
# define secure_getenv __secure_getenv
|
||||
# else
|
||||
# error neither secure_getenv nor __secure_getenv is available
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* work around missing uchar.h */
|
||||
|
|
@ -118,6 +133,14 @@ typedef guint32 char32_t;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
|
||||
|
||||
static inline int
|
||||
sd_notify (int unset_environment, const char *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Can't include both net/if.h and linux/if.h; so have to define this here */
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
|
|
|
|||
|
|
@ -51,25 +51,29 @@ static inline void freep(void *p) {
|
|||
|
||||
#define _cleanup_free_ _cleanup_(freep)
|
||||
|
||||
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
|
||||
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
||||
return NULL;
|
||||
|
||||
return malloc(a * b);
|
||||
static inline bool size_multiply_overflow(size_t size, size_t need) {
|
||||
return _unlikely_(need != 0 && size > (SIZE_MAX / need));
|
||||
}
|
||||
|
||||
_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
|
||||
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
||||
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
|
||||
if (size_multiply_overflow(size, need))
|
||||
return NULL;
|
||||
|
||||
return realloc(p, a * b);
|
||||
return malloc(size * need);
|
||||
}
|
||||
|
||||
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
|
||||
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
||||
_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) {
|
||||
if (size_multiply_overflow(size, need))
|
||||
return NULL;
|
||||
|
||||
return memdup(p, a * b);
|
||||
return realloc(p, size * need);
|
||||
}
|
||||
|
||||
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
|
||||
if (size_multiply_overflow(size, need))
|
||||
return NULL;
|
||||
|
||||
return memdup(p, size * need);
|
||||
}
|
||||
|
||||
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
|
||||
|
|
|
|||
|
|
@ -415,6 +415,34 @@ char *xescape(const char *s, const char *bad) {
|
|||
return r;
|
||||
}
|
||||
|
||||
char *octescape(const char *s, size_t len) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
|
||||
/* Escapes all chars in bad, in addition to \ and " chars,
|
||||
* in \nnn style escaping. */
|
||||
|
||||
r = new(char, len * 4 + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
for (f = s, t = r; f < s + len; f++) {
|
||||
|
||||
if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') {
|
||||
*(t++) = '\\';
|
||||
*(t++) = '0' + (*f >> 6);
|
||||
*(t++) = '0' + ((*f >> 3) & 8);
|
||||
*(t++) = '0' + (*f & 8);
|
||||
} else
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
|
||||
assert(bad);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
|
|||
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
|
||||
|
||||
char *xescape(const char *s, const char *bad);
|
||||
char *octescape(const char *s, size_t len);
|
||||
|
||||
char *shell_escape(const char *s, const char *bad);
|
||||
char *shell_maybe_quote(const char *s);
|
||||
|
|
|
|||
58
src/systemd/src/basic/ether-addr-util.c
Normal file
58
src/systemd/src/basic/ether-addr-util.c
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen
|
||||
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
|
||||
assert(addr);
|
||||
assert(buffer);
|
||||
|
||||
/* Like ether_ntoa() but uses %02x instead of %x to print
|
||||
* ethernet addresses, which makes them look less funny. Also,
|
||||
* doesn't use a static buffer. */
|
||||
|
||||
sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
addr->ether_addr_octet[0],
|
||||
addr->ether_addr_octet[1],
|
||||
addr->ether_addr_octet[2],
|
||||
addr->ether_addr_octet[3],
|
||||
addr->ether_addr_octet[4],
|
||||
addr->ether_addr_octet[5]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
37
src/systemd/src/basic/ether-addr-util.h
Normal file
37
src/systemd/src/basic/ether-addr-util.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2014 Tom Gundersen
|
||||
|
||||
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 <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_equal(const struct ether_addr *a, const struct ether_addr *b);
|
||||
|
||||
#define ETHER_ADDR_NULL ((const struct ether_addr){})
|
||||
|
||||
static inline bool ether_addr_is_null(const struct ether_addr *addr) {
|
||||
return ether_addr_equal(addr, ÐER_ADDR_NULL);
|
||||
}
|
||||
|
|
@ -42,9 +42,7 @@
|
|||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "random-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "stdio-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
|
|
@ -356,7 +354,7 @@ static int parse_env_file_internal(
|
|||
case KEY:
|
||||
if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
line++;
|
||||
n_key = 0;
|
||||
} else if (c == '=') {
|
||||
state = PRE_VALUE;
|
||||
|
|
@ -380,7 +378,7 @@ static int parse_env_file_internal(
|
|||
case PRE_VALUE:
|
||||
if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
line++;
|
||||
key[n_key] = 0;
|
||||
|
||||
if (value)
|
||||
|
|
@ -420,7 +418,7 @@ static int parse_env_file_internal(
|
|||
case VALUE:
|
||||
if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
line++;
|
||||
|
||||
key[n_key] = 0;
|
||||
|
||||
|
|
@ -539,7 +537,7 @@ static int parse_env_file_internal(
|
|||
state = COMMENT_ESCAPE;
|
||||
else if (strchr(newline, c)) {
|
||||
state = PRE_KEY;
|
||||
line ++;
|
||||
line++;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -912,7 +910,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
|
|||
/* Back off one char if there's nothing but whitespace
|
||||
and zeros */
|
||||
if (!*t || isspace(*t))
|
||||
t --;
|
||||
t--;
|
||||
}
|
||||
|
||||
len = strcspn(t, terminator);
|
||||
|
|
|
|||
|
|
@ -291,24 +291,6 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
|
||||
assert(fd >= 0);
|
||||
|
||||
/* Under the assumption that we are running privileged we
|
||||
* first change the access mode and only then hand out
|
||||
* ownership to avoid a window where access is too open. */
|
||||
|
||||
if (mode != MODE_INVALID)
|
||||
if (fchmod(fd, mode) < 0)
|
||||
return -errno;
|
||||
|
||||
if (uid != UID_INVALID || gid != GID_INVALID)
|
||||
if (fchown(fd, uid, gid) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int fchmod_umask(int fd, mode_t m) {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ int readlink_and_canonicalize(const char *p, char **r);
|
|||
int readlink_and_make_absolute_root(const char *root, const char *path, char **ret);
|
||||
|
||||
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
int fchmod_umask(int fd, mode_t mode);
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ enum HashmapType {
|
|||
};
|
||||
|
||||
struct _packed_ indirect_storage {
|
||||
char *storage; /* where buckets and DIBs are stored */
|
||||
void *storage; /* where buckets and DIBs are stored */
|
||||
uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */
|
||||
|
||||
unsigned n_entries; /* number of stored entries */
|
||||
|
|
@ -197,7 +197,7 @@ struct direct_storage {
|
|||
/* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
|
||||
* That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
|
||||
* or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
|
||||
char storage[sizeof(struct indirect_storage)];
|
||||
uint8_t storage[sizeof(struct indirect_storage)];
|
||||
};
|
||||
|
||||
#define DIRECT_BUCKETS(entry_t) \
|
||||
|
|
@ -306,7 +306,7 @@ static void n_entries_dec(HashmapBase *h) {
|
|||
h->n_direct_entries--;
|
||||
}
|
||||
|
||||
static char *storage_ptr(HashmapBase *h) {
|
||||
static void *storage_ptr(HashmapBase *h) {
|
||||
return h->has_indirect ? h->indirect.storage
|
||||
: h->direct.storage;
|
||||
}
|
||||
|
|
@ -351,7 +351,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
|
|||
|
||||
static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) {
|
||||
return (struct hashmap_base_entry*)
|
||||
(storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
|
||||
((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
|
||||
}
|
||||
|
||||
static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) {
|
||||
|
|
@ -385,7 +385,7 @@ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_
|
|||
|
||||
static dib_raw_t *dib_raw_ptr(HashmapBase *h) {
|
||||
return (dib_raw_t*)
|
||||
(storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
|
||||
((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
|
||||
}
|
||||
|
||||
static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
|
||||
|
|
@ -1032,7 +1032,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
|
|||
*/
|
||||
static int resize_buckets(HashmapBase *h, unsigned entries_add) {
|
||||
struct swap_entries swap;
|
||||
char *new_storage;
|
||||
void *new_storage;
|
||||
dib_raw_t *old_dibs, *new_dibs;
|
||||
const struct hashmap_type_info *hi;
|
||||
unsigned idx, optimal_idx;
|
||||
|
|
@ -1099,7 +1099,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) {
|
|||
h->indirect.n_buckets = (1U << new_shift) /
|
||||
(hi->entry_size + sizeof(dib_raw_t));
|
||||
|
||||
old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets);
|
||||
old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets);
|
||||
new_dibs = dib_raw_ptr(h);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "alloc-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
char octchar(int x) {
|
||||
return '0' + (x & 7);
|
||||
|
|
@ -277,8 +278,8 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
|
|||
if (padding) {
|
||||
/* strip the padding */
|
||||
while (l > 0 && p[l - 1] == '=' && pad < 7) {
|
||||
pad ++;
|
||||
l --;
|
||||
pad++;
|
||||
l--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -506,7 +507,7 @@ int unbase64char(char c) {
|
|||
if (c == '+')
|
||||
return offset;
|
||||
|
||||
offset ++;
|
||||
offset++;
|
||||
|
||||
if (c == '/')
|
||||
return offset;
|
||||
|
|
@ -574,7 +575,7 @@ static int base64_append_width(char **prefix, int plen,
|
|||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(t + plen, sep, slen);
|
||||
memcpy_safe(t + plen, sep, slen);
|
||||
|
||||
for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
|
||||
int act = MIN(width, avail);
|
||||
|
|
@ -622,9 +623,9 @@ int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
|
|||
|
||||
/* strip the padding */
|
||||
if (l > 0 && p[l - 1] == '=')
|
||||
l --;
|
||||
l--;
|
||||
if (l > 0 && p[l - 1] == '=')
|
||||
l --;
|
||||
l--;
|
||||
|
||||
/* a group of four input bytes needs three output bytes, in case of
|
||||
padding we need to add two or three extra bytes */
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <bits/local_lim.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -51,6 +50,10 @@ 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 fail is OOM.
|
||||
* It might even return "localhost" if that's set. */
|
||||
|
||||
assert_se(uname(&u) >= 0);
|
||||
|
||||
if (isempty(u.nodename) || streq(u.nodename, "(none)"))
|
||||
|
|
@ -59,6 +62,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') ||
|
||||
|
|
@ -98,7 +126,7 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
|
|||
return false;
|
||||
|
||||
dot = true;
|
||||
n_dots ++;
|
||||
n_dots++;
|
||||
} else {
|
||||
if (!hostname_valid_char(*p))
|
||||
return false;
|
||||
|
|
@ -124,6 +152,8 @@ char* hostname_cleanup(char *s) {
|
|||
|
||||
assert(s);
|
||||
|
||||
strshorten(s, HOST_NAME_MAX);
|
||||
|
||||
for (p = s, d = s, dot = true; *p; p++) {
|
||||
if (*p == '.') {
|
||||
if (dot)
|
||||
|
|
@ -143,8 +173,6 @@ char* hostname_cleanup(char *s) {
|
|||
else
|
||||
*d = 0;
|
||||
|
||||
strshorten(s, HOST_NAME_MAX);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
|
|||
} else if (n > 0)
|
||||
q += n;
|
||||
else
|
||||
q ++;
|
||||
q++;
|
||||
}
|
||||
|
||||
if (q > w) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
|
|||
char *_s = (char *)(s); \
|
||||
_i->iov_base = _s; \
|
||||
_i->iov_len = strlen(_s); \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
|
||||
unsigned j;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#define LIST_HEAD_INIT(head) \
|
||||
do { \
|
||||
(head) = NULL; } \
|
||||
while(false)
|
||||
while (false)
|
||||
|
||||
/* Initialize a list item */
|
||||
#define LIST_INIT(name,item) \
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
typeof(*(item)) *_item = (item); \
|
||||
assert(_item); \
|
||||
_item->name##_prev = _item->name##_next = NULL; \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
/* Prepend an item to the list */
|
||||
#define LIST_PREPEND(name,head,item) \
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
_item->name##_next->name##_prev = _item; \
|
||||
_item->name##_prev = NULL; \
|
||||
*_head = _item; \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
/* Append an item to the list */
|
||||
#define LIST_APPEND(name,head,item) \
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
typeof(*(head)) *_tail; \
|
||||
LIST_FIND_TAIL(name,head,_tail); \
|
||||
LIST_INSERT_AFTER(name,head,_tail,item); \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
/* Remove an item from the list */
|
||||
#define LIST_REMOVE(name,head,item) \
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
*_head = _item->name##_next; \
|
||||
} \
|
||||
_item->name##_next = _item->name##_prev = NULL; \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
/* Find the head of the list */
|
||||
#define LIST_FIND_HEAD(name,item,head) \
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
_b->name##_prev = _a; \
|
||||
_a->name##_next = _b; \
|
||||
} \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
/* Insert an item before another one (a = where, b = what) */
|
||||
#define LIST_INSERT_BEFORE(name,head,a,b) \
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
_b->name##_next = _a; \
|
||||
_a->name##_prev = _b; \
|
||||
} \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
||||
#define LIST_JUST_US(name,item) \
|
||||
(!(item)->name##_prev && !(item)->name##_next) \
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ void log_assert_failed_return(
|
|||
#ifdef LOG_TRACE
|
||||
# define log_trace(...) log_debug(__VA_ARGS__)
|
||||
#else
|
||||
# define log_trace(...) do {} while(0)
|
||||
# define log_trace(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* Structured logging */
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
/* We override the glibc assert() here. */
|
||||
#undef assert
|
||||
#ifdef NDEBUG
|
||||
#define assert(expr) do {} while(false)
|
||||
#define assert(expr) do {} while (false)
|
||||
#else
|
||||
#define assert(expr) assert_message_se(expr, #expr)
|
||||
#endif
|
||||
|
|
@ -370,6 +370,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
_found; \
|
||||
})
|
||||
|
||||
#define SWAP_TWO(x, y) do { \
|
||||
typeof(x) _t = (x); \
|
||||
(x) = (y); \
|
||||
(y) = (_t); \
|
||||
} while (false)
|
||||
|
||||
/* Define C11 thread_local attribute even on older gcc compiler
|
||||
* version */
|
||||
#ifndef thread_local
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void* mempool_alloc0_tile(struct mempool *mp);
|
|||
void mempool_free_tile(struct mempool *mp, void *p);
|
||||
|
||||
#define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \
|
||||
struct mempool pool_name = { \
|
||||
static struct mempool pool_name = { \
|
||||
.tile_size = sizeof(tile_type), \
|
||||
.at_least = alloc_at_least, \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -511,7 +511,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
|
|||
s = *p;
|
||||
|
||||
/* accept any number of digits, strtoull is limted to 19 */
|
||||
for(i=0; i < digits; i++,s++) {
|
||||
for (i=0; i < digits; i++,s++) {
|
||||
if (*s < '0' || *s > '9') {
|
||||
if (i == 0)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ int set_put_strdupv(Set *s, char **l);
|
|||
#define SET_FOREACH(e, s, i) \
|
||||
for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); )
|
||||
|
||||
#define SET_FOREACH_MOVE(e, d, s) \
|
||||
for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); )
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
|
||||
|
||||
|
|
|
|||
982
src/systemd/src/basic/socket-util.c
Normal file
982
src/systemd/src/basic/socket-util.c
Normal file
|
|
@ -0,0 +1,982 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 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 "nm-sd-adapt.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "formats-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "missing.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "user-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int socket_address_parse(SocketAddress *a, const char *s) {
|
||||
char *e, *n;
|
||||
unsigned u;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
zero(*a);
|
||||
a->type = SOCK_STREAM;
|
||||
|
||||
if (*s == '[') {
|
||||
/* IPv6 in [x:.....:z]:p notation */
|
||||
|
||||
e = strchr(s+1, ']');
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
n = strndupa(s+1, e-s-1);
|
||||
|
||||
errno = 0;
|
||||
if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
|
||||
return errno > 0 ? -errno : -EINVAL;
|
||||
|
||||
e++;
|
||||
if (*e != ':')
|
||||
return -EINVAL;
|
||||
|
||||
e++;
|
||||
r = safe_atou(e, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (u <= 0 || u > 0xFFFF)
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
|
||||
} else if (*s == '/') {
|
||||
/* AF_UNIX socket */
|
||||
|
||||
size_t l;
|
||||
|
||||
l = strlen(s);
|
||||
if (l >= sizeof(a->sockaddr.un.sun_path))
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.un.sun_family = AF_UNIX;
|
||||
memcpy(a->sockaddr.un.sun_path, s, l);
|
||||
a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
|
||||
|
||||
} else if (*s == '@') {
|
||||
/* Abstract AF_UNIX socket */
|
||||
size_t l;
|
||||
|
||||
l = strlen(s+1);
|
||||
if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.un.sun_family = AF_UNIX;
|
||||
memcpy(a->sockaddr.un.sun_path+1, s+1, l);
|
||||
a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
|
||||
|
||||
} else {
|
||||
e = strchr(s, ':');
|
||||
if (e) {
|
||||
r = safe_atou(e+1, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (u <= 0 || u > 0xFFFF)
|
||||
return -EINVAL;
|
||||
|
||||
n = strndupa(s, e-s);
|
||||
|
||||
/* IPv4 in w.x.y.z:p notation? */
|
||||
r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (r > 0) {
|
||||
/* Gotcha, it's a traditional IPv4 address */
|
||||
a->sockaddr.in.sin_family = AF_INET;
|
||||
a->sockaddr.in.sin_port = htons((uint16_t) u);
|
||||
a->size = sizeof(struct sockaddr_in);
|
||||
} else {
|
||||
unsigned idx;
|
||||
|
||||
if (strlen(n) > IF_NAMESIZE-1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Uh, our last resort, an interface name */
|
||||
idx = if_nametoindex(n);
|
||||
if (idx == 0)
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
|
||||
a->sockaddr.in6.sin6_scope_id = idx;
|
||||
a->sockaddr.in6.sin6_addr = in6addr_any;
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Just a port */
|
||||
r = safe_atou(s, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (u <= 0 || u > 0xFFFF)
|
||||
return -EINVAL;
|
||||
|
||||
if (socket_ipv6_is_supported()) {
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
|
||||
a->sockaddr.in6.sin6_addr = in6addr_any;
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
a->sockaddr.in.sin_family = AF_INET;
|
||||
a->sockaddr.in.sin_port = htons((uint16_t) u);
|
||||
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
a->size = sizeof(struct sockaddr_in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
|
||||
SocketAddress b;
|
||||
int r;
|
||||
|
||||
/* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
|
||||
|
||||
r = socket_address_parse(&b, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
|
||||
log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
*a = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
|
||||
int family;
|
||||
unsigned group = 0;
|
||||
_cleanup_free_ char *sfamily = NULL;
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
zero(*a);
|
||||
a->type = SOCK_RAW;
|
||||
|
||||
errno = 0;
|
||||
if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
|
||||
return errno > 0 ? -errno : -EINVAL;
|
||||
|
||||
family = netlink_family_from_string(sfamily);
|
||||
if (family < 0)
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.nl.nl_family = AF_NETLINK;
|
||||
a->sockaddr.nl.nl_groups = group;
|
||||
|
||||
a->type = SOCK_RAW;
|
||||
a->size = sizeof(struct sockaddr_nl);
|
||||
a->protocol = family;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_verify(const SocketAddress *a) {
|
||||
assert(a);
|
||||
|
||||
switch (socket_address_family(a)) {
|
||||
|
||||
case AF_INET:
|
||||
if (a->size != sizeof(struct sockaddr_in))
|
||||
return -EINVAL;
|
||||
|
||||
if (a->sockaddr.in.sin_port == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
case AF_INET6:
|
||||
if (a->size != sizeof(struct sockaddr_in6))
|
||||
return -EINVAL;
|
||||
|
||||
if (a->sockaddr.in6.sin6_port == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
case AF_UNIX:
|
||||
if (a->size < offsetof(struct sockaddr_un, sun_path))
|
||||
return -EINVAL;
|
||||
|
||||
if (a->size > offsetof(struct sockaddr_un, sun_path)) {
|
||||
|
||||
if (a->sockaddr.un.sun_path[0] != 0) {
|
||||
char *e;
|
||||
|
||||
/* path */
|
||||
e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
case AF_NETLINK:
|
||||
|
||||
if (a->size != sizeof(struct sockaddr_nl))
|
||||
return -EINVAL;
|
||||
|
||||
if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
int socket_address_print(const SocketAddress *a, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(ret);
|
||||
|
||||
r = socket_address_verify(a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (socket_address_family(a) == AF_NETLINK) {
|
||||
_cleanup_free_ char *sfamily = NULL;
|
||||
|
||||
r = netlink_family_to_string_alloc(a->protocol, &sfamily);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
|
||||
}
|
||||
|
||||
bool socket_address_can_accept(const SocketAddress *a) {
|
||||
assert(a);
|
||||
|
||||
return
|
||||
a->type == SOCK_STREAM ||
|
||||
a->type == SOCK_SEQPACKET;
|
||||
}
|
||||
|
||||
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
/* Invalid addresses are unequal to all */
|
||||
if (socket_address_verify(a) < 0 ||
|
||||
socket_address_verify(b) < 0)
|
||||
return false;
|
||||
|
||||
if (a->type != b->type)
|
||||
return false;
|
||||
|
||||
if (socket_address_family(a) != socket_address_family(b))
|
||||
return false;
|
||||
|
||||
switch (socket_address_family(a)) {
|
||||
|
||||
case AF_INET:
|
||||
if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
|
||||
return false;
|
||||
|
||||
if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
|
||||
return false;
|
||||
|
||||
if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case AF_UNIX:
|
||||
if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
|
||||
b->size <= offsetof(struct sockaddr_un, sun_path))
|
||||
return false;
|
||||
|
||||
if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
|
||||
return false;
|
||||
|
||||
if (a->sockaddr.un.sun_path[0]) {
|
||||
if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
|
||||
return false;
|
||||
} else {
|
||||
if (a->size != b->size)
|
||||
return false;
|
||||
|
||||
if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AF_NETLINK:
|
||||
if (a->protocol != b->protocol)
|
||||
return false;
|
||||
|
||||
if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Cannot compare, so we assume the addresses are different */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket_address_is(const SocketAddress *a, const char *s, int type) {
|
||||
struct SocketAddress b;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
if (socket_address_parse(&b, s) < 0)
|
||||
return false;
|
||||
|
||||
b.type = type;
|
||||
|
||||
return socket_address_equal(a, &b);
|
||||
}
|
||||
|
||||
bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
|
||||
struct SocketAddress b;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
if (socket_address_parse_netlink(&b, s) < 0)
|
||||
return false;
|
||||
|
||||
return socket_address_equal(a, &b);
|
||||
}
|
||||
|
||||
const char* socket_address_get_path(const SocketAddress *a) {
|
||||
assert(a);
|
||||
|
||||
if (socket_address_family(a) != AF_UNIX)
|
||||
return NULL;
|
||||
|
||||
if (a->sockaddr.un.sun_path[0] == 0)
|
||||
return NULL;
|
||||
|
||||
return a->sockaddr.un.sun_path;
|
||||
}
|
||||
|
||||
bool socket_ipv6_is_supported(void) {
|
||||
if (access("/proc/net/sockstat6", F_OK) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd) {
|
||||
SocketAddress b;
|
||||
socklen_t solen;
|
||||
|
||||
assert(a);
|
||||
assert(fd >= 0);
|
||||
|
||||
b.size = sizeof(b.sockaddr);
|
||||
if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
|
||||
return false;
|
||||
|
||||
if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
|
||||
return false;
|
||||
|
||||
solen = sizeof(b.type);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
|
||||
return false;
|
||||
|
||||
if (b.type != a->type)
|
||||
return false;
|
||||
|
||||
if (a->protocol != 0) {
|
||||
solen = sizeof(b.protocol);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
|
||||
return false;
|
||||
|
||||
if (b.protocol != a->protocol)
|
||||
return false;
|
||||
}
|
||||
|
||||
return socket_address_equal(a, &b);
|
||||
}
|
||||
|
||||
int sockaddr_port(const struct sockaddr *_sa) {
|
||||
union sockaddr_union *sa = (union sockaddr_union*) _sa;
|
||||
|
||||
assert(sa);
|
||||
|
||||
if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
return ntohs(sa->sa.sa_family == AF_INET6 ?
|
||||
sa->in6.sin6_port :
|
||||
sa->in.sin_port);
|
||||
}
|
||||
|
||||
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
|
||||
union sockaddr_union *sa = (union sockaddr_union*) _sa;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(sa);
|
||||
assert(salen >= sizeof(sa->sa.sa_family));
|
||||
|
||||
switch (sa->sa.sa_family) {
|
||||
|
||||
case AF_INET: {
|
||||
uint32_t a;
|
||||
|
||||
a = ntohl(sa->in.sin_addr.s_addr);
|
||||
|
||||
if (include_port)
|
||||
r = asprintf(&p,
|
||||
"%u.%u.%u.%u:%u",
|
||||
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
|
||||
ntohs(sa->in.sin_port));
|
||||
else
|
||||
r = asprintf(&p,
|
||||
"%u.%u.%u.%u",
|
||||
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
case AF_INET6: {
|
||||
static const unsigned char ipv4_prefix[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
if (translate_ipv6 &&
|
||||
memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
|
||||
const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
|
||||
if (include_port)
|
||||
r = asprintf(&p,
|
||||
"%u.%u.%u.%u:%u",
|
||||
a[0], a[1], a[2], a[3],
|
||||
ntohs(sa->in6.sin6_port));
|
||||
else
|
||||
r = asprintf(&p,
|
||||
"%u.%u.%u.%u",
|
||||
a[0], a[1], a[2], a[3]);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
char a[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
|
||||
|
||||
if (include_port) {
|
||||
r = asprintf(&p,
|
||||
"[%s]:%u",
|
||||
a,
|
||||
ntohs(sa->in6.sin6_port));
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
p = strdup(a);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AF_UNIX:
|
||||
if (salen <= offsetof(struct sockaddr_un, sun_path)) {
|
||||
p = strdup("<unnamed>");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
} else if (sa->un.sun_path[0] == 0) {
|
||||
/* abstract */
|
||||
|
||||
/* FIXME: We assume we can print the
|
||||
* socket path here and that it hasn't
|
||||
* more than one NUL byte. That is
|
||||
* actually an invalid assumption */
|
||||
|
||||
p = new(char, sizeof(sa->un.sun_path)+1);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
p[0] = '@';
|
||||
memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
|
||||
p[sizeof(sa->un.sun_path)] = 0;
|
||||
|
||||
} else {
|
||||
p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
*ret = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getpeername_pretty(int fd, bool include_port, char **ret) {
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
if (getpeername(fd, &sa.sa, &salen) < 0)
|
||||
return -errno;
|
||||
|
||||
if (sa.sa.sa_family == AF_UNIX) {
|
||||
struct ucred ucred = {};
|
||||
|
||||
/* UNIX connection sockets are anonymous, so let's use
|
||||
* PID/UID as pretty credentials instead */
|
||||
|
||||
r = getpeercred(fd, &ucred);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For remote sockets we translate IPv6 addresses back to IPv4
|
||||
* if applicable, since that's nicer. */
|
||||
|
||||
return sockaddr_pretty(&sa.sa, salen, true, include_port, ret);
|
||||
}
|
||||
|
||||
int getsockname_pretty(int fd, char **ret) {
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
if (getsockname(fd, &sa.sa, &salen) < 0)
|
||||
return -errno;
|
||||
|
||||
/* For local sockets we do not translate IPv6 addresses back
|
||||
* to IPv6 if applicable, since this is usually used for
|
||||
* listening sockets where the difference between IPv4 and
|
||||
* IPv6 matters. */
|
||||
|
||||
return sockaddr_pretty(&sa.sa, salen, false, true, ret);
|
||||
}
|
||||
|
||||
int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
|
||||
int r;
|
||||
char host[NI_MAXHOST], *ret;
|
||||
|
||||
assert(_ret);
|
||||
|
||||
r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
|
||||
NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
|
||||
if (r != 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
|
||||
} else {
|
||||
ret = strdup(host);
|
||||
if (!ret)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*_ret = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getnameinfo_pretty(int fd, char **ret) {
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
if (getsockname(fd, &sa.sa, &salen) < 0)
|
||||
return -errno;
|
||||
|
||||
return socknameinfo_pretty(&sa, salen, ret);
|
||||
}
|
||||
|
||||
int socket_address_unlink(SocketAddress *a) {
|
||||
assert(a);
|
||||
|
||||
if (socket_address_family(a) != AF_UNIX)
|
||||
return 0;
|
||||
|
||||
if (a->sockaddr.un.sun_path[0] == 0)
|
||||
return 0;
|
||||
|
||||
if (unlink(a->sockaddr.un.sun_path) < 0)
|
||||
return -errno;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char* const netlink_family_table[] = {
|
||||
[NETLINK_ROUTE] = "route",
|
||||
[NETLINK_FIREWALL] = "firewall",
|
||||
[NETLINK_INET_DIAG] = "inet-diag",
|
||||
[NETLINK_NFLOG] = "nflog",
|
||||
[NETLINK_XFRM] = "xfrm",
|
||||
[NETLINK_SELINUX] = "selinux",
|
||||
[NETLINK_ISCSI] = "iscsi",
|
||||
[NETLINK_AUDIT] = "audit",
|
||||
[NETLINK_FIB_LOOKUP] = "fib-lookup",
|
||||
[NETLINK_CONNECTOR] = "connector",
|
||||
[NETLINK_NETFILTER] = "netfilter",
|
||||
[NETLINK_IP6_FW] = "ip6-fw",
|
||||
[NETLINK_DNRTMSG] = "dnrtmsg",
|
||||
[NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
|
||||
[NETLINK_GENERIC] = "generic",
|
||||
[NETLINK_SCSITRANSPORT] = "scsitransport",
|
||||
[NETLINK_ECRYPTFS] = "ecryptfs"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
|
||||
|
||||
static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
|
||||
[SOCKET_ADDRESS_DEFAULT] = "default",
|
||||
[SOCKET_ADDRESS_BOTH] = "both",
|
||||
[SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
|
||||
|
||||
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
if (a->sa.sa_family != b->sa.sa_family)
|
||||
return false;
|
||||
|
||||
if (a->sa.sa_family == AF_INET)
|
||||
return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
|
||||
|
||||
if (a->sa.sa_family == AF_INET6)
|
||||
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd_inc_sndbuf(int fd, size_t n) {
|
||||
int r, value;
|
||||
socklen_t l = sizeof(value);
|
||||
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
|
||||
if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
|
||||
return 0;
|
||||
|
||||
/* If we have the privileges we will ignore the kernel limit. */
|
||||
|
||||
value = (int) n;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd_inc_rcvbuf(int fd, size_t n) {
|
||||
int r, value;
|
||||
socklen_t l = sizeof(value);
|
||||
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
|
||||
if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
|
||||
return 0;
|
||||
|
||||
/* If we have the privileges we will ignore the kernel limit. */
|
||||
|
||||
value = (int) n;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
|
||||
return -errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char* const ip_tos_table[] = {
|
||||
[IPTOS_LOWDELAY] = "low-delay",
|
||||
[IPTOS_THROUGHPUT] = "throughput",
|
||||
[IPTOS_RELIABILITY] = "reliability",
|
||||
[IPTOS_LOWCOST] = "low-cost",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
|
||||
|
||||
int getpeercred(int fd, struct ucred *ucred) {
|
||||
socklen_t n = sizeof(struct ucred);
|
||||
struct ucred u;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ucred);
|
||||
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (n != sizeof(struct ucred))
|
||||
return -EIO;
|
||||
|
||||
/* Check if the data is actually useful and not suppressed due
|
||||
* to namespacing issues */
|
||||
if (u.pid <= 0)
|
||||
return -ENODATA;
|
||||
if (u.uid == UID_INVALID)
|
||||
return -ENODATA;
|
||||
if (u.gid == GID_INVALID)
|
||||
return -ENODATA;
|
||||
|
||||
*ucred = u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getpeersec(int fd, char **ret) {
|
||||
socklen_t n = 64;
|
||||
char *s;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
s = new0(char, n);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
|
||||
if (r < 0) {
|
||||
free(s);
|
||||
|
||||
if (errno != ERANGE)
|
||||
return -errno;
|
||||
|
||||
s = new0(char, n);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
|
||||
if (r < 0) {
|
||||
free(s);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
if (isempty(s)) {
|
||||
free(s);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_one_fd_sa(
|
||||
int transport_fd,
|
||||
int fd,
|
||||
const struct sockaddr *sa, socklen_t len,
|
||||
int flags) {
|
||||
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(int))];
|
||||
} control = {};
|
||||
struct msghdr mh = {
|
||||
.msg_name = (struct sockaddr*) sa,
|
||||
.msg_namelen = len,
|
||||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
assert(transport_fd >= 0);
|
||||
assert(fd >= 0);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&mh);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
|
||||
|
||||
mh.msg_controllen = CMSG_SPACE(sizeof(int));
|
||||
if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int receive_one_fd(int transport_fd, int flags) {
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(int))];
|
||||
} control = {};
|
||||
struct msghdr mh = {
|
||||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
struct cmsghdr *cmsg, *found = NULL;
|
||||
|
||||
assert(transport_fd >= 0);
|
||||
|
||||
/*
|
||||
* Receive a single FD via @transport_fd. We don't care for
|
||||
* the transport-type. We retrieve a single FD at most, so for
|
||||
* packet-based transports, the caller must ensure to send
|
||||
* only a single FD per packet. This is best used in
|
||||
* combination with send_one_fd().
|
||||
*/
|
||||
|
||||
if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
|
||||
return -errno;
|
||||
|
||||
CMSG_FOREACH(cmsg, &mh) {
|
||||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||
cmsg->cmsg_type == SCM_RIGHTS &&
|
||||
cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
|
||||
assert(!found);
|
||||
found = cmsg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
cmsg_close_all(&mh);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return *(int*) CMSG_DATA(found);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
ssize_t next_datagram_size_fd(int fd) {
|
||||
ssize_t l;
|
||||
int k;
|
||||
|
||||
/* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
|
||||
* actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't
|
||||
* do. This difference is actually of major importance as we need to be sure that the size returned here
|
||||
* actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
|
||||
* the wrong size. */
|
||||
|
||||
l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
|
||||
if (l < 0) {
|
||||
if (errno == EOPNOTSUPP)
|
||||
goto fallback;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
if (l == 0)
|
||||
goto fallback;
|
||||
|
||||
return l;
|
||||
|
||||
fallback:
|
||||
k = 0;
|
||||
|
||||
/* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD
|
||||
* for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */
|
||||
|
||||
if (ioctl(fd, FIONREAD, &k) < 0)
|
||||
return -errno;
|
||||
|
||||
return (ssize_t) k;
|
||||
}
|
||||
|
|
@ -133,5 +133,7 @@ int send_one_fd_sa(int transport_fd,
|
|||
#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags)
|
||||
int receive_one_fd(int transport_fd, int flags);
|
||||
|
||||
ssize_t next_datagram_size_fd(int fd);
|
||||
|
||||
#define CMSG_FOREACH(cmsg, mh) \
|
||||
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
|
||||
|
|
|
|||
|
|
@ -73,4 +73,4 @@ do { \
|
|||
assert_not_reached("Unknown format string argument."); \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
} while (false)
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
|
|||
}
|
||||
|
||||
if (k > x) /* last character was wide and went over quota */
|
||||
x ++;
|
||||
x++;
|
||||
|
||||
for (j = s + old_length; k < new_length && j > i; ) {
|
||||
char32_t c;
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ char *strv_join(char **l, const char *separator) {
|
|||
|
||||
n = 0;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (n != 0)
|
||||
if (s != l)
|
||||
n += k;
|
||||
n += strlen(*s);
|
||||
}
|
||||
|
|
@ -388,7 +388,7 @@ char *strv_join(char **l, const char *separator) {
|
|||
|
||||
e = r;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (e != r)
|
||||
if (s != l)
|
||||
e = stpcpy(e, separator);
|
||||
|
||||
e = stpcpy(e, *s);
|
||||
|
|
|
|||
|
|
@ -44,10 +44,30 @@
|
|||
|
||||
static nsec_t timespec_load_nsec(const struct timespec *ts);
|
||||
|
||||
static clockid_t map_clock_id(clockid_t c) {
|
||||
|
||||
/* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
|
||||
* fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
|
||||
* when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
|
||||
* those archs. */
|
||||
|
||||
switch (c) {
|
||||
|
||||
case CLOCK_BOOTTIME_ALARM:
|
||||
return CLOCK_BOOTTIME;
|
||||
|
||||
case CLOCK_REALTIME_ALARM:
|
||||
return CLOCK_REALTIME;
|
||||
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
usec_t now(clockid_t clock_id) {
|
||||
struct timespec ts;
|
||||
|
||||
assert_se(clock_gettime(clock_id, &ts) == 0);
|
||||
assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
|
||||
|
||||
return timespec_load(&ts);
|
||||
}
|
||||
|
|
@ -55,7 +75,7 @@ usec_t now(clockid_t clock_id) {
|
|||
nsec_t now_nsec(clockid_t clock_id) {
|
||||
struct timespec ts;
|
||||
|
||||
assert_se(clock_gettime(clock_id, &ts) == 0);
|
||||
assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
|
||||
|
||||
return timespec_load_nsec(&ts);
|
||||
}
|
||||
|
|
@ -121,8 +141,7 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
|
|||
usec_t timespec_load(const struct timespec *ts) {
|
||||
assert(ts);
|
||||
|
||||
if (ts->tv_sec == (time_t) -1 &&
|
||||
ts->tv_nsec == (long) -1)
|
||||
if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
|
||||
return USEC_INFINITY;
|
||||
|
||||
if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
|
||||
|
|
@ -136,13 +155,13 @@ usec_t timespec_load(const struct timespec *ts) {
|
|||
static nsec_t timespec_load_nsec(const struct timespec *ts) {
|
||||
assert(ts);
|
||||
|
||||
if (ts->tv_sec == (time_t) -1 &&
|
||||
ts->tv_nsec == (long) -1)
|
||||
if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
|
||||
return NSEC_INFINITY;
|
||||
|
||||
return
|
||||
(nsec_t) ts->tv_sec * NSEC_PER_SEC +
|
||||
(nsec_t) ts->tv_nsec;
|
||||
if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
|
||||
return NSEC_INFINITY;
|
||||
|
||||
return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
|
||||
}
|
||||
|
||||
struct timespec *timespec_store(struct timespec *ts, usec_t u) {
|
||||
|
|
@ -434,7 +453,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
|
|||
assert(t);
|
||||
|
||||
if (sscanf(value, "%llu %llu", &a, &b) != 2) {
|
||||
log_debug("Failed to parse finish timestamp value %s.", value);
|
||||
log_debug("Failed to parse dual timestamp value \"%s\": %m", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -444,6 +463,18 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int timestamp_deserialize(const char *value, usec_t *timestamp) {
|
||||
int r;
|
||||
|
||||
assert(value);
|
||||
|
||||
r = safe_atou64(value, timestamp);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int parse_timestamp(const char *t, usec_t *usec) {
|
||||
static const struct {
|
||||
const char *name;
|
||||
|
|
@ -550,12 +581,12 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
|||
goto from_tm;
|
||||
|
||||
} else if (streq(t, "yesterday")) {
|
||||
tm.tm_mday --;
|
||||
tm.tm_mday--;
|
||||
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
|
||||
goto from_tm;
|
||||
|
||||
} else if (streq(t, "tomorrow")) {
|
||||
tm.tm_mday ++;
|
||||
tm.tm_mday++;
|
||||
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
|
||||
goto from_tm;
|
||||
}
|
||||
|
|
@ -678,8 +709,7 @@ finish:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
||||
|
||||
static char* extract_multiplier(char *p, usec_t *multiplier) {
|
||||
static const struct {
|
||||
const char *suffix;
|
||||
usec_t usec;
|
||||
|
|
@ -713,7 +743,22 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
{ "usec", 1ULL },
|
||||
{ "us", 1ULL },
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++) {
|
||||
char *e;
|
||||
|
||||
e = startswith(p, table[i].suffix);
|
||||
if (e) {
|
||||
*multiplier = table[i].usec;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
||||
const char *p, *s;
|
||||
usec_t r = 0;
|
||||
bool something = false;
|
||||
|
|
@ -738,8 +783,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
for (;;) {
|
||||
long long l, z = 0;
|
||||
char *e;
|
||||
unsigned i, n = 0;
|
||||
usec_t multiplier, k;
|
||||
unsigned n = 0;
|
||||
usec_t multiplier = default_unit, k;
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
|
||||
|
|
@ -752,10 +797,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
|
||||
errno = 0;
|
||||
l = strtoll(p, &e, 10);
|
||||
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
|
||||
if (l < 0)
|
||||
return -ERANGE;
|
||||
|
||||
|
|
@ -779,18 +822,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
return -EINVAL;
|
||||
|
||||
e += strspn(e, WHITESPACE);
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++)
|
||||
if (startswith(e, table[i].suffix)) {
|
||||
multiplier = table[i].usec;
|
||||
p = e + strlen(table[i].suffix);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ELEMENTSOF(table)) {
|
||||
multiplier = default_unit;
|
||||
p = e;
|
||||
}
|
||||
p = extract_multiplier(e, &multiplier);
|
||||
|
||||
something = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
|
|||
|
||||
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
|
||||
int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
|
||||
int timestamp_deserialize(const char *value, usec_t *timestamp);
|
||||
|
||||
int parse_timestamp(const char *t, usec_t *usec);
|
||||
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ char *utf8_escape_non_printable(const char *str) {
|
|||
*(s++) = hexchar((int) *str);
|
||||
|
||||
str += 1;
|
||||
len --;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,16 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_
|
|||
qsort(base, nmemb, size, compar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal memcpy requires src to be nonnull. We do nothing if n is 0.
|
||||
*/
|
||||
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
|
||||
if (n == 0)
|
||||
return;
|
||||
assert(src);
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
int on_ac_power(void);
|
||||
|
||||
#define memzero(x,l) (memset((x), 0, (l)))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
|
|||
|
||||
if (code != SD_DHCP_OPTION_END)
|
||||
/* always make sure there is space for an END option */
|
||||
size --;
|
||||
size--;
|
||||
|
||||
switch (code) {
|
||||
|
||||
|
|
@ -56,12 +56,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
|
|||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen;
|
||||
|
||||
if (optlen) {
|
||||
assert(optval);
|
||||
|
||||
memcpy(&options[*offset + 2], optval, optlen);
|
||||
}
|
||||
|
||||
memcpy_safe(&options[*offset + 2], optval, optlen);
|
||||
*offset += optlen + 2;
|
||||
|
||||
break;
|
||||
|
|
@ -142,7 +137,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;
|
||||
|
|
@ -228,7 +223,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;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
|
|||
/* wrap around in one's complement */
|
||||
sum++;
|
||||
|
||||
buf_64 ++;
|
||||
buf_64++;
|
||||
}
|
||||
|
||||
if (len % sizeof(uint64_t)) {
|
||||
|
|
|
|||
|
|
@ -73,8 +73,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (optval)
|
||||
memcpy(*buf, optval, optlen);
|
||||
memcpy_safe(*buf, optval, optlen);
|
||||
|
||||
*buf += optlen;
|
||||
*buflen -= optlen;
|
||||
|
|
|
|||
|
|
@ -1,362 +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 "nm-sd-adapt.h"
|
||||
|
||||
#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__)
|
||||
|
|
|
|||
794
src/systemd/src/libsystemd-network/lldp-neighbor.c
Normal file
794
src/systemd/src/libsystemd-network/lldp-neighbor.c
Normal file
|
|
@ -0,0 +1,794 @@
|
|||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#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/systemd/src/libsystemd-network/lldp-neighbor.h
Normal file
106
src/systemd/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);
|
||||
|
|
@ -21,65 +21,58 @@
|
|||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <linux/filter.h>
|
||||
#include <linux/if_ether.h>
|
||||
#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,118 +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 "nm-sd-adapt.h"
|
||||
|
||||
#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,640 +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 "nm-sd-adapt.h"
|
||||
|
||||
#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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
|
|||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size ++;
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = addresses;
|
||||
|
|
@ -488,7 +488,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
|
|||
return -ENOMEM;
|
||||
|
||||
entry = strndup(word, len);
|
||||
if(!entry)
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
tok = entry;
|
||||
|
|
|
|||
|
|
@ -103,7 +103,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;
|
||||
|
|
@ -123,7 +123,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);
|
||||
|
||||
|
|
@ -960,7 +960,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
|
|||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||
|
||||
if (client->start_delay) {
|
||||
sd_event_now(client->event, clock_boottime_or_monotonic(), &usec);
|
||||
assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
|
||||
usec += client->start_delay;
|
||||
}
|
||||
|
||||
|
|
@ -1527,20 +1527,17 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
|
|||
uint32_t revents, void *userdata) {
|
||||
sd_dhcp_client *client = userdata;
|
||||
_cleanup_free_ DHCPMessage *message = NULL;
|
||||
int buflen = 0, len, r;
|
||||
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
|
||||
const struct ether_addr *expected_chaddr = NULL;
|
||||
uint8_t expected_hlen = 0;
|
||||
ssize_t len, buflen;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
|
||||
r = ioctl(fd, FIONREAD, &buflen);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
else if (buflen < 0)
|
||||
/* this can't be right */
|
||||
return -EIO;
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (buflen < 0)
|
||||
return buflen;
|
||||
|
||||
message = malloc0(buflen);
|
||||
if (!message)
|
||||
|
|
@ -1618,17 +1615,15 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
|
|||
};
|
||||
struct cmsghdr *cmsg;
|
||||
bool checksum = true;
|
||||
int buflen = 0, len, r;
|
||||
ssize_t buflen, len;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
|
||||
r = ioctl(fd, FIONREAD, &buflen);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
else if (buflen < 0)
|
||||
/* this can't be right */
|
||||
return -EIO;
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (buflen < 0)
|
||||
return buflen;
|
||||
|
||||
packet = malloc0(buflen);
|
||||
if (!packet)
|
||||
|
|
@ -1698,8 +1693,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);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "in-addr-util.h"
|
||||
#include "network-internal.h"
|
||||
#include "random-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
@ -65,7 +66,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;
|
||||
|
|
@ -112,7 +113,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;
|
||||
|
|
@ -893,18 +894,16 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
|||
sd_dhcp6_client *client = userdata;
|
||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||
_cleanup_free_ DHCP6Message *message = NULL;
|
||||
int r, buflen, len;
|
||||
ssize_t buflen, len;
|
||||
int r = 0;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
assert(client->event);
|
||||
|
||||
r = ioctl(fd, FIONREAD, &buflen);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
else if (buflen < 0)
|
||||
/* This really should not happen */
|
||||
return -EIO;
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (buflen < 0)
|
||||
return buflen;
|
||||
|
||||
message = malloc(buflen);
|
||||
if (!message)
|
||||
|
|
@ -1207,7 +1206,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);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,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;
|
||||
};
|
||||
|
||||
|
|
@ -430,7 +430,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);
|
||||
|
|
@ -449,7 +449,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;
|
||||
|
|
@ -458,7 +458,7 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ struct sd_ipv4ll {
|
|||
|
||||
/* External */
|
||||
be32_t claimed_address;
|
||||
sd_ipv4ll_cb_t cb;
|
||||
sd_ipv4ll_callback_t cb;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
|
|
@ -162,7 +162,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);
|
||||
|
|
@ -174,7 +174,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;
|
||||
|
|
@ -183,7 +183,7 @@ int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
|
||||
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
2905
src/systemd/src/libsystemd/sd-event/sd-event.c
Normal file
2905
src/systemd/src/libsystemd/sd-event/sd-event.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -155,7 +155,6 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
|
||||
static thread_local sd_id128_t saved_boot_id;
|
||||
static thread_local bool saved_boot_id_valid = false;
|
||||
|
|
@ -211,6 +210,7 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ int sd_id128_randomize(sd_id128_t *ret) {
|
||||
sd_id128_t t;
|
||||
int r;
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
|
|||
unsigned slashes = 0;
|
||||
|
||||
for (y = terminal - 1; y >= name && *y == '\\'; y--)
|
||||
slashes ++;
|
||||
slashes++;
|
||||
|
||||
if (slashes % 2 == 0) {
|
||||
/* The '.' was not escaped */
|
||||
|
|
@ -194,7 +194,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
|
|||
}
|
||||
}
|
||||
|
||||
terminal --;
|
||||
terminal--;
|
||||
}
|
||||
|
||||
r = dns_label_unescape(&name, dest, sz);
|
||||
|
|
@ -333,7 +333,7 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
|
|||
|
||||
l = strlen(buffer);
|
||||
|
||||
/* Verify that the the result is not longer than one DNS label. */
|
||||
/* Verify that the result is not longer than one DNS label. */
|
||||
if (l <= 0 || l > DNS_LABEL_MAX)
|
||||
return -EINVAL;
|
||||
if (l > decoded_max)
|
||||
|
|
@ -1177,7 +1177,7 @@ int dns_name_skip(const char *a, unsigned n_labels, const char **ret) {
|
|||
assert(a);
|
||||
assert(ret);
|
||||
|
||||
for (; n_labels > 0; n_labels --) {
|
||||
for (; n_labels > 0; n_labels--) {
|
||||
r = dns_name_parent(&a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ test_wired_defname_LDADD = \
|
|||
test_systemd_CFLAGS = \
|
||||
"-I$(srcdir)/../" \
|
||||
"-I$(srcdir)/../platform" \
|
||||
"-I$(srcdir)/../systemd" \
|
||||
"-I$(srcdir)/../systemd/src/systemd"
|
||||
|
||||
test_systemd_SOURCES = \
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "sd-lldp.h"
|
||||
#include "sd-event.h"
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "nm-test-utils.h"
|
||||
|
||||
|
|
@ -48,7 +50,7 @@ test_lldp_create (void)
|
|||
int ifindex = 1;
|
||||
int r;
|
||||
|
||||
r = sd_lldp_new (ifindex, "lo", (struct ether_addr *) ((guint8[]) { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }), &lldp);
|
||||
r = sd_lldp_new (&lldp, ifindex);
|
||||
g_assert (r == 0);
|
||||
g_assert (lldp);
|
||||
|
||||
|
|
@ -57,6 +59,71 @@ test_lldp_create (void)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
GMainLoop *mainloop;
|
||||
sd_event_source *event_source;
|
||||
} TestSdEventData;
|
||||
|
||||
static int
|
||||
_test_sd_event_timeout_cb (sd_event_source *s, uint64_t usec, void *userdata)
|
||||
{
|
||||
TestSdEventData *user_data = userdata;
|
||||
|
||||
g_assert (user_data);
|
||||
g_assert (user_data->mainloop);
|
||||
g_assert (user_data->event_source);
|
||||
|
||||
user_data->event_source = sd_event_source_unref (user_data->event_source);
|
||||
g_main_loop_quit (user_data->mainloop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_sd_event (void)
|
||||
{
|
||||
int repeat;
|
||||
|
||||
for (repeat = 0; repeat < 2; repeat++) {
|
||||
guint sd_id = 0;
|
||||
int r;
|
||||
int i, n;
|
||||
sd_event *other_events[3] = { NULL }, *event = NULL;
|
||||
TestSdEventData user_data = { 0 };
|
||||
|
||||
g_assert_cmpint (sd_event_default (NULL), ==, 0);
|
||||
|
||||
for (i = 0, n = (nmtst_get_rand_int () % (G_N_ELEMENTS (other_events) + 1)); i < n; i++) {
|
||||
r = sd_event_default (&other_events[i]);
|
||||
g_assert (r >= 0 && other_events[i]);
|
||||
}
|
||||
|
||||
sd_id = nm_sd_event_attach_default ();
|
||||
|
||||
r = sd_event_default (&event);
|
||||
g_assert (r >= 0 && event);
|
||||
|
||||
r = sd_event_add_time (event, &user_data.event_source, CLOCK_MONOTONIC, 1, 0, _test_sd_event_timeout_cb, &user_data);
|
||||
g_assert (r >= 0 && user_data.event_source);
|
||||
|
||||
user_data.mainloop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (user_data.mainloop);
|
||||
g_main_loop_unref (user_data.mainloop);
|
||||
|
||||
g_assert (!user_data.event_source);
|
||||
|
||||
event = sd_event_unref (event);
|
||||
for (i = 0, n = (nmtst_get_rand_int () % (G_N_ELEMENTS (other_events) + 1)); i < n; i++)
|
||||
other_events[i] = sd_event_unref (other_events[i]);
|
||||
nm_clear_g_source (&sd_id);
|
||||
for (i = 0, n = G_N_ELEMENTS (other_events); i < n; i++)
|
||||
other_events[i] = sd_event_unref (other_events[i]);
|
||||
|
||||
g_assert_cmpint (sd_event_default (NULL), ==, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int
|
||||
|
|
@ -66,6 +133,7 @@ main (int argc, char **argv)
|
|||
|
||||
g_test_add_func ("/systemd/dhcp/create", test_dhcp_create);
|
||||
g_test_add_func ("/systemd/lldp/create", test_lldp_create);
|
||||
g_test_add_func ("/systemd/sd-event", test_sd_event);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue