mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-04 10:40:58 +01:00
merge: merge branch 'systemd' into master
This commit is contained in:
commit
90fb64024c
54 changed files with 7102 additions and 1083 deletions
|
|
@ -53,6 +53,7 @@ dnl
|
|||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
dnl
|
||||
AC_TYPE_PID_T
|
||||
AC_CHECK_SIZEOF(dev_t)
|
||||
|
||||
dnl
|
||||
dnl translation support
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ noinst_LTLIBRARIES = \
|
|||
SYSTEMD_NM_CFLAGS_PATHS = \
|
||||
-I$(top_srcdir)/src/systemd/src/systemd \
|
||||
-I$(top_srcdir)/src/systemd/src/libsystemd-network \
|
||||
-I$(top_srcdir)/src/systemd/src/libsystemd/sd-event \
|
||||
-I$(top_srcdir)/src/systemd/src/basic \
|
||||
-I$(top_srcdir)/src/systemd
|
||||
|
||||
|
|
@ -68,6 +69,8 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/basic/async.h \
|
||||
systemd/src/basic/fileio.c \
|
||||
systemd/src/basic/fileio.h \
|
||||
systemd/src/basic/hashmap.c \
|
||||
systemd/src/basic/hashmap.h \
|
||||
systemd/src/basic/hostname-util.c \
|
||||
systemd/src/basic/hostname-util.h \
|
||||
systemd/src/basic/in-addr-util.c \
|
||||
|
|
@ -75,13 +78,18 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/basic/list.h \
|
||||
systemd/src/basic/log.h \
|
||||
systemd/src/basic/macro.h \
|
||||
systemd/src/basic/mempool.c \
|
||||
systemd/src/basic/mempool.h \
|
||||
systemd/src/basic/path-util.c \
|
||||
systemd/src/basic/path-util.h \
|
||||
systemd/src/basic/prioq.c \
|
||||
systemd/src/basic/prioq.h \
|
||||
systemd/src/basic/random-util.c \
|
||||
systemd/src/basic/random-util.h \
|
||||
systemd/src/basic/refcnt.h \
|
||||
systemd/src/basic/siphash24.c \
|
||||
systemd/src/basic/siphash24.h \
|
||||
systemd/src/basic/set.h \
|
||||
systemd/src/basic/socket-util.h \
|
||||
systemd/src/basic/sparse-endian.h \
|
||||
systemd/src/basic/strv.c \
|
||||
|
|
@ -93,6 +101,8 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/basic/utf8.h \
|
||||
systemd/src/basic/util.c \
|
||||
systemd/src/basic/util.h \
|
||||
systemd/src/libsystemd-network/arp-util.c \
|
||||
systemd/src/libsystemd-network/arp-util.h \
|
||||
systemd/src/libsystemd-network/dhcp-identifier.c \
|
||||
systemd/src/libsystemd-network/dhcp-identifier.h \
|
||||
systemd/src/libsystemd-network/dhcp-internal.h \
|
||||
|
|
@ -106,17 +116,27 @@ 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/ipv4ll-internal.h \
|
||||
systemd/src/libsystemd-network/ipv4ll-network.c \
|
||||
systemd/src/libsystemd-network/ipv4ll-packet.c \
|
||||
systemd/src/libsystemd-network/lldp.h \
|
||||
systemd/src/libsystemd-network/lldp-network.h \
|
||||
systemd/src/libsystemd-network/lldp-network.c \
|
||||
systemd/src/libsystemd-network/lldp-tlv.c \
|
||||
systemd/src/libsystemd-network/lldp-tlv.h \
|
||||
systemd/src/libsystemd-network/lldp-port.c \
|
||||
systemd/src/libsystemd-network/lldp-port.h \
|
||||
systemd/src/libsystemd-network/lldp-util.h \
|
||||
systemd/src/libsystemd-network/lldp-internal.h \
|
||||
systemd/src/libsystemd-network/lldp-internal.c \
|
||||
systemd/src/libsystemd-network/network-internal.c \
|
||||
systemd/src/libsystemd-network/network-internal.h \
|
||||
systemd/src/libsystemd-network/sd-dhcp-client.c \
|
||||
systemd/src/libsystemd-network/sd-dhcp-lease.c \
|
||||
systemd/src/libsystemd-network/sd-dhcp6-client.c \
|
||||
systemd/src/libsystemd-network/sd-dhcp6-lease.c \
|
||||
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-id128/sd-id128.c \
|
||||
systemd/src/libsystemd/sd-event/event-util.h \
|
||||
systemd/src/shared/dns-domain.c \
|
||||
systemd/src/shared/dns-domain.h \
|
||||
systemd/src/systemd/_sd-common.h \
|
||||
|
|
@ -124,9 +144,11 @@ libsystemd_nm_la_SOURCES = \
|
|||
systemd/src/systemd/sd-dhcp-lease.h \
|
||||
systemd/src/systemd/sd-dhcp6-client.h \
|
||||
systemd/src/systemd/sd-dhcp6-lease.h \
|
||||
systemd/src/systemd/sd-lldp.h \
|
||||
systemd/src/systemd/sd-event.h \
|
||||
systemd/src/systemd/sd-icmp6-nd.h \
|
||||
systemd/src/systemd/sd-id128.h \
|
||||
systemd/src/systemd/sd-ipv4acd.h \
|
||||
systemd/src/systemd/sd-ipv4ll.h
|
||||
|
||||
libsystemd_nm_la_CPPFLAGS = \
|
||||
|
|
|
|||
|
|
@ -3245,7 +3245,7 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data)
|
|||
return;
|
||||
|
||||
switch (event) {
|
||||
case IPV4LL_EVENT_BIND:
|
||||
case SD_IPV4LL_EVENT_BIND:
|
||||
r = sd_ipv4ll_get_address (ll, &address);
|
||||
if (r < 0) {
|
||||
_LOGE (LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r);
|
||||
|
|
|
|||
|
|
@ -491,15 +491,15 @@ dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data)
|
|||
nm_log_dbg (LOGD_DHCP4, "(%s): DHCPv4 client event %d", iface, event);
|
||||
|
||||
switch (event) {
|
||||
case DHCP_EVENT_EXPIRED:
|
||||
case SD_DHCP_CLIENT_EVENT_EXPIRED:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_EXPIRE, NULL, NULL);
|
||||
break;
|
||||
case DHCP_EVENT_STOP:
|
||||
case SD_DHCP_CLIENT_EVENT_STOP:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
break;
|
||||
case DHCP_EVENT_RENEW:
|
||||
case DHCP_EVENT_IP_CHANGE:
|
||||
case DHCP_EVENT_IP_ACQUIRE:
|
||||
case SD_DHCP_CLIENT_EVENT_RENEW:
|
||||
case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
|
||||
case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
|
||||
bound4_handle (self);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -671,14 +671,14 @@ dhcp6_event_cb (sd_dhcp6_client *client, int event, gpointer user_data)
|
|||
nm_log_dbg (LOGD_DHCP6, "(%s): DHCPv6 client event %d", iface, event);
|
||||
|
||||
switch (event) {
|
||||
case DHCP6_EVENT_RETRANS_MAX:
|
||||
case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL);
|
||||
break;
|
||||
case DHCP6_EVENT_RESEND_EXPIRE:
|
||||
case DHCP6_EVENT_STOP:
|
||||
case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
|
||||
case SD_DHCP6_CLIENT_EVENT_STOP:
|
||||
nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL);
|
||||
break;
|
||||
case DHCP6_EVENT_IP_ACQUIRE:
|
||||
case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
|
||||
bound6_handle (self);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ G_STMT_START { \
|
|||
g_assert_not_reached (); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_assert_failed_unreachable(text, file, line, func) \
|
||||
G_STMT_START { \
|
||||
log_internal (LOG_CRIT, 0, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", text, file, line, func); \
|
||||
g_assert_not_reached (); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_assert_failed_return(text, file, line, func) \
|
||||
({ \
|
||||
log_internal (LOG_DEBUG, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", text, file, line, func); \
|
||||
|
|
@ -76,7 +82,6 @@ G_STMT_START { \
|
|||
(void) 0; \
|
||||
})
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* The remainder of the header is only enabled when building the systemd code
|
||||
* itself.
|
||||
|
|
@ -132,6 +137,10 @@ static inline pid_t gettid(void) {
|
|||
return (pid_t) syscall(SYS_gettid);
|
||||
}
|
||||
|
||||
static inline bool is_main_thread(void) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* (NETWORKMANAGER_COMPILATION) == NM_NETWORKMANAGER_COMPILATION_SYSTEMD */
|
||||
|
||||
#endif /* NM_SD_ADAPT_H */
|
||||
|
|
|
|||
|
|
@ -777,15 +777,19 @@ int executable_is_script(const char *path, char **interpreter) {
|
|||
|
||||
/**
|
||||
* Retrieve one field from a file like /proc/self/status. pattern
|
||||
* should start with '\n' and end with a ':'. Whitespace and zeros
|
||||
* after the ':' will be skipped. field must be freed afterwards.
|
||||
* should not include whitespace or the delimiter (':'). pattern matches only
|
||||
* the beginning of a line. Whitespace before ':' is skipped. Whitespace and
|
||||
* zeros after the ':' will be skipped. field must be freed afterwards.
|
||||
* terminator specifies the terminating characters of the field value (not
|
||||
* included in the value).
|
||||
*/
|
||||
int get_status_field(const char *filename, const char *pattern, char **field) {
|
||||
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
|
||||
_cleanup_free_ char *status = NULL;
|
||||
char *t, *f;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
assert(terminator);
|
||||
assert(filename);
|
||||
assert(pattern);
|
||||
assert(field);
|
||||
|
|
@ -794,11 +798,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = strstr(status, pattern);
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
t = status;
|
||||
|
||||
do {
|
||||
bool pattern_ok;
|
||||
|
||||
do {
|
||||
t = strstr(t, pattern);
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
|
||||
/* Check that pattern occurs in beginning of line. */
|
||||
pattern_ok = (t == status || t[-1] == '\n');
|
||||
|
||||
t += strlen(pattern);
|
||||
|
||||
} while (!pattern_ok);
|
||||
|
||||
t += strspn(t, " \t");
|
||||
if (!*t)
|
||||
return -ENOENT;
|
||||
|
||||
} while (*t != ':');
|
||||
|
||||
t++;
|
||||
|
||||
t += strlen(pattern);
|
||||
if (*t) {
|
||||
t += strspn(t, " \t");
|
||||
|
||||
|
|
@ -814,7 +838,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
|
|||
t --;
|
||||
}
|
||||
|
||||
len = strcspn(t, WHITESPACE);
|
||||
len = strcspn(t, terminator);
|
||||
|
||||
f = strndup(t, len);
|
||||
if (!f)
|
||||
|
|
|
|||
|
|
@ -51,4 +51,4 @@ int write_env_file(const char *fname, char **l);
|
|||
|
||||
int executable_is_script(const char *path, char **interpreter);
|
||||
|
||||
int get_status_field(const char *filename, const char *pattern, char **field);
|
||||
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
|
||||
|
|
|
|||
1865
src/systemd/src/basic/hashmap.c
Normal file
1865
src/systemd/src/basic/hashmap.c
Normal file
File diff suppressed because it is too large
Load diff
415
src/systemd/src/basic/hashmap.h
Normal file
415
src/systemd/src/basic/hashmap.h
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
Copyright 2014 Michal Schmidt
|
||||
|
||||
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 <stdbool.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "siphash24.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* A hash table implementation. As a minor optimization a NULL hashmap object
|
||||
* will be treated as empty hashmap for all read operations. That way it is not
|
||||
* necessary to instantiate an object for each Hashmap use.
|
||||
*
|
||||
* If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
|
||||
* the implemention will:
|
||||
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
|
||||
* - perform extra checks for invalid use of iterators
|
||||
*/
|
||||
|
||||
#define HASH_KEY_SIZE 16
|
||||
|
||||
/* The base type for all hashmap and set types. Many functions in the
|
||||
* implementation take (HashmapBase*) parameters and are run-time polymorphic,
|
||||
* though the API is not meant to be polymorphic (do not call functions
|
||||
* internal_*() directly). */
|
||||
typedef struct HashmapBase HashmapBase;
|
||||
|
||||
/* Specific hashmap/set types */
|
||||
typedef struct Hashmap Hashmap; /* Maps keys to values */
|
||||
typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */
|
||||
typedef struct Set Set; /* Stores just keys */
|
||||
|
||||
/* Ideally the Iterator would be an opaque struct, but it is instantiated
|
||||
* by hashmap users, so the definition has to be here. Do not use its fields
|
||||
* directly. */
|
||||
typedef struct {
|
||||
unsigned idx; /* index of an entry to be iterated next */
|
||||
const void *next_key; /* expected value of that entry's key pointer */
|
||||
#ifdef ENABLE_DEBUG_HASHMAP
|
||||
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
|
||||
unsigned rem_count; /* hashmap's rem_count in previous iteration */
|
||||
unsigned prev_idx; /* idx in previous iteration */
|
||||
#endif
|
||||
} Iterator;
|
||||
|
||||
#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
|
||||
#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
|
||||
|
||||
typedef void (*hash_func_t)(const void *p, struct siphash *state);
|
||||
typedef int (*compare_func_t)(const void *a, const void *b);
|
||||
|
||||
struct hash_ops {
|
||||
hash_func_t hash;
|
||||
compare_func_t compare;
|
||||
};
|
||||
|
||||
void string_hash_func(const void *p, struct siphash *state);
|
||||
int string_compare_func(const void *a, const void *b) _pure_;
|
||||
extern const struct hash_ops string_hash_ops;
|
||||
|
||||
/* This will compare the passed pointers directly, and will not
|
||||
* dereference them. This is hence not useful for strings or
|
||||
* suchlike. */
|
||||
void trivial_hash_func(const void *p, struct siphash *state);
|
||||
int trivial_compare_func(const void *a, const void *b) _const_;
|
||||
extern const struct hash_ops trivial_hash_ops;
|
||||
|
||||
/* 32bit values we can always just embedd in the pointer itself, but
|
||||
* in order to support 32bit archs we need store 64bit values
|
||||
* indirectly, since they don't fit in a pointer. */
|
||||
void uint64_hash_func(const void *p, struct siphash *state);
|
||||
int uint64_compare_func(const void *a, const void *b) _pure_;
|
||||
extern const struct hash_ops uint64_hash_ops;
|
||||
|
||||
/* On some archs dev_t is 32bit, and on others 64bit. And sometimes
|
||||
* it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */
|
||||
#if SIZEOF_DEV_T != 8
|
||||
void devt_hash_func(const void *p, struct siphash *state) _pure_;
|
||||
int devt_compare_func(const void *a, const void *b) _pure_;
|
||||
extern const struct hash_ops devt_hash_ops = {
|
||||
.hash = devt_hash_func,
|
||||
.compare = devt_compare_func
|
||||
};
|
||||
#else
|
||||
#define devt_hash_func uint64_hash_func
|
||||
#define devt_compare_func uint64_compare_func
|
||||
#define devt_hash_ops uint64_hash_ops
|
||||
#endif
|
||||
|
||||
/* Macros for type checking */
|
||||
#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
|
||||
(__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
|
||||
__builtin_types_compatible_p(typeof(h), Hashmap*) || \
|
||||
__builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \
|
||||
__builtin_types_compatible_p(typeof(h), Set*))
|
||||
|
||||
#define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \
|
||||
(__builtin_types_compatible_p(typeof(h), Hashmap*) || \
|
||||
__builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \
|
||||
|
||||
#define HASHMAP_BASE(h) \
|
||||
__builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \
|
||||
(HashmapBase*)(h), \
|
||||
(void)0)
|
||||
|
||||
#define PLAIN_HASHMAP(h) \
|
||||
__builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \
|
||||
(Hashmap*)(h), \
|
||||
(void)0)
|
||||
|
||||
#ifdef ENABLE_DEBUG_HASHMAP
|
||||
# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
|
||||
# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
|
||||
# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
|
||||
#else
|
||||
# define HASHMAP_DEBUG_PARAMS
|
||||
# define HASHMAP_DEBUG_SRC_ARGS
|
||||
# define HASHMAP_DEBUG_PASS_ARGS
|
||||
#endif
|
||||
|
||||
Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
HashmapBase *internal_hashmap_free(HashmapBase *h);
|
||||
static inline Hashmap *hashmap_free(Hashmap *h) {
|
||||
return (void*)internal_hashmap_free(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
|
||||
return (void*)internal_hashmap_free(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
HashmapBase *internal_hashmap_free_free(HashmapBase *h);
|
||||
static inline Hashmap *hashmap_free_free(Hashmap *h) {
|
||||
return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
|
||||
return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
Hashmap *hashmap_free_free_free(Hashmap *h);
|
||||
static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
|
||||
return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h));
|
||||
}
|
||||
|
||||
HashmapBase *internal_hashmap_copy(HashmapBase *h);
|
||||
static inline Hashmap *hashmap_copy(Hashmap *h) {
|
||||
return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
|
||||
return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
int hashmap_put(Hashmap *h, const void *key, void *value);
|
||||
static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) {
|
||||
return hashmap_put(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
int hashmap_update(Hashmap *h, const void *key, void *value);
|
||||
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
|
||||
return hashmap_update(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
int hashmap_replace(Hashmap *h, const void *key, void *value);
|
||||
static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) {
|
||||
return hashmap_replace(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
void *internal_hashmap_get(HashmapBase *h, const void *key);
|
||||
static inline void *hashmap_get(Hashmap *h, const void *key) {
|
||||
return internal_hashmap_get(HASHMAP_BASE(h), key);
|
||||
}
|
||||
static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
|
||||
return internal_hashmap_get(HASHMAP_BASE(h), key);
|
||||
}
|
||||
|
||||
void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
|
||||
static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) {
|
||||
return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
|
||||
}
|
||||
|
||||
bool internal_hashmap_contains(HashmapBase *h, const void *key);
|
||||
static inline bool hashmap_contains(Hashmap *h, const void *key) {
|
||||
return internal_hashmap_contains(HASHMAP_BASE(h), key);
|
||||
}
|
||||
static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
|
||||
return internal_hashmap_contains(HASHMAP_BASE(h), key);
|
||||
}
|
||||
|
||||
void *internal_hashmap_remove(HashmapBase *h, const void *key);
|
||||
static inline void *hashmap_remove(Hashmap *h, const void *key) {
|
||||
return internal_hashmap_remove(HASHMAP_BASE(h), key);
|
||||
}
|
||||
static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
|
||||
return internal_hashmap_remove(HASHMAP_BASE(h), key);
|
||||
}
|
||||
|
||||
void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
|
||||
static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) {
|
||||
return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
|
||||
}
|
||||
|
||||
void *hashmap_remove_value(Hashmap *h, const void *key, void *value);
|
||||
static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
|
||||
return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
|
||||
static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
|
||||
return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value);
|
||||
}
|
||||
|
||||
int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);
|
||||
static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
|
||||
return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value);
|
||||
}
|
||||
|
||||
/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
|
||||
* should just work, allow this by having looser type-checking here. */
|
||||
int internal_hashmap_merge(Hashmap *h, Hashmap *other);
|
||||
#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
|
||||
#define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
|
||||
|
||||
int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
|
||||
static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
|
||||
return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
|
||||
}
|
||||
static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
|
||||
return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
|
||||
}
|
||||
|
||||
int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
|
||||
/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
|
||||
static inline int hashmap_move(Hashmap *h, Hashmap *other) {
|
||||
return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
|
||||
}
|
||||
static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
|
||||
return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
|
||||
}
|
||||
|
||||
int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
|
||||
static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
|
||||
return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
|
||||
}
|
||||
static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
|
||||
return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
|
||||
}
|
||||
|
||||
unsigned internal_hashmap_size(HashmapBase *h) _pure_;
|
||||
static inline unsigned hashmap_size(Hashmap *h) {
|
||||
return internal_hashmap_size(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
|
||||
return internal_hashmap_size(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
static inline bool hashmap_isempty(Hashmap *h) {
|
||||
return hashmap_size(h) == 0;
|
||||
}
|
||||
static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
|
||||
return ordered_hashmap_size(h) == 0;
|
||||
}
|
||||
|
||||
unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
|
||||
static inline unsigned hashmap_buckets(Hashmap *h) {
|
||||
return internal_hashmap_buckets(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
|
||||
return internal_hashmap_buckets(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
|
||||
static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
|
||||
return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
|
||||
}
|
||||
static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
|
||||
return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
|
||||
}
|
||||
|
||||
void internal_hashmap_clear(HashmapBase *h);
|
||||
static inline void hashmap_clear(Hashmap *h) {
|
||||
internal_hashmap_clear(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
|
||||
internal_hashmap_clear(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
void internal_hashmap_clear_free(HashmapBase *h);
|
||||
static inline void hashmap_clear_free(Hashmap *h) {
|
||||
internal_hashmap_clear_free(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
|
||||
internal_hashmap_clear_free(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
void hashmap_clear_free_free(Hashmap *h);
|
||||
static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
|
||||
hashmap_clear_free_free(PLAIN_HASHMAP(h));
|
||||
}
|
||||
|
||||
/*
|
||||
* Note about all *_first*() functions
|
||||
*
|
||||
* For plain Hashmaps and Sets the order of entries is undefined.
|
||||
* The functions find whatever entry is first in the implementation
|
||||
* internal order.
|
||||
*
|
||||
* Only for OrderedHashmaps the order is well defined and finding
|
||||
* the first entry is O(1).
|
||||
*/
|
||||
|
||||
void *internal_hashmap_steal_first(HashmapBase *h);
|
||||
static inline void *hashmap_steal_first(Hashmap *h) {
|
||||
return internal_hashmap_steal_first(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
|
||||
return internal_hashmap_steal_first(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
void *internal_hashmap_steal_first_key(HashmapBase *h);
|
||||
static inline void *hashmap_steal_first_key(Hashmap *h) {
|
||||
return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
|
||||
return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
void *internal_hashmap_first_key(HashmapBase *h) _pure_;
|
||||
static inline void *hashmap_first_key(Hashmap *h) {
|
||||
return internal_hashmap_first_key(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
|
||||
return internal_hashmap_first_key(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
void *internal_hashmap_first(HashmapBase *h) _pure_;
|
||||
static inline void *hashmap_first(Hashmap *h) {
|
||||
return internal_hashmap_first(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline void *ordered_hashmap_first(OrderedHashmap *h) {
|
||||
return internal_hashmap_first(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
/* no hashmap_next */
|
||||
void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
|
||||
|
||||
char **internal_hashmap_get_strv(HashmapBase *h);
|
||||
static inline char **hashmap_get_strv(Hashmap *h) {
|
||||
return internal_hashmap_get_strv(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
|
||||
return internal_hashmap_get_strv(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashmaps are iterated in unpredictable order.
|
||||
* OrderedHashmaps are an exception to this. They are iterated in the order
|
||||
* the entries were inserted.
|
||||
* It is safe to remove the current entry.
|
||||
*/
|
||||
#define HASHMAP_FOREACH(e, h, i) \
|
||||
for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); )
|
||||
|
||||
#define ORDERED_HASHMAP_FOREACH(e, h, i) \
|
||||
for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); )
|
||||
|
||||
#define HASHMAP_FOREACH_KEY(e, k, h, i) \
|
||||
for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
|
||||
|
||||
#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
|
||||
for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
|
||||
|
||||
#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
|
||||
#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep)
|
||||
#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep)
|
||||
#define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep)
|
||||
#define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep)
|
||||
#define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep)
|
||||
|
|
@ -231,3 +231,15 @@ int log_syntax_internal(
|
|||
? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
|
||||
: -abs(_e); \
|
||||
})
|
||||
|
||||
#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \
|
||||
({ \
|
||||
int _level = (level); \
|
||||
if (log_get_max_level() >= LOG_PRI(_level)) { \
|
||||
_cleanup_free_ char *_p = NULL; \
|
||||
_p = utf8_escape_invalid(rvalue); \
|
||||
log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \
|
||||
"String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
|
||||
} \
|
||||
-EINVAL; \
|
||||
})
|
||||
|
|
|
|||
|
|
@ -125,8 +125,11 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL));
|
||||
}
|
||||
|
||||
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
#define ELEMENTSOF(x) \
|
||||
__extension__ (__builtin_choose_expr( \
|
||||
!__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
|
||||
sizeof(x)/sizeof((x)[0]), \
|
||||
(void)0))
|
||||
/*
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
|
|
@ -215,18 +218,20 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
(__x / __y + !!(__x % __y)); \
|
||||
})
|
||||
|
||||
#define assert_se(expr) \
|
||||
#define assert_message_se(expr, message) \
|
||||
do { \
|
||||
if (_unlikely_(!(expr))) \
|
||||
log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||
} while (false) \
|
||||
log_assert_failed(message, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||
} while (false)
|
||||
|
||||
#define assert_se(expr) assert_message_se(expr, #expr)
|
||||
|
||||
/* We override the glibc assert() here. */
|
||||
#undef assert
|
||||
#ifdef NDEBUG
|
||||
#define assert(expr) do {} while(false)
|
||||
#else
|
||||
#define assert(expr) assert_se(expr)
|
||||
#define assert(expr) assert_message_se(expr, #expr)
|
||||
#endif
|
||||
|
||||
#define assert_not_reached(t) \
|
||||
|
|
@ -251,19 +256,19 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
REENABLE_WARNING
|
||||
#endif
|
||||
|
||||
#define assert_log(expr) ((_likely_(expr)) \
|
||||
? (true) \
|
||||
: (log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__), false))
|
||||
#define assert_log(expr, message) ((_likely_(expr)) \
|
||||
? (true) \
|
||||
: (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false))
|
||||
|
||||
#define assert_return(expr, r) \
|
||||
do { \
|
||||
if (!assert_log(expr)) \
|
||||
if (!assert_log(expr, #expr)) \
|
||||
return (r); \
|
||||
} while (false)
|
||||
|
||||
#define assert_return_errno(expr, r, err) \
|
||||
do { \
|
||||
if (!assert_log(expr)) { \
|
||||
if (!assert_log(expr, #expr)) { \
|
||||
errno = err; \
|
||||
return (r); \
|
||||
} \
|
||||
|
|
@ -469,18 +474,6 @@ do { \
|
|||
#define MODE_INVALID ((mode_t) -1)
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
static inline bool UID_IS_INVALID(uid_t uid) {
|
||||
/* We consider both the old 16bit -1 user and the newer 32bit
|
||||
* -1 user invalid, since they are or used to be incompatible
|
||||
* with syscalls such as setresuid() or chown(). */
|
||||
|
||||
return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1);
|
||||
}
|
||||
|
||||
static inline bool GID_IS_INVALID(gid_t gid) {
|
||||
return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1);
|
||||
}
|
||||
|
||||
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
|
||||
static inline void func##p(type *p) { \
|
||||
if (*p) \
|
||||
|
|
|
|||
105
src/systemd/src/basic/mempool.c
Normal file
105
src/systemd/src/basic/mempool.c
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010-2014 Lennart Poettering
|
||||
Copyright 2014 Michal Schmidt
|
||||
|
||||
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 "mempool.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
struct pool {
|
||||
struct pool *next;
|
||||
unsigned n_tiles;
|
||||
unsigned n_used;
|
||||
};
|
||||
|
||||
void* mempool_alloc_tile(struct mempool *mp) {
|
||||
unsigned i;
|
||||
|
||||
/* When a tile is released we add it to the list and simply
|
||||
* place the next pointer at its offset 0. */
|
||||
|
||||
assert(mp->tile_size >= sizeof(void*));
|
||||
assert(mp->at_least > 0);
|
||||
|
||||
if (mp->freelist) {
|
||||
void *r;
|
||||
|
||||
r = mp->freelist;
|
||||
mp->freelist = * (void**) mp->freelist;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (_unlikely_(!mp->first_pool) ||
|
||||
_unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) {
|
||||
unsigned n;
|
||||
size_t size;
|
||||
struct pool *p;
|
||||
|
||||
n = mp->first_pool ? mp->first_pool->n_tiles : 0;
|
||||
n = MAX(mp->at_least, n * 2);
|
||||
size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size);
|
||||
n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->next = mp->first_pool;
|
||||
p->n_tiles = n;
|
||||
p->n_used = 0;
|
||||
|
||||
mp->first_pool = p;
|
||||
}
|
||||
|
||||
i = mp->first_pool->n_used++;
|
||||
|
||||
return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size;
|
||||
}
|
||||
|
||||
void* mempool_alloc0_tile(struct mempool *mp) {
|
||||
void *p;
|
||||
|
||||
p = mempool_alloc_tile(mp);
|
||||
if (p)
|
||||
memzero(p, mp->tile_size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void mempool_free_tile(struct mempool *mp, void *p) {
|
||||
* (void**) p = mp->freelist;
|
||||
mp->freelist = p;
|
||||
}
|
||||
|
||||
#ifdef VALGRIND
|
||||
|
||||
void mempool_drop(struct mempool *mp) {
|
||||
struct pool *p = mp->first_pool;
|
||||
while (p) {
|
||||
struct pool *n;
|
||||
n = p->next;
|
||||
free(p);
|
||||
p = n;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
51
src/systemd/src/basic/mempool.h
Normal file
51
src/systemd/src/basic/mempool.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011-2014 Lennart Poettering
|
||||
Copyright 2014 Michal Schmidt
|
||||
|
||||
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 <stddef.h>
|
||||
|
||||
struct pool;
|
||||
|
||||
struct mempool {
|
||||
struct pool *first_pool;
|
||||
void *freelist;
|
||||
size_t tile_size;
|
||||
unsigned at_least;
|
||||
};
|
||||
|
||||
void* mempool_alloc_tile(struct mempool *mp);
|
||||
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 = { \
|
||||
.tile_size = sizeof(tile_type), \
|
||||
.at_least = alloc_at_least, \
|
||||
}
|
||||
|
||||
|
||||
#ifdef VALGRIND
|
||||
void mempool_drop(struct mempool *mp);
|
||||
#endif
|
||||
320
src/systemd/src/basic/prioq.c
Normal file
320
src/systemd/src/basic/prioq.c
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 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/>.
|
||||
***/
|
||||
|
||||
/*
|
||||
* Priority Queue
|
||||
* The prioq object implements a priority queue. That is, it orders objects by
|
||||
* their priority and allows O(1) access to the object with the highest
|
||||
* priority. Insertion and removal are Θ(log n). Optionally, the caller can
|
||||
* provide a pointer to an index which will be kept up-to-date by the prioq.
|
||||
*
|
||||
* The underlying algorithm used in this implementation is a Heap.
|
||||
*/
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "prioq.h"
|
||||
|
||||
struct prioq_item {
|
||||
void *data;
|
||||
unsigned *idx;
|
||||
};
|
||||
|
||||
struct Prioq {
|
||||
compare_func_t compare_func;
|
||||
unsigned n_items, n_allocated;
|
||||
|
||||
struct prioq_item *items;
|
||||
};
|
||||
|
||||
Prioq *prioq_new(compare_func_t compare_func) {
|
||||
Prioq *q;
|
||||
|
||||
q = new0(Prioq, 1);
|
||||
if (!q)
|
||||
return q;
|
||||
|
||||
q->compare_func = compare_func;
|
||||
return q;
|
||||
}
|
||||
|
||||
Prioq* prioq_free(Prioq *q) {
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
free(q->items);
|
||||
free(q);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
|
||||
assert(q);
|
||||
|
||||
if (*q)
|
||||
return 0;
|
||||
|
||||
*q = prioq_new(compare_func);
|
||||
if (!*q)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void swap(Prioq *q, unsigned j, unsigned k) {
|
||||
void *saved_data;
|
||||
unsigned *saved_idx;
|
||||
|
||||
assert(q);
|
||||
assert(j < q->n_items);
|
||||
assert(k < q->n_items);
|
||||
|
||||
assert(!q->items[j].idx || *(q->items[j].idx) == j);
|
||||
assert(!q->items[k].idx || *(q->items[k].idx) == k);
|
||||
|
||||
saved_data = q->items[j].data;
|
||||
saved_idx = q->items[j].idx;
|
||||
q->items[j].data = q->items[k].data;
|
||||
q->items[j].idx = q->items[k].idx;
|
||||
q->items[k].data = saved_data;
|
||||
q->items[k].idx = saved_idx;
|
||||
|
||||
if (q->items[j].idx)
|
||||
*q->items[j].idx = j;
|
||||
|
||||
if (q->items[k].idx)
|
||||
*q->items[k].idx = k;
|
||||
}
|
||||
|
||||
static unsigned shuffle_up(Prioq *q, unsigned idx) {
|
||||
assert(q);
|
||||
|
||||
while (idx > 0) {
|
||||
unsigned k;
|
||||
|
||||
k = (idx-1)/2;
|
||||
|
||||
if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0)
|
||||
break;
|
||||
|
||||
swap(q, idx, k);
|
||||
idx = k;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static unsigned shuffle_down(Prioq *q, unsigned idx) {
|
||||
assert(q);
|
||||
|
||||
for (;;) {
|
||||
unsigned j, k, s;
|
||||
|
||||
k = (idx+1)*2; /* right child */
|
||||
j = k-1; /* left child */
|
||||
|
||||
if (j >= q->n_items)
|
||||
break;
|
||||
|
||||
if (q->compare_func(q->items[j].data, q->items[idx].data) < 0)
|
||||
|
||||
/* So our left child is smaller than we are, let's
|
||||
* remember this fact */
|
||||
s = j;
|
||||
else
|
||||
s = idx;
|
||||
|
||||
if (k < q->n_items &&
|
||||
q->compare_func(q->items[k].data, q->items[s].data) < 0)
|
||||
|
||||
/* So our right child is smaller than we are, let's
|
||||
* remember this fact */
|
||||
s = k;
|
||||
|
||||
/* s now points to the smallest of the three items */
|
||||
|
||||
if (s == idx)
|
||||
/* No swap necessary, we're done */
|
||||
break;
|
||||
|
||||
swap(q, idx, s);
|
||||
idx = s;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int prioq_put(Prioq *q, void *data, unsigned *idx) {
|
||||
struct prioq_item *i;
|
||||
unsigned k;
|
||||
|
||||
assert(q);
|
||||
|
||||
if (q->n_items >= q->n_allocated) {
|
||||
unsigned n;
|
||||
struct prioq_item *j;
|
||||
|
||||
n = MAX((q->n_items+1) * 2, 16u);
|
||||
j = realloc(q->items, sizeof(struct prioq_item) * n);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
q->items = j;
|
||||
q->n_allocated = n;
|
||||
}
|
||||
|
||||
k = q->n_items++;
|
||||
i = q->items + k;
|
||||
i->data = data;
|
||||
i->idx = idx;
|
||||
|
||||
if (idx)
|
||||
*idx = k;
|
||||
|
||||
shuffle_up(q, k);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void remove_item(Prioq *q, struct prioq_item *i) {
|
||||
struct prioq_item *l;
|
||||
|
||||
assert(q);
|
||||
assert(i);
|
||||
|
||||
l = q->items + q->n_items - 1;
|
||||
|
||||
if (i == l)
|
||||
/* Last entry, let's just remove it */
|
||||
q->n_items--;
|
||||
else {
|
||||
unsigned k;
|
||||
|
||||
/* Not last entry, let's replace the last entry with
|
||||
* this one, and reshuffle */
|
||||
|
||||
k = i - q->items;
|
||||
|
||||
i->data = l->data;
|
||||
i->idx = l->idx;
|
||||
if (i->idx)
|
||||
*i->idx = k;
|
||||
q->n_items--;
|
||||
|
||||
k = shuffle_down(q, k);
|
||||
shuffle_up(q, k);
|
||||
}
|
||||
}
|
||||
|
||||
_pure_ static struct prioq_item* find_item(Prioq *q, void *data, unsigned *idx) {
|
||||
struct prioq_item *i;
|
||||
|
||||
assert(q);
|
||||
|
||||
if (idx) {
|
||||
if (*idx == PRIOQ_IDX_NULL ||
|
||||
*idx > q->n_items)
|
||||
return NULL;
|
||||
|
||||
i = q->items + *idx;
|
||||
if (i->data != data)
|
||||
return NULL;
|
||||
|
||||
return i;
|
||||
} else {
|
||||
for (i = q->items; i < q->items + q->n_items; i++)
|
||||
if (i->data == data)
|
||||
return i;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int prioq_remove(Prioq *q, void *data, unsigned *idx) {
|
||||
struct prioq_item *i;
|
||||
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
i = find_item(q, data, idx);
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
remove_item(q, i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
|
||||
struct prioq_item *i;
|
||||
unsigned k;
|
||||
|
||||
assert(q);
|
||||
|
||||
i = find_item(q, data, idx);
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
k = i - q->items;
|
||||
k = shuffle_down(q, k);
|
||||
shuffle_up(q, k);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *prioq_peek(Prioq *q) {
|
||||
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
if (q->n_items <= 0)
|
||||
return NULL;
|
||||
|
||||
return q->items[0].data;
|
||||
}
|
||||
|
||||
void *prioq_pop(Prioq *q) {
|
||||
void *data;
|
||||
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
if (q->n_items <= 0)
|
||||
return NULL;
|
||||
|
||||
data = q->items[0].data;
|
||||
remove_item(q, q->items);
|
||||
return data;
|
||||
}
|
||||
|
||||
unsigned prioq_size(Prioq *q) {
|
||||
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
return q->n_items;
|
||||
}
|
||||
|
||||
bool prioq_isempty(Prioq *q) {
|
||||
|
||||
if (!q)
|
||||
return true;
|
||||
|
||||
return q->n_items <= 0;
|
||||
}
|
||||
44
src/systemd/src/basic/prioq.h
Normal file
44
src/systemd/src/basic/prioq.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 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 "hashmap.h"
|
||||
|
||||
typedef struct Prioq Prioq;
|
||||
|
||||
#define PRIOQ_IDX_NULL ((unsigned) -1)
|
||||
|
||||
Prioq *prioq_new(compare_func_t compare);
|
||||
Prioq *prioq_free(Prioq *q);
|
||||
int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func);
|
||||
|
||||
int prioq_put(Prioq *q, void *data, unsigned *idx);
|
||||
int prioq_remove(Prioq *q, void *data, unsigned *idx);
|
||||
int prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
|
||||
|
||||
void *prioq_peek(Prioq *q) _pure_;
|
||||
void *prioq_pop(Prioq *q);
|
||||
|
||||
unsigned prioq_size(Prioq *q) _pure_;
|
||||
bool prioq_isempty(Prioq *q) _pure_;
|
||||
138
src/systemd/src/basic/set.h
Normal file
138
src/systemd/src/basic/set.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
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 "hashmap.h"
|
||||
#include "macro.h"
|
||||
|
||||
Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
|
||||
static inline Set *set_free(Set *s) {
|
||||
internal_hashmap_free(HASHMAP_BASE(s));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline Set *set_free_free(Set *s) {
|
||||
internal_hashmap_free_free(HASHMAP_BASE(s));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* no set_free_free_free */
|
||||
|
||||
static inline Set *set_copy(Set *s) {
|
||||
return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
int set_put(Set *s, const void *key);
|
||||
/* no set_update */
|
||||
/* no set_replace */
|
||||
static inline void *set_get(Set *s, void *key) {
|
||||
return internal_hashmap_get(HASHMAP_BASE(s), key);
|
||||
}
|
||||
/* no set_get2 */
|
||||
|
||||
static inline bool set_contains(Set *s, const void *key) {
|
||||
return internal_hashmap_contains(HASHMAP_BASE(s), key);
|
||||
}
|
||||
|
||||
static inline void *set_remove(Set *s, const void *key) {
|
||||
return internal_hashmap_remove(HASHMAP_BASE(s), key);
|
||||
}
|
||||
|
||||
/* no set_remove2 */
|
||||
/* no set_remove_value */
|
||||
int set_remove_and_put(Set *s, const void *old_key, const void *new_key);
|
||||
/* no set_remove_and_replace */
|
||||
int set_merge(Set *s, Set *other);
|
||||
|
||||
static inline int set_reserve(Set *h, unsigned entries_add) {
|
||||
return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
|
||||
}
|
||||
|
||||
static inline int set_move(Set *s, Set *other) {
|
||||
return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
|
||||
}
|
||||
|
||||
static inline int set_move_one(Set *s, Set *other, const void *key) {
|
||||
return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
|
||||
}
|
||||
|
||||
static inline unsigned set_size(Set *s) {
|
||||
return internal_hashmap_size(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
static inline bool set_isempty(Set *s) {
|
||||
return set_size(s) == 0;
|
||||
}
|
||||
|
||||
static inline unsigned set_buckets(Set *s) {
|
||||
return internal_hashmap_buckets(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
bool set_iterate(Set *s, Iterator *i, void **value);
|
||||
|
||||
static inline void set_clear(Set *s) {
|
||||
internal_hashmap_clear(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
static inline void set_clear_free(Set *s) {
|
||||
internal_hashmap_clear_free(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
/* no set_clear_free_free */
|
||||
|
||||
static inline void *set_steal_first(Set *s) {
|
||||
return internal_hashmap_steal_first(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
/* no set_steal_first_key */
|
||||
/* no set_first_key */
|
||||
|
||||
static inline void *set_first(Set *s) {
|
||||
return internal_hashmap_first(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
/* no set_next */
|
||||
|
||||
static inline char **set_get_strv(Set *s) {
|
||||
return internal_hashmap_get_strv(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
int set_consume(Set *s, void *value);
|
||||
int set_put_strdup(Set *s, const char *p);
|
||||
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_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
|
||||
|
||||
#define _cleanup_set_free_ _cleanup_(set_freep)
|
||||
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
|
||||
|
|
@ -13,126 +13,172 @@
|
|||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
|
||||
(Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
|
||||
(Refactored by Tom Gundersen to split up in several functions and follow systemd
|
||||
coding style)
|
||||
*/
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sparse-endian.h"
|
||||
|
||||
#include "siphash24.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint8_t u8;
|
||||
static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
|
||||
assert(b < 64);
|
||||
|
||||
#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
|
||||
return (x << b) | (x >> (64 - b));
|
||||
}
|
||||
|
||||
#define U32TO8_LE(p, v) \
|
||||
(p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \
|
||||
(p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24);
|
||||
static inline void sipround(struct siphash *state) {
|
||||
assert(state);
|
||||
|
||||
#define U64TO8_LE(p, v) \
|
||||
U32TO8_LE((p), (u32)((v) )); \
|
||||
U32TO8_LE((p) + 4, (u32)((v) >> 32));
|
||||
state->v0 += state->v1;
|
||||
state->v1 = rotate_left(state->v1, 13);
|
||||
state->v1 ^= state->v0;
|
||||
state->v0 = rotate_left(state->v0, 32);
|
||||
state->v2 += state->v3;
|
||||
state->v3 = rotate_left(state->v3, 16);
|
||||
state->v3 ^= state->v2;
|
||||
state->v0 += state->v3;
|
||||
state->v3 = rotate_left(state->v3, 21);
|
||||
state->v3 ^= state->v0;
|
||||
state->v2 += state->v1;
|
||||
state->v1 = rotate_left(state->v1, 17);
|
||||
state->v1 ^= state->v2;
|
||||
state->v2 = rotate_left(state->v2, 32);
|
||||
}
|
||||
|
||||
#define U8TO64_LE(p) \
|
||||
(((u64)((p)[0]) ) | \
|
||||
((u64)((p)[1]) << 8) | \
|
||||
((u64)((p)[2]) << 16) | \
|
||||
((u64)((p)[3]) << 24) | \
|
||||
((u64)((p)[4]) << 32) | \
|
||||
((u64)((p)[5]) << 40) | \
|
||||
((u64)((p)[6]) << 48) | \
|
||||
((u64)((p)[7]) << 56))
|
||||
void siphash24_init(struct siphash *state, const uint8_t k[16]) {
|
||||
uint64_t k0, k1;
|
||||
|
||||
#define SIPROUND \
|
||||
do { \
|
||||
v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
|
||||
v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
|
||||
v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
|
||||
v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
|
||||
} while(0)
|
||||
assert(state);
|
||||
assert(k);
|
||||
|
||||
k0 = le64toh(*(le64_t*) k);
|
||||
k1 = le64toh(*(le64_t*) (k + 8));
|
||||
|
||||
/* "somepseudorandomlygeneratedbytes" */
|
||||
state->v0 = 0x736f6d6570736575ULL ^ k0;
|
||||
state->v1 = 0x646f72616e646f6dULL ^ k1;
|
||||
state->v2 = 0x6c7967656e657261ULL ^ k0;
|
||||
state->v3 = 0x7465646279746573ULL ^ k1;
|
||||
state->padding = 0;
|
||||
state->inlen = 0;
|
||||
}
|
||||
|
||||
void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
|
||||
uint64_t m;
|
||||
const uint8_t *in = _in;
|
||||
const uint8_t *end = in + inlen;
|
||||
unsigned left = state->inlen & 7;
|
||||
|
||||
assert(in);
|
||||
assert(state);
|
||||
|
||||
/* update total length */
|
||||
state->inlen += inlen;
|
||||
|
||||
/* if padding exists, fill it out */
|
||||
if (left > 0) {
|
||||
for ( ; in < end && left < 8; in ++, left ++ )
|
||||
state->padding |= ( ( uint64_t )*in ) << (left * 8);
|
||||
|
||||
if (in == end && left < 8)
|
||||
/* we did not have enough input to fill out the padding completely */
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
|
||||
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
|
||||
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
|
||||
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
|
||||
printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
|
||||
#endif
|
||||
state->v3 ^= state->padding;
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
state->v0 ^= state->padding;
|
||||
|
||||
state->padding = 0;
|
||||
}
|
||||
|
||||
end -= ( state->inlen % sizeof (uint64_t) );
|
||||
|
||||
for ( ; in < end; in += 8 ) {
|
||||
m = le64toh(*(le64_t*) in);
|
||||
#ifdef DEBUG
|
||||
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
|
||||
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
|
||||
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
|
||||
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
|
||||
printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
|
||||
#endif
|
||||
state->v3 ^= m;
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
state->v0 ^= m;
|
||||
}
|
||||
|
||||
left = state->inlen & 7;
|
||||
|
||||
switch(left)
|
||||
{
|
||||
case 7: state->padding |= ((uint64_t) in[6]) << 48;
|
||||
|
||||
case 6: state->padding |= ((uint64_t) in[5]) << 40;
|
||||
|
||||
case 5: state->padding |= ((uint64_t) in[4]) << 32;
|
||||
|
||||
case 4: state->padding |= ((uint64_t) in[3]) << 24;
|
||||
|
||||
case 3: state->padding |= ((uint64_t) in[2]) << 16;
|
||||
|
||||
case 2: state->padding |= ((uint64_t) in[1]) << 8;
|
||||
|
||||
case 1: state->padding |= ((uint64_t) in[0]); break;
|
||||
|
||||
case 0: break;
|
||||
}
|
||||
}
|
||||
|
||||
void siphash24_finalize(uint8_t out[8], struct siphash *state) {
|
||||
uint64_t b;
|
||||
|
||||
b = state->padding | (( ( uint64_t )state->inlen ) << 56);
|
||||
#ifdef DEBUG
|
||||
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t)state->v0);
|
||||
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t)state->v1);
|
||||
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2);
|
||||
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3);
|
||||
printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
|
||||
#endif
|
||||
state->v3 ^= b;
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
state->v0 ^= b;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
|
||||
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
|
||||
printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
|
||||
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
|
||||
#endif
|
||||
state->v2 ^= 0xff;
|
||||
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
|
||||
*(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3);
|
||||
}
|
||||
|
||||
/* SipHash-2-4 */
|
||||
void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16])
|
||||
{
|
||||
/* "somepseudorandomlygeneratedbytes" */
|
||||
u64 v0 = 0x736f6d6570736575ULL;
|
||||
u64 v1 = 0x646f72616e646f6dULL;
|
||||
u64 v2 = 0x6c7967656e657261ULL;
|
||||
u64 v3 = 0x7465646279746573ULL;
|
||||
u64 b;
|
||||
u64 k0 = U8TO64_LE( k );
|
||||
u64 k1 = U8TO64_LE( k + 8 );
|
||||
u64 m;
|
||||
const u8 *in = _in;
|
||||
const u8 *end = in + inlen - ( inlen % sizeof( u64 ) );
|
||||
const int left = inlen & 7;
|
||||
b = ( ( u64 )inlen ) << 56;
|
||||
v3 ^= k1;
|
||||
v2 ^= k0;
|
||||
v1 ^= k1;
|
||||
v0 ^= k0;
|
||||
void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) {
|
||||
struct siphash state;
|
||||
|
||||
for ( ; in != end; in += 8 )
|
||||
{
|
||||
m = U8TO64_LE( in );
|
||||
#ifdef DEBUG
|
||||
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
|
||||
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
|
||||
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
|
||||
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
|
||||
printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m );
|
||||
#endif
|
||||
v3 ^= m;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= m;
|
||||
}
|
||||
|
||||
switch( left )
|
||||
{
|
||||
case 7: b |= ( ( u64 )in[ 6] ) << 48;
|
||||
|
||||
case 6: b |= ( ( u64 )in[ 5] ) << 40;
|
||||
|
||||
case 5: b |= ( ( u64 )in[ 4] ) << 32;
|
||||
|
||||
case 4: b |= ( ( u64 )in[ 3] ) << 24;
|
||||
|
||||
case 3: b |= ( ( u64 )in[ 2] ) << 16;
|
||||
|
||||
case 2: b |= ( ( u64 )in[ 1] ) << 8;
|
||||
|
||||
case 1: b |= ( ( u64 )in[ 0] ); break;
|
||||
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
|
||||
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
|
||||
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
|
||||
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
|
||||
printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b );
|
||||
#endif
|
||||
v3 ^= b;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= b;
|
||||
#ifdef DEBUG
|
||||
printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
|
||||
printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
|
||||
printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
|
||||
printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
|
||||
#endif
|
||||
v2 ^= 0xff;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
U64TO8_LE( out, b );
|
||||
siphash24_init(&state, k);
|
||||
siphash24_compress(_in, inlen, &state);
|
||||
siphash24_finalize(out, &state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,17 @@
|
|||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct siphash {
|
||||
uint64_t v0;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t padding;
|
||||
size_t inlen;
|
||||
};
|
||||
|
||||
void siphash24_init(struct siphash *state, const uint8_t k[16]);
|
||||
void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
|
||||
void siphash24_finalize(uint8_t out[8], struct siphash *state);
|
||||
|
||||
void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]);
|
||||
|
|
|
|||
|
|
@ -280,8 +280,8 @@ char **strv_split_newlines(const char *s) {
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
|
||||
size_t n = 0, allocated = 0;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
size_t n = 0, allocated = 0;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
|
|
@ -305,13 +305,16 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
|
|||
l[n] = NULL;
|
||||
}
|
||||
|
||||
if (!l)
|
||||
if (!l) {
|
||||
l = new0(char*, 1);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*t = l;
|
||||
l = NULL;
|
||||
|
||||
return 0;
|
||||
return (int) n;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
|
@ -724,3 +727,66 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
char ***strv_free_free(char ***l) {
|
||||
char ***i;
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
for (i = l; *i; i++)
|
||||
strv_free(*i);
|
||||
|
||||
free(l);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **strv_skip(char **l, size_t n) {
|
||||
|
||||
while (n > 0) {
|
||||
if (strv_isempty(l))
|
||||
return l;
|
||||
|
||||
l++, n--;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n) {
|
||||
size_t i, j, k;
|
||||
char **nl;
|
||||
|
||||
assert(l);
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* Adds the value value n times to l */
|
||||
|
||||
k = strv_length(*l);
|
||||
|
||||
nl = realloc(*l, sizeof(char*) * (k + n + 1));
|
||||
if (!nl)
|
||||
return -ENOMEM;
|
||||
|
||||
*l = nl;
|
||||
|
||||
for (i = k; i < k + n; i++) {
|
||||
nl[i] = strdup(value);
|
||||
if (!nl[i])
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
nl[i] = NULL;
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
for (j = k; j < i; i++)
|
||||
free(nl[j]);
|
||||
|
||||
nl[k] = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,3 +156,9 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
|
|||
return strv_isempty(patterns) ||
|
||||
strv_fnmatch(patterns, s, flags);
|
||||
}
|
||||
|
||||
char ***strv_free_free(char ***l);
|
||||
|
||||
char **strv_skip(char **l, size_t n);
|
||||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n);
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ bool timezone_is_valid(const char *name);
|
|||
|
||||
clockid_t clock_boottime_or_monotonic(void);
|
||||
|
||||
#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0)
|
||||
#define xstrftime(buf, fmt, tm) \
|
||||
assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \
|
||||
"xstrftime: " #buf "[] must be big enough")
|
||||
|
||||
int get_timezone(char **timezone);
|
||||
|
|
|
|||
|
|
@ -21,49 +21,48 @@
|
|||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <sched.h>
|
||||
#include <sys/resource.h>
|
||||
#include <linux/sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdarg.h>
|
||||
#include <poll.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <pwd.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glob.h>
|
||||
#include <grp.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/mount.h>
|
||||
#include <linux/magic.h>
|
||||
#include <limits.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/sched.h>
|
||||
#include <locale.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <poll.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* When we include libgen.h because we need dirname() we immediately
|
||||
* undefine basename() since libgen.h defines it as a macro to the POSIX
|
||||
* version which is really broken. We prefer GNU basename(). */
|
||||
* undefine basename() since libgen.h defines it as a macro to the
|
||||
* POSIX version which is really broken. We prefer GNU basename(). */
|
||||
#include <libgen.h>
|
||||
#undef basename
|
||||
|
||||
|
|
@ -71,36 +70,42 @@
|
|||
#include <sys/auxv.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
/* We include linux/fs.h as last of the system headers, as it
|
||||
* otherwise conflicts with sys/mount.h. Yay, Linux is great! */
|
||||
#include <linux/fs.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "build.h"
|
||||
#include "def.h"
|
||||
#include "device-nodes.h"
|
||||
#include "env-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fileio.h"
|
||||
#include "formats-util.h"
|
||||
#include "gunicode.h"
|
||||
#include "hashmap.h"
|
||||
#include "hostname-util.h"
|
||||
#include "ioprio.h"
|
||||
#include "missing.h"
|
||||
#include "log.h"
|
||||
#include "strv.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "macro.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "missing.h"
|
||||
#include "mkdir.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "path-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "exit-status.h"
|
||||
#include "hashmap.h"
|
||||
#include "env-util.h"
|
||||
#include "fileio.h"
|
||||
#include "device-nodes.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "utf8.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "gunicode.h"
|
||||
#include "virt.h"
|
||||
#include "def.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "formats-util.h"
|
||||
#include "process-util.h"
|
||||
#include "random-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "utf8.h"
|
||||
#include "util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "virt.h"
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/* Put this test here for a lack of better place */
|
||||
|
|
@ -109,6 +114,7 @@ assert_cc(EAGAIN == EWOULDBLOCK);
|
|||
#if 0 /* NM_IGNORED */
|
||||
int saved_argc = 0;
|
||||
char **saved_argv = NULL;
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
size_t page_size(void) {
|
||||
static thread_local size_t pgsz = 0;
|
||||
|
|
@ -123,7 +129,6 @@ size_t page_size(void) {
|
|||
pgsz = (size_t) r;
|
||||
return pgsz;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int strcmp_ptr(const char *a, const char *b) {
|
||||
|
||||
|
|
@ -366,6 +371,17 @@ FILE* safe_fclose(FILE *f) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
DIR* safe_closedir(DIR *d) {
|
||||
|
||||
if (d) {
|
||||
PROTECT_ERRNO;
|
||||
|
||||
assert_se(closedir(d) >= 0 || errno != EBADF);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int unlink_noerrno(const char *path) {
|
||||
PROTECT_ERRNO;
|
||||
int r;
|
||||
|
|
@ -2159,7 +2175,13 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||
assert(fd >= 0);
|
||||
assert(buf);
|
||||
|
||||
while (nbytes > 0) {
|
||||
/* If called with nbytes == 0, let's call read() at least
|
||||
* once, to validate the operation */
|
||||
|
||||
if (nbytes > (size_t) SSIZE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
ssize_t k;
|
||||
|
||||
k = read(fd, p, nbytes);
|
||||
|
|
@ -2173,7 +2195,7 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||
* and expect that any error/EOF is reported
|
||||
* via read() */
|
||||
|
||||
fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
|
||||
(void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2183,10 +2205,12 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||
if (k == 0)
|
||||
return n;
|
||||
|
||||
assert((size_t) k <= nbytes);
|
||||
|
||||
p += k;
|
||||
nbytes -= k;
|
||||
n += k;
|
||||
}
|
||||
} while (nbytes > 0);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
@ -2196,9 +2220,10 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||
|
||||
n = loop_read(fd, buf, nbytes, do_poll);
|
||||
if (n < 0)
|
||||
return n;
|
||||
return (int) n;
|
||||
if ((size_t) n != nbytes)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2209,7 +2234,8 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
|
|||
assert(fd >= 0);
|
||||
assert(buf);
|
||||
|
||||
errno = 0;
|
||||
if (nbytes > (size_t) SSIZE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
ssize_t k;
|
||||
|
|
@ -2224,16 +2250,18 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
|
|||
* and expect that any error/EOF is reported
|
||||
* via write() */
|
||||
|
||||
fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
|
||||
(void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
|
||||
continue;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (nbytes > 0 && k == 0) /* Can't really happen */
|
||||
if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
|
||||
return -EIO;
|
||||
|
||||
assert((size_t) k <= nbytes);
|
||||
|
||||
p += k;
|
||||
nbytes -= k;
|
||||
} while (nbytes > 0);
|
||||
|
|
@ -2552,34 +2580,6 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
|
||||
cpu_set_t *r;
|
||||
unsigned n = 1024;
|
||||
|
||||
/* Allocates the cpuset in the right size */
|
||||
|
||||
for (;;) {
|
||||
if (!(r = CPU_ALLOC(n)))
|
||||
return NULL;
|
||||
|
||||
if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
|
||||
CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
|
||||
|
||||
if (ncpus)
|
||||
*ncpus = n;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
CPU_FREE(r);
|
||||
|
||||
if (errno != EINVAL)
|
||||
return NULL;
|
||||
|
||||
n *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
int files_same(const char *filea, const char *fileb) {
|
||||
struct stat a, b;
|
||||
|
||||
|
|
@ -5279,6 +5279,19 @@ unsigned long personality_from_string(const char *p) {
|
|||
|
||||
if (streq(p, "x86"))
|
||||
return PER_LINUX;
|
||||
|
||||
#elif defined(__s390x__)
|
||||
|
||||
if (streq(p, "s390"))
|
||||
return PER_LINUX32;
|
||||
|
||||
if (streq(p, "s390x"))
|
||||
return PER_LINUX;
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
if (streq(p, "s390"))
|
||||
return PER_LINUX;
|
||||
#endif
|
||||
|
||||
return PERSONALITY_INVALID;
|
||||
|
|
@ -5298,6 +5311,20 @@ const char* personality_to_string(unsigned long p) {
|
|||
|
||||
if (p == PER_LINUX)
|
||||
return "x86";
|
||||
|
||||
#elif defined(__s390x__)
|
||||
|
||||
if (p == PER_LINUX)
|
||||
return "s390x";
|
||||
|
||||
if (p == PER_LINUX32)
|
||||
return "s390";
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
if (p == PER_LINUX)
|
||||
return "s390";
|
||||
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
|
@ -5362,15 +5389,13 @@ int update_reboot_param_file(const char *param) {
|
|||
int r = 0;
|
||||
|
||||
if (param) {
|
||||
|
||||
r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
|
||||
if (r < 0)
|
||||
log_error("Failed to write reboot param to "
|
||||
REBOOT_PARAM_FILE": %s", strerror(-r));
|
||||
return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
|
||||
} else
|
||||
unlink(REBOOT_PARAM_FILE);
|
||||
(void) unlink(REBOOT_PARAM_FILE);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int umount_recursive(const char *prefix, int flags) {
|
||||
|
|
@ -6006,6 +6031,7 @@ int extract_first_word_and_warn(
|
|||
const char *filename,
|
||||
unsigned line,
|
||||
const char *rvalue) {
|
||||
|
||||
/* Try to unquote it, if it fails, warn about it and try again but this
|
||||
* time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
|
||||
* in invalid escape sequences. */
|
||||
|
|
@ -6014,17 +6040,17 @@ int extract_first_word_and_warn(
|
|||
|
||||
save = *p;
|
||||
r = extract_first_word(p, ret, separators, flags);
|
||||
if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
|
||||
if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
|
||||
|
||||
/* Retry it with EXTRACT_CUNESCAPE_RELAX. */
|
||||
*p = save;
|
||||
r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
|
||||
else
|
||||
log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
|
||||
"Invalid escape sequences in command line: \"%s\"", rvalue);
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -6138,15 +6164,6 @@ int ptsname_malloc(int fd, char **ret) {
|
|||
int openpt_in_namespace(pid_t pid, int flags) {
|
||||
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
|
||||
_cleanup_close_pair_ int pair[2] = { -1, -1 };
|
||||
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;
|
||||
siginfo_t si;
|
||||
pid_t child;
|
||||
int r;
|
||||
|
|
@ -6180,15 +6197,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
|
|||
if (unlockpt(master) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
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), &master, sizeof(int));
|
||||
|
||||
mh.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
|
||||
if (send_one_fd(pair[1], master, 0) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
|
@ -6202,39 +6211,23 @@ int openpt_in_namespace(pid_t pid, int flags) {
|
|||
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
|
||||
return -errno;
|
||||
|
||||
CMSG_FOREACH(cmsg, &mh)
|
||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
||||
int *fds;
|
||||
unsigned n_fds;
|
||||
|
||||
fds = (int*) CMSG_DATA(cmsg);
|
||||
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
|
||||
|
||||
if (n_fds != 1) {
|
||||
close_many(fds, n_fds);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return fds[0];
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
return receive_one_fd(pair[0], 0);
|
||||
}
|
||||
|
||||
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
|
||||
char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
||||
_cleanup_close_ int fd = -1;
|
||||
ssize_t l;
|
||||
|
||||
/* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
|
||||
|
||||
fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
|
||||
fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
l = fgetxattr(fd, attribute, value, size);
|
||||
xsprintf(fn, "/proc/self/fd/%i", fd);
|
||||
|
||||
l = getxattr(fn, attribute, value, size);
|
||||
if (l < 0)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -6584,7 +6577,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|||
|
||||
for (i = 0; i < len; ++i)
|
||||
if (streq_ptr(table[i], key))
|
||||
return (ssize_t)i;
|
||||
return (ssize_t) i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -6824,4 +6817,110 @@ int fgetxattr_malloc(int fd, const char *name, char **value) {
|
|||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
int send_one_fd(int transport_fd, int 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void nop_signal_handler(int sig) {
|
||||
/* nothing here */
|
||||
}
|
||||
|
||||
int version(void) {
|
||||
puts(PACKAGE_STRING "\n"
|
||||
SYSTEMD_FEATURES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool fdname_is_valid(const char *s) {
|
||||
const char *p;
|
||||
|
||||
/* Validates a name for $LISTEN_FDNAMES. We basically allow
|
||||
* everything ASCII that's not a control character. Also, as
|
||||
* special exception the ":" character is not allowed, as we
|
||||
* use that as field separator in $LISTEN_FDNAMES.
|
||||
*
|
||||
* Note that the empty string is explicitly allowed
|
||||
* here. However, we limit the length of the names to 255
|
||||
* characters. */
|
||||
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
for (p = s; *p; p++) {
|
||||
if (*p < ' ')
|
||||
return false;
|
||||
if (*p >= 127)
|
||||
return false;
|
||||
if (*p == ':')
|
||||
return false;
|
||||
}
|
||||
|
||||
return p - s < 256;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -24,34 +24,33 @@
|
|||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <alloca.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <mntent.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "formats-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "macro.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "missing.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "time-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "formats-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/* What is interpreted as whitespace? */
|
||||
#define WHITESPACE " \t\n\r"
|
||||
|
|
@ -157,6 +156,7 @@ void close_many(const int fds[], unsigned n_fd);
|
|||
|
||||
int fclose_nointr(FILE *f);
|
||||
FILE* safe_fclose(FILE *f);
|
||||
DIR* safe_closedir(DIR *f);
|
||||
|
||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||
|
||||
|
|
@ -166,7 +166,10 @@ int parse_uid(const char *s, uid_t* ret_uid);
|
|||
#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
|
||||
|
||||
bool uid_is_valid(uid_t uid);
|
||||
#define gid_is_valid(gid) uid_is_valid(gid)
|
||||
|
||||
static inline bool gid_is_valid(gid_t gid) {
|
||||
return uid_is_valid((uid_t) gid);
|
||||
}
|
||||
|
||||
int safe_atou(const char *s, unsigned *ret_u);
|
||||
int safe_atoi(const char *s, int *ret_i);
|
||||
|
|
@ -295,9 +298,9 @@ bool chars_intersect(const char *a, const char *b) _pure_;
|
|||
|
||||
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
|
||||
|
||||
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
|
||||
scope inline type name##_from_string(const char *s) { \
|
||||
return (type)string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
|
||||
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
|
||||
scope type name##_from_string(const char *s) { \
|
||||
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
|
||||
}
|
||||
|
||||
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
|
||||
|
|
@ -314,17 +317,15 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|||
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
|
||||
int name##_to_string_alloc(type i, char **str) { \
|
||||
char *s; \
|
||||
int r; \
|
||||
if (i < 0 || i > max) \
|
||||
return -ERANGE; \
|
||||
if (i < (type) ELEMENTSOF(name##_table)) { \
|
||||
s = strdup(name##_table[i]); \
|
||||
if (!s) \
|
||||
return log_oom(); \
|
||||
return -ENOMEM; \
|
||||
} else { \
|
||||
r = asprintf(&s, "%i", i); \
|
||||
if (r < 0) \
|
||||
return log_oom(); \
|
||||
if (asprintf(&s, "%i", i) < 0) \
|
||||
return -ENOMEM; \
|
||||
} \
|
||||
*str = s; \
|
||||
return 0; \
|
||||
|
|
@ -332,10 +333,10 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|||
type name##_from_string(const char *s) { \
|
||||
type i; \
|
||||
unsigned u = 0; \
|
||||
assert(s); \
|
||||
for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
|
||||
if (name##_table[i] && \
|
||||
streq(name##_table[i], s)) \
|
||||
if (!s) \
|
||||
return (type) -1; \
|
||||
for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
|
||||
if (streq_ptr(name##_table[i], s)) \
|
||||
return i; \
|
||||
if (safe_atou(s, &u) >= 0 && u <= max) \
|
||||
return (type) u; \
|
||||
|
|
@ -375,12 +376,9 @@ int fd_is_temporary_fs(int fd);
|
|||
|
||||
int pipe_eof(int fd);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
|
||||
#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
|
||||
|
||||
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
|
||||
|
||||
#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
|
||||
#define xsprintf(buf, fmt, ...) \
|
||||
assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \
|
||||
"xsprintf: " #buf "[] must be big enough")
|
||||
|
||||
int files_same(const char *filea, const char *fileb);
|
||||
|
||||
|
|
@ -440,7 +438,9 @@ int get_files_in_directory(const char *path, char ***list);
|
|||
|
||||
char *strjoin(const char *x, ...) _sentinel_;
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool is_main_thread(void);
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
static inline bool _pure_ in_charset(const char *s, const char* charset) {
|
||||
assert(s);
|
||||
|
|
@ -948,3 +948,12 @@ int reset_uid_gid(void);
|
|||
|
||||
int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
|
||||
int fgetxattr_malloc(int fd, const char *name, char **value);
|
||||
|
||||
int send_one_fd(int transport_fd, int fd, int flags);
|
||||
int receive_one_fd(int transport_fd, int flags);
|
||||
|
||||
void nop_signal_handler(int sig);
|
||||
|
||||
int version(void);
|
||||
|
||||
bool fdname_is_valid(const char *s);
|
||||
|
|
|
|||
155
src/systemd/src/libsystemd-network/arp-util.c
Normal file
155
src/systemd/src/libsystemd-network/arp-util.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Axis Communications AB. All rights reserved.
|
||||
Copyright (C) 2015 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 <linux/filter.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "arp-util.h"
|
||||
|
||||
int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
|
||||
struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
/* Sender Hardware Address must be different from our own */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((uint32_t *) eth_mac))), /* A <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((uint16_t *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
/* Sender Protocol Address or Target Protocol Address must be equal to the one we care about*/
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = (struct sock_filter*) filter
|
||||
};
|
||||
union sockaddr_union link = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_protocol = htons(ETH_P_ARP),
|
||||
.ll.sll_ifindex = ifindex,
|
||||
.ll.sll_halen = ETH_ALEN,
|
||||
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
|
||||
s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = bind(s, &link.sa, sizeof(link.ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int arp_send_packet(int fd, int ifindex,
|
||||
be32_t pa, const struct ether_addr *ha,
|
||||
bool announce) {
|
||||
union sockaddr_union link = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_protocol = htons(ETH_P_ARP),
|
||||
.ll.sll_ifindex = ifindex,
|
||||
.ll.sll_halen = ETH_ALEN,
|
||||
.ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
};
|
||||
struct ether_arp arp = {
|
||||
.ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */
|
||||
.ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */
|
||||
.ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
|
||||
.ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */
|
||||
.ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(pa != 0);
|
||||
assert(ha);
|
||||
|
||||
memcpy(&arp.arp_sha, ha, ETH_ALEN);
|
||||
memcpy(&arp.arp_tpa, &pa, sizeof(pa));
|
||||
|
||||
if (announce)
|
||||
memcpy(&arp.arp_spa, &pa, sizeof(pa));
|
||||
|
||||
r = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arp_send_probe(int fd, int ifindex,
|
||||
be32_t pa, const struct ether_addr *ha) {
|
||||
return arp_send_packet(fd, ifindex, pa, ha, false);
|
||||
}
|
||||
|
||||
int arp_send_announcement(int fd, int ifindex,
|
||||
be32_t pa, const struct ether_addr *ha) {
|
||||
return arp_send_packet(fd, ifindex, pa, ha, true);
|
||||
}
|
||||
|
|
@ -28,13 +28,9 @@
|
|||
#include "sparse-endian.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
int arp_network_bind_raw_socket(int index, union sockaddr_union *link);
|
||||
int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
|
||||
const struct ether_arp *arp);
|
||||
int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac);
|
||||
|
||||
void arp_packet_init(struct ether_arp *arp);
|
||||
void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
|
||||
void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
|
||||
int arp_packet_verify_headers(struct ether_arp *arp);
|
||||
|
||||
#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
|
||||
int arp_send_probe(int fd, int ifindex,
|
||||
be32_t pa, const struct ether_addr *ha);
|
||||
int arp_send_announcement(int fd, int ifindex,
|
||||
be32_t pa, const struct ether_addr *ha);
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Axis Communications AB. All rights reserved.
|
||||
|
||||
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 <linux/filter.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "ipv4ll-internal.h"
|
||||
|
||||
int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
|
||||
const struct ether_arp *arp) {
|
||||
int r;
|
||||
|
||||
assert(arp);
|
||||
assert(link);
|
||||
assert(fd >= 0);
|
||||
|
||||
r = sendto(fd, arp, sizeof(struct ether_arp), 0, &link->sa, sizeof(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arp_network_bind_raw_socket(int ifindex, union sockaddr_union *link) {
|
||||
|
||||
static const struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 0, 1), /* protocol == request ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), /* protocol == reply ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = (struct sock_filter*) filter
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
assert(link);
|
||||
|
||||
s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
link->ll.sll_family = AF_PACKET;
|
||||
link->ll.sll_protocol = htons(ETH_P_ARP);
|
||||
link->ll.sll_ifindex = ifindex;
|
||||
link->ll.sll_halen = ETH_ALEN;
|
||||
memset(link->ll.sll_addr, 0xff, ETH_ALEN);
|
||||
|
||||
r = bind(s, &link->sa, sizeof(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Axis Communications AB. All rights reserved.
|
||||
|
||||
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 "util.h"
|
||||
#include "ipv4ll-internal.h"
|
||||
|
||||
void arp_packet_init(struct ether_arp *arp) {
|
||||
assert(arp);
|
||||
|
||||
memzero(arp, sizeof(struct ether_arp));
|
||||
/* Header */
|
||||
arp->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); /* HTYPE */
|
||||
arp->ea_hdr.ar_pro = htons(ETHERTYPE_IP); /* PTYPE */
|
||||
arp->ea_hdr.ar_hln = ETH_ALEN; /* HLEN */
|
||||
arp->ea_hdr.ar_pln = sizeof arp->arp_spa; /* PLEN */
|
||||
arp->ea_hdr.ar_op = htons(ARPOP_REQUEST); /* REQUEST */
|
||||
}
|
||||
|
||||
void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha) {
|
||||
assert(ha);
|
||||
|
||||
arp_packet_init(arp);
|
||||
memcpy(arp->arp_sha, ha, ETH_ALEN);
|
||||
memcpy(arp->arp_tpa, &pa, sizeof(pa));
|
||||
}
|
||||
|
||||
void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha) {
|
||||
assert(ha);
|
||||
|
||||
arp_packet_init(arp);
|
||||
memcpy(arp->arp_sha, ha, ETH_ALEN);
|
||||
memcpy(arp->arp_tpa, &pa, sizeof(pa));
|
||||
memcpy(arp->arp_spa, &pa, sizeof(pa));
|
||||
}
|
||||
|
||||
int arp_packet_verify_headers(struct ether_arp *arp) {
|
||||
assert(arp);
|
||||
|
||||
if (arp->ea_hdr.ar_hrd != htons(ARPHRD_ETHER)) {
|
||||
log_ipv4ll(NULL, "ignoring packet: header is not ARPHRD_ETHER");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (arp->ea_hdr.ar_pro != htons(ETHERTYPE_IP)) {
|
||||
log_ipv4ll(NULL, "ignoring packet: protocol is not ETHERTYPE_IP");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (arp->ea_hdr.ar_op != htons(ARPOP_REQUEST) &&
|
||||
arp->ea_hdr.ar_op != htons(ARPOP_REPLY)) {
|
||||
log_ipv4ll(NULL, "ignoring packet: operation is not ARPOP_REQUEST or ARPOP_REPLY");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
362
src/systemd/src/libsystemd-network/lldp-internal.c
Normal file
362
src/systemd/src/libsystemd-network/lldp-internal.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "lldp-internal.h"
|
||||
#include "sd-lldp.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_lldp_packet_unref_ 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);
|
||||
}
|
||||
94
src/systemd/src/libsystemd-network/lldp-internal.h
Normal file
94
src/systemd/src/libsystemd-network/lldp-internal.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "lldp-tlv.h"
|
||||
#include "prioq.h"
|
||||
#include "sd-event.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 lldp_neighbour_port {
|
||||
uint8_t type;
|
||||
uint8_t *data;
|
||||
|
||||
uint16_t length;
|
||||
usec_t until;
|
||||
|
||||
unsigned prioq_idx;
|
||||
|
||||
lldp_chassis *c;
|
||||
tlv_packet *packet;
|
||||
|
||||
LIST_FIELDS(lldp_neighbour_port, port);
|
||||
};
|
||||
|
||||
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__)
|
||||
86
src/systemd/src/libsystemd-network/lldp-network.c
Normal file
86
src/systemd/src/libsystemd-network/lldp-network.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 <linux/filter.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
#include "lldp-tlv.h"
|
||||
#include "lldp-network.h"
|
||||
#include "lldp-internal.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 */
|
||||
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_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_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 = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = filter
|
||||
};
|
||||
|
||||
_cleanup_close_ int s = -1;
|
||||
|
||||
union sockaddr_union saddrll = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_ifindex = ifindex,
|
||||
};
|
||||
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
|
||||
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = bind(s, &saddrll.sa, sizeof(saddrll.ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = s;
|
||||
s = -1;
|
||||
|
||||
return r;
|
||||
}
|
||||
29
src/systemd/src/libsystemd-network/lldp-network.h
Normal file
29
src/systemd/src/libsystemd-network/lldp-network.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
int lldp_network_bind_raw_socket(int ifindex);
|
||||
119
src/systemd/src/libsystemd-network/lldp-port.c
Normal file
119
src/systemd/src/libsystemd-network/lldp-port.c
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "async.h"
|
||||
#include "lldp-port.h"
|
||||
#include "lldp-network.h"
|
||||
#include "lldp-internal.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;
|
||||
}
|
||||
73
src/systemd/src/libsystemd-network/lldp-port.h
Normal file
73
src/systemd/src/libsystemd-network/lldp-port.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#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);
|
||||
649
src/systemd/src/libsystemd-network/lldp-tlv.c
Normal file
649
src/systemd/src/libsystemd-network/lldp-tlv.c
Normal file
|
|
@ -0,0 +1,649 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 <net/ethernet.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "lldp-tlv.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)
|
||||
goto out;
|
||||
|
||||
r = tlv_packet_read_u16(tlv, value);
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out:
|
||||
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)
|
||||
goto out2;
|
||||
|
||||
r = tlv_packet_read_u8(tlv, &subtype);
|
||||
if (r < 0)
|
||||
goto out1;
|
||||
|
||||
switch (subtype) {
|
||||
case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
|
||||
|
||||
r = tlv_packet_read_bytes(tlv, data, length);
|
||||
if (r < 0)
|
||||
goto out1;
|
||||
|
||||
break;
|
||||
default:
|
||||
r = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
*type = subtype;
|
||||
|
||||
out1:
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out2:
|
||||
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)
|
||||
goto out2;
|
||||
|
||||
r = tlv_packet_read_u8(tlv, &subtype);
|
||||
if (r < 0)
|
||||
goto out1;
|
||||
|
||||
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 out1;
|
||||
|
||||
*data = (uint8_t *) s;
|
||||
|
||||
break;
|
||||
case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
|
||||
|
||||
r = tlv_packet_read_bytes(tlv, data, length);
|
||||
if (r < 0)
|
||||
goto out1;
|
||||
|
||||
break;
|
||||
default:
|
||||
r = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
*type = subtype;
|
||||
|
||||
out1:
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out2:
|
||||
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)
|
||||
goto out;
|
||||
|
||||
r = tlv_packet_read_u16(tlv, id);
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out:
|
||||
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)
|
||||
goto out;
|
||||
|
||||
r = tlv_packet_read_u8(tlv, flags);
|
||||
if (r >= 0)
|
||||
r = tlv_packet_read_u16(tlv, id);
|
||||
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out:
|
||||
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)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
|
||||
out:
|
||||
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)
|
||||
goto out;
|
||||
|
||||
r = tlv_packet_read_u16(tlv, id);
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out:
|
||||
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)
|
||||
goto out;
|
||||
|
||||
r = tlv_packet_read_u8(tlv, status);
|
||||
if (r >= 0)
|
||||
r = tlv_packet_read_u32(tlv, id);
|
||||
|
||||
r2 = lldp_tlv_packet_exit_container(tlv);
|
||||
|
||||
out:
|
||||
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;
|
||||
}
|
||||
101
src/systemd/src/libsystemd-network/lldp-tlv.h
Normal file
101
src/systemd/src/libsystemd-network/lldp-tlv.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "lldp.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "sd-lldp.h"
|
||||
|
||||
typedef struct tlv_packet tlv_packet;
|
||||
typedef struct tlv_section tlv_section;
|
||||
|
||||
#define LLDP_OUI_LEN 3
|
||||
|
||||
struct tlv_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 tlv_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);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp_packet*, sd_lldp_packet_unref);
|
||||
#define _cleanup_lldp_packet_unref_ _cleanup_(sd_lldp_packet_unrefp)
|
||||
|
||||
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);
|
||||
28
src/systemd/src/libsystemd-network/lldp-util.h
Normal file
28
src/systemd/src/libsystemd-network/lldp-util.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp *, sd_lldp_free);
|
||||
#define _cleanup_lldp_free_ _cleanup_(sd_lldp_freep)
|
||||
130
src/systemd/src/libsystemd-network/lldp.h
Normal file
130
src/systemd/src/libsystemd-network/lldp.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
|
||||
|
||||
#define ETHERTYPE_LLDP 0x88cc
|
||||
|
||||
/* IEEE 802.3AB Clause 9: TLV Types */
|
||||
typedef enum LLDPTypes {
|
||||
LLDP_TYPE_END = 0,
|
||||
LLDP_TYPE_CHASSIS_ID = 1,
|
||||
LLDP_TYPE_PORT_ID = 2,
|
||||
LLDP_TYPE_TTL = 3,
|
||||
LLDP_TYPE_PORT_DESCRIPTION = 4,
|
||||
LLDP_TYPE_SYSTEM_NAME = 5,
|
||||
LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
|
||||
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 {
|
||||
LLDP_CHASSIS_SUBTYPE_RESERVED = 0,
|
||||
LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1,
|
||||
LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2,
|
||||
LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3,
|
||||
LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
|
||||
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 {
|
||||
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_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 {
|
||||
LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
|
||||
LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
|
||||
LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
|
||||
LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3,
|
||||
LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4,
|
||||
LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5,
|
||||
LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6,
|
||||
LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
|
||||
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;
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
@ -205,8 +205,7 @@ int config_parse_ifname(const char *unit,
|
|||
return log_oom();
|
||||
|
||||
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -249,8 +248,7 @@ int config_parse_ifnames(const char *unit,
|
|||
return log_oom();
|
||||
|
||||
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -287,8 +285,7 @@ int config_parse_ifalias(const char *unit,
|
|||
return log_oom();
|
||||
|
||||
if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -333,8 +330,7 @@ int config_parse_hwaddr(const char *unit,
|
|||
&n->ether_addr_octet[4],
|
||||
&n->ether_addr_octet[5]);
|
||||
if (r != 6) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Not a valid MAC address, ignoring assignment: %s", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -404,8 +400,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
|
|||
assert(size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
fprintf(f, SD_ICMP6_ADDRESS_FORMAT_STR"%s",
|
||||
SD_ICMP6_ADDRESS_FORMAT_VAL(addresses[i]),
|
||||
fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
|
||||
(i < (size - 1)) ? " ": "");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
|
|||
log_dhcp_client(client, "Changing MAC address on running DHCP "
|
||||
"client, restarting");
|
||||
need_restart = true;
|
||||
client_stop(client, DHCP_EVENT_STOP);
|
||||
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
|
||||
}
|
||||
|
||||
memcpy(&client->mac_addr, addr, addr_len);
|
||||
|
|
@ -279,7 +279,7 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
|
|||
log_dhcp_client(client, "Changing client ID on running DHCP "
|
||||
"client, restarting");
|
||||
need_restart = true;
|
||||
client_stop(client, DHCP_EVENT_STOP);
|
||||
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
|
||||
}
|
||||
|
||||
client->client_id.type = type;
|
||||
|
|
@ -387,7 +387,7 @@ static void client_stop(sd_dhcp_client *client, int error) {
|
|||
|
||||
if (error < 0)
|
||||
log_dhcp_client(client, "STOPPED: %s", strerror(-error));
|
||||
else if (error == DHCP_EVENT_STOP)
|
||||
else if (error == SD_DHCP_CLIENT_EVENT_STOP)
|
||||
log_dhcp_client(client, "STOPPED");
|
||||
else
|
||||
log_dhcp_client(client, "STOPPED: Unknown event");
|
||||
|
|
@ -985,7 +985,7 @@ static int client_timeout_expire(sd_event_source *s, uint64_t usec,
|
|||
|
||||
log_dhcp_client(client, "EXPIRED");
|
||||
|
||||
client_notify(client, DHCP_EVENT_EXPIRED);
|
||||
client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
|
||||
|
||||
/* lease was lost, start over if not freed or stopped in callback */
|
||||
if (client->state != DHCP_STATE_STOPPED) {
|
||||
|
|
@ -1145,14 +1145,14 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
|
|||
}
|
||||
}
|
||||
|
||||
r = DHCP_EVENT_IP_ACQUIRE;
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
|
||||
if (client->lease) {
|
||||
if (client->lease->address != lease->address ||
|
||||
client->lease->subnet_mask != lease->subnet_mask ||
|
||||
client->lease->router != lease->router) {
|
||||
r = DHCP_EVENT_IP_CHANGE;
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
|
||||
} else
|
||||
r = DHCP_EVENT_RENEW;
|
||||
r = SD_DHCP_CLIENT_EVENT_RENEW;
|
||||
|
||||
client->lease = sd_dhcp_lease_unref(client->lease);
|
||||
}
|
||||
|
|
@ -1384,8 +1384,8 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
|
|||
|
||||
if (IN_SET(client->state, DHCP_STATE_REQUESTING,
|
||||
DHCP_STATE_REBOOTING))
|
||||
notify_event = DHCP_EVENT_IP_ACQUIRE;
|
||||
else if (r != DHCP_EVENT_IP_ACQUIRE)
|
||||
notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
|
||||
else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
|
||||
notify_event = r;
|
||||
|
||||
client->state = DHCP_STATE_BOUND;
|
||||
|
|
@ -1635,7 +1635,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) {
|
|||
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client_stop(client, DHCP_EVENT_STOP);
|
||||
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
|
||||
client->state = DHCP_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -316,10 +316,14 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
|
|||
else {
|
||||
char *string;
|
||||
|
||||
if (memchr(option, 0, len))
|
||||
/*
|
||||
* One trailing NUL byte is OK, we don't mind. See:
|
||||
* https://github.com/systemd/systemd/issues/1337
|
||||
*/
|
||||
if (memchr(option, 0, len - 1))
|
||||
return -EINVAL;
|
||||
|
||||
string = strndup((const char *)option, len);
|
||||
string = strndup((const char *) option, len);
|
||||
if (!string)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,8 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
|
|||
assert_return(client, -EINVAL);
|
||||
assert_return(interface_index >= -1, -EINVAL);
|
||||
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
client->index = interface_index;
|
||||
|
||||
return 0;
|
||||
|
|
@ -144,6 +146,8 @@ int sd_dhcp6_client_set_mac(
|
|||
assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
|
||||
assert_return(arp_type > 0, -EINVAL);
|
||||
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(addr_len == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
|
|
@ -177,6 +181,8 @@ int sd_dhcp6_client_set_duid(
|
|||
assert_return(duid, -EINVAL);
|
||||
assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
|
||||
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
switch (type) {
|
||||
case DHCP6_DUID_LLT:
|
||||
if (duid_len <= sizeof(client->duid.llt))
|
||||
|
|
@ -209,6 +215,8 @@ int sd_dhcp6_client_set_duid(
|
|||
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
client->information_request = enabled;
|
||||
|
||||
return 0;
|
||||
|
|
@ -270,13 +278,18 @@ static void client_notify(sd_dhcp6_client *client, int event) {
|
|||
client->cb(client, event, client->userdata);
|
||||
}
|
||||
|
||||
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
client->lease = lease;
|
||||
}
|
||||
|
||||
static int client_reset(sd_dhcp6_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
client->lease = sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
client_set_lease(client, NULL);
|
||||
|
||||
client->receive_message =
|
||||
sd_event_source_unref(client->receive_message);
|
||||
|
|
@ -468,7 +481,7 @@ static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
|
|||
|
||||
state = client->state;
|
||||
|
||||
client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
|
||||
|
||||
/* RFC 3315, section 18.1.4., says that "...the client may choose to
|
||||
use a Solicit message to locate a new DHCP server..." */
|
||||
|
|
@ -558,7 +571,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
|
|||
|
||||
if (max_retransmit_count &&
|
||||
client->retransmit_count >= max_retransmit_count) {
|
||||
client_stop(client, DHCP6_EVENT_RETRANS_MAX);
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -830,12 +843,7 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
client->lease = sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
|
||||
client->lease = lease;
|
||||
client_set_lease(client, lease);
|
||||
lease = NULL;
|
||||
|
||||
return DHCP6_STATE_BOUND;
|
||||
|
|
@ -864,11 +872,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
|
|||
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
|
||||
|
||||
if (r < 0 || pref_advertise > pref_lease) {
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
client->lease = lease;
|
||||
client_set_lease(client, lease);
|
||||
lease = NULL;
|
||||
r = 0;
|
||||
}
|
||||
|
|
@ -937,7 +941,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
|||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
|
||||
client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
|
||||
|
||||
client_start(client, DHCP6_STATE_STOPPED);
|
||||
|
||||
|
|
@ -969,7 +973,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
|||
return 0;
|
||||
}
|
||||
|
||||
client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
|
||||
client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -1120,7 +1124,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
|||
}
|
||||
|
||||
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
|
||||
client_stop(client, DHCP6_EVENT_STOP);
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1133,6 +1137,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
|||
assert_return(client->event, -EINVAL);
|
||||
assert_return(client->index > 0, -EINVAL);
|
||||
|
||||
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
|
||||
return -EALREADY;
|
||||
|
||||
r = client_reset(client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -1240,7 +1247,6 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
|
|||
client_reset(client);
|
||||
|
||||
sd_dhcp6_client_detach_event(client);
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
|
||||
free(client->req_opts);
|
||||
free(client);
|
||||
|
|
|
|||
531
src/systemd/src/libsystemd-network/sd-ipv4acd.c
Normal file
531
src/systemd/src/libsystemd-network/sd-ipv4acd.c
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Axis Communications AB. All rights reserved.
|
||||
Copyright (C) 2015 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 <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "list.h"
|
||||
#include "refcnt.h"
|
||||
#include "random-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "arp-util.h"
|
||||
#include "sd-ipv4acd.h"
|
||||
|
||||
/* Constants from the RFC */
|
||||
#define PROBE_WAIT 1
|
||||
#define PROBE_NUM 3
|
||||
#define PROBE_MIN 1
|
||||
#define PROBE_MAX 2
|
||||
#define ANNOUNCE_WAIT 2
|
||||
#define ANNOUNCE_NUM 2
|
||||
#define ANNOUNCE_INTERVAL 2
|
||||
#define MAX_CONFLICTS 10
|
||||
#define RATE_LIMIT_INTERVAL 60
|
||||
#define DEFEND_INTERVAL 10
|
||||
|
||||
#define IPV4ACD_NETWORK 0xA9FE0000L
|
||||
#define IPV4ACD_NETMASK 0xFFFF0000L
|
||||
|
||||
#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
|
||||
|
||||
#define log_ipv4acd_debug(ll, ...) log_ipv4acd_full(ll, LOG_DEBUG, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_info(ll, ...) log_ipv4acd_full(ll, LOG_INFO, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_notice(ll, ...) log_ipv4acd_full(ll, LOG_NOTICE, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_warning(ll, ...) log_ipv4acd_full(ll, LOG_WARNING, 0, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_error(ll, ...) log_ipv4acd_full(ll, LOG_ERR, 0, ##__VA_ARGS__)
|
||||
|
||||
#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_info_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_INFO, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__)
|
||||
#define log_ipv4acd_error_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_ERR, error, ##__VA_ARGS__)
|
||||
|
||||
typedef enum IPv4ACDState {
|
||||
IPV4ACD_STATE_INIT,
|
||||
IPV4ACD_STATE_WAITING_PROBE,
|
||||
IPV4ACD_STATE_PROBING,
|
||||
IPV4ACD_STATE_WAITING_ANNOUNCE,
|
||||
IPV4ACD_STATE_ANNOUNCING,
|
||||
IPV4ACD_STATE_RUNNING,
|
||||
_IPV4ACD_STATE_MAX,
|
||||
_IPV4ACD_STATE_INVALID = -1
|
||||
} IPv4ACDState;
|
||||
|
||||
struct sd_ipv4acd {
|
||||
RefCount n_ref;
|
||||
|
||||
IPv4ACDState state;
|
||||
int index;
|
||||
int fd;
|
||||
int iteration;
|
||||
int conflict;
|
||||
sd_event_source *receive_message;
|
||||
sd_event_source *timer;
|
||||
usec_t defend_window;
|
||||
be32_t address;
|
||||
/* External */
|
||||
struct ether_addr mac_addr;
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
sd_ipv4acd_cb_t cb;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) {
|
||||
if (ll)
|
||||
assert_se(REFCNT_INC(ll->n_ref) >= 2);
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) {
|
||||
if (!ll || REFCNT_DEC(ll->n_ref) > 0)
|
||||
return NULL;
|
||||
|
||||
ll->receive_message = sd_event_source_unref(ll->receive_message);
|
||||
ll->fd = safe_close(ll->fd);
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
|
||||
sd_ipv4acd_detach_event(ll);
|
||||
|
||||
free(ll);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4acd*, sd_ipv4acd_unref);
|
||||
#define _cleanup_ipv4acd_unref_ _cleanup_(sd_ipv4acd_unrefp)
|
||||
|
||||
int sd_ipv4acd_new(sd_ipv4acd **ret) {
|
||||
_cleanup_ipv4acd_unref_ sd_ipv4acd *ll = NULL;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
ll = new0(sd_ipv4acd, 1);
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
ll->n_ref = REFCNT_INIT;
|
||||
ll->state = IPV4ACD_STATE_INIT;
|
||||
ll->index = -1;
|
||||
ll->fd = -1;
|
||||
|
||||
*ret = ll;
|
||||
ll = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) {
|
||||
|
||||
assert(ll);
|
||||
assert(st < _IPV4ACD_STATE_MAX);
|
||||
|
||||
if (st == ll->state && !reset_counter)
|
||||
ll->iteration++;
|
||||
else {
|
||||
ll->state = st;
|
||||
ll->iteration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) {
|
||||
assert(ll);
|
||||
|
||||
if (ll->cb)
|
||||
ll->cb(ll, event, ll->userdata);
|
||||
}
|
||||
|
||||
static void ipv4acd_stop(sd_ipv4acd *ll) {
|
||||
assert(ll);
|
||||
|
||||
ll->receive_message = sd_event_source_unref(ll->receive_message);
|
||||
ll->fd = safe_close(ll->fd);
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
|
||||
log_ipv4acd_debug(ll, "STOPPED");
|
||||
|
||||
ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true);
|
||||
}
|
||||
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ipv4acd_stop(ll);
|
||||
|
||||
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
|
||||
static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) {
|
||||
_cleanup_event_source_unref_ sd_event_source *timer = NULL;
|
||||
usec_t next_timeout;
|
||||
usec_t time_now;
|
||||
int r;
|
||||
|
||||
assert(sec >= 0);
|
||||
assert(random_sec >= 0);
|
||||
assert(ll);
|
||||
|
||||
next_timeout = sec * USEC_PER_SEC;
|
||||
|
||||
if (random_sec)
|
||||
next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
|
||||
|
||||
assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
||||
|
||||
r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(),
|
||||
time_now + next_timeout, 0, ipv4acd_on_timeout, ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_priority(timer, ll->event_priority);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_description(timer, "ipv4acd-timer");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
ll->timer = timer;
|
||||
timer = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) {
|
||||
assert(ll);
|
||||
assert(arp);
|
||||
|
||||
/* see the BPF */
|
||||
if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0)
|
||||
return true;
|
||||
|
||||
/* the TPA matched instead of the SPA, this is not a conflict */
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_ipv4acd *ll = userdata;
|
||||
int r = 0;
|
||||
|
||||
assert(ll);
|
||||
|
||||
switch (ll->state) {
|
||||
case IPV4ACD_STATE_INIT:
|
||||
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true);
|
||||
|
||||
if (ll->conflict >= MAX_CONFLICTS) {
|
||||
log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL);
|
||||
r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
ll->conflict = 0;
|
||||
} else {
|
||||
r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
break;
|
||||
case IPV4ACD_STATE_WAITING_PROBE:
|
||||
case IPV4ACD_STATE_PROBING:
|
||||
/* Send a probe */
|
||||
r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr);
|
||||
if (r < 0) {
|
||||
log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m");
|
||||
goto out;
|
||||
} else {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
union in_addr_union addr = { .in.s_addr = ll->address };
|
||||
|
||||
r = in_addr_to_string(AF_INET, &addr, &address);
|
||||
if (r >= 0)
|
||||
log_ipv4acd_debug(ll, "Probing %s", address);
|
||||
}
|
||||
|
||||
if (ll->iteration < PROBE_NUM - 2) {
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
|
||||
if (r < 0)
|
||||
goto out;
|
||||
} else {
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IPV4ACD_STATE_ANNOUNCING:
|
||||
if (ll->iteration >= ANNOUNCE_NUM - 1) {
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case IPV4ACD_STATE_WAITING_ANNOUNCE:
|
||||
/* Send announcement packet */
|
||||
r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
|
||||
if (r < 0) {
|
||||
log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
|
||||
goto out;
|
||||
} else
|
||||
log_ipv4acd_debug(ll, "ANNOUNCE");
|
||||
|
||||
ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false);
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (ll->iteration == 0) {
|
||||
ll->conflict = 0;
|
||||
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Invalid state.");
|
||||
}
|
||||
|
||||
out:
|
||||
if (r < 0)
|
||||
sd_ipv4acd_stop(ll);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ipv4acd_on_conflict(sd_ipv4acd *ll) {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
union in_addr_union addr = { .in.s_addr = ll->address };
|
||||
int r;
|
||||
|
||||
assert(ll);
|
||||
|
||||
ll->conflict++;
|
||||
|
||||
r = in_addr_to_string(AF_INET, &addr, &address);
|
||||
if (r >= 0)
|
||||
log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict);
|
||||
|
||||
ipv4acd_stop(ll);
|
||||
|
||||
ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT);
|
||||
}
|
||||
|
||||
static int ipv4acd_on_packet(sd_event_source *s, int fd,
|
||||
uint32_t revents, void *userdata) {
|
||||
sd_ipv4acd *ll = userdata;
|
||||
struct ether_arp packet;
|
||||
int r;
|
||||
|
||||
assert(ll);
|
||||
assert(fd >= 0);
|
||||
|
||||
r = read(fd, &packet, sizeof(struct ether_arp));
|
||||
if (r < (int) sizeof(struct ether_arp))
|
||||
goto out;
|
||||
|
||||
switch (ll->state) {
|
||||
case IPV4ACD_STATE_ANNOUNCING:
|
||||
case IPV4ACD_STATE_RUNNING:
|
||||
if (ipv4acd_arp_conflict(ll, &packet)) {
|
||||
usec_t ts;
|
||||
|
||||
assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0);
|
||||
|
||||
/* Defend address */
|
||||
if (ts > ll->defend_window) {
|
||||
ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC;
|
||||
r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
|
||||
if (r < 0) {
|
||||
log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
|
||||
goto out;
|
||||
} else
|
||||
log_ipv4acd_debug(ll, "DEFEND");
|
||||
|
||||
} else
|
||||
ipv4acd_on_conflict(ll);
|
||||
}
|
||||
|
||||
break;
|
||||
case IPV4ACD_STATE_WAITING_PROBE:
|
||||
case IPV4ACD_STATE_PROBING:
|
||||
case IPV4ACD_STATE_WAITING_ANNOUNCE:
|
||||
/* BPF ensures this packet indicates a conflict */
|
||||
ipv4acd_on_conflict(ll);
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Invalid state.");
|
||||
}
|
||||
|
||||
out:
|
||||
if (r < 0)
|
||||
sd_ipv4acd_stop(ll);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(interface_index > 0, -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
ll->index = interface_index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
memcpy(&ll->mac_addr, addr, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ll->event = sd_event_unref(ll->event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(!ll->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
ll->event = sd_event_ref(event);
|
||||
else {
|
||||
r = sd_event_default(&ll->event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ll->event_priority = priority;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ll->cb = cb;
|
||||
ll->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ll->address = address->s_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sd_ipv4acd_is_running(sd_ipv4acd *ll) {
|
||||
assert_return(ll, false);
|
||||
|
||||
return ll->state != IPV4ACD_STATE_INIT;
|
||||
}
|
||||
|
||||
static bool ether_addr_is_nul(const struct ether_addr *addr) {
|
||||
const struct ether_addr nul_addr = {};
|
||||
|
||||
assert(addr);
|
||||
|
||||
return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0;
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
|
||||
|
||||
int sd_ipv4acd_start(sd_ipv4acd *ll) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ll->event, -EINVAL);
|
||||
assert_return(ll->index > 0, -EINVAL);
|
||||
assert_return(ll->address != 0, -EINVAL);
|
||||
assert_return(!ether_addr_is_nul(&ll->mac_addr), -EINVAL);
|
||||
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
|
||||
|
||||
ll->defend_window = 0;
|
||||
|
||||
r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
ll->fd = safe_close(ll->fd);
|
||||
ll->fd = r;
|
||||
|
||||
r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
|
||||
EPOLLIN, ipv4acd_on_packet, ll);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_description(ll->receive_message, "ipv4acd-receive-message");
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ipv4acd_set_next_wakeup(ll, 0, 0);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
out:
|
||||
if (r < 0) {
|
||||
ipv4acd_stop(ll);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Axis Communications AB. All rights reserved.
|
||||
Copyright (C) 2015 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
|
||||
|
|
@ -25,429 +26,153 @@
|
|||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "siphash24.h"
|
||||
#include "event-util.h"
|
||||
#include "list.h"
|
||||
#include "random-util.h"
|
||||
#include "refcnt.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "ipv4ll-internal.h"
|
||||
#include "sd-ipv4acd.h"
|
||||
#include "sd-ipv4ll.h"
|
||||
|
||||
/* Constants from the RFC */
|
||||
#define PROBE_WAIT 1
|
||||
#define PROBE_NUM 3
|
||||
#define PROBE_MIN 1
|
||||
#define PROBE_MAX 2
|
||||
#define ANNOUNCE_WAIT 2
|
||||
#define ANNOUNCE_NUM 2
|
||||
#define ANNOUNCE_INTERVAL 2
|
||||
#define MAX_CONFLICTS 10
|
||||
#define RATE_LIMIT_INTERVAL 60
|
||||
#define DEFEND_INTERVAL 10
|
||||
|
||||
#define IPV4LL_NETWORK 0xA9FE0000L
|
||||
#define IPV4LL_NETMASK 0xFFFF0000L
|
||||
|
||||
typedef enum IPv4LLTrigger{
|
||||
IPV4LL_TRIGGER_NULL,
|
||||
IPV4LL_TRIGGER_PACKET,
|
||||
IPV4LL_TRIGGER_TIMEOUT,
|
||||
_IPV4LL_TRIGGER_MAX,
|
||||
_IPV4LL_TRIGGER_INVALID = -1
|
||||
} IPv4LLTrigger;
|
||||
|
||||
typedef enum IPv4LLState {
|
||||
IPV4LL_STATE_INIT,
|
||||
IPV4LL_STATE_WAITING_PROBE,
|
||||
IPV4LL_STATE_PROBING,
|
||||
IPV4LL_STATE_WAITING_ANNOUNCE,
|
||||
IPV4LL_STATE_ANNOUNCING,
|
||||
IPV4LL_STATE_RUNNING,
|
||||
IPV4LL_STATE_STOPPED,
|
||||
_IPV4LL_STATE_MAX,
|
||||
_IPV4LL_STATE_INVALID = -1
|
||||
} IPv4LLState;
|
||||
#define IPV4LL_DONT_DESTROY(ll) \
|
||||
_cleanup_ipv4ll_unref_ _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll)
|
||||
|
||||
struct sd_ipv4ll {
|
||||
unsigned n_ref;
|
||||
|
||||
IPv4LLState state;
|
||||
int index;
|
||||
int fd;
|
||||
union sockaddr_union link;
|
||||
int iteration;
|
||||
int conflict;
|
||||
sd_event_source *receive_message;
|
||||
sd_event_source *timer;
|
||||
usec_t next_wakeup;
|
||||
usec_t defend_window;
|
||||
int next_wakeup_valid;
|
||||
be32_t address;
|
||||
sd_ipv4acd *acd;
|
||||
be32_t address; /* the address pushed to ACD */
|
||||
struct random_data *random_data;
|
||||
char *random_data_state;
|
||||
|
||||
/* External */
|
||||
be32_t claimed_address;
|
||||
struct ether_addr mac_addr;
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
sd_ipv4ll_cb_t cb;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data);
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return NULL;
|
||||
|
||||
static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) {
|
||||
|
||||
assert(ll);
|
||||
assert(st < _IPV4LL_STATE_MAX);
|
||||
|
||||
if (st == ll->state && !reset_counter) {
|
||||
ll->iteration++;
|
||||
} else {
|
||||
ll->state = st;
|
||||
ll->iteration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static sd_ipv4ll *ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
|
||||
assert(ll);
|
||||
|
||||
if (ll->cb) {
|
||||
ll = sd_ipv4ll_ref(ll);
|
||||
ll->cb(ll, event, ll->userdata);
|
||||
ll = sd_ipv4ll_unref(ll);
|
||||
}
|
||||
assert(ll->n_ref >= 1);
|
||||
ll->n_ref++;
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
static sd_ipv4ll *ipv4ll_stop(sd_ipv4ll *ll, int event) {
|
||||
assert(ll);
|
||||
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return NULL;
|
||||
|
||||
ll->receive_message = sd_event_source_unref(ll->receive_message);
|
||||
ll->fd = safe_close(ll->fd);
|
||||
assert(ll->n_ref >= 1);
|
||||
ll->n_ref--;
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
if (ll->n_ref > 0)
|
||||
return NULL;
|
||||
|
||||
log_ipv4ll(ll, "STOPPED");
|
||||
sd_ipv4acd_unref(ll->acd);
|
||||
|
||||
ll = ipv4ll_client_notify(ll, event);
|
||||
free(ll->random_data);
|
||||
free(ll->random_data_state);
|
||||
free(ll);
|
||||
|
||||
if (ll) {
|
||||
ll->claimed_address = 0;
|
||||
ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
|
||||
}
|
||||
|
||||
return ll;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) {
|
||||
be32_t addr;
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
|
||||
#define _cleanup_ipv4ll_unref_ _cleanup_(sd_ipv4ll_unrefp)
|
||||
|
||||
static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
|
||||
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
_cleanup_ipv4ll_unref_ sd_ipv4ll *ll = NULL;
|
||||
int r;
|
||||
int32_t random;
|
||||
|
||||
assert(ll);
|
||||
assert(address);
|
||||
assert(ll->random_data);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
do {
|
||||
r = random_r(ll->random_data, &random);
|
||||
if (r < 0)
|
||||
return r;
|
||||
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
|
||||
} while (addr == ll->address ||
|
||||
(ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
|
||||
ll = new0(sd_ipv4ll, 1);
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
*address = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
|
||||
|
||||
assert(ll);
|
||||
|
||||
ll->next_wakeup_valid = 0;
|
||||
ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_TIMEOUT, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) {
|
||||
usec_t next_timeout = 0;
|
||||
usec_t time_now = 0;
|
||||
|
||||
assert(sec >= 0);
|
||||
assert(random_sec >= 0);
|
||||
assert(ll);
|
||||
|
||||
next_timeout = sec * USEC_PER_SEC;
|
||||
|
||||
if (random_sec)
|
||||
next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
|
||||
|
||||
assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
||||
|
||||
ll->next_wakeup = time_now + next_timeout;
|
||||
ll->next_wakeup_valid = 1;
|
||||
}
|
||||
|
||||
static bool ipv4ll_arp_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
|
||||
assert(ll);
|
||||
assert(arp);
|
||||
|
||||
if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0 &&
|
||||
memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
|
||||
assert(ll);
|
||||
assert(arp);
|
||||
|
||||
if (ipv4ll_arp_conflict(ll, arp))
|
||||
return true;
|
||||
|
||||
if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0 &&
|
||||
memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) {
|
||||
struct ether_arp out_packet;
|
||||
int out_packet_ready = 0;
|
||||
int r = 0;
|
||||
|
||||
assert(ll);
|
||||
assert(trigger < _IPV4LL_TRIGGER_MAX);
|
||||
|
||||
if (ll->state == IPV4LL_STATE_INIT) {
|
||||
|
||||
log_ipv4ll(ll, "PROBE");
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
|
||||
ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
|
||||
|
||||
} else if ((ll->state == IPV4LL_STATE_WAITING_PROBE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
|
||||
(ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {
|
||||
|
||||
/* Send a probe */
|
||||
arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
|
||||
out_packet_ready = 1;
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0);
|
||||
|
||||
ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
|
||||
|
||||
} else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {
|
||||
|
||||
/* Send the last probe */
|
||||
arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
|
||||
out_packet_ready = 1;
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1);
|
||||
|
||||
ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
|
||||
|
||||
} else if ((ll->state == IPV4LL_STATE_WAITING_ANNOUNCE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
|
||||
(ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {
|
||||
|
||||
/* Send announcement packet */
|
||||
arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
|
||||
out_packet_ready = 1;
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0);
|
||||
|
||||
ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
|
||||
|
||||
if (ll->iteration == 0) {
|
||||
log_ipv4ll(ll, "ANNOUNCE");
|
||||
ll->claimed_address = ll->address;
|
||||
ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
|
||||
if (!ll || ll->state == IPV4LL_STATE_STOPPED)
|
||||
goto out;
|
||||
|
||||
ll->conflict = 0;
|
||||
}
|
||||
|
||||
} else if ((ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT &&
|
||||
ll->iteration >= ANNOUNCE_NUM-1)) {
|
||||
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0);
|
||||
ll->next_wakeup_valid = 0;
|
||||
|
||||
} else if (trigger == IPV4LL_TRIGGER_PACKET) {
|
||||
|
||||
int conflicted = 0;
|
||||
usec_t time_now;
|
||||
struct ether_arp* in_packet = (struct ether_arp*)trigger_data;
|
||||
|
||||
assert(in_packet);
|
||||
|
||||
if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {
|
||||
|
||||
if (ipv4ll_arp_conflict(ll, in_packet)) {
|
||||
|
||||
r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* Defend address */
|
||||
if (time_now > ll->defend_window) {
|
||||
ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
|
||||
arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
|
||||
out_packet_ready = 1;
|
||||
} else
|
||||
conflicted = 1;
|
||||
}
|
||||
|
||||
} else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
|
||||
IPV4LL_STATE_PROBING,
|
||||
IPV4LL_STATE_WAITING_ANNOUNCE)) {
|
||||
|
||||
conflicted = ipv4ll_arp_probe_conflict(ll, in_packet);
|
||||
}
|
||||
|
||||
if (conflicted) {
|
||||
log_ipv4ll(ll, "CONFLICT");
|
||||
ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
|
||||
if (!ll || ll->state == IPV4LL_STATE_STOPPED)
|
||||
goto out;
|
||||
|
||||
ll->claimed_address = 0;
|
||||
|
||||
/* Pick a new address */
|
||||
r = ipv4ll_pick_address(ll, &ll->address);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
ll->conflict++;
|
||||
ll->defend_window = 0;
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
|
||||
|
||||
if (ll->conflict >= MAX_CONFLICTS) {
|
||||
log_ipv4ll(ll, "MAX_CONFLICTS");
|
||||
ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
|
||||
} else
|
||||
ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (out_packet_ready) {
|
||||
r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet);
|
||||
if (r < 0) {
|
||||
log_ipv4ll(ll, "failed to send arp packet out");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (ll->next_wakeup_valid) {
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(),
|
||||
ll->next_wakeup, 0, ipv4ll_timer, ll);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_priority(ll->timer, ll->event_priority);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (r < 0 && ll)
|
||||
ipv4ll_stop(ll, r);
|
||||
}
|
||||
|
||||
static int ipv4ll_receive_message(sd_event_source *s, int fd,
|
||||
uint32_t revents, void *userdata) {
|
||||
int r;
|
||||
struct ether_arp arp;
|
||||
sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
|
||||
|
||||
assert(ll);
|
||||
|
||||
r = read(fd, &arp, sizeof(struct ether_arp));
|
||||
if (r < (int) sizeof(struct ether_arp))
|
||||
return 0;
|
||||
|
||||
r = arp_packet_verify_headers(&arp);
|
||||
r = sd_ipv4acd_new(&ll->acd);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
return r;
|
||||
|
||||
ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp);
|
||||
r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ll->n_ref = 1;
|
||||
|
||||
*ret = ll;
|
||||
ll = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
r = sd_ipv4acd_stop(ll->acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(interface_index > 0, -EINVAL);
|
||||
assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
|
||||
IPV4LL_STATE_STOPPED), -EBUSY);
|
||||
|
||||
ll->index = interface_index;
|
||||
|
||||
return 0;
|
||||
return sd_ipv4acd_set_index(ll->acd, interface_index);
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
|
||||
|
||||
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
|
||||
bool need_restart = false;
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
if (memcmp(&ll->mac_addr, addr, ETH_ALEN) == 0)
|
||||
return 0;
|
||||
if (!ll->random_data) {
|
||||
uint8_t seed[8];
|
||||
|
||||
if (!IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED)) {
|
||||
log_ipv4ll(ll, "Changing MAC address on running IPv4LL "
|
||||
"client, restarting");
|
||||
ll = ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
|
||||
need_restart = true;
|
||||
/* If no random data is set, generate some from the MAC */
|
||||
siphash24(seed, &addr->ether_addr_octet,
|
||||
ETH_ALEN, HASH_KEY.bytes);
|
||||
|
||||
assert_cc(sizeof(unsigned) <= 8);
|
||||
|
||||
r = sd_ipv4ll_set_address_seed(ll, *(unsigned*)seed);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!ll)
|
||||
return 0;
|
||||
|
||||
memcpy(&ll->mac_addr, addr, ETH_ALEN);
|
||||
|
||||
if (need_restart)
|
||||
sd_ipv4ll_start(ll);
|
||||
|
||||
return 0;
|
||||
return sd_ipv4acd_set_mac(ll->acd, addr);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ll->event = sd_event_unref(ll->event);
|
||||
|
||||
return 0;
|
||||
return sd_ipv4acd_detach_event(ll->acd);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(!ll->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
ll->event = sd_event_ref(event);
|
||||
else {
|
||||
r = sd_event_default(&ll->event);
|
||||
if (r < 0) {
|
||||
ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ll->event_priority = priority;
|
||||
r = sd_ipv4acd_attach_event(ll->acd, event, priority);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -469,189 +194,146 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
|
|||
return -ENOENT;
|
||||
|
||||
address->s_addr = ll->claimed_address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]) {
|
||||
unsigned int entropy;
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
|
||||
_cleanup_free_ struct random_data *random_data = NULL;
|
||||
_cleanup_free_ char *random_data_state = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(seed, -EINVAL);
|
||||
|
||||
entropy = *seed;
|
||||
random_data = new0(struct random_data, 1);
|
||||
if (!random_data)
|
||||
return -ENOMEM;
|
||||
|
||||
random_data_state = new0(char, 128);
|
||||
if (!random_data_state)
|
||||
return -ENOMEM;
|
||||
|
||||
r = initstate_r(seed, random_data_state, 128, random_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free(ll->random_data);
|
||||
ll->random_data = random_data;
|
||||
random_data = NULL;
|
||||
|
||||
free(ll->random_data_state);
|
||||
ll->random_data_state = random_data_state;
|
||||
random_data_state = NULL;
|
||||
|
||||
ll->random_data = new0(struct random_data, 1);
|
||||
ll->random_data_state = new0(char, 128);
|
||||
|
||||
if (!ll->random_data || !ll->random_data_state) {
|
||||
r = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = initstate_r((unsigned int)entropy, ll->random_data_state, 128, ll->random_data);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
error:
|
||||
if (r < 0){
|
||||
free(ll->random_data);
|
||||
free(ll->random_data_state);
|
||||
ll->random_data = NULL;
|
||||
ll->random_data_state = NULL;
|
||||
}
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
|
||||
assert_return(ll, false);
|
||||
|
||||
return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED);
|
||||
return sd_ipv4acd_is_running(ll->acd);
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
|
||||
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
|
||||
struct in_addr in_addr;
|
||||
be32_t addr;
|
||||
int r;
|
||||
int32_t random;
|
||||
|
||||
int sd_ipv4ll_start (sd_ipv4ll *ll) {
|
||||
assert(ll);
|
||||
assert(ll->random_data);
|
||||
|
||||
do {
|
||||
r = random_r(ll->random_data, &random);
|
||||
if (r < 0)
|
||||
return r;
|
||||
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
|
||||
} while (addr == ll->address ||
|
||||
(ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
|
||||
|
||||
in_addr.s_addr = addr;
|
||||
|
||||
r = sd_ipv4acd_set_address(ll->acd, &in_addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ll->address = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_start(sd_ipv4ll *ll) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ll->event, -EINVAL);
|
||||
assert_return(ll->index > 0, -EINVAL);
|
||||
assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
|
||||
IPV4LL_STATE_STOPPED), -EBUSY);
|
||||
|
||||
ll->state = IPV4LL_STATE_INIT;
|
||||
|
||||
r = arp_network_bind_raw_socket(ll->index, &ll->link);
|
||||
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
ll->fd = r;
|
||||
ll->conflict = 0;
|
||||
ll->defend_window = 0;
|
||||
ll->claimed_address = 0;
|
||||
|
||||
if (!ll->random_data) {
|
||||
uint8_t seed[8];
|
||||
|
||||
/* Fallback to mac */
|
||||
siphash24(seed, &ll->mac_addr.ether_addr_octet,
|
||||
ETH_ALEN, HASH_KEY.bytes);
|
||||
|
||||
r = sd_ipv4ll_set_address_seed(ll, seed);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
assert_return(ll->random_data, -EINVAL);
|
||||
|
||||
if (ll->address == 0) {
|
||||
r = ipv4ll_pick_address(ll, &ll->address);
|
||||
r = ipv4ll_pick_address(ll);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
}
|
||||
|
||||
ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
|
||||
|
||||
r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
|
||||
EPOLLIN, ipv4ll_receive_message, ll);
|
||||
r = sd_ipv4acd_start(ll->acd);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message");
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_add_time(ll->event,
|
||||
&ll->timer,
|
||||
clock_boottime_or_monotonic(),
|
||||
now(clock_boottime_or_monotonic()), 0,
|
||||
ipv4ll_timer, ll);
|
||||
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_priority(ll->timer, ll->event_priority);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
|
||||
out:
|
||||
if (r < 0)
|
||||
ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll) {
|
||||
ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
|
||||
if (ll)
|
||||
ipv4ll_set_state(ll, IPV4LL_STATE_STOPPED, 1);
|
||||
static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
|
||||
assert(ll);
|
||||
|
||||
return 0;
|
||||
if (ll->cb)
|
||||
ll->cb(ll, event, ll->userdata);
|
||||
}
|
||||
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
|
||||
void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
sd_ipv4ll *ll = userdata;
|
||||
IPV4LL_DONT_DESTROY(ll);
|
||||
int r;
|
||||
|
||||
if (!ll)
|
||||
return NULL;
|
||||
assert(acd);
|
||||
assert(ll);
|
||||
|
||||
assert(ll->n_ref >= 1);
|
||||
ll->n_ref++;
|
||||
switch (event) {
|
||||
case SD_IPV4ACD_EVENT_STOP:
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
|
||||
|
||||
if (!ll)
|
||||
return NULL;
|
||||
|
||||
assert(ll->n_ref >= 1);
|
||||
ll->n_ref--;
|
||||
|
||||
if (ll->n_ref > 0)
|
||||
return ll;
|
||||
|
||||
ll->receive_message = sd_event_source_unref(ll->receive_message);
|
||||
ll->fd = safe_close(ll->fd);
|
||||
|
||||
ll->timer = sd_event_source_unref(ll->timer);
|
||||
|
||||
sd_ipv4ll_detach_event(ll);
|
||||
|
||||
free(ll->random_data);
|
||||
free(ll->random_data_state);
|
||||
free(ll);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
|
||||
#define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_unrefp)
|
||||
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
_cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
ll = new0(sd_ipv4ll, 1);
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
ll->n_ref = 1;
|
||||
ll->state = IPV4LL_STATE_INIT;
|
||||
ll->index = -1;
|
||||
ll->fd = -1;
|
||||
|
||||
*ret = ll;
|
||||
ll = NULL;
|
||||
|
||||
return 0;
|
||||
ll->claimed_address = 0;
|
||||
|
||||
break;
|
||||
case SD_IPV4ACD_EVENT_BIND:
|
||||
ll->claimed_address = ll->address;
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND);
|
||||
|
||||
break;
|
||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||
/* if an address was already bound we must call up to the
|
||||
user to handle this, otherwise we just try again */
|
||||
if (ll->claimed_address != 0) {
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT);
|
||||
|
||||
ll->claimed_address = 0;
|
||||
} else {
|
||||
r = ipv4ll_pick_address(ll);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_ipv4acd_start(ll->acd);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
assert_not_reached("Invalid IPv4ACD event.");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
|
||||
}
|
||||
|
|
|
|||
736
src/systemd/src/libsystemd-network/sd-lldp.c
Normal file
736
src/systemd/src/libsystemd-network/sd-lldp.c
Normal file
|
|
@ -0,0 +1,736 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "siphash24.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
#include "lldp-tlv.h"
|
||||
#include "lldp-port.h"
|
||||
#include "sd-lldp.h"
|
||||
#include "prioq.h"
|
||||
#include "lldp-internal.h"
|
||||
#include "lldp-util.h"
|
||||
|
||||
typedef enum LLDPAgentRXState {
|
||||
LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
|
||||
LLDP_AGENT_RX_DELETE_AGED_INFO,
|
||||
LLDP_AGENT_RX_LLDP_INITIALIZE,
|
||||
LLDP_AGENT_RX_WAIT_FOR_FRAME,
|
||||
LLDP_AGENT_RX_RX_FRAME,
|
||||
LLDP_AGENT_RX_DELETE_INFO,
|
||||
LLDP_AGENT_RX_UPDATE_INFO,
|
||||
_LLDP_AGENT_RX_STATE_MAX,
|
||||
_LLDP_AGENT_RX_INVALID = -1,
|
||||
} LLDPAgentRXState;
|
||||
|
||||
/* Section 10.5.2.2 Reception counters */
|
||||
struct lldp_agent_statistics {
|
||||
uint64_t stats_ageouts_total;
|
||||
uint64_t stats_frames_discarded_total;
|
||||
uint64_t stats_frames_in_errors_total;
|
||||
uint64_t stats_frames_in_total;
|
||||
uint64_t stats_tlvs_discarded_total;
|
||||
uint64_t stats_tlvs_unrecognized_total;
|
||||
};
|
||||
|
||||
struct sd_lldp {
|
||||
lldp_port *port;
|
||||
|
||||
Prioq *by_expiry;
|
||||
Hashmap *neighbour_mib;
|
||||
|
||||
sd_lldp_cb_t cb;
|
||||
|
||||
void *userdata;
|
||||
|
||||
LLDPAgentRXState rx_state;
|
||||
lldp_agent_statistics statistics;
|
||||
};
|
||||
|
||||
static void chassis_id_hash_func(const void *p, struct siphash *state) {
|
||||
const lldp_chassis_id *id = p;
|
||||
|
||||
assert(id);
|
||||
assert(id->data);
|
||||
|
||||
siphash24_compress(&id->length, sizeof(id->length), state);
|
||||
siphash24_compress(id->data, id->length, state);
|
||||
}
|
||||
|
||||
static int chassis_id_compare_func(const void *_a, const void *_b) {
|
||||
const lldp_chassis_id *a, *b;
|
||||
|
||||
a = _a;
|
||||
b = _b;
|
||||
|
||||
assert(!a->length || a->data);
|
||||
assert(!b->length || b->data);
|
||||
|
||||
if (a->type != b->type)
|
||||
return -1;
|
||||
|
||||
if (a->length != b->length)
|
||||
return a->length < b->length ? -1 : 1;
|
||||
|
||||
return memcmp(a->data, b->data, a->length);
|
||||
}
|
||||
|
||||
static const struct hash_ops chassis_id_hash_ops = {
|
||||
.hash = chassis_id_hash_func,
|
||||
.compare = chassis_id_compare_func
|
||||
};
|
||||
|
||||
static void lldp_mib_delete_objects(sd_lldp *lldp);
|
||||
static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state);
|
||||
static void lldp_run_state_machine(sd_lldp *ll);
|
||||
|
||||
static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) {
|
||||
int r;
|
||||
|
||||
assert(lldp);
|
||||
assert(tlv);
|
||||
|
||||
/* Remove expired packets */
|
||||
if (prioq_size(lldp->by_expiry) > 0) {
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO);
|
||||
|
||||
lldp_mib_delete_objects(lldp);
|
||||
}
|
||||
|
||||
r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO);
|
||||
|
||||
log_lldp("Packet added. MIB size: %d , PQ size: %d",
|
||||
hashmap_size(lldp->neighbour_mib),
|
||||
prioq_size(lldp->by_expiry));
|
||||
|
||||
lldp->statistics.stats_frames_in_total ++;
|
||||
|
||||
out:
|
||||
if (r < 0)
|
||||
log_lldp("Receive frame failed: %s", strerror(-r));
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 10.3.2 LLDPDU validation: rxProcessFrame() */
|
||||
int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
|
||||
uint16_t type, len, i, l, t;
|
||||
bool chassis_id = false;
|
||||
bool malformed = false;
|
||||
bool port_id = false;
|
||||
bool ttl = false;
|
||||
bool end = false;
|
||||
lldp_port *port;
|
||||
uint8_t *p, *q;
|
||||
sd_lldp *lldp;
|
||||
int r;
|
||||
|
||||
assert(tlv);
|
||||
assert(length > 0);
|
||||
|
||||
port = (lldp_port *) tlv->userdata;
|
||||
lldp = (sd_lldp *) port->userdata;
|
||||
|
||||
if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) {
|
||||
log_lldp("Port is disabled : %s . Dropping ...",
|
||||
lldp->port->ifname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME);
|
||||
|
||||
p = tlv->pdu;
|
||||
p += sizeof(struct ether_header);
|
||||
|
||||
for (i = 1, l = 0; l <= length; i++) {
|
||||
|
||||
memcpy(&t, p, sizeof(uint16_t));
|
||||
|
||||
type = ntohs(t) >> 9;
|
||||
len = ntohs(t) & 0x01ff;
|
||||
|
||||
if (type == LLDP_TYPE_END) {
|
||||
if (len != 0) {
|
||||
log_lldp("TLV type end is not length 0. Length:%d received . Dropping ...",
|
||||
len);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
end = true;
|
||||
|
||||
break;
|
||||
} else if (type >=_LLDP_TYPE_MAX) {
|
||||
log_lldp("TLV type not recognized %d . Dropping ...",
|
||||
type);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* skip type and length encoding */
|
||||
p += 2;
|
||||
q = p;
|
||||
|
||||
p += len;
|
||||
l += (len + 2);
|
||||
|
||||
if (i <= 3) {
|
||||
if (i != type) {
|
||||
log_lldp("TLV missing or out of order. Dropping ...");
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case LLDP_TYPE_CHASSIS_ID:
|
||||
|
||||
if (len < 2) {
|
||||
log_lldp("Received malformed Chassis ID TLV len = %d. Dropping",
|
||||
len);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chassis_id) {
|
||||
log_lldp("Duplicate Chassis ID TLV found. Dropping ...");
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Look what subtype it has */
|
||||
if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED ||
|
||||
*q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) {
|
||||
log_lldp("Unknown subtype: %d found in Chassis ID TLV . Dropping ...",
|
||||
*q);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
chassis_id = true;
|
||||
|
||||
break;
|
||||
case LLDP_TYPE_PORT_ID:
|
||||
|
||||
if (len < 2) {
|
||||
log_lldp("Received malformed Port ID TLV len = %d. Dropping",
|
||||
len);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (port_id) {
|
||||
log_lldp("Duplicate Port ID TLV found. Dropping ...");
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Look what subtype it has */
|
||||
if (*q == LLDP_PORT_SUBTYPE_RESERVED ||
|
||||
*q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) {
|
||||
log_lldp("Unknown subtype: %d found in Port ID TLV . Dropping ...",
|
||||
*q);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
port_id = true;
|
||||
|
||||
break;
|
||||
case LLDP_TYPE_TTL:
|
||||
|
||||
if(len != 2) {
|
||||
log_lldp(
|
||||
"Received invalid lenth: %d TTL TLV. Dropping ...",
|
||||
len);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ttl) {
|
||||
log_lldp("Duplicate TTL TLV found. Dropping ...");
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ttl = true;
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
if (len == 0) {
|
||||
log_lldp("TLV type = %d's, length 0 received . Dropping ...",
|
||||
type);
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!chassis_id || !port_id || !ttl || !end) {
|
||||
log_lldp( "One or more mandotory TLV missing . Dropping ...");
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
r = tlv_packet_parse_pdu(tlv, length);
|
||||
if (r < 0) {
|
||||
log_lldp( "Failed to parse the TLV. Dropping ...");
|
||||
|
||||
malformed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return lldp_receive_frame(lldp, tlv);
|
||||
|
||||
out:
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
|
||||
|
||||
if (malformed) {
|
||||
lldp->statistics.stats_frames_discarded_total ++;
|
||||
lldp->statistics.stats_frames_in_errors_total ++;
|
||||
}
|
||||
|
||||
sd_lldp_packet_unref(tlv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) {
|
||||
const lldp_neighbour_port *p = a, *q = b;
|
||||
|
||||
if (p->until < q->until)
|
||||
return -1;
|
||||
|
||||
if (p->until > q->until)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) {
|
||||
|
||||
assert(lldp);
|
||||
assert(state < _LLDP_AGENT_RX_STATE_MAX);
|
||||
|
||||
lldp->rx_state = state;
|
||||
|
||||
lldp_run_state_machine(lldp);
|
||||
}
|
||||
|
||||
static void lldp_run_state_machine(sd_lldp *lldp) {
|
||||
if (!lldp->cb)
|
||||
return;
|
||||
|
||||
switch (lldp->rx_state) {
|
||||
case LLDP_AGENT_RX_UPDATE_INFO:
|
||||
lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 10.5.5.2.1 mibDeleteObjects ()
|
||||
* The mibDeleteObjects () procedure deletes all information in the LLDP remote
|
||||
* systems MIB associated with the MSAP identifier if an LLDPDU is received with
|
||||
* an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */
|
||||
|
||||
static void lldp_mib_delete_objects(sd_lldp *lldp) {
|
||||
lldp_neighbour_port *p;
|
||||
usec_t t = 0;
|
||||
|
||||
/* Remove all entries that are past their TTL */
|
||||
for (;;) {
|
||||
|
||||
if (prioq_size(lldp->by_expiry) <= 0)
|
||||
break;
|
||||
|
||||
p = prioq_peek(lldp->by_expiry);
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
if (t <= 0)
|
||||
t = now(clock_boottime_or_monotonic());
|
||||
|
||||
if (p->until > t)
|
||||
break;
|
||||
|
||||
lldp_neighbour_port_remove_and_free(p);
|
||||
|
||||
lldp->statistics.stats_ageouts_total ++;
|
||||
}
|
||||
}
|
||||
|
||||
static void lldp_mib_objects_flush(sd_lldp *lldp) {
|
||||
lldp_neighbour_port *p, *q;
|
||||
lldp_chassis *c;
|
||||
|
||||
assert(lldp);
|
||||
assert(lldp->neighbour_mib);
|
||||
assert(lldp->by_expiry);
|
||||
|
||||
/* Drop all packets */
|
||||
while ((c = hashmap_steal_first(lldp->neighbour_mib))) {
|
||||
|
||||
LIST_FOREACH_SAFE(port, p, q, c->ports) {
|
||||
lldp_neighbour_port_remove_and_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
assert(hashmap_size(lldp->neighbour_mib) == 0);
|
||||
assert(prioq_size(lldp->by_expiry) == 0);
|
||||
}
|
||||
|
||||
int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
uint8_t *mac, *port_id, type;
|
||||
lldp_neighbour_port *p;
|
||||
uint16_t data = 0, length = 0;
|
||||
char buf[LINE_MAX];
|
||||
lldp_chassis *c;
|
||||
usec_t time;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(lldp);
|
||||
assert(lldp_file);
|
||||
|
||||
r = fopen_temporary(lldp_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
fchmod(fileno(f), 0644);
|
||||
|
||||
HASHMAP_FOREACH(c, lldp->neighbour_mib, i) {
|
||||
LIST_FOREACH(port, p, c->ports) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
char *k, *t;
|
||||
|
||||
r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
|
||||
|
||||
s = strdup(buf);
|
||||
if (!s) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) {
|
||||
k = strndup((char *) port_id, length -1);
|
||||
if (!k) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type);
|
||||
free(k);
|
||||
} else {
|
||||
mac = port_id;
|
||||
sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
|
||||
}
|
||||
|
||||
k = strappend(s, buf);
|
||||
if (!k) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free(s);
|
||||
s = k;
|
||||
|
||||
time = now(clock_boottime_or_monotonic());
|
||||
|
||||
/* Don't write expired packets */
|
||||
if (time - p->until <= 0)
|
||||
continue;
|
||||
|
||||
sprintf(buf, "'_TTL="USEC_FMT"' ", p->until);
|
||||
|
||||
k = strappend(s, buf);
|
||||
if (!k) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free(s);
|
||||
s = k;
|
||||
|
||||
r = sd_lldp_packet_read_system_name(p->packet, &k, &length);
|
||||
if (r < 0)
|
||||
k = strappend(s, "'_NAME=N/A' ");
|
||||
else {
|
||||
t = strndup(k, length);
|
||||
if (!t) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
k = strjoin(s, "'_NAME=", t, "' ", NULL);
|
||||
free(t);
|
||||
}
|
||||
|
||||
if (!k) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free(s);
|
||||
s = k;
|
||||
|
||||
(void) sd_lldp_packet_read_system_capability(p->packet, &data);
|
||||
|
||||
sprintf(buf, "'_CAP=%x'", data);
|
||||
|
||||
k = strappend(s, buf);
|
||||
if (!k) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free(s);
|
||||
s = k;
|
||||
|
||||
fprintf(f, "%s\n", s);
|
||||
}
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (rename(temp_path, lldp_file) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (temp_path)
|
||||
(void) unlink(temp_path);
|
||||
|
||||
return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file);
|
||||
}
|
||||
|
||||
int sd_lldp_start(sd_lldp *lldp) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp, -EINVAL);
|
||||
assert_return(lldp->port, -EINVAL);
|
||||
|
||||
lldp->port->status = LLDP_PORT_STATUS_ENABLED;
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE);
|
||||
|
||||
r = lldp_port_start(lldp->port);
|
||||
if (r < 0) {
|
||||
log_lldp("Failed to start Port : %s , %s",
|
||||
lldp->port->ifname,
|
||||
strerror(-r));
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_stop(sd_lldp *lldp) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp, -EINVAL);
|
||||
assert_return(lldp->port, -EINVAL);
|
||||
|
||||
lldp->port->status = LLDP_PORT_STATUS_DISABLED;
|
||||
|
||||
r = lldp_port_stop(lldp->port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lldp_mib_objects_flush(lldp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp, -EINVAL);
|
||||
assert_return(!lldp->port->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
lldp->port->event = sd_event_ref(event);
|
||||
else {
|
||||
r = sd_event_default(&lldp->port->event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
lldp->port->event_priority = priority;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_detach_event(sd_lldp *lldp) {
|
||||
|
||||
assert_return(lldp, -EINVAL);
|
||||
|
||||
lldp->port->event = sd_event_unref(lldp->port->event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) {
|
||||
assert_return(lldp, -EINVAL);
|
||||
|
||||
lldp->cb = cb;
|
||||
lldp->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sd_lldp_free(sd_lldp *lldp) {
|
||||
|
||||
if (!lldp)
|
||||
return;
|
||||
|
||||
/* Drop all packets */
|
||||
lldp_mib_objects_flush(lldp);
|
||||
|
||||
lldp_port_free(lldp->port);
|
||||
|
||||
hashmap_free(lldp->neighbour_mib);
|
||||
prioq_free(lldp->by_expiry);
|
||||
|
||||
free(lldp);
|
||||
}
|
||||
|
||||
int sd_lldp_new(int ifindex,
|
||||
const char *ifname,
|
||||
const struct ether_addr *mac,
|
||||
sd_lldp **ret) {
|
||||
_cleanup_lldp_free_ sd_lldp *lldp = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(ifname, -EINVAL);
|
||||
assert_return(mac, -EINVAL);
|
||||
|
||||
lldp = new0(sd_lldp, 1);
|
||||
if (!lldp)
|
||||
return -ENOMEM;
|
||||
|
||||
r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops);
|
||||
if (!lldp->neighbour_mib)
|
||||
return -ENOMEM;
|
||||
|
||||
r = prioq_ensure_allocated(&lldp->by_expiry,
|
||||
ttl_expiry_item_prioq_compare_func);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL;
|
||||
|
||||
*ret = lldp;
|
||||
lldp = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) {
|
||||
lldp_neighbour_port *p;
|
||||
lldp_chassis *c;
|
||||
Iterator iter;
|
||||
unsigned count = 0, i;
|
||||
|
||||
assert_return(lldp, -EINVAL);
|
||||
assert_return(tlvs, -EINVAL);
|
||||
|
||||
HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
|
||||
LIST_FOREACH(port, p, c->ports)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
*tlvs = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*tlvs = new(sd_lldp_packet *, count);
|
||||
if (!*tlvs)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
|
||||
LIST_FOREACH(port, p, c->ports)
|
||||
(*tlvs)[i++] = sd_lldp_packet_ref(p->packet);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
33
src/systemd/src/libsystemd/sd-event/event-util.h
Normal file
33
src/systemd/src/libsystemd/sd-event/event-util.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2013 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 "util.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref);
|
||||
|
||||
#define _cleanup_event_unref_ _cleanup_(sd_event_unrefp)
|
||||
#define _cleanup_event_source_unref_ _cleanup_(sd_event_source_unrefp)
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
#include "random-util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
|
||||
_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
|
||||
unsigned n;
|
||||
|
||||
assert_return(s, NULL);
|
||||
|
|
|
|||
|
|
@ -382,9 +382,8 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
|
||||
void dns_name_hash_func(const void *s, struct siphash *state) {
|
||||
const char *p = s;
|
||||
unsigned long ul = hash_key[0];
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
|
@ -403,13 +402,17 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
|
|||
if (k > 0)
|
||||
r = k;
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
label[r] = 0;
|
||||
ascii_strlower(label);
|
||||
|
||||
ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
|
||||
string_hash_func(label, state);
|
||||
}
|
||||
|
||||
return ul;
|
||||
/* enforce that all names are terminated by the empty label */
|
||||
string_hash_func("", state);
|
||||
}
|
||||
|
||||
int dns_name_compare_func(const void *a, const void *b) {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static inline int dns_name_is_valid(const char *s) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]);
|
||||
void dns_name_hash_func(const void *s, struct siphash *state);
|
||||
int dns_name_compare_func(const void *a, const void *b);
|
||||
extern const struct hash_ops dns_name_hash_ops;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@
|
|||
#include "sd-dhcp-lease.h"
|
||||
|
||||
enum {
|
||||
DHCP_EVENT_STOP = 0,
|
||||
DHCP_EVENT_IP_ACQUIRE = 1,
|
||||
DHCP_EVENT_IP_CHANGE = 2,
|
||||
DHCP_EVENT_EXPIRED = 3,
|
||||
DHCP_EVENT_RENEW = 4,
|
||||
SD_DHCP_CLIENT_EVENT_STOP = 0,
|
||||
SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1,
|
||||
SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2,
|
||||
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
|
||||
SD_DHCP_CLIENT_EVENT_RENEW = 4,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp_client sd_dhcp_client;
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@
|
|||
#include "sd-dhcp6-lease.h"
|
||||
|
||||
enum {
|
||||
DHCP6_EVENT_STOP = 0,
|
||||
DHCP6_EVENT_RESEND_EXPIRE = 10,
|
||||
DHCP6_EVENT_RETRANS_MAX = 11,
|
||||
DHCP6_EVENT_IP_ACQUIRE = 12,
|
||||
DHCP6_EVENT_INFORMATION_REQUEST = 13,
|
||||
SD_DHCP6_CLIENT_EVENT_STOP = 0,
|
||||
SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10,
|
||||
SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11,
|
||||
SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12,
|
||||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@
|
|||
#include "sd-event.h"
|
||||
|
||||
enum {
|
||||
ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
|
||||
ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
|
||||
ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
|
||||
ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
|
||||
ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
|
||||
SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4,
|
||||
};
|
||||
|
||||
typedef struct sd_icmp6_nd sd_icmp6_nd;
|
||||
|
|
@ -66,9 +66,9 @@ int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr,
|
|||
int sd_icmp6_nd_stop(sd_icmp6_nd *nd);
|
||||
int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd);
|
||||
|
||||
#define SD_ICMP6_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
|
||||
#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
|
||||
|
||||
#define SD_ICMP6_ADDRESS_FORMAT_VAL(address) \
|
||||
#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \
|
||||
be16toh((address).s6_addr16[0]), \
|
||||
be16toh((address).s6_addr16[1]), \
|
||||
be16toh((address).s6_addr16[2]), \
|
||||
|
|
|
|||
57
src/systemd/src/systemd/sd-ipv4acd.h
Normal file
57
src/systemd/src/systemd/sd-ipv4acd.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdipv4acdfoo
|
||||
#define foosdipv4acdfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2014 Axis Communications AB. All rights reserved.
|
||||
Copyright (C) 2015 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 <stdbool.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
enum {
|
||||
SD_IPV4ACD_EVENT_STOP = 0,
|
||||
SD_IPV4ACD_EVENT_BIND = 1,
|
||||
SD_IPV4ACD_EVENT_CONFLICT = 2,
|
||||
};
|
||||
|
||||
typedef struct sd_ipv4acd sd_ipv4acd;
|
||||
typedef void (*sd_ipv4acd_cb_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_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_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);
|
||||
bool sd_ipv4acd_is_running(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_start(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *ll);
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_new (sd_ipv4acd **ret);
|
||||
|
||||
#endif
|
||||
|
|
@ -31,9 +31,9 @@
|
|||
#include "sd-event.h"
|
||||
|
||||
enum {
|
||||
IPV4LL_EVENT_STOP = 0,
|
||||
IPV4LL_EVENT_BIND = 1,
|
||||
IPV4LL_EVENT_CONFLICT = 2,
|
||||
SD_IPV4LL_EVENT_STOP = 0,
|
||||
SD_IPV4LL_EVENT_BIND = 1,
|
||||
SD_IPV4LL_EVENT_CONFLICT = 2,
|
||||
};
|
||||
|
||||
typedef struct sd_ipv4ll sd_ipv4ll;
|
||||
|
|
@ -45,7 +45,7 @@ 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_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_seed(sd_ipv4ll *ll, uint8_t seed[8]);
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
|
||||
bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_start(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll);
|
||||
|
|
|
|||
76
src/systemd/src/systemd/sd-lldp.h
Normal file
76
src/systemd/src/systemd/sd-lldp.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
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 "nm-sd-adapt.h"
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
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 tlv_packet sd_lldp_packet;
|
||||
|
||||
typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
|
||||
|
||||
int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret);
|
||||
void sd_lldp_free(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_detach_event(sd_lldp *lldp);
|
||||
|
||||
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata);
|
||||
int sd_lldp_save(sd_lldp *lldp, const char *file);
|
||||
|
||||
int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
|
||||
int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
|
||||
int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl);
|
||||
int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length);
|
||||
int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
|
||||
int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data);
|
||||
int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
|
||||
|
||||
/* IEEE 802.1 organizationally specific TLVs */
|
||||
int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id);
|
||||
int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id);
|
||||
int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length);
|
||||
int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id);
|
||||
int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id);
|
||||
|
||||
sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv);
|
||||
sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
|
||||
|
||||
int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
|
||||
|
||||
int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
|
||||
Loading…
Add table
Reference in a new issue